The composer's plan-mode chip rendered its label followed by a 12px
one-pixel cross, out of step with the sibling access-mode trigger's
glyph-then-label layout. The chip now leads with the 14px plan glyph
(the /plan command's own icon) and swaps it for a new circled close —
IconCloseCircleFill, a filled disc with the cross knocked out — while
the enabled chip is hovered or keyboard-focused, so the pending click
reads as turning plan mode off.
The pill's corners move from a 999px circular capsule to the compact
Button geometry (14px on the 28px row) under the theme's superellipse
curvature, matching every neighbouring control; the lifecycle-chrome
probe now pins that radius and the shared corner-shape.
* fix(web): bind the right Sidebar before same-commit mount effects
A plan review arriving while a global panel was active crashed its opener when the user returned: the frame mounts the Conversation column ahead of the right Sidebar seat, so PlanReviewOpen's mount effect called ctx.sidebarRight.openResource before the seat's passive bindService effect had published the binding. The slot runtime retired the crashed entry for the rest of the page, removing the View full plan link and every later automatic open.
Publish the seat binding from a layout effect, which runs before any passive effect of the same commit regardless of tree order. The seat spec mounts a Conversation-column opener ahead of the seat and returns from a global panel; the plan-review Web scenario delivers a review while the Plugins panel is open and expects the preview and the link after the return. Both fail before the fix.
* fix(web): open the plan review once the Sidebar seat is mounted
Replace the layout-effect binding with an observable: ctx.sidebarRight.mounted publishes the session whose seat is on screen, undefined while a global panel replaces the Conversation. The seat keeps binding from its passive effect. PlanReviewOpen reads the source through a bound hook and opens once a seat is defined, so a review mounting ahead of the seat in the same commit no longer assumes a bound seat and never crashes its entry.
The seat spec's opener stand-in now reads `mounted` the way a slot component does; the service spec pins that only real transitions publish, and the PlanReviewOpen spec covers a review that mounts before any seat and opens once the seat binds.
* test(web): align the plan-review console tripwires and the seat term
The off-screen review case now asserts the reconnect warnings like its siblings and filters crash logs by error level as the other e2e files do. The zh README keeps 席位 for the seat throughout.
* test(plan): keep the review props cast at its baseline fingerprint
verify-no-unknown-casts counts a modified assertion as new. The two PlanReviewOpen specs now share the unchanged baseline cast through one helper and supply the seat hook as a typed value beside it.
Merge a2acc7d3eb620bb52f09f7ea3b5a3a1c23353e18 after preserving the earlier
master checkpoint and its successful CI. Carry current provider input-history
handling, UI controls, agent targeting, and runner-concurrency changes into
the integration base without changing the Session migration feature layers.
Keep durable direct-child catalog semantics alongside the upstream running /
inactive vocabulary. Resolve the snapshot description conflicts by retaining
that upstream status text and the existing descendants-only diagnostic rule;
the source and all 53 JSON tool descriptions agree. Preserve parent-session
availability handling with the upstream stale-blank and batched-history fixes.
The merged application builds, all 41 documentation gates pass, and focused
provider, tool-control, and Session Controller tests pass (98, 29, and 125).
Recorded input changes come from master: one refreshed v3 list-agents sample
and three new v3 scenarios; no migration bumps an existing snapshot generation.
* fix(web): make the plan chip a business-accent control at row height
The chip borrowed the warn-state pair for a plain mode flag, so it read as
a warning, and its 2px vertical padding left it 4px shorter than the + and
select controls beside it. It now uses the business accent pair, takes the
row's 28px height, and carries Chinese copy; the unused chip.off.*
dictionary entries had no surface and are dropped.
* docs(web): re-record the plan chip README pair
* docs(web): state the plan chip's close glyph and drop stale copy claims
The READMEs described the chip without the × the component renders, and the
zh side still quoted the English accessibility string after this branch gave
the namespace its own Chinese one.
* test(web): pin the plan chip's accent tokens, height, and Chinese copy
The lifecycle-chrome lane asserted the chip's warn pair; it now asserts the
business pair plus the 28px row height, and a zh plan-active golden records
the 「计划」 label the chip shows under the Chinese locale.
* fix(web): color claimed command tokens with the business accent
The draft's claimed token still used the warn label color while the plan chip
moved to the business pair, so a claimed /计划 read orange above a blue chip.
The claim decoration and the tests asserting its inline style now use
state-business-primary.
* fix(web): keep the composer control row on one line at narrow widths
The fixed-width mode chips and send circle left the row's 12px gaps deciding
between a slack first line and a wrapped trailing group: beside the plan chip,
a long model name moved the model trigger and send circle to a second line
while the first line still had room. Narrow rows now use 8px gaps, which holds
the row together down to the icon-only model trigger.
* fix(web): drop the context ring in the narrow composer row
With plan mode on and a long model name, the 28px occupancy ring plus its gap
was what pushed the trailing group onto a second line. The ring yields at the
same row width that already hides the access-mode label, so the fixed controls
keep one line; the reading stays reachable from a wider window.
---------
Co-authored-by: Turtle <turtle1999@deepseek.com>
Merge master 0fdadce5189dcf13a00c2ed8293be95b9bb29c2c into the reviewed
Session V4 integration base. Preserve its V4 persistence and direct-catalog
subagent navigation while carrying forward current UI controls, decorative
icons, Desktop signing/runtime changes, and upstream tests.
Resolve lineage conflicts by retaining interaction-time catalog authority,
known-leaf handling and row order together with the shared status icons.
Keep both Desktop shell-routing regressions and one production route; master
now includes the route repair previously carried by this integration branch.
The full build, 41 documentation gates, two Desktop shell tests and 34 focused
Client lineage tests pass. Further built Web and packaging checks precede
publication. Preserve this pinned merge checkpoint before taking a newer
master tip, and propagate it through the reorganized feature stack.
A child conversation rendered in a parent Sidebar keeps the child Session identity for reading its plan. Routing navigation through openResourceIn(child) confused that document identity with the layout owner: a child with no adopted Sidebar store silently opened nothing, and an existing child store was invisible.
Use the mounted Sidebar navigation service for both logged and temporary plan previews. Keep the complete child Session resource address, so reads and reload still target the correct document. A real-controller regression adopts only the visible parent store and proves both child entry points populate it without creating child layout state; it fails before the fix.
All 47 ui-plan owner tests and all four built Web plan-review cases pass, along with the full build, scoped typed lint, and bilingual pairing. No Session event, stored document, fixture generation, or resource-address format changed.
Apply global visual polish across the web client: corner-shape:
superellipse(1.5) with corner-shape: round pairing for full circles,
elevation tokens that draw 0.5px stroke outlines inside box-shadow for
floating surfaces, 0.5px hairline borders and divider lines for
neutral-token strokes, and tuned stroke contrast plus larger radii for
menus, settings panels, and cards. Stylesheet-scan specs in ui-theme
reject unpaired circles, border+shadow mixes, and 1px neutral hairlines
repo-wide.
Closes#3287
A claimed slash command consumed only the text half of the composer
submission: /goal with reference images executed, cleared the draft, and
silently stranded the images in the rail. Model-visible attachment intent
had no route through the command plane.
The submission envelope is now modeled end to end. CommandDefinition
input.images declares acceptance; the declaration rides the descriptor to
every client, onto the minted CommandClaim, and into the input machine's
claim snapshot. commands.execute carries the submission's base64 images
and enforces the declaration in the executor: non-declaring commands, a
missing attachment store, and exceeded batch limits settle as logged
error results before the handler runs. Admission reuses the attachment
package's new admitEncodedImages, extracted from api-proxy's prompt path
so both wire endpoints share one limits/validation/commit sequence.
Producers own model visibility: /goal submits one user followup (image
blocks + a fixed reference line) after a successful create/edit so goal
rounds read the images from session history; /plan folds them into its
steered message. Grammar misfits (/goal pause, bare /plan, /plan off)
return direct errors and the composer keeps the images.
On the client, enter adjudication carries a SubmitEnvelope and every
command route that cannot consume images throws a localized refusal that
renders as one composer notice with draft and images retained; the
claimed pre-gate applies the same copy. An accepting claim serializes the
draft images, forwards them to commands.execute, and clears plus releases
them only on a success outcome.
The assembled web test roster gains the ui-input-trigger and ui-commands
plugins, mirroring the shipped composition, so slash submissions exercise
the command plane; a new keyless snapshot pins the refusal banner and the
accepting /goal flow over the built client graph.
`CommandService.list` and `execute` carry the wire contract directly through
`@Remote`, and the Client assembly mounts the generated commands
contribution. The legacy API Proxy route, its schemas, the map rows, the
generated client methods and the fixture's command domain are removed, so the
catalog and the admission call have one owner again.
`Session.command()` keeps a result-shaped public face for parity with the
prompt, cancel and attachment neighbours it sits beside, and reads the
generated namespace through one `SessionRemotes` parameter. The Session
cluster declares that face against the owning business package rather than the
generated contribution: the Host compiler aggregate builds this package, and
it runs before any contribution is emitted.
Migrated calls lose the `title-invalid` class of protocol-only error codes and
report `internal`; no production caller branched on them.
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.
Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.
The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.
Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
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.
The idle /plan and /plan off command paths pin the immediate-commit copy;
the chip's dead leaving/locked guard is deleted (both states disable the
button, so no click reaches the handler); the multi-turn TUI golden is
re-recorded keyless over the idle-commit wording and the standalone
plan/mode narration ordering.
Plan mode is entered through /plan only — the select control is retired.
The conversation.input.plan seat (now right of the access-mode control)
renders a read-only Plan chip while the projection's effective target is
plan mode; its hover x executes /plan off, and the chip follows the folded
target (appears on /plan immediately, disappears on /plan off) with frames
correcting either way. While plan mode is targeted the composer textarea's
placeholder switches to the plan-task wording — InputBar reads the same
projection through the standard-kit useProjection (the TodoDock posture:
a type-only key merge, no domain service edge), and owner placeholders
still win.
Drop the assertions eslint proved unnecessary (getByRole gains the element
type parameter instead, keeping tsc satisfied), declare the injected
setPlanMode as a function property (the seat face is this-free), and narrow
the fixture's command args without String()'s object stringification arm.
Rewrite ui-plan as a pure browser surface plugin. The control occupies the
composer's named plan seat (declared empty by ui-conversation); reads render
the host-computed plan projection through the standard-kit useProjection
(absent key = capability absence, hides the control), writes execute /plan
or /plan off through command.execute. The node half becomes the empty
roster apply: plan behavior (command, policy, projection unit) is owned by
dsh-plan-mode, already composed on the web roster with its policy in
cordis.yml. The superseded RPC-backed setPlanMode face, the WEB_PLAN_SECTION
duplicate, and the node-plugin spec are removed; the roster row moves from
the retired CLIENT_PACKAGES table to the cordis.yml dshClient roster.