Commit Graph

3991 Commits

Author SHA1 Message Date
creatixchu 2b64341bc0 fix(web): align the directory browser with the figma frame and merge the seam tip
The dialog now owns the figma structure through a new headless Modal
mode (mask/card/Escape stay shared): header block with the title and
crumbs 8px apart above the l3 separator (no close chrome — the figma
frame has none), 16px to the level, and the 12px card bottom. The
picker-kind narrowing returns for the merged open describe kind — an
unrecognized advertised kind hides the local-folder entry, now covered
alongside the stale-navigation failure arm and the unmount races.
2026-07-28 17:33:19 +08:00
Tianyi Cui 9c78a7df33 test(snapshot): share identical header sidecars 2026-07-28 17:26:03 +08:00
creatixchu ee5deee0de Merge remote-tracking branch 'origin/feat/directory-picker' into feat/workspace-directory-browser 2026-07-28 17:24:50 +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
creatixchu 6e299cd55a Merge remote-tracking branch 'origin/doc/host-client-group-readmes' into feat/directory-picker 2026-07-28 17:10:00 +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 772653464d fix(connection): hold markerless requests to the Host fence — plain-HTTP browser reads carry no markers
Fetch-Metadata and Origin are only attached to trustworthy destinations, so
over plain HTTP a rebound page's same-origin GET (EventSource, images,
navigations) arrives with no browser markers and a readable response. Remove
the marker shortcut; non-browser clients pass the same fence via loopback,
the CLI-derived LAN IP literals, or a declared authority.
2026-07-28 17:02:39 +08:00
imccyu de56936c87 docs: fix test and docs conflicts 2026-07-28 16:50:07 +08:00
imccyu 6c4e606e61 revert: use session.append 2026-07-28 16:49:55 +08:00
creatixchu 7ff8da56df fix(connection): require trustedHosts entries in canonical authority form
A dangling colon (harness.internal:) or zero-padded port parses cleanly while
WHATWG silently rewrites it, turning an intended exact-port grant into an
any-port grant. Replace the character blacklist with a round-trip check: an
entry must read back from parsing exactly as written (case aside), refusing
the whole rewrite class at load.
2026-07-28 16:49:52 +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 0fcfc5214b Merge remote-tracking branch 'origin/doc/host-client-group-readmes' into feat/directory-picker 2026-07-28 16:42:36 +08:00
Chinesezjc 75ae2cb4eb Merge remote-tracking branch 'origin/master' into feat/scrollbar-tokens 2026-07-28 16:23:44 +08:00
creatixchu 34518cb012 fix(connection): judge an entry's explicit port from the parsed URL, not the raw string
WHATWG trimming strips stray whitespace before parsing, so 'host:port ' passed
the load assert while the raw-string port regex read it as port-less —
broadening an exact-port grant to every port on that hostname. The explicit-
port judgment now reads URL parses under both special schemes (:80/:443 stay
explicit), and the load assert refuses whitespace outright.
2026-07-28 16:19:31 +08:00
imccyu 9ce201e490 Merge remote-tracking branch 'origin/master' into worktree-guifork 2026-07-28 16:12:12 +08:00
creatixchu b9cbe2f029 fix(connection): fail the load on a trustedHosts entry that is not a bare authority
WHATWG parsing would quietly read a hostname out of harness.internal/path or
user@harness.internal, authorizing the typo's hostname; other typos would sit
silently ignored until requests 403. Refuse every URL part beyond host[:port]
at plugin load.
2026-07-28 15:57:02 +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
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
creatixchu 01eea07bab fix(connection): keep LAN serving working under the /api browser-trust fence
Markerless requests pass on any Host (a non-browser sender is the principal
and forges headers anyway); browser Host matching gains port-less entries and
WHATWG normalization; dsh derives LAN IP-literal authorities for an
all-interfaces bind and web grows --trusted-host for named ones.
2026-07-28 15:40:02 +08:00
_Kerman 102ebb8772 Merge branch 'master' into xtr/remove-append-out-of-band 2026-07-28 15:33:34 +08:00
_Kerman b1af35145b fix: enforce message snapshot invariants 2026-07-28 15:33:00 +08:00
_Kerman 0cd28959e8 Merge branch 'master' into xtr/remove-append-out-of-band 2026-07-28 15:32:42 +08:00
imccyu 0bc9fa9546 Merge branch 'master' into fix/web-ui-optimization 2026-07-28 15:26:38 +08:00
Tianyi Cui 16958cdbe7 fix(pty): observe readiness before exact probe threshold 2026-07-28 15:22:05 +08:00
07akioni c30c891628 fix: ci 2026-07-28 15:21:34 +08:00
_Kerman f074444cf0 Merge remote-tracking branch 'origin/master' into xtr/remove-append-out-of-band 2026-07-28 15:19:00 +08:00
_Kerman a39ffb095a fix(session): preserve plugin turn invariants 2026-07-28 15:18:48 +08:00
imccyu ee9627f232 Merge remote-tracking branch 'origin/master' into fix/web-ui-optimization 2026-07-28 15:06:17 +08:00
creatixchu d1ce22e7ad doc(packages): add the host/ and client/ group READMEs and table rows
Both web-GUI groups shipped without the group README that the packages
table names as each group's canonical package/ctx-key map, and without
rows in that table. Adds both bilingual pairs, the two table rows
(ceiling 835→870: two genuinely new product groups joined the canonical
table at minimal row width), and fixes webserver README drift
(WebServerService/ctx.webServer → HttpServerService/ctx.httpServer,
matching src/index.ts).
2026-07-28 15:04:59 +08:00
Chinesezjc fb5c4ef4e3 Merge remote-tracking branch 'origin/master' into feat/scrollbar-tokens 2026-07-28 15:02:38 +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 0a3d38bb08 Merge remote-tracking branch 'origin/master' into xtr/identified-immutable-messages
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-28 14:59:40 +08:00
Tianyi Cui 6a763e4b3c Merge branch 'master' into worktree/ci-flake-followup-20260728 2026-07-28 14:58:47 +08:00
creatixchu 01d68dee4e fix(connection): fence every /api request behind one browser-trust check
The only browser-trust guard covered host.pickDirectory, while the
consequential methods (session.prompt drives bash) accepted any Host —
open to DNS rebinding, where a rebound page reads and writes the API as
if same-origin and only the Host header betrays the attacker's domain.

The pickDirectory-specific loopback guard becomes a prefix-wide fence:
Host must be loopback or an exact host[:port] from the new trustedHosts
config, an attached Origin must equal that authority, and explicit
cross-site markers are refused; requests without browser markers (curl,
tests, native clients) pass, because without a browser there is no
confused deputy. The loopback-socket check is dropped — binding policy
expresses reachability, and the fence is not an auth layer. The Agent
Note records the full threat model and the alternatives.
2026-07-28 14:56:45 +08:00
_Kerman 80ce377c82 test(session-title): cover direct fallback races 2026-07-28 14:56:17 +08:00
imccyu 095e3944ae docs(client): state the reactive-read rules positively 2026-07-28 14:52:04 +08:00
Tianyi Cui eeaf4c7220 fix(ci): stabilize readiness timing boundaries 2026-07-28 14:49:59 +08:00
imccyu 059ba4e0d1 docs(client): add the reactive-read and contract-currency discipline 2026-07-28 14:48:46 +08:00
_Kerman 0225d598e3 fix: preserve message occurrence contracts 2026-07-28 14:44:15 +08:00
_Kerman cee0666a4d refactor(session): remove synthetic log-only turns 2026-07-28 14:41:51 +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
imccyu 2665e55e5d docs(runtime): align the zh README resolution sentence with the privatized resolvers 2026-07-28 14:36:16 +08:00
imccyu d833be412a fix(client): contain notification-callback failures and document the source lifecycle
Review follow-ups: the three new notify loops (currentProvideInfo
subscribers, ui-skill lexicon listeners, late-registration controller
setup) now contain per-callback failures so one faulty consumer cannot
starve the rest, abort the list projection pass, or poison the source
roster with no disposer; controller lexicon polling drops a throwing
source with a console record like the candidate path. The ui-slash
README (both languages) now states the late-registration warm and the
subscribeLexicon contract, and the scenario suite drives a typed /name
token gaining its decoration when the roll settles with no further
input.
2026-07-28 14:33:37 +08:00
_Kerman 971f20b66e fix: restore message migration CI coverage 2026-07-28 14:29:54 +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
imccyu f331f248d8 fix: static 2026-07-28 14:16:14 +08:00
_Kerman 350c296cff fix: complete immutable message migration 2026-07-28 14:15:23 +08:00
imccyu 2b74db670e refactor(client): rename the provide reprojection to updateCurrentProvideInfo and privatize the id resolvers
provideInfo(id)/maybeProvideInfo(id) lost their last external caller
when the renderer host switched to the currentProvideInfo observable;
both become private (tests assert through the public projection). The
reprojection method's name now says what it does — re-derive and
publish on change — and matches the field family it maintains.
2026-07-28 14:06:08 +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