`observedInputs` now reads every `input`-position Node, and a Node's
payload is not guaranteed to be an object. Check the payload and its
`source` before reading the composer `rpcId`, so an input Node without a
message payload no longer throws while pending echoes are matched.
The position-order case includes `input`. A Turn without opening input
whose control anchors after a position-less row still renders the control
before the group that holds that row.
State in the `exclusive` JSDoc and the Conversation reference that the
claimed target's fallback does not run and that a fallback's own claim
has no effect. Reword the `input` position as the Turn's opening input
and separate the finalized-answer exemption from position-less
`assistant-step` rows. Point both package READMEs at the claim and the
group-tree positions.
Assembler cases cover a claim in either registration order and on live
append, other targets and target-less Definitions, the skipped fallback,
and both dispatch failures. Chat grouping cases split the step run by
position regardless of kind and regroup on a position change; the late
reply produces one Chat Node through a real assembler.
Add the exclusive Conversation matches Agent Note; bring the group-tree
note up to the `input` position and the migrated kind lists, and the
timed-question note up to claim-based reply deduplication. Pair the
Chinese Conversation reference and Chat grouping README with the
English updates.
Chat grouping, whole-Turn folding, and Turn-input detection read each
Node's declared `groupTree` position instead of the `INDEPENDENT` and
`TURN_PROCESS_INDEPENDENT_KINDS` kind lists and the user/steering/
turn-trigger checks. `ChatGroupTree` gains an `input` position between
`exchange` and `turn`; the built-in Definitions declare the positions
their kinds had, so built-in rows keep their placement.
The late question reply claims its message on the Chat target, so the
generic message Definition no longer projects a duplicate trigger and
grouping drops the message-id aggregation. Its placement is unchanged.
A match result may set `exclusive: true`. The assembler evaluates every
match of an event before accepting any, so a claim is independent of
registration order: other Definitions of the claimed target build no
Context for the event and the target's fallback does not run, while
Definitions of other targets and target-less Definitions still receive
it. Two claims on one target, or a claim without a target, throw.
The responsive change had moved `.pageIntro` off flex, which put the information
icon 1.06px off the subtitle's vertical centre and failed the existing geometry
assertion in `plugin-manager.e2e.ts`. Restore the flex row and the button's
`flex: none`, which keeps the 4px gap and the centring. The header still wraps
its action group onto another line, which is what this change is for.
Pin the wrap threshold in both header scenarios. Each records whether the action
group sits beside or below the heading, the plugin scenario asserts the wide and
narrow sides explicitly, and the plugin scenario launches its own scaffold so an
install task left by an earlier test cannot move the threshold between runs.
- Compute each group's baseline watermark once per render.
- Skip the row-motion reset when folding drops no raised watermark.
- Document that the watermark is a row count that a reorder can outrun, and
that any unmount of the grouped tree resets it; pin both in tests.
- Cover raise-to-current, keep-after-leaving, and fold reset in the keyless
Web folding scenario.
The page header keeps the title at its natural width and moves the New action
onto another line once the two no longer fit, so a narrow content column never
splits the title across lines.
Register the new browser scenario in both web programs: the host aggregate owns
files that boot the host spine, and the client-registered app project excludes
them.
The scenario asserts the title stays on one line, the action separates when the
column narrows, and focus survives the change.
The page header wraps its action group onto another line when the title and the
actions no longer fit together, so the title keeps its width and the actions keep
their labels on one line. The information button follows the subtitle text
instead of a flex row, which keeps it beside the copy at every width.
Cover the header in the plugin-manager browser scenario: the action group stays
inline when it fits, moves below when it does not, keeps its labels on one line,
stays inside the header, and retains focus across the change.
Each Workspace shows a contiguous prefix of its Sessions up to a watermark.
The watermark rises to cover running, waiting, unread-completion, and
current Sessions within the first 50 rows, and to a search reveal target at
any row. It never falls on its own; Show more raises it past 50, and Show
less or folding (including an ancestor) resets it.
Reuse read_image and automatic compaction in the standalone profile without
adding SDK slash-command handling. Update profile guidance, upgrade steps,
and startup and recorded-session coverage.
Share locationCoordinates between the Chat Builder and GroupTreeSegments,
find the last opening Turn with a loop instead of spreading every key,
and pass the resolved Location through chatNode so message Nodes resolve
it once. The notice e2e now waits for observable barriers (each Step's
row, the notice Turn's start, the notice row) instead of fixed sleeps,
asserts the settled tail through polling plus a later-frame recheck
instead of one absolute blank threshold, and fails on console warnings.
Record exchange in the terminology table and keep Goal Round in English.
Under "On next message" folding, a Turn woken by a notice (settled
subagent, goal round, schedule, background job) advanced the bottom Turn
and folded the finished Turn without an own-input driver, so the generic
fold room left a following reader looking at blank space.
Chat Nodes now declare a group-tree position (`groupTree`, ordered
`exchange` > `turn` > `process`). Human input claimed in Step 1 marks its
Turn as opening an exchange; notices and later steering carry no
position. `GroupTreeSegments` splits the loaded Turns at opening Turns,
and `bottomSource` covers the whole latest exchange, so notice-woken
Turns no longer fold earlier ones while the next human message folds the
exchange through the own-input path. Only `exchange` is read today; the
`turn` and `process` positions are reserved for the existing kind lists.
- Note B: final medians of two interleaved samples (build 317.1 -> 169.1 s,
build:src developer view -51.6%, lint prerequisite 159.8 -> 90.9 s), the
CI lanes that run the parallel build, and their concurrency settings.
- Both notes: medians with sample counts instead of raw sample lists.
- Note A: why the typertPlugin() hook changes need no upgrade guide; final
serial stage times.
- Typert Remote note: the top-level build now runs the scripts/build.ts
step graph; build:lib and build:lib:host keep their remaining callers.
- docs/development.md agreement fix; packages/client/AGENTS.md rule 8 names
the manifest globs the gate checks.
Refs #5852
The client tsdown presets found a package's own manifest by name: a glob of
every packages/*/*/package.json, parsed until the name matched. tsdown's
native config loader imports each package config without module cache, so
the module-level cache never hit and all 82 configs repeated the glob
(40-125 ms each) synchronously on tsdown's main thread, where it delayed
every other package build. It was 34.5% of the client pass's main thread.
- clientBundle, staticLinked and clientLibrary take the package directory
(import.meta.dirname at every call site) and read <dir>/package.json
once; the package name, loader id and externals come from that manifest.
- A missing, unreadable or nameless manifest throws an actionable error.
- The glob, the name search and the module-level caches are removed.
tsdown client pass 12.78 s -> 8.73 s (median of 3 interleaved runs each,
-31.7%); all 11,566 lib outputs byte-identical; all 82 configs resolve the
same externals and banners.
Refs #5852
TypeScript builds a synthetic signature for every JSX intrinsic element and
computes a module specifier for @types/react (index and jsx-runtime) per
importing file. computeModuleSpecifiers visits every symlinked location of
that file and scans all 491 tsconfig paths for each; pnpm gave 65 packages
their own node_modules/@types/react link. Client test-aggregate Check
followed 26.9 + 0.494 * N seconds for N locations.
- Remove @types/react and @types/react-dom from all 67 workspace manifests
and declare them once in the root devDependencies; packages keep declaring
the react and react-dom they import (ui-slots gains react).
- verify-package-dependencies rejects either package in any workspace
manifest and requires the root declaration, so a new package cannot add
the link back.
- packages/client/AGENTS.md states the rule.
Client aggregate Check 59.1 s -> 26.5 s; the 76 client-only package
projects 54-57 s -> ~44 s wall. File set (2,613) and diagnostics unchanged.
Refs #5852