Commit Graph
100 Commits
Author SHA1 Message Date
imccyu 499c2e347f docs(session-projection): correct compatibility statements
Describe async generator yields, key-conflict reads, and macrotask timing as implemented, restore the API controller and mods bridge sentence in the upgrade guide, record the rejected plugin-disposal alternative, and pin the async generator behavior with a test.
2026-10-20 01:09:43 +08:00
imccyu 8f348ee760 docs(notes): fold projection compatibility into the registration handles note
Record the deprecated registration and keyed-read compatibility in the retained-reader decision instead of a separate note, and remove the 2026-10-19 compatibility note.
2026-10-20 00:42:33 +08:00
imccyu 33101ad29f fix(session-projection): log unobserved legacy registration rejections
A legacy plugin may store the registration result as a disposer or ignore it,
so a failed registration became an unhandled rejection that ends a dsh process.
The registry now attaches its own handler: once the current turn ends, a
rejection nobody observed through then/catch/finally is logged through the
calling plugin's logger while the plugin stays active, and one whose owner is
no longer loading or active is dropped. Observed rejections are unchanged.
2026-10-20 00:31:55 +08:00
imccyu f415c83579 refactor(session-projection): simplify legacy registration compatibility
- register() returns the registration's effect disposer with then/catch/finally
  attached; the original body moves unchanged into a private acquire(), keeping
  synchronous installation and the asynchronous handle handoff.
- Legacy stateOf(session, key) logs one ctx.logger.warn per key per registry;
  registration and calls to its result no longer warn.
- Containing an ignored legacy registration failure is deferred and recorded
  under Known Limitations.
2026-10-20 00:18:25 +08:00
imccyu 87ca056c0d docs(upgrade): fold registration compatibility into the projection handles guide
Move the session projection handles guide from the released v0.2.1-alpha.3
directory to the current v0.2.1-rc.2 directory and fold in the callable
registration and deprecated keyed-read notes, replacing the separate
session-projection-registration guide.
2026-10-20 00:12:00 +08:00
imccyu 85f4eca731 Merge pull request #6592 from deepseek-harness/revert-6530-feat/image-pan-and-share
Revert "feat(gui): 支持图片拖动平移与原图拖放分享"
2026-10-19 18:05:23 +08:00
imccyu a3debca9ab Revert "feat(gui): 支持图片拖动平移与原图拖放分享" 2026-10-19 18:04:17 +08:00
imccyu d5b432ac2c Merge pull request #6519 from deepseek-harness/worktree-thinkfold
fix(chat): close a reader-opened process group from its height cap
2026-10-19 14:31:28 +08:00
imccyu 473b3d360c Merge pull request #6524 from deepseek-harness/docs/ai-usage-pr-section
docs(skills): present AI usage as a badged stage table
2026-10-19 13:27:40 +08:00
imccyu 1260d96ef3 fix(chat): close a reader-opened process group from its height cap 2026-10-19 12:23:46 +08:00
imccyu d9ae93d0c4 Merge pull request #6485 from deepseek-harness/projection-summary
perf(session-projection): serve session-list rows from a summary key set
2026-10-19 11:10:40 +08:00
imccyu ab77d85f8e chore(docs): regenerate the persistence catalog 2026-10-19 10:53:13 +08:00
imccyu 76bc66b54c Merge pull request #6312 from deepseek-harness/worktree-keepreplies
fix(chat): keep every assistant reply visible when a turn folds
2026-10-19 10:50:20 +08:00
imccyu 99eacb881f fix(session-controller): drop a redundant projection cast and refresh doc graphs 2026-10-19 10:43:21 +08:00
imccyu 6292808bf9 fix(session-controller): keep the list summary contract honest 2026-10-19 10:20:10 +08:00
imccyu af2fa50f8a docs(session-projection): stop describing a removed interlock 2026-10-19 03:00:08 +08:00
imccyu 8ff30ebd96 docs(session-projection): state the shipped summary behavior 2026-10-19 02:57:09 +08:00
imccyu 76eba949bd chore(docs): regenerate the config catalog after the import shift
Adding the `ProjectionKeySelection` import to the projection cache moved its
`Config`/`inject` declaration down one line, so the config catalog's source
reference is regenerated. Only the source location changes.
2026-10-19 01:37:39 +08:00
imccyu a8f85009e5 test(web): skip blank bands between fully transparent fold rows
The fold blank matrix counted every band that no row box covered, including
a band whose rows on both sides had already faded to opacity 0. Such a band
shows the same background as those rows. Kept intermediate replies move with
the layout while closing groups stay in place, so that band could exceed the
transient limit in side/composer/steps without any visible difference.

A band now counts when a visible row borders it on either side, with the
viewport top and the composer treated as visible. A synthetic-DOM case keeps
a band beside a visible row failing the measurement.
2026-10-19 01:14:04 +08:00
imccyu f230fc2fc2 refactor(session-projection): review fixes for the summary key set
- Export `ProjectionKeySelection` (the read faces' key selection) and reuse it
  from the projection cache instead of restating the union twice. The Cordis
  catalog can now resolve the type its generated signatures reference.
- Make `wire.summary` a plain boolean: omitted means `true`, and a key whose
  map entry carries the summary mark declares `false` so the runtime key set
  and the client view type agree. The type no longer forbids a declaration.
- Describe the mark accurately: it has no runtime representation; `wire.view`
  and `viewSchema` are typed with `SessionProjectionViewValue`, which strips it,
  so the registration erase only widens the state type.
- Say plainly in the package README, the subsystem page, the client field
  comments, and the Agent Note that a list row carries the summary projection
  and never the full projection: a connected Session's store may hold more
  values, but those are outside the list contract.
- Document the summary vocabulary on the subsystem page with `ts type-equiv`
  blocks for the mark, its stripping, the excluded-key test, the summary value
  type, and the key selection; split the prose paragraph.
- Revert the behavior-neutral cache-double refactors in three specs, and record
  in the Agent Note why no upgrade guide accompanies the wire change and how a
  consumer migrates.
2026-10-19 01:13:24 +08:00
imccyu b5f0c91f3f docs(chat): describe reply visibility per Replies After Collapse choice
The group-tree JSDoc and the ui-chat README stated that every reply stays outside whole-Turn folding and named only the collapse-timing setting. They now distinguish All replies from Final answer only and link the new setting.
2026-10-18 23:18:59 +08:00
imccyu 31cca04e6c test(web): expect the 12px reply gap in seeded history
The seeded-history check measured the folded final answer 16px below the Turn control. Hidden process rows separate the two, so the answer now keeps the 12px reply gap.
2026-10-18 23:18:54 +08:00
imccyu 64a1d1e95f chore(docs): regenerate the event graph after the line shift
The producer/consumer matrix points at the declaring line of each event. Adding
the `imageLimits` JSDoc and map-entry wrap moved the `api-session/*` declarations
in `packages/api/session-controller/src/types.ts` down by four lines, so the
graph pair is regenerated. Only source locations change.
2026-10-18 23:12:27 +08:00
imccyu 8e2dd67de8 perf(session-controller): exclude the shared image limits from session summaries
`imageLimits` is a boot constant every Session shares: the unit stores no
per-Session state (`stateSchema: z.null()`, `apply: state => state`) and its
view returns `ctx.attachments.imageLimits`. A list row therefore repeated one
host-wide capability fact on every row. It now carries the summary mark like
the three log-derived units, so a summary read skips it while an opened Session
still receives it through `session/follow`, the control baseline, and
`session.projections`.

No other logic changes: the registration, its schema, its constant view, and
the host-side prompt validation keep reading `ctx.attachments` directly.
2026-10-18 23:04:29 +08:00
imccyu c458eab0a0 fix(chat): keep the reply gap on a folded final answer
A folded Turn gave its final answer the control's 16px clearance through
compactAnswer and data-turn-process-answer, because hidden process rows
keep the answer from matching the control's adjacent-row rule. With every
reply kept, the final answer no longer follows the control, so that 16px
only widened the gap above it. In both choices the margin also switched
from 12px to 16px when the closing rows became hidden at the end of a
next-message fold, moving the answer down about 4px.

A reply separated from the control by folded rows now keeps the 12px reply
gap in both choices; only a row directly following the control receives
16px, and no reply changes its spacing when a fold finishes.
2026-10-18 23:01:23 +08:00
imccyu 8598307c1e test(web): cover kept replies and the replies setting
Settings goldens gain the Replies After Collapse row; folded-Turn aria
goldens for plan review, goal turns, and turn-tail actions include their
intermediate replies. The folded layout checks measure the intermediate
reply that now follows the Turn control at the 12px reply gap.
2026-10-18 23:01:23 +08:00
imccyu 94ebbf124e fix(chat): keep every assistant reply visible when a turn folds
Whole-Turn folding chose the final answer by position, so a Turn that
continued after answering (a notice reply, record keeping, or a tool call)
hid the real answer with the process. A folded Turn now hides only its
process; every assistant-step reply row stays visible.

Settings -> General -> Replies After Collapse (ui-chat.foldedReplies,
default "all") switches back to the previous final-answer-only rule; the
choice applies immediately and is hidden in Verbose.
2026-10-18 23:01:23 +08:00
imccyu 4edfc1ad15 docs(chat): record keeping every assistant reply in folded turns 2026-10-18 23:01:22 +08:00
imccyu ef446fc85f docs(agent-notes): record the session-list summary projection decision
The note records why a Session-list row carries a summary key set instead of
every registered client view: the type-only exclusion mark with its
registration interlock, the derived stable key set reused through the existing
key-taking read faces, the nullable-wrapper rule for `todos`, and the estimated
payload effect of omitting `turnOutline`, `sessionStats`, and `todos`. It lists
the rejected alternatives (a summary-specific read face, a hardcoded key list,
post-hoc filtering, opt-in summaries, and lazy per-value reads) and the costs
the decision accepts.
2026-10-18 22:39:21 +08:00
imccyu 0e1ffcb3a6 chore(persistence): regenerate the event catalog after the line shift
The catalog pages embed the declaring source location of each documented type.
Adding the summary-exclusion import and map-entry JSDoc to
`packages/todo/tool-todo/src/types.ts` moved `TodoItem` and `todo/write` two
lines down, so both catalog languages and their pairing record are regenerated.
No type fingerprint changes: `verify-persistence-changes` still reports 65
roots matching 16 history records.

A second `gen-persistence-catalog` run is required after a schema change: the
page and the machine inventory are generated in one pass, and the page reads
the inventory as it was on disk.
2026-10-18 22:39:11 +08:00
imccyu 3a39d2b132 Merge pull request #6033 from deepseek-harness/docs/pr-declare-skill
docs(skills): add dsh-pr-description and slim the PR template
2026-10-18 22:24:11 +08:00
imccyu 0def172a02 chore(persistence): refresh source line references in the schema catalog
`docs/persistence-schema.json` records the declaring source location of every
persisted type. Adding the summary-exclusion import and map-entry JSDoc to
`packages/todo/tool-todo/src/types.ts` moved two declarations down by two
lines, so the generated catalog is regenerated. No persisted type, field, or
history record changes: `verify-persistence-changes` reports 65 roots matching
16 history records, and the release/format catalogs are unchanged.
2026-10-18 22:23:15 +08:00
imccyu 92f9e79fac perf(session-projection): serve session-list rows from a summary key set
A Session-list row no longer carries every registered client view: the three
units whose values a list row never renders (`turnOutline`, `sessionStats`,
and `todos`) are excluded, which removes the whole-log turn outline and the
figure and todo payloads from every row. An opened Session is unchanged —
`session/follow`, the `session/control` baseline, and `session.projections`
still serve every projected key.

The exclusion is one type-level mark plus one registration interlock:
`SessionProjectionSummaryExcluded<T>` marks a map entry, and
`ProjectionDefinition.wire` requires `summary: false` exactly on a marked key
and rejects it everywhere else, so the mark and the declaration cannot drift.
A nullable entry keeps `null` outside the wrapper, so `todos` stays
`TodoItem[] | null`. `summaryKeys()` returns the derived set, stable until a
registration or its disposal changes the key table, and the existing
key-taking read faces (`cachedSnapshot`, `viewCheckpoint`) accept that set
directly, so summaries need no separate read face and no per-read key copy.
`packages/api/session-controller/src/list.ts` passes the set to the live and
cold cached faces; `cachedPredecessorTitle` is untouched.

Client types only: `SessionSummary.projectionValues` narrows to
`SessionProjectionSummaryValues`, `SessionProjectionSnapshot.values` keeps
every view value with the mark stripped, and no wire field or client name
changed. The cache, subsystem page, and package README document the summary
rule and the two read faces.
2026-10-18 22:13:18 +08:00
imccyu c651566a49 docs(skills): calibrate dsh-pr-description levels and grading criteria
Set the autonomy ranges to hint 0-10, assist 15-25, pair 30-50, copilot
55-85, and auto 90-100 in the skill and the template level line, and
refill the example accordingly.

Sharpen the stage criteria where trial runs disagreed: grade design by
who supplied the adopted structure, count only the author in the first
four stages, ignore process and ordering instructions, define the main
change, keep review at n/a until a comment is handled, and separate
copilot from pair by whether every non-wording item got a human
response. Clarify the Changes categories, test evidence, disclosure
placement, language, and when to update the description.

Refs #6034
2026-10-18 22:02:42 +08:00
imccyu 85a17ec9af Merge pull request #6482 from deepseek-harness/ws-deflate
feat(api-gateway): compress Remote stream WebSocket with permessage-deflate
2026-10-18 21:57:41 +08:00
imccyu d3a6b8ba6f fix(api-gateway): state the compressed-write liveness contract
Correct the downlink-write activity contract for compressed frames: a write
that does not complete at once counts, and a frame above the threshold
deflates asynchronously so its completion always counts. The Host compresses
only its own outbound frames; uplink compression remains the peer's choice.

Stabilize the compressed-write liveness test with a 500 ms heartbeat interval
and assert the bounded half: after the downlink stops, missing Pongs still
terminate the socket.

Refs #6476
2026-10-18 20:57:55 +08:00
imccyu d2da953b5b docs(skills): address dsh-pr-description review findings
Start the template's review line as n/a, as the skill requires at PR
creation, and prompt for an Issue reference under Motivation. Read the
skill's stages only from its Stages and criteria section and reject a
stage name that does not pair one English word with a Chinese name.

Point the GIF disclosure row at record-browser-gif instead of copying
part of its list, merge the calibration notes into one TODO, replace the
design skeleton wording, and reduce the root AGENTS.md rule to a pointer.

Refs #6034
2026-10-18 20:56:28 +08:00
imccyu bf07dbc509 fix(api-gateway): drop maxPayload from the WebSocket compression change
Restore the `ws` default `maxPayload`: the pre-change mux passed no limit, so
the 1 MiB ceiling was an unrelated breaking change. Remove the exported
constant and the oversize-frame test, and drop the matching docs.

Pin the per-frame compression threshold and the accepted compressed-write
liveness consequence with regression tests, correct the queued-write
documentation, move the Agent Note to `implemented/`, and sync the Remote
duplex stream note with `websocketCompression`.

Refs #6476
2026-10-18 20:35:32 +08:00
imccyu 96adf85b5f docs(skills): rewrite pr-declare as the repository dsh-pr-description skill
Replace the pr-declare skill with dsh-pr-description, a repository-only
skill (user-invocable: false) that owns how deepseek-harness PR
descriptions are written and updated: section rules, Issue references,
test design, change-specific disclosures, and the Human and Agent Roles
section with its levels, stages, grading rules, and update timing. The
skill no longer fetches an external specification, asks the user for a
level, or adds badges.

Reduce the pull request template to a skeleton that points to the skill,
point root AGENTS.md at the skill, and make the template test check that
the template's role level line and stage placeholders match the skill.

Closes #6034
2026-10-18 20:30:14 +08:00
imccyu f881f61024 feat(api-gateway): compress Remote stream WebSocket with permessage-deflate
Add a `websocketCompression` Gateway config field (`'deflate'` by default,
`'none'` to disable) and negotiate `permessage-deflate` on `/api/remote.mux`.
Frames whose JSON text reaches 1024 characters are compressed in the mux send
path, because `ws` ignores its `threshold` option under the default context
takeover. `maxPayload` is bounded by `max(streamInboxBytes, 1 MiB)` so one
compressed frame cannot inflate past the fixed ceiling.

Fixes #6476
2026-10-18 20:07:13 +08:00
imccyu 586e3a3f59 Merge pull request #6321 from deepseek-harness/worktree-chatwhalepos
feat(ui-chat): anchor running status to the running turn tail
2026-10-18 16:00:42 +08:00
imccyu bde15f201b fix(ui-chat): keep echoes after a running Turn's empty control at the input gap
After a stop, steering still pending is claimed with the next prompt and the
AgentLoop logs it first. Once the first of those rows is durable, the
remaining echoes follow the new Turn's process control, which renders empty
while the Turn runs. The 16px clearance after that control applied to them
and moved each echo by 10px before its durable row replaced it. The clearance
now applies after a visible control to every row, and after any control only
to rows that are not local echoes, so the echoes keep the input gap.

Also state that a switch lifted within a move's duration plays the rest of
it, that the steering entrance approximates the status's previous position,
and that the runtime-context notice placement follows from the README rule.
2026-10-18 15:45:57 +08:00
imccyu 11bc10f621 test(web): refresh steering snapshots for the running status position
The running status now renders after the transcript rows and before the
steering echoes that are still waiting, so the mid-steer accessibility
snapshots list the status ahead of the interjection echo. Refreshed with
DSH_SNAPSHOT=refresh on the steering scenarios; no other golden changed.
2026-10-18 15:14:16 +08:00
imccyu 39323bbc5f fix(ui-chat): keep the steering entrance while the tail is pinned
A pinned tail zeroed both running status moves. Following scrolls absorb
output growth, so the status keeps its on-screen position for the first
output, but admitted steering still moves the status past its pending
echo below it: in a long transcript at the floor the status jumped the
height of that echo with no motion. The input-fold switch keeps zeroing
both moves; the pinned switch now repeats only the first-output slide's
structure, so the entrance after an admitted steering row keeps its
duration while the page scrolls by the added slot. Update the README and
the CSS check that the pin applies to the slide structure alone.
2026-10-18 15:14:16 +08:00
imccyu 3cea71bd94 fix(ui-chat): keep the running status moves from replaying when a switch lifts
The steering entrance and the first-output slide were selected through
`:not([data-input-fold]):not([data-chat-tail-pinned])`. Removing either
attribute added the animation name back while the structure still
matched, so a finished move replayed: scrolling away from a long running
transcript and back short of the floor, or the end of any fold batch,
faded the status in again and slid it one row. The structure alone now
names each move, wrapped in `:where()`, and the two switches only set
`animation-duration: 0s`; turning a switch off changes the duration of a
move that already finished, and turning it on completes a running one.

The tail pin now uses the test fold batches use for a tail landing:
follow intent with no unsampled reader movement, over content that
overflows the scrollport excluding fold room. A reader scroll keeps follow
intent until its 500ms sample settles while growth is not followed, so
the old pin claimed a held status there and skipped a needed move.
ChatReading recomputes the pin where follow intent and sampling settle,
the viewport recomputes it after scroll, scrollend, and each resize's own
follow scroll, reusing the scroll metrics or the resize's clean-layout
measurement, and the attribute is written only when the pin changes.

Record the decision to precompute the steering batch start in Definition
state with process-evidence and reader.previous as an Agent Note.
2026-10-18 15:14:16 +08:00
imccyu 8a3b0be658 fix(ui-chat): hold the running status still while the tail is pinned
The first-output slide set its 6px default through a selector that
outranked both variants, so a response (12px) and a new Turn's first
output after the empty process control (16px) travelled 6px and started
with a 6px or 10px jump. The default now sits on the single-class
`.running` rule, which every variant outranks.

When the transcript overflows the viewport and follows its bottom, the
follow scroll of the same resize absorbs new rows and the status keeps its
on-screen position; replaying a move there lifted the status 28-44px and
slid it back. The viewport now marks the column `data-chat-tail-pinned`
while the reader follows overflowing content, updated after each resize's
follow scroll and on scroll, and neither the steering entrance nor the
first-output slide plays under that mark. Update the README and add
viewport and CSS checks.
2026-10-18 15:14:16 +08:00
imccyu ed9a92d1a8 fix(ui-chat): slide the running status below a Step's first output
While a Step has no output yet, the running status sits directly below its
input. When the first process row, group header, or response appears, the
status now slides from that position into its slot below the row instead of
jumping. It travels the row's gap plus one font-scaled 24px row: 6px for a
process row or group header, 12px for a response, and 16px after the running
Turn's process control, which renders empty until the Turn closes. The move
reuses the steering entrance technique with the standard easing over 110ms,
runs once per input-to-output change, and is skipped under reduced motion and
during an input fold.

Group header titles take the process-row line height, so the travel matches
the inserted row in every display mode and font size. Update the README and
the CSS checks that keep the travel equal to the rows that cause it.
2026-10-18 15:14:16 +08:00
imccyu b4fcdd6e94 fix(ui-chat): keep queued steering echoes ahead of the opening submission
After a stop, steering still waiting in the next-step queue is claimed
together with the next idle submission, and the AgentLoop logs it first.
Echoes before the first transcript echo now render with that submission as
the next Turn's opening inputs above the running status, and move ahead of
the new Turn's empty process control together, so the echo order matches the
durable rows. Update the flow-tail spec and README for the echo order.
2026-10-18 15:14:15 +08:00
imccyu c538d65adb feat(ui-chat): anchor the running status to the running turn tail
Render the running status after the transcript rows and opening echoes and
before steering or Inbox echoes, so its position shows whether a waiting
steering message has been consumed. The status uses the completed Turn's
actions-row slot, its divider no longer takes layout space, and it hides once
the Turn tail is rendered.

The first steering row of each next-step claim keeps that 44px slot above it.
A state-only process-evidence Definition records each Step with durable
visible output, and the message Definition marks a claim's first human
message as a batch start when the latest earlier evidence belongs to the same
Turn. Rows claimed together stay 6px apart.
2026-10-18 15:14:15 +08:00
imccyu 687f282e86 Merge pull request #6408 from deepseek-harness/worktree/release-dsh-0.2.1-rc.2
release: next version [email protected]
2026-10-17 15:22:43 +08:00
imccyu d1b9c04067 release(dsh): 0.2.1-rc.2 2026-10-17 15:10:31 +08:00
imccyu 1600d8a1e1 Merge pull request #6387 from deepseek-harness/worktree/release-dsh-0.2.1-rc.1
release: next version [email protected]
2026-10-16 21:46:57 +08:00
imccyu c6e89e6755 release(dsh): 0.2.1-rc.1 2026-10-16 21:39:18 +08:00
imccyu ca912356fb Merge pull request #6388 from deepseek-harness/worktree/release-vendor-4.0.5
release(vendor): prepare cordis 4.0.5 stable packages
2026-10-16 21:19:31 +08:00
imccyu d9c04d6cc6 release(vendor): cordis 4.0.5, cosmokit 1.8.6, group 1.0.5, hmr 1.0.20, include 1.0.10, loader 1.0.6, logger-console 1.0.5, schemastery 3.18.5, timer 1.1.7 2026-10-16 20:53:44 +08:00
imccyu 1517a4dbca Merge pull request #6327 from deepseek-harness/worktree/release-dsh-0.2.1-alpha.5
release: next version [email protected]
2026-10-16 19:02:34 +08:00
imccyu a5e553a5ee Merge branch 'master' into worktree/release-dsh-0.2.1-alpha.5 2026-10-16 18:44:50 +08:00
imccyu e28419f15b Merge pull request #6353 from deepseek-harness/fix/sidebar-pageup-shift
fix(web): clip the collapsed right sidebar so PageUp cannot shift the frame
2026-10-16 15:49:54 +08:00
fz d614ae2769 Merge pull request #6348 from deepseek-harness/fix/ptc-prompt-alignment
fix(prompts): restore compatible PTC guidance and SDK persona
2026-10-16 15:48:04 +08:00
imccyu 8953554b5e fix(web): clip the collapsed right sidebar so PageUp cannot shift the frame
While the right sidebar is collapsed, its docked hosts are translated past
the frame's right edge and widen the frame's scrollable overflow. Outside
macOS, PageUp in a text field moves the caret and reveals it against the
start edge of every scrollable ancestor, so the `overflow: hidden` frame
scrolled sideways and the whole UI shifted left.

Clip the panel's overflow. `overflow: clip` does not make the panel a scroll
container and does not clip the fixed-position floating panels, whose
containing block is the viewport; the DockLayout ancestor contract now says so.

Fixes #6341
2026-10-16 14:21:08 +08:00
imccyu 085f3c6a58 Merge pull request #6339 from deepseek-harness/ci/master-baseline-canary-1016
test(web): keep page timers running under the pinned fixture day
2026-10-16 12:41:53 +08:00
imccyu 4cea5c36d2 test(web): sweep the Host clock distance in the pinned-clock regression
The page clock failure depended on the real-to-fixture distance modulo
2^32 ms, so a regression run on today's date alone passes against the old
fixture for half of every period. The test now shifts the Host clock across
eight phases of that period; the page.clock fixture fails every phase,
either with stopped page timers or with a Date that does not advance.
2026-10-16 12:23:10 +08:00
imccyu 81803f7ca5 test(web): keep page timers running under the pinned fixture day
pinHostClock replaces Date.now in the Vitest worker, where Playwright's
server also runs. page.clock.setFixedTime therefore recorded the fixture
day, and after a navigation the page clock replayed the gap to the real
day. The resulting negative timer delay was truncated to a 32-bit integer
and, from 2026-10-15T13:45:20Z, became a delay of weeks that stopped every
page timer, failing the steering and seeded-history suites.

pinBrowserClock now replaces only the page's Date so it reads the fixture
day while native timers and animation frames keep their real schedule; a
regression test navigates twice with both clocks pinned.
2026-10-16 12:07:47 +08:00
imccyu 5026df8fd1 Merge pull request #6250 from deepseek-harness/worktree-optbundles
feat(webworker): offer optional bundles in the preview and fetch lazy chunks on demand
2026-10-15 12:17:34 +08:00
imccyu 6e43ad6bb1 Merge pull request #6164 from deepseek-harness/fix/subprocess-linux-probe-once
fix(subprocess-local): probe Linux native containment once and support systemd before v254
2026-10-15 11:32:27 +08:00
imccyu 18a22f73b2 Merge pull request #6228 from deepseek-harness/worktree-versionmismatch
feat(client-modules): prompt to reload when the host release changes
2026-10-15 11:31:54 +08:00
imccyu 93d2ad2d25 feat(webworker): boot the preview from the shipped profile and fetch lazy chunks on demand
The packer images the web template bundles, every optional bundle, and an installation manifest instead of a dumped composition, and the Worker boots that profile through app-boot like dsh web. Package-local lazy client chunks move into content-addressed archives that the VFS fetches on first asynchronous read; client-modules reads chunks asynchronously.

The Worker replaces node-addon-require-builtin with Node v24.18.0 internal-module interfaces and reports Node 24, so plugin metadata, the Cordis Loader, and HMR reach one cascaded loader backed by the Worker loader. Resolution failures carry Node error codes, the empty load cache lets HMR apply profile changes, and every optional bundle switches on and off live. Platform stubs throw ERR_FEATURE_UNAVAILABLE_ON_PLATFORM.
2026-10-15 11:30:45 +08:00
imccyu bf1a2bf69c fix(inspector): serve the Client bootstrap while the Inspector Worker starts
A Client plugin loaded after the page starts fetches its bootstrap once. The Host now registers that route before starting the Worker and answers once the Worker is ready, so enabling Developer Tools on a running page opens the bottom DevTools without a reload. A failed start answers 503.

When the platform cannot run the Worker (ERR_FEATURE_UNAVAILABLE_ON_PLATFORM), the Host warns once and stays active with only the 503 bootstrap route; serve-static and open load after the Worker starts. Every other startup failure still fails the fiber.
2026-10-15 03:56:26 +08:00
imccyu 22c51728ed fix(dependencies): check experimental packages under the published dependency policy
verify-package-dependencies now covers every packages/*/* manifest, experimental included, and reads each package's tsdown build entries so Worker and child-process entries count as Host runtime sources. Experimental Client packages no longer declare browser and type relationships as peers.
2026-10-15 03:56:26 +08:00
imccyu b77cc1c0f2 feat(gates): reject module-scope await in package sources
Package modules that other code imports must not suspend evaluation at module scope. A syntax-aware gate scans packages/*/*/src and excludes only executables (a shebang or a package bin target). The SenseVoice worker, the SSH helper entry, and the Inspector worker entry now run an explicit main().
2026-10-15 03:56:25 +08:00
imccyu ba090a4b59 fix(ui-settings-general): focus Not now when the release prompt opens 2026-10-15 02:26:28 +08:00
imccyu a7a40f93d9 fix(client-modules): compare host releases before parsing the graph 2026-10-15 01:35:28 +08:00
imccyu f52abc04fa feat(client-modules): apply no plugin update from another host release 2026-10-15 00:51:20 +08:00
imccyu da5e23e8e8 refactor(subprocess-local): decide Linux containment in a testable selector
The provider's Linux decisions now live in LinuxScopeSelector, a state machine
over injected observations: the deep probe, the user-manager listener, the
manager confirmation, and the systemd-run binary identity. Each decision
carries its reason and probe trigger, the runtime logs it at debug level, and
table-driven scenarios cover every transition.

- A positive verdict probes again when the systemd-run found through PATH
  changes device, inode, size, or modification time, so an in-place upgrade
  past v254 cannot reuse options that no longer keep argv literal.
- The listener is read before the probe, so a manager that starts during a
  failed probe counts as a new listener.
- The kernel socket table is decoded as UTF-8, matching runtime directories
  outside ASCII.
- LinuxScopeNotStartedError drops its unused code field.
2026-10-15 00:51:05 +08:00
imccyu 71de43d8ee fix(subprocess-local): probe Linux again after a scope never starts or a new manager listens
A cached positive verdict let a hung user manager that still listens fail every
later command, and a cached negative verdict ignored a manager that started
later until the provider restarted.

- A scope launch whose bootstrap never consumed its launch request now fails
  with LinuxScopeNotStartedError, and the runtime clears the verdict it
  launched under, so the next eligible spawn probes again and records the
  fallback when that probe fails. A generation counter keeps launches from a
  superseded probe from forcing another probe.
- After a negative verdict, the runtime records the /proc/net/unix listener on
  $XDG_RUNTIME_DIR/systemd/private and probes again only when a different
  listener, meaning a new manager instance, appears.
2026-10-15 00:14:50 +08:00
imccyu 514e8893b5 test(subprocess-local): harden the socket-table checks and state their scope
The real-socket test rejects on a listen error instead of hanging, the table
fixture comment names the accepted-connection row it models, and the remaining
linux-scope module mocks provide confirmLinuxManager. The README notes that
the socket-table read matches only listeners in the same network namespace and
costs time proportional to the table size.
2026-10-14 19:53:13 +08:00
imccyu ac5a3e336c test(ui-settings-general): read the release prompt inject face without an unknown cast 2026-10-14 19:39:47 +08:00
imccyu c97f840c89 fix(subprocess-local): confirm the user manager from its listening socket
systemd closes the private listening socket on shutdown without unlinking its
path, so the socket file outlives a manager stopped in place. The fast path now
reads /proc/net/unix, where the kernel lists a bound socket only while a
process holds it open, and accepts the manager only when a process listens on
$XDG_RUNTIME_DIR/systemd/private; otherwise the systemctl query decides. The
scope startup error names an unreachable manager as the cause, and the spawn
test again asserts that Windows launches never reach the fallback.
2026-10-14 19:34:14 +08:00
imccyu 055c7d7a74 fix(subprocess-local): confirm the user manager before each cached Linux scope launch
Without a per-spawn check, a user manager that stops after a positive probe,
such as after a logout without lingering, made every later scope launch fail.
Each eligible spawn now confirms the manager: its socket file at
$XDG_RUNTIME_DIR/systemd/private disappears when the manager stops, so its
presence answers with one stat; otherwise the restored systemctl --user show
query decides and the spawn falls back while it fails. A crashed or hung
manager that leaves its socket file still fails the scope launch with the
existing restart hint.
2026-10-14 19:14:29 +08:00
imccyu 7c9e54b3ef feat(client-modules): prompt to reload when the host release changes 2026-10-14 19:11:22 +08:00
imccyu f12bf31c4a docs(notes): record the host release change refresh prompt 2026-10-14 19:10:48 +08:00
imccyu c218e79102 docs(subprocess-local): name the systemd 236 floor for --collect
The probe always passes --collect, which systemd-run rejects before v236, so those hosts use the fallback regardless of the --expand-environment=no retry.
2026-10-14 18:05:02 +08:00
imccyu d73ad23353 fix(subprocess-local): name the recovery when a cached Linux scope fails to start
With the probe cached for the provider lifetime, a user manager that stops
after a positive probe makes every later scope launch fail. The startup error
now says to restart the provider to probe native containment again. The README
no longer lists older user-systemd among fallback hosts and notes the second
probe attempt for a systemd-run that rejects --expand-environment=no.
2026-10-14 17:50:29 +08:00
imccyu 39874e62ba docs(subprocess-local): state the provider-lifetime Linux probe and its cost
The README says the provider also keeps a failed or timed-out first probe and
names the user manager as reachable rather than live, since it is checked once.
The probe cache documents why no later spawn repeats the probe, and the spawn
test now starts two Windows commands to match its per-spawn Job recheck title.
2026-10-14 17:32:15 +08:00
imccyu 0fffa2432a fix(subprocess-local): support systemd before v254 for native scopes
systemd-run before v254 rejects --expand-environment=no, so the scope probe
always failed and those hosts used the weaker fallback. Its scope mode never
expands argv, so the probe retries without the option only when systemd-run
reports it as unrecognized, and scope launches reuse the probed options.

systemctl before v252 rejects --kill-whom. Use --kill-who, the older
spelling, which newer systemctl accepts as an unambiguous prefix.
2026-10-14 17:24:14 +08:00
imccyu 404e64b435 fix(subprocess-local): probe Linux native containment once per provider
Every Linux spawn() and spawnTerminal() ran a synchronous spawnSync probe
before launching the command: the full systemd-run scope probe until it first
succeeded (a failed verdict was never cached), then a systemctl manager recheck.
spawnSync blocks the host event loop until the probe exits, so hosts without a
usable user manager paid the full probe on every grep, glob, and shell command.

Keep the first verdict, positive or negative, for the provider lifetime and
drop the per-spawn manager recheck.
2026-10-14 17:24:14 +08:00
imccyu a941635df3 Merge pull request #5945 from deepseek-harness/worktree/client-control/operator-connect
feat(connection): scope the connect handshake to one operator
2026-10-14 16:56:53 +08:00
imccyu c233ca3df5 fix(typert): recognize Cordis Context across built copies 2026-10-14 14:44:01 +08:00
imccyu 1d0ff1d2e4 test(snapshot): let inspect fixture receive events 2026-10-14 14:44:01 +08:00
imccyu b679a3aa32 docs(typert): include Peer interaction participation in type excerpt 2026-10-14 14:44:01 +08:00
imccyu fd1b8bd095 test(gateway): supply interaction mode for stream Peer fixture 2026-10-14 14:44:01 +08:00
imccyu 10672c4c24 Integrate Peer interaction scope with Remote access 2026-10-14 14:44:01 +08:00
imccyu d3de1613b6 Bundle shared Clients separately for browser and Node 2026-10-14 14:44:00 +08:00
imccyu 88ee3d2961 test(connection): cover operator lifecycle failures and update fixtures 2026-10-14 14:44:00 +08:00
imccyu 0f7ac58213 feat(connection): isolate API operators without changing browser identity 2026-10-14 14:44:00 +08:00
imccyu 30d48c4d49 test(client): share dynamic import bundle fixture 2026-10-14 14:44:00 +08:00
imccyu e137ebaaa1 Build shared Client bundles independently for Node and browser 2026-10-14 14:43:59 +08:00
imccyu a2486e8243 Merge pull request #6160 from deepseek-harness/worktree-listperf
perf(session): speed up @ session candidates and session listing
2026-10-14 10:52:25 +08:00
imccyu d1f4261356 Merge pull request #6158 from deepseek-harness/worktree-foldmidscroll
fix(ui-chat): fold next-message work details on one frame clock
2026-10-14 10:52:10 +08:00
imccyu a6e9071b82 fix(ui-chat): continue batch members from their current size
A revealing row that ran on its own CSS transition and was then taken
over by a batch entered the landing twice: the measured starting layout
held the height it had already reached, and the growth amount added its
full height again while the batch restarted it from zero. The extra
height raised the tail target above the real floor and stayed as bottom
room. Rows revealed while a batch ran kept their own transitions and were
taken over this way by the next batch.

- A row that starts revealing while a batch runs waits at zero size like
  a held closing row; the next flush drives it in a batch or starts its
  own transition when nothing closes.
- A batch continues every member from its current size: closing rows
  shrink from the height they have now, and revealing rows grow from the
  height they reached, so only the remaining growth enters the landing.
2026-10-14 03:38:35 +08:00