refactor: structured command/run payload {commandId, name, args, source}

The line field is deleted (pre-release, no shim): name and args are
parseCommand's own split — name plus verbatim rawInput with its separator
whitespace — so a consumer (a projection unit folding its own command
records, a rich command card) never re-parses a line. CommandNode mirrors
the split (name/args, both null on a run-less cross-window node); the
generic card rebuilds its display line as /name + args. The connection
fixture logs the same structured payload.
This commit is contained in:
imccyu
2026-07-27 20:57:23 +08:00
parent f72f06e84a
commit 2ebaa30c6d
16 changed files with 49 additions and 40 deletions

View File

@@ -126,7 +126,7 @@ export interface UnknownSurfaceNode {
* Log-only events never enter the surface fold, so the FoldAdapter indexes
* them separately and merges the nodes into the flow by seq. A window cut
* between the pair soft-falls like tool pairs: a done with no in-window run
* still builds a node (name/line null), and a run with no done renders as
* still builds a node (name/args null), and a run with no done renders as
* still executing.
*/
export interface CommandNode {
@@ -137,10 +137,10 @@ export interface CommandNode {
time: number
/** Pairing id minted by the host executor. */
commandId: string
/** Command name (run payload); null when the run fell outside the window. */
/** Command name (run payload's structured field); null when the run fell outside the window. */
name: string | null
/** Exact dispatched command line (run payload); null when the run fell outside the window. */
line: string | null
/** Verbatim rawInput after the name, separator whitespace included (run payload); null when the run fell outside the window. */
args: string | null
/** Settlement outcome (done payload); null while the command is still executing. */
outcome: { kind: 'success' | 'error'; text?: string } | null
}

View File

@@ -229,10 +229,10 @@ export class FoldAdapter {
// enter the client program, so this wire consumer narrows structurally
// (the same posture as tool/code-dispatch in session.ts).
if ((event.type as string) === 'command/run') {
const data = event.data as unknown as { commandId: string; name: string; line: string }
const data = event.data as unknown as { commandId: string; name: string; args: string }
this.commandIdx.set(data.commandId, {
kind: 'command', seq: event.seq, time: event.time,
commandId: data.commandId, name: data.name, line: data.line, outcome: null,
commandId: data.commandId, name: data.name, args: data.args, outcome: null,
})
return
}
@@ -245,7 +245,7 @@ export class FoldAdapter {
// node from the done alone (same soft-fall as a call-less tool result).
this.commandIdx.set(data.commandId, {
kind: 'command', seq: event.seq, time: event.time,
commandId: data.commandId, name: null, line: null, outcome,
commandId: data.commandId, name: null, args: null, outcome,
})
return
}