Commit Graph

87 Commits

Author SHA1 Message Date
creatixchu
c5ae7dd65e Merge remote-tracking branch 'origin/doc/host-client-group-readmes' into feat/directory-picker
# Conflicts:
#	packages/host/apiproxy/package.json
#	pnpm-lock.yaml
2026-07-29 06:43:09 +08:00
creatixchu
1779488c99 Merge remote-tracking branch 'origin/master' into doc/host-client-group-readmes 2026-07-29 06:40:26 +08:00
creatixchu
baaa535235 fix(host): race directory reads against the caller's signal; report aborts as cancelled
Every filesystem await in the browse scan (opendir and each read) now
races the signal through raceAbort, so a stalled network open/read stops
with a departed caller and an already-aborted request rejects even for
an empty level; the abandoned settlement is swallowed and an abandoned
open that still mints a handle is closed, never leaked. apiproxy maps an
aborted listing to the cancelled wire code, matching pickDirectory and
command.execute, instead of reporting a false internal failure. The
fixture spec call sites gain the wire signal argument the previous
commit's static lane flagged.
2026-07-29 05:05:36 +08:00
creatixchu
7503390590 fix(host): cancellable listing scans and O(log window) insertion
capability.list gains an optional AbortSignal threaded from the RPC
carrier's request signal (the pickDirectory pattern): a disconnected or
timed-out caller stops the opendir loop instead of the scan outliving
its caller, and the abort surfaces as its own reason rather than a
directory-unreadable dressing. boundedInsert rejects a full window's
at-or-beyond-tail candidate on one comparison and binary-inserts
retained candidates, so an oversized level no longer pays a window scan
per dirent.
2026-07-29 04:42:13 +08:00
creatixchu
5245182db2 fix(host): bound listDirectory levels at a configurable maxEntries
One list call now materializes at most maxEntries child rows (config,
default 1000 - GitHub's web-UI directory-listing bound). Candidates sort
before probing so a cut level keeps the name-sorted head and symlink
probing stops with the bound, and DirectoryListing carries a required
truncated flag on the seam and the wire so clients can state
incompleteness instead of silently missing tail entries.
2026-07-29 03:45:26 +08:00
imccyu
d4ba2ecd63 Merge origin/master: goal domain lands beside plan
Union resolutions throughout — the fixture serves both the goal and plan
projection units (catalog gains /goal beside /plan; the retired
goal-fixture sample command yields to the real goal mirror), the mux
baseline spec expects all four unit frames, and the tsconfig paths /
Model Experience allowlist carry both domains' outlets.
2026-07-29 02:27:16 +08:00
imccyu
532b2b9107 Merge origin/master (regenerate the event producer-consumer graph) 2026-07-29 01:21:29 +08:00
creatixchu
6a78bf4dd0 Merge remote-tracking branch 'origin/doc/host-client-group-readmes' into feat/directory-picker 2026-07-29 01:09:33 +08:00
creatixchu
51b70f5864 Merge remote-tracking branch 'origin/master' into doc/host-client-group-readmes
# Conflicts:
#	apps/cli/README.i18n.yaml
2026-07-29 01:08:17 +08:00
imccyu
2f6b9843b4 Merge origin/master (session-projection cache column) into goal-ui-merge-master 2026-07-29 00:17:39 +08:00
imccyu
d804c9c94d fix(web): blank means the conversation has not started
The summary blank bit switches from log emptiness to the absence of any
turn/start: standalone plugin events — command lifecycle records,
plan/mode, session titles, goal metadata — no longer surface a fresh
session in lists or steal the New Session view. Running /plan (or /goal)
on a blank session keeps it blank and reusable; the first accepted
prompt's turn clears it. Both carriers share one predicate (summarize +
the host/session-added frame); the cold path keeps its constant false
with the index-read rationale; the client mirror already flips only on
prompt acceptance and needed no change.
2026-07-28 23:17:46 +08:00
imccyu
c46419cf5c fix(apiproxy,client): the list projection column becomes a seedable watermarked block
Review finding (PR #791): the column carried bare values (no seq), so the
client could not seed its value store without risking a stale list block
outranking newer push frames — and nothing consumed the column at all,
leaving cold titles absent after a restart. SessionSummary.projections is
now the same SessionProjectionsBlock as the history tail (values +
asOfSeq; attached rows cut the live registry, cold rows serve the cache's
identity-checked cachedSnapshot whose asOfSeq is the lowest served-row
watermark). SessionManager.refreshList seeds each row's block into the
per-session projection store via per-key apply — partial-baseline
semantics: an absent key never clears, and higher-seq-wins keeps stale
list blocks beneath push frames and tail baselines — so cold titles
surface in the sidebar without opening a session.
2026-07-28 22:26:11 +08:00
imccyu
003b22a157 feat(apiproxy): projection column on session.list — cold titles with zero log loads
SessionSummary grows an optional projections column (whole value per key,
same passthrough posture as the history-tail block): attached rows cut the
live registry watermark cache; cold rows view the persisted projection
cache's stored rows via the new registry viewCheckpoint face (version-
matching keys only, zero I/O) — the RFC's motivating scenario, every
session's title across a listing without loading one event log. The column
is fail-soft and absence-coded: no registry, no cache row, or a throwing
read serve the row without the column, never breaking the listing.
2026-07-28 22:25:29 +08:00
creatixchu
85ca8be104 feat(host,client): compose directory picking through slots — dual-face -native, no wire advertisement
ui-workspace's two trigger surfaces each declare a single-kind directory-flow
hole (conversation.hero.workspace.directoryFlow / sidebar.workspaces.directoryFlow,
same owner contract) and keep only the trigger and the adoption: the Open-local-
folder entry renders while the surface's hole is occupied, and the occupant
reports one picked path per open through the hole's owner conversation
(open/busy/onPicked/onCancel/onError).

directory-picker-native becomes dual-face: its browser half fills both holes
with a renderless occupant driving host.pickDirectory, so the cordis.yml row
that mounts the backend also composes the client interaction — a mismatch is
impossible and a second flow package fails at client load.

With composition wiring both sides, the host.describe.directoryPicker
advertisement and the client's kind branching lose their last consumer:
the field, WorkspacesService.directoryPickerKind(), the DirectoryPickerKind
wire type, and the picker's per-open describe read are deleted. The connection
fixture now serves a deterministic pickDirectory path so the keyless snapshot
drives the full pick-then-adopt flow. ui-workspace's hand-rolled declaration
deferral is replaced by the deferRegistration helper it duplicated.
2026-07-28 21:51:01 +08:00
creatixchu
a94df18bcf Merge remote-tracking branch 'origin/doc/host-client-group-readmes' into feat/directory-picker
# Conflicts:
#	packages/client/connection/src/client/fixture.ts
#	packages/client/connection/tests/fake-api.ts
#	packages/client/runtime/src/client/workspaces/service.ts
#	packages/client/runtime/tests/fake-api.ts
#	packages/client/ui-workspace/src/client/WorkspaceBrowser.tsx
#	packages/client/ui-workspace/src/client/WorkspacePicker.tsx
#	packages/client/ui-workspace/tests/workspace-picker.spec.tsx
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/host.schema.ts
#	packages/host/apiproxy/src/api/host.ts
#	packages/host/apiproxy/src/api/rpc-map.ts
#	packages/host/apiproxy/src/fetch/client.ts
#	packages/host/apiproxy/src/fetch/handler.ts
#	packages/host/apiproxy/tests/api-proxy-workspace.spec.ts
#	packages/host/apiproxy/tests/client-handler.spec.ts
#	packages/host/apiproxy/tests/fetch-carrier.spec.ts
2026-07-28 21:21:21 +08:00
creatixchu
5579b13503 refactor(host): rename the directory-picker dialog backend and kind to native
The browse interaction also presents a dialog (the in-app modal), so 'dialog'
failed to discriminate the two capability kinds; 'native' names where the
chooser runs. Package directory-picker-dialog -> directory-picker-native, kind
'dialog' -> 'native', with every seam/gateway/client/doc reference updated and
the seam Agent Note's naming rationale rewritten to match.
2026-07-28 21:07:28 +08:00
imccyu
1c2923c84f feat(web): re-land the goals wire domain as mutation-only ref acknowledgements
Six mutation RPCs (create/edit/pause/resume/complete/clear) move into
dsh-host-apiproxy (the PR's host/runtime carrier is gone): goalService()
resolves ctx.get('goals') with a loud absence error, mutateGoal() resolves
the session's agent (agentFor, the command.* implicit-resume precedent) and
acknowledges with the new CAS ref only. GoalError codes ride err.details.

goal.get and the wire GoalView/goalViewSchema are gone: the read side is the
'goal' session projection (whole values on the history tail page and
session/projection frames), so responses never feed client state — the rule
whose absence forced the original PR's write-revision fences.
2026-07-28 21:05:43 +08:00
creatixchu
302dfca4d5 Merge remote-tracking branch 'origin/master' into doc/host-client-group-readmes
# Conflicts:
#	packages/README.i18n.yaml
#	packages/README.md
#	packages/README.zh.md
#	packages/client/connection/src/index.ts
#	packages/client/connection/src/native-dialog-request.ts
#	packages/client/connection/tests/node-half.spec.ts
#	packages/host/apiproxy/README.i18n.yaml
2026-07-28 21:01:20 +08:00
imccyu
cbab62bdea Merge origin/master into goal-ui: adopt the rewritten client core and apiproxy carrier
Conflict rulings follow the projection-reattach plan:
- host/runtime package (deleted on master): take master; the PR's boot
  composition moves to the cordis.yml roster and its goals handlers will be
  re-landed in dsh-host-apiproxy; the session.prompt slash interception and
  its spec are dropped entirely (superseded by command.execute + command/run
  logging).
- client core (rewritten on master): take master; the PR's Session goal
  fields/methods, ConversationSnapshot.goal, goalActions injection, and the
  hard-mounted GoalBar are all superseded by the 'goal' session projection
  (useProjection) and will return as the ui-goal plugin.
- wire contract: union of master's workspace/command/skill domains and the
  PR's goal domain, minus goal.get (the read side is the projection block +
  session/projection frames; six mutation RPCs stay).
- GoalBar component and spec leave ui-conversation (they re-land in the new
  ui-goal package); IconSparkle16 stays in ui-conversation chat.
- The web-slash-command-dispatch note documents the dropped interception and
  is removed; the goal-bar note will be rewritten for the projection model.
- pnpm-lock.yaml taken from master (reinstall recomputes).
2026-07-28 20:55:36 +08:00
imccyu
2ecc89a186 chore(web): drop plan RPC residue and stale carriers after merge
Sweep the silently auto-merged leftovers of the superseded #587 wire layer:
the PlanModeState interface and planMode/setPlanMode entries in the sessions
API and rpc map, the fixture plan RPC spec, the composer.controls README
paragraph and spec assertions, the old-format plan-mode snapshot, and the
two Agent Notes written against the RPC design (to be rewritten for the
projection reattachment). ChatView/PendingCard keep the approval-only
pending rendering; QuestionComposer improvements ride along unchanged.
2026-07-28 20:28:43 +08:00
imccyu
ae55771511 Merge origin/master: session projection base, command channel, composer seats
Resolution follows the reattachment plan: the #587 wire layer (planMode/
setPlanMode RPC, prompt.planMode, client Session projection fences) is
dropped in favor of the session-projection base now on master; master
structure wins in all shared files. Kept from the PR side: the approval-only
pending filter in ChatView (questions render solely through the composer
takeover) and the auto-merged QuestionComposer improvements. The deleted
host/runtime package and retired test carriers are removed with master.
2026-07-28 20:24:06 +08:00
_Kerman
9220dbd271 Merge remote-tracking branch 'origin/master' into xtr/identified-immutable-messages
# Conflicts:
#	docs/event-producer-consumer.md
#	packages/client/connection/src/client/fixture.ts
#	packages/goal/command-goal/tests/command-goal.spec.ts
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/events.schema.ts
#	packages/host/apiproxy/src/api/events.ts
#	packages/host/apiproxy/tests/api-proxy-view.spec.ts
#	packages/host/apiproxy/tests/rpc-schemas.spec.ts
#	tsconfig.base.json
2026-07-28 18:11:13 +08:00
imccyu
5dd2e77914 Merge remote-tracking branch 'origin/master' into worktree-guifork 2026-07-28 17:48:48 +08:00
creatixchu
c565022c8a fix(host): derive the picker capability union from a merge-extensible map
ds-review-bot round 1: the seam documented a merge-extensible union but
shipped a closed alias, and the gateway schema rejected any kind beyond
dialog/browse — a third backend could neither implement the seam nor be
advertised. The union now derives from an augmentable DirectoryPickerCapabilities
map, host.describe.directoryPicker preserves unknown wire kinds, and the
browse fixture applies listDirectory's root special case so creating under
'/' no longer mints a '//name' identity.
2026-07-28 17:09:43 +08:00
creatixchu
716d3ca636 test(apiproxy): drive the browse RPCs through the fetch carrier
The full-suite coverage gate found the new listDirectory/createDirectory
client methods and handler routes unexecuted: the implementation and
schema layers were tested directly, but nothing crossed the wire form.
One round trip through InProcessApiClient covers both arrows on each
side.
2026-07-28 16:44:22 +08:00
creatixchu
7fd2abd828 feat(host): directory-picker capability seam with dialog and browse backends
The web GUI's folder picking was hardwired to one interaction: a native
OS chooser compiled into the gateway, unusable for remote deployments
and swappable only by editing apiproxy source.

Directory picking becomes a three-package capability seam in
packages/host: ctx.directoryPicker returns a discriminated capability —
dialog (the extracted native chooser; host-display only) or browse
(new: one-level listing + child creation over Node stdlib, hidden flags
host-stamped, symlinks followed, ancestry crumbs; remote-capable). The
gateway injects the seam, advertises the kind via
host.describe.directoryPicker, serves host.listDirectory /
host.createDirectory under browse, and answers
directory-picker-unavailable across kinds. cordis.yml is the swap
point; apps/cli keeps dialog mounted, so behavior is unchanged until
the in-app browser PR flips the default. The connection fixture serves
a deterministic browse tree; WorkspacesService gains the browse calls
the browser UI will drive. Decision record:
.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md
2026-07-28 15:44:53 +08:00
_Kerman
b1af35145b fix: enforce message snapshot invariants 2026-07-28 15:33:00 +08:00
07akioni
c30c891628 fix: ci 2026-07-28 15:21:34 +08:00
_Kerman
0225d598e3 fix: preserve message occurrence contracts 2026-07-28 14:44:15 +08:00
creatixchu
d2fea6d789 fix(apiproxy): refuse non-JSON media types on /api POST bodies
Browsers send "simple" POSTs (text/plain, form encodings) without a CORS
preflight, so a malicious page could execute side-effectful RPCs blind —
the response stays unreadable cross-origin, but session.prompt would
still run. The carrier now answers 415 unless the declared media type is
application/json, forcing every cross-site attempt into a preflight this
server never answers. Raw-fetch specs gain the header; a new handler case
proves the fence rejects before the impl runs.
2026-07-28 14:40:13 +08:00
07akioni
b926044c13 feat: click file name to open file in toolcall, remove hover bg of toolcall, do not trigger sidebar any more (follow designer's instruction) 2026-07-28 14:24:41 +08:00
_Kerman
350c296cff fix: complete immutable message migration 2026-07-28 14:15:23 +08:00
_Kerman
fbf87e660c refactor: identify and freeze messages at creation 2026-07-28 13:55:59 +08:00
imccyu
a3bdec4450 Merge remote-tracking branch 'origin/master' into worktree-guifork 2026-07-28 10:23:48 +08:00
imccyu
755ce21334 refactor: brand the command lifecycle pairing id as CommandId
commandId crosses three boundaries (session log, wire admission response,
client flow pairing), so per the branded-id rule it becomes
Branded<'CommandId'>, declared in a new pure @deepseek-ai/dsh-commands/brand
outlet (the dsh-llm/brand shape: type + constructor, no Context merges, so
wire and client programs can name it without loading the host plugin). The
event payloads, CommandExecution, and the executor mint carry the brand; the
wire schema gains commandIdSchema as the domain's single brand-cast point
(the approvals precedent); CommandNode and the fixture's fabrication cast
follow type-only.
2026-07-28 01:37:45 +08:00
imccyu
2c5c1e72ba fix: merge conflicts 2026-07-28 00:45:27 +08:00
imccyu
af70af4020 Merge remote-tracking branch 'origin/master' into worktree/web-session-model-selector 2026-07-28 00:39:24 +08:00
imccyu
e78edd6ae4 refactor: retire the session/title frame and the todos history rider from the wire 2026-07-27 23:07:46 +08:00
imccyu
6f47df0913 feat: session/projection push frame; tail block reads the watermark snapshot 2026-07-27 23:07:16 +08:00
imccyu
6d2e5a7cd7 feat: command.execute returns the lifecycle pairing id ({matched, commandId?})
CommandService.execute now returns a CommandExecution — the normalized
result plus the commandId minted for its command/run/command/done records —
and the wire admission value carries commandId exactly when matched, so the
issuing client can correlate its RPC acknowledgment with the flow node the
lifecycle events produce. apiproxy api/schema/handler, the connection
fixture, and the TUI/plan/goal consumers follow the new shape.
2026-07-27 23:07:13 +08:00
imccyu
2ebaa30c6d refactor: structured command/run payload {commandId, name, args, source}
The line field is deleted (pre-release, no shim): name and args are
parseCommand's own split — name plus verbatim rawInput with its separator
whitespace — so a consumer (a projection unit folding its own command
records, a rich command card) never re-parses a line. CommandNode mirrors
the split (name/args, both null on a run-less cross-window node); the
generic card rebuilds its display line as /name + args. The connection
fixture logs the same structured payload.
2026-07-27 23:06:52 +08:00
imccyu
4ddec0ba2f refactor: command.execute degrades to pure admission; composer notice channel retired
The wire response now carries only the matched bit — CommandExecuteResult
is deleted from the api, schema, and client mirrors (pre-release, no shim);
outcomes ride the durably logged command/run/command/done pair broadcast on
the mux stream and render as flow nodes. ui-command's runDetached→noticeFor
outcome routing is retired: admitted commands surface nothing through the
composer, while admission misses (matched:false, syntax feedback) and
transport failures keep their immediate notice. The connection fixture
mirrors the host: an admitted command appends the lifecycle pair to the
session log instead of returning result text.
2026-07-27 23:06:49 +08:00
imccyu
65e41f1cb0 feat: projections block on the session.history tail page 2026-07-27 22:58:56 +08:00
_Kerman
fb1dc6d117 Merge remote-tracking branch 'origin/master' into xtr/agent-loop-message-machine
# Conflicts:
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/session.i18n.yaml
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
2026-07-27 21:51:37 +08:00
_Kerman
ed67ad53d2 refactor(agent): return request retry action 2026-07-27 21:17:49 +08:00
ZiyaZhang
a5239b0f64 test(gui): cover native workspace picker branches 2026-07-27 04:37:24 -07:00
ZiyaZhang
fef928a7e1 feat(gui): add native workspace folder picker 2026-07-27 03:50:22 -07:00
_Kerman
f63d937496 fix(tui): route prompts by next-step capability 2026-07-27 18:05:43 +08:00
_Kerman
a59ce0367c fix(agent-loop): route next-step input during admission 2026-07-27 17:55:55 +08:00
Yichen Jiang
7f4905c4bf Merge remote-tracking branch 'origin/master' into worktree/web-session-model-selector
# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
2026-07-27 17:18:29 +08:00