Commit Graph

621 Commits

Author SHA1 Message Date
creatixchu
f5ab6d94a8 Merge remote-tracking branch 'origin/master' into worktree/approval-panel-max-height 2026-07-30 18:59:06 +08:00
creatixchu
12b55adf6b fix(web): keyboard reach and resting metrics on the approval scroll region
Review follow-ups on the approval takeover:

The scroll region is now a tab stop (tabIndex + named role="group"). The
question composer's scroll body needs none — its option rows are focusable and
pull the container along — but this one holds nothing but text, so a
keyboard-only user could reach the buttons and never the command's tail, and
approve what they could not finish reading.

The action row's padding reproduces the 14px gap it had inside the body: the
flex gap of 6 plus its 8px top margin, neither of which reaches it now that the
row sits outside the scroll region. The resting card is unchanged again.
2026-07-30 18:35:20 +08:00
Chinesezjc
8c5c4b46c8 fix(web): address diff card review — split terminator, error arm, wire narrowing
- DiffBlock: an empty side contributes zero lines and a trailing newline is a
  terminator, so a create ending in a newline draws one added line (not a
  phantom empty one) and a full deletion draws no phantom + line.
- diffCardModel: narrow the wire diffs payload (card is the only validated
  field) so a malformed diff card falls back to the generic path instead of
  throwing inside DiffBlock.
- FileMutationRow: surface the result text when an errored mutation has no diff
  card, so a failed edit/write is more than a red dot.
- copyText ends its closed union on assertNever.
- Docs: drop the "bridge relativizes" claim, record the file-count divergence
  from the TUI footer, correct the built-boot overclaim, note why the row title
  outranks the view title, and make fixture turn 67 args self-consistent.
- Tests: terminator/empty-side/interior-blank rows, wire-narrowing null arms,
  the error-text arm and its name/code fallback, stopped state, no-path summary,
  and the registration/disposal shape.
2026-07-30 18:32:55 +08:00
kingwl
1f5d09c2d7 Merge origin/master into codex/figma-context-injection-row
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 18:27:49 +08:00
kingwl
cdd1074805 Merge remote-tracking branch 'origin/master' into codex/queue-collapse
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 18:21:07 +08:00
Hypatia May
d0e387dfdc Merge remote-tracking branch 'origin/master' into codex/status-bar-token-metrics
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 18:19:35 +08:00
Chinesezjc
7a60a236bc feat(web): render read tool output as a line-numbered code card
Consume the card:'read' result view (path, numbered lines, totalLines, lang)
the read backend PR added. ReadBlock (ui-primitives) draws a per-line gutter
with each line's own file number, shiki highlighting via a new highlightLines
returning per-line token arrays, a 显示 X / Y 行 window note, a height cap
matching TerminalBlock, and a copy control. read-card-model is the single
resultView derivation; a keyed ReadRow registers under read with the card
resident under its path-link summary. The generic fallback and the details
panel are read-aware. Fixture gains a windowed read turn for the built-boot
snapshot.
2026-07-30 18:15:38 +08:00
creatixchu
c0679f42b5 fix(web): cap the approval takeover at the composer's text height
The approval panel replaces the InputBar while a sandbox escalation waits,
and its justification and command are unbounded model text. With no height
cap, a long command grew the card until the refuse/allow row went under the
fold: at 900x700 the action row's bottom landed at y=749, so the user could
read the request and not answer it.

Justification and command now scroll in one region capped at the same height
as the composer's draft area, with the amber strip and the action row outside
it. The cap is one value with two consumers — declared as
--dsh-composer-text-max-height on ConversationRoot's .composerSeat, the
composer chain's only shared ancestor — so the seat cannot cap its two states
differently. The card rebinds the l2 scrollbar pair like every other scrolling
surface on an elevated background.

Covered by a new web e2e scenario that drives the real composition (read-only
session, denied write, the model's escalation retry, answer clicked through
the panel) and measures the live panel at two viewport heights against the
composer's own cap, read off the textarea rather than hardcoded.
2026-07-30 17:50:04 +08:00
Chinesezjc
f6802ee019 feat(web): render web_search/web_fetch output as a web card
Consume the card:'web' result view (structured sources + answer for search, the
URL and HTTP status for fetch) the web backend PR added. WebBlock
(ui-primitives) draws both kinds via the kind discriminant: a citation list of
safe external links (the MarkdownText protocol allowlist, title-or-hostname
label), a truncation indicator, a height cap matching TerminalBlock; a fetch
summary for the other kind. web-card-model is the single resultView derivation;
a keyed WebRow registers under web_search and web_fetch with the card resident
under its summary. The generic fallback and the details panel are web-aware.
Fixture gains web_search and web_fetch turns for the built-boot snapshot.
2026-07-30 17:43:13 +08:00
Chinesezjc
71adea8ba4 feat(web): render grep/glob search output as a search card
Consume the card:'search' result view (matches grouped by file for grep, a
path list for glob) the search backend PR added. SearchBlock (ui-primitives)
draws both kinds via the kind discriminant with a per-file collapse, a
truncation pill, a height cap matching TerminalBlock, and a copy control;
search-card-model is the single resultView derivation; a keyed SearchRow
registers under grep and glob with the card resident under its summary. The
generic fallback and the details panel are search-aware. Fixture gains grep and
glob turns for the built-boot snapshot.
2026-07-30 17:42:59 +08:00
kingwl
3d6cacc59b Merge remote-tracking branch 'origin/master' into codex/composer-dock-stacking
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 17:35:22 +08:00
kingwl
f5228e7c71 Merge origin/master into codex/figma-context-injection-row
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/ToolRow.module.css
#	packages/client/ui-conversation/src/client/chat/ToolRow.tsx
2026-07-30 17:34:14 +08:00
creatixchu
d9cb19f276 feat(ui): drop the slash and the argument echo from the command row
The web command row renders `title · summary` from one logged command
lifecycle pair, and the two halves were written without knowing about each
other: the title was the dispatched line rebuilt from `command/run` and the
summary was `command/done`'s verbatim text, so every Access-chip pick read
`/permission workspace-write · Permission preset: workspace-write.` — the
command name twice and its argument twice.

The title is now the bare command name (no `/`, no arguments — the summary
already says what the command did), and a command handler's settlement text
never repeats the command's own name, so `/permission` returns `preset
workspace-write`. The row reads `permission · preset workspace-write`, and
the TUI notice still names the preset that now applies. The log is
unchanged: `command/run` keeps its structured name/args split for a richer
registered row.
2026-07-30 17:34:03 +08:00
Hypatia May
16378e4ba7 Merge remote-tracking branch 'origin/fix/human-transcript-projection' into fix/web-transcript-projection
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 17:33:55 +08:00
_Kerman
d1dc303bc6 Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification
# Conflicts:
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/session.i18n.yaml
#	docs/persistence-catalog.md
#	packages/cordis/tool-cordis/src/api-catalog.ts
2026-07-30 17:30:10 +08:00
kingwl
abf498b8dc fix(web): align composer context stack 2026-07-30 17:26:44 +08:00
Hypatia May
fd0fa8806f Merge remote-tracking branch 'origin/master' into codex/status-bar-token-metrics
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 17:22:42 +08:00
Hypatia May
6d58953f30 fix(token-meter): close projected usage review gaps 2026-07-30 17:22:15 +08:00
Hypatia May
da41677049 fix(web): address transcript review follow-ups 2026-07-30 17:10:45 +08:00
Chinesezjc
d7e46bea35 test(web): update chat-apply keyed-entry assertion for the file-mutation rows
The diff card registers edit and write into the keyed toolview hole, so the
mounted-entry set is now ['bash', 'edit', 'write', 'todo_write'].
2026-07-30 16:45:00 +08:00
kingwl
0a25c0d237 feat(web): add queue collapse control 2026-07-30 16:41:55 +08:00
Hypatia May
3b3d5579cb Merge remote-tracking branch 'origin/fix/human-transcript-projection' into fix/web-transcript-projection
# Conflicts:
#	apps/web/tests/snapshots/seeded-history/ui.expected.md
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/README.md
#	packages/client/runtime/src/client/index.ts
#	packages/client/runtime/src/client/sessions/fold-adapter.ts
#	packages/client/runtime/tests/fold-adapter.spec.ts
#	packages/client/ui-trajectory/src/client/layout.ts
#	packages/client/ui-trajectory/src/client/spans.ts
#	packages/compact/compact/README.i18n.yaml
2026-07-30 16:37:22 +08:00
kingwl
17893c503e feat(web): match context injection disclosure design 2026-07-30 16:20:34 +08:00
Chinesezjc
d2582b8dc1 feat(web): render write/edit tool output as a diff card
The write/edit tools already declare card:'diff' with applied hunks on
callView/resultView, but the Web client discarded it: a mutation landed on
GenericToolCard and the details panel flattened the result to a <pre>. Add
DiffBlock (ui-primitives), diff-card-model (the single callView/resultView
derivation), and FileMutationRow (keyed under write and edit), and make the
generic fallback row and the details panel diff-aware. The +/- block form,
per-file path header, same-file gap, and footer mirror the TUI diff card;
the chat row caps at CHAT_DIFF_MAX_LINES against the panel's full height.
2026-07-30 16:11:59 +08:00
_Kerman
4370004360 refactor(agent): expose mutable inbox state 2026-07-30 15:35:18 +08:00
imccyu
4c33ca8bec fix: hero layout when no-workspace 2026-07-30 15:25:50 +08:00
imccyu
6ea1238714 docs(web): the composer bar is one session-maybe slot, not a swapped pair
fix(web): keep one composer bar DOM across the no-workspace transition

The composer.bar slot moves from session to session-maybe scope: with no
current session the entry still mounts, the machine faces (keyboard, stop,
command) arrive undefined, and the bar renders its normal DOM inert via the
disabled owner prop. DisabledInputBar and its parallel tree are gone, so the
textarea node survives the cold-start workspace pick instead of flashing
through a remount. A blank session whose workspace was deleted takes the
same inert path through owner props.

test(web): add the composer DOM-continuity acceptance probe

Drives a real dsh web server with headless chromium through the cold-start
-> pick-workspace -> type flow and asserts the composer textarea is the
same DOM node throughout (a marker property must survive). Rerun
prerequisites are in the header comment.

docs(web): session-maybe identity is adoption, not hold-forever

fix(web): session-maybe entries adopt the first session, then remount like strict entries

A session-maybe entry used to keep one React instance across every
transition, so component-local state leaked between sessions once the
composer bar moved to that scope (PermissionSelect's optimistic pick, the
IME composition guard). Identity is now adoption: an incarnation born
session-less holds through the arrival of the first session (the blank
shell's DOM survives the workspace pick), and afterwards behaves exactly
like a strict session entry — a switch or a drop to no-session remounts,
clearing local state by construction. The child key is an incarnation
counter kept in the stable outlet wrapper via render-phase setState.

chore: knip knows the root acceptance probe's playwright dependency

scripts/hero-composer-dom-continuity.mjs resolves playwright through
apps/web's devDependency tree (createRequire), which knip cannot follow;
ignore it at the root workspace.
2026-07-30 15:18:06 +08:00
imccyu
03936cb320 Merge remote-tracking branch 'origin/master' into mergebot/pr883
# Conflicts:
#	packages/client/ui-question/package.json
#	packages/client/ui-question/src/client/QuestionComposer.tsx
#	packages/client/ui-question/src/client/contract/slots.ts
#	packages/client/ui-question/src/client/index.ts
#	packages/client/ui-question/src/client/locales.ts
#	packages/client/ui-question/tests/browser-plugin.spec.ts
#	packages/client/ui-question/tests/question-composer.spec.tsx
2026-07-30 15:01:10 +08:00
Hypatia May
8a8c1965d7 feat(web): show durable token usage and context occupancy in the stats line
The chat stats line took its token totals from the loaded conversation nodes,
so paging changed them and compaction erased the billing behind replaced
content. It also had no way to show context occupancy: the numerator and
capacity never reached the browser.

Both now come from token-meter session projections read through the standard
useProjection seat. Window nodes keep supplying turn and step counts plus LLM
and tool wall times, which are correctly window-scoped facts about what is on
screen; accounting no longer comes from there.

`tokenUsage` supplies billing and cache hit. `contextPressure` supplies
occupancy, pairing the newest provider-reported prompt size with the newest
capacity recorded by `request/context`. Deployments without token-meter drop
the token groups; a route whose adapter advertises no capacity drops the
occupancy group rather than rendering a placeholder.

Occupancy is deliberately approximate: the numerator and capacity are
independent last-wins fields, not one atomic request observation, so switching
models pairs a fresh capacity with the prior route's pressure until the next
request reports usage. It is a user-facing reference figure that nothing in the
harness makes decisions from, and it matches how the TUI status line has always
computed occupancy. The Agent Note and token-meter README state this as a
decision, including why the atomic alternative was implemented and rejected, so
it is not re-litigated as a defect.

Snapshot delta is one added `Context N% of 128K` segment across eight web
goldens; the preceding commit absorbed master's pre-existing golden drift.
2026-07-30 14:48:19 +08:00
Hypatia May
7f30a7e30c Merge remote-tracking branch 'origin/master' into codex/status-bar-token-metrics
Conflict resolution notes:

- StatsLine: master redesigned the row into pipe-separated groups with LLM and
  tool wall times. Kept that design and swapped only the token accounting
  source, so counts and durations stay window-scoped while billing and context
  occupancy read the durable projections.
- Generated artifacts (cordis catalog, module graph, event producer/consumer,
  i18n pairing hashes) and web snapshots took master's side; they are
  regenerated and re-recorded after this merge.
- Web e2e goldens and details-panel/timeline assertions took master's side:
  that evolution is unrelated to this branch.
- ui-conversation package.json: kept master's devDependency ordering, re-adding
  only the token-meter entry this branch needs.
2026-07-30 13:56:39 +08:00
Hypatia May
4819210142 refactor(token-meter): make context occupancy durable projection state
Replace the transient `session/model-request` mux frame with ordinary durable
session state. Occupancy now rides two last-wins projection fields instead of a
non-replayable frame that needed removal tombstones and cross-stream fencing.

The frame was the only non-replayable class on the mux stream. Because host and
mux are independent SSE streams with no cross-stream order, a request emitted
before a removal could arrive after `host/session-removed`, and a legitimate
request for a new lifecycle reusing the same id could be fenced by a late
removal. Fixing that needed a lifecycle generation on every frame; the frame
itself was the problem.

Removed: the `session/model-request` frame and schema, the `agent/model-request`
core event, the ApiProxy measurement point, the client-side telemetry map and
removal tombstone, and the synthetic `cancelled` open error used to signal
reconnect through the error channel.

Added: `request/context`, a log-only session event recording the
registration-bound capacity of the route a request resolved to, appended beside
`request/header` from the lookup that already prepared the call and skipped when
the route is unchanged. Capacity stays out of `EpochHeader` because it is
adapter metadata about a route, not an input the request was built from, so it
must not join request reconstruction or header equality.

The `contextPressure` projection pairs the newest provider-reported prompt size
with the newest recorded capacity. The two are deliberately not one atomic
request observation: switching models can pair a fresh capacity with the prior
route's pressure until the next request reports usage. The figure is a
user-facing reference, and this matches how the TUI status line has always
computed occupancy.
2026-07-30 13:53:08 +08:00
kingwl
751b970997 fix(web): align queue panel with responsive composer 2026-07-30 12:25:48 +08:00
imccyu
6e99027917 Merge remote-tracking branch 'origin/master' into mergebot/pr937
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/queue/QueueDock.module.css
2026-07-30 11:59:59 +08:00
kingwl
ad1bb84425 Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-30 11:38:54 +08:00
07akioni
b92c6bcc66 Merge branch 'master' into fix/ui-action-display 2026-07-30 11:15:35 +08:00
imccyu
60620ec36c Green the jsdom lane for the composer-seat ResizeObserver and new StatsLine format
The seat's height publisher needs a ResizeObserver stub in every spec that
renders ConversationRoot (jsdom has none), and the two branch-tail StatsLine
assertions move to the grouped detail-row output.
2026-07-30 11:09:03 +08:00
Yichen Jiang
a35e372594 Merge remote-tracking branch 'origin/master' into worktree/web-model-request-retry
# Conflicts:
#	apps/web/tests/session-title.snapshot.ts
2026-07-30 10:27:00 +08:00
Yif
04f6dfdc29 Web composer stats detail row and input-zone polish
Stats line moves into the InputBar's new footer slot (sharing the card's
width column) and expands to the design's grouped detail row: turns/steps,
LLM and tool wall time, cache hit, and input/output token split, all
derived client-side from the snapshot. The composer stack owns one 8px
rhythm, the seat fades the transcript through a fixed 36px gradient band,
back-to-bottom follows a live --dsh-composer-height, and goal/todo strips
share one 752px tip-fill column.
2026-07-30 10:22:44 +08:00
Hypatia May
8e5c792b50 round 1: project the web transcript from append-origin events
Replace the surface-ordered fold with a log-ordered human transcript:
append-origin surface events at their own log positions plus one marker per
landed compaction checkpoint. Command folding, the tool-call index, and the
rev-keyed memo carry over unchanged.

Removes foldDegraded, the padding sentinels, baseSeq, and degradedSeqs() --
they existed only to satisfy the core fold's seq === index assertion. That
also closes the pagination hole A1 exposed: a page can carry a checkpoint
whose shadowed range fell outside the window, and nothing resolves
surfaceOp.start anymore.
2026-07-30 10:18:24 +08:00
kingwl
112b0fbad1 fix(web): address queue review feedback 2026-07-30 04:12:38 +08:00
kingwl
ebbcfdd03b Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	packages/core/agent-loop/src/agent.ts
2026-07-30 03:33:41 +08:00
kingwl
7ce330f0e4 refactor(agent): scope queue actions to edit and remove 2026-07-30 01:58:51 +08:00
imccyu
93fc1e2ab8 Merge branch 'master' into feat/ask-question-gui 2026-07-30 01:46:05 +08:00
imccyu
3c8cd4eca3 fix(web): repair merge tails — todo-row selector and composer handler clone
The #921 selector change and the duplication gate both first ran against
this branch after the merge made it MERGEABLE: assembly-surfaces still
queried the retired data-sample="todo-row" hook (the composed TodoRow
carries ToolRow's data-tool attribute instead), and the redesigned
QuestionComposer duplicated the custom-draft onChange/onKeyDown pair
across its inline input and optionless textarea. The spec now anchors on
data-tool="todo_write", and the composer shares one draftCustom /
continueFromCustom handler pair (Enter continues, Shift+Enter stays a
newline, IME composition stays inert).
2026-07-30 01:34:56 +08:00
imccyu
e56c0699a9 Merge branch 'master' into codex/web-queue-actions 2026-07-30 01:21:13 +08:00
Tianyi Cui
4582e1425c Merge commit 'refs/codex/pr885/master-20260730' into worktree/retarget-pr885-20260729
# Conflicts:
#	eslint.config.mjs
2026-07-30 01:18:28 +08:00
imccyu
643f9be33f Merge remote-tracking branch 'origin/master' into mergebot/pr883
# Conflicts:
#	apps/web/tests/todo-display.snapshot.ts
#	docs/event-producer-consumer.md
2026-07-30 01:16:46 +08:00
imccyu
d9eb3545d8 Merge remote-tracking branch 'origin/master' into mergebot/pr883
# Conflicts:
#	packages/client/tsdown.client.ts
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/client/ui-conversation/src/client/chat/PendingCard.tsx
#	packages/client/ui-conversation/src/client/chat/ToolRow.tsx
#	packages/client/ui-conversation/src/client/toolviews/todo-row.module.css
#	packages/client/ui-conversation/src/client/toolviews/todo-row.tsx
#	packages/client/ui-conversation/tests/chat-apply.spec.tsx
#	packages/client/ui-conversation/tests/coverage-tails.spec.tsx
#	packages/client/ui-conversation/tests/todo-panel.spec.tsx
#	packages/client/ui-primitives/src/icons/index.tsx
#	packages/client/ui-primitives/tests/icons.spec.tsx
#	packages/client/ui-question/README.i18n.yaml
#	packages/client/ui-question/src/client/QuestionComposer.module.css
#	packages/client/ui-question/src/client/QuestionComposer.tsx
2026-07-30 01:01:14 +08:00
kingwl
c97b1d025e Merge remote-tracking branch 'origin/master' into codex/web-queue-actions
# Conflicts:
#	apps/web/tsconfig.json
#	docs/architecture.i18n.yaml
#	docs/event-producer-consumer.md
#	packages/client/runtime/README.i18n.yaml
#	packages/client/tsdown.client.ts
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/core/agent-loop/README.i18n.yaml
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/README.zh.md
#	packages/host/apiproxy/README.i18n.yaml
#	tsconfig.host.json
2026-07-30 00:30:38 +08:00
Yichen Jiang
3eec30c278 Merge remote-tracking branch 'origin/master' into worktree/web-model-request-retry
# Conflicts:
#	apps/cli/README.i18n.yaml
#	apps/web/tests/snapshots/live-interactions/retry.expected.md
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/src/client/index.ts
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.md
#	packages/client/ui-conversation/README.zh.md
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
#	packages/client/ui-conversation/tests/chat-branch-tails.spec.tsx
#	packages/client/ui-trajectory/README.i18n.yaml
#	packages/client/ui-trajectory/README.md
#	packages/client/ui-trajectory/README.zh.md
#	packages/client/ui-trajectory/src/client/spans.ts
#	packages/client/ui-trajectory/tests/views.spec.tsx
#	packages/llm/llm-retry/README.i18n.yaml
#	packages/llm/llm-retry/README.zh.md
2026-07-30 00:16:32 +08:00