@wrongstack/core 0.283.0 → 0.284.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 (79) hide show
  1. package/dist/{compactor-BxddyCFu.d.ts → compactor-DQLL4HTo.d.ts} +1 -1
  2. package/dist/{config-DkCbA3Bw.d.ts → config-MRqn1V-u.d.ts} +130 -22
  3. package/dist/coordination/index.d.ts +43 -20
  4. package/dist/coordination/index.js +1744 -912
  5. package/dist/coordination/index.js.map +1 -1
  6. package/dist/{default-config-Buho8yge.d.ts → default-config-B79_gJYv.d.ts} +7 -0
  7. package/dist/defaults/index.d.ts +25 -29
  8. package/dist/defaults/index.js +2546 -7396
  9. package/dist/defaults/index.js.map +1 -1
  10. package/dist/{director-state-B_GPa78Q.d.ts → director-state-CMS_bMs4.d.ts} +2 -0
  11. package/dist/{events-KmxSmvho.d.ts → events-Bgnh43r9.d.ts} +27 -10
  12. package/dist/execution/index.d.ts +15 -16
  13. package/dist/execution/index.js +534 -140
  14. package/dist/execution/index.js.map +1 -1
  15. package/dist/execution/prompt-enhancer.d.ts +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{global-mailbox-rWVt8YlO.d.ts → global-mailbox-sZwyI6CS.d.ts} +13 -2
  18. package/dist/{goal-store-8owBXJT2.d.ts → goal-store-Datpp-ar.d.ts} +1 -1
  19. package/dist/hq/index.d.ts +35 -9
  20. package/dist/hq/index.js +80 -7
  21. package/dist/hq/index.js.map +1 -1
  22. package/dist/{index-BhCteHAF.d.ts → index--Gm41aBJ.d.ts} +26 -11
  23. package/dist/{index-BEFWNZYs.d.ts → index-CbyuOE5y.d.ts} +5 -1
  24. package/dist/index.d.ts +52 -1017
  25. package/dist/index.js +21053 -27778
  26. package/dist/index.js.map +1 -1
  27. package/dist/infrastructure/index.d.ts +9 -7
  28. package/dist/infrastructure/index.js +7 -2
  29. package/dist/infrastructure/index.js.map +1 -1
  30. package/dist/kernel/index.d.ts +11 -11
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/{mcp-servers-BUx9A_AQ.d.ts → mcp-servers-DEV4s6Ks.d.ts} +3 -3
  33. package/dist/models/index.d.ts +4 -4
  34. package/dist/models/index.js +18 -3
  35. package/dist/models/index.js.map +1 -1
  36. package/dist/{agent-subagent-runner-BsuWhB28.d.ts → multi-agent-coordinator-4RCRZKjN.d.ts} +417 -9
  37. package/dist/{null-fleet-bus-D4e9R7Qc.d.ts → null-fleet-bus-CFoNVQEK.d.ts} +53 -12
  38. package/dist/observability/index.d.ts +3 -3
  39. package/dist/{parallel-eternal-engine-iY2uxocj.d.ts → parallel-eternal-engine-HUrtePLd.d.ts} +4 -5
  40. package/dist/{permission-B6YAtNFz.d.ts → permission-ByDKXEcG.d.ts} +1 -1
  41. package/dist/{pipeline-ixSFe5jg.d.ts → pipeline-DGDyIohT.d.ts} +28 -7
  42. package/dist/{provider-model-resolve-DIxKL_T-.d.ts → provider-model-resolve-o2hHLs79.d.ts} +3 -3
  43. package/dist/{provider-runner-oQhDaZmH.d.ts → provider-runner-ChL-kVg6.d.ts} +3 -3
  44. package/dist/{retry-policy-V67lBOJz.d.ts → retry-policy-CQ7KwXJa.d.ts} +2 -2
  45. package/dist/{secret-vault-D7jeyXUQ.d.ts → secret-vault-DxohkUBc.d.ts} +3 -2
  46. package/dist/security/index.d.ts +4 -4
  47. package/dist/security/index.js +232 -2
  48. package/dist/security/index.js.map +1 -1
  49. package/dist/{selector-Bx2HgUkU.d.ts → selector-D8O6B_Rm.d.ts} +1 -1
  50. package/dist/{session-event-bridge-Bkp7ORfc.d.ts → session-event-bridge-D_z_mBwk.d.ts} +3 -3
  51. package/dist/{session-reader-B-Fi9L6I.d.ts → session-reader-7Esxrkpw.d.ts} +1 -1
  52. package/dist/storage/index.d.ts +77 -39
  53. package/dist/storage/index.js +1223 -288
  54. package/dist/storage/index.js.map +1 -1
  55. package/dist/tasking/index.d.ts +124 -0
  56. package/dist/tasking/index.js +492 -0
  57. package/dist/tasking/index.js.map +1 -0
  58. package/dist/{todos-checkpoint-BwCrj4Cb.d.ts → todos-checkpoint-FY7PjmMx.d.ts} +13 -4
  59. package/dist/{tool-LVSLiE1s.d.ts → tool-BNlnIJvo.d.ts} +216 -17
  60. package/dist/{tool-executor-kElSEgO0.d.ts → tool-executor-CckSCM5E.d.ts} +12 -15
  61. package/dist/tools/index.d.ts +2 -2
  62. package/dist/tools/index.js.map +1 -1
  63. package/dist/types/index.d.ts +94 -19
  64. package/dist/types/index.js +76 -12
  65. package/dist/types/index.js.map +1 -1
  66. package/dist/utils/index.d.ts +44 -10
  67. package/dist/utils/index.js +106 -17
  68. package/dist/utils/index.js.map +1 -1
  69. package/dist/{worktree-manager-BjyAW30D.d.ts → worktree-manager-DzwxKE35.d.ts} +1 -1
  70. package/instructions/coordination/subagent-baseline.md +5 -0
  71. package/instructions/llm/autonomy-brain.md +3 -2
  72. package/instructions/system.md +4 -0
  73. package/package.json +10 -3
  74. package/skills/mailbox-bridge/SKILL.md +33 -0
  75. package/dist/multi-agent-coordinator-CrjeTB9i.d.ts +0 -357
  76. package/dist/sdd/index.d.ts +0 -1993
  77. package/dist/sdd/index.js +0 -9500
  78. package/dist/sdd/index.js.map +0 -1
  79. package/dist/spec-TBi3Jr6T.d.ts +0 -78
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tasking/task-store.ts","../../src/types/task-graph.ts","../../src/utils/error.ts","../../src/types/errors.ts","../../src/tasking/task-tracker.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { TaskGraph } from '../types/task-graph.js';\nimport type { TaskStore } from './task-tracker.js';\n\n/**\n * In-memory task-graph store used by AutoPhase and tests.\n *\n * The store clones the graph container on read/write so callers cannot replace\n * its Maps/arrays behind the store's back. Task nodes themselves intentionally\n * remain shared: TaskTracker owns node mutation and persists after each change.\n */\nexport class DefaultTaskStore implements TaskStore {\n private readonly graphs = new Map<string, TaskGraph>();\n\n async saveGraph(graph: TaskGraph): Promise<void> {\n this.graphs.set(graph.id, this.cloneGraph(graph));\n }\n\n async loadGraph(id: string): Promise<TaskGraph | null> {\n const graph = this.graphs.get(id);\n return graph ? this.cloneGraph(graph) : null;\n }\n\n async listGraphs(): Promise<Array<{ id: string; title: string; updatedAt: number }>> {\n return Array.from(this.graphs.values()).map((graph) => ({\n id: graph.id,\n title: graph.title,\n updatedAt: graph.updatedAt,\n }));\n }\n\n async deleteGraph(id: string): Promise<void> {\n this.graphs.delete(id);\n }\n\n private cloneGraph(graph: TaskGraph): TaskGraph {\n return {\n ...graph,\n nodes: new Map(graph.nodes),\n edges: [...graph.edges],\n rootNodes: [...graph.rootNodes],\n };\n }\n}\n","export type TaskStatus = 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\nexport type TaskPriority = 'critical' | 'high' | 'medium' | 'low';\nexport type TaskType = 'feature' | 'bugfix' | 'refactor' | 'docs' | 'test' | 'chore';\n\nexport interface TaskNode {\n id: string;\n title: string;\n description: string;\n type: TaskType;\n priority: TaskPriority;\n status: TaskStatus;\n assignee?: string | undefined;\n estimateHours?: number | undefined;\n actualHours?: number | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n parentId?: string | undefined;\n children?: string[] | undefined;\n createdAt: number;\n updatedAt: number;\n startedAt?: number | undefined; // set when status → in_progress\n completedAt?: number | undefined;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TaskEdge {\n id: string;\n from: string;\n to: string;\n type: 'blocks' | 'depends_on' | 'relates_to' | 'implements';\n weight?: number | undefined;\n}\n\nexport interface TaskGraph {\n id: string;\n specId: string;\n title: string;\n nodes: Map<string, TaskNode>;\n edges: TaskEdge[];\n rootNodes: string[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface TaskDependency {\n taskId: string;\n blockedBy: string[];\n blocking: string[];\n}\n\nexport interface TaskAssignment {\n taskId: string;\n assignee: string;\n assignedAt: number;\n}\n\nexport interface TaskProgress {\n total: number;\n pending: number;\n inProgress: number;\n blocked: number;\n failed: number;\n review: number;\n completed: number;\n percentComplete: number;\n estimatedHours: number;\n actualHours: number;\n}\n\nexport interface TaskFilter {\n status?: TaskStatus[] | undefined;\n priority?: TaskPriority[] | undefined;\n type?: TaskType[] | undefined;\n assignee?: string[] | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n}\n\nexport interface TaskSort {\n field: 'priority' | 'createdAt' | 'updatedAt' | 'status';\n direction: 'asc' | 'desc';\n}\n\nexport interface CriticalPathResult {\n taskIds: string[];\n totalEstimateHours: number;\n bottleneckTasks: string[];\n}\n\nexport function computeTaskProgress(graph: TaskGraph): TaskProgress {\n let completed = 0;\n let pending = 0;\n let inProgress = 0;\n let blocked = 0;\n let failed = 0;\n let review = 0;\n let estimatedHours = 0;\n let actualHours = 0;\n for (const n of graph.nodes.values()) {\n switch (n.status) {\n case 'completed':\n completed++;\n break;\n case 'pending':\n pending++;\n break;\n case 'in_progress':\n inProgress++;\n break;\n case 'blocked':\n blocked++;\n break;\n case 'failed':\n failed++;\n break;\n case 'review':\n review++;\n break;\n }\n estimatedHours += n.estimateHours ?? 0;\n actualHours += n.actualHours ?? 0;\n }\n const total = graph.nodes.size;\n\n return {\n total,\n pending,\n inProgress,\n blocked,\n failed,\n review,\n completed,\n percentComplete: total > 0 ? Math.round((completed / total) * 100) : 0,\n estimatedHours,\n actualHours,\n };\n}\n\nexport function findCriticalPath(graph: TaskGraph): CriticalPathResult {\n const nodes = Array.from(graph.nodes.values());\n const criticalNodes = nodes.filter((n) => n.priority === 'critical');\n const bottleneckTasks = criticalNodes\n .filter((n) => graph.edges.some((e) => e.to === n.id && e.type === 'depends_on'))\n .map((n) => n.id);\n\n const totalEstimateHours = criticalNodes.reduce((sum, n) => sum + (n.estimateHours ?? 0), 0);\n\n return {\n taskIds: criticalNodes.map((n) => n.id),\n totalEstimateHours,\n bottleneckTasks,\n };\n}\n\nexport function topologicalSort(graph: TaskGraph): string[] {\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const result: string[] = [];\n\n function visit(id: string): void {\n // Cycle: callers must detect cycles up-front if they care; we just stop recursing.\n if (inStack.has(id)) return;\n if (visited.has(id)) return;\n if (!graph.nodes.has(id)) return;\n\n visited.add(id);\n inStack.add(id);\n\n for (const edge of graph.edges) {\n if (edge.from === id) visit(edge.to);\n }\n\n inStack.delete(id);\n result.push(id);\n }\n\n for (const rootId of graph.rootNodes) {\n visit(rootId);\n }\n\n return result;\n}\n\nexport type SerializableTaskGraphNodes =\n | TaskNode[]\n | Array<[string, TaskNode]>\n | Record<string, TaskNode>;\n\nexport type SerializableTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: SerializableTaskGraphNodes;\n};\n\nexport type SerializedTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: TaskNode[];\n};\n\nexport function serializeTaskGraph(graph: TaskGraph): SerializedTaskGraph {\n return {\n ...graph,\n nodes: Array.from(graph.nodes.values()),\n };\n}\n\nexport function deserializeTaskGraph(input: SerializableTaskGraph): TaskGraph {\n const nodes = new Map<string, TaskNode>();\n if (Array.isArray(input.nodes)) {\n for (const entry of input.nodes) {\n if (Array.isArray(entry)) nodes.set(entry[0], { ...entry[1], id: entry[1].id || entry[0] });\n else nodes.set(entry.id, entry);\n }\n } else {\n for (const [id, node] of Object.entries(input.nodes)) {\n nodes.set(id, { ...node, id: node.id || id });\n }\n }\n return { ...input, nodes };\n}\n","/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n","import { toErrorMessage } from '../utils/index.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// ── Error codes ──────────────────────────────────────────────────────\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` — no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// ── Base error class ─────────────────────────────────────────────────\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// ── Specific error classes ───────────────────────────────────────────\n\n/**\n * Tool execution errors — thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors — thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors — spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error — thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 → transient, 404 → not_found, 401 → permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error — thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error — thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed — e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// ── Type guards ──────────────────────────────────────────────────────\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n","import type {\n TaskFilter,\n TaskGraph,\n TaskNode,\n TaskProgress,\n TaskSort,\n} from '../types/task-graph.js';\nimport { computeTaskProgress } from '../types/task-graph.js';\nimport { ERROR_CODES, SddError } from '../types/errors.js';\nimport { toErrorMessage } from '../utils/error.js';\n\nexport interface TaskStore {\n saveGraph(graph: TaskGraph): Promise<void>;\n loadGraph(id: string): Promise<TaskGraph | null>;\n listGraphs(): Promise<{ id: string; title: string; updatedAt: number }[]>;\n deleteGraph(id: string): Promise<void>;\n}\n\nexport interface TaskTrackerOptions {\n store: TaskStore;\n /**\n * Called when an in-the-background persistence (`saveGraph`) rejects.\n * The synchronous TaskTracker methods (addNode/addEdge/updateNodeStatus)\n * fire-and-forget their writes; without this, a failing store silently\n * loses graph mutations. Defaults to a console.warn.\n */\n onPersistError?: (((err: unknown) => void)) | undefined;\n}\n\nexport interface TaskTransition {\n from: TaskNode['status'];\n to: TaskNode['status'];\n timestamp: number;\n reason?: string | undefined;\n}\n\n/** A change notification emitted to `TaskTracker.subscribe` listeners. */\nexport interface TaskTrackerChange {\n type: 'node_added' | 'node_updated' | 'status_changed' | 'node_removed';\n nodeId: string;\n /** For `node_removed` this is the node as it was just before deletion. */\n node: TaskNode;\n transition?: TaskTransition | undefined;\n}\n\nexport type TaskTrackerListener = (change: TaskTrackerChange) => void;\n\nexport class TaskTracker {\n private graph: TaskGraph | null = null;\n private transitions: TaskTransition[] = [];\n private listeners: TaskTrackerListener[] = [];\n\n constructor(private readonly opts: TaskTrackerOptions) {}\n\n /**\n * Subscribe to live task mutations (add / update / status change). Returns an\n * unsubscribe fn. This is the hook the board projector uses to stream a live\n * snapshot — the tracker was previously fire-and-forget with no observability.\n */\n subscribe(listener: TaskTrackerListener): () => void {\n this.listeners.push(listener);\n return () => {\n const i = this.listeners.indexOf(listener);\n if (i >= 0) this.listeners.splice(i, 1);\n };\n }\n\n private notifyChange(change: TaskTrackerChange): void {\n for (const l of this.listeners) {\n try {\n l(change);\n } catch {\n // A faulty listener must never break a tracker mutation.\n }\n }\n }\n\n /**\n * Attach an existing graph (used by PhaseOrchestrator to associate a tracker\n * with a phase's pre-built task graph without re-creating it).\n */\n setGraph(graph: TaskGraph): void {\n this.graph = graph;\n }\n\n async createGraph(specId: string, title: string): Promise<TaskGraph> {\n this.graph = {\n id: crypto.randomUUID(),\n specId,\n title,\n nodes: new Map(),\n edges: [],\n rootNodes: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n await this.opts.store.saveGraph(this.graph);\n return this.graph;\n }\n\n async loadGraph(id: string): Promise<TaskGraph | null> {\n this.graph = await this.opts.store.loadGraph(id);\n return this.graph;\n }\n\n addNode(node: Omit<TaskNode, 'id' | 'createdAt' | 'updatedAt'>): TaskNode {\n if (!this.graph) throw new SddError({\n message: 'No graph loaded',\n code: ERROR_CODES.SDD_INVALID_STATE,\n });\n\n const now = Date.now();\n const newNode: TaskNode = {\n ...node,\n id: crypto.randomUUID(),\n status: node.status ?? 'pending',\n createdAt: now,\n updatedAt: now,\n };\n\n this.graph.nodes.set(newNode.id, newNode);\n\n if (!node.parentId) {\n this.graph.rootNodes.push(newNode.id);\n }\n\n this.graph.updatedAt = now;\n this.persist();\n this.notifyChange({ type: 'node_added', nodeId: newNode.id, node: newNode });\n\n return newNode;\n }\n\n addEdge(from: string, to: string, type: TaskGraph['edges'][0]['type'] = 'depends_on'): void {\n if (!this.graph) throw new SddError({\n message: 'No graph loaded',\n code: ERROR_CODES.SDD_INVALID_STATE,\n });\n\n this.graph.edges.push({\n id: crypto.randomUUID(),\n from,\n to,\n type,\n });\n this.graph.updatedAt = Date.now();\n this.persist();\n }\n\n /**\n * Declare that `taskId` depends on `depId` (a `depends_on` edge `depId → taskId`),\n * guarding against self-loops, duplicates, missing nodes, and cycles. Returns\n * true if the dependency now holds (added or already present), false if it was\n * rejected (would create a cycle / unknown node). This is the safe entry point\n * for wiring agent-declared `dependsOn` references into the graph.\n */\n addDependency(depId: string, taskId: string): boolean {\n if (!this.graph) return false;\n if (depId === taskId) return false;\n if (!this.graph.nodes.has(depId) || !this.graph.nodes.has(taskId)) return false;\n // Already a blocker — idempotent success.\n if (this.getBlockers(taskId).includes(depId)) return true;\n // Cycle guard: if `depId` already (transitively) depends on `taskId`, adding\n // `taskId → depId` would close a loop. Reject rather than deadlock the run.\n if (this.dependsOnTransitively(depId, taskId, new Set())) return false;\n this.addEdge(depId, taskId, 'depends_on');\n return true;\n }\n\n /** True when `taskId` transitively depends on `targetId` (follows depends_on blockers). */\n private dependsOnTransitively(taskId: string, targetId: string, seen: Set<string>): boolean {\n if (taskId === targetId) return true;\n if (seen.has(taskId)) return false;\n seen.add(taskId);\n for (const blocker of this.getBlockers(taskId)) {\n if (this.dependsOnTransitively(blocker, targetId, seen)) return true;\n }\n return false;\n }\n\n /**\n * Merge `patch` into a node's `metadata` (used for per-task model/provider/\n * fallback assignment and the cancel marker). Persists + notifies as a node\n * update. No-op if the node is missing.\n */\n patchMetadata(id: string, patch: Record<string, unknown>): void {\n if (!this.graph) return;\n const node = this.graph.nodes.get(id);\n if (!node) return;\n node.metadata = { ...node.metadata, ...patch };\n node.updatedAt = Date.now();\n this.graph.updatedAt = node.updatedAt;\n this.persist();\n this.notifyChange({ type: 'node_updated', nodeId: id, node });\n }\n\n /**\n * Remove a node and every edge touching it. Intended for deleting a task that\n * has not started yet — callers must gate on status (do not remove a running\n * task). Dependents simply lose this blocker (re-evaluated by `canStart`).\n * Returns true if a node was removed.\n */\n removeNode(id: string): boolean {\n if (!this.graph) return false;\n const node = this.graph.nodes.get(id);\n if (!node) return false;\n this.graph.nodes.delete(id);\n this.graph.edges = this.graph.edges.filter((e) => e.from !== id && e.to !== id);\n this.graph.rootNodes = this.graph.rootNodes.filter((r) => r !== id);\n // Detach from any parent's children list.\n for (const n of this.graph.nodes.values()) {\n if (n.children?.includes(id)) n.children = n.children.filter((c) => c !== id);\n }\n this.graph.updatedAt = Date.now();\n this.persist();\n this.notifyChange({ type: 'node_removed', nodeId: id, node });\n return true;\n }\n\n updateNodeStatus(id: string, status: TaskNode['status'], reason?: string): void {\n if (!this.graph) throw new SddError({\n message: 'No graph loaded',\n code: ERROR_CODES.SDD_INVALID_STATE,\n });\n\n const node = this.graph.nodes.get(id);\n if (!node) throw new SddError({\n message: `Node ${id} not found`,\n code: ERROR_CODES.SDD_NOT_READY,\n context: { nodeId: id },\n });\n\n const from = node.status;\n const now = Date.now();\n node.status = status;\n node.updatedAt = now;\n\n if (status === 'completed') {\n node.completedAt = now;\n node.startedAt = node.startedAt ?? now; // ensure startedAt is set\n }\n if (status === 'in_progress') {\n node.startedAt = now;\n }\n\n this.transitions.push({ from, to: status, timestamp: now, reason });\n\n // Auto-unblock dependents\n if (status === 'completed') {\n this.unblockDependents(id);\n }\n\n // Auto-block blockers\n if (status === 'in_progress') {\n this.checkAndBlockIfNeeded(id);\n }\n\n this.graph.updatedAt = now;\n this.persist();\n this.notifyChange({\n type: 'status_changed',\n nodeId: id,\n node,\n transition: { from, to: status, timestamp: now, reason },\n });\n }\n\n updateNode(id: string, patch: Partial<Pick<TaskNode, 'title' | 'description' | 'priority' | 'estimateHours' | 'tags' | 'assignee'>>): void {\n if (!this.graph) throw new SddError({\n message: 'No graph loaded',\n code: ERROR_CODES.SDD_INVALID_STATE,\n });\n\n const node = this.graph.nodes.get(id);\n if (!node) throw new SddError({\n message: `Node ${id} not found`,\n code: ERROR_CODES.SDD_NOT_READY,\n context: { nodeId: id },\n });\n\n if (patch.title !== undefined) node.title = patch.title;\n if (patch.description !== undefined) node.description = patch.description;\n if (patch.priority !== undefined) node.priority = patch.priority;\n if (patch.estimateHours !== undefined) node.estimateHours = patch.estimateHours;\n if (patch.tags !== undefined) node.tags = patch.tags;\n if (patch.assignee !== undefined) node.assignee = patch.assignee;\n node.updatedAt = Date.now();\n this.graph.updatedAt = node.updatedAt;\n this.persist();\n this.notifyChange({ type: 'node_updated', nodeId: id, node });\n }\n\n getNode(id: string): TaskNode | undefined {\n return this.graph?.nodes.get(id);\n }\n\n getAllNodes(filter?: TaskFilter, sort?: TaskSort): TaskNode[] {\n if (!this.graph) return [];\n\n let nodes = Array.from(this.graph.nodes.values());\n\n if (filter) {\n nodes = nodes.filter((n) => {\n if (filter.status?.length && !filter.status.includes(n.status)) return false;\n if (filter.priority?.length && !filter.priority.includes(n.priority)) return false;\n if (filter.type?.length && !filter.type.includes(n.type)) return false;\n if (filter.assignee?.length && n.assignee && !filter.assignee.includes(n.assignee))\n return false;\n if (filter.tags?.length && n.tags && !n.tags.some((t) => filter.tags?.includes(t)))\n return false;\n if (filter.specRequirementId && n.specRequirementId !== filter.specRequirementId)\n return false;\n return true;\n });\n }\n\n if (sort) {\n nodes.sort((a, b) => {\n const cmp = compareByField(a, b, sort.field);\n return sort.direction === 'asc' ? cmp : -cmp;\n });\n }\n\n return nodes;\n }\n\n getChildren(parentId: string): TaskNode[] {\n if (!this.graph) return [];\n return Array.from(this.graph.nodes.values()).filter((n) => n.parentId === parentId);\n }\n\n getDependents(taskId: string): string[] {\n if (!this.graph) return [];\n return this.graph.edges\n .filter((e) => e.from === taskId && e.type === 'depends_on')\n .map((e) => e.to);\n }\n\n getBlockers(taskId: string): string[] {\n if (!this.graph) return [];\n return this.graph.edges\n .filter((e) => e.to === taskId && e.type === 'depends_on')\n .map((e) => e.from);\n }\n\n canStart(taskId: string): boolean {\n const blockers = this.getBlockers(taskId);\n return blockers.every((id) => {\n const node = this.graph?.nodes.get(id);\n // A task can start when all blockers are either completed or failed.\n // Failed blockers should not permanently deadlock dependent tasks.\n return node?.status === 'completed' || node?.status === 'failed';\n });\n }\n\n getProgress(): TaskProgress {\n if (!this.graph) {\n return {\n total: 0,\n pending: 0,\n inProgress: 0,\n blocked: 0,\n failed: 0,\n review: 0,\n completed: 0,\n percentComplete: 0,\n estimatedHours: 0,\n actualHours: 0,\n };\n }\n return computeTaskProgress(this.graph);\n }\n\n getTransitions(_taskId?: string): TaskTransition[] {\n return [...this.transitions];\n }\n\n private unblockDependents(completedId: string): void {\n if (!this.graph) return;\n const dependents = this.getDependents(completedId);\n for (const depId of dependents) {\n const dep = this.graph.nodes.get(depId);\n if (dep?.status === 'blocked') {\n // Check if all blockers are now completed\n const remainingBlockers = this.getBlockers(depId);\n const allUnblocked = remainingBlockers.every((id) => {\n const blocker = this.graph?.nodes.get(id);\n return blocker?.status === 'completed' || blocker?.status === 'failed';\n });\n if (allUnblocked) {\n dep.status = 'pending';\n dep.updatedAt = Date.now();\n }\n }\n }\n }\n\n private checkAndBlockIfNeeded(taskId: string): void {\n if (!this.graph) return;\n const blockers = this.getBlockers(taskId);\n const someBlocked = blockers.some((id) => {\n const blocker = this.graph?.nodes.get(id);\n // A task is only blocked by incomplete blockers that haven't failed.\n // Failed tasks should not block their dependents.\n return blocker?.status !== 'completed' && blocker?.status !== 'failed';\n });\n if (someBlocked) {\n const node = this.graph.nodes.get(taskId);\n if (node) {\n node.status = 'blocked';\n node.updatedAt = Date.now();\n }\n }\n }\n\n /**\n * Fire-and-forget persistence with attached error handler.\n * Synchronous mutators (addNode/addEdge/updateNodeStatus) use this to\n * avoid forcing an async cascade through every caller; if the store\n * is missing or throwing, the error is surfaced via onPersistError.\n */\n private persist(): void {\n if (!this.graph) return;\n this.opts.store.saveGraph(this.graph).catch((err) => {\n this.opts.onPersistError\n ? this.opts.onPersistError(err)\n : console.warn(JSON.stringify({\n level: 'warn',\n event: 'task_tracker.save_graph_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n }\n}\n\n// Sort comparison helpers\nconst PRIORITY_RANK: Record<TaskNode['priority'], number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\nconst STATUS_RANK: Record<TaskNode['status'], number> = {\n in_progress: 0,\n pending: 1,\n review: 2,\n blocked: 3,\n failed: 4,\n completed: 5,\n};\n\nfunction compareByField(a: TaskNode, b: TaskNode, field: TaskSort['field']): number {\n switch (field) {\n case 'priority': return PRIORITY_RANK[a.priority] - PRIORITY_RANK[b.priority];\n case 'status': return STATUS_RANK[a.status] - STATUS_RANK[b.status];\n case 'createdAt': return a.createdAt - b.createdAt;\n case 'updatedAt': return a.updatedAt - b.updatedAt;\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
- import { A as AttachmentStore, a as AddAttachmentInput, b as AttachmentRef, c as Attachment } from './session-reader-B-Fi9L6I.js';
2
- import { i as ContentBlock, u as ConversationState, k as SessionStore, S as SessionEvent, j as SessionMetadata, b as SessionWriter, v as ResumedSession, w as SessionData, x as SessionSummary, y as TodoItem } from './tool-LVSLiE1s.js';
3
- import { E as EventBus, M as MemoryScope, b as MemoryEntry, c as MemoryStore, d as MemoryRelevanceContext, S as ScoredEntry } from './events-KmxSmvho.js';
4
- import { C as Config, i as ConfigLoader, j as SyncConfig, k as ConfigStore } from './config-DkCbA3Bw.js';
1
+ import { A as AttachmentStore, a as AddAttachmentInput, b as AttachmentRef, c as Attachment } from './session-reader-7Esxrkpw.js';
2
+ import { i as ContentBlock, u as ConversationState, k as SessionStore, S as SessionEvent, j as SessionMetadata, b as SessionWriter, v as SessionForkOptions, F as ForkedSession, W as WorkspaceCheckpointRef, w as WorkspaceMaterializationResult, x as ResumedSession, y as SessionData, z as SessionSummary, A as TodoItem } from './tool-BNlnIJvo.js';
3
+ import { E as EventBus, M as MemoryScope, b as MemoryEntry, c as MemoryStore, d as MemoryRelevanceContext, S as ScoredEntry } from './events-Bgnh43r9.js';
4
+ import { j as Config, l as ConfigLoader, m as SyncConfig, n as ConfigStore } from './config-MRqn1V-u.js';
5
5
  import { S as SecretVault } from './secret-vault-BAKpgFw_.js';
6
6
  import { W as WstackPaths } from './wstack-paths-C3K40Qst.js';
7
7
  import { S as SecretScrubber } from './secret-scrubber-3MHDDAtm.js';
@@ -606,6 +606,11 @@ declare class SessionAnalyzer {
606
606
 
607
607
  interface SessionStoreOptions {
608
608
  dir: string;
609
+ /**
610
+ * Active project root used to revalidate persisted file-observation hashes
611
+ * during resume. Omit for stores that only inspect/archive transcripts.
612
+ */
613
+ projectRoot?: string | undefined;
609
614
  /** Optional EventBus for emitting session diagnostics. */
610
615
  events?: EventBus | undefined;
611
616
  /**
@@ -632,6 +637,8 @@ declare class DefaultSessionStore implements SessionStore {
632
637
  private readonly dir;
633
638
  private readonly events?;
634
639
  private readonly secretScrubber?;
640
+ private readonly projectRoot?;
641
+ private readonly checkpointCas?;
635
642
  private readonly isSessionInUse?;
636
643
  /**
637
644
  * In-memory cache for load() results, keyed by session ID. The cache is
@@ -671,6 +678,8 @@ declare class DefaultSessionStore implements SessionStore {
671
678
  */
672
679
  private ensureShardDir;
673
680
  create(meta: Omit<SessionMetadata, 'startedAt'>): Promise<SessionWriter>;
681
+ fork(id: string, opts?: SessionForkOptions): Promise<ForkedSession>;
682
+ materializeWorkspaceCheckpoint(checkpoint: WorkspaceCheckpointRef, targetRoot: string): Promise<WorkspaceMaterializationResult>;
674
683
  resume(id: string): Promise<ResumedSession>;
675
684
  load(id: string): Promise<SessionData>;
676
685
  /**
@@ -483,6 +483,15 @@ interface Usage {
483
483
  cacheWrite5m?: number | undefined;
484
484
  cacheWrite1h?: number | undefined;
485
485
  }
486
+ /**
487
+ * Effective prompt tokens loaded by the model for one request.
488
+ *
489
+ * Provider adapters normalize `Usage` to disjoint fields: `input` is fresh
490
+ * full-rate tokens, `cacheRead` is cached prefix tokens, and `cacheWrite` is
491
+ * the cache-written prefix segment. Context-window pressure cares about the
492
+ * full prompt the model saw, not only the bill-at-full-rate slice.
493
+ */
494
+ declare function effectiveInputTokens(usage: Usage): number;
486
495
  interface ReasoningRequest {
487
496
  enabled?: boolean | undefined;
488
497
  effort?: ReasoningEffort | undefined;
@@ -695,14 +704,47 @@ interface ProviderErrorBody {
695
704
  /** Original length of the response body in bytes, when `truncated` is true. */
696
705
  rawLength?: number | undefined;
697
706
  }
707
+ /**
708
+ * Canonical provider-failure taxonomy. Computed ONCE at error-construction
709
+ * time (`classifyProviderError`) and carried on `ProviderError.kind` so
710
+ * every downstream consumer — retry policy, cross-provider fallback,
711
+ * recovery strategies, the subagent error classifier — branches on the
712
+ * same classification instead of re-deriving it from status codes and
713
+ * message regexes. When a new provider's error format needs special
714
+ * handling, this module is the only place to teach it.
715
+ */
716
+ type ProviderErrorKind = 'rate_limit' | 'overloaded' | 'server' | 'timeout' | 'network' | 'stream_hang' | 'auth' | 'context_overflow' | 'content_filter' | 'invalid_request' | 'unknown';
717
+ /**
718
+ * Classify a provider HTTP failure into the canonical taxonomy from its
719
+ * status code plus the parsed error body (and, for message-only errors
720
+ * without a structured body, the error message itself). Pure and total —
721
+ * always returns a kind, never throws.
722
+ */
723
+ declare function classifyProviderError(status: number, body?: ProviderErrorBody, message?: string): ProviderErrorKind;
724
+ /**
725
+ * Whether a kind is worth retrying against the SAME provider/model.
726
+ * `context_overflow` is deliberately false — the request must shrink first;
727
+ * `auth`/`invalid_request`/`content_filter` won't improve on replay.
728
+ *
729
+ * Exhaustive by construction (`Record<ProviderErrorKind, …>`): adding a new
730
+ * kind refuses to compile until it is classified here. Every kind→X mapping
731
+ * in the codebase follows this drift-guard pattern — see also KIND_TO_CODE
732
+ * below, DefaultRetryPolicy.maxAttempts, fallback-model shouldFallback, and
733
+ * the coordinator's providerErrorToSubagentError.
734
+ */
735
+ declare function isRetryableKind(kind: ProviderErrorKind): boolean;
698
736
  declare class ProviderError extends WrongStackError {
699
737
  readonly status: number;
700
738
  readonly retryable: boolean;
701
739
  readonly providerId: string;
740
+ /** Canonical failure classification — see {@link ProviderErrorKind}. */
741
+ readonly kind: ProviderErrorKind;
702
742
  readonly body?: ProviderErrorBody | undefined;
703
743
  constructor(message: string, status: number, retryable: boolean, providerId: string, opts?: {
704
744
  body?: ProviderErrorBody | undefined;
705
745
  cause?: unknown | undefined;
746
+ /** Override the computed classification (rarely needed — tests, custom wires). */
747
+ kind?: ProviderErrorKind | undefined;
706
748
  });
707
749
  /**
708
750
  * Render a one-line, user-facing description. Designed for the CLI/TUI
@@ -758,6 +800,14 @@ interface SessionMetadata {
758
800
  endedAt?: string | undefined;
759
801
  /** Set when a session is closed with open tool calls — used to restore pending state on resume. */
760
802
  pendingToolUses?: string[] | undefined;
803
+ /** Parent journal metadata when this session was created by fork(). */
804
+ forkedFrom?: {
805
+ sessionId: string;
806
+ checkpointPromptIndex?: number | undefined;
807
+ checkpointHash: string;
808
+ workspace: 'shared-current';
809
+ workspaceCheckpointHash?: string | undefined;
810
+ } | undefined;
761
811
  }
762
812
  /**
763
813
  * SessionEvent — per-session persistent JSONL audit + reconstruct log.
@@ -765,8 +815,8 @@ interface SessionMetadata {
765
815
  * ## Two-Tier Model (see Config.session.auditLevel)
766
816
  *
767
817
  * **Core Reconstruct Set** (always persisted, minimal & reliable):
768
- * - `session_start`, `session_resumed`, `user_input`, `llm_response`, `tool_result`
769
- * - `checkpoint`, `file_snapshot`, `rewound`
818
+ * - `session_start`, `session_resumed`, `session_forked`, `user_input`, `llm_response`, `tool_result`
819
+ * - `context_snapshot`, `checkpoint`, `file_snapshot`, `file_observation`, `rewound`
770
820
  * - `in_flight_start` / `in_flight_end`, `session_end`
771
821
  *
772
822
  * These events are **required** for correct resume, rewind, crash recovery
@@ -784,8 +834,9 @@ interface SessionMetadata {
784
834
  * ## Guarantees
785
835
  * - All appends are best-effort. A failed write logs a throttled warning but
786
836
  * never aborts the agent loop.
787
- * - Sensitive content in `user_input` and `llm_response` is passed through
788
- * the configured SecretScrubber before being written or summarized.
837
+ * - Sensitive content in `user_input`, `llm_response`, and
838
+ * `context_snapshot` is passed through the configured SecretScrubber before
839
+ * being written or summarized.
789
840
  * - The log is append-only JSONL. Individual lines may be malformed after
790
841
  * hard crashes; `DefaultSessionStore.load()` silently skips bad lines.
791
842
  *
@@ -807,6 +858,15 @@ type SessionEvent = {
807
858
  id: string;
808
859
  model: string;
809
860
  provider: string;
861
+ } | {
862
+ type: 'session_forked';
863
+ ts: string;
864
+ parentSessionId: string;
865
+ parentCheckpointPromptIndex?: number | undefined;
866
+ parentCheckpointHash: string;
867
+ /** The child journal is isolated; filesystem state remains shared. */
868
+ workspace: 'shared-current';
869
+ workspaceCheckpointHash?: string | undefined;
810
870
  } | {
811
871
  type: 'user_input';
812
872
  ts: string;
@@ -838,6 +898,16 @@ type SessionEvent = {
838
898
  id: string;
839
899
  content: unknown;
840
900
  isError: boolean;
901
+ } | {
902
+ /**
903
+ * Exact post-rewrite conversation state. Replay replaces all messages
904
+ * reconstructed before this event, then continues applying later events.
905
+ * Currently emitted after compaction.
906
+ */
907
+ type: 'context_snapshot';
908
+ ts: string;
909
+ reason: 'compaction';
910
+ messages: Message[];
841
911
  } | {
842
912
  type: 'compaction';
843
913
  ts: string;
@@ -996,11 +1066,25 @@ type SessionEvent = {
996
1066
  ts: string;
997
1067
  promptIndex: number;
998
1068
  promptPreview: string;
1069
+ /** Content-addressed Git HEAD + dirty/untracked workspace manifest. */
1070
+ workspaceCheckpoint?: WorkspaceCheckpointRef | undefined;
999
1071
  } | {
1000
1072
  type: 'file_snapshot';
1001
1073
  ts: string;
1002
1074
  promptIndex: number;
1003
1075
  files: FileSnapshot[];
1076
+ } | {
1077
+ /**
1078
+ * Hash of a file version observed by a tool. The latest observation per
1079
+ * path is revalidated when the session resumes so stale tool context is
1080
+ * surfaced to the model before it continues.
1081
+ */
1082
+ type: 'file_observation';
1083
+ ts: string;
1084
+ path: string;
1085
+ hash: string;
1086
+ mtimeMs: number;
1087
+ source: 'user' | 'write';
1004
1088
  } | {
1005
1089
  type: 'rewound';
1006
1090
  ts: string;
@@ -1013,9 +1097,10 @@ type SessionEvent = {
1013
1097
  * Marks the start of "the process is currently working on this
1014
1098
  * point in the log". If the process exits cleanly, a matching
1015
1099
  * `in_flight_end` follows. If the process dies (crash, OOM,
1016
- * machine sleep, SIGKILL) the marker is the last event in the
1017
- * file and `SessionRecovery.detectStale` flags the session
1018
- * as resumable.
1100
+ * machine sleep, SIGKILL), ordinary request/response/tool events may
1101
+ * follow the start marker but no later lifecycle boundary closes it.
1102
+ * `SessionRecovery.detectStale` scans for that latest unmatched
1103
+ * lifecycle boundary and flags the session as resumable.
1019
1104
  *
1020
1105
  * `context` is a free-form description of the current
1021
1106
  * operation (e.g. "iteration 14 / tool: read / id: tu-7") so
@@ -1050,6 +1135,39 @@ type FileSnapshot = {
1050
1135
  before: string | null;
1051
1136
  after: string | null;
1052
1137
  };
1138
+ interface WorkspaceCheckpointRef {
1139
+ manifestHash: string;
1140
+ baseHead: string;
1141
+ entryCount: number;
1142
+ unresolvedCount: number;
1143
+ capturedAt: string;
1144
+ /** Base Git tree plus every non-ignored changed/untracked path. */
1145
+ coverage: 'git-head-plus-dirty';
1146
+ }
1147
+ interface WorkspaceMaterializationResult {
1148
+ targetRoot: string;
1149
+ writtenFiles: string[];
1150
+ deletedFiles: string[];
1151
+ errors: string[];
1152
+ }
1153
+ type ResumeFileStatus = 'modified' | 'deleted' | 'unreadable' | 'outside_project';
1154
+ interface ResumeFileValidationEntry {
1155
+ /** Absolute path recorded by the original tool observation. */
1156
+ path: string;
1157
+ /** Timestamp of the latest observation that was checked. */
1158
+ observedAt: string;
1159
+ status: ResumeFileStatus;
1160
+ expectedHash: string;
1161
+ actualHash?: string | undefined;
1162
+ detail?: string | undefined;
1163
+ }
1164
+ interface ResumeValidation {
1165
+ checkedAt: string;
1166
+ /** Number of distinct paths with a valid persisted observation. */
1167
+ checkedFileCount: number;
1168
+ /** Changed, missing, unreadable, or out-of-scope paths. */
1169
+ staleFiles: ResumeFileValidationEntry[];
1170
+ }
1053
1171
  interface SessionSummary {
1054
1172
  id: string;
1055
1173
  title: string;
@@ -1098,11 +1216,29 @@ interface SessionData {
1098
1216
  outputTokens?: number | undefined;
1099
1217
  outputLines?: number | undefined;
1100
1218
  }>;
1219
+ /** Present on resume when the store is configured with a project root. */
1220
+ resumeValidation?: ResumeValidation | undefined;
1101
1221
  }
1102
1222
  interface ResumedSession {
1103
1223
  writer: SessionWriter;
1104
1224
  data: SessionData;
1105
1225
  }
1226
+ interface SessionForkOptions {
1227
+ /** Omit to fork the latest persisted event boundary. */
1228
+ checkpointPromptIndex?: number | undefined;
1229
+ }
1230
+ interface ForkedSession {
1231
+ id: string;
1232
+ data: SessionData;
1233
+ parentSessionId: string;
1234
+ checkpointPromptIndex?: number | undefined;
1235
+ /** SHA-256 of the exact parent event prefix used to create this branch. */
1236
+ checkpointHash: string;
1237
+ /** Session history is isolated, but both branches still see the same files. */
1238
+ workspace: 'shared-current';
1239
+ /** Available for checkpoint forks captured by workspace-CAS-aware writers. */
1240
+ workspaceCheckpoint?: WorkspaceCheckpointRef | undefined;
1241
+ }
1106
1242
  interface SessionStore {
1107
1243
  create(meta: Omit<SessionMetadata, 'startedAt'>): Promise<SessionWriter>;
1108
1244
  load(id: string): Promise<SessionData>;
@@ -1113,6 +1249,14 @@ interface SessionStore {
1113
1249
  * `session_resumed` marker is appended for audit.
1114
1250
  */
1115
1251
  resume(id: string): Promise<ResumedSession>;
1252
+ /**
1253
+ * Create a non-destructive child journal from a persisted parent boundary.
1254
+ * Parent file snapshots are intentionally not inherited as rewind authority;
1255
+ * filesystem isolation is the caller's worktree/CAS responsibility.
1256
+ */
1257
+ fork?(id: string, opts?: SessionForkOptions): Promise<ForkedSession>;
1258
+ /** Apply a captured workspace manifest to an already-isolated checkout. */
1259
+ materializeWorkspaceCheckpoint?(checkpoint: WorkspaceCheckpointRef, targetRoot: string): Promise<WorkspaceMaterializationResult>;
1116
1260
  list(limit?: number): Promise<SessionSummary[]>;
1117
1261
  /**
1118
1262
  * Set or clear a user-supplied name on a session. An empty/whitespace
@@ -1200,9 +1344,19 @@ interface SessionWriter {
1200
1344
  * Flush any buffered events to disk immediately. Use after critical
1201
1345
  * events (user_input, llm_response) to ensure they survive a crash
1202
1346
  * or SIGKILL that would otherwise leave them in the in-memory buffer.
1203
- * Idempotent — safe to call even when the buffer is empty.
1347
+ * Idempotent — safe to call even when the buffer is empty. File-backed
1348
+ * writers reject on a failed disk append while retaining the batch for a
1349
+ * later retry; callers may log/degrade without losing event chronology.
1204
1350
  */
1205
1351
  flush(): Promise<void>;
1352
+ /**
1353
+ * Last-gasp synchronous drain for hard-exit paths (e.g. `process.exit`
1354
+ * after rapid Ctrl+C) where the async `flush()` cannot be awaited.
1355
+ * Writes whatever is still in the in-memory buffer with a blocking
1356
+ * append. Best-effort — errors are swallowed. Optional: in-memory
1357
+ * writers have nothing durable to drain.
1358
+ */
1359
+ flushSync?(): void;
1206
1360
  close(): Promise<void>;
1207
1361
  /**
1208
1362
  * Register a file change for later snapshotting.
@@ -1214,6 +1368,17 @@ interface SessionWriter {
1214
1368
  before: string | null;
1215
1369
  after: string | null;
1216
1370
  }): void;
1371
+ /**
1372
+ * Persist the hash of a file version observed by a tool. Optional for
1373
+ * alternate/in-memory writers; file-backed writers use it for stale-file
1374
+ * validation during resume.
1375
+ */
1376
+ recordFileObservation?(input: {
1377
+ path: string;
1378
+ hash: string;
1379
+ mtimeMs: number;
1380
+ source: 'user' | 'write';
1381
+ }): void;
1217
1382
  /**
1218
1383
  * Record a structured side effect for audit (P2 #5). Implementations
1219
1384
  * append a `side_effect` event to the session JSONL. Best-effort —
@@ -1354,22 +1519,23 @@ interface TokenCounter {
1354
1519
  /** Optional live session binding used by token.accounted events. */
1355
1520
  setSessionId?(sessionId: string | (() => string | undefined) | undefined): void;
1356
1521
  /**
1357
- * Tokens from the most recently-accounted request (input + cacheRead).
1358
- * Use this for per-request context pressure tracking (e.g. status bar
1359
- * ctx bar) — tokenCounter.total() is cumulative across all requests
1360
- * and cannot be compared meaningfully against a per-request maxContext
1361
- * ceiling.
1522
+ * Disjoint token counts from the most recently-accounted request. Sum
1523
+ * input + cacheRead + cacheWrite for per-request context pressure tracking
1524
+ * (e.g. status bar ctx bar) — tokenCounter.total() is cumulative across all
1525
+ * requests and cannot be compared meaningfully against a per-request
1526
+ * maxContext ceiling.
1362
1527
  */
1363
1528
  currentRequestTokens(): {
1364
1529
  input: number;
1365
1530
  cacheRead: number;
1531
+ cacheWrite: number;
1366
1532
  };
1367
1533
  /**
1368
1534
  * Override the last-request token snapshot. Used by slash commands like
1369
1535
  * /compact that modify ctx.messages without making an API request —
1370
1536
  * after calling this, the TUI/REPL context bar reflects the new size.
1371
1537
  */
1372
- setCurrentRequestTokens(input: number, cacheRead?: number): void;
1538
+ setCurrentRequestTokens(input: number, cacheRead?: number, cacheWrite?: number): void;
1373
1539
  total(): Usage;
1374
1540
  estimateCost(): {
1375
1541
  input: number;
@@ -1425,10 +1591,13 @@ interface ReadonlyConversationState {
1425
1591
  declare class ConversationState {
1426
1592
  private readonly ctx;
1427
1593
  private readonly listeners;
1594
+ private _revision;
1428
1595
  constructor(ctx: Context);
1429
1596
  get messages(): readonly Message[];
1430
1597
  get todos(): readonly TodoItem[];
1431
1598
  get meta(): Readonly<Record<string, unknown>>;
1599
+ /** Monotonic mutation counter for consumers that need to detect rewrites. */
1600
+ get revision(): number;
1432
1601
  /**
1433
1602
  * Cheap immutable snapshot. Useful for tests and for compaction passes
1434
1603
  * that need a stable view across an async boundary.
@@ -1609,6 +1778,18 @@ declare class Context implements RunEnv {
1609
1778
  */
1610
1779
  writtenFiles: Set<string>;
1611
1780
  fileMtimes: Map<string, number>;
1781
+ /**
1782
+ * sha-256 (hex) of file content at the last recorded read/write, when the
1783
+ * recording tool had the content in hand. Used by `edit` as the authoritative
1784
+ * staleness arbiter: mtime comparison has a 2 s tolerance window on Windows
1785
+ * (FAT/NTFS granularity) during which an external modification is invisible,
1786
+ * and conversely a bare `touch` bumps mtime without changing content. Hash
1787
+ * equality resolves both cases exactly. Entries are dropped whenever a
1788
+ * hash-less `recordRead` observes a *different* mtime (content may have
1789
+ * changed under us — fall back to the mtime heuristic rather than trust a
1790
+ * stale hash).
1791
+ */
1792
+ fileHashes: Map<string, string>;
1612
1793
  /**
1613
1794
  * Structured side-effect records accumulated during the current run
1614
1795
  * (P2 #5). Populated by `recordSideEffect()` — read by /diag for an
@@ -1707,8 +1888,16 @@ declare class Context implements RunEnv {
1707
1888
  * approved the new content (P1 #1, before-release.md).
1708
1889
  *
1709
1890
  * `fileMtimes` is updated in both cases so mtime-based staleness checks work.
1710
- */
1711
- recordRead(absPath: string, mtimeMs: number, source?: 'user' | 'write'): void;
1891
+ *
1892
+ * `contentHash` (sha-256 hex of the exact content seen) is optional so
1893
+ * existing callers keep working. When provided it is stored in `fileHashes`
1894
+ * and becomes the authoritative staleness arbiter for later edits. When
1895
+ * omitted, a previously stored hash survives only if the observed mtime is
1896
+ * unchanged — a different mtime with no fresh hash means the content may
1897
+ * have changed, so the stale hash is dropped and staleness checks fall back
1898
+ * to mtime comparison.
1899
+ */
1900
+ recordRead(absPath: string, mtimeMs: number, source?: 'user' | 'write', contentHash?: string): void;
1712
1901
  /** Clear accumulated file-read metadata after compaction or at boundaries
1713
1902
  * where stale read history could cause tools to skip legitimate re-reads.
1714
1903
  * The agent re-populates this naturally on the next file access. */
@@ -1734,6 +1923,9 @@ declare class Context implements RunEnv {
1734
1923
  /** True if `edit`/`write` wrote this file in the current session. */
1735
1924
  hasWritten(absPath: string): boolean;
1736
1925
  lastReadMtime(absPath: string): number | undefined;
1926
+ /** sha-256 (hex) of the content at the last recorded read/write, if the
1927
+ * recording tool supplied one. See `fileHashes` for drop semantics. */
1928
+ lastReadHash(absPath: string): string | undefined;
1737
1929
  /**
1738
1930
  * Change the working directory for path resolution. Resolves relative paths
1739
1931
  * against `projectRoot` and validates the result is within the project root.
@@ -1817,6 +2009,13 @@ interface Tool<I = unknown, O = unknown> {
1817
2009
  */
1818
2010
  _estDefTokens?: number | undefined;
1819
2011
  usageHint?: string | undefined;
2012
+ /** Structured guidance for choosing between similar tools. */
2013
+ selection?: {
2014
+ /** A concise boundary where this tool should not be selected. */
2015
+ doNotUseWhen: string;
2016
+ /** Tool names the model should prefer for that boundary. */
2017
+ useInstead?: readonly string[] | undefined;
2018
+ } | undefined;
1820
2019
  /** Optional category for grouping in help lists and system prompts. */
1821
2020
  category?: string | undefined;
1822
2021
  inputSchema: JSONSchema;
@@ -1988,4 +2187,4 @@ interface ToolErrorInfo {
1988
2187
  readonly detail?: string;
1989
2188
  }
1990
2189
 
1991
- export { type MessageRole as $, type ToolResultBlock as A, AgentError as B, type CacheStats as C, type CompletedWorkEvidence as D, type CompletedWorkSource as E, ConfigError as F, type ContextEvidenceState as G, type ContextFileEvidence as H, type ContextInit as I, type JSONSchema as J, type ContextIntentEvidence as K, type ContextRepeatedReadEvidence as L, type Message as M, ERROR_CODES as N, type ErrorCode as O, type Provider as P, type ErrorSeverity as Q, type ReasoningRequest as R, type SessionEvent as S, type TokenCounter as T, type Usage as U, type ErrorSubsystem as V, FetchError as W, type FileSnapshot as X, FsError as Y, type ImageBlock as Z, type JsonSchemaSpec as _, type ReasoningConfig as a, ParseError as a0, PluginError as a1, type ProviderErrorBody as a2, type ReadonlyConversationState as a3, type RequestCacheControl as a4, type ResponseFormat as a5, type RunEnv as a6, type SafetySetting as a7, SddError as a8, SessionError as a9, isSessionError as aA, isTextBlock as aB, isToolError as aC, isToolResultBlock as aD, isToolUseBlock as aE, isToolValidationError as aF, isWrongStackError as aG, toWrongStackError as aH, wrapAsState as aI, type SideEffect as aa, type SideEffectRisk as ab, type StateChange as ac, type StateChangeHandler as ad, type StopReason as ae, type StreamEvent as af, StreamHangError as ag, type ThinkingBlock as ah, type ToolCallContext as ai, ToolError as aj, type ToolErrorInfo as ak, type ToolEvidenceStatus as al, type ToolFinalEvent as am, type ToolIconId as an, type ToolStreamEvent as ao, ToolValidationError as ap, WrongStackError as aq, extractRunEnv as ar, isAgentError as as, isConfigError as at, isFetchError as au, isFsError as av, isImageBlock as aw, isParseError as ax, isPluginError as ay, isSddError as az, type SessionWriter as b, type Request as c, Context as d, type Response as e, type Permission as f, type Tool as g, ProviderError as h, type ContentBlock as i, type SessionMetadata as j, type SessionStore as k, ToolErrorCategory as l, type ToolProgressEvent as m, type RiskTier as n, type ToolOutputMetadata as o, type ReasoningEffort as p, type CacheTtl as q, type Capabilities as r, type TextBlock as s, type RunOptions as t, ConversationState as u, type ResumedSession as v, type SessionData as w, type SessionSummary as x, type TodoItem as y, type ToolUseBlock as z };
2190
+ export { type FileSnapshot as $, type TodoItem as A, type ToolUseBlock as B, type CacheStats as C, type ToolResultBlock as D, AgentError as E, type ForkedSession as F, type CompletedWorkEvidence as G, type CompletedWorkSource as H, ConfigError as I, type JSONSchema as J, type ContextEvidenceState as K, type ContextFileEvidence as L, type Message as M, type ContextInit as N, type ContextIntentEvidence as O, type Provider as P, type ContextRepeatedReadEvidence as Q, type ReasoningRequest as R, type SessionEvent as S, type TokenCounter as T, type Usage as U, ERROR_CODES as V, type WorkspaceCheckpointRef as W, type ErrorCode as X, type ErrorSeverity as Y, type ErrorSubsystem as Z, FetchError as _, type ReasoningConfig as a, FsError as a0, type ImageBlock as a1, type JsonSchemaSpec as a2, type MessageRole as a3, ParseError as a4, PluginError as a5, type ProviderErrorBody as a6, type ProviderErrorKind as a7, type ReadonlyConversationState as a8, type RequestCacheControl as a9, effectiveInputTokens as aA, extractRunEnv as aB, isAgentError as aC, isConfigError as aD, isFetchError as aE, isFsError as aF, isImageBlock as aG, isParseError as aH, isPluginError as aI, isRetryableKind as aJ, isSddError as aK, isSessionError as aL, isTextBlock as aM, isToolError as aN, isToolResultBlock as aO, isToolUseBlock as aP, isToolValidationError as aQ, isWrongStackError as aR, toWrongStackError as aS, wrapAsState as aT, type ResponseFormat as aa, type ResumeFileStatus as ab, type ResumeFileValidationEntry as ac, type ResumeValidation as ad, type RunEnv as ae, type SafetySetting as af, SddError as ag, SessionError as ah, type SideEffect as ai, type SideEffectRisk as aj, type StateChange as ak, type StateChangeHandler as al, type StopReason as am, type StreamEvent as an, StreamHangError as ao, type ThinkingBlock as ap, type ToolCallContext as aq, ToolError as ar, type ToolErrorInfo as as, type ToolEvidenceStatus as at, type ToolFinalEvent as au, type ToolIconId as av, type ToolStreamEvent as aw, ToolValidationError as ax, WrongStackError as ay, classifyProviderError as az, type SessionWriter as b, type Request as c, Context as d, type Response as e, type Permission as f, type Tool as g, ProviderError as h, type ContentBlock as i, type SessionMetadata as j, type SessionStore as k, ToolErrorCategory as l, type ToolProgressEvent as m, type RiskTier as n, type ToolOutputMetadata as o, type ReasoningEffort as p, type CacheTtl as q, type Capabilities as r, type TextBlock as s, type RunOptions as t, ConversationState as u, type SessionForkOptions as v, type WorkspaceMaterializationResult as w, type ResumedSession as x, type SessionData as y, type SessionSummary as z };
@@ -1,14 +1,14 @@
1
- import { d as Context, c as Request, P as Provider, h as ProviderError, g as Tool, z as ToolUseBlock, A as ToolResultBlock } from './tool-LVSLiE1s.js';
2
- import { E as EventBus } from './events-KmxSmvho.js';
3
- import { M as MiddlewareHandler, b as Middleware } from './pipeline-ixSFe5jg.js';
4
- import { S as SessionEventBridge } from './session-event-bridge-Bkp7ORfc.js';
5
- import { C as Compactor, a as CompactReport } from './compactor-BxddyCFu.js';
6
- import { l as ContextWindowAggressiveOn, m as ContextWindowPolicy, M as ModelsRegistry, C as Config } from './config-DkCbA3Bw.js';
7
- import { A as Agent, D as DoneCondition } from './agent-subagent-runner-BsuWhB28.js';
8
- import { R as RunResult, S as SystemPromptContributor, A as AgentPipelines, T as ToolCallPipelinePayload, U as UserInputPayload, f as ToolExecutorOptions, g as ToolExecutorStrategy, h as ToolBatchResult } from './index-BhCteHAF.js';
9
- import { D as DesignStack, a as DesignStudioState, b as DesignKitLoader, c as DesignKitManifest, d as DesignKitEntry, e as DesignKitTokens } from './parallel-eternal-engine-iY2uxocj.js';
10
- import { E as ErrorHandler, a as RecoveryDecision, R as RetryPolicy } from './retry-policy-V67lBOJz.js';
11
- import { M as MessageSelector } from './selector-Bx2HgUkU.js';
1
+ import { d as Context, c as Request, P as Provider, h as ProviderError, g as Tool, B as ToolUseBlock, D as ToolResultBlock } from './tool-BNlnIJvo.js';
2
+ import { E as EventBus } from './events-Bgnh43r9.js';
3
+ import { M as MiddlewareHandler, b as Middleware } from './pipeline-DGDyIohT.js';
4
+ import { S as SessionEventBridge } from './session-event-bridge-D_z_mBwk.js';
5
+ import { C as Compactor, a as CompactReport } from './compactor-DQLL4HTo.js';
6
+ import { o as ContextWindowAggressiveOn, p as ContextWindowPolicy, M as ModelsRegistry, j as Config } from './config-MRqn1V-u.js';
7
+ import { A as Agent, c as DoneCondition } from './multi-agent-coordinator-4RCRZKjN.js';
8
+ import { f as RunResult, S as SystemPromptContributor, A as AgentPipelines, T as ToolCallPipelinePayload, U as UserInputPayload, g as ToolExecutorOptions, h as ToolExecutorStrategy, i as ToolBatchResult } from './index--Gm41aBJ.js';
9
+ import { D as DesignStack, a as DesignStudioState, b as DesignKitLoader, c as DesignKitManifest, d as DesignKitEntry, e as DesignKitTokens } from './parallel-eternal-engine-HUrtePLd.js';
10
+ import { E as ErrorHandler, a as RecoveryDecision, R as RetryPolicy } from './retry-policy-CQ7KwXJa.js';
11
+ import { M as MessageSelector } from './selector-D8O6B_Rm.js';
12
12
  import { S as SkillLoader, a as SkillManifest, b as SkillEntry } from './skill-DHniprNl.js';
13
13
  import { W as WstackPaths } from './wstack-paths-C3K40Qst.js';
14
14
  import { P as PromptLoader, a as PromptEntry, b as PromptSearchOptions, c as PromptCategoryCount } from './prompt-DLd35n4Q.js';
@@ -492,10 +492,7 @@ declare const DEFAULT_RECOVERY_STRATEGIES: RecoveryStrategy[];
492
492
  declare class DefaultErrorHandler implements ErrorHandler {
493
493
  private readonly strategies;
494
494
  constructor(strategies?: RecoveryStrategy[]);
495
- classify(err: unknown): {
496
- kind: 'rate_limit' | 'overloaded' | 'server' | 'client' | 'network' | 'abort' | 'context_overflow' | 'unknown';
497
- retryable: boolean;
498
- };
495
+ classify(err: unknown): ReturnType<ErrorHandler['classify']>;
499
496
  recover(err: unknown, ctx: Context): Promise<RecoveryDecision | null>;
500
497
  }
501
498