Commit Graph
60 Commits
Author SHA1 Message Date
zhc bc1bff3c82 test(web): pin message snapshot calendars across midnight 2026-10-22 00:14:00 +08:00
Kaige-Gaoandimccyu 0778dec09f feat(ui-user-questions): show answered batches as shared message bubbles (#6362)
* feat(ui-user-questions): show answered batches as shared message bubbles

* refactor(ui-primitives): share clipboard confirmation lifecycle

* test(web): include answered question bubbles in steering goldens

* fix(ui-user-questions): keep answered turns collapsible

* test(ui-user-questions): drop the removed compactAnswer expectation

master removed ChatTurnProcessPresentation.compactAnswer in aaeb344
("fix(chat): keep the reply gap on a folded final answer"); reply spacing
now comes from the adjacent-row rules. The rebase left this assertion
behind, so the parametrized replay/live/prepend cases failed on every CI
coverage lane even though typecheck stayed green: toMatchObject accepts
the stale property.

* fix(ui-user-questions): address answer bubble review feedback

* test(web): observe file card styles after both cards mount

---------

Co-authored-by: imccyu <[email protected]>
2026-10-21 23:44:02 +08:00
yudshj f9816f62eb Merge origin/master into fix/question-composer-compact-details
Re-record the merged Answering section's bilingual pairing hashes and add the new Expand/Collapse copy to the Japanese dictionary.
2026-10-21 16:26:39 +08:00
yudshj fb290b388d fix(ui-user-questions): clip dropped lines from hit testing
A collapsed question or description keeps its full line budget and only
masked its dropped line, so that transparent line still took clicks: it
covered the first line of the question detail and the top edge of the
custom answer row. clip-path now removes the line from hit testing as
well as from view, and Web e2e hit tests pin both targets.

Expansions also record the question they belong to and apply only while
that question is shown, so a position change from another surface of the
same Session no longer carries them to a different question. `.title`
returns to its base margin; `.questionTitle` owns the flex sizing.
2026-10-21 16:20:04 +08:00
yudshj f8a094e465 fix(ui-user-questions): label every copy toggle Expand or Collapse
Option names made the toggle tooltips as long and unpredictable as the
option labels themselves. Every question and description toggle now uses
the same Expand and Collapse copy, and the question toggle, like the
description toggles, is described by the text it controls.
2026-10-21 16:20:04 +08:00
yudshj 5d5bd8eb41 test(web): re-check long question copy across chat and window widths
A long question with long, width-sensitive, and short option descriptions
is driven through the transcript width handle at its narrowest and widest
positions, an opened and collapsed right sidebar, and a smaller and
restored window. At each settled width every collapsed copy follows its
own overflow, the expanded description stays expanded, and the actions
stay reachable; collapsing the sidebar or restoring the window returns
the wide state exactly.
2026-10-21 16:20:03 +08:00
yudshj 012bfe03e2 style(ui-user-questions): expand long copy with chevron icon buttons
The expand and collapse controls reuse the composer's 24px icon button
with the existing downward and upward chevron icons instead of text. Each
carries a localized accessible name, which a portaled Tooltip shows on
hover. The fade at the end of clipped copy narrows to the 24px button.
2026-10-21 16:20:03 +08:00
yudshj 45fd961413 refactor(ui-user-questions): expand long copy in place
A question shows in full up to three rendered lines and an option
description up to two. Longer copy keeps one line fewer, fades at the end
of that line, and offers a "More" text button that expands it in place;
expanded copy offers "Show less" on its own line.

CSS scroll timelines decide which copy overflows, so the composer no
longer measures layout in an effect. Each box keeps its full line budget
plus a 2px glyph allowance, and a negative margin returns the dropped
line, so the overflow reading never depends on the collapsed layout.
Navigation resets scroll and expansions from the navigation handler.
2026-10-21 16:20:03 +08:00
yudshj 2e420e6fad test(client): verify responsive question disclosures after rebase 2026-10-21 16:20:03 +08:00
yudshj 2b6360c1d9 refactor(ui-user-questions): let CSS wrap option descriptions 2026-10-21 16:20:02 +08:00
yudshj 50a9e31c2c fix(client): preserve question focus and dismiss hover cards 2026-10-21 16:20:02 +08:00
yudshj fbc2550f52 fix(ui-user-questions): preview long questions in three lines 2026-10-21 16:20:02 +08:00
yudshj 9d44ecefb7 style(ui-user-questions): fade truncated option details 2026-10-21 16:20:02 +08:00
yudshj 935a891a45 fix(ui-user-questions): preserve inline short option descriptions 2026-10-21 16:20:02 +08:00
yudshj 005bb7255a test(web): verify question callout in dark mode 2026-10-21 16:20:01 +08:00
yudshj 5b96747630 fix(ui-user-questions): refine option detail callouts 2026-10-21 16:20:01 +08:00
yudshj 1cbf50d03e test(web): stress long question layouts 2026-10-21 16:20:01 +08:00
yudshj aa099a9b40 fix(ui-user-questions): keep long questions answerable 2026-10-21 16:20:01 +08:00
creatixchu b7c9d1d7a5 fix(approval): keep generic question fallback answerable 2026-10-20 13:08:24 +08:00
Magolor ed34a1d7fe fix: keep queued question replies read-only after reload 2026-09-28 23:21:38 +08:00
Magolor b6401085cb fix(user-questions): address review findings 2026-09-28 23:21:36 +08:00
Magolorandimccyu 3a296b16b4 feat(user-questions): support timed waits and late replies
Co-authored-by: imccyu <[email protected]>
2026-09-28 23:21:35 +08:00
Turtle 32905d5ab5 Revert "feat: reconcile timed questions with legacy default" 2026-09-24 20:06:09 +08:00
Magolorandimccyu bb19061473 feat(user-questions): support timed waits and late replies
Co-authored-by: imccyu <[email protected]>
2026-09-24 19:43:16 +08:00
imccyu 12d9dd6aa4 test(web): refresh chat process group snapshots 2026-09-22 00:45:46 +08:00
Yichen Jiang cbae324bfa feat(workspace): stop a Session's running work before archiving it (#4765)
* feat(workspace): stop a Session's running work before archiving it

Archiving was a pure visibility write, so a Session archived mid-turn kept
running out of sight. The Workspace registry now owns archive admission
through two Host events: `workspace/session-activity` reports what still
runs and refuses the plain archive as `workspace/session-active`;
`workspace/session-stop`, requested with `stopActivity`, stops that work the
way the user's own stop actions do before the archive write. The API Session
Controller reports and stops turns, subagent descendants, and owned jobs and
rejects any model step for an archived Session; the Schedule plugin reports
and deletes active reminders. The sidebar turns the refusal into a
stop-and-archive confirmation listing the Host's answer.

* test(workspace): pin the widened archive signature and prove child liveness by heartbeat

The Client inspect catalog spec pins archiveSession's new options
parameter, and the archive e2e reads the Bash child's liveness from a
heartbeat file instead of a pid: the Linux sandbox runs the tool in its own
PID namespace, so the pid it reports is not comparable from the test.

* test(workspace): cover the archive-admission providers and dialog to the per-file gate

Drop the provider's unused disposer and the dialog's unreachable confirm
guard, read reminders without a catch that no composition can reach, and
add the cases the coverage lane found missing: a stop without a jobs
registry, a looping lineage, a descendant whose projections reject, the
dialog's Escape guard and non-Error reason, and a family merged by another
provider.

* fix(workspace): write the archive before stopping, gate subagent lineage, and delete reminders under the schedule barriers

Review round on #4765. The registry now writes the archive set before it
dispatches `workspace/session-stop`, so the durable set already gates
every wake the stops induce; the controller's `agent/pre-step` gate also
blocks subagent descendants of an archived Session and contains each
cancel or kill on its own. The Schedule plugin's stop listener runs as a
management delete in the agent's transaction queue between the same two
persistence barriers the `schedule_delete` tool uses. The confirm dialog
selects singular or plural English lines and keys list rows by index.
Docs: archive-admission section with type-equiv blocks on the workspace
subsystem page, write-first order and residual windows in the READMEs
and the Agent Note, and the missing zh reminders sentence.

* test(web): scope the question composer's New Session wait to the Sessions tree

The wide sidebar's New Session button carries the same visible label as
a fresh session row, so the unscoped `getByText` either settled on the
button before the row existed or hit a strict-mode violation once the
row rendered first, which is how the snapshots lane failed on
ece68c2ab5. Waiting inside the Sessions tree names the row alone.

* fix(schedule): answer archive admission from the owned runtime's fold, not the projection registry

The `sessionProjections.snapshot` API is the Client projection view and
is not a Host read path (review on #4765). `ScheduleRuntime.activeRecords()`
folds the live log the way every drive does, and the archive-admission
listeners ask the owned runtime for that fold: a session without a live
agent or without an owned runtime has nothing armed to fire, so it reports
nothing and has nothing to stop. Covers the runtime-less agent, a fold that
turns unreadable at the persistence barrier, and the stopping/faulted
runtime answering nothing.

* refactor(subagent): report and stop subagent descendants from the Subagent runtime

The `subagent` family of archive admission moves out of the API Session
Controller into `dsh-subagent`, which records the lineage at delegation
and owns the descriptor (review on #4765): `SubagentRuntime` answers
`workspace/session-activity` with the running descendants, labelled from
each child's descriptor through a live Session observation, and
`workspace/session-stop` by cancelling each of them with the parent
cause. The controller keeps turns, owned jobs, and the lineage step gate,
and composes its provider through `ctx.plugin(SessionActivityProvider)`
with declared injections instead of a bare installer call. `dsh-workspace`
becomes an optional type-only peer of `dsh-subagent`.

* refactor(jobs): answer archive admission for owned jobs from the job registry seam

The `job` family moves out of the API Session Controller into `dsh-jobs`
(review on #4765): the seam's constructor installs the
`workspace/session-activity` and `workspace/session-stop` listeners for
every implementation through the abstract `list` and `kill` alone, so the
controller no longer knows the jobs vocabulary and keeps only the turn
family and the archived-lineage step gate. `dsh-workspace` becomes an
optional type-only peer of `dsh-jobs`.

* refactor(workspace): leave SessionActivityKindMap empty and let each provider merge its family

The workspace package no longer names any activity family (review on
#4765): `SessionActivityKindMap` is empty, and each provider merges its own
key from a module both its faces import — `turn` in the API Session
Controller's types, `job` in the job registry seam's view, `subagent` in
the Subagent runtime's control types, `schedule` in the Schedule plugin's
types. The confirm dialog imports those modules for its cases and keeps
the generic line for any other key; the registry and controller suites
merge test-owned families instead of borrowing the providers'.

* refactor(agent): report and stop the running turn from the Agent registry

The `turn` family moves out of the API Session Controller into `dsh-agent`
(review on #4765): the registry's constructor installs the
`workspace/session-activity` and `workspace/session-stop` listeners for
every Agent it publishes, answering with its own lookup and cancelling the
turn with the user cause, and merges the `turn` key from its client-safe
types. The controller keeps only the archived-lineage step gate, renamed
`ArchivedSessionGate`. `dsh-workspace` becomes an optional type-only peer
of `dsh-agent`; the workspace package depends on none of the providers,
so the edge stays acyclic.

Since #3127 a foreground Bash command is a registered job from its start,
so the archive dialog lists it beside the turn; the e2e and its ARIA golden
expect that row, and the capture keeps the running job by design.
2026-09-21 11:46:13 +00:00
_KermanandTianyi Cui f4a32dbd0a refactor(llm): flatten tool results and validate native V4 sessions
Represent tool results as tool-role messages and migrate released wrappers
without losing outer own JSON fields, call identity, error state, or writer
field order. Refuse nested or wrapper-only information that has no lossless
current representation before successor publication.

Validate current event relationships directly instead of projecting V4 data
back into V3. Keep lifecycle, PTC, title/command, compaction, system-field and
retired-syntax checks on catalog restoration and ordinary JSONL opens. The
Worker JSON equality helper must inspect own keys so it cannot admit PTC
arguments that Node rejects.

Keep the source role change, required native admission and consumer fixture
updates in one complete review layer. Explain shared-type changes in the
persistence record and the native reader rationale in its existing note.
Use checked branded fixture identities and discriminant narrowing instead
of unknown double casts; fixture values and assertions remain intact.

This recomposes the original tool-role work by _Kerman with the independently
validated migration and admission repairs by Tianyi Cui. Frozen generations
and snapshot input version selection are retained.

Co-authored-by: Tianyi Cui <[email protected]>
2026-09-18 19:05:32 +08:00
yixiangihsiang 4937343a5e feat(web): unify the client visual language 2026-09-17 19:14:41 +08:00
ZiyaZhang 69db89f848 fix(web): shorten English question skip label 2026-09-10 05:06:14 -07:00
Tianyi Cui 1a9bef60c2 test: separate native V3 writer expectations from historical replay 2026-09-06 20:45:00 +08:00
Tianyi Cui 8de41bbe99 Merge embedded stream migration into v2 snapshot rollout
# Conflicts:
#	docs/testing.i18n.yaml
#	docs/testing.md
#	docs/testing.zh.md
#	packages/test-support/session-snapshot/README.i18n.yaml
#	packages/test-support/session-snapshot/README.md
#	packages/test-support/session-snapshot/README.zh.md
#	snapshots/session/read-image-attachment-path/session.v2.jsonl
#	snapshots/session/read-image-dimension/session.v2.jsonl
#	snapshots/session/read-image-reencode/session.v2.jsonl
#	snapshots/session/read-image/session.v2.jsonl
#	snapshots/web/navigation-panes/session.jsonl
#	snapshots/web/ptc-round/session.v2.jsonl
#	snapshots/web/pwsh-terminal/session.jsonl
#	snapshots/web/seeded-history/session.jsonl
2026-09-02 18:45:14 +08:00
Tianyi Cui f693946509 test(snapshot): roll corpus forward to format v2 2026-09-02 04:18:52 +08:00
Tianyi Cui d1521ea783 feat(session)!: add released format migration 2026-09-01 22:12:21 +08:00
lsdsjyandYif 8b09a0be52 feat(ui-conversation): fold turn process before final answer (#2547)
* feat(ui-conversation): fold turn process before final answer

* fix(ui-chat): polish turn-process control row from review

* test(web): drive preset slash catalog with gestures

* fix(ui-chat): keep turn process order stable

* fix(ui-chat): preserve prompt order after pagination

Co-authored-by: Yif <[email protected]>
2026-08-27 10:12:39 +00:00
Yichen Jiang 49753b33fa fix(web): keep question card props data-only 2026-08-27 13:21:22 +08:00
Yichen Jiang 94db8e881b fix(web): render readable ask-user transcripts 2026-08-27 11:28:59 +08:00
Yichen Jiang 605e33a2f5 fix(web): address question draft review feedback 2026-08-26 14:53:37 +08:00
Yichen Jiang 2c90710383 fix(web): preserve question drafts across Session switches 2026-08-26 11:42:52 +08:00
Yichen Jiang e177571236 Merge remote-tracking branch 'origin/master' into worktree/web-textarea-refactor-991614
# Conflicts:
#	.agents/notes/archived/manifest.json
#	apps/web/tests/reference-composer.e2e.ts
#	pnpm-lock.yaml
2026-08-25 19:35:55 +08:00
Tianyi Cui ce031ddd16 fix(web): cover authenticated host runtimes 2026-08-25 14:23:46 +08:00
Yichen Jiang 0a247137f0 Merge remote-tracking branch 'origin/master' into worktree/web-textarea-refactor-991614
# Conflicts:
#	apps/web/tests/composer-draft-scroll.e2e.ts
#	apps/web/tests/expected/reference-composer/caret-edits.expected.md
#	apps/web/tests/startup-auto-selection.e2e.ts
#	pnpm-lock.yaml
2026-08-25 10:42:32 +08:00
Tianyi Cui 6ca682733f refactor(test): drive sessions through owning profiles 2026-08-24 21:37:13 +08:00
Tianyi Cui 6189e4a374 test(web): separate session snapshots from goldens 2026-08-24 21:36:31 +08:00
Yichen Jiang 0cdb569cf8 Merge remote-tracking branch 'origin/master' into worktree/web-textarea-refactor-991614
# Conflicts:
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.zh.md
2026-08-20 19:53:44 +08:00
Yichen Jiang f6fb66a318 docs+build(ui-conversation): lexical composer collateral
The client-bundle preset pins the production/development exports condition
(lexical's node-condition file selects its flavor with a top-level await a
CJS bundle cannot carry); the composer carries an explicit aria-label (a
div's data-placeholder does not name it the way a textarea placeholder
did); READMEs, the composer.bar slot doc, and the Agent Note record the
editor architecture; web e2e drives the contenteditable surface.
2026-08-20 18:27:55 +08:00
Yichen Jiang 7260f4cf64 fix(web): cap the answer field at six text lines in both variants
The card-wide `border-box` reached `.fieldMirror`, so the growth cap counted
text plus padding. The inline variant carries none and landed on the declared
line count, while the optionless variant's 16px inset spent two thirds of a
line and delivered its last one as an 8px sliver. The e2e measured only the
inline shape, so nothing caught the drift.

The mirror now takes `box-sizing: content-box`, which states the cap in the
units it is written in, and the cap moves to six lines. The e2e asserts whole
text lines rather than a box height, and covers the optionless shape — asked
straight through the user-questions seam, since a layout metric needs no model
round — including that the reserved empty field is fully covered by its own
control.
2026-08-20 16:58:41 +08:00
Yichen Jiang 9616790b6c feat(web): answer ask_user_question over multiple lines
A question that carried options collected its free-text answer in a
single-line input: a long sentence scrolled sideways inside one line and
Shift+Enter was inert, so an answer with structure could not be typed.
The optionless question already used a textarea, but a fixed 64-140px box
that never followed the draft.

Both shapes now answer into one AnswerField: a `textarea rows=1` sharing a
grid cell with a hidden mirror that renders the draft plus a trailing
newline and so owns the height. Soft wraps are invisible to a '\n' count,
so the mirror is what grows the box; growth stops at eight lines and the
textarea scrolls from there, keeping the choices the answer belongs to in
view. Enter still continues and submits, Shift+Enter breaks the line, and
the IME guard is unchanged.
2026-08-20 15:29:13 +08:00
Tianyi Cui a2d0f7f411 refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
2026-08-13 00:54:38 +08:00
Turtle a27efdef36 docs: make technical prose concrete 2026-08-10 16:34:20 +08:00
Turtle 00d4349eb4 feat(client): surface pending session interactions 2026-08-04 17:15:10 +08:00