Commit Graph

568 Commits

Author SHA1 Message Date
Tianyi Cui
3a4c436d83 refactor: narrow web image input v1 2026-07-29 23:18:57 +08:00
imccyu
8348a409aa Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input 2026-07-29 23:04:39 +08:00
imccyu
0a1c0dcb07 Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input 2026-07-29 22:52:14 +08:00
imccyu
67acf86b2e Merge branch 'master' into fix/page-scroll 2026-07-29 22:35:13 +08:00
imccyu
87b19a1ded Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input 2026-07-29 22:35:12 +08:00
imccyu
20c446e033 Merge branch 'master' into worktree-renameweb 2026-07-29 22:28:34 +08:00
imccyu
b0ee207a2a Merge remote-tracking branch 'origin/master' into mergebot/pr908
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 22:27:37 +08:00
imccyu
2b56d972eb Merge remote-tracking branch 'origin/master' into mergebot/pr908
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-trajectory/src/client/views.module.css
2026-07-29 22:15:22 +08:00
imccyu
32c3d1e17f Merge remote-tracking branch 'origin/master' into worktree-renameweb
# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/client/test-runtime/src/sessions.ts
2026-07-29 21:45:29 +08:00
imccyu
f4bc0a4a86 Merge remote-tracking branch 'origin/master' into feat/input-command-interaction 2026-07-29 21:40:28 +08:00
imccyu
76b4563380 Merge remote-tracking branch 'origin/master' into feat/input-command-interaction 2026-07-29 21:23:13 +08:00
imccyu
45b21bcc3c fix(client): mark independent replay projections 2026-07-29 21:07:53 +08:00
07akioni
08d097077e fix: cr 2026-07-29 21:03:40 +08:00
imccyu
6e8ad4b382 Merge remote-tracking branch 'origin/master' into worktree-renameweb
# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/README.zh.md
#	packages/session-title/session-title/README.i18n.yaml
#	packages/session-title/session-title/README.zh.md
2026-07-29 20:58:22 +08:00
imccyu
b23c3d596a Merge remote-tracking branch 'origin/master' into trajectory-history-source 2026-07-29 20:58:04 +08:00
07akioni
2a12057345 fix: ci 2026-07-29 20:56:56 +08:00
Yif
be9042e5a1 docs(client): sync package READMEs and agent notes with the input interaction rework
Update the six touched client package README pairs (slash menu ordering,
localized group titles and dismiss, permission label twin, goal pause,
plan hint localization, useAnchoredMaxHeight) and keep the owning agent
notes current: SlashSource.order and the MenuView dismiss/localize/clamp
face in the slash-pipeline note, the pause verb in the goal bar note.
2026-07-29 20:46:29 +08:00
imccyu
64acc5874b test(client): cover independent trajectory history 2026-07-29 20:46:02 +08:00
07akioni
382884e237 fix: scroll to bottom 2026-07-29 20:39:45 +08:00
07akioni
63e1054916 Merge branch 'master' into fix/page-scroll 2026-07-29 20:36:11 +08:00
07akioni
a4602b959e feat: optimize chat page scroll area 2026-07-29 20:26:48 +08:00
xjt
795bdda223 Merge remote-tracking branch 'origin/master' into xjt/readme-proofreading-batch-1
# Conflicts:
#	packages/client/ui-primitives/README.i18n.yaml
#	packages/client/ui-primitives/README.zh.md
2026-07-29 20:21:48 +08:00
imccyu
e0022ff19e refactor(client): isolate trajectory history 2026-07-29 20:21:37 +08:00
xjt
de0348bd9e docs(i18n): standardize reviewed README headings 2026-07-29 20:16:45 +08:00
imccyu
ee9ea7e3aa docs(client): document independent trajectory history 2026-07-29 20:16:13 +08:00
imccyu
acd9716634 fix(client): fixture rename via requireSession, unchanged-title pin gesture
The fixture route shares the requireSession guard, reads the accepted seq off
the appended event, and gains the error-arm spec the workspace.rename case
set as precedent; WorkspaceBrowser drops the unchanged-title block — confirming
the current automatic title IS the pin gesture — and both touched client
READMEs document the new dialog and the unary-settle rule bilingually.
2026-07-29 20:11:43 +08:00
Yif
82a43a7240 test(client): cover menu dismiss, goal pause, and permission label paths
Close the per-file coverage gaps the new UI behavior introduced: MenuView
pointer-outside dismiss (all guard branches), the GoalBar pause action,
the ui-slash injected onDismiss face, and the non-kebab permission name
passthrough.
2026-07-29 19:59:42 +08:00
Yif
45c9205caf feat(client): localize composer hints and rework input command interaction
Unify the /plan claimed hint with the plan placeholder through a locale
namespace, localize slash menu group titles, replace the PermissionSelect
native select with the Menu primitive, add a goal pause verb chain, clamp
anchored popups to the viewport with scroll-into-view and outside-dismiss,
and fix onPasteUpgrade insertedRange to account for the chip trailing gap.
2026-07-29 19:46:48 +08:00
creatixchu
f73bf425ec fix: address ds-review-bot v8 findings
- llm-deepseek: the uncatalogued resolveModel fallback declares text-only
  modalities — the wire route is text-only regardless of catalog
  membership, so "unknown" must not let the host persist-then-fail images.
- session.selectModel also consults the pending-inbox mirror: a queued
  image prompt enters the log only when claimed, after a switch would land.
- attachment store: ensureDurableDirectory syncs every ancestor entry up to
  a caller-vouched boundary regardless of what mkdir reports — a raced
  "already existed" is not "already durable".
- One image walker (imageBlockIn/imageInEvent) now serves both attachment
  authorization and the selection gate; referencedImage therefore also
  authorizes references inside wrapped message content.
- InputHub: the scope disposer resolves the conversation service optionally
  (teardown/HMR must reach quiescence), and a send failing after its scope
  died releases the in-flight drafts instead of restoring them onto a
  disposed shell.
- http-bridge destroys declared-oversize requests with connection: close
  instead of draining a body the client can trickle indefinitely.
- LlmService validates AND detaches modality arrays identically on the
  advisory and exact routes; READMEs record the fourth INVALID_MODEL_INFO
  rejection reason.
- CLI provider docs (JSDoc, README pair, Agent Note pair) describe the
  reuse behavior; llm-route.spec now parses the SHIPPED cordis.yml through
  the production extraction, pinning the row coupling.
- image-display lane pins gallery/rail shape in inline snapshots and the
  object-URL scheme this environment must take; stale host.schema comment
  dropped.
2026-07-29 19:40:17 +08:00
imccyu
c54bbc0f7e test(web): cover the spacer-write and dead-lead spacer branches 2026-07-29 19:38:43 +08:00
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
imccyu
ff049f1e82 feat(client): ISession.rename settles the title projection cell from the response
rename is a per-session verb on the outward session face (prompt/cancel
precedent), not a list-service verb: the Session calls session.rename and
applies the response {title, seq} to its projection store under
higher-seq-wins, so the list row updates before the push frame. The fixture
api and the test-runtime double follow the same face.
2026-07-29 18:59:34 +08:00
creatixchu
adce3b833d fix: address ds-review-bot v6/v7 findings on the image-input assembly
- resolveLlmRoute: reuse the yml pi-ai row for providers it already routes
  (DUPLICATE_ADAPTER boot failure) and detect an unset model by origin, not
  by comparison against one deployment default; covered by a new spec.
- LlmService.resolveModelInfoFor preserves (and validates) modality
  metadata, arming the host image preflight for exact-route resolution.
- session.selectModel refuses a text-only target once the session log
  carries an image on any replayed route; an accepted switch would strand
  every later turn with no in-product recovery.
- The composer no longer gates image intake on the handshake activeModel
  snapshot (wrong authority for a per-session decision); the host preflight
  plus the error strip own capability, deployment limits stay client-side.
- InputHub shell teardown releases the scope's draft images (File objects
  and object URLs leaked for the page lifetime).
- session.prompt image parts carry optional alt into the durable block;
  ImageBlock documents assistant-side rendering as forward compatibility.
- Assembled built-client lane apps/web/tests/image-display.snapshot.ts pins
  the history galleries over the authorized attachment route, the lightbox,
  and the composer paste rail; the attachment rail is an accessible group.
- Docs: validateImage on the seam page, fixture byte metadata matches its
  PNG, and the Agent Note claims now match the shipped coverage.
2026-07-29 18:56:40 +08:00
xjt
e1481e2d98 docs(i18n): resolve follow-up review findings 2026-07-29 18:38:56 +08:00
creatixchu
22e48c1953 Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input
# Conflicts:
#	apps/cli/README.i18n.yaml
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
2026-07-29 18:05:44 +08:00
creatixchu
ae94d32c35 fix(fixture): follow the message-event shape and keep todo_write the alpha log tail
The multimodal sample turn carried the pre-send-unify event shape (bare
content/provenance instead of the message wrapper), crashing the built
client fold; it also sat after the todo_write turn, retiring the plan
projection the TodoPanel tests pin. Wrap both messages through the
fixture helpers and order the image turn before the todo turn; re-record
the code-mode trajectory ordinals the two added message nodes shift.
2026-07-29 17:53:13 +08:00
j-xiang
ed4a6fd026 docs(i18n): address automated review 2026-07-29 17:46:06 +08:00
_Kerman
859452d807 Merge remote-tracking branch 'github/master' into xtr/trajectory-inspection-ui
# Conflicts:
#	apps/web/tests/snapshots/code-mode-round/ui.expected.md
#	apps/web/tests/snapshots/cordis-tool-round/ui.expected.md
#	apps/web/tests/snapshots/fresh-round-trip/ui.expected.md
#	apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md
#	apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md
#	apps/web/tests/snapshots/live-interactions/cancel.expected.md
#	apps/web/tests/snapshots/live-interactions/error-auth.expected.md
#	apps/web/tests/snapshots/live-interactions/retry.expected.md
#	apps/web/tests/snapshots/question-composer/answered.expected.md
#	apps/web/tests/snapshots/seeded-history/ui.expected.md
#	apps/web/tests/snapshots/steering/mid-steer.expected.md
#	apps/web/tests/snapshots/steering/settled.expected.md
#	packages/client/runtime/src/client/contract/session.ts
#	packages/client/ui-conversation/README.i18n.yaml
2026-07-29 17:31:33 +08:00
j-xiang
5bd49b1f0e docs(i18n): address final line audit 2026-07-29 16:53:53 +08:00
Chinesezjc
dffb5c888f test(web): cover the normalized SGR fold and the wide-pair clear
CI's coverage gate rejected `ansi.ts` after the state normalization: the new
fold carries shapes the existing cases never reached.

Added, each expectation checked against a real terminal where the terminal is
the authority — three of my first guesses were wrong and the implementation
was right:

- `48;2;R;G;B` (the extended-background arm and its 4-parameter span), a bright
  foreground and background (`91`/`101`, which resolve to `--dsw-*` tokens
  rather than literal rgb), a `38` with no kind byte, re-opening an attribute
  already in force, and the bare `\x1b[m` reset.
- Clearing a wide pair from the spacer side: `中x\r\bA` shows `A x`, since the
  backspace clamps at column 0 and writing the lead blanks its spacer instead
  of letting the `x` slide left. An erase reaching the lead does the same, so
  `中x\x1b[1K|` shows three blanks before the bar.
2026-07-29 16:48:26 +08:00
Chinesezjc
fdcb45b619 fix(web): bound the SGR state and follow real terminal widths
Nine findings, one critical. Terminal cases verified in a real terminal first.

CRITICAL: cells held the accumulated SGR history, so every state boundary
re-emitted the whole chain — output switching color without a full reset
emitted O(n^2) characters. Measured: 3200 such cells produced 25 MB, and the
reviewer's ~90 KB alternating-color case is well under bash's own output cap.
State is now a normalized record (foreground, background, attribute set) with
one canonical sequence per boundary, so the emitted text is linear in cells;
the 90 KB case parses in 36 ms. That also makes the attribute closers every
chalk-based tool writes actually close: `\x1b[1mbold\x1b[22mplain` leaves the
following write PLAIN, which a real terminal confirms.

Width follows emoji presentation, not the U+2600-U+27BF block: `A✓B` redrawn
with `XY` shows `XYB`, so the check every progress line writes is ONE column.
Taking the block as wide misaligned exactly the output this card exists for.

Writing over either half of a wide pair blanks the other, since a terminal
cannot leave one cell of a two-cell glyph standing.

`line\n\x1b[0m` does not end in a newline as a string yet its last parsed line
holds nothing visible, so the terminator check now reads the parsed lines — it
had added a blank row and inflated the collapse count.

A line with no cursor movement no longer builds a column buffer at all; only
its SGR is folded, so an `ls -R` or a 5k-line log allocates nothing per
character.

The `.terminalDescription` rule had been inserted into an existing grouped
selector, silently giving `.codeBody` description typography and changing its
bottom margin from 4px to 0 — a pre-existing surface this PR does not own.
Split out, `.codeBody`'s margin restored.

Three comments contradicted their code: the fixture's exit-marker line (still
claiming recovery from a marker deliberately removed), `bash-sample`'s header
(still routing a click to the details panel, and calling the consumer's cap the
block's own), and a DetailsPanel comment stacked above the wrong rule. The
ui-primitives README documented only the CR/BS half of the replay, so a reader
would expect `OK0%` where `100%\r\x1b[KOK` renders `OK`.
2026-07-29 16:42:10 +08:00
Chinesezjc
4145cd7075 test(web): cover the cursor replay's remaining branches
CI's coverage gate caught `ansi.ts` at 95.31% branches. My local check had
scoped coverage to that one file, which measures a different test set than
the gate does — the gate is the authority and it was right.

Three branches. Two are now pinned, each verified in a real terminal first:

`ab\r` + U+0301 + `x` shows `xb` — the redraw leaves the cursor at column 0,
so a combining mark has no cell to attach to and the terminal shows nothing
for it. It also revealed that the mark was kept when `cursor` was 0, which is
fixed.

`ab\rX\x1b[31m` then a plain line shows `Xb` unstyled and the next line RED:
the mirror of the reset case, where the scan ends styled while the last cell
is not, so the convergence has to OPEN the run at the line end for it to
reach the following line.

The third was `?? ''` on a `String.split` result, which always yields at
least one element — removed rather than tested, since no input can reach it.
2026-07-29 16:20:01 +08:00
Chinesezjc
b588060b90 fix(web): close a run at the line end and count columns correctly
Eight findings, each terminal case verified in a real terminal first:

`\x1b[32mdone\rok\x1b[0m` then `plain` shows `okne` green and `plain` in the
DEFAULT color. The replay returned the last written cell's state, so a reset
landing after the final write vanished from both the text and the returned
state — and every build tool writes exactly that shape, so the color leaked
onto all later output. The replay now converges to the state the scan ended
in, which is also what it hands to the next line.

`abcd\b\x1b[1K|` shows `   |`: CSI 1K erases THROUGH the cursor column, and
the loop stopped before it. The erase mode also reads only the first
parameter now, since a terminal treats `1;2K` exactly as `1K`.

`éx\rYZ` shows `YZ`: a combining mark takes no column, so it attaches
to the cell already written instead of advancing the cursor and leaving the
`x` standing.

`中x\rA` shows `A x`: overwriting a wide character's lead cell leaves its
spacer as a blank rather than closing the gap, which would shift everything
after it one column left.

The banner lost its span when the gutter became padding — a plain block child
only reaches the content box, so the reserved column was painted in the body
color and the card's top-left radius drawn in it. Invisible in the light
theme, where banner and body share a token; visible in the dark one. The
header now pulls back across the gutter and re-insets by the same amount.

The replay trigger matches the same CSI shape the parser accepts, so a form
like `\x1b[1;2K` can no longer skip its own erase, and `replayLine`'s JSDoc
documents its new parameter and returned pair.

Docs: four places still described the dot as sitting left of the card surface,
which stopped being true when the gutter became the card's own padding, and
two fixture comments still referenced the exit marker that was deliberately
removed.
2026-07-29 16:10:37 +08:00
Chinesezjc
c87a20b506 Merge remote-tracking branch 'origin/master' into feat/web-terminal-card
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.md
#	packages/client/ui-conversation/README.zh.md
2026-07-29 15:44:58 +08:00
Chinesezjc
43de478d10 fix(web): model erase-in-line, tab stops, and cross-line SGR
Six findings. Each terminal-semantics case was checked in a real terminal
(tmux, reading back the painted screen) before changing anything:

`100%\r\x1b[KOK` shows `OK`. Modelling the `\r` without its erase left the
previous frame's tail standing — a regression against the old truncate, since
`\r\x1b[K` is the single idiom every spinner and progress bar writes. Erase is
now part of the same replay, in all three parameter forms.

`a\tb\rXY` shows `XY      b`. Counting a tab as one column produced `XYb` and
destroyed the alignment this card exists to hold, so the cursor now advances
by terminal columns: tabs reach the next 8-column stop and a wide character
takes two cells.

`\x1b[31mabc\rX\nnext` paints BOTH lines red. A newline does not reset the
graphic state, so state threads from one replayed line to the next instead of
closing at each line end.

Only `m` accumulates into a cell's style now. Folding cursor and erase
sequences in grew the state string per redraw and emitted boundaries anser
had to discard.

The empty check reads the parsed lines the card renders rather than the raw
text: output that is only escapes or control bytes survives `trim()` yet
parses to nothing, and drew blank rows plus a copy control for invisible
bytes instead of the placeholder.

The gutter is the card's own left padding rather than a margin. Every render
site rewrites `margin` wholesale for its own indent, which silently cancelled
the reservation and let a container clip the dot.

The fixture sample no longer carries an `[exit code: 1]` line: the real bash
presenter consumes that marker precisely because the card shows the exit as
its own pill, so the built-bundle snapshot had pinned a frame showing it
twice — one the product path cannot produce.
2026-07-29 15:36:16 +08:00
j-xiang
599e6edc87 docs(i18n): record proofread README pairs 2026-07-29 15:30:44 +08:00
j-xiang
90c75be466 docs(i18n): proofread README translations 21-40 2026-07-29 15:29:38 +08:00
07akioni
c8ea9a5204 fix(ui-conversation): share MessageIconActions to clear jscpd clone
User and assistant chrome both rendered copy/branch buttons; one shared
row owns the chrome and keeps clock placement / edit as props.
2026-07-29 15:11:06 +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