Commit Graph
179 Commits
Author SHA1 Message Date
imccyu d257c3878e feat(web): session-row Rename menu action with a browser-owned dialog
The row menu's Rename item opens the same dialog pattern as workspace rename
(no client-side conflict rule; the host normalizes) and resolves through the
session face via ctx.sessions.binding. Assembled-app snapshot covers the
row-menu -> dialog -> unary-settle flow.
2026-07-29 18:59:46 +08:00
07akioni 59c0f92cb6 Merge branch 'master' into feat/agent-action 2026-07-29 15:09:04 +08:00
imccyu f7f51e29dc Merge branch 'master' into fix/web-details-session-lifecycle 2026-07-29 15:02:39 +08:00
imccyu 66d650e4fb refactor: simplify sidebar logics 2026-07-29 14:52:41 +08:00
07akioni 4aa1aa4a66 test(web): refresh aria goldens for message IconActions and clocks
Settled history now exposes user/assistant chrome (including date-aware
clocks) in the accessibility tree; collapse clocks via scaffold and update
keyless scenario goldens.
2026-07-29 14:30:09 +08:00
07akioni afab428c0c Merge branch 'master' into feat/agent-action 2026-07-29 14:21:44 +08:00
NI0317 f280a97c56 test(web): isolate details session lifecycle e2e 2026-07-29 11:32:03 +08:00
NI0317 ca2e6207b5 Merge origin/master into fix/web-details-session-lifecycle 2026-07-29 11:21:48 +08:00
NI0317 406cd3602b fix(web): close details when current session changes 2026-07-29 11:21:13 +08:00
imccyu 5c432955ed Merge remote-tracking branch 'origin/master' into web-permission-sandbox-merge-master 2026-07-29 11:16:49 +08:00
creatixchu 459128dfb6 fix(web): root USERPROFILE for the browser golden; re-record it against fresh bundles
- homedir() reads USERPROFILE on Windows: the golden's home collapse now
  sets and restores both variables, keeping the artifact machine-independent
  on every platform (ds-review-bot).
- The committed golden is re-recorded against freshly built bundles: the
  earlier recording ran with a stale dist that predated the navigation
  landmark and the button-in-listitem markup, which is why refreshes had
  looked byte-identical.
2026-07-29 01:57:19 +08:00
imccyu 667b0aff87 test(web): answer the fixture approval takeover; refresh aria goldens
The assembled fixture app now takes over the composer while fx-alpha's
resident approval is pending — the feature under test, not chrome noise —
so the session-title snapshot answers it (允许一次) before asserting the
model seat, mirroring what a user sees. The eleven keyless ui.expected.md
goldens re-record (DSH_SNAPSHOT=refresh, no key) for the Access placeholder
→ projection chip swap (Danger Full Access under the roster default) plus
the master-side chrome drift the goldens had accumulated (copy/branch/edit
buttons, tab rows) since their last refresh.
2026-07-29 01:15:31 +08:00
creatixchu 6add9a8eef fix(host): harden the browser dialog against review round-2 races
- Dismissal (Escape/mask) is ignored while adoption is busy: the owner's
  in-flight createWorkspace must not land behind an apparent cancel.
- Every parent control goes inert while the nested create dialog is open
  (Modal traps no focus, so Shift-Tab/AT could close, adopt, or retarget
  underneath the child).
- Creation settlements are gated on an open-generation ref: a create that
  resolves or rejects after the flow closed (and possibly reopened) can no
  longer relist the stale target or surface its alert in the fresh dialog.
- The keyless snapshot waits for the Open button's enabled state before
  clicking — on slow runners the selection's child listing was still in
  flight and the click landed on a disabled button.
2026-07-28 23:37:07 +08:00
creatixchu 6cd63f741c fix(host): address review — Escape scoping, relist gating, crumb overflow, aria golden
- Escape (and the mask) now reaches only the topmost dialog: while the
  nested New-folder dialog is up the browser ignores its own Modal close,
  and the nested dialog's in-flight fence keeps both open during creation.
- New folder disables while any listing loads, so a slow post-create
  relist/select sequence cannot host a second create against a target the
  pending listing is about to change.
- Deep ancestry scrolls inside a dedicated crumb trail whose tail is pinned
  into view; the path-edit zone keeps its reserved width instead of being
  clipped by the card, preserving cross-drive path entry.
- The workspace-management e2e records a directory-browser aria golden at a
  staged tree (host HOME pointed at the scaffold cwd collapses ancestry into
  the Home crumb, keeping the artifact machine-independent), and the keyless
  snapshot's row targeting goes through visible label text — listitem
  accessible-name computation differs across dom-accessibility-api
  environments (the CI-only miss).
2026-07-28 23:21:27 +08:00
creatixchu 0d9ac53fb0 test(web): give the browse-dialog snapshot finds the lane's standard 10s timeout
CI's cold jsdom needs more than findByRole's 1s default between opening the
dialog and the fixture listing's first paint; the surrounding helpers already
wait 10s.
2026-07-28 23:04:33 +08:00
creatixchu 4822622cb7 feat(host,client): ship the in-app directory browser as the browse package's client half
directory-picker-browse becomes dual-face: its browser half fills
ui-workspace's two directory-flow holes with the Select Workspace Directory
dialog (figma Harness 813-23126 family — Miller two-column view, breadcrumb
with click-to-edit path zone, nested New-folder dialog), driving the node
half's host.listDirectory/host.createDirectory and owning its locale
namespace (directory-browser, zh default / en). The dialog moves here from
ui-workspace wholesale — the trigger surfaces keep only the flow-hole owner
conversation.

apps/cli flips its one directory-picker row -native -> -browse, swapping the
host backend and the client interaction together; picking now works for
remote deployments out of the box. The keyless workspace-flow snapshot boots
the browse bundle and drives menu -> dialog -> Documents -> project -> Open
against the fixture tree.
2026-07-28 22:22:14 +08:00
creatixchu 05b5059dda Merge remote-tracking branch 'origin/feat/directory-picker' into feat/workspace-directory-browser
# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.md
#	.agents/notes/implemented/architecture/2026-07-28-directory-picker-capability-seam.zh.md
#	apps/cli/cordis.yml
#	apps/cli/package.json
#	docs/module-graph.md
#	packages/client/ui-workspace/README.i18n.yaml
#	packages/client/ui-workspace/README.md
#	packages/client/ui-workspace/README.zh.md
#	packages/client/ui-workspace/src/client/WorkspaceBrowser.tsx
#	packages/client/ui-workspace/src/client/WorkspacePicker.tsx
#	packages/client/ui-workspace/src/client/contract/slots.ts
#	packages/client/ui-workspace/src/client/index.ts
#	packages/client/ui-workspace/tests/apply.spec.ts
#	packages/client/ui-workspace/tests/workspace-browser.spec.tsx
#	packages/client/ui-workspace/tests/workspace-picker.spec.tsx
#	pnpm-lock.yaml
2026-07-28 22:01:26 +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
07akioni a39890bba5 Merge branch 'master' into feat/close-todo 2026-07-28 19:45:36 +08:00
07akioni 7bf36c6aa3 Merge origin/master into feat/close-todo
Keep master's session-projection carrier for todos, and fold turn/start
clearance into the tool-todo projection unit (plus TUI/fixture mirrors).
2026-07-28 19:43:56 +08:00
07akioni 6978dbfb13 fix: cr 2026-07-28 19:16:39 +08:00
Tianyi Cui 291676f704 Merge branch 'master' into xtr/identified-immutable-messages 2026-07-28 18:55:50 +08:00
Chinesezjc 60248e99d1 Merge remote-tracking branch 'origin/master' into feat/scrollbar-tokens 2026-07-28 18:15:00 +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
Chinesezjc 4265ac876c fix(client): rebind the scrollbar indirection on three missed elevated surfaces
Review found three scroll containers sitting on surfaces the rebinding
contract covers, none of which rebound: ui-primitives' shared Menu card
on --dsw-specific-menu (the surface PopupSelectView already rebinds for),
and the composer input and question composer cards, both on
--dsw-specific-input-major. Each rendered the l1 thumb, which differs
from l2 only in the dark palette and only on that surface, so a
light-palette screenshot and a code read both look correct.

Adds the mechanical check that would have caught them instead of leaving
it to inspection: a sheet that scrolls somewhere and paints a known
elevated surface somewhere must rebind. The elevated set is derived from
the sheets that already rebind, since a rebinding rule paints the surface
whose elevation it declares, so a new elevated surface joins the set by
rebinding rather than by anyone updating a list. Surface-level rather than
element-level because the card and the descendant that scrolls are
separate rules and CSS text does not say which contains which. Verified by
reverting each of the three fixes in turn: the check names the sheet and
the surface every time.

Also commits snapshots/sidebar-scrollbar/geometry.expected.md, the
resolved scrollbar style and geometry in both palettes. The aria goldens
the other web scenarios commit cannot carry a CSS-only change, since it
alters no DOM and no accessible name and leaves their trees
byte-identical. Absolute coordinates stay out: they track font metrics and
the laid-out sidebar width, so committing them would document the platform
and force a per-platform re-record.
2026-07-28 17:42:57 +08:00
creatixchu cd7aa3c7d8 fix(host,client): gate the picker affordance on the advertised kind; reject non-absolute browse paths
ds-review-bot round 2. The workspace UI never consulted the advertised
directoryPicker kind: under a browse (or merge-added) backend it still
rendered 'Open local folder…' and called pickDirectory(), which the host
answers with directory-picker-unavailable. The create flow now reads
directoryPickerKind() per menu open and renders the dialog affordance only
under 'dialog' — browse (until its in-app browser UI lands) and unknown
kinds hide the entry, realizing the seam's documented default; a keyless
workspace-flow snapshot pins the hidden entry over the browse fixture.

The browse backend also resolved wire paths, silently rebasing '' or
relative parents under the host process cwd; both primitives now reject
non-absolute explicit paths with their business codes, and the seam JSDoc
carries the contract.
2026-07-28 17:39:15 +08:00
Chinesezjc 17419aa6b9 test(web): assert the timestamp occlusion the sidebar gutter fixes
The e2e measured the reserved band but never the symptom the change is
named for. Headless chromium defaults to an overlay scrollbar, which is
the configuration where a bar can cover row content at all, so the
scenario already ran in the right mode: against clean master the band is
0 and the bar covers 7px of the relative time.

Adds timeCoveredBy, the overlap between the relative time's right edge
and the range the bar occupies, taking the bar's width from the sheet
where it applies and from the UA's overlay width otherwise. Assuming 0
there would report no occlusion in precisely the state that has it.

Keeps the band assertion rather than replacing it: the two catch
different regressions. Removing only scrollbar-gutter leaves
timeCoveredBy at 0, because the bar is then 8px and the row's right
padding is also 8px, so it abuts the timestamp without covering it.
Removing the pseudo-element width as well is what produces the overlap.
Each was mutation-checked with the other assertions in its test silenced.

Records in the note that the gutter and the ::-webkit-scrollbar width are
jointly necessary against an overlay bar, measured by deleting each from
the live cascade with the other in force: either alone drops the band
from 8 to 0.
2026-07-28 17:22:09 +08:00
creatixchu 006a6655ee feat(web): in-app workspace-directory browser as the shipped picking default
The Open-local-folder flow now branches on the Host's advertised picker
interaction (host.describe.directoryPicker, read per menu open; unknown
kinds hide the entry): dialog keeps the native-chooser flow, and browse
opens the new in-app directory browser (figma Harness 802-56979) —
breadcrumbs rooted at a localized Home crumb, a click-to-edit path zone
right of the crumbs, host-flagged hidden entries filtered client-side,
an inline New-folder row, and Open adopting the listed directory
through the existing workspace-creation error surface. Dialog copy is
localized (ctx.locale, namespace 'workspace'); the plugin re-registers
its entries on locale/change.

apps/cli flips the composed backend from -dialog to -browse, so the
picker works for remote deployments out of the box; -dialog stays a
composable alternative. The workspace-management e2e drops its native
picker monkey-patch and drives the real modal end-to-end via the
path-edit affordance.
2026-07-28 17:15:39 +08:00
Chinesezjc 75ae2cb4eb Merge remote-tracking branch 'origin/master' into feat/scrollbar-tokens 2026-07-28 16:23:44 +08:00
imccyu 9ce201e490 Merge remote-tracking branch 'origin/master' into worktree-guifork 2026-07-28 16:12:12 +08:00
07akioni fff09b2a41 Merge branch 'master' into feat/toolcall-open
Keep openFile path links (no tool-row sidebar handoff) while taking master's
cwd-relative summaries, running sweep, and expandable chevron polish.
2026-07-28 15:55:22 +08:00
_Kerman 019b0abb68 Merge remote-tracking branch 'origin/master' into xtr/identified-immutable-messages
# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-24-separate-context-injection-from-turn-execution.i18n.yaml
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/session.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	packages/core/session/README.i18n.yaml
#	packages/session-title/session-title/tests/persistence.spec.ts
2026-07-28 15:45:53 +08:00
imccyu 0b1a8b3fee fix: ci 2026-07-28 15:25:38 +08:00
07akioni c30c891628 fix: ci 2026-07-28 15:21:34 +08:00
Chinesezjc c3e9690b2e fix(ui-theme): gate the standard scrollbar properties behind the missing WebKit pseudo-element
A non-`auto` `scrollbar-width` or `scrollbar-color` makes Chromium and Safari
discard every `::-webkit-scrollbar*` rule for that element, including
`::-webkit-scrollbar-thumb:hover`. Declaring both unconditionally left the
hover tokens rendering nowhere: the engines implementing the hover
pseudo-element are exactly the ones the standard properties silence, and
Firefox has no hover pseudo-element to fall back on. Both hover tokens and all
four elevated surfaces' hover rebinds were therefore dead code.

Measured in chromium on probe elements with `scrollbar-gutter: stable`: an 8px
`::-webkit-scrollbar` alone reserved a 30px band, and adding
`scrollbar-width: thin` dropped it to the 10px `thin` reserves.

The standard properties now sit inside `@supports not
selector(::-webkit-scrollbar)`, so Firefox takes them and WebKit-based engines
take the pseudo-elements. The WebKit rules stay ungated: an engine without
those pseudo-elements drops them as unknown selectors, and gating them would
hide them from an engine that implements them without `selector()` — the
pre-16.4 Safari the ungated form serves correctly.

Three unit assertions pin the split by source offset, which the existing
at-rule-flattening parser cannot see. The web e2e now reads the path chromium
actually takes: the `auto` standard properties as the gate's signature, the
pseudo-element sizing and track, the indirection variables resolved per
throwaway probe, and the hover declaration as cascade rule text — chromium
folds the `:hover` rule into `getComputedStyle(el,
'::-webkit-scrollbar-thumb')`, so no computed query separates the states.
2026-07-28 15:02:20 +08:00
_Kerman f5ec71f5b1 Merge remote-tracking branch 'origin/master' into xtr/identified-immutable-messages
# Conflicts:
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.i18n.yaml
#	packages/context/session-reference/README.i18n.yaml
#	packages/context/session-reference/README.md
#	packages/context/session-reference/README.zh.md
#	packages/context/session-reference/src/index.ts
2026-07-28 13:58:06 +08:00
_Kerman fbf87e660c refactor: identify and freeze messages at creation 2026-07-28 13:55:59 +08:00
Chinesezjc a6b0cd6f8d Merge remote-tracking branch 'origin/master' into feat/scrollbar-tokens 2026-07-28 13:43:11 +08:00
imccyu 91045a467b Merge branch 'master' into worktree-guifork 2026-07-28 11:50:56 +08:00
Chinesezjc a031967181 test(web): register the sidebar scrollbar e2e on the host plane
Every scaffold-importing e2e compiles on the host plane, so the new file
goes in tsconfig.host.json's include list and apps/web/tsconfig.json's
exclude list. Without both, tsc -p apps/web/tsconfig.json fails with
TS6059/TS6307.
2026-07-28 11:06:03 +08:00
Chinesezjc 662089dd76 fix(client): theme the scrollbars and reserve the workspace list gutter
design-platform.css declared four --dsw-alias-scrollbar-* tokens in both
palettes that no rule read, so every scrolling region rendered the user
agent's own scrollbar and the dark theme showed a light native bar against
dark surfaces.

The symptom that surfaced the gap was in the sidebar: the workspace
browser's session list is its only scrolling region, and each row's
trailing content (the relative timestamp, and the hover action buttons
that replace it) is `flex: none` flush against the row's 8px right
padding, so an overlaid scrollbar painted on top of the timestamp.

ui-theme/styles/scrollbar.css becomes the sole consumer of the four
tokens, imported by the web shell's base.css after design-platform.css
because it reads that sheet's tokens. The rules sit on `body`, not
`html`: the alias tokens are declared on `body`, custom properties
inherit only downward, and from `html` they resolve to the
guaranteed-invalid value with scrollbar-color computing to `auto`.
scrollbar-width and scrollbar-color are declared on `body, body *` rather
than inherited, because inheritance would carry the color already
substituted at `body` and an elevated surface could not retint its own
thumb; scrollbar-width does not inherit at all.

Both the standard properties and the ::-webkit-scrollbar pseudo-elements
read one indirection pair bound to the l1 tokens, so an elevated surface
rebinds that pair to the l2 tokens once and retints both renderings. The
command popup, slash menu, model-select panel, and settings panel do so,
which gives the l2 tokens their first consumers.

WorkspaceBrowser's `.list` declares scrollbar-gutter: stable, keeping the
bar beside the rows. `stable` rather than `auto` so the reservation holds
when the list is short enough not to scroll: expanding a workspace group
would otherwise shift every row sideways at the moment it starts
scrolling.
2026-07-28 11:02:11 +08:00
07akioni fb9495b21e Merge branch 'master' into fix/todo-tool-ui 2026-07-28 10:59:05 +08:00
imccyu a3bdec4450 Merge remote-tracking branch 'origin/master' into worktree-guifork 2026-07-28 10:23:48 +08:00
imccyu af70af4020 Merge remote-tracking branch 'origin/master' into worktree/web-session-model-selector 2026-07-28 00:39:24 +08:00
Tianyi Cui 064cea4ebe Merge remote-tracking branch 'origin/master' into worktree/pr743-merge-20260727
# Conflicts:
#	examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/session-query-spill/session.jsonl
#	examples/cordis-agent/tests/cordis-tools.e2e.ts
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl
2026-07-27 23:59:33 +08:00
imccyu 2b2840a6e1 fix: mount the session-projection registry in the shipped web composition 2026-07-27 23:38:31 +08:00
Tianyi Cui 7a60a523f9 Merge branch 'master' into feature/cordis-temporary-tools 2026-07-27 22:26:49 +08:00
07akioni 560dc1d8d8 Merge branch 'master' into fix/todo-tool-ui 2026-07-27 22:22:40 +08:00