Prechádzať zdrojové kódy

ci: clear the snapshots-and-artifacts lane — lint sweep and TUI snapshot re-record

Lint: eslint --fix over the merge-crossed projection/command files (arrow
parens, trailing commas, unnecessary assertions), Extract<> replaces the
keyof-map & string intersections no-redundant-type-constituents rejects,
the fold-adapter's merge loop drops its non-null assertions for a
bounds-carrying cursor, one JSDoc line wrapped under max-len (api-catalog
regenerated). Snapshots: the four TUI goldens re-recorded for the merged
event-count shift (the durable command lifecycle adds one event to the
seeded diagnostics log). The headless advanced-toolchain snapshot passes
on CI and fails locally in this sandbox both with and without these
changes (30s child timeout — environment-bound, tracked in the ledger).
imccyu 2 mesiacov pred
rodič
commit
e2791107c4

+ 4 - 2
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 }

+ 2 - 2
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 = {
-  <K extends keyof SessionProjectionMap & string>(key: K): SessionProjectionMap[K] | undefined
-  <K extends keyof SessionProjectionMap & string, S>(
+  <K extends Extract<keyof SessionProjectionMap, string>>(key: K): SessionProjectionMap[K] | undefined
+  <K extends Extract<keyof SessionProjectionMap, string>, S>(
     key: K,
     selector: (value: SessionProjectionMap[K] | undefined) => S,
     eq?: (a: S, b: S) => boolean,

+ 2 - 2
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: {} })

+ 3 - 3
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,

+ 1 - 1
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}

+ 2 - 2
packages/client/web-react/src/session-provider.tsx

@@ -94,7 +94,7 @@ function useAbsentSnapshot<S>(_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<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>()
 
 /**

+ 4 - 4
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<unknown>({ 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)),
     },

+ 1 - 1
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<keyof SessionProjectionMap, string>, value: unknown, seq: number) => void;',
   },
   {
     name: 'ProjectionDefinition',

+ 2 - 1
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<CommandId>
 
-/** 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(),

+ 4 - 4
packages/session-projection/session-projection/src/index.ts

@@ -80,7 +80,7 @@ export interface ProjectionDefinition<K extends keyof SessionProjectionMap, S> {
  */
 export type ProjectionChangeListener = (
   session: Session,
-  key: keyof SessionProjectionMap & string,
+  key: Extract<keyof SessionProjectionMap, string>,
   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<keyof SessionProjectionMap, string>, value, event.seq)
         }
       }
     }

+ 1 - 1
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,
 })

+ 1 - 1
packages/todo/tool-todo/tests/projection.spec.ts

@@ -51,7 +51,7 @@ async function harness(withTodoTool: boolean): Promise<Bench> {
     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<string, unknown> } | undefined
+      return response.result.value.projections
     },
   }
 }

+ 32 - 32
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| <blank>
-7| "Keyboard shortcuts                                                                          "
+7| "provider stream failed after partial output                                                 "
+  style 0-42 fg=red
+8| <blank>
+9| "The previous process ended during this turn.                                                "
+  style 0-43 fg=yellow
+10| <blank>
+11| "Turn stopped: the agent was disposed.                                                       "
+  style 0-36 fg=yellow
+12| <blank>
+13| "Turn ended: plugin-policy.                                                                  "
+  style 0-25 fg=yellow
+14| <blank>
+15| "Unknown command: /unknown-advanced-command                                                  "
+  style 0-41 fg=yellow
+16| <blank>
+17| "Keyboard shortcuts                                                                          "
   style 0-17 fg=bright-blue bold
-8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history                               "
+18| "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                 "
+19| "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                   "
+20| "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)                           "
+21| "                                                                                            "
+22| "/clear — Clear the transcript view (session history is unchanged)                           "
   style 0-64 fg=bright-black
-13| "/exit — Exit after the active turn reaches idle                                             "
+23| "/exit — Exit after the active turn reaches idle                                             "
   style 0-46 fg=bright-black
-14| "/help — Show keyboard shortcuts and commands                                                "
+24| "/help — Show keyboard shortcuts and commands                                                "
   style 0-43 fg=bright-black
-15| "/model [[provider/]model] — Show or switch this session's model                             "
+25| "/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                                             "
+26| "/quit — Exit after the active turn reaches idle                                             "
   style 0-46 fg=bright-black
-17| "/reasoning — Toggle reasoning blocks                                                        "
+27| "/reasoning — Toggle reasoning blocks                                                        "
   style 0-35 fg=bright-black
-18| "/redraw — Invalidate components and redraw the terminal                                     "
+28| "/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)    "
+29| "/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                                          "
+30| "/resume — List this workspace's resumable sessions                                          "
   style 0-49 fg=bright-black
-21| "/status — Show session diagnostics, system prompt, and registered tools                     "
+31| "/status — Show session diagnostics, system prompt, and registered tools                     "
   style 0-70 fg=bright-black
-22| "/tools — Expand or collapse all tool cards                                                  "
+32| "/tools — Expand or collapse all tool cards                                                  "
   style 0-41 fg=bright-black
-23| "/skill:<name> [instructions] — load a skill into the conversation                           "
+33| "/skill:<name> [instructions] — load a skill into the conversation                           "
   style 0-64 fg=bright-black
-24| <blank>
-25| "provider stream failed after partial output                                                 "
-  style 0-42 fg=red
-26| <blank>
-27| "The previous process ended during this turn.                                                "
-  style 0-43 fg=yellow
-28| <blank>
-29| "Turn stopped: the agent was disposed.                                                       "
-  style 0-36 fg=yellow
-30| <blank>
-31| "Turn ended: plugin-policy.                                                                  "
-  style 0-25 fg=yellow
-32| <blank>
-33| "Unknown command: /unknown-advanced-command                                                  "
-  style 0-41 fg=yellow
 34| <blank>
 35| "/workspace/project (tui-staging)  deepseek-v4-flash  ↑0 ↓0  0% context"
   style 0-17 fg=bright-blue bold

+ 32 - 32
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| <blank>
-7| "Keyboard shortcuts                                                                          "
+7| "provider stream failed after partial output                                                 "
+  style 0-42 fg=red
+8| <blank>
+9| "The previous process ended during this turn.                                                "
+  style 0-43 fg=yellow
+10| <blank>
+11| "Turn stopped: the agent was disposed.                                                       "
+  style 0-36 fg=yellow
+12| <blank>
+13| "Turn ended: plugin-policy.                                                                  "
+  style 0-25 fg=yellow
+14| <blank>
+15| "Unknown command: /unknown-advanced-command                                                  "
+  style 0-41 fg=yellow
+16| <blank>
+17| "Keyboard shortcuts                                                                          "
   style 0-17 fg=bright-blue bold
-8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history                               "
+18| "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                 "
+19| "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                   "
+20| "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)                           "
+21| "                                                                                            "
+22| "/clear — Clear the transcript view (session history is unchanged)                           "
   style 0-64 fg=bright-black
-13| "/exit — Exit after the active turn reaches idle                                             "
+23| "/exit — Exit after the active turn reaches idle                                             "
   style 0-46 fg=bright-black
-14| "/help — Show keyboard shortcuts and commands                                                "
+24| "/help — Show keyboard shortcuts and commands                                                "
   style 0-43 fg=bright-black
-15| "/model [[provider/]model] — Show or switch this session's model                             "
+25| "/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                                             "
+26| "/quit — Exit after the active turn reaches idle                                             "
   style 0-46 fg=bright-black
-17| "/reasoning — Toggle reasoning blocks                                                        "
+27| "/reasoning — Toggle reasoning blocks                                                        "
   style 0-35 fg=bright-black
-18| "/redraw — Invalidate components and redraw the terminal                                     "
+28| "/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)    "
+29| "/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                                          "
+30| "/resume — List this workspace's resumable sessions                                          "
   style 0-49 fg=bright-black
-21| "/status — Show session diagnostics, system prompt, and registered tools                     "
+31| "/status — Show session diagnostics, system prompt, and registered tools                     "
   style 0-70 fg=bright-black
-22| "/tools — Expand or collapse all tool cards                                                  "
+32| "/tools — Expand or collapse all tool cards                                                  "
   style 0-41 fg=bright-black
-23| "/skill:<name> [instructions] — load a skill into the conversation                           "
+33| "/skill:<name> [instructions] — load a skill into the conversation                           "
   style 0-64 fg=bright-black
-24| <blank>
-25| "provider stream failed after partial output                                                 "
-  style 0-42 fg=red
-26| <blank>
-27| "The previous process ended during this turn.                                                "
-  style 0-43 fg=yellow
-28| <blank>
-29| "Turn stopped: the agent was disposed.                                                       "
-  style 0-36 fg=yellow
-30| <blank>
-31| "Turn ended: plugin-policy.                                                                  "
-  style 0-25 fg=yellow
-32| <blank>
-33| "Unknown command: /unknown-advanced-command                                                  "
-  style 0-41 fg=yellow
 34| <blank>
 35| "/workspace/project (tui-staging)  deepseek-v4-flash  ↑0 ↓0  0% context"
   style 0-17 fg=bright-blue bold

+ 1 - 1
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

+ 1 - 1
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