Commit Graph
100 Commits
Author SHA1 Message Date
imccyu 36e8141145 chore(lint): bring .tsx files into the eslint, lefthook, and jscpd lanes
.tsx sources and specs were invisible to every lint surface: the eslint
flat-config globs, the lefthook staged-file glob, and the jscpd clone
scan all matched *.ts only. Widen the five eslint file groups (source,
test, client-test, sonar, formatting), the pre-commit glob, and the
jscpd format/pattern to cover .tsx.

Existing .tsx files predate these lanes; follow-up commits on this PR
clear the backlog they surface.
2026-07-27 21:42:08 +08:00
imccyu 4feb657b45 Merge pull request #754 from deepseek-harness/fix/question-composer-row-shrink
fix(ui-question): stop option rows absorbing the capped card's shortfall
2026-07-27 21:19:10 +08:00
imccyu 9b23fe84c1 Merge pull request #751 from deepseek-harness/feat/workspace-native-folder-picker
feat(gui): add native workspace folder picker
2026-07-27 20:59:50 +08:00
imccyu 5cae7874f6 git: add .orig to gitignore 2026-07-27 17:27:41 +08:00
imccyu 67ad0eb887 Merge branch 'master' into fix/remove-orig 2026-07-27 17:23:03 +08:00
imccyu e8cbf6cc72 fix: remove orig 2026-07-27 17:22:01 +08:00
imccyu d8ce036295 Merge pull request #738 from deepseek-harness/feature/delete-workspace
feat(web): delete workspace registrations
2026-07-27 17:08:48 +08:00
imccyu 0052ea49ff Merge branch 'master' into feature/delete-workspace 2026-07-27 16:59:28 +08:00
imccyu 4918872c5c Merge pull request #740 from deepseek-harness/feat/todo-tool-ui
feat: optimize ui of todo tool
2026-07-27 16:59:18 +08:00
imccyu cbcb911781 Merge branch 'master' into feat/todo-tool-ui 2026-07-27 16:55:35 +08:00
imccyu 50ec3b1db0 Merge branch 'master' into feat/todo-tool-ui 2026-07-27 16:54:34 +08:00
imccyu 5b81025b58 Merge branch 'master' into feature/delete-workspace 2026-07-27 16:52:24 +08:00
imccyu 5f589da54d Merge pull request #706 from deepseek-harness/markdown-ui
feat: optimize chat ui
2026-07-27 16:08:48 +08:00
imccyu 52985d688d Merge branch 'master' into markdown-ui 2026-07-27 15:58:13 +08:00
imccyu 228d503230 fix: code-mode fixture snapshot 2026-07-27 15:49:37 +08:00
imccyu b8d7938498 Merge branch 'master' into markdown-ui 2026-07-27 15:44:30 +08:00
imccyu 0a7c8a284d chore 2026-07-27 15:44:10 +08:00
imccyu b241d4332c Merge branch 'master' into markdown-ui 2026-07-27 15:23:13 +08:00
imccyu e14c2aea3d Merge pull request #497 from deepseek-harness/web2-todo
feat(gui): todo display — TodoPanel plan strip + dedicated todo_write tool row
2026-07-27 15:22:03 +08:00
imccyu 8dce7981c4 refresh code-mode trajectory ordinals for the todo fixture turn
Turn 65 (todo_write) at the fx-alpha tail slides the 50-message history
window: two head-of-window messages drop out, so every trajectory cell
ordinal shifts down by two. Timing, labels, and cell content are unchanged.
2026-07-27 11:38:02 +08:00
imccyu f2a9f4a40e retire the stale ACP plan-mapping claim in the todo note
The automation-only ACP bridge deliberately omits todo presentation (its
edge test asserts plan updates are omitted; the todo-write tool note records
the mapping's retirement). Chinese counterpart updated, pair re-recorded;
the TodoPanel header comment drops the same claim.
2026-07-27 10:43:49 +08:00
imccyu 35ce35d8a6 Merge branch 'master' into web2-todo 2026-07-27 10:37:34 +08:00
imccyu 8d1a3b89c7 fix runtime README pairing record left with merge conflict markers
The master merge committed the i18n.yaml with unresolved conflict hunks
(carried over from the adapt branch's own master merge); re-recorded via
verify-translation-pairing --write. 518 pairs consistent.
2026-07-27 10:25:12 +08:00
imccyu 83d3179d34 disambiguate the snapshot's workspace-group lookup
Latest master seeds a blank session also titled "fixture"; anchor the
session-tree lookup on the expandable group row instead of the first text
match.
2026-07-27 10:14:37 +08:00
imccyu dadb92302f adapt todo display to the slash/input/session architecture
- TodoPanel mounts through a 'conversation.input.dock' list entry
  (todoDockEntry, QueueDock posture, order -1 above the queue rows) instead
  of a ConversationRoot hardcode; the inner component is unchanged and takes
  useSession from the dock entry's standard kit.
- The verify-todo-display.mjs chromium probe is replaced by an assembled
  keyless snapshot (apps/web/tests/todo-display.snapshot.ts, the
  code-mode-fixture idiom) pinning the TodoRow summary/state, the dock
  panel content, and the collapse round-trip over built bundles.
- Fake snapshots across specs gain the todos field; bilingual note/READMEs
  updated for the dock mount and the snapshot.
2026-07-27 10:09:42 +08:00
imccyu 9d63d75a6f Merge remote-tracking branch 'origin/master' into web2-todo
# Conflicts:
#	packages/client/connection/src/client/fixture.ts
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/README.md
#	packages/client/runtime/README.zh.md
#	packages/client/runtime/src/client/index.ts
#	packages/client/runtime/src/client/sessions/session.ts
#	packages/client/ui-conversation/src/client/apply.ts
#	packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx
#	packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx
#	packages/client/ui-conversation/tests/chat-toolview-slot.spec.tsx
#	packages/client/ui-conversation/tests/chat-view.spec.tsx
#	packages/client/ui-conversation/tests/gate-branch-tails.spec.tsx
#	packages/client/ui-conversation/tests/skeleton.spec.tsx
#	packages/client/ui-trajectory/tests/views.spec.tsx
2026-07-27 10:07:51 +08:00
imccyu b044fe626c chore 2026-07-27 09:06:19 +08:00
imccyu 7a5576a4a8 style: reshape the fixture session guard under max-len and indent rules 2026-07-27 09:02:50 +08:00
imccyu 1b49666cd5 Merge branch 'master' into worktree-slash-split 2026-07-27 08:54:56 +08:00
imccyu dd2d9ca50a refactor: dedupe the jscpd clones; drop the baseline loading gate
- Extract the shared New Session action into WorkspacesService.startSession
  (sidebar button and workspace browser both delegate; recent-Workspace
  targeting and the no-workspace clear live in one place).
- Fold the chip-insertion transaction shared by insert-ref and paste-upgrade
  into one InputMachine helper.
- Share the fixture's session-not-found guard across the sessionId-addressed
  catalog routes.
- Drop the AppFrame baselines-ready loading gate (user ruling: the bare
  status line reads worse than the shell's own pending rendering); both
  column occupants mount from first paint.
2026-07-27 08:51:05 +08:00
imccyu 084e64744a test: defer coverage for the four new client plugin entry files
The exhaustive lane imports the loader-facing src/index.ts of the new
ui-slash/ui-command/ui-skill/ui-subagent packages without executing them
(0% functions); same client-lane deferral as their client/ halves.
2026-07-27 08:30:57 +08:00
imccyu ecdaf0dc24 test(web): connect a Workspace in the e2e boot path and refresh goldens
The startup-selection flow leaves a fresh world (no Workspace) in the
locked view state, so every e2e scenario that types into the composer
now connects one first via the shared connectFreshWorkspace helper
(hero picker create-by-name dialog; the default 'workspace' name keeps
the session-header cwd assertions intact).

Golden refreshes carry the current composer chrome: the plan/model
control seats are empty until their owning plugins register (the seats
shipped without occupants on this branch), the sidebar shows the
connected workspace group pre-send, and the bash details material
renders Input/code/Output as separate nodes. The cancel scenario polls
the frozen-partial swap instead of counting synchronously — the abort
frame reaches the browser over SSE after the host settles.
2026-07-27 08:25:00 +08:00
imccyu 250e2415ae test(web): re-anchor snapshot suites to the startup-selection boot flow
The startup Workspace auto-selection (wired in cd8ed43e4) changed the
boot landing: with any Workspace present the client connects its blank
session directly instead of resting in the locked view state.

- workspace-flow: New Session now reuses the blank session in place
  (no locked interlude); the failed-attach scenario asserts the actual
  recovery semantics — the host publishes the session before rejecting
  attachment, so the next connect reuses it into the hero (connect
  failures log to console, there is no view-state alert surface); the
  rejected-prompt scenario anchors on the sidebar New Session row since
  a send attempt leaves the hero for the engaging retry chrome.
- slash-flow: drop the stale i18n PLUGINS row (the package is locale).
2026-07-27 07:48:07 +08:00
imccyu cbe8735d7c feat(web): wire startup Workspace selection and sync docs
- Mount WorkspacesService.startInitialSelection in the runtime apply (the
  one-shot baseline follower shipped in 98633b5aa without a caller): a
  restored current session wins, an explicit clear stays cleared, a failed
  connect retries on the next baseline projection.
- Cover the policy in client-apply and the assembled workspace-flow
  snapshot; startup now lands in the recent Workspace's blank session, so
  the draft-carry scenario starts from the hero directly.
- Bring docs along: startup-selection paragraphs in the session-scope RFC
  note (both languages), bilingual README pairs for the four new client
  packages, doc-graph regeneration with client-declared events exempt from
  the dispatcher requirement (client dispatch sites are structurally
  invisible to the host-side ts.Program), and pairing re-records.
2026-07-27 06:24:09 +08:00
imccyu 22e4c05e69 style: reflow the send-committed event doc under max-len 2026-07-27 05:36:01 +08:00
imccyu 10bb708eb7 fix: review-bot findings on the provider-hosted shell
- Keep ConversationSession mounted for blank sessions (chrome-less) so the
  draft-persistence mirror stays bound in the hero; hero typing reaches the
  chat store again.
- Restore the baselines-ready gate in AppFrame: empty boot snapshots no
  longer flash the New Workspace hero before either baseline lands.
- Commit ordinary sends through the machine (send-committed event +
  Shell.commitSend): undo can no longer resurrect already-sent content on
  the default-sink path.
- Give the production InputMachine a real wall clock so the typing-run
  merge window actually expires.
- Coalesce concurrent connectWorkspace creates per workspace: the summary
  has no cwd until the host frame lands, so a second New Session inside
  that window minted a duplicate hidden blank session.
2026-07-27 05:07:59 +08:00
imccyu 45ad06ece9 test: defer per-file coverage for the new slash/command client files
Same client-lane debt as the existing GUI exclusions (TODO(gui)): the new
ui-slash/ui-command/ui-skill/ui-sidebar/ui-workspace client files and the
connection fixture keep their uncovered branches until the browser-grade
harness lands.
2026-07-27 04:51:07 +08:00
imccyu 45eee34faf test: adapt suites to the provider-hosted conversation shell
Test-side catch-up with the session-maybe conversation architecture: the
provide channel's descriptor shape and maybeProvideInfo in fakes, the shared
chat-store handle asserted on conversation.session (the session-maybe shell
carries no store), startSession fakes exposing the workspace list snapshot,
strict session slots declining (not throwing) without a session, AppFrame's
removed empty seat and loading gate, and the hero draft asserted on the
machine (the chat-store mirror binds with ConversationSession). Plus three
lint fixes (max-len split, boolean-compare, arrow-parens/unbound-method).
2026-07-27 04:28:42 +08:00
imccyu d1e43fcd8c style: typed queries in slash-flow snapshot, widen chat-apply key union 2026-07-27 04:13:05 +08:00
imccyu f6396f2573 style: fix lint across client packages
eslint --fix autofixes plus manual repairs: max-len line splits
(fake-api handlers, notifier/slots JSDoc, spec signatures), charAt over
non-null-asserted indexing in slash detect/menu cores, Array.from for
code-point capping, typeof assertions for unbound-method in specs,
generic getByRole for the send-button cast, effect disposer void-wrap in
command register, and dropped unused type imports.
2026-07-27 04:13:00 +08:00
imccyu a27be43ac1 feat: slash system / input service / agent scope 2026-07-27 03:28:39 +08:00
imccyu 92700c2375 Merge pull request #644 from deepseek-harness/worktree-websettings
Slot-composed settings surface with locale and theme preferences
2026-07-26 13:59:14 +08:00
imccyu 0fe9ff888d Merge origin/master into worktree-websettings
ui-sidebar shell landed on master (#643: geometry-only shell, the
browsing region moved to the sidebar.workspaces slot); this branch's
sidebar.settings foot seat re-applies on top — the hardcoded foot row
becomes the seat, the seat rides the railIn crossfade, and the shell
spec's renderSlot stub key-splits region vs settings.
2026-07-26 13:15:57 +08:00
imccyu fabc843c22 docs(gui): regenerate graphs for the returning ui-settings-general package 2026-07-26 12:48:30 +08:00
imccyu 7e20322c40 docs(notes): retitle the rejected alternative as per-feature satellite packages
The rejected shape is a settings satellite per feature; the ownerless
copy stays with ui-settings-general, which carries no feature surface.
2026-07-26 12:43:17 +08:00
imccyu a04a223bab refactor(gui): copy-free settings shell; ui-settings-general owns ownerless copy
The shell is now a pure composition face: no dictionaries, no locale
dependency, and three new chrome content seats (settings.trigger /
settings.header / settings.close) whose slot content also carries the
accessible names (trigger text, dialog aria-labelledby, visually hidden
close label). ui-settings-general returns as the owner of copy that
belongs to no single feature: chrome content, the General section with
its item slot, and the settings dictionaries. Slot types split homes —
trigger/header/close/section live in the shell contract; the
settings.general.item entry moves to the locale package (the common
dependency of every item registrant), with ui-theme consuming it
through a re-export seam; the verbatim duplicate merges are gone and
the dependency graph is a clean DAG.
2026-07-26 12:40:17 +08:00
imccyu 9a4be33899 docs(notes): record slot-declaration-as-service as future work
deferRegistration() stays the shipped form; the note pins the follow-up
direction (bridge declarations into slot:<name> services, migrate
registrants to nested ctx.inject, delete the helper) and the boundaries
a separate PR must settle.
2026-07-26 12:09:38 +08:00
imccyu 08251eb180 Merge branch 'master' into worktree-ws-more 2026-07-26 11:20:05 +08:00
imccyu 15c0b6290b docs(notes): state the rejected per-section split without implementation history 2026-07-26 11:18:46 +08:00
imccyu a04ce7afbb refactor(client): shared declaration-aware registration deferral
The five settings-surface registrants carried near-identical
spec-check/ledger-judge/subscribe scaffolding (three jscpd clones);
ui-slots now owns deferRegistration() — ledger-judged presence, refresh
for registrant-localized labels, one-call disposal — and every
registrant shrinks to its registration body.
2026-07-26 04:15:56 +08:00
imccyu c5d323e8e5 fix(gui): follow-ups for the feature-owned settings surfaces
The ui-layout apply bench provides a real LocaleService before the
theme plugin boots (ui-theme now injects slots/locale to register its
Appearance row); drop locale's unused clsx dependency.
2026-07-26 03:22:35 +08:00
imccyu 0c9f310008 test(gui): apply-level suites for the feature-owned settings rows
Locale and ui-theme apply coverage on a real Context + SlotCore:
dictionary assembly, declaration-aware registration both ways,
inject-time getter re-sync, service write-back through the event flow,
HMR collapse recovery, and teardown reclamation. Four settings-surface
packages sit at full per-file coverage.
2026-07-26 02:57:54 +08:00
imccyu a3ee5dd8a0 docs(gui): regenerate graphs and sync the note's English pair
Generated docs follow the ui-models rename and the removed
ui-settings-general package; the English note side picks up the
feature-owner self-registration doctrine.
2026-07-26 02:54:29 +08:00
imccyu 23a60ade67 refactor(gui): features register their own settings surfaces
Settings collaboration direction (recorded in the note): the shell only
provides composition faces — feature plugins register themselves. The
General section moves into the ui-settings shell (order 0, skeleton
rows) and declares the settings.general.item list slot; locale registers
the Language row and ui-theme the Appearance row (each with its own
store mirror, dictionaries, and ledger-judged deferral); the
ui-settings-general package is gone. ui-settings-models becomes
ui-models — a feature package that contributes its Settings section
rather than a settings-owned satellite. The item-slot SlotMap entry is
authored in the ui-settings contract and repeated verbatim in
locale/ui-theme (reference-cycle avoidance; declaration merging keeps
the copies identical).
2026-07-26 02:51:36 +08:00
imccyu b2d8815a34 test(llm-mock-server): poll for the client-closed outcome
The fixed 5ms sleep raced slow CI runners (the server observes the socket
close asynchronously); vi.waitFor polls until the outcome lands.
2026-07-26 02:29:13 +08:00
imccyu 6cc68baddf Merge remote-tracking branch 'origin/master' into worktree-ws-more 2026-07-26 02:26:27 +08:00
imccyu ad419065a0 test(web): stop pre-clicking the fixture group in the title snapshot
The Intent's current-group effect already expands the target workspace;
with intent no longer forcing expansion, the header click collapsed it.
2026-07-26 02:10:59 +08:00
imccyu 4ae86001a5 style(web): wrap a long tree.ts doc line 2026-07-26 02:03:05 +08:00
imccyu d147673dfd refactor(apiproxy): share the workspace-not-found response
The rename/insertSessionBefore lookups tripped the cross-file clone gate;
one helper owns the error row now.
2026-07-26 01:58:53 +08:00
imccyu 9fc8a616a9 test(web): close the per-file coverage gate for the session-list surfaces
New and touched sources reach the CI per-file 100% thresholds: HoverCard
(timers, placement clamp, disabled guard), Menu label/danger/pointer-leave
branches, WorkspaceBrowser (mode switch, search, rail icons, rename dialog,
drag), rows and tree derivations, the workspace fixture stubs, the rename/
insertSessionBefore wire rows, and the entity move semantics. HoverCard's
position state narrows to {left, top} (equivalent refactor, no behavior
change).
2026-07-26 01:48:36 +08:00
imccyu 2ee4cda066 fix(client): lint conformance for the preference services
Replace optional chains on always-present globals with the repo's
typeof guards (store.ts precedent), drop the non-null assertion by
failing loud on an impossible registry miss, and fix two arrow-parens
slips; cover the no-localStorage boot path in both service suites.
2026-07-26 01:30:46 +08:00
imccyu ba5c136871 docs(notes): record the session-list browsing and manual-order decisions 2026-07-26 01:30:14 +08:00
imccyu 8cc46e6025 docs(notes): export settings note contract types
Both sides of the bilingual pair compile in one doc-typecheck program;
module-scoped (exported) declarations keep the shared identifiers from
colliding across the pair.
2026-07-26 01:16:39 +08:00
imccyu f1b877e3c6 fix(web): review-bot round one + regenerate doc catalogs
- rename same-title no-op moves inside the serialized creation chain
- insertSessionBefore maps only the typed WorkspaceMoveInvalidError to
  workspace-move-invalid; storage failures stay internal
- workspace upsert rejects snapshots older than the installed projection
- flat-mode empty state shows when the query hides the intent row
- intent row no longer forces group expansion; header twist stays live
- group-by menu rides a portal; menu clicks stop propagating to the row
- intent row uses the same single-slot indent in both list modes
- regenerate cordis api/catalog + doc graphs
2026-07-26 01:11:17 +08:00
imccyu c5cc348816 test(gui): settings package suites; ledger-judged re-registration
Full per-file coverage for the three settings packages: invariant
companions, store mirroring with revision guards, behavior-shaped
section/shell specs (props-fed, real store engine), and apply-level
suites on a real Context + SlotCore covering declaration-aware deferral
and HMR collapse recovery. All three registrants now judge presence on
the slot ledger instead of a local disposer, which went stale when a
parent redeclaration cascade removed the entry (ds-review-bot finding);
the locale re-register path keeps the same idempotence.
2026-07-26 01:10:23 +08:00
imccyu b1b180e098 fix(gui): CI gate repairs — docs, coverage, HMR re-registration
Regenerate the module-graph/config-catalog/event-graph docs for the
locale rename and new packages; allowlist the three settings READMEs;
complete the RFC code block and add its English pair. Cover the
ThemeService media-query paths (stubbed matchMedia) and mark the
unreachable registry fallback. General section re-registration now
judges presence on the slot ledger instead of a local disposer, which
went stale when an HMR collapse removed the entry.
2026-07-26 00:57:21 +08:00
imccyu ea8b1178cd feat(web): session list one-list, hover card, row menus, rename, manual ordering
Sidebar session list grows the figma 239-10458 feature set and the
workspace/session browsing region moves wholesale into ui-workspace:

- Group-by menu (WorkSpace / In one list): flat mode lists every session
  top-level, strictly newest-first; the choice persists across reloads.
- Session rows get a 500ms hover detail card (title / relative time /
  status line) and a ... menu (Rename / Fork session / Delete session,
  visual-only for now); workspace headers get ... with Rename (wired) and
  Delete workspace (visual-only).
- workspace.rename RPC: trims, rejects duplicate titles on the create
  chain (workspace-name-conflict), no-op on same title; modal dialog with
  client-side duplicate pre-check.
- workspace.insertSessionBefore RPC (DOM-insertBefore semantics, omitted
  anchor appends): HTML5 drag reorder of root sessions inside a workspace
  group; order truth stays host-side, the view refreshes from the
  response/changed frame.
- Activity pinning removed: the session/event touchSession chain is gone;
  workspace accounts are manually owned (new sessions prepend, explicit
  reordering only). Contracts and tests updated, api catalog regenerated.
- ui-sidebar reduced to the column shell (brand, fold state machine, New
  Session, Settings) exposing one sidebar.workspaces hole with a two-fact
  owner share {wide, expandSidebar}; ui-workspace owns the whole region
  (header, search, grouped/flat lists, dialogs, drag) plus the picker via
  a shared WorkspaceCreateFlow. The old sidebar.workspace picker slot and
  its deferral indirection are gone.
- ui-primitives: Menu gains label entries, danger rows, and
  closeOnPointerLeave; new HoverCard (portaled, open-delay, disabled
  guard). Hover card and row menu never coexist.
2026-07-26 00:55:17 +08:00
imccyu 7bcb005f29 Merge branch 'master' into fix-update-builderror 2026-07-26 00:54:08 +08:00
imccyu 6e721b9fdd feat(gui): settings panel with locale and theme preferences
Add the browser Settings surface as slot-composed plugins over new
preference services:

- Rename dsh-client-i18n to dsh-client-locale (locale is the domain
  name); LocaleService adds getLocale()/setLocale(id), immutable
  snapshots, a locale/change event, and dsh.locale persistence.
- ThemeService owns the light/dark/system preference (default system),
  resolves system via prefers-color-scheme, publishes theme/change
  snapshots, persists dsh.theme, and no longer touches the DOM;
  ui-layout's ThemePresenter applies resolved snapshots
  (body[data-ds-dark-theme] + alias tokens) and cleans up on dispose.
- ui-sidebar drops the phase-1 settings dropdown/modal; the foot renders
  the new sidebar.settings slot with the column state.
- New ui-settings shell occupies sidebar.settings: foot trigger row and
  the centered 1080x700 panel (figma 501:29947) with 24% mask, close
  button / mask click / Escape all closing, and a 188px nav projected
  from the settings.section list slot it declares. Nav labels are
  registrant-localized; sections re-register on locale change, so the
  ledger version is the shell's only subscription.
- ui-settings-general registers the General section: Permission and
  Tool Call skeletons, live Language (locale menu) and Appearance
  (Light/Dark/System cubes following the persisted preference); its
  slot store mirrors both service snapshots via apply-side listeners.
- ui-settings-models registers the Models nav entry with an empty
  content column.
- Portaled menus pin z-index above modal overlays (a menu anchored
  inside the settings dialog rendered underneath it and was
  unclickable).
- theme/data/list-pen icons in ui-primitives; settings copy ships as
  zh/en dictionaries; fixture manifests gain the settings rows.
2026-07-26 00:28:43 +08:00
imccyu cf31643480 Merge branch 'master' into fix-update-builderror 2026-07-26 00:06:18 +08:00
imccyu 787b4e6b9e fix(build): derive clean outputs from project graph 2026-07-25 20:30:35 +08:00
imccyu 22875a6c9d fix(build): clean stale workspace residue 2026-07-25 20:06:01 +08:00
imccyu be3a9f6a75 docs: document repository clean workflow 2026-07-25 20:05:29 +08:00
imccyu 1f0d555f60 docs(missions): record workspace GUI closeout lessons 2026-07-25 17:46:05 +08:00
imccyu 1a9c1596b8 test(web): cover workspace UI branches 2026-07-25 17:46:05 +08:00
imccyu c06cb2deec test(web): stabilize workspace snapshots 2026-07-25 17:46:05 +08:00
imccyu 468c64a078 fix(web): keep composer add action attachment-only 2026-07-25 17:46:05 +08:00
imccyu 08ce02da2b docs(web): finalize workspace UI product flow 2026-07-25 17:46:04 +08:00
imccyu 9eb9c70a8a feat(web): add workspace-aware session flow 2026-07-25 17:45:26 +08:00
imccyu f7d85bf9f5 fix(headless): CI green + review-bot findings for the shared composition
Coverage: api-proxy.ts joins the web-transport exclusion block (its
behavior specs moved here with it; the assembled-entry coverage lands with
the GUI test lane). Static: config-catalog regenerated after the log-round
revert shifted a source anchor. Prose brought current per review: the cli
README now describes the one shared composition (and its build
prerequisite), the apiproxy README points at the api-gateway row instead of
the deleted runtime package, and the config-tree agent note's headless
deferral paragraph records what actually landed (bilingual pair
re-recorded).
2026-07-25 14:40:45 +08:00
imccyu 0e287b582c feat(headless): boot dsh -p from the shared composition; retire dsh-host-runtime
dsh -p now runs AppCLIEntry over the same cordis.yml as dsh web — one
composition, no disabled rows, no layer marks. The only surface difference
is port 0 (parallel runs never collide), and the printed URL opens the live
headless session in a browser while it runs. The model face gains what web
already had (ask_user_question, workspace context, model titles) per the
unification ruling. InProcessApiClient now wraps toFetchHandler(ctx.apiProxy)
directly, so bootHost/startHost lose their last consumer and the
dsh-host-runtime package retires; its api-proxy behavior specs move to
dsh-host-apiproxy where the implementation lives.
2026-07-25 14:40:45 +08:00
imccyu 4a27da44cf test(web): real-composition webserver spec
Boots a test-only cordis.yml through the real Loader and asserts the route
service's behavior surface: exact/longest-prefix matching, tapIndex
transform order and unsubscription, traversal 403, non-GET 405, SPA-200
fallback, malformed-request 400 without process exit, duplicate-pattern
throw, dispose closing held connections with register/disposer symmetry,
and a listen-failure fail-loud case (EADDRINUSE -> FAILED fiber + late
rejection). Replaces the retired factory-era specs.
2026-07-25 14:40:45 +08:00
imccyu f5506cf35f refactor(storage): rename dsh-domain to dsh-storage-domain
The bare 'domain' name was too generic for a published package. The
directory moves to packages/storage/storage-domain, the package becomes
@deepseek-ai/dsh-storage-domain, and the plugin/invariant names follow;
the ctx surface (ctx.storage.domain), the domain/changed event, and all
runtime behavior are unchanged. References, catalogs, graphs, and the
bilingual design note move together.
2026-07-25 11:08:04 +08:00
imccyu 71923d7213 chore(storage): exempt the copied sqlite open sequence from clone detection
The jscpd gate flags the deliberately mirrored open/stamp sequence
against session-persistence-sqlite and session-query-sqlite. The copy
is the settled this-phase choice — this group is the third user and the
shared medium helper is deferred to the log-facet migration so the
session packages stay untouched (reuse audit in the design note); mark
the span accordingly.
2026-07-25 11:08:04 +08:00
imccyu 507dd25a3a fix(storage,workspace): review-bot findings — emit isolation, domain ownership, null globals
- domain/changed emission is isolated from the write path: an observer
  throwing synchronously can no longer turn a committed (durable +
  in-memory) write into a rejection; the failure is logged and later
  writes proceed.
- Domain lifecycle belongs to the opening consumer: Domain gains an
  idempotent close() (drain, unit close, reservation release), the
  facility stops registering effects on its own context and instead
  closes any still-open domains on unmount; WorkspaceRegistry holds its
  domain through its own effect, so disposing and re-mounting the
  consumer no longer wedges on already-open.
- defineDomain rejects a global schema accepting null at declaration
  time: JSON null is the medium's absence sentinel, so a nullable global
  could never round-trip; failing loud at the spec keeps set(null)
  unrepresentable.

Regression tests cover all three (hostile listener, close/reopen and
consumer re-mount, nullable-global rejection).
2026-07-25 11:08:04 +08:00
imccyu 1bddf5269a fix(storage): keep the json loadAll closed guard a rejection
Dropping async for the lint gate turned the closed-unit guard into a
synchronous throw, breaking the conformance clause that every post-close
operation rejects. Restore async with a justified require-await disable;
the guard's rejection semantics are what the shared suite pins.
2026-07-25 11:08:04 +08:00
imccyu 2e986ee1e3 style(storage,workspace): satisfy the repository lint gate
eslint --fix formatting sweep plus the manual residue: sync method
bodies drop async behind Promise-returning signatures (the sqlite unit
routes primitives through a settle() guard preserving the never-throws-
synchronously contract), catch callbacks type their reason as unknown,
loadAll's global slot is plain unknown (null semantics stay in JSDoc),
a non-null assertion becomes a narrowing, and unsafe any assignments in
tests gain explicit types. One justified eslint-disable for
prefer-promise-reject-errors follows the core/session precedent —
wrapping would discard the original StorageError code.
2026-07-25 11:08:04 +08:00
imccyu 25a4a2063b docs(storage): replace design-sketch fences with prose in the bilingual note
CI's static lane counts opted-out ts fences repo-wide and the note's
ignore-check sketches tipped the ratio past 50%. The hub/backend/event
shapes those fences sketched are all shipped code now, so the sections
point at the owning source files (src/index.ts, src/backend.ts,
src/error.ts, src/events.ts) instead of restating signatures; both
language sides move together and the pairing record is re-confirmed.
2026-07-25 11:08:04 +08:00
imccyu 0559e0207e chore(storage,workspace): gates — coverage, catalogs, bilingual note
- Per-file 100% coverage across the five new packages (invariant
  companion suites, failure-injection negatives, lifecycle and
  malformed-medium branches).
- Canonical README Model Experience / Known Limitations sections; new
  storage/ and workspace/ group READMEs; packages/README.md rows (budget
  ceiling raised 760 → 790 for the two new groups).
- Cordis catalog/type-link registrations, service-role classification,
  and regenerated catalogs/graphs for the new services and events.
- Agent Note: English body + i18n pairing record; design-sketch fences
  opted out of doc-typecheck as ignore-check.
- Two exactOptionalPropertyTypes/discriminant fixes in new tests.

doc-sync (24 gates), typecheck, hygiene, and the five-package suite
(92 tests) all pass.
2026-07-25 11:08:04 +08:00
imccyu 80b3b6d917 fix(storage,workspace): post-review hardening
Review findings applied across the group:
- storage hub: stale disposers no longer remove a successor registration;
  the package now default-exports the Storage service class per the
  service-package export shape.
- json backend: failed publishes roll back the authoritative memory state
  (a rejected write can no longer resurface via get() or ride the next
  publish); close() drains in-flight writes and blocks in-flight opens;
  double-open rejects as a plain caller error instead of malformed-medium.
- sqlite backend: loadAll builds records on a null prototype (__proto__
  keys round-trip instead of polluting), user_version is stamped only
  after the schema is fully created, and corrupt record JSON rejects as
  malformed-medium instead of a bare SyntaxError.
- domain form: writes persist before mutating authoritative memory or
  emitting; DomainChanged is a put/deleted discriminated union.
- workspace: attach/detach idempotence decided on the write chain (stale
  snapshots no longer short-circuit), create() requires a directory, and
  startup fails loud on duplicate stored paths.

Eleven regression tests pin the fixed behaviors.
2026-07-25 11:08:04 +08:00
imccyu 3f16cb4c3c docs: domain KV storage + workspace Agent Note and dev plan
Proposed-lifecycle Agent Note (Chinese draft, English body to follow
after review) recording the storage hub / domain form / workspace
design, the deletion semantics deferred to future work, alternatives
considered, and the session-backend migration reuse audit. The dev plan
under missions/ carries the engineering breakdown.
2026-07-25 11:08:04 +08:00
imccyu 013e6f8769 feat(workspace): persistent workspace entity over the domain form
ctx.workspace registry owns WorkspaceId-branded records: realpath-
normalized unique paths (create rejects collisions; resolveByPath shares
the normalization), ordered sessionIds as the single source of ownership
truth, attachSession gated on the session header cwd matching the
workspace path (double-booking structurally impossible), dead session
ids filtered on projection and pruned on the next mutate, status()
reporting missing directories. No delete surface this phase — deletion
ships together with the session-side primitives as future work.
2026-07-25 11:08:04 +08:00
imccyu 7c27107be4 feat(storage): domain data form — typed schemas over opaque KV units
ctx.storage.domain opens declared domains: zod value schemas parsed at
the durable boundary, one write chain per domain (update(fn) is the only
read-modify-write), domain/changed emitted per record after durability
(new snapshot + operation, no old value, per repo event convention).
Domain-to-backend routing is configuration (default backend + per-domain
overrides); unknown names and missing facets fail loud. Ships the
MemoryStorageBackend test helper and a runtime invariant asserting every
change event matches the in-memory state.
2026-07-25 11:08:04 +08:00
imccyu 9dee9e1a71 feat(storage): sqlite backend — one database hosting all routed units
node:sqlite DatabaseSync with the session-persistence-sqlite open
sequence (0o700 dir, exclusive 0o600 create, foreign_keys, configurable
journal mode, user_version stamp-or-reject). STRICT tables throughout:
units/unit_globals meta tables plus one document-per-row table per
declared unit table, keeping per-key durable updates precise.
2026-07-25 11:08:04 +08:00
imccyu 1529be6fd4 feat(storage): json backend — one human-readable file per unit
Atomic whole-file replacement (same-dir temp + fsync + rename + parent
fsync); the in-memory unit state is authoritative and the file is always
the current net state, pretty-printed. Missing files open as empty units
and materialize on first write; foreign or unparsable files reject with
malformed-medium, stored-version drift with version-mismatch.
2026-07-25 11:08:04 +08:00
imccyu e90b0d51df feat(storage): storage hub with named backend registry and data-form mounts
ctx.storage is a pure registration hub: multiple named backends stay
mounted side by side, data forms (domain first) mount via the
merge-extensible StorageForms map. src/backend.ts is the normative
KV-facet contract; tests/contract.ts is the shared conformance suite
every backend runs. Backends expose data-shape facets (kv now, an
append-log facet reserved for the future session-backend migration).
2026-07-25 11:08:04 +08:00
imccyu 2e27b8aeef chore(web): gate repairs for the config-tree boot round
Lint (bridge JSDoc params, service-class export shape, async invariant
listener form), regenerated doc catalogs/graphs with role classifications
for httpServer and clientModuleHost, catalog type-link exemptions for the
route/graph contracts, knip alignment (apps/cli composes via cordis.yml so
its yml-named deps are runtime edges knip cannot see; webserver's deleted
test dir), the zh side of the loading-model note brought along with its
pairing records, and coverage exclusions for the new web-transport halves
under the GUI test-lane TODO (real-composition harnesses land with that
lane).
2026-07-25 10:38:54 +08:00
imccyu db59d32c9b docs(gui): agent notes for the config-tree boot and transport layering
New note records the dsh web composition decision (flat cordis.yml, the
AppCLIEntry/AppWebEntry class pair, one declaration place per config
source, the five-way transport split) with its rejected alternatives; the
client-plugin-loading note's roster endgame and HMR sections are brought
current with what shipped.
2026-07-25 10:25:02 +08:00
imccyu 5466a81474 feat(web): boot dsh web from a config tree via AppCLIEntry
apps/cli/cordis.yml holds the whole composition flat — the host runtime
rows, the api-gateway row, the webserver row, and the ten dshClient rows.
AppCLIEntry is the pre-cordis glue: layered env (ambient > cwd .env >
$DSH_HOME/.env, fixing DSH_HOME=... dsh web not finding its key), patch
composition from the three non-yml sources (profile json through the static
PROFILE_MAPPINGS table, CLI flags, the resolved frontend distIndex), the
Loader include boot (--dev appends the hmr row before the settle), and the
fail-loud triple (assertEntriesLoaded + installFailLoud + an all-ACTIVE
sweep for PENDING fibers). web.ts shrinks to argv parsing + the URL line.
2026-07-25 10:25:02 +08:00
imccyu 80cd8f54b5 refactor(web): collapse the shell boot into the AppWebEntry class
The four free functions in boot.tsx become one kernel class holding what
must exist before cordis: the parsed BootManifest, the ClientModuleSystem
instance, and the loading-page handles. Context/Loader setup runs in
parallel with the immediately-tier prefetch, but entry creation awaits the
prefetch: materialization is tree.import's synchronous require, so
cross-package require edges (i18n -> runtime/client) need every
immediately-tier factory registered first — unbarriered creation raced
10-25% of boots. The kernel adopts the modules entry (writes the
__DSH_MODULES__ slot pre-cordis, creates the entry first, skips its graph
row), and provide('modules') now lives in the adoption apply. apps/web
drops its host-package edges (composition is apps/cli's job).
2026-07-25 10:23:40 +08:00