Commit Graph
13007 Commits
Author SHA1 Message Date
Yichen Jiang 732a7361f5 feat(authorization): obtain a credential by asking the human
Some credentials cannot be configured, only obtained: getting one means
a conversation — open this page, paste that code, pick an account. The
new seam owns that conversation and the one-attempt-per-key lifecycle,
and never the protocol, so a second authorization protocol arrives as
another flow rather than as another seam.

A flow is registered under the CredentialKey it writes, which is also
how the seam knows which plugin answers for the format inside that
record. The flow owns the write: run() resolving means the record is
already committed through ctx.credentials, and the seam confirms it.
That keeps a library persisting through its own store adapter the
single writer instead of being copied back out and written twice.

The interaction travels with the request rather than a registry,
because whoever starts an authorization is the one who can talk to the
human about it. A request already withdrawn never claims the key and
never starts the flow — relying on each flow to check its signal before
the first await would let one that does not hang holding the key.
2026-08-20 17:58:38 +08:00
Yichen Jiang 86a9f8c862 feat(credentials): store durable credential records beside references
The seam answered one question — what is behind this environment-variable
name — and that shape cannot hold what an authorization grant is: a
multi-field, rotating value keyed by a provider id rather than by a POSIX
identifier. The Models page already works around the gap by inventing a
synthetic environment name (`MINIMAX_CN_API_KEY`) for a route the user added
by hand, because the store's key must look like one.

`CredentialKey` is `<scope>/<id>`, where the scope is the owning plugin's
registered name. The owner is in the key because a `grant` payload is written
in its owner's format: two plugins serving the same provider name would
otherwise read each other's payload, and a record left by an uninstalled
plugin could not be told from a live one. The `/` also keeps the grammar
disjoint from `CredentialRef`, so the key spaces cannot collide.

`CredentialRecord` is `api-key` (key and/or provider environment values) or
`grant` (an opaque, owner-owned payload). The asymmetry is deliberate: an api
key is the harness's own data, a grant is a package it carries for someone
else. `modifyRecord` is the only write path because a correct write depends
on the current value — a token refresh is read-decide-replace under one
cross-process lock, without which two processes rotating one refresh token
lose whichever wrote first.

`.credentials.yaml` becomes a versioned two-section document. The pre-release
flat layout is refused by name, with the entry count and the one edit needed,
rather than read as an empty store — which would surface as an authentication
failure on the first request instead of at load. A grant payload is admitted
in both directions, so a value the document could not read back exactly as
written is refused rather than stored lossily.
2026-08-20 17:58:38 +08:00
Yichen Jiang 26a8e6a555 feat(atomic-write): state the writer-lock wait limit per call
How long a contender waits is a property of the operation the lock holder
runs, not of the write protocol. The 2s default was sized for the
render-and-rename cycle every call site had; a credential mutation that
refreshes an expired token performs a network round trip while holding the
lock, and leaving the default in place would fail every other writer of that
file for the duration.

`withFileLock` takes an optional `waitMs`; the retry cadence stays fixed
because it governs how often a contender asks, which no caller varies. Every
existing call site keeps the default.
2026-08-20 17:58:38 +08:00
Chinesezjc f5faeae4d3 Merge pull request #2798 from deepseek-harness/ci/release-check-panel
ci: stop PR gray checks from lifecycle and release publish jobs
2026-08-20 17:36:12 +08:00
pku-xht 3a9e1a6e24 Merge pull request #2749 from deepseek-harness/codex/cache-hit-decimal-display-v2
feat(web): preserve near-full cache-hit precision
2026-08-20 17:27:06 +08:00
pku-xht 36aead7320 Merge remote-tracking branch 'origin/master' into codex/cache-hit-decimal-display-v2 2026-08-20 17:18:29 +08:00
Yichen Jiang 6d6262703b Merge pull request #2820 from deepseek-harness/feat/1687-multiline-question-answer
feat(web): answer ask_user_question over multiple lines
2026-08-20 17:12:39 +08:00
Yichen Jiang 7260f4cf64 fix(web): cap the answer field at six text lines in both variants
The card-wide `border-box` reached `.fieldMirror`, so the growth cap counted
text plus padding. The inline variant carries none and landed on the declared
line count, while the optionless variant's 16px inset spent two thirds of a
line and delivered its last one as an 8px sliver. The e2e measured only the
inline shape, so nothing caught the drift.

The mirror now takes `box-sizing: content-box`, which states the cap in the
units it is written in, and the cap moves to six lines. The e2e asserts whole
text lines rather than a box height, and covers the optionless shape — asked
straight through the user-questions seam, since a layout metric needs no model
round — including that the reserved empty field is fully covered by its own
control.
2026-08-20 16:58:41 +08:00
imccyu 3866791579 Merge pull request #2725 from deepseek-harness/worktree-bootserver
feat(webserver): structured index injection table and the client boot seams
2026-08-20 16:26:31 +08:00
imccyu be3a630da8 docs(web): retire tap-era prose across READMEs, subsystems, and notes 2026-08-20 16:13:05 +08:00
imccyu d582939783 docs(web): align injection-surface JSDoc, notes, and bilingual READMEs 2026-08-20 16:13:05 +08:00
imccyu 97f4d4608b test(gateway): pin the namespace atomic-visibility guarantee 2026-08-20 16:13:05 +08:00
imccyu 10f9f506e2 fix(web): stand down prefetch only when the transport owns bundle bytes 2026-08-20 16:13:05 +08:00
imccyu 3ca4997cd2 test: cover gateway rollback and theme fallback branches 2026-08-20 16:13:05 +08:00
imccyu d4fd03ae53 chore(docs): classify IndexInjection and regenerate the catalog surfaces 2026-08-20 16:13:04 +08:00
imccyu 156bd075a9 feat(webserver): structured index injection table and the client boot seams
Replace per-plugin tapIndex regex edits with pure-data IndexInjection rows
collected fresh per render over one webserver/index-inject event. One table,
two renderers: the served form renders rows into index.html; a static worker
form ships the same rows over its boot payload. tapIndex survives as the
raw-HTML escape hatch, applied after row rendering; client-modules and
ui-theme move to the event, and the manifest global renders as
globalThis["__DSH_BOOT__"].

The client boot chain gains the seams a pre-injected transport needs: the
module loader takes loadBundle from the transport global by default, HTTP
prefetch stands down when a transport owns bundle bytes, the web-app bundle
can decline frontend serving, the gateway client installs a namespace's
whole method group inside its fiber apply so a parked dependent never
observes the service without its methods, and the dynamic-code precheck
gates through new Function so hosts without a real node:vm keep the
define-time parse gate.
2026-08-20 16:13:04 +08:00
Chinesezjc 56a8f7d325 fix(cic): cover release-publish in client-build gate and correct group wording
Address the latest review pass on PR #2798:

- client-build-environment.client.spec.ts: add release-publish.yml to
  dshBuildWorkflows so the 'workflow env must not set DSH_CLIENT_*' gate covers
  the new dsh publish path (it runs build:official and writes a dsh client
  build record). vendor-publish runs only build:lib:host, so it is not added.
- 2026-08-10-npm-release-sequences note (en/zh/i18n): the Release-publish group
  is carried by the publish job (job-level concurrency), not the whole
  workflow; corrected the wording.
2026-08-20 15:59:40 +08:00
07akioni e483c9e30e Merge pull request #2776 from deepseek-harness/feat/table-optmize
feat(web): wrap markdown tables to the column with an overflow wide view
2026-08-20 15:46:40 +08:00
Chinesezjc 16affb84fb fix(cic): restore subscription-type gates and note table for split publish
Address the fresh review pass on PR #2798:

- ci-workflow.spec.ts: restore the subscription-type assertions the rewrite had
  dropped (issue-lifecycle pull_request types omit ready_for_review and include
  review_requested; pull_request_review types == ['submitted']) alongside the
  new step-level gate checks, so the 'tests pin the subscribed events' gate
  holds.
- 2026-08-10-npm-release-sequences note (en/zh/i18n): the three-sequence table's
  Workflow column now lists the pack and publish workflows for dsh/vendor, and
  line 114 no longer claims release.yml publishes (the dsh pack job packs the
  vendored family for verification; release-publish.yml repacks and publishes).

Follow-up for the pack-job copy drift is filed as #2816.
2026-08-20 15:41:24 +08:00
Chinesezjc abe414a7e3 Merge remote-tracking branch 'origin/master' into ci/release-check-panel 2026-08-20 15:30:47 +08:00
Yichen Jiang 4562616c9b docs(apiproxy): record that a pending question dies with the host
The pending-question registry holds the awaiting tool call's own
resolve/reject, so it is host-process memory. events.mux replays every
still-pending question on reopen, which covers a browser reload or a
reconnect, but a host restart takes the awaiting turn with it and the
reopened Session offers no composer for that question.
2026-08-20 15:29:14 +08:00
Yichen Jiang 9616790b6c feat(web): answer ask_user_question over multiple lines
A question that carried options collected its free-text answer in a
single-line input: a long sentence scrolled sideways inside one line and
Shift+Enter was inert, so an answer with structure could not be typed.
The optionless question already used a textarea, but a fixed 64-140px box
that never followed the draft.

Both shapes now answer into one AnswerField: a `textarea rows=1` sharing a
grid cell with a hidden mirror that renders the draft plus a trailing
newline and so owns the height. Soft wraps are invisible to a '\n' count,
so the mirror is what grows the box; growth stops at eight lines and the
textarea scrolls from there, keeping the choices the answer belongs to in
view. Enter still continues and submits, Shift+Enter breaks the line, and
the IME guard is unchanged.
2026-08-20 15:29:13 +08:00
Chinesezjc 63d9de0eb3 fix(cic): address gray-check PR review - official build, step-level gate, note sync
Address ds-review-bot findings on PR #2798:

- release-publish.yml: use pnpm run build:official (not build) so the dsh
  pack step's verifyBuildArtifacts (families.ts:327, readClientBuildRecord with
  officialClientBuildEnvironment) finds the official client-build record; build
  would fail Pack release tarballs on a clean runner.
- issue-lifecycle.yml: move the previous job-level if to step level on
  Create project token and Handle repository event, so approved/commented
  reviews pass (job reported success, no gray segment) without minting a
  write-capable App token or touching the board — preserving the original
  least-privilege property.
- ci-workflow.spec.ts: lock the step-level gate on the two lifecycle steps, and
  add a release-workflow invariant test (release.yml/vendor are pack-only;
  release-publish.yml/vendor-publish.yml are workflow_dispatch-only with the
  npm-publish environment and Release-publish group) to prevent #2797 recurrence.
- Update 2026-08-10-event-directed-pr-review-status and 2026-08-10-npm-release-
  sequences notes (en/zh/i18n) to the new split and step-level behavior.

Verification: ci-workflow.spec.ts 14/14, typecheck clean, all five workflows
YAML-parse, verify-translation-pairing consistent, note-format 582.
2026-08-20 15:21:59 +08:00
_Kerman e333dfc8f5 Merge pull request #2794 from deepseek-harness/fix/web-new-session-first
fix(ui-workspace): pin the current blank New Session row first
2026-08-20 14:53:08 +08:00
07akioni c9ce61136d feat(web): reveal the wide-table scrollbar on hover instead of painting it
The themed WebKit scrollbar skin keeps a wide table's horizontal bar
permanently painted. Chromium never repaints state-conditioned scrollbar
styles (hover-conditioned ::-webkit-scrollbar* rules and :hover
scrollbar-color changes both compute but never reach the painted bar,
measured headed and headless), so the hover reveal toggles overflow-x
itself: hidden at rest with a padding-bottom matching the themed bar
height, auto on hover or keyboard focus with the padding released — the
appearing bar exactly replaces the padding and nothing below shifts.
Resting hidden overflow drops Chromium's implicit scroller focusability,
so wide wrappers carry an explicit tabindex for arrow-key scrolling.
2026-08-20 14:45:15 +08:00
_Kerman 9a2dc3327d test(web): align blank-session activity snapshot 2026-08-20 14:40:09 +08:00
_Kerman b3b6407a2c fix(ui-workspace): promote new sessions only once 2026-08-20 14:21:55 +08:00
_Kerman 4ea6f4df24 Merge pull request #2730 from deepseek-harness/xtr/projection-state-schema
refactor(projection): separate host state from client views
2026-08-20 13:55:58 +08:00
hypatiamay fe12e04732 Merge pull request #1798 from deepseek-harness/codex/fix-bwrap-proc-root-escape
fix(sandbox): prevent bwrap procfs root escapes
2026-08-20 13:48:37 +08:00
Hypatia May 9003f459aa Merge remote-tracking branch 'origin/master' into codex/fix-bwrap-proc-root-escape 2026-08-20 13:38:36 +08:00
_Kerman d53292b30a fix(ui-workspace): make the blank-session pin render-only and skip masked drags
Review follow-up on #2794: the pin was applied inside nextSessionOrderAccount,
whose output syncSessionOrderAccount persists into sessionOrderByAccount, so a
reused blank stayed first forever after turning non-blank (even across
reloads). Move the pin to the render-derived layer (orderedWorkspaces,
orderedUngroupedSessionIds, ungrouped order, flat rows) so the persisted
account order is never touched, and skip drags the pin would mask (dragging
the pinned blank, or parking another row into the pinned slot) entirely,
including the Host account write.

Adds regression tests for the masked-drag skip and for the pin releasing when
the blank turns real; updates the sidebar-order Agent Note (EN + ZH) and its
pairing hash.
2026-08-20 13:25:55 +08:00
_Kerman fa39fb0881 Merge remote-tracking branch 'origin/master' into dshw/pr-deepseek-harness-deepseek-harness-2730 2026-08-20 13:25:35 +08:00
Yichen Jiang d18f4ed3de Merge pull request #2796 from deepseek-harness/worktree/mention-backdrop-perf-issue-4bd518
fix(web): key composer reference decorations by draft order
2026-08-20 13:21:29 +08:00
_Kerman f9cd580a33 Merge remote-tracking branch 'origin/master' into xtr/projection-state-schema 2026-08-20 13:21:03 +08:00
Chinesezjc a33ed4ddf8 ci: stop PR gray checks from lifecycle and release publish jobs
Remove the three skipped (gray) checks from the PR check panel without changing
functional semantics:

- issue-lifecycle: remove the job-level 'if' that skipped the lifecycle job on
  non-changes-requested pull_request_review events, so it now runs and reports
  success (the lifecycle handler already no-ops for approved/commented reviews).
  The changes-requested board transition is unchanged.
- release.yml / release-vendor.yml: drop the publish job (and its
  workflow_dispatch 'publish' input + RELEASE_PUBLISH pass-through) so it no
  longer appears as a skipped Publish-to-npm check on PRs; the files keep the
  pack job that validates tarballs on PR/push.
- new release-publish.yml / release-vendor-publish.yml: manual workflow_dispatch
  only, repack on the current tree then publish, so publication behaves exactly
  as the old publish job (explicit dispatch, uses the packed bytes) but never
  shows as a PR check.

Update the 2026-08-10 review-status note (en/zh/i18n) and the issue-lifecycle
spec assertion to match the unconditional lifecycle job.

Verification: ci-workflow.spec.ts 19/19, all five workflows YAML-parse, typecheck
clean, verify-translation-pairing consistent, note-format 582.
2026-08-20 13:15:58 +08:00
Yichen Jiang 99aad0ebcd fix(web): key composer reference decorations by draft order
The backdrop keyed each plain-text reference mark by its draft offset, so
any character typed ahead of a reference changed the key and made React
unmount the mark with its nested spans and inline glyph. Every keystroke
before a reference rebuilt every reference after the caret.

A scan derives these ranges fresh on every render, so a range carries no
identity past the render slot it occupies. The mark now keys by its index
in the offset-sorted textRefs list. Structured chips keep occurrenceId,
the identity their occurrence table owns.
2026-08-20 12:59:13 +08:00
_Kerman 98723525c6 docs(notes): record current-blank pinning in the sidebar order note
The New Session being created renders first in its account while selected,
in both order modes; opening or reusing a blank never advances its
updatedAt, so the pin keeps the reused row at the front.
2026-08-20 12:51:59 +08:00
_Kerman d0b7dea8af fix(ui-workspace): pin the current blank New Session row first
Clicking New Session reuses the workspace's existing blank session when one
exists; reuse only opens it, so its updatedAt (host: max(createdAt,
lastPromptAt)) never advances and the row kept its old creation-time
position in the sidebar. nextSessionOrderAccount now pins the currently
selected blank session to the front of its account in both Manual and Last
updated modes; non-blank navigation stays untouched.

Fixes #2788
2026-08-20 12:51:51 +08:00
Chinesezjc 297fff6e9c Merge pull request #2768 from deepseek-harness/ci/split-master-workflows
ci: split master-only jobs into ci-master.yml
2026-08-20 12:19:10 +08:00
Kaige-Gao 4e1b3e4b87 Merge pull request #2608 from deepseek-harness/fix/permission-copy-and-default
fix(web): improve permission labels and blank defaults
2026-08-20 11:58:25 +08:00
Chinesezjc 77437b1f50 docs(e2e): point keyless-gate comment at ci.yml (PR) and ci-master.yml (push)
The e2e comment said the keyless gates run in ci.yml on every push/PR; since the
split, master push is covered by ci-master.yml standby instead.
2026-08-20 11:25:21 +08:00
Chinesezjc a42102fb27 Merge pull request #2758 from deepseek-harness/knip-eval
Trim knip.json to 655 lines by removing 15 stale or glob-duplicate workspace entries. Behavior-neutral under knip's specificity-based workspace config selection; CI green, issue policy green, review threads resolved.
2026-08-20 10:59:36 +08:00
_Kerman bb79203f53 fix(docs): drop stale persist field from projection type-equiv block
ProjectionDefinition lost its persist?: boolean opt-in when every
projection unit became uniformly checkpointed, but the subsystem doc's
type-equiv paste still carried the field, so verify-type-equiv drifted
from packages/session/session-projection/src/index.ts. Remove the field
and its JSDoc from both language sides and re-record the bilingual
pairing record.
2026-08-20 10:29:56 +08:00
kingwl 82db1515fb fix(sandbox): isolate bwrap PID namespace 2026-08-20 10:05:16 +08:00
_Kerman 83a3457b4a Merge remote-tracking branch 'origin/master' into dshw/pr-deepseek-harness-deepseek-harness-2730 2026-08-20 10:04:04 +08:00
Kaige-Gao a0bfc2c3fe test: sync permission origin artifacts 2026-08-20 00:01:28 +08:00
Kaige-Gao 027b1d579f Merge remote-tracking branch 'origin/master' into fix/permission-copy-and-default 2026-08-19 23:23:54 +08:00
imccyu 141eb6fef8 Merge pull request #2783 from deepseek-harness/release/dsh-0.1.0-rc.8
release: dsh@0.1.0-rc.8
dsh-v0.1.0-rc.8
2026-08-19 23:11:50 +08:00
imccyu f1f7dc36fa release(dsh): 0.1.0-rc.8 2026-08-19 23:00:28 +08:00
imccyu b862725e74 Merge pull request #2787 from deepseek-harness/worktree-rename-team
refactor: mark Agent Teams packages as experimental
2026-08-19 22:59:48 +08:00