@wrongstack/webui-server 0.296.3 → 0.297.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.js +948 -429
  2. package/dist/index.js.map +4 -4
  3. package/dist/protocol/client-conversation.d.ts +1 -1
  4. package/dist/protocol/client-conversation.d.ts.map +1 -1
  5. package/dist/protocol/index.js +7 -1
  6. package/dist/protocol/index.js.map +2 -2
  7. package/dist/protocol/projections.d.ts +5 -1
  8. package/dist/protocol/projections.d.ts.map +1 -1
  9. package/dist/protocol/registry.d.ts +2 -2
  10. package/dist/protocol/registry.d.ts.map +1 -1
  11. package/dist/protocol/server-conversation.d.ts +1 -1
  12. package/dist/protocol/server-conversation.d.ts.map +1 -1
  13. package/dist/server/backend-services.d.ts +6 -2
  14. package/dist/server/backend-services.d.ts.map +1 -1
  15. package/dist/server/collaboration-ws-handler.d.ts +2 -2
  16. package/dist/server/collaboration-ws-handler.d.ts.map +1 -1
  17. package/dist/server/connections-health-route.d.ts.map +1 -1
  18. package/dist/server/embedded-lifecycle.d.ts +2 -0
  19. package/dist/server/embedded-lifecycle.d.ts.map +1 -1
  20. package/dist/server/entry.js +870 -395
  21. package/dist/server/entry.js.map +4 -4
  22. package/dist/server/goal-ws-handler.d.ts +3 -1
  23. package/dist/server/goal-ws-handler.d.ts.map +1 -1
  24. package/dist/server/handlers.js.map +2 -2
  25. package/dist/server/http-server.d.ts.map +1 -1
  26. package/dist/server/kanban-supervisor.d.ts +6 -0
  27. package/dist/server/kanban-supervisor.d.ts.map +1 -1
  28. package/dist/server/mailbox-handlers.d.ts +2 -1
  29. package/dist/server/mailbox-handlers.d.ts.map +1 -1
  30. package/dist/server/mailbox-routes.d.ts +1 -0
  31. package/dist/server/mailbox-routes.d.ts.map +1 -1
  32. package/dist/server/memory-diagnostics.d.ts +69 -0
  33. package/dist/server/memory-diagnostics.d.ts.map +1 -0
  34. package/dist/server/sdd-board-ws-handler.d.ts +14 -8
  35. package/dist/server/sdd-board-ws-handler.d.ts.map +1 -1
  36. package/dist/server/sdd-wizard-wiring.d.ts +5 -6
  37. package/dist/server/sdd-wizard-wiring.d.ts.map +1 -1
  38. package/dist/server/sdd-wizard-ws-handler.d.ts +16 -6
  39. package/dist/server/sdd-wizard-ws-handler.d.ts.map +1 -1
  40. package/dist/server/start-webui.d.ts.map +1 -1
  41. package/dist/server/types.d.ts +2 -0
  42. package/dist/server/types.d.ts.map +1 -1
  43. package/dist/server/worktree-ws-handler.d.ts +30 -2
  44. package/dist/server/worktree-ws-handler.d.ts.map +1 -1
  45. package/dist/server/ws-payload-validation.d.ts +8 -0
  46. package/dist/server/ws-payload-validation.d.ts.map +1 -1
  47. package/package.json +10 -10
@@ -1,7 +1,7 @@
1
- import type { WebSocket } from 'ws';
2
1
  import type { Agent, Context } from '@wrongstack/core/agent';
3
2
  import type { EventBus } from '@wrongstack/core/kernel';
4
3
  import type { Logger } from '@wrongstack/core/types';
4
+ import type { WebSocket } from 'ws';
5
5
  interface GoalWSMessage {
6
6
  type: string;
7
7
  payload?: Record<string, unknown>;
@@ -66,6 +66,8 @@ export declare class GoalWebSocketHandler {
66
66
  */
67
67
  onBoardState?: ((graphId: string, state: Record<string, unknown>) => void) | undefined);
68
68
  addClient(ws: WebSocket): void;
69
+ /** Release timers, in-flight work, and socket references owned by this host. */
70
+ dispose(): void;
69
71
  handleMessage(ws: WebSocket, msg: GoalWSMessage): Promise<void>;
70
72
  /**
71
73
  * Assess a goal prompt for duration realism. Runs a lightweight LLM call
@@ -1 +1 @@
1
- {"version":3,"file":"goal-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/goal-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAiBpC,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA2CrD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IA2B7B,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,MAAM,CAAC;IACf,OAAO,CAAC,WAAW,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAC;IAvCvB,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,iBAAiB,CAA+C;IACxE,kFAAkF;IAClF,OAAO,CAAC,KAAK,CAAgC;IAC7C;;yBAEqB;IACrB,OAAO,CAAC,WAAW,CAAgC;IACnD,mEAAmE;IACnE,OAAO,CAAC,SAAS,CAAK;IACtB;;uFAEmF;IACnF,OAAO,CAAC,QAAQ,CAAS;IACzB,2EAA2E;IAC3E,OAAO,CAAC,SAAS,CAAgC;IACjD;oFACgF;IAChF,OAAO,CAAC,OAAO,CAAgD;IAC/D,wEAAwE;IACxE,OAAO,CAAC,aAAa,CAAqB;IAE1C,YACU,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EACR,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,EAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS;IACxC;;;;;;OAMG;IACK,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAG/F;IAED,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAS7B;IAEK,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4GpE;IAED;;;;;;OAMG;YACW,YAAY;YAmEZ,WAAW;IAsLzB;;;;;OAKG;YACW,UAAU;IAWxB;;;;OAIG;YACW,WAAW;IAYzB;;;;;OAKG;YACW,YAAY;IAsB1B,4EAA4E;IAC5E,OAAO,CAAC,aAAa;IAUrB;;;4BAGwB;YACV,UAAU;YA2BV,oBAAoB;IA+BlC;;;OAGG;YACW,gBAAgB;IA0C9B,+DAA+D;IAC/D,OAAO,CAAC,kBAAkB;YAKZ,sBAAsB;IAcpC,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,UAAU;IAwGlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
1
+ {"version":3,"file":"goal-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/goal-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAc7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAGrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAwCpC,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IA2B7B,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,MAAM,CAAC;IACf,OAAO,CAAC,WAAW,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAC;IAvCvB,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,iBAAiB,CAA+C;IACxE,kFAAkF;IAClF,OAAO,CAAC,KAAK,CAAgC;IAC7C;;yBAEqB;IACrB,OAAO,CAAC,WAAW,CAAgC;IACnD,mEAAmE;IACnE,OAAO,CAAC,SAAS,CAAK;IACtB;;uFAEmF;IACnF,OAAO,CAAC,QAAQ,CAAS;IACzB,2EAA2E;IAC3E,OAAO,CAAC,SAAS,CAAgC;IACjD;oFACgF;IAChF,OAAO,CAAC,OAAO,CAAgD;IAC/D,wEAAwE;IACxE,OAAO,CAAC,aAAa,CAAqB;IAE1C,YACU,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EACR,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,EAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS;IACxC;;;;;;OAMG;IACK,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAG/F;IAED,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAS7B;IAED,gFAAgF;IAChF,OAAO,IAAI,IAAI,CASd;IAEK,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmHpE;IAED;;;;;;OAMG;YACW,YAAY;YAsEZ,WAAW;IAmMzB;;;;;OAKG;YACW,UAAU;IAWxB;;;;OAIG;YACW,WAAW;IAYzB;;;;;OAKG;YACW,YAAY;IAsB1B,4EAA4E;IAC5E,OAAO,CAAC,aAAa;IAwCrB;;;4BAGwB;YACV,UAAU;YA2BV,oBAAoB;IA+BlC;;;OAGG;YACW,gBAAgB;IA4C9B,+DAA+D;IAC/D,OAAO,CAAC,kBAAkB;YAKZ,sBAAsB;IAcpC,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,UAAU;IAwHlB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/server/handlers/worklist-handlers.ts", "../../src/server/ws-payload-validation.ts"],
4
- "sourcesContent": ["import {\n addPlanItem,\n emptyPlan,\n getPlanTemplate,\n loadPlan,\n loadTasks,\n mutatePlan,\n mutateTasks,\n savePlan,\n setPlanItemStatus,\n} from '@wrongstack/core/storage';\nimport type { TodoItem } from '@wrongstack/core/agent';\nimport type { WebSocket } from 'ws';\nimport type { WSServerMessage } from '../types.js';\nimport { validatePlanTemplateUsePayload } from '../ws-payload-validation.js';\n\nexport interface WorklistContext {\n context: {\n todos: TodoItem[];\n meta: Record<string, unknown>;\n session: { id: string } | null;\n };\n send: (ws: WebSocket, msg: WSServerMessage) => void;\n broadcast: (msg: WSServerMessage) => void;\n replaceTodos?: ((todos: TodoItem[]) => void) | undefined;\n}\n\nexport interface WorklistMessage {\n type: string;\n payload?: unknown;\n}\n\nfunction sendResult(ctx: WorklistContext, ws: WebSocket, success: boolean, message: string): void {\n ctx.send(ws, { type: 'key.operation_result', payload: { success, message } });\n}\n\nfunction currentSessionId(ctx: WorklistContext): string {\n return ctx.context.session?.id ?? '';\n}\n\nfunction sessionPayload<T extends Record<string, unknown>>(\n ctx: WorklistContext,\n payload: T,\n): T & { sessionId: string } {\n const provided = payload['sessionId'];\n const sessionId =\n typeof provided === 'string' && provided.length > 0 ? provided : currentSessionId(ctx);\n return { ...payload, sessionId };\n}\n\nfunction planPathOf(ctx: WorklistContext): string | undefined {\n const value = ctx.context.meta['plan.path'];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction taskPathOf(ctx: WorklistContext): string | undefined {\n const value = ctx.context.meta['task.path'];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nexport function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void {\n ctx.send(ws, {\n type: 'todos.updated',\n payload: sessionPayload(ctx, { todos: [...ctx.context.todos] }),\n });\n}\n\nexport function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void {\n ctx.replaceTodos?.([]);\n sendResult(ctx, ws, true, 'Todos cleared');\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: [] }) });\n}\n\nexport function handleTodosRemove(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id?: string | undefined; index?: number | undefined } | undefined,\n): void {\n if (!payload) {\n sendResult(ctx, ws, false, 'Missing id or index');\n return;\n }\n const todos = ctx.context.todos;\n let targetIndex = -1;\n if (typeof payload.id === 'string') {\n targetIndex = todos.findIndex((todo) => todo.id === payload.id);\n } else if (typeof payload.index === 'number' && payload.index > 0) {\n targetIndex = payload.index - 1;\n }\n const removed = todos[targetIndex];\n if (targetIndex < 0 || !removed) {\n sendResult(ctx, ws, false, 'Todo not found');\n return;\n }\n const next = [...todos.slice(0, targetIndex), ...todos.slice(targetIndex + 1)];\n ctx.replaceTodos?.(next);\n sendResult(ctx, ws, true, `Removed: ${removed.content}`);\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: next }) });\n}\n\nexport function handleTodoUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id: string; status?: TodoItem['status'] | undefined; activeForm?: string | undefined },\n): void {\n const index = ctx.context.todos.findIndex((todo) => todo.id === payload.id);\n const existing = ctx.context.todos[index];\n if (index === -1 || !existing) {\n sendResult(ctx, ws, false, 'Todo not found');\n return;\n }\n const next = [...ctx.context.todos];\n next[index] = {\n ...existing,\n status: payload.status ?? existing.status,\n activeForm: payload.activeForm !== undefined ? payload.activeForm : existing.activeForm,\n };\n ctx.replaceTodos?.(next);\n sendResult(ctx, ws, true, `Todo \"${existing.content}\" updated`);\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: next }) });\n}\n\nexport async function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const taskPath = taskPathOf(ctx);\n if (!taskPath) {\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: [], error: 'Task storage not configured.' }),\n });\n return;\n }\n try {\n const file = await loadTasks(taskPath);\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: file?.tasks ?? [] }),\n });\n } catch {\n ctx.send(ws, { type: 'tasks.updated', payload: sessionPayload(ctx, { tasks: [] }) });\n }\n}\n\nexport async function handleTaskUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n): Promise<void> {\n const taskPath = taskPathOf(ctx);\n if (!taskPath) {\n sendResult(ctx, ws, false, 'Task storage not configured.');\n return;\n }\n try {\n const file = await mutateTasks(taskPath, currentSessionId(ctx), async (tasks) => {\n const task = tasks.tasks.find((candidate) => candidate.id === payload.id);\n if (!task) return tasks;\n task.status = payload.status;\n task.updatedAt = new Date().toISOString();\n return tasks;\n });\n sendResult(ctx, ws, true, `Task status updated to \"${payload.status}\".`);\n ctx.broadcast({\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: file.tasks }),\n });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const planPath = planPathOf(ctx);\n const emptySnapshot = () => ({\n version: 1,\n sessionId: currentSessionId(ctx),\n updatedAt: new Date().toISOString(),\n items: [],\n });\n if (!planPath) {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, {\n plan: null,\n error: 'Plan storage is not configured for this session.',\n }),\n });\n return;\n }\n try {\n const plan = await loadPlan(planPath);\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, { plan: plan ?? emptySnapshot() }),\n });\n } catch {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, { plan: emptySnapshot() }),\n });\n }\n}\n\nexport async function handlePlanTemplateUse(\n ctx: WorklistContext,\n ws: WebSocket,\n template: string,\n): Promise<void> {\n const planPath = planPathOf(ctx);\n if (!planPath) {\n sendResult(ctx, ws, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const templateDefinition = getPlanTemplate(template);\n if (!templateDefinition) {\n sendResult(ctx, ws, false, `Unknown template \"${template}\".`);\n return;\n }\n let plan = (await loadPlan(planPath)) ?? emptyPlan(currentSessionId(ctx));\n for (const item of templateDefinition.items) {\n ({ plan } = addPlanItem(plan, item.title, item.details));\n }\n await savePlan(planPath, plan);\n sendResult(\n ctx,\n ws,\n true,\n `Applied template \"${templateDefinition.name}\" \u2014 ${templateDefinition.items.length} items added.`,\n );\n ctx.broadcast({ type: 'plan.updated', payload: sessionPayload(ctx, { plan }) });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handlePlanItemUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { target: string; status: 'open' | 'in_progress' | 'done' },\n): Promise<void> {\n const planPath = planPathOf(ctx);\n if (!planPath) {\n sendResult(ctx, ws, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n let changed = false;\n const plan = await mutatePlan(planPath, currentSessionId(ctx), async (currentPlan) => {\n const before = currentPlan.updatedAt;\n const next = setPlanItemStatus(currentPlan, payload.target, payload.status);\n changed = next.updatedAt !== before;\n return next;\n });\n if (!changed) {\n sendResult(ctx, ws, false, `No plan item matched \"${payload.target}\".`);\n return;\n }\n sendResult(ctx, ws, true, `Plan item status updated to \"${payload.status}\".`);\n ctx.broadcast({ type: 'plan.updated', payload: sessionPayload(ctx, { plan }) });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handleWorklistMessage(\n ctx: WorklistContext,\n ws: WebSocket,\n message: WorklistMessage,\n): Promise<void> {\n switch (message.type) {\n case 'todos.get':\n handleTodosGet(ctx, ws);\n return;\n case 'todos.clear':\n handleTodosClear(ctx, ws);\n return;\n case 'todos.remove':\n handleTodosRemove(ctx, ws, message.payload as { id?: string; index?: number } | undefined);\n return;\n case 'todo.update':\n handleTodoUpdate(\n ctx,\n ws,\n message.payload as {\n id: string;\n status?: TodoItem['status'];\n activeForm?: string;\n },\n );\n return;\n case 'tasks.get':\n await handleTasksGet(ctx, ws);\n return;\n case 'task.update':\n await handleTaskUpdate(\n ctx,\n ws,\n message.payload as {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n );\n return;\n case 'plan.get':\n await handlePlanGet(ctx, ws);\n return;\n case 'plan.template_use': {\n const parsed = validatePlanTemplateUsePayload(message.payload);\n if (!parsed.ok) {\n sendResult(ctx, ws, false, parsed.message);\n return;\n }\n await handlePlanTemplateUse(ctx, ws, parsed.value.template);\n return;\n }\n case 'plan.item.update':\n await handlePlanItemUpdate(\n ctx,\n ws,\n message.payload as { target: string; status: 'open' | 'in_progress' | 'done' },\n );\n }\n}\n", "export { validatePrefsUpdatePayload } from './ws-payload-preferences.js';\n\ntype PayloadValidationResult<T> = { ok: true; value: T } | { ok: false; message: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\ninterface ModelSwitchPayload {\n provider: string;\n model: string;\n requestId?: string | undefined;\n}\n\nexport function validateModelSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModelSwitchPayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'model.switch payload must be an object with string provider and model',\n };\n }\n const provider = payload['provider'];\n const model = payload['model'];\n const requestId = payload['requestId'];\n if (typeof provider !== 'string' || provider.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.provider must be a non-empty string' };\n }\n if (typeof model !== 'string' || model.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.model must be a non-empty string' };\n }\n if (requestId !== undefined && (typeof requestId !== 'string' || requestId.trim().length === 0)) {\n return { ok: false, message: 'model.switch payload.requestId must be a non-empty string' };\n }\n return {\n ok: true,\n value: {\n provider: provider.trim(),\n model: model.trim(),\n ...(typeof requestId === 'string' ? { requestId: requestId.trim() } : {}),\n },\n };\n}\n\nconst AUTONOMY_VALUES = new Set(['off', 'suggest', 'auto', 'eternal', 'eternal-parallel']);\n\ninterface MailboxMessagesPayload {\n limit?: number;\n agentId?: string;\n unreadOnly?: boolean;\n incompleteOnly?: boolean;\n}\n\nexport function validateMailboxMessagesPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxMessagesPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.messages payload must be an object when provided' };\n }\n const limit = payload['limit'];\n const agentId = payload['agentId'];\n const unreadOnly = payload['unreadOnly'];\n const incompleteOnly = payload['incompleteOnly'];\n if (limit !== undefined && (typeof limit !== 'number' || !Number.isFinite(limit) || limit < 1)) {\n return {\n ok: false,\n message: 'mailbox.messages payload.limit must be a positive number when provided',\n };\n }\n if (agentId !== undefined && typeof agentId !== 'string') {\n return {\n ok: false,\n message: 'mailbox.messages payload.agentId must be a string when provided',\n };\n }\n if (unreadOnly !== undefined && typeof unreadOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.unreadOnly must be a boolean when provided',\n };\n }\n if (incompleteOnly !== undefined && typeof incompleteOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.incompleteOnly must be a boolean when provided',\n };\n }\n return {\n ok: true,\n value: {\n ...(limit !== undefined ? { limit: limit as number } : {}),\n ...(agentId !== undefined ? { agentId: agentId as string } : {}),\n ...(unreadOnly !== undefined ? { unreadOnly: unreadOnly as boolean } : {}),\n ...(incompleteOnly !== undefined ? { incompleteOnly: incompleteOnly as boolean } : {}),\n },\n };\n}\n\ninterface MailboxAgentsPayload {\n onlineOnly?: boolean;\n}\n\nconst MAILBOX_SEND_TYPES = new Set([\n 'note',\n 'ask',\n 'assign',\n 'steer',\n 'btw',\n 'broadcast',\n 'status',\n 'result',\n 'review',\n]);\n\nexport interface MailboxSendPayload {\n requestId: string;\n to: string;\n type: 'note' | 'ask' | 'assign' | 'steer' | 'btw' | 'broadcast' | 'status' | 'result' | 'review';\n audience: 'all' | 'leaders';\n subject: string;\n body: string;\n priority: 'low' | 'normal' | 'high';\n replyTo?: string | undefined;\n}\n\nexport function validateMailboxSendPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxSendPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.send payload must be an object' };\n }\n const requestId = payload['requestId'];\n const rawTo = payload['to'];\n const rawType = payload['type'];\n const rawAudience = payload['audience'];\n const rawSubject = payload['subject'];\n const rawBody = payload['body'];\n const rawPriority = payload['priority'];\n const rawReplyTo = payload['replyTo'];\n\n if (typeof requestId !== 'string' || requestId.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.requestId must be a non-empty string' };\n }\n if (typeof rawTo !== 'string' || rawTo.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.to must be a non-empty string' };\n }\n if (typeof rawType !== 'string' || !MAILBOX_SEND_TYPES.has(rawType)) {\n return {\n ok: false,\n message: 'mailbox.send payload.type must be a supported non-control message type',\n };\n }\n if (rawAudience !== 'all' && rawAudience !== 'leaders') {\n return { ok: false, message: 'mailbox.send payload.audience must be all or leaders' };\n }\n if (typeof rawSubject !== 'string' || rawSubject.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.subject must be a non-empty string' };\n }\n if (typeof rawBody !== 'string' || rawBody.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.body must be a non-empty string' };\n }\n if (rawPriority !== 'low' && rawPriority !== 'normal' && rawPriority !== 'high') {\n return { ok: false, message: 'mailbox.send payload.priority must be low, normal, or high' };\n }\n if (rawReplyTo !== undefined && typeof rawReplyTo !== 'string') {\n return { ok: false, message: 'mailbox.send payload.replyTo must be a string when provided' };\n }\n\n const type = rawType as MailboxSendPayload['type'];\n const to = type === 'broadcast' ? '*' : rawTo.trim();\n if ((type === 'assign' || type === 'steer') && (to === '*' || to.toLowerCase() === 'all')) {\n return {\n ok: false,\n message: `mailbox.send payload.type ${type} requires a specific recipient`,\n };\n }\n\n return {\n ok: true,\n value: {\n requestId: requestId.trim(),\n to,\n type,\n audience: rawAudience,\n subject: rawSubject.trim(),\n body: rawBody.trim(),\n priority: rawPriority,\n ...(rawReplyTo !== undefined ? { replyTo: rawReplyTo } : {}),\n },\n };\n}\n\nexport function validateMailboxAgentsPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxAgentsPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.agents payload must be an object when provided' };\n }\n const onlineOnly = payload['onlineOnly'];\n if (onlineOnly !== undefined && typeof onlineOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.agents payload.onlineOnly must be a boolean when provided',\n };\n }\n return {\n ok: true,\n value: { ...(onlineOnly !== undefined ? { onlineOnly: onlineOnly as boolean } : {}) },\n };\n}\n\ninterface MailboxPurgePayload {\n completedMaxAgeMs?: number;\n incompleteMaxAgeMs?: number;\n}\n\nexport function validateMailboxPurgePayload(\n payload: unknown,\n): PayloadValidationResult<MailboxPurgePayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.purge payload must be an object when provided' };\n }\n const completedMaxAgeMs = payload['completedMaxAgeMs'];\n const incompleteMaxAgeMs = payload['incompleteMaxAgeMs'];\n if (\n completedMaxAgeMs !== undefined &&\n (typeof completedMaxAgeMs !== 'number' ||\n !Number.isFinite(completedMaxAgeMs) ||\n completedMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.completedMaxAgeMs must be a non-negative number when provided',\n };\n }\n if (\n incompleteMaxAgeMs !== undefined &&\n (typeof incompleteMaxAgeMs !== 'number' ||\n !Number.isFinite(incompleteMaxAgeMs) ||\n incompleteMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.incompleteMaxAgeMs must be a non-negative number when provided',\n };\n }\n return {\n ok: true,\n value: {\n ...(completedMaxAgeMs !== undefined\n ? { completedMaxAgeMs: completedMaxAgeMs as number }\n : {}),\n ...(incompleteMaxAgeMs !== undefined\n ? { incompleteMaxAgeMs: incompleteMaxAgeMs as number }\n : {}),\n },\n };\n}\n\ninterface BrainRiskPayload {\n level: string;\n}\n\nconst BRAIN_RISK_VALUES = new Set(['off', 'low', 'medium', 'high', 'all']);\n\nexport function validateBrainRiskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainRiskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.risk payload must be an object with string level' };\n }\n const level = payload['level'];\n if (typeof level !== 'string' || !BRAIN_RISK_VALUES.has(level)) {\n return {\n ok: false,\n message: 'brain.risk payload.level must be one of off, low, medium, high, all',\n };\n }\n return { ok: true, value: { level } };\n}\n\ninterface BrainAskPayload {\n question: string;\n}\n\nexport function validateBrainAskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainAskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.ask payload must be an object with string question' };\n }\n const question = payload['question'];\n if (typeof question !== 'string' || question.trim().length === 0) {\n return { ok: false, message: 'brain.ask payload.question must be a non-empty string' };\n }\n return { ok: true, value: { question: question.trim() } };\n}\n\ninterface BrainConfigSetPayload {\n patch: Record<string, unknown>;\n}\n\nexport function validateBrainConfigSetPayload(\n payload: unknown,\n): PayloadValidationResult<BrainConfigSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.config.set payload must be an object with a patch object' };\n }\n const patch = payload['patch'];\n if (!isRecord(patch)) {\n // Field-level validation happens in BrainRuntime.apply(), which throws\n // BEFORE any live state changes \u2014 this only guards the envelope shape.\n return { ok: false, message: 'brain.config.set payload.patch must be an object' };\n }\n return { ok: true, value: { patch } };\n}\n\ninterface AutonomySwitchPayload {\n mode: string;\n}\n\nexport function validateAutonomySwitchPayload(\n payload: unknown,\n): PayloadValidationResult<AutonomySwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'autonomy.switch payload must be an object with string mode' };\n }\n const mode = payload['mode'];\n if (typeof mode !== 'string' || !AUTONOMY_VALUES.has(mode)) {\n return { ok: false, message: 'autonomy.switch payload.mode must be a valid autonomy mode' };\n }\n return { ok: true, value: { mode } };\n}\n\ninterface PlanTemplateUsePayload {\n template: string;\n}\n\nexport function validatePlanTemplateUsePayload(\n payload: unknown,\n): PayloadValidationResult<PlanTemplateUsePayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'plan.template_use payload must be an object with string template',\n };\n }\n const template = payload['template'];\n if (typeof template !== 'string' || template.trim().length === 0) {\n return { ok: false, message: 'plan.template_use payload.template must be a non-empty string' };\n }\n return { ok: true, value: { template } };\n}\ninterface SkillsCreatePayload {\n name: string;\n description: string;\n scope: 'project' | 'global';\n}\n\nexport function validateSkillsCreatePayload(\n payload: unknown,\n): PayloadValidationResult<SkillsCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.create payload must be an object' };\n }\n const name = payload['name'];\n const description = payload['description'];\n const scope = payload['scope'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name.trim())) {\n return { ok: false, message: 'Skill name must be kebab-case (e.g. my-new-skill)' };\n }\n if (typeof description !== 'string' || description.trim().length === 0) {\n return { ok: false, message: 'Description/trigger is required' };\n }\n if (scope !== 'project' && scope !== 'global') {\n return { ok: false, message: 'skills.create payload.scope must be project or global' };\n }\n return { ok: true, value: { name, description, scope } };\n}\n\ninterface SkillsEditPayload {\n name: string;\n body: string;\n}\n\nexport function validateSkillsEditPayload(\n payload: unknown,\n): PayloadValidationResult<SkillsEditPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.edit payload must be an object' };\n }\n const name = payload['name'];\n const body = payload['body'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (typeof body !== 'string' || body.length === 0) {\n return { ok: false, message: 'Skill body is required' };\n }\n return { ok: true, value: { name, body } };\n}\n\ninterface ProcessKillPayload {\n pid: number;\n}\n\nexport function validateProcessKillPayload(\n payload: unknown,\n): PayloadValidationResult<ProcessKillPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'process.kill payload must be an object with numeric pid' };\n }\n const pid = payload['pid'];\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) {\n return { ok: false, message: 'process.kill payload.pid must be a positive integer' };\n }\n return { ok: true, value: { pid } };\n}\n\ninterface WorkingDirSetPayload {\n path: string;\n}\n\nexport function validateWorkingDirSetPayload(\n payload: unknown,\n): PayloadValidationResult<WorkingDirSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'working_dir.set payload must be an object with string path' };\n }\n const newPath = payload['path'];\n if (typeof newPath !== 'string' || newPath.trim().length === 0) {\n return { ok: false, message: 'working_dir.set payload.path must be a non-empty string' };\n }\n return { ok: true, value: { path: newPath } };\n}\n\ninterface ModeSwitchPayload {\n id: string;\n}\n\nexport function validateModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModeSwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mode.switch payload must be an object with string id' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'mode.switch payload.id must be a non-empty string' };\n }\n return { ok: true, value: { id } };\n}\n\ninterface ContextModeIdPayload {\n id: string;\n}\n\nfunction validateContextModeIdPayload(\n payload: unknown,\n type: 'context.mode.switch' | 'context.mode.delete',\n): PayloadValidationResult<ContextModeIdPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: `${type} payload must be an object with string id` };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: `${type} payload.id must be a non-empty string` };\n }\n return { ok: true, value: { id } };\n}\n\nexport function validateContextModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.switch');\n}\n\nexport function validateContextModeDeletePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.delete');\n}\n\ninterface ContextModeCreatePayload {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n preserveK: number;\n eliseThreshold: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nexport function validateContextModeCreatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.create payload must be an object' };\n }\n const id = payload['id'];\n const name = payload['name'];\n const description = payload['description'];\n const thresholds = payload['thresholds'];\n const preserveK = payload['preserveK'];\n const eliseThreshold = payload['eliseThreshold'];\n\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.id must be a non-empty string' };\n }\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.name must be a non-empty string' };\n }\n if (typeof description !== 'string') {\n return { ok: false, message: 'context.mode.create payload.description must be a string' };\n }\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message:\n 'context.mode.create payload.thresholds must be an object with warn/soft/hard numbers',\n };\n }\n if (\n !isFiniteNumber(thresholds['warn']) ||\n !isFiniteNumber(thresholds['soft']) ||\n !isFiniteNumber(thresholds['hard'])\n ) {\n return {\n ok: false,\n message: 'context.mode.create payload.thresholds.warn/soft/hard must be finite numbers',\n };\n }\n if (!isFiniteNumber(preserveK)) {\n return { ok: false, message: 'context.mode.create payload.preserveK must be a finite number' };\n }\n if (!isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.create payload.eliseThreshold must be a finite number',\n };\n }\n return {\n ok: true,\n value: {\n id,\n name,\n description,\n thresholds: { warn: thresholds['warn'], soft: thresholds['soft'], hard: thresholds['hard'] },\n preserveK,\n eliseThreshold,\n },\n };\n}\n\ninterface ContextModeUpdatePayload {\n id: string;\n name?: string;\n description?: string;\n thresholds?: { warn?: number; soft?: number; hard?: number };\n preserveK?: number;\n eliseThreshold?: number;\n}\n\nexport function validateContextModeUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.update payload must be an object' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.update payload.id must be a non-empty string' };\n }\n\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.name must be a string when provided',\n };\n }\n\n const description = payload['description'];\n if (description !== undefined && typeof description !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.description must be a string when provided',\n };\n }\n\n const thresholds = payload['thresholds'];\n let validatedThresholds: ContextModeUpdatePayload['thresholds'];\n if (thresholds !== undefined) {\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message: 'context.mode.update payload.thresholds must be an object when provided',\n };\n }\n for (const key of ['warn', 'soft', 'hard'] as const) {\n const val = thresholds[key];\n if (val !== undefined && !isFiniteNumber(val)) {\n return {\n ok: false,\n message: `context.mode.update payload.thresholds.${key} must be a finite number when provided`,\n };\n }\n }\n validatedThresholds = {\n ...(typeof thresholds['warn'] === 'number' ? { warn: thresholds['warn'] } : {}),\n ...(typeof thresholds['soft'] === 'number' ? { soft: thresholds['soft'] } : {}),\n ...(typeof thresholds['hard'] === 'number' ? { hard: thresholds['hard'] } : {}),\n };\n }\n\n const preserveK = payload['preserveK'];\n if (preserveK !== undefined && !isFiniteNumber(preserveK)) {\n return {\n ok: false,\n message: 'context.mode.update payload.preserveK must be a finite number when provided',\n };\n }\n\n const eliseThreshold = payload['eliseThreshold'];\n if (eliseThreshold !== undefined && !isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.update payload.eliseThreshold must be a finite number when provided',\n };\n }\n\n return {\n ok: true,\n value: {\n id,\n ...(typeof name === 'string' ? { name } : {}),\n ...(typeof description === 'string' ? { description } : {}),\n ...(validatedThresholds !== undefined ? { thresholds: validatedThresholds } : {}),\n ...(typeof preserveK === 'number' ? { preserveK } : {}),\n ...(typeof eliseThreshold === 'number' ? { eliseThreshold } : {}),\n },\n };\n}\n\ninterface ShellOpenPayload {\n path: string;\n target?: 'file' | 'terminal';\n}\n\nexport function validateShellOpenPayload(\n payload: unknown,\n): PayloadValidationResult<ShellOpenPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'shell.open payload must be an object with string path' };\n }\n const path = payload['path'];\n if (typeof path !== 'string' || path.trim().length === 0) {\n return { ok: false, message: 'shell.open payload.path must be a non-empty string' };\n }\n const target = payload['target'];\n if (target !== undefined && target !== 'file' && target !== 'terminal') {\n return {\n ok: false,\n message: 'shell.open payload.target must be \"file\" or \"terminal\" when provided',\n };\n }\n return {\n ok: true,\n value: {\n path,\n ...(target !== undefined ? { target: target as 'file' | 'terminal' } : {}),\n },\n };\n}\n\ninterface GitDiffPayload {\n path: string;\n}\n\nexport function validateGitDiffPayload(payload: unknown): PayloadValidationResult<GitDiffPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'git.diff payload must be an object' };\n }\n const path = payload['path'];\n if (path === undefined || path === null) {\n return { ok: true, value: { path: '' } };\n }\n if (typeof path !== 'string') {\n return { ok: false, message: 'git.diff payload.path must be a string when provided' };\n }\n return { ok: true, value: { path } };\n}\n\ninterface ProjectsAddPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsAddPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsAddPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.add payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.add payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.add payload.name must be a string when provided' };\n }\n return {\n ok: true,\n value: { root, ...(typeof name === 'string' ? { name } : {}) },\n };\n}\n\ninterface ProjectsSelectPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsSelectPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsSelectPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.select payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.select payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.select payload.name must be a string when provided' };\n }\n return {\n ok: true,\n value: { root, ...(typeof name === 'string' ? { name } : {}) },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n addPlanItem,\n emptyPlan,\n getPlanTemplate,\n loadPlan,\n loadTasks,\n mutatePlan,\n mutateTasks,\n savePlan,\n setPlanItemStatus,\n} from '@wrongstack/core/storage';\nimport type { TodoItem } from '@wrongstack/core/agent';\nimport type { WebSocket } from 'ws';\nimport type { WSServerMessage } from '../types.js';\nimport { validatePlanTemplateUsePayload } from '../ws-payload-validation.js';\n\nexport interface WorklistContext {\n context: {\n todos: TodoItem[];\n meta: Record<string, unknown>;\n session: { id: string } | null;\n };\n send: (ws: WebSocket, msg: WSServerMessage) => void;\n broadcast: (msg: WSServerMessage) => void;\n replaceTodos?: ((todos: TodoItem[]) => void) | undefined;\n}\n\nexport interface WorklistMessage {\n type: string;\n payload?: unknown;\n}\n\nfunction sendResult(ctx: WorklistContext, ws: WebSocket, success: boolean, message: string): void {\n ctx.send(ws, { type: 'key.operation_result', payload: { success, message } });\n}\n\nfunction currentSessionId(ctx: WorklistContext): string {\n return ctx.context.session?.id ?? '';\n}\n\nfunction sessionPayload<T extends Record<string, unknown>>(\n ctx: WorklistContext,\n payload: T,\n): T & { sessionId: string } {\n const provided = payload['sessionId'];\n const sessionId =\n typeof provided === 'string' && provided.length > 0 ? provided : currentSessionId(ctx);\n return { ...payload, sessionId };\n}\n\nfunction planPathOf(ctx: WorklistContext): string | undefined {\n const value = ctx.context.meta['plan.path'];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nfunction taskPathOf(ctx: WorklistContext): string | undefined {\n const value = ctx.context.meta['task.path'];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nexport function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void {\n ctx.send(ws, {\n type: 'todos.updated',\n payload: sessionPayload(ctx, { todos: [...ctx.context.todos] }),\n });\n}\n\nexport function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void {\n ctx.replaceTodos?.([]);\n sendResult(ctx, ws, true, 'Todos cleared');\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: [] }) });\n}\n\nexport function handleTodosRemove(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id?: string | undefined; index?: number | undefined } | undefined,\n): void {\n if (!payload) {\n sendResult(ctx, ws, false, 'Missing id or index');\n return;\n }\n const todos = ctx.context.todos;\n let targetIndex = -1;\n if (typeof payload.id === 'string') {\n targetIndex = todos.findIndex((todo) => todo.id === payload.id);\n } else if (typeof payload.index === 'number' && payload.index > 0) {\n targetIndex = payload.index - 1;\n }\n const removed = todos[targetIndex];\n if (targetIndex < 0 || !removed) {\n sendResult(ctx, ws, false, 'Todo not found');\n return;\n }\n const next = [...todos.slice(0, targetIndex), ...todos.slice(targetIndex + 1)];\n ctx.replaceTodos?.(next);\n sendResult(ctx, ws, true, `Removed: ${removed.content}`);\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: next }) });\n}\n\nexport function handleTodoUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id: string; status?: TodoItem['status'] | undefined; activeForm?: string | undefined },\n): void {\n const index = ctx.context.todos.findIndex((todo) => todo.id === payload.id);\n const existing = ctx.context.todos[index];\n if (index === -1 || !existing) {\n sendResult(ctx, ws, false, 'Todo not found');\n return;\n }\n const next = [...ctx.context.todos];\n next[index] = {\n ...existing,\n status: payload.status ?? existing.status,\n activeForm: payload.activeForm !== undefined ? payload.activeForm : existing.activeForm,\n };\n ctx.replaceTodos?.(next);\n sendResult(ctx, ws, true, `Todo \"${existing.content}\" updated`);\n ctx.broadcast({ type: 'todos.updated', payload: sessionPayload(ctx, { todos: next }) });\n}\n\nexport async function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const taskPath = taskPathOf(ctx);\n if (!taskPath) {\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: [], error: 'Task storage not configured.' }),\n });\n return;\n }\n try {\n const file = await loadTasks(taskPath);\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: file?.tasks ?? [] }),\n });\n } catch {\n ctx.send(ws, { type: 'tasks.updated', payload: sessionPayload(ctx, { tasks: [] }) });\n }\n}\n\nexport async function handleTaskUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n): Promise<void> {\n const taskPath = taskPathOf(ctx);\n if (!taskPath) {\n sendResult(ctx, ws, false, 'Task storage not configured.');\n return;\n }\n try {\n const file = await mutateTasks(taskPath, currentSessionId(ctx), async (tasks) => {\n const task = tasks.tasks.find((candidate) => candidate.id === payload.id);\n if (!task) return tasks;\n task.status = payload.status;\n task.updatedAt = new Date().toISOString();\n return tasks;\n });\n sendResult(ctx, ws, true, `Task status updated to \"${payload.status}\".`);\n ctx.broadcast({\n type: 'tasks.updated',\n payload: sessionPayload(ctx, { tasks: file.tasks }),\n });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const planPath = planPathOf(ctx);\n const emptySnapshot = () => ({\n version: 1,\n sessionId: currentSessionId(ctx),\n updatedAt: new Date().toISOString(),\n items: [],\n });\n if (!planPath) {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, {\n plan: null,\n error: 'Plan storage is not configured for this session.',\n }),\n });\n return;\n }\n try {\n const plan = await loadPlan(planPath);\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, { plan: plan ?? emptySnapshot() }),\n });\n } catch {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: sessionPayload(ctx, { plan: emptySnapshot() }),\n });\n }\n}\n\nexport async function handlePlanTemplateUse(\n ctx: WorklistContext,\n ws: WebSocket,\n template: string,\n): Promise<void> {\n const planPath = planPathOf(ctx);\n if (!planPath) {\n sendResult(ctx, ws, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const templateDefinition = getPlanTemplate(template);\n if (!templateDefinition) {\n sendResult(ctx, ws, false, `Unknown template \"${template}\".`);\n return;\n }\n let plan = (await loadPlan(planPath)) ?? emptyPlan(currentSessionId(ctx));\n for (const item of templateDefinition.items) {\n ({ plan } = addPlanItem(plan, item.title, item.details));\n }\n await savePlan(planPath, plan);\n sendResult(\n ctx,\n ws,\n true,\n `Applied template \"${templateDefinition.name}\" \u2014 ${templateDefinition.items.length} items added.`,\n );\n ctx.broadcast({ type: 'plan.updated', payload: sessionPayload(ctx, { plan }) });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handlePlanItemUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { target: string; status: 'open' | 'in_progress' | 'done' },\n): Promise<void> {\n const planPath = planPathOf(ctx);\n if (!planPath) {\n sendResult(ctx, ws, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n let changed = false;\n const plan = await mutatePlan(planPath, currentSessionId(ctx), async (currentPlan) => {\n const before = currentPlan.updatedAt;\n const next = setPlanItemStatus(currentPlan, payload.target, payload.status);\n changed = next.updatedAt !== before;\n return next;\n });\n if (!changed) {\n sendResult(ctx, ws, false, `No plan item matched \"${payload.target}\".`);\n return;\n }\n sendResult(ctx, ws, true, `Plan item status updated to \"${payload.status}\".`);\n ctx.broadcast({ type: 'plan.updated', payload: sessionPayload(ctx, { plan }) });\n } catch (error) {\n sendResult(ctx, ws, false, error instanceof Error ? error.message : String(error));\n }\n}\n\nexport async function handleWorklistMessage(\n ctx: WorklistContext,\n ws: WebSocket,\n message: WorklistMessage,\n): Promise<void> {\n switch (message.type) {\n case 'todos.get':\n handleTodosGet(ctx, ws);\n return;\n case 'todos.clear':\n handleTodosClear(ctx, ws);\n return;\n case 'todos.remove':\n handleTodosRemove(ctx, ws, message.payload as { id?: string; index?: number } | undefined);\n return;\n case 'todo.update':\n handleTodoUpdate(\n ctx,\n ws,\n message.payload as {\n id: string;\n status?: TodoItem['status'];\n activeForm?: string;\n },\n );\n return;\n case 'tasks.get':\n await handleTasksGet(ctx, ws);\n return;\n case 'task.update':\n await handleTaskUpdate(\n ctx,\n ws,\n message.payload as {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n );\n return;\n case 'plan.get':\n await handlePlanGet(ctx, ws);\n return;\n case 'plan.template_use': {\n const parsed = validatePlanTemplateUsePayload(message.payload);\n if (!parsed.ok) {\n sendResult(ctx, ws, false, parsed.message);\n return;\n }\n await handlePlanTemplateUse(ctx, ws, parsed.value.template);\n return;\n }\n case 'plan.item.update':\n await handlePlanItemUpdate(\n ctx,\n ws,\n message.payload as { target: string; status: 'open' | 'in_progress' | 'done' },\n );\n }\n}\n", "export { validatePrefsUpdatePayload } from './ws-payload-preferences.js';\n\ntype PayloadValidationResult<T> = { ok: true; value: T } | { ok: false; message: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\ninterface ModelSwitchPayload {\n provider: string;\n model: string;\n requestId?: string | undefined;\n}\n\nexport function validateModelSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModelSwitchPayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'model.switch payload must be an object with string provider and model',\n };\n }\n const provider = payload['provider'];\n const model = payload['model'];\n const requestId = payload['requestId'];\n if (typeof provider !== 'string' || provider.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.provider must be a non-empty string' };\n }\n if (typeof model !== 'string' || model.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.model must be a non-empty string' };\n }\n if (requestId !== undefined && (typeof requestId !== 'string' || requestId.trim().length === 0)) {\n return { ok: false, message: 'model.switch payload.requestId must be a non-empty string' };\n }\n return {\n ok: true,\n value: {\n provider: provider.trim(),\n model: model.trim(),\n ...(typeof requestId === 'string' ? { requestId: requestId.trim() } : {}),\n },\n };\n}\n\nconst AUTONOMY_VALUES = new Set(['off', 'suggest', 'auto', 'eternal', 'eternal-parallel']);\n\ninterface MailboxMessagesPayload {\n limit?: number;\n agentId?: string;\n unreadOnly?: boolean;\n incompleteOnly?: boolean;\n}\n\nexport function validateMailboxMessagesPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxMessagesPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.messages payload must be an object when provided' };\n }\n const limit = payload['limit'];\n const agentId = payload['agentId'];\n const unreadOnly = payload['unreadOnly'];\n const incompleteOnly = payload['incompleteOnly'];\n if (limit !== undefined && (typeof limit !== 'number' || !Number.isFinite(limit) || limit < 1)) {\n return {\n ok: false,\n message: 'mailbox.messages payload.limit must be a positive number when provided',\n };\n }\n if (agentId !== undefined && typeof agentId !== 'string') {\n return {\n ok: false,\n message: 'mailbox.messages payload.agentId must be a string when provided',\n };\n }\n if (unreadOnly !== undefined && typeof unreadOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.unreadOnly must be a boolean when provided',\n };\n }\n if (incompleteOnly !== undefined && typeof incompleteOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.incompleteOnly must be a boolean when provided',\n };\n }\n return {\n ok: true,\n value: {\n ...(limit !== undefined ? { limit: limit as number } : {}),\n ...(agentId !== undefined ? { agentId: agentId as string } : {}),\n ...(unreadOnly !== undefined ? { unreadOnly: unreadOnly as boolean } : {}),\n ...(incompleteOnly !== undefined ? { incompleteOnly: incompleteOnly as boolean } : {}),\n },\n };\n}\n\ninterface MailboxAgentsPayload {\n onlineOnly?: boolean;\n}\n\nconst MAILBOX_ACTIONS = new Set(['mark-read', 'acknowledge', 'reopen', 'soft-delete']);\n\nexport interface MailboxActionPayload {\n requestId: string;\n mailId: string;\n action: 'mark-read' | 'acknowledge' | 'reopen' | 'soft-delete';\n readerId: string;\n}\n\nexport function validateMailboxActionPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxActionPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.action payload must be an object' };\n }\n const requestId = payload['requestId'];\n const mailId = payload['mailId'];\n const action = payload['action'];\n const readerId = payload['readerId'];\n if (typeof requestId !== 'string' || requestId.trim().length === 0) {\n return { ok: false, message: 'mailbox.action payload.requestId must be a non-empty string' };\n }\n if (typeof mailId !== 'string' || mailId.trim().length === 0) {\n return { ok: false, message: 'mailbox.action payload.mailId must be a non-empty string' };\n }\n if (typeof action !== 'string' || !MAILBOX_ACTIONS.has(action)) {\n return { ok: false, message: 'mailbox.action payload.action must be a supported action' };\n }\n if (typeof readerId !== 'string' || readerId.trim().length === 0) {\n return { ok: false, message: 'mailbox.action payload.readerId must be a non-empty string' };\n }\n return {\n ok: true,\n value: {\n requestId: requestId.trim(),\n mailId: mailId.trim(),\n action: action as MailboxActionPayload['action'],\n readerId: readerId.trim(),\n },\n };\n}\n\nconst MAILBOX_SEND_TYPES = new Set([\n 'note',\n 'ask',\n 'assign',\n 'steer',\n 'btw',\n 'broadcast',\n 'status',\n 'result',\n 'review',\n]);\n\nexport interface MailboxSendPayload {\n requestId: string;\n from?: string | undefined;\n to: string;\n type: 'note' | 'ask' | 'assign' | 'steer' | 'btw' | 'broadcast' | 'status' | 'result' | 'review';\n audience: 'all' | 'leaders';\n subject: string;\n body: string;\n priority: 'low' | 'normal' | 'high';\n replyTo?: string | undefined;\n}\n\nexport function validateMailboxSendPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxSendPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.send payload must be an object' };\n }\n const requestId = payload['requestId'];\n const rawFrom = payload['from'];\n const rawTo = payload['to'];\n const rawType = payload['type'];\n const rawAudience = payload['audience'];\n const rawSubject = payload['subject'];\n const rawBody = payload['body'];\n const rawPriority = payload['priority'];\n const rawReplyTo = payload['replyTo'];\n\n if (typeof requestId !== 'string' || requestId.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.requestId must be a non-empty string' };\n }\n if (rawFrom !== undefined && (typeof rawFrom !== 'string' || rawFrom.trim().length === 0)) {\n return { ok: false, message: 'mailbox.send payload.from must be a non-empty string when provided' };\n }\n if (typeof rawTo !== 'string' || rawTo.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.to must be a non-empty string' };\n }\n if (typeof rawType !== 'string' || !MAILBOX_SEND_TYPES.has(rawType)) {\n return {\n ok: false,\n message: 'mailbox.send payload.type must be a supported non-control message type',\n };\n }\n if (rawAudience !== 'all' && rawAudience !== 'leaders') {\n return { ok: false, message: 'mailbox.send payload.audience must be all or leaders' };\n }\n if (typeof rawSubject !== 'string' || rawSubject.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.subject must be a non-empty string' };\n }\n if (typeof rawBody !== 'string' || rawBody.trim().length === 0) {\n return { ok: false, message: 'mailbox.send payload.body must be a non-empty string' };\n }\n if (rawPriority !== 'low' && rawPriority !== 'normal' && rawPriority !== 'high') {\n return { ok: false, message: 'mailbox.send payload.priority must be low, normal, or high' };\n }\n if (rawReplyTo !== undefined && typeof rawReplyTo !== 'string') {\n return { ok: false, message: 'mailbox.send payload.replyTo must be a string when provided' };\n }\n\n const type = rawType as MailboxSendPayload['type'];\n const to = type === 'broadcast' ? '*' : rawTo.trim();\n if ((type === 'assign' || type === 'steer') && (to === '*' || to.toLowerCase() === 'all')) {\n return {\n ok: false,\n message: `mailbox.send payload.type ${type} requires a specific recipient`,\n };\n }\n\n return {\n ok: true,\n value: {\n requestId: requestId.trim(),\n ...(rawFrom !== undefined ? { from: rawFrom.trim() } : {}),\n to,\n type,\n audience: rawAudience,\n subject: rawSubject.trim(),\n body: rawBody.trim(),\n priority: rawPriority,\n ...(rawReplyTo !== undefined ? { replyTo: rawReplyTo } : {}),\n },\n };\n}\n\nexport function validateMailboxAgentsPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxAgentsPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.agents payload must be an object when provided' };\n }\n const onlineOnly = payload['onlineOnly'];\n if (onlineOnly !== undefined && typeof onlineOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.agents payload.onlineOnly must be a boolean when provided',\n };\n }\n return {\n ok: true,\n value: { ...(onlineOnly !== undefined ? { onlineOnly: onlineOnly as boolean } : {}) },\n };\n}\n\ninterface MailboxPurgePayload {\n completedMaxAgeMs?: number;\n incompleteMaxAgeMs?: number;\n}\n\nexport function validateMailboxPurgePayload(\n payload: unknown,\n): PayloadValidationResult<MailboxPurgePayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.purge payload must be an object when provided' };\n }\n const completedMaxAgeMs = payload['completedMaxAgeMs'];\n const incompleteMaxAgeMs = payload['incompleteMaxAgeMs'];\n if (\n completedMaxAgeMs !== undefined &&\n (typeof completedMaxAgeMs !== 'number' ||\n !Number.isFinite(completedMaxAgeMs) ||\n completedMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.completedMaxAgeMs must be a non-negative number when provided',\n };\n }\n if (\n incompleteMaxAgeMs !== undefined &&\n (typeof incompleteMaxAgeMs !== 'number' ||\n !Number.isFinite(incompleteMaxAgeMs) ||\n incompleteMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.incompleteMaxAgeMs must be a non-negative number when provided',\n };\n }\n return {\n ok: true,\n value: {\n ...(completedMaxAgeMs !== undefined\n ? { completedMaxAgeMs: completedMaxAgeMs as number }\n : {}),\n ...(incompleteMaxAgeMs !== undefined\n ? { incompleteMaxAgeMs: incompleteMaxAgeMs as number }\n : {}),\n },\n };\n}\n\ninterface BrainRiskPayload {\n level: string;\n}\n\nconst BRAIN_RISK_VALUES = new Set(['off', 'low', 'medium', 'high', 'all']);\n\nexport function validateBrainRiskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainRiskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.risk payload must be an object with string level' };\n }\n const level = payload['level'];\n if (typeof level !== 'string' || !BRAIN_RISK_VALUES.has(level)) {\n return {\n ok: false,\n message: 'brain.risk payload.level must be one of off, low, medium, high, all',\n };\n }\n return { ok: true, value: { level } };\n}\n\ninterface BrainAskPayload {\n question: string;\n}\n\nexport function validateBrainAskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainAskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.ask payload must be an object with string question' };\n }\n const question = payload['question'];\n if (typeof question !== 'string' || question.trim().length === 0) {\n return { ok: false, message: 'brain.ask payload.question must be a non-empty string' };\n }\n return { ok: true, value: { question: question.trim() } };\n}\n\ninterface BrainConfigSetPayload {\n patch: Record<string, unknown>;\n}\n\nexport function validateBrainConfigSetPayload(\n payload: unknown,\n): PayloadValidationResult<BrainConfigSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.config.set payload must be an object with a patch object' };\n }\n const patch = payload['patch'];\n if (!isRecord(patch)) {\n // Field-level validation happens in BrainRuntime.apply(), which throws\n // BEFORE any live state changes \u2014 this only guards the envelope shape.\n return { ok: false, message: 'brain.config.set payload.patch must be an object' };\n }\n return { ok: true, value: { patch } };\n}\n\ninterface AutonomySwitchPayload {\n mode: string;\n}\n\nexport function validateAutonomySwitchPayload(\n payload: unknown,\n): PayloadValidationResult<AutonomySwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'autonomy.switch payload must be an object with string mode' };\n }\n const mode = payload['mode'];\n if (typeof mode !== 'string' || !AUTONOMY_VALUES.has(mode)) {\n return { ok: false, message: 'autonomy.switch payload.mode must be a valid autonomy mode' };\n }\n return { ok: true, value: { mode } };\n}\n\ninterface PlanTemplateUsePayload {\n template: string;\n}\n\nexport function validatePlanTemplateUsePayload(\n payload: unknown,\n): PayloadValidationResult<PlanTemplateUsePayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'plan.template_use payload must be an object with string template',\n };\n }\n const template = payload['template'];\n if (typeof template !== 'string' || template.trim().length === 0) {\n return { ok: false, message: 'plan.template_use payload.template must be a non-empty string' };\n }\n return { ok: true, value: { template } };\n}\ninterface SkillsCreatePayload {\n name: string;\n description: string;\n scope: 'project' | 'global';\n}\n\nexport function validateSkillsCreatePayload(\n payload: unknown,\n): PayloadValidationResult<SkillsCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.create payload must be an object' };\n }\n const name = payload['name'];\n const description = payload['description'];\n const scope = payload['scope'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name.trim())) {\n return { ok: false, message: 'Skill name must be kebab-case (e.g. my-new-skill)' };\n }\n if (typeof description !== 'string' || description.trim().length === 0) {\n return { ok: false, message: 'Description/trigger is required' };\n }\n if (scope !== 'project' && scope !== 'global') {\n return { ok: false, message: 'skills.create payload.scope must be project or global' };\n }\n return { ok: true, value: { name, description, scope } };\n}\n\ninterface SkillsEditPayload {\n name: string;\n body: string;\n}\n\nexport function validateSkillsEditPayload(\n payload: unknown,\n): PayloadValidationResult<SkillsEditPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.edit payload must be an object' };\n }\n const name = payload['name'];\n const body = payload['body'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (typeof body !== 'string' || body.length === 0) {\n return { ok: false, message: 'Skill body is required' };\n }\n return { ok: true, value: { name, body } };\n}\n\ninterface ProcessKillPayload {\n pid: number;\n}\n\nexport function validateProcessKillPayload(\n payload: unknown,\n): PayloadValidationResult<ProcessKillPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'process.kill payload must be an object with numeric pid' };\n }\n const pid = payload['pid'];\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) {\n return { ok: false, message: 'process.kill payload.pid must be a positive integer' };\n }\n return { ok: true, value: { pid } };\n}\n\ninterface WorkingDirSetPayload {\n path: string;\n}\n\nexport function validateWorkingDirSetPayload(\n payload: unknown,\n): PayloadValidationResult<WorkingDirSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'working_dir.set payload must be an object with string path' };\n }\n const newPath = payload['path'];\n if (typeof newPath !== 'string' || newPath.trim().length === 0) {\n return { ok: false, message: 'working_dir.set payload.path must be a non-empty string' };\n }\n return { ok: true, value: { path: newPath } };\n}\n\ninterface ModeSwitchPayload {\n id: string;\n}\n\nexport function validateModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModeSwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mode.switch payload must be an object with string id' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'mode.switch payload.id must be a non-empty string' };\n }\n return { ok: true, value: { id } };\n}\n\ninterface ContextModeIdPayload {\n id: string;\n}\n\nfunction validateContextModeIdPayload(\n payload: unknown,\n type: 'context.mode.switch' | 'context.mode.delete',\n): PayloadValidationResult<ContextModeIdPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: `${type} payload must be an object with string id` };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: `${type} payload.id must be a non-empty string` };\n }\n return { ok: true, value: { id } };\n}\n\nexport function validateContextModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.switch');\n}\n\nexport function validateContextModeDeletePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.delete');\n}\n\ninterface ContextModeCreatePayload {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n preserveK: number;\n eliseThreshold: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nexport function validateContextModeCreatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.create payload must be an object' };\n }\n const id = payload['id'];\n const name = payload['name'];\n const description = payload['description'];\n const thresholds = payload['thresholds'];\n const preserveK = payload['preserveK'];\n const eliseThreshold = payload['eliseThreshold'];\n\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.id must be a non-empty string' };\n }\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.name must be a non-empty string' };\n }\n if (typeof description !== 'string') {\n return { ok: false, message: 'context.mode.create payload.description must be a string' };\n }\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message:\n 'context.mode.create payload.thresholds must be an object with warn/soft/hard numbers',\n };\n }\n if (\n !isFiniteNumber(thresholds['warn']) ||\n !isFiniteNumber(thresholds['soft']) ||\n !isFiniteNumber(thresholds['hard'])\n ) {\n return {\n ok: false,\n message: 'context.mode.create payload.thresholds.warn/soft/hard must be finite numbers',\n };\n }\n if (!isFiniteNumber(preserveK)) {\n return { ok: false, message: 'context.mode.create payload.preserveK must be a finite number' };\n }\n if (!isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.create payload.eliseThreshold must be a finite number',\n };\n }\n return {\n ok: true,\n value: {\n id,\n name,\n description,\n thresholds: { warn: thresholds['warn'], soft: thresholds['soft'], hard: thresholds['hard'] },\n preserveK,\n eliseThreshold,\n },\n };\n}\n\ninterface ContextModeUpdatePayload {\n id: string;\n name?: string;\n description?: string;\n thresholds?: { warn?: number; soft?: number; hard?: number };\n preserveK?: number;\n eliseThreshold?: number;\n}\n\nexport function validateContextModeUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.update payload must be an object' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.update payload.id must be a non-empty string' };\n }\n\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.name must be a string when provided',\n };\n }\n\n const description = payload['description'];\n if (description !== undefined && typeof description !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.description must be a string when provided',\n };\n }\n\n const thresholds = payload['thresholds'];\n let validatedThresholds: ContextModeUpdatePayload['thresholds'];\n if (thresholds !== undefined) {\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message: 'context.mode.update payload.thresholds must be an object when provided',\n };\n }\n for (const key of ['warn', 'soft', 'hard'] as const) {\n const val = thresholds[key];\n if (val !== undefined && !isFiniteNumber(val)) {\n return {\n ok: false,\n message: `context.mode.update payload.thresholds.${key} must be a finite number when provided`,\n };\n }\n }\n validatedThresholds = {\n ...(typeof thresholds['warn'] === 'number' ? { warn: thresholds['warn'] } : {}),\n ...(typeof thresholds['soft'] === 'number' ? { soft: thresholds['soft'] } : {}),\n ...(typeof thresholds['hard'] === 'number' ? { hard: thresholds['hard'] } : {}),\n };\n }\n\n const preserveK = payload['preserveK'];\n if (preserveK !== undefined && !isFiniteNumber(preserveK)) {\n return {\n ok: false,\n message: 'context.mode.update payload.preserveK must be a finite number when provided',\n };\n }\n\n const eliseThreshold = payload['eliseThreshold'];\n if (eliseThreshold !== undefined && !isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.update payload.eliseThreshold must be a finite number when provided',\n };\n }\n\n return {\n ok: true,\n value: {\n id,\n ...(typeof name === 'string' ? { name } : {}),\n ...(typeof description === 'string' ? { description } : {}),\n ...(validatedThresholds !== undefined ? { thresholds: validatedThresholds } : {}),\n ...(typeof preserveK === 'number' ? { preserveK } : {}),\n ...(typeof eliseThreshold === 'number' ? { eliseThreshold } : {}),\n },\n };\n}\n\ninterface ShellOpenPayload {\n path: string;\n target?: 'file' | 'terminal';\n}\n\nexport function validateShellOpenPayload(\n payload: unknown,\n): PayloadValidationResult<ShellOpenPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'shell.open payload must be an object with string path' };\n }\n const path = payload['path'];\n if (typeof path !== 'string' || path.trim().length === 0) {\n return { ok: false, message: 'shell.open payload.path must be a non-empty string' };\n }\n const target = payload['target'];\n if (target !== undefined && target !== 'file' && target !== 'terminal') {\n return {\n ok: false,\n message: 'shell.open payload.target must be \"file\" or \"terminal\" when provided',\n };\n }\n return {\n ok: true,\n value: {\n path,\n ...(target !== undefined ? { target: target as 'file' | 'terminal' } : {}),\n },\n };\n}\n\ninterface GitDiffPayload {\n path: string;\n}\n\nexport function validateGitDiffPayload(payload: unknown): PayloadValidationResult<GitDiffPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'git.diff payload must be an object' };\n }\n const path = payload['path'];\n if (path === undefined || path === null) {\n return { ok: true, value: { path: '' } };\n }\n if (typeof path !== 'string') {\n return { ok: false, message: 'git.diff payload.path must be a string when provided' };\n }\n return { ok: true, value: { path } };\n}\n\ninterface ProjectsAddPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsAddPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsAddPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.add payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.add payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.add payload.name must be a string when provided' };\n }\n return {\n ok: true,\n value: { root, ...(typeof name === 'string' ? { name } : {}) },\n };\n}\n\ninterface ProjectsSelectPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsSelectPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsSelectPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.select payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.select payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.select payload.name must be a string when provided' };\n }\n return {\n ok: true,\n value: { root, ...(typeof name === 'string' ? { name } : {}) },\n };\n}\n"],
5
+ "mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACNP,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAkYO,SAAS,+BACd,SACiD;AACjD,MAAI,CAAC,SAAS,OAAO,GAAG;AACtB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,IACX;AAAA,EACF;AACA,QAAM,WAAW,QAAQ,UAAU;AACnC,MAAI,OAAO,aAAa,YAAY,SAAS,KAAK,EAAE,WAAW,GAAG;AAChE,WAAO,EAAE,IAAI,OAAO,SAAS,gEAAgE;AAAA,EAC/F;AACA,SAAO,EAAE,IAAI,MAAM,OAAO,EAAE,SAAS,EAAE;AACzC;;;ADtXA,SAAS,WAAW,KAAsB,IAAe,SAAkB,SAAuB;AAChG,MAAI,KAAK,IAAI,EAAE,MAAM,wBAAwB,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;AAC9E;AAEA,SAAS,iBAAiB,KAA8B;AACtD,SAAO,IAAI,QAAQ,SAAS,MAAM;AACpC;AAEA,SAAS,eACP,KACA,SAC2B;AAC3B,QAAM,WAAW,QAAQ,WAAW;AACpC,QAAM,YACJ,OAAO,aAAa,YAAY,SAAS,SAAS,IAAI,WAAW,iBAAiB,GAAG;AACvF,SAAO,EAAE,GAAG,SAAS,UAAU;AACjC;AAEA,SAAS,WAAW,KAA0C;AAC5D,QAAM,QAAQ,IAAI,QAAQ,KAAK,WAAW;AAC1C,SAAO,OAAO,UAAU,YAAY,QAAQ,QAAQ;AACtD;AAEA,SAAS,WAAW,KAA0C;AAC5D,QAAM,QAAQ,IAAI,QAAQ,KAAK,WAAW;AAC1C,SAAO,OAAO,UAAU,YAAY,QAAQ,QAAQ;AACtD;AAEO,SAAS,eAAe,KAAsB,IAAqB;AACxE,MAAI,KAAK,IAAI;AAAA,IACX,MAAM;AAAA,IACN,SAAS,eAAe,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI,QAAQ,KAAK,EAAE,CAAC;AAAA,EAChE,CAAC;AACH;AAEO,SAAS,iBAAiB,KAAsB,IAAqB;AAC1E,MAAI,eAAe,CAAC,CAAC;AACrB,aAAW,KAAK,IAAI,MAAM,eAAe;AACzC,MAAI,UAAU,EAAE,MAAM,iBAAiB,SAAS,eAAe,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AACtF;AAEO,SAAS,kBACd,KACA,IACA,SACM;AACN,MAAI,CAAC,SAAS;AACZ,eAAW,KAAK,IAAI,OAAO,qBAAqB;AAChD;AAAA,EACF;AACA,QAAM,QAAQ,IAAI,QAAQ;AAC1B,MAAI,cAAc;AAClB,MAAI,OAAO,QAAQ,OAAO,UAAU;AAClC,kBAAc,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAAA,EAChE,WAAW,OAAO,QAAQ,UAAU,YAAY,QAAQ,QAAQ,GAAG;AACjE,kBAAc,QAAQ,QAAQ;AAAA,EAChC;AACA,QAAM,UAAU,MAAM,WAAW;AACjC,MAAI,cAAc,KAAK,CAAC,SAAS;AAC/B,eAAW,KAAK,IAAI,OAAO,gBAAgB;AAC3C;AAAA,EACF;AACA,QAAM,OAAO,CAAC,GAAG,MAAM,MAAM,GAAG,WAAW,GAAG,GAAG,MAAM,MAAM,cAAc,CAAC,CAAC;AAC7E,MAAI,eAAe,IAAI;AACvB,aAAW,KAAK,IAAI,MAAM,YAAY,QAAQ,OAAO,EAAE;AACvD,MAAI,UAAU,EAAE,MAAM,iBAAiB,SAAS,eAAe,KAAK,EAAE,OAAO,KAAK,CAAC,EAAE,CAAC;AACxF;AAEO,SAAS,iBACd,KACA,IACA,SACM;AACN,QAAM,QAAQ,IAAI,QAAQ,MAAM,UAAU,CAAC,SAAS,KAAK,OAAO,QAAQ,EAAE;AAC1E,QAAM,WAAW,IAAI,QAAQ,MAAM,KAAK;AACxC,MAAI,UAAU,MAAM,CAAC,UAAU;AAC7B,eAAW,KAAK,IAAI,OAAO,gBAAgB;AAC3C;AAAA,EACF;AACA,QAAM,OAAO,CAAC,GAAG,IAAI,QAAQ,KAAK;AAClC,OAAK,KAAK,IAAI;AAAA,IACZ,GAAG;AAAA,IACH,QAAQ,QAAQ,UAAU,SAAS;AAAA,IACnC,YAAY,QAAQ,eAAe,SAAY,QAAQ,aAAa,SAAS;AAAA,EAC/E;AACA,MAAI,eAAe,IAAI;AACvB,aAAW,KAAK,IAAI,MAAM,SAAS,SAAS,OAAO,WAAW;AAC9D,MAAI,UAAU,EAAE,MAAM,iBAAiB,SAAS,eAAe,KAAK,EAAE,OAAO,KAAK,CAAC,EAAE,CAAC;AACxF;AAEA,eAAsB,eAAe,KAAsB,IAA8B;AACvF,QAAM,WAAW,WAAW,GAAG;AAC/B,MAAI,CAAC,UAAU;AACb,QAAI,KAAK,IAAI;AAAA,MACX,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,EAAE,OAAO,CAAC,GAAG,OAAO,+BAA+B,CAAC;AAAA,IACnF,CAAC;AACD;AAAA,EACF;AACA,MAAI;AACF,UAAM,OAAO,MAAM,UAAU,QAAQ;AACrC,QAAI,KAAK,IAAI;AAAA,MACX,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,EAAE,OAAO,MAAM,SAAS,CAAC,EAAE,CAAC;AAAA,IAC3D,CAAC;AAAA,EACH,QAAQ;AACN,QAAI,KAAK,IAAI,EAAE,MAAM,iBAAiB,SAAS,eAAe,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;AAAA,EACrF;AACF;AAEA,eAAsB,iBACpB,KACA,IACA,SAIe;AACf,QAAM,WAAW,WAAW,GAAG;AAC/B,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,IAAI,OAAO,8BAA8B;AACzD;AAAA,EACF;AACA,MAAI;AACF,UAAM,OAAO,MAAM,YAAY,UAAU,iBAAiB,GAAG,GAAG,OAAO,UAAU;AAC/E,YAAM,OAAO,MAAM,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,QAAQ,EAAE;AACxE,UAAI,CAAC,KAAM,QAAO;AAClB,WAAK,SAAS,QAAQ;AACtB,WAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,aAAO;AAAA,IACT,CAAC;AACD,eAAW,KAAK,IAAI,MAAM,2BAA2B,QAAQ,MAAM,IAAI;AACvE,QAAI,UAAU;AAAA,MACZ,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,SAAS,OAAO;AACd,eAAW,KAAK,IAAI,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,EACnF;AACF;AAEA,eAAsB,cAAc,KAAsB,IAA8B;AACtF,QAAM,WAAW,WAAW,GAAG;AAC/B,QAAM,gBAAgB,OAAO;AAAA,IAC3B,SAAS;AAAA,IACT,WAAW,iBAAiB,GAAG;AAAA,IAC/B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO,CAAC;AAAA,EACV;AACA,MAAI,CAAC,UAAU;AACb,QAAI,KAAK,IAAI;AAAA,MACX,MAAM;AAAA,MACN,SAAS,eAAe,KAAK;AAAA,QAC3B,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AACD;AAAA,EACF;AACA,MAAI;AACF,UAAM,OAAO,MAAM,SAAS,QAAQ;AACpC,QAAI,KAAK,IAAI;AAAA,MACX,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,EAAE,MAAM,QAAQ,cAAc,EAAE,CAAC;AAAA,IAChE,CAAC;AAAA,EACH,QAAQ;AACN,QAAI,KAAK,IAAI;AAAA,MACX,MAAM;AAAA,MACN,SAAS,eAAe,KAAK,EAAE,MAAM,cAAc,EAAE,CAAC;AAAA,IACxD,CAAC;AAAA,EACH;AACF;AAEA,eAAsB,sBACpB,KACA,IACA,UACe;AACf,QAAM,WAAW,WAAW,GAAG;AAC/B,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,IAAI,OAAO,kDAAkD;AAC7E;AAAA,EACF;AACA,MAAI;AACF,UAAM,qBAAqB,gBAAgB,QAAQ;AACnD,QAAI,CAAC,oBAAoB;AACvB,iBAAW,KAAK,IAAI,OAAO,qBAAqB,QAAQ,IAAI;AAC5D;AAAA,IACF;AACA,QAAI,OAAQ,MAAM,SAAS,QAAQ,KAAM,UAAU,iBAAiB,GAAG,CAAC;AACxE,eAAW,QAAQ,mBAAmB,OAAO;AAC3C,OAAC,EAAE,KAAK,IAAI,YAAY,MAAM,KAAK,OAAO,KAAK,OAAO;AAAA,IACxD;AACA,UAAM,SAAS,UAAU,IAAI;AAC7B;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,mBAAmB,IAAI,YAAO,mBAAmB,MAAM,MAAM;AAAA,IACpF;AACA,QAAI,UAAU,EAAE,MAAM,gBAAgB,SAAS,eAAe,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;AAAA,EAChF,SAAS,OAAO;AACd,eAAW,KAAK,IAAI,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,EACnF;AACF;AAEA,eAAsB,qBACpB,KACA,IACA,SACe;AACf,QAAM,WAAW,WAAW,GAAG;AAC/B,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,IAAI,OAAO,kDAAkD;AAC7E;AAAA,EACF;AACA,MAAI;AACF,QAAI,UAAU;AACd,UAAM,OAAO,MAAM,WAAW,UAAU,iBAAiB,GAAG,GAAG,OAAO,gBAAgB;AACpF,YAAM,SAAS,YAAY;AAC3B,YAAM,OAAO,kBAAkB,aAAa,QAAQ,QAAQ,QAAQ,MAAM;AAC1E,gBAAU,KAAK,cAAc;AAC7B,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,iBAAW,KAAK,IAAI,OAAO,yBAAyB,QAAQ,MAAM,IAAI;AACtE;AAAA,IACF;AACA,eAAW,KAAK,IAAI,MAAM,gCAAgC,QAAQ,MAAM,IAAI;AAC5E,QAAI,UAAU,EAAE,MAAM,gBAAgB,SAAS,eAAe,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;AAAA,EAChF,SAAS,OAAO;AACd,eAAW,KAAK,IAAI,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,EACnF;AACF;AAEA,eAAsB,sBACpB,KACA,IACA,SACe;AACf,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,qBAAe,KAAK,EAAE;AACtB;AAAA,IACF,KAAK;AACH,uBAAiB,KAAK,EAAE;AACxB;AAAA,IACF,KAAK;AACH,wBAAkB,KAAK,IAAI,QAAQ,OAAsD;AACzF;AAAA,IACF,KAAK;AACH;AAAA,QACE;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MAKV;AACA;AAAA,IACF,KAAK;AACH,YAAM,eAAe,KAAK,EAAE;AAC5B;AAAA,IACF,KAAK;AACH,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MAIV;AACA;AAAA,IACF,KAAK;AACH,YAAM,cAAc,KAAK,EAAE;AAC3B;AAAA,IACF,KAAK,qBAAqB;AACxB,YAAM,SAAS,+BAA+B,QAAQ,OAAO;AAC7D,UAAI,CAAC,OAAO,IAAI;AACd,mBAAW,KAAK,IAAI,OAAO,OAAO,OAAO;AACzC;AAAA,MACF;AACA,YAAM,sBAAsB,KAAK,IAAI,OAAO,MAAM,QAAQ;AAC1D;AAAA,IACF;AAAA,IACA,KAAK;AACH,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV;AAAA,EACJ;AACF;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/server/http-server.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AA6BlC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAWL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAQjC,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kFAAkF;IAClF,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAChD;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACjE;;;;;OAKG;IACH,MAAM,CAAC,EACH,CAAC,MAAM;QAAE,QAAQ,EAAE,OAAO,wBAAwB,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,GAC1F,SAAS,CAAC;IACd,4EAA4E;IAC5E,uBAAuB,CAAC,EAAE,OAAO,yBAAyB,EAAE,oBAAoB,CAAC,yBAAyB,CAAC,CAAC;CAC7G;AAoBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAU/F;AAkED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CA4BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAIxE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD;AAmBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAAC,MAAM,CAqiB3E"}
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/server/http-server.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AA8BlC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAWL,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAQjC,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kFAAkF;IAClF,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAChD;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACjE;;;;;OAKG;IACH,MAAM,CAAC,EACH,CAAC,MAAM;QAAE,QAAQ,EAAE,OAAO,wBAAwB,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,GAC1F,SAAS,CAAC;IACd,4EAA4E;IAC5E,uBAAuB,CAAC,EAAE,OAAO,yBAAyB,EAAE,oBAAoB,CAAC,yBAAyB,CAAC,CAAC;CAC7G;AAoBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAU/F;AAkED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CA4BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAIxE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD;AAgBD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAAC,MAAM,CAmiB3E"}
@@ -36,6 +36,12 @@ export interface KanbanSupervisorDeps {
36
36
  export interface KanbanSupervisor {
37
37
  getSnapshot(boardId: string): KanbanSupervisorSnapshot | undefined;
38
38
  auditNow(boardId?: string): Promise<KanbanSupervisorSnapshot[]>;
39
+ getStats(): {
40
+ snapshots: number;
41
+ scheduledBoards: number;
42
+ agentCooldowns: number;
43
+ runningAgents: number;
44
+ };
39
45
  dispose(): void;
40
46
  }
41
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"kanban-supervisor.d.ts","sourceRoot":"","sources":["../../src/server/kanban-supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,wBAAwB,EAK9B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EACJ;QACE,MAAM,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACtE,GACD,SAAS,CAAC;IACd,MAAM,CAAC,EACH,CAAC,CAAC,MAAM,EAAE;QACR,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;QAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAC3B,SAAS,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACjE,YAAY,CAAC,EACT,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,+BAA+B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAClF,SAAS,CAAC;IACd,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAAC;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAChE,OAAO,IAAI,IAAI,CAAC;CACjB;AAaD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAsOnF"}
1
+ {"version":3,"file":"kanban-supervisor.d.ts","sourceRoot":"","sources":["../../src/server/kanban-supervisor.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,wBAAwB,EAK9B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EACJ;QACE,MAAM,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACtE,GACD,SAAS,CAAC;IACd,MAAM,CAAC,EACH,CAAC,CAAC,MAAM,EAAE;QACR,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;QAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAC3B,SAAS,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACjE,YAAY,CAAC,EACT,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,+BAA+B,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAClF,SAAS,CAAC;IACd,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAAC;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAAC;IAChE,QAAQ,IAAI;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,OAAO,IAAI,IAAI,CAAC;CACjB;AAaD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAiRnF"}
@@ -8,7 +8,7 @@
8
8
  import { type RemoteMailbox } from '@wrongstack/core/coordination';
9
9
  import type { EventBus } from '@wrongstack/core/kernel';
10
10
  import type { WebSocket } from 'ws';
11
- import type { MailboxSendPayload } from './ws-payload-validation.js';
11
+ import type { MailboxActionPayload, MailboxSendPayload } from './ws-payload-validation.js';
12
12
  export interface MailboxHandlerDeps {
13
13
  /** Absolute project root or a live getter for hosts that can switch projects. */
14
14
  projectRoot: string | (() => string);
@@ -18,6 +18,7 @@ export interface MailboxHandlerDeps {
18
18
  events?: EventBus | undefined;
19
19
  }
20
20
  export declare function getMailboxForDeps(deps: MailboxHandlerDeps): RemoteMailbox | null;
21
+ export declare function handleMailboxAction(ws: WebSocket, deps: MailboxHandlerDeps, payload: MailboxActionPayload): Promise<void>;
21
22
  /** Persist a human-authored WebUI message in the shared project mailbox. */
22
23
  export declare function handleMailboxSend(ws: WebSocket, deps: MailboxHandlerDeps, payload: MailboxSendPayload): Promise<void>;
23
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"mailbox-handlers.d.ts","sourceRoot":"","sources":["../../src/server/mailbox-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAKL,KAAK,aAAa,EAEnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGrE,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACrC,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACpC,sEAAsE;IACtE,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC/B;AAMD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,GAAG,IAAI,CAMhF;AAID,4EAA4E;AAC5E,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA4Cf;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EACH;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACpF,SAAS,GACZ,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GAC5C,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/F;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,CAAC,EAAE;IACL,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"mailbox-handlers.d.ts","sourceRoot":"","sources":["../../src/server/mailbox-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAML,KAAK,aAAa,EAEnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAG3F,MAAM,WAAW,kBAAkB;IACjC,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACrC,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACpC,sEAAsE;IACtE,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC/B;AAMD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,GAAG,IAAI,CAMhF;AAID,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,4EAA4E;AAC5E,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA6Cf;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EACH;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACpF,SAAS,GACZ,OAAO,CAAC,IAAI,CAAC,CA+Ef;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GAC5C,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/F;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,SAAS,EACb,IAAI,EAAE,kBAAkB,EACxB,IAAI,CAAC,EAAE;IACL,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -2,6 +2,7 @@ import type { EventBus } from '@wrongstack/core/kernel';
2
2
  import type { WebSocket } from 'ws';
3
3
  import type { WSClientMessage } from './types.js';
4
4
  export interface MailboxRouteHandlers {
5
+ action: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
5
6
  send: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
6
7
  messages: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
7
8
  agents: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
@@ -1 +1 @@
1
- {"version":3,"file":"mailbox-routes.d.ts","sourceRoot":"","sources":["../../src/server/mailbox-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAUpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASlD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxE,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,mBAAmB,GAAG,oBAAoB,CAiEzF;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,SAAS,EACb,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
1
+ {"version":3,"file":"mailbox-routes.d.ts","sourceRoot":"","sources":["../../src/server/mailbox-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAWpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAUlD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtE,IAAI,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpE,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxE,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,mBAAmB,GAAG,oBAAoB,CAyEzF;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,SAAS,EACb,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,OAAO,CAAC,CA0BlB"}
@@ -0,0 +1,69 @@
1
+ export interface ProcessMemoryDiagnostic {
2
+ pid: number;
3
+ surface: string;
4
+ sessionId?: string | undefined;
5
+ ts: string;
6
+ memory: {
7
+ rss: number;
8
+ heapUsed: number;
9
+ heapTotal: number;
10
+ retainedHeapUsed?: number | undefined;
11
+ nativeResidual?: number | undefined;
12
+ external?: number | undefined;
13
+ arrayBuffers?: number | undefined;
14
+ };
15
+ signal?: string | undefined;
16
+ heapGrowthBytesPerHour?: number | undefined;
17
+ rssGrowthBytesPerHour?: number | undefined;
18
+ workload: {
19
+ messages?: number | undefined;
20
+ messageEstimatedTokens?: number | undefined;
21
+ historyEntries?: number | undefined;
22
+ historyMountedEntries?: number | undefined;
23
+ historyCachedGroups?: number | undefined;
24
+ appRenders?: number | undefined;
25
+ metricsDroppedObservations?: number | undefined;
26
+ kanbanSyncActive?: boolean | undefined;
27
+ kanbanSyncPendingBoards?: number | undefined;
28
+ kanbanSyncFullRescanPending?: boolean | undefined;
29
+ kanbanSyncRemoteApplyQueued?: boolean | undefined;
30
+ kanbanSyncPendingRemoteBoards?: number | undefined;
31
+ kanbanSyncPublishRuns?: number | undefined;
32
+ kanbanSyncCoalescedRefreshes?: number | undefined;
33
+ kanbanSupervisorSnapshots?: number | undefined;
34
+ kanbanSupervisorScheduledBoards?: number | undefined;
35
+ kanbanSupervisorAgentCooldowns?: number | undefined;
36
+ kanbanSupervisorRunningAgents?: number | undefined;
37
+ };
38
+ resources: {
39
+ active?: number | undefined;
40
+ types?: string | undefined;
41
+ };
42
+ hqQueue?: {
43
+ entries: number;
44
+ bytes: number;
45
+ maxBytes: number;
46
+ droppedFrames: number;
47
+ droppedBytes: number;
48
+ coalescedFrames: number;
49
+ coalescedBytes: number;
50
+ } | undefined;
51
+ hqSnapshot?: {
52
+ inFlight: boolean;
53
+ pending: boolean;
54
+ timerScheduled: boolean;
55
+ eventInFlight: boolean;
56
+ pendingEvents: number;
57
+ coalescedEvents: number;
58
+ droppedEvents: number;
59
+ } | undefined;
60
+ profileTopStack?: string | undefined;
61
+ profileTopStackBytes?: number | undefined;
62
+ }
63
+ /**
64
+ * Read only the tail of the process-wide heap JSONL flight recorder and
65
+ * return the newest sample for each PID. This endpoint must stay cheap even
66
+ * after weeks of uptime, so it never loads the full log into the WebUI server.
67
+ */
68
+ export declare function readRecentProcessMemoryDiagnostics(globalRoot: string | undefined, tailBytes?: number): Promise<ProcessMemoryDiagnostic[]>;
69
+ //# sourceMappingURL=memory-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-diagnostics.d.ts","sourceRoot":"","sources":["../../src/server/memory-diagnostics.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,10 @@ interface SddBoardWSMessage {
9
9
  /** Project paths the handler needs to apply lifecycle ops directly. */
10
10
  export interface SddBoardLifecycleDeps {
11
11
  projectRoot: string;
12
+ /** Explicit compatibility hook for file-codec tests and old integrations. */
13
+ controlTransport?: 'kanban' | 'legacy-file' | undefined;
14
+ /** Explicit compatibility hook for legacy snapshot-file readers. */
15
+ stateTransport?: 'kanban' | 'legacy-file' | undefined;
12
16
  paths: {
13
17
  projectSpecs: string;
14
18
  projectTaskGraphs: string;
@@ -27,19 +31,19 @@ export interface SddBoardSecurityDeps {
27
31
  * Two observe modes (one class, shared by both webui servers):
28
32
  * • in-process (CLI-hosted): subscribe the shared EventBus `sdd.board.snapshot`
29
33
  * for instant updates;
30
- * • standalone (separate process): poll the on-disk snapshot store (the CLI
31
- * run persists JSON every change).
34
+ * • standalone (separate process): poll the project-scoped Kanban workflow
35
+ * state owned by the daemon.
32
36
  *
33
- * Control is uniform + cross-process: every command is appended to the run's
34
- * `<runId>.control.jsonl`, which the CLI run drains and applies — so the run
35
- * stays the single driver and nothing races on shared state.
37
+ * Control is uniform + cross-process: every command is durably enqueued in the
38
+ * Kanban project daemon, which the CLI run drains and applies — so the run stays
39
+ * the single driver and nothing races on shared state.
36
40
  */
37
41
  export declare class SddBoardWebSocketHandler {
38
42
  private readonly store;
39
43
  private readonly clients;
40
44
  private readonly lifecycle?;
41
45
  private readonly security?;
42
- private readonly diskPollingEnabled;
46
+ private readonly standalonePollingEnabled;
43
47
  private latest;
44
48
  private poll;
45
49
  private pollInFlight;
@@ -48,7 +52,7 @@ export declare class SddBoardWebSocketHandler {
48
52
  addClient(ws: WebSocket): void;
49
53
  handleMessage(msg: SddBoardWSMessage): Promise<void>;
50
54
  /**
51
- * Apply a cleanup/rollback/destroy from disk and broadcast a structured
55
+ * Apply a cleanup/rollback/destroy from durable state and broadcast a structured
52
56
  * `sdd.board.lifecycle_result`. Refuses (no-op) while a run is still active —
53
57
  * the user must stop it first; the UI gates the buttons on `!active` and the
54
58
  * Destroy flow auto-stops then waits before sending `destroy`.
@@ -60,7 +64,9 @@ export declare class SddBoardWebSocketHandler {
60
64
  private stopPolling;
61
65
  private sendCurrent;
62
66
  private broadcastCurrent;
63
- private loadLatestFromDisk;
67
+ private loadLatestSnapshot;
68
+ private listBoardEntries;
69
+ private usesKanbanState;
64
70
  private broadcast;
65
71
  private send;
66
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sdd-board-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/sdd-board-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AASpC,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AA+BD,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAmC;IAC7D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAA6B;IAE1C,YACE,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,QAAQ,EACjB,SAAS,CAAC,EAAE,qBAAqB,EACjC,QAAQ,CAAC,EAAE,oBAAoB,EAehC;IAED,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAqB7B;IAEK,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEzD;IAED;;;;;OAKG;YACW,cAAc;IAgD5B,OAAO,IAAI,IAAI,CAId;YAIa,UAAU;IAuBxB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;YAML,WAAW;YAKX,gBAAgB;YAKhB,kBAAkB;IAKhC,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
1
+ {"version":3,"file":"sdd-board-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/sdd-board-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAerD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AASpC,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AA8BD,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS,CAAC;IACxD,oEAAoE;IACpE,cAAc,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS,CAAC;IACtD,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,aAAa,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAoC;IAC/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAmC;IAC7D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IACnD,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAA6B;IAE1C,YACE,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,QAAQ,EACjB,SAAS,CAAC,EAAE,qBAAqB,EACjC,QAAQ,CAAC,EAAE,oBAAoB,EAehC;IAED,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAqB7B;IAEK,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+EzD;IAED;;;;;OAKG;YACW,cAAc;IAwD5B,OAAO,IAAI,IAAI,CAId;YAIa,UAAU;IA4BxB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;YAML,WAAW;YAKX,gBAAgB;YAKhB,kBAAkB;YAalB,gBAAgB;IAoB9B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
@@ -1,7 +1,7 @@
1
- import type { AgentFactory, BrainArbiter } from '@wrongstack/core/coordination';
2
1
  import type { Agent } from '@wrongstack/core/agent';
3
- import { TaskTracker } from '@wrongstack/core/tasking';
2
+ import type { AgentFactory, BrainArbiter } from '@wrongstack/core/coordination';
4
3
  import type { EventBus } from '@wrongstack/core/kernel';
4
+ import { type TaskStore, TaskTracker } from '@wrongstack/core/tasking';
5
5
  import type { TaskGraph } from '@wrongstack/core/types';
6
6
  import { type SddRunHandle, SddRunRegistry } from '@wrongstack/sdd';
7
7
  import type { SddWizardDeps } from './sdd-wizard-ws-handler.js';
@@ -27,6 +27,8 @@ export interface StartSddRunFromGraphDeps {
27
27
  subagentFactory: AgentFactory;
28
28
  brain?: BrainArbiter | undefined;
29
29
  projectSddBoards: string;
30
+ /** Persist task status transitions so a replacement process can resume. */
31
+ taskStore?: TaskStore | undefined;
30
32
  registry?: SddRunRegistry | undefined;
31
33
  /** Isolated read-only LLM turn for the supervisor's auto-split. Omit → no split. */
32
34
  runIsolatedTurn?: ((prompt: string, name: string) => Promise<string>) | undefined;
@@ -61,10 +63,7 @@ export interface SddWizardWiringOptions {
61
63
  projectTaskGraphs: string;
62
64
  projectSddBoards: string;
63
65
  projectDir: string;
64
- /**
65
- * Canonical interview session file (same as wpaths.projectSddSession).
66
- * Destroy + resume share this path so a wipe actually clears the wizard.
67
- */
66
+ /** Legacy interview session file imported into project workflow state. */
68
67
  projectSddSession?: string | undefined;
69
68
  };
70
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sdd-wizard-wiring.d.ts","sourceRoot":"","sources":["../../src/server/sdd-wizard-wiring.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACb,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAEL,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD,OAAO,EAUL,KAAK,YAAY,EAEjB,cAAc,EAKf,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGjF,+EAA+E;AAC/E,MAAM,WAAW,0BAA0B;IACzC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,qFAAqF;IACrF,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,YAAY,CAAC;IAC9B,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,oFAAoF;IACpF,eAAe,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;CACnF;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,wBAAwB,EAC9B,MAAM,GAAE,0BAA+B,EACvC,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,CAAC,CAoGvB;AAED,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,KAAK,EAAE,KAAK,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,eAAe,EAAE,YAAY,CAAC;IAC9B;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,6DAA6D;IAC7D,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;QACnB;;;WAGG;QACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACxC,CAAC;CACH;AAeD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,aAAa,CAgH9E"}
1
+ {"version":3,"file":"sdd-wizard-wiring.d.ts","sourceRoot":"","sources":["../../src/server/sdd-wizard-wiring.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAoB,KAAK,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD,OAAO,EAYL,KAAK,YAAY,EACjB,cAAc,EAKf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEjF,+EAA+E;AAC/E,MAAM,WAAW,0BAA0B;IACzC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,qFAAqF;IACrF,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,YAAY,CAAC;IAC9B,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,oFAAoF;IACpF,eAAe,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;CACnF;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,wBAAwB,EAC9B,MAAM,GAAE,0BAA+B,EACvC,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,CAAC,CAqGvB;AAED,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,KAAK,EAAE,KAAK,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,QAAQ,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,eAAe,EAAE,YAAY,CAAC;IAC9B;;;;OAIG;IACH,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACjC,6DAA6D;IAC7D,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;QACnB,0EAA0E;QAC1E,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACxC,CAAC;CACH;AAeD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,aAAa,CAqH9E"}
@@ -1,5 +1,5 @@
1
- import type { WebSocket } from 'ws';
2
1
  import type { SddInterviewDriver } from '@wrongstack/sdd';
2
+ import type { WebSocket } from 'ws';
3
3
  interface WizardMessage {
4
4
  type: string;
5
5
  payload?: Record<string, unknown>;
@@ -22,11 +22,11 @@ export interface SddRunStartOpts {
22
22
  * light factory). This keeps the wizard protocol identical across both servers.
23
23
  */
24
24
  export interface SddWizardDeps {
25
- /** Build a fresh interview driver (disk spec/graph stores + session path). */
25
+ /** Build a fresh interview driver (artifact stores + durable session owner). */
26
26
  makeDriver: () => SddInterviewDriver;
27
27
  /**
28
28
  * Await before the first message / client snapshot so project context and any
29
- * disk resume finish loading. Optional for unit tests that inject a ready driver.
29
+ * durable resume finish loading. Optional for unit tests that inject a ready driver.
30
30
  */
31
31
  ensureReady?: (() => Promise<void>) | undefined;
32
32
  /**
@@ -62,7 +62,7 @@ export interface SddWizardDeps {
62
62
  * {@link SddWizardDeps}.
63
63
  *
64
64
  * Continuity: on construction (and before the first client message) the handler
65
- * rehydrates any on-disk interview session so a browser refresh or process
65
+ * rehydrates the durable interview session so a browser refresh or process
66
66
  * restart resumes mid-Q&A / mid-review without re-running the model.
67
67
  */
68
68
  export declare class SddWizardWebSocketHandler {
@@ -73,11 +73,21 @@ export declare class SddWizardWebSocketHandler {
73
73
  private lastAgentText;
74
74
  /** Guards against overlapping interview turns (one in flight at a time). */
75
75
  private busy;
76
- /** Resolves once project-context gather + disk resume finish. */
76
+ /** Set when authoritative session state could not be read during bootstrap. */
77
+ private resumeError;
78
+ /** Resolves once project-context gather + durable resume finish. */
77
79
  private readonly ready;
80
+ /**
81
+ * Single-flight slot for the resume probe. `handleMessage` awaits this
82
+ * when `resumeError` is set, so concurrent frames cannot race the retry
83
+ * — one probe either clears the gate or re-latches it, then every
84
+ * queued frame re-checks and proceeds. `null` when no probe is in
85
+ * flight (or after the probe has settled).
86
+ */
87
+ private resumeProbe;
78
88
  constructor(deps: SddWizardDeps);
79
89
  private bootstrap;
80
- /** Rehydrate a persisted interview if one exists on disk. */
90
+ /** Rehydrate a persisted interview if one exists. */
81
91
  private tryResume;
82
92
  addClient(ws: WebSocket): void;
83
93
  handleMessage(msg: WizardMessage): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"sdd-wizard-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/sdd-wizard-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,iBAAiB,CAAC;AAQhF,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAaD,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,kBAAkB,CAAC;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAChD;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD;;;OAGG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5F;;;OAGG;IACH,mBAAmB,CAAC,EAChB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GACxE,SAAS,CAAC;IACd;;;OAGG;IACH,qBAAqB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;;GASG;AACH,qBAAa,yBAAyB;IAUxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,MAAM,CAAmC;IACjD,2EAA2E;IAC3E,OAAO,CAAC,aAAa,CAAM;IAC3B,4EAA4E;IAC5E,OAAO,CAAC,IAAI,CAAS;IACrB,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,YAA6B,IAAI,EAAE,aAAa,EAE/C;YAEa,SAAS;IASvB,6DAA6D;YAC/C,SAAS;IAevB,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAc7B;IAEK,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDrD;IAID,OAAO,CAAC,YAAY;YAeN,OAAO;YAoDP,SAAS;YAiBT,SAAS;YAYT,SAAS;YAWT,UAAU;YA+BV,cAAc;YAgBd,aAAa;IA0B3B,kFAAkF;YACpE,OAAO;IAiBrB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
1
+ {"version":3,"file":"sdd-wizard-ws-handler.d.ts","sourceRoot":"","sources":["../../src/server/sdd-wizard-ws-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,iBAAiB,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAQpC,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAaD,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,UAAU,EAAE,MAAM,kBAAkB,CAAC;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAChD;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD;;;OAGG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5F;;;OAGG;IACH,mBAAmB,CAAC,EAChB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,GACxE,SAAS,CAAC;IACd;;;OAGG;IACH,qBAAqB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;;GASG;AACH,qBAAa,yBAAyB;IAoBxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAnBjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,MAAM,CAAmC;IACjD,2EAA2E;IAC3E,OAAO,CAAC,aAAa,CAAM;IAC3B,4EAA4E;IAC5E,OAAO,CAAC,IAAI,CAAS;IACrB,+EAA+E;IAC/E,OAAO,CAAC,WAAW,CAAuB;IAC1C,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC;;;;;;OAMG;IACH,OAAO,CAAC,WAAW,CAA8B;IAEjD,YAA6B,IAAI,EAAE,aAAa,EAE/C;YAEa,SAAS;IASvB,qDAAqD;YACvC,SAAS;IAsBvB,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAkB7B;IAEK,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFrD;IAID,OAAO,CAAC,YAAY;YAiBN,OAAO;YAoDP,SAAS;YAiBT,SAAS;YAYT,SAAS;YAWT,UAAU;YA+BV,cAAc;YAgBd,aAAa;IA0B3B,kFAAkF;YACpE,OAAO;IAiBrB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;CAGb"}
@@ -1 +1 @@
1
- {"version":3,"file":"start-webui.d.ts","sourceRoot":"","sources":["../../src/server/start-webui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EACL,qBAAqB,EAItB,MAAM,0BAA0B,CAAC;AAkDlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAgB,wCAAwC,CAAC,KAAK,EAAE;IAC9D,KAAK,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD,GAAG;IACF,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B,CA4DA;AAED,wBAAsB,UAAU,CAC9B,IAAI,GAAE,YAAY,GAAG;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACvB,GACL,OAAO,CAAC,IAAI,CAAC,CA80Bf;AAED;;;;;;;;;;;;;;;;GAgBG"}
1
+ {"version":3,"file":"start-webui.d.ts","sourceRoot":"","sources":["../../src/server/start-webui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EACL,qBAAqB,EAItB,MAAM,0BAA0B,CAAC;AAkDlC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAgB,wCAAwC,CAAC,KAAK,EAAE;IAC9D,KAAK,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD,GAAG;IACF,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B,CA4DA;AAED,wBAAsB,UAAU,CAC9B,IAAI,GAAE,YAAY,GAAG;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACvB,GACL,OAAO,CAAC,IAAI,CAAC,CA21Bf;AAED;;;;;;;;;;;;;;;;GAgBG"}