diff --git a/packages/client/runtime/src/client/sessions/fold-adapter.ts b/packages/client/runtime/src/client/sessions/fold-adapter.ts index 5c79bbf702..874d6b0d88 100644 --- a/packages/client/runtime/src/client/sessions/fold-adapter.ts +++ b/packages/client/runtime/src/client/sessions/fold-adapter.ts @@ -204,10 +204,12 @@ export class FoldAdapter { const commands = [...this.commandIdx.values()] let next = 0 for (const node of out) { - while (next < commands.length && commands[next]!.seq < node.seq) nodes.push(commands[next++]!) + for (let cmd = commands[next]; cmd !== undefined && cmd.seq < node.seq; cmd = commands[++next]) { + nodes.push(cmd) + } nodes.push(node) } - while (next < commands.length) nodes.push(commands[next++]!) + for (let cmd = commands[next]; cmd !== undefined; cmd = commands[++next]) nodes.push(cmd) } const value = { nodes, degraded: this.degraded } this.nodesResult = { rev: this.rev, value } diff --git a/packages/client/runtime/src/client/sessions/projection-store.ts b/packages/client/runtime/src/client/sessions/projection-store.ts index 7d26eadf66..4e6e7dd626 100644 --- a/packages/client/runtime/src/client/sessions/projection-store.ts +++ b/packages/client/runtime/src/client/sessions/projection-store.ts @@ -28,8 +28,8 @@ export type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/t * only when a frame or baseline lands). */ export type UseProjection = { - (key: K): SessionProjectionMap[K] | undefined - ( + >(key: K): SessionProjectionMap[K] | undefined + , S>( key: K, selector: (value: SessionProjectionMap[K] | undefined) => S, eq?: (a: S, b: S) => boolean, diff --git a/packages/client/runtime/tests/projection-store.spec.ts b/packages/client/runtime/tests/projection-store.spec.ts index 45aa4078f5..eea43b67f3 100644 --- a/packages/client/runtime/tests/projection-store.spec.ts +++ b/packages/client/runtime/tests/projection-store.spec.ts @@ -45,12 +45,12 @@ describe('ProjectionValueStore semantics', () => { const store = new ProjectionValueStore() store.apply('test/marks', { marks: ['frame-20'] }, 20) // Stale cut: carried key loses to the newer frame; omitted key survives. - store.seed({ asOfSeq: 10, values: { 'test/marks': { marks: ['baseline-10'] } } as never }) + store.seed({ asOfSeq: 10, values: { 'test/marks': { marks: ['baseline-10'] } } }) expect(store.get('test/marks')).toEqual({ marks: ['frame-20'] }) store.seed({ asOfSeq: 15, values: {} }) expect(store.get('test/marks')).toEqual({ marks: ['frame-20'] }) // Fresh cut: carried key reseeds… - store.seed({ asOfSeq: 30, values: { 'test/marks': { marks: ['baseline-30'] } } as never }) + store.seed({ asOfSeq: 30, values: { 'test/marks': { marks: ['baseline-30'] } } }) expect(store.get('test/marks')).toEqual({ marks: ['baseline-30'] }) // …and an omitting fresh cut clears (capability absent as of the cut). store.seed({ asOfSeq: 40, values: {} }) diff --git a/packages/client/ui-conversation/tests/skeleton.spec.tsx b/packages/client/ui-conversation/tests/skeleton.spec.tsx index 3b026b19a3..ca87680dfa 100644 --- a/packages/client/ui-conversation/tests/skeleton.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.spec.tsx @@ -93,7 +93,7 @@ function mount( useSession={useSession} useSessions={props.useSessions} useWorkspaces={props.useWorkspaces} - useProjection={(() => undefined) as never} + useProjection={(() => undefined)} useInput={useInput} inputActions={inputActions} useStore={bindSnapshotSelector(chat)} @@ -116,7 +116,7 @@ function mount( useSession={useSession} useSessions={props.useSessions} useWorkspaces={props.useWorkspaces} - useProjection={(() => undefined) as never} + useProjection={(() => undefined)} useInput={useInput} inputActions={inputActions} keyboard={wiring} @@ -135,7 +135,7 @@ function mount( useSession, useSessions: bindSnapshotSelector(sessions), useWorkspaces: bindSnapshotSelector(workspaces), - useProjection: (() => undefined) as never, + useProjection: (() => undefined), useInput, inputActions, renderSlot, diff --git a/packages/client/ui-trajectory/tests/views.spec.tsx b/packages/client/ui-trajectory/tests/views.spec.tsx index 27da3d6d24..917beaccc6 100644 --- a/packages/client/ui-trajectory/tests/views.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.spec.tsx @@ -136,7 +136,7 @@ function mount(slots: SlotsService, nodes: ConversationSnapshot['nodes'] = NODES useSession={useSession} useSessions={emptySessions()} useWorkspaces={emptyWorkspaces()} - useProjection={(() => undefined) as never} + useProjection={(() => undefined)} useStore={bindSnapshotSelector(chat)} actions={chat.actions} renderSlot={renderSlot} diff --git a/packages/client/web-react/src/session-provider.tsx b/packages/client/web-react/src/session-provider.tsx index 5eadbcff74..784f2b67b8 100644 --- a/packages/client/web-react/src/session-provider.tsx +++ b/packages/client/web-react/src/session-provider.tsx @@ -94,7 +94,7 @@ function useAbsentSnapshot(_selector: (snapshot: never) => S, _equal?: (a: S, * capability absence — keeping the hook order constant. */ export function projectionHook(info: SessionMaybeProvideInfo): ( - key: string, selector?: (value: unknown) => unknown, eq?: (a: unknown, b: unknown) => boolean + key: string, selector?: (value: unknown) => unknown, eq?: (a: unknown, b: unknown) => boolean, ) => unknown { let hook = projectionHookCache.get(info) if (hook === undefined) { @@ -113,7 +113,7 @@ export function projectionHook(info: SessionMaybeProvideInfo): ( return hook } const projectionHookCache = new WeakMap unknown, eq?: (a: unknown, b: unknown) => boolean + key: string, selector?: (value: unknown) => unknown, eq?: (a: unknown, b: unknown) => boolean, ) => unknown>() /** diff --git a/packages/client/web-react/tests/use-projection.spec.tsx b/packages/client/web-react/tests/use-projection.spec.tsx index 4194198046..54d39e92a3 100644 --- a/packages/client/web-react/tests/use-projection.spec.tsx +++ b/packages/client/web-react/tests/use-projection.spec.tsx @@ -46,15 +46,15 @@ function makeHost() { const host: SlotRendererHost = { subscribe: () => () => {}, getVersion: () => 0, - entriesOf: (key) => key === 'root' ? [rootEntry] : sessionEntries, - specOf: (key) => key === 'k.session' ? { kind: 'single', scope: 'session' } : undefined, + entriesOf: key => key === 'root' ? [rootEntry] : sessionEntries, + specOf: key => key === 'k.session' ? { kind: 'single', scope: 'session' } : undefined, isLive: () => true, storeOf: () => undefined, sessions: { list: observable({ ids: [] }), current, - provideInfo: (id) => info(id), - maybeProvideInfo: (id) => (id === undefined + provideInfo: id => info(id), + maybeProvideInfo: id => (id === undefined ? { sessionId: undefined, hooks: { session: undefined }, props: {} } : info(id)), }, diff --git a/packages/cordis/tool-cordis/src/api-catalog.ts b/packages/cordis/tool-cordis/src/api-catalog.ts index b7bf1a0c41..6846c4d3ad 100644 --- a/packages/cordis/tool-cordis/src/api-catalog.ts +++ b/packages/cordis/tool-cordis/src/api-catalog.ts @@ -1857,7 +1857,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ProjectionChangeListener', - declaration: 'export type ProjectionChangeListener = (session: Session, key: keyof SessionProjectionMap & string, value: unknown, seq: number) => void;', + declaration: 'export type ProjectionChangeListener = (session: Session, key: Extract, value: unknown, seq: number) => void;', }, { name: 'ProjectionDefinition', diff --git a/packages/host/apiproxy/src/api/commands.schema.ts b/packages/host/apiproxy/src/api/commands.schema.ts index 81d9df2a9f..89bfa76aa2 100644 --- a/packages/host/apiproxy/src/api/commands.schema.ts +++ b/packages/host/apiproxy/src/api/commands.schema.ts @@ -36,7 +36,8 @@ export const commandExecuteRequestSchema = z.object({ /** CommandId: one brand cast after shape validation (the only cast point in this domain). */ export const commandIdSchema = z.string().min(1) as unknown as z.ZodType -/** command.execute response value: pure admission — outcomes ride the logged lifecycle events; commandId (present exactly when matched) correlates with them. */ +/** command.execute response value: pure admission — outcomes ride the logged + * lifecycle events; commandId (present exactly when matched) correlates with them. */ export const commandExecuteValueSchema = z.object({ matched: z.boolean(), commandId: commandIdSchema.optional(), diff --git a/packages/session-projection/session-projection/src/index.ts b/packages/session-projection/session-projection/src/index.ts index 8b88c974e8..e43a03d38b 100644 --- a/packages/session-projection/session-projection/src/index.ts +++ b/packages/session-projection/session-projection/src/index.ts @@ -80,7 +80,7 @@ export interface ProjectionDefinition { */ export type ProjectionChangeListener = ( session: Session, - key: keyof SessionProjectionMap & string, + key: Extract, value: unknown, seq: number, ) => void @@ -165,7 +165,7 @@ export class SessionProjectionRegistry extends Service { if (this.registrations.has(key)) { throw new Error(`session projection key ${JSON.stringify(key)} is already registered`) } - this.registrations.set(key, { def: definition as unknown as ErasedDefinition, cells: new WeakMap() }) + this.registrations.set(key, { def: definition, cells: new WeakMap() }) yield () => { this.registrations.delete(key) } @@ -203,7 +203,7 @@ export class SessionProjectionRegistry extends Service { const cell = this.cellFor(registration, session) values[registration.def.key] = registration.def.schema.parse(registration.def.view(cell.state)) } - return { asOfSeq: session.seq - 1, values: values as ProjectionSnapshot['values'] } + return { asOfSeq: session.seq - 1, values: values } } /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */ @@ -240,7 +240,7 @@ export class SessionProjectionRegistry extends Service { if (changed && this.listeners.size > 0) { const value = registration.def.schema.parse(registration.def.view(next)) for (const listener of this.listeners) { - listener(session, registration.def.key as keyof SessionProjectionMap & string, value, event.seq) + listener(session, registration.def.key as Extract, value, event.seq) } } } diff --git a/packages/session-projection/session-projection/tests/registry.spec.ts b/packages/session-projection/session-projection/tests/registry.spec.ts index bebe17f477..e5b1205478 100644 --- a/packages/session-projection/session-projection/tests/registry.spec.ts +++ b/packages/session-projection/session-projection/tests/registry.spec.ts @@ -38,7 +38,7 @@ const marksUnit = (): ProjectionDefinition<'test/marks', MarksState> => ({ key: 'test/marks', schema: z.object({ marks: z.array(z.string()) }), init: () => null, - apply: (state, event) => (event.type === 'test/mark' ? (event as SessionEvent<'test/mark'>).data : state), + apply: (state, event) => (event.type === 'test/mark' ? (event).data : state), view: state => state ?? { marks: [] }, stateVersion: 1, }) diff --git a/packages/todo/tool-todo/tests/projection.spec.ts b/packages/todo/tool-todo/tests/projection.spec.ts index 860613f462..7f5d61eb2a 100644 --- a/packages/todo/tool-todo/tests/projection.spec.ts +++ b/packages/todo/tool-todo/tests/projection.spec.ts @@ -51,7 +51,7 @@ async function harness(withTodoTool: boolean): Promise { async tailProjections() { const response = await api.sessions.history(request({ sessionId: session.id })) if (!response.result.ok) throw new Error('history failed') - return response.result.value.projections as { asOfSeq: number; values: Record } | undefined + return response.result.value.projections }, } } diff --git a/packages/ui/tui/tests/snapshots/disposed-terminal.expected.txt b/packages/ui/tui/tests/snapshots/disposed-terminal.expected.txt index 9be96fe5e1..6f7c70a9c3 100644 --- a/packages/ui/tui/tests/snapshots/disposed-terminal.expected.txt +++ b/packages/ui/tui/tests/snapshots/disposed-terminal.expected.txt @@ -16,54 +16,54 @@ buffer 5| "Model wait 0.0s · Completed 2026-07-21 15:05:00 " style 0-46 dim 6| -7| "Keyboard shortcuts " - style 0-17 fg=bright-blue bold -8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history " - style 0-60 fg=bright-black -9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning " - style 0-74 fg=bright-black -10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit " - style 0-72 fg=bright-black -11| " " -12| "/clear — Clear the transcript view (session history is unchanged) " - style 0-64 fg=bright-black -13| "/exit — Exit after the active turn reaches idle " - style 0-46 fg=bright-black -14| "/help — Show keyboard shortcuts and commands " - style 0-43 fg=bright-black -15| "/model [[provider/]model] — Show or switch this session's model " - style 0-62 fg=bright-black -16| "/quit — Exit after the active turn reaches idle " - style 0-46 fg=bright-black -17| "/reasoning — Toggle reasoning blocks " - style 0-35 fg=bright-black -18| "/redraw — Invalidate components and redraw the terminal " - style 0-54 fg=bright-black -19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) " - style 0-87 fg=bright-black -20| "/resume — List this workspace's resumable sessions " - style 0-49 fg=bright-black -21| "/status — Show session diagnostics, system prompt, and registered tools " - style 0-70 fg=bright-black -22| "/tools — Expand or collapse all tool cards " - style 0-41 fg=bright-black -23| "/skill: [instructions] — load a skill into the conversation " - style 0-64 fg=bright-black -24| -25| "provider stream failed after partial output " +7| "provider stream failed after partial output " style 0-42 fg=red -26| -27| "The previous process ended during this turn. " +8| +9| "The previous process ended during this turn. " style 0-43 fg=yellow -28| -29| "Turn stopped: the agent was disposed. " +10| +11| "Turn stopped: the agent was disposed. " style 0-36 fg=yellow -30| -31| "Turn ended: plugin-policy. " +12| +13| "Turn ended: plugin-policy. " style 0-25 fg=yellow -32| -33| "Unknown command: /unknown-advanced-command " +14| +15| "Unknown command: /unknown-advanced-command " style 0-41 fg=yellow +16| +17| "Keyboard shortcuts " + style 0-17 fg=bright-blue bold +18| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history " + style 0-60 fg=bright-black +19| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning " + style 0-74 fg=bright-black +20| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit " + style 0-72 fg=bright-black +21| " " +22| "/clear — Clear the transcript view (session history is unchanged) " + style 0-64 fg=bright-black +23| "/exit — Exit after the active turn reaches idle " + style 0-46 fg=bright-black +24| "/help — Show keyboard shortcuts and commands " + style 0-43 fg=bright-black +25| "/model [[provider/]model] — Show or switch this session's model " + style 0-62 fg=bright-black +26| "/quit — Exit after the active turn reaches idle " + style 0-46 fg=bright-black +27| "/reasoning — Toggle reasoning blocks " + style 0-35 fg=bright-black +28| "/redraw — Invalidate components and redraw the terminal " + style 0-54 fg=bright-black +29| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) " + style 0-87 fg=bright-black +30| "/resume — List this workspace's resumable sessions " + style 0-49 fg=bright-black +31| "/status — Show session diagnostics, system prompt, and registered tools " + style 0-70 fg=bright-black +32| "/tools — Expand or collapse all tool cards " + style 0-41 fg=bright-black +33| "/skill: [instructions] — load a skill into the conversation " + style 0-64 fg=bright-black 34| 35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context" style 0-17 fg=bright-blue bold diff --git a/packages/ui/tui/tests/snapshots/errors-and-help.expected.txt b/packages/ui/tui/tests/snapshots/errors-and-help.expected.txt index f93a4b47da..e726056108 100644 --- a/packages/ui/tui/tests/snapshots/errors-and-help.expected.txt +++ b/packages/ui/tui/tests/snapshots/errors-and-help.expected.txt @@ -16,54 +16,54 @@ buffer 5| "Model wait 0.0s · Completed 2026-07-21 15:05:00 " style 0-46 dim 6| -7| "Keyboard shortcuts " - style 0-17 fg=bright-blue bold -8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history " - style 0-60 fg=bright-black -9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning " - style 0-74 fg=bright-black -10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit " - style 0-72 fg=bright-black -11| " " -12| "/clear — Clear the transcript view (session history is unchanged) " - style 0-64 fg=bright-black -13| "/exit — Exit after the active turn reaches idle " - style 0-46 fg=bright-black -14| "/help — Show keyboard shortcuts and commands " - style 0-43 fg=bright-black -15| "/model [[provider/]model] — Show or switch this session's model " - style 0-62 fg=bright-black -16| "/quit — Exit after the active turn reaches idle " - style 0-46 fg=bright-black -17| "/reasoning — Toggle reasoning blocks " - style 0-35 fg=bright-black -18| "/redraw — Invalidate components and redraw the terminal " - style 0-54 fg=bright-black -19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) " - style 0-87 fg=bright-black -20| "/resume — List this workspace's resumable sessions " - style 0-49 fg=bright-black -21| "/status — Show session diagnostics, system prompt, and registered tools " - style 0-70 fg=bright-black -22| "/tools — Expand or collapse all tool cards " - style 0-41 fg=bright-black -23| "/skill: [instructions] — load a skill into the conversation " - style 0-64 fg=bright-black -24| -25| "provider stream failed after partial output " +7| "provider stream failed after partial output " style 0-42 fg=red -26| -27| "The previous process ended during this turn. " +8| +9| "The previous process ended during this turn. " style 0-43 fg=yellow -28| -29| "Turn stopped: the agent was disposed. " +10| +11| "Turn stopped: the agent was disposed. " style 0-36 fg=yellow -30| -31| "Turn ended: plugin-policy. " +12| +13| "Turn ended: plugin-policy. " style 0-25 fg=yellow -32| -33| "Unknown command: /unknown-advanced-command " +14| +15| "Unknown command: /unknown-advanced-command " style 0-41 fg=yellow +16| +17| "Keyboard shortcuts " + style 0-17 fg=bright-blue bold +18| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history " + style 0-60 fg=bright-black +19| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning " + style 0-74 fg=bright-black +20| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit " + style 0-72 fg=bright-black +21| " " +22| "/clear — Clear the transcript view (session history is unchanged) " + style 0-64 fg=bright-black +23| "/exit — Exit after the active turn reaches idle " + style 0-46 fg=bright-black +24| "/help — Show keyboard shortcuts and commands " + style 0-43 fg=bright-black +25| "/model [[provider/]model] — Show or switch this session's model " + style 0-62 fg=bright-black +26| "/quit — Exit after the active turn reaches idle " + style 0-46 fg=bright-black +27| "/reasoning — Toggle reasoning blocks " + style 0-35 fg=bright-black +28| "/redraw — Invalidate components and redraw the terminal " + style 0-54 fg=bright-black +29| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) " + style 0-87 fg=bright-black +30| "/resume — List this workspace's resumable sessions " + style 0-49 fg=bright-black +31| "/status — Show session diagnostics, system prompt, and registered tools " + style 0-70 fg=bright-black +32| "/tools — Expand or collapse all tool cards " + style 0-41 fg=bright-black +33| "/skill: [instructions] — load a skill into the conversation " + style 0-64 fg=bright-black 34| 35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context" style 0-17 fg=bright-blue bold diff --git a/packages/ui/tui/tests/snapshots/status-diagnostics-narrow.expected.txt b/packages/ui/tui/tests/snapshots/status-diagnostics-narrow.expected.txt index a22787ea49..5bb673882a 100644 --- a/packages/ui/tui/tests/snapshots/status-diagnostics-narrow.expected.txt +++ b/packages/ui/tui/tests/snapshots/status-diagnostics-narrow.expected.txt @@ -48,7 +48,7 @@ buffer 17| "│ │" style 0-0 dim style 55-55 dim -18| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 │" +18| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 │" style 0-0 dim style 3-12 fg=bright-black style 55-55 dim diff --git a/packages/ui/tui/tests/snapshots/status-diagnostics.expected.txt b/packages/ui/tui/tests/snapshots/status-diagnostics.expected.txt index d8fb37bac4..cff733907e 100644 --- a/packages/ui/tui/tests/snapshots/status-diagnostics.expected.txt +++ b/packages/ui/tui/tests/snapshots/status-diagnostics.expected.txt @@ -45,7 +45,7 @@ buffer 16| "│ │" style 0-0 dim style 81-81 dim -17| "│ Agent: idle · 6 events · 1 turn · 1 step · 1 tool call │" +17| "│ Agent: idle · 7 events · 1 turn · 1 step · 1 tool call │" style 0-0 dim style 3-12 fg=bright-black style 81-81 dim