hankweave 0.5.7 → 0.6.2

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/README.md +12 -11
  2. package/dist/base-process-manager.d.ts +30 -0
  3. package/dist/budget.d.ts +315 -0
  4. package/dist/checkpoint-git.d.ts +98 -0
  5. package/dist/claude-agent-sdk-manager.d.ts +144 -0
  6. package/dist/claude-log-parser.d.ts +63 -0
  7. package/dist/claude-runtime-extractor.d.ts +73 -0
  8. package/dist/codex-runtime-extractor.d.ts +107 -0
  9. package/dist/codon-runner.d.ts +278 -0
  10. package/dist/config-validation/model-validator.d.ts +16 -0
  11. package/dist/config-validation/sentinel.schema.d.ts +6967 -0
  12. package/dist/config.d.ts +40815 -0
  13. package/dist/cost-tracker.d.ts +72 -0
  14. package/dist/execution-planner.d.ts +62 -0
  15. package/dist/execution-thread.d.ts +71 -0
  16. package/dist/exports/schemas.d.ts +9 -0
  17. package/dist/exports/schemas.js +1019 -0
  18. package/dist/exports/types.d.ts +15 -0
  19. package/dist/exports/types.js +60 -0
  20. package/dist/file-resolver.d.ts +33 -0
  21. package/dist/index.js +380 -293
  22. package/dist/index.js.map +33 -29
  23. package/dist/llm/llm-provider-registry.d.ts +207 -0
  24. package/dist/llm/models-dev-schema.d.ts +679 -0
  25. package/dist/llm/provider-config.d.ts +30 -0
  26. package/dist/prompt-builder.d.ts +75 -0
  27. package/dist/prompt-frontmatter.d.ts +61 -0
  28. package/dist/replay-process-manager.d.ts +82 -0
  29. package/dist/runtime-extractor-base.d.ts +120 -0
  30. package/dist/schemas/event-schemas.d.ts +8389 -0
  31. package/dist/schemas/websocket-log-schemas.d.ts +4502 -0
  32. package/dist/shim-process-manager.d.ts +98 -0
  33. package/dist/shim-runtime-extractor.d.ts +51 -0
  34. package/dist/shims/codex/README.md +129 -0
  35. package/dist/shims/codex/THIRDPARTY.md +18 -0
  36. package/dist/shims/codex/VERSION +1 -0
  37. package/dist/shims/codex/common/package.json +24 -0
  38. package/dist/shims/codex/index.js +1154 -970
  39. package/dist/shims/codex/package.json +46 -0
  40. package/dist/shims/codex/tsup.config.ts +16 -0
  41. package/dist/shims/gemini/README.md +59 -0
  42. package/dist/shims/gemini/THIRDPARTY.md +32 -0
  43. package/dist/shims/gemini/VERSION +1 -0
  44. package/dist/shims/gemini/common/package.json +24 -0
  45. package/dist/shims/gemini/index.js +1359 -30
  46. package/dist/shims/gemini/package.json +37 -0
  47. package/dist/shims/opencode/README.md +82 -0
  48. package/dist/shims/opencode/THIRDPARTY.md +32 -0
  49. package/dist/shims/opencode/VERSION +1 -0
  50. package/dist/shims/opencode/common/package.json +24 -0
  51. package/dist/shims/opencode/index.js +1476 -0
  52. package/dist/shims/opencode/package.json +38 -0
  53. package/dist/shims/pi/README.md +87 -0
  54. package/dist/shims/pi/THIRDPARTY.md +24 -0
  55. package/dist/shims/pi/VERSION +1 -0
  56. package/dist/shims/pi/common/package.json +24 -0
  57. package/dist/shims/pi/index.js +249832 -0
  58. package/dist/shims/pi/package.json +53 -0
  59. package/dist/state-manager.d.ts +161 -0
  60. package/dist/state-transition-guards.d.ts +37 -0
  61. package/dist/telemetry/telemetry-types.d.ts +206 -0
  62. package/dist/typed-event-emitter.d.ts +57 -0
  63. package/dist/types/branded-types.d.ts +15 -0
  64. package/dist/types/budget-types.d.ts +82 -0
  65. package/dist/types/claude-session-schema.d.ts +2430 -0
  66. package/dist/types/error-types.d.ts +44 -0
  67. package/dist/types/input-ai-types.d.ts +1070 -0
  68. package/dist/types/llm-call-types.d.ts +3829 -0
  69. package/dist/types/sentinel-types.d.ts +66 -0
  70. package/dist/types/state-types.d.ts +1099 -0
  71. package/dist/types/tool-types.d.ts +86 -0
  72. package/dist/types/types.d.ts +367 -0
  73. package/dist/types/websocket-log-types.d.ts +7 -0
  74. package/dist/utils.d.ts +452 -0
  75. package/package.json +15 -2
  76. package/schemas/hank.schema.json +158 -3
  77. package/schemas/hankweave.schema.json +17 -1
  78. package/shims/codex/index.js +0 -1583
  79. package/shims/gemini/index.js +0 -31
@@ -0,0 +1,1099 @@
1
+ import type { CodonId, RunId, SessionId } from "./branded-types.js";
2
+ import type { BudgetExceededData } from "./budget-types.js";
3
+ import type { FailureReason, TokenUsage } from "./types.js";
4
+ export type { CodonId, RunId, SessionId, FailureReason, TokenUsage };
5
+ /**
6
+ * State tracking for a single sentinel within a codon.
7
+ * Mutable structure updated in-place during codon execution.
8
+ */
9
+ export interface SentinelState {
10
+ id: string;
11
+ model: string;
12
+ loadedAt: string;
13
+ unloadedAt?: string;
14
+ llmCallCount: number;
15
+ failedLLMCalls: number;
16
+ lastLlmCallAt?: string;
17
+ totalTriggers: number;
18
+ totalCost: number;
19
+ status: "active" | "unloaded";
20
+ unloadReason?: "codon-complete" | "fatal-error" | "consecutive-failures";
21
+ }
22
+ /**
23
+ * Codon execution status progression.
24
+ *
25
+ * Normal flow: preparing → starting → initializing → running → completing-sentinels → completed
26
+ * Can skip to "failed" or "skipped" from any non-terminal state.
27
+ *
28
+ * Intent: Track granular progress for better crash recovery and user feedback.
29
+ */
30
+ export type CodonStatus = "preparing" | "starting" | "initializing" | "running" | "completing-sentinels" | "completed" | "failed" | "skipped";
31
+ /**
32
+ * Base properties shared by all codon states.
33
+ * These are set when the codon starts and never change.
34
+ */
35
+ interface BaseCodon {
36
+ /**
37
+ * Which codon configuration this execution is for.
38
+ * References the codon in hank.json.
39
+ *
40
+ * Used by: UI to show codon name, state queries for codon history
41
+ */
42
+ codonId: CodonId;
43
+ /**
44
+ * When this codon execution started.
45
+ * ISO 8601 timestamp.
46
+ *
47
+ * Used by: Duration calculations, UI timeline display
48
+ */
49
+ startTime: string;
50
+ /**
51
+ * Loop context if this codon is part of a loop iteration.
52
+ * Used for resuming loops after interruption and rollback.
53
+ */
54
+ loopContext?: {
55
+ loopId: CodonId;
56
+ iteration: number;
57
+ codonIndexInLoop: number;
58
+ };
59
+ }
60
+ /**
61
+ * Codon is preparing rig (running rig setup operations).
62
+ *
63
+ * Next states:
64
+ * - starting: Rig setup succeeded
65
+ * - failed: Copy failed, command failed, etc.
66
+ * - skipped: User skipped during prep
67
+ */
68
+ export interface PreparingCodon extends BaseCodon {
69
+ status: "preparing";
70
+ }
71
+ /**
72
+ * Spawning Claude process.
73
+ *
74
+ * Next states:
75
+ * - initializing: Process started successfully
76
+ * - failed: Spawn failed (Claude not found, etc.)
77
+ * - skipped: User skipped during startup
78
+ */
79
+ export interface StartingCodon extends BaseCodon {
80
+ status: "starting";
81
+ /**
82
+ * Git commit SHA after rig setup completed.
83
+ * Only set if codon config has rigSetup operations.
84
+ *
85
+ * Used by: Rollback to know exact state after setup
86
+ * Edge case: May be undefined if no rig setup configured
87
+ */
88
+ rigSetupCheckpoint?: string;
89
+ /**
90
+ * Sentinels loaded for this codon.
91
+ * Set after sentinels load during starting state.
92
+ */
93
+ sentinels?: {
94
+ loaded: SentinelState[];
95
+ totalCost: number;
96
+ };
97
+ }
98
+ /**
99
+ * Claude process running but no session ID yet.
100
+ * Waiting for init message from Claude.
101
+ *
102
+ * Next states:
103
+ * - running: Got session ID from init message
104
+ * - completed: Process exited cleanly but init message failed validation
105
+ * - failed: Process crashed before init
106
+ * - skipped: User skipped during init
107
+ */
108
+ export interface InitializingCodon extends BaseCodon {
109
+ status: "initializing";
110
+ rigSetupCheckpoint?: string;
111
+ /**
112
+ * Claude process ID for monitoring/cleanup.
113
+ *
114
+ * Used by: Process manager to kill on skip/shutdown
115
+ * Edge case: Process might already be dead
116
+ */
117
+ claudePid: number;
118
+ /**
119
+ * Path to Claude's JSONL log file.
120
+ * Relative to .hankweave directory.
121
+ * Example: "runs/1234-abc/codon-research-claude.log"
122
+ *
123
+ * Used by: Log parser, debugging, cleanup
124
+ */
125
+ claudeLogPath: string;
126
+ /**
127
+ * Session ID from previous codon if continuing.
128
+ * Only set if codon has continueFromPrevious: true.
129
+ *
130
+ * Used by: Claude CLI --resume flag
131
+ */
132
+ previousSessionId?: SessionId;
133
+ /**
134
+ * Sentinels loaded for this codon.
135
+ * Optional field added during starting state, carried forward to initializing.
136
+ */
137
+ sentinels?: {
138
+ loaded: SentinelState[];
139
+ totalCost: number;
140
+ };
141
+ }
142
+ /**
143
+ * Claude is actively working.
144
+ * This is where most time is spent.
145
+ *
146
+ * Next states:
147
+ * - completed: Claude process exited cleanly
148
+ * - failed: Timeout, API error, crash
149
+ * - skipped: User skipped
150
+ */
151
+ export interface RunningCodon extends BaseCodon {
152
+ status: "running";
153
+ rigSetupCheckpoint?: string;
154
+ claudePid: number;
155
+ /**
156
+ * Claude's session UUID from init message.
157
+ * Required for continuation in later codons.
158
+ *
159
+ * Used by: Continue functionality, logs correlation
160
+ */
161
+ claudeSessionId: SessionId;
162
+ claudeLogPath: string;
163
+ previousSessionId?: SessionId;
164
+ /**
165
+ * Accumulated cost so far in USD.
166
+ * Updated on each token usage message.
167
+ *
168
+ * Used by: Cost display, cost limits (future)
169
+ * Edge case: May be stale if messages delayed
170
+ */
171
+ currentCost: number;
172
+ /**
173
+ * Accumulated token counts.
174
+ * Updated on each assistant message with usage.
175
+ *
176
+ * Used by: Token display, rate limit tracking
177
+ */
178
+ currentTokens: TokenUsage;
179
+ /**
180
+ * Number of assistant messages received.
181
+ * Used to determine if Claude has established a conversation.
182
+ * Initialized to 0 when codon enters running state.
183
+ *
184
+ * Used by: Continue functionality to check if session is valid
185
+ */
186
+ assistantMessageCount: number;
187
+ /**
188
+ * Number of extensions performed so far.
189
+ * 0 initially, increments with each extension.
190
+ * Used for tracking progress and enforcing maxExtensions.
191
+ */
192
+ extensionCount: number;
193
+ /**
194
+ * Sentinels loaded for this codon.
195
+ * Updated in-place during execution.
196
+ */
197
+ sentinels?: {
198
+ loaded: SentinelState[];
199
+ totalCost: number;
200
+ };
201
+ }
202
+ /**
203
+ * Codon is completing sentinel work.
204
+ * Transient state between agent completion and final state.
205
+ *
206
+ * This state indicates:
207
+ * - Main Claude agent has finished (process exited)
208
+ * - Sentinel queues are being drained
209
+ * - All pending LLM calls are completing
210
+ * - Output files are being finalized
211
+ *
212
+ * Next states:
213
+ * - completed: All work done successfully
214
+ * - failed: Checkpoint creation failed
215
+ * - skipped: Should not normally happen from this state
216
+ */
217
+ export interface CompletingSentinelsCodon extends BaseCodon {
218
+ status: "completing-sentinels";
219
+ rigSetupCheckpoint?: string;
220
+ claudePid: number;
221
+ claudeSessionId: SessionId;
222
+ claudeLogPath: string;
223
+ previousSessionId?: SessionId;
224
+ /**
225
+ * Current cost accumulated while Claude was running.
226
+ * Will become finalCost when transitioning to completed.
227
+ */
228
+ currentCost: number;
229
+ /**
230
+ * Current token counts.
231
+ * Will become finalTokens when transitioning to completed.
232
+ */
233
+ currentTokens: TokenUsage;
234
+ /**
235
+ * Number of assistant messages received.
236
+ */
237
+ assistantMessageCount: number;
238
+ /**
239
+ * Extension count from the running state.
240
+ * Preserved during sentinel completion.
241
+ */
242
+ extensionCount: number;
243
+ /**
244
+ * Sentinels being completed.
245
+ * States are updated in-place as work completes.
246
+ */
247
+ sentinels?: {
248
+ loaded: SentinelState[];
249
+ totalCost: number;
250
+ };
251
+ }
252
+ /**
253
+ * Codon completed successfully.
254
+ * This is a terminal state - no further transitions possible.
255
+ *
256
+ * Immutability: All fields are final. To retry, start a new run.
257
+ */
258
+ export interface CompletedCodon extends BaseCodon {
259
+ status: "completed";
260
+ /**
261
+ * When codon completed. Used for duration calculation.
262
+ */
263
+ endTime: string;
264
+ claudeSessionId: SessionId;
265
+ claudeLogPath: string;
266
+ previousSessionId?: SessionId;
267
+ /**
268
+ * Always 0 for successful completion.
269
+ *
270
+ * Used by: Success detection
271
+ */
272
+ exitCode: 0;
273
+ /**
274
+ * Final cost from result message or last token update.
275
+ * This is the authoritative cost for this codon.
276
+ *
277
+ * Used by: Billing, cost reports
278
+ * Edge case: May be from token updates if result message timed out
279
+ */
280
+ finalCost: number;
281
+ /**
282
+ * Final token counts.
283
+ *
284
+ * Used by: Usage analytics, model comparison
285
+ */
286
+ finalTokens: TokenUsage;
287
+ /**
288
+ * Whether we got Claude's result message before timeout.
289
+ * False means costs might be slightly off.
290
+ *
291
+ * Used by: Cost accuracy warnings
292
+ */
293
+ resultMessageReceived: boolean;
294
+ /**
295
+ * Final count of extensions performed.
296
+ * Used for reporting and debugging.
297
+ */
298
+ extensionCount: number;
299
+ rigSetupCheckpoint?: string;
300
+ /**
301
+ * Git commit after successful completion.
302
+ * Always created for successful codons.
303
+ *
304
+ * Used by: Rollback target points
305
+ */
306
+ completionCheckpoint: string;
307
+ /**
308
+ * Sentinels that executed during this codon (final state).
309
+ * Field renamed from 'loaded' to 'executed' when codon completes.
310
+ */
311
+ sentinels?: {
312
+ executed: SentinelState[];
313
+ totalCost: number;
314
+ };
315
+ /** Present when codon was force-completed due to budget limit. */
316
+ budgetExceeded?: BudgetExceededData;
317
+ }
318
+ /**
319
+ * Codon failed with error.
320
+ * Terminal state - must start new run to retry.
321
+ */
322
+ export interface FailedCodon extends BaseCodon {
323
+ status: "failed";
324
+ endTime: string;
325
+ /**
326
+ * Which state we were in when failure occurred.
327
+ * Helps understand how far we got.
328
+ *
329
+ * Used by: Error analysis, retry strategies
330
+ * Example: "preparing" means rig setup failed
331
+ * Note: Can include "completing-sentinels" if checkpoint creation fails during that codon
332
+ */
333
+ failedDuring: "preparing" | "starting" | "initializing" | "running" | "completing-sentinels";
334
+ claudePid?: number;
335
+ claudeSessionId?: SessionId;
336
+ claudeLogPath?: string;
337
+ previousSessionId?: SessionId;
338
+ /**
339
+ * Process exit code. 0 means clean exit (shouldn't happen for failed).
340
+ * Common codes:
341
+ * - 1: General error
342
+ * - -1: Killed by signal
343
+ * - 130: Ctrl+C
344
+ *
345
+ * Used by: Debugging, retry decisions
346
+ */
347
+ exitCode: number;
348
+ /**
349
+ * Structured failure information.
350
+ *
351
+ * Used by: UI error display, retry logic
352
+ */
353
+ failureReason: FailureReason;
354
+ /**
355
+ * Costs accumulated before failure.
356
+ * Will be 0 if failed before Claude started.
357
+ *
358
+ * Used by: Partial cost tracking
359
+ */
360
+ partialCost: number;
361
+ partialTokens: TokenUsage;
362
+ /**
363
+ * Number of extensions performed before failure.
364
+ * Only present if codon reached running state and attempted extensions.
365
+ */
366
+ extensionCount?: number;
367
+ rigSetupCheckpoint?: string;
368
+ /**
369
+ * Error checkpoint if created.
370
+ * On error branch in git.
371
+ *
372
+ * Edge case: Might not exist if git operations failed
373
+ */
374
+ errorCheckpoint?: string;
375
+ /**
376
+ * Sentinels that executed before failure.
377
+ */
378
+ sentinels?: {
379
+ executed: SentinelState[];
380
+ totalCost: number;
381
+ };
382
+ }
383
+ /**
384
+ * Codon was skipped by user.
385
+ * Terminal state - represents user choice to skip.
386
+ */
387
+ export interface SkippedCodon extends BaseCodon {
388
+ status: "skipped";
389
+ endTime: string;
390
+ /**
391
+ * Which state we were in when skipped.
392
+ *
393
+ * Used by: Understanding skip patterns
394
+ */
395
+ skippedDuring: "preparing" | "starting" | "initializing" | "running";
396
+ claudePid?: number;
397
+ claudeSessionId?: SessionId;
398
+ claudeLogPath?: string;
399
+ previousSessionId?: SessionId;
400
+ /**
401
+ * Partial cost accumulated before skip.
402
+ * Usually 0, but may have accumulated costs if skipped while running.
403
+ *
404
+ * Used by: Cost calculations, continuation logic
405
+ */
406
+ partialCost: number;
407
+ /**
408
+ * All zeros - no tokens used for skipped.
409
+ */
410
+ partialTokens: TokenUsage;
411
+ /**
412
+ * Number of assistant messages received before skip.
413
+ * Used to determine if session can be continued.
414
+ *
415
+ * Used by: Continue functionality
416
+ */
417
+ assistantMessageCount?: number;
418
+ rigSetupCheckpoint?: string;
419
+ /**
420
+ * Skip checkpoint if any files were being tracked.
421
+ * Even empty commits are created for skip markers.
422
+ *
423
+ * Used by: Skip history in git
424
+ */
425
+ skipCheckpoint?: string;
426
+ /**
427
+ * Sentinels that executed before skip.
428
+ */
429
+ sentinels?: {
430
+ executed: SentinelState[];
431
+ totalCost: number;
432
+ };
433
+ }
434
+ /**
435
+ * Union of all possible codon states.
436
+ * Use discriminated union on `status` field for type narrowing.
437
+ */
438
+ export type CodonExecution = PreparingCodon | StartingCodon | InitializingCodon | RunningCodon | CompletingSentinelsCodon | CompletedCodon | FailedCodon | SkippedCodon;
439
+ /**
440
+ * Represents one server lifecycle (start → shutdown).
441
+ * Runs form a tree via parent relationships for rollback/retry.
442
+ */
443
+ export interface Run {
444
+ /**
445
+ * Unique identifier for this run.
446
+ * Also used as git branch name.
447
+ *
448
+ * Used by: State lookups, folder naming, git branches
449
+ */
450
+ runId: RunId;
451
+ /**
452
+ * Absolute path where run files are stored.
453
+ * Example: "/project/.hankweave/runs/1234-abc"
454
+ *
455
+ * Used by: Log file storage, cleanup operations
456
+ * Edge case: Folder might not exist if run failed early
457
+ */
458
+ runFolder: string;
459
+ /**
460
+ * Git branch name for this run.
461
+ * Usually same as runId, but explicit for flexibility.
462
+ *
463
+ * Used by: Checkpoint system
464
+ */
465
+ gitBranch: string;
466
+ /**
467
+ * How this run started - fresh or continuation.
468
+ * Immutable after run creation.
469
+ *
470
+ * Used by: UI to show run relationships, rollback tracking
471
+ */
472
+ startingConditions: StartingConditions;
473
+ /**
474
+ * Ordered list of codon executions in this run.
475
+ * Append-only - new codons added as they start.
476
+ *
477
+ * Used by: Progress tracking, cost calculation
478
+ * Invariant: Only one codon can be non-terminal at a time
479
+ */
480
+ codons: CodonExecution[];
481
+ /**
482
+ * Overall run status.
483
+ * - running: Currently executing
484
+ * - completed: All codons done successfully
485
+ * - failed: Stopped due to codon failure
486
+ * - crashed: Detected on recovery
487
+ *
488
+ * Used by: Run selection, cleanup decisions
489
+ */
490
+ status: "running" | "completed" | "failed" | "crashed";
491
+ /**
492
+ * When server started. Never changes.
493
+ */
494
+ startTime: string;
495
+ /**
496
+ * When server stopped. Set when status becomes terminal.
497
+ */
498
+ endTime?: string;
499
+ /**
500
+ * Server process ID for lock file validation.
501
+ *
502
+ * Used by: Detecting stale lock files, crash recovery
503
+ * Edge case: Process might not exist anymore
504
+ */
505
+ serverPid: number;
506
+ }
507
+ /**
508
+ * How a run started - fresh project or continuation.
509
+ */
510
+ export type StartingConditions = {
511
+ type: "fresh";
512
+ initialCheckpointSha?: string;
513
+ } | {
514
+ type: "continuation";
515
+ source: {
516
+ /**
517
+ * Which run we're continuing from.
518
+ *
519
+ * Used by: Building run relationships tree
520
+ */
521
+ runId: RunId;
522
+ /**
523
+ * Which codon to continue after.
524
+ * null means start from beginning of that run.
525
+ *
526
+ * Example: "codon-2" means start from codon-3
527
+ * Used by: Determining next codon to execute
528
+ */
529
+ afterCodon: CodonId | null;
530
+ /**
531
+ * Git commit SHA we restored to.
532
+ * This is the exact state we're continuing from.
533
+ *
534
+ * Used by: Verifying correct restoration
535
+ */
536
+ checkpointSha: string;
537
+ };
538
+ /**
539
+ * Human-readable reason for continuation.
540
+ * Optional metadata for UI/analytics.
541
+ *
542
+ * Used by: Understanding user patterns
543
+ */
544
+ reason?: "retry" | "rollback" | "continue";
545
+ };
546
+ /**
547
+ * Root state object for Hankweave.
548
+ * Stored in .hankweave/state.json.
549
+ *
550
+ * Design decisions:
551
+ * - Single file instead of per-run for simplicity
552
+ * - No version field per user request
553
+ * - No denormalized costs - computed when needed
554
+ */
555
+ export interface HankweaveState {
556
+ /**
557
+ * All runs, newest first.
558
+ * Append-only - runs are never removed from history.
559
+ *
560
+ * Used by: History UI, cost calculations, rollback sources
561
+ * Scaling: May need pagination/archival eventually
562
+ */
563
+ runs: Run[];
564
+ /**
565
+ * Currently active run ID.
566
+ * null when server not running.
567
+ *
568
+ * Used by: State queries, preventing multiple servers
569
+ * Invariant: Only one run can be "running" status
570
+ */
571
+ currentRunId: RunId | null;
572
+ /**
573
+ * Initial checkpoint SHA from git repository initialization.
574
+ * This is the empty commit created when the checkpoint system starts.
575
+ * Represents the project's clean state before any codons have executed.
576
+ *
577
+ * Used by: Rollback to clean state, project-level rollback commands
578
+ */
579
+ initialCheckpoint?: string;
580
+ /**
581
+ * Current execution plan with all loop iterations expanded.
582
+ * This is the flattened plan that represents the actual execution sequence.
583
+ * Rebuilt on server start but persisted for crash recovery and debugging.
584
+ *
585
+ * Note: May be empty array during initialization before first run starts,
586
+ * but the field itself is always present.
587
+ *
588
+ * Used by: Codon execution, execution thread analysis, crash recovery
589
+ */
590
+ executionPlan: import("../execution-planner.js").ExecutionCodonEntry[];
591
+ }
592
+ /**
593
+ * Defines which status transitions are legal.
594
+ * This is enforced at compile time by the state manager.
595
+ *
596
+ * Key rules:
597
+ * - Can skip to "failed" or "skipped" from any non-terminal state
598
+ * - Terminal states (completed/failed/skipped) have no valid transitions
599
+ * - Must progress through states in order for normal execution
600
+ */
601
+ export declare const CodonTransitions: Record<CodonStatus, CodonStatus[]>;
602
+ /**
603
+ * All possible state changes in the system.
604
+ * These are the only way to modify state - ensures consistency.
605
+ *
606
+ * Design: Each event captures the minimal data needed for the transition.
607
+ * The state manager computes derived state (like totals) as needed.
608
+ */
609
+ export type StateTransition =
610
+ /**
611
+ * New run started (fresh or from continuation point).
612
+ * Creates new Run entry with starting codon.
613
+ *
614
+ * Triggered by: Server startup
615
+ * State changes:
616
+ * - Adds new run to runs array
617
+ * - Sets currentRunId
618
+ * - Creates git branch
619
+ */
620
+ {
621
+ type: "RunStarted";
622
+ data: {
623
+ runId: RunId;
624
+ runFolder: string;
625
+ gitBranch: string;
626
+ startingConditions: StartingConditions;
627
+ serverPid: number;
628
+ };
629
+ }
630
+ /**
631
+ * Run completed successfully (all codons done).
632
+ *
633
+ * Triggered by: Last codon completing successfully
634
+ * State changes:
635
+ * - Sets run.status = "completed"
636
+ * - Sets run.endTime
637
+ * - Clears currentRunId
638
+ */
639
+ | {
640
+ type: "RunCompleted";
641
+ data: {
642
+ runId: RunId;
643
+ };
644
+ }
645
+ /**
646
+ * Run failed (codon failed and server shutting down).
647
+ *
648
+ * Triggered by: Codon failure, fatal error
649
+ * State changes:
650
+ * - Sets run.status = "failed"
651
+ * - Sets run.endTime
652
+ * - Clears currentRunId
653
+ */
654
+ | {
655
+ type: "RunFailed";
656
+ data: {
657
+ runId: RunId;
658
+ };
659
+ }
660
+ /**
661
+ * Run crashed (detected on recovery).
662
+ *
663
+ * Triggered by: Stale lock file detection
664
+ * State changes:
665
+ * - Sets run.status = "crashed"
666
+ * - Sets run.endTime
667
+ * - Marks running codons as failed
668
+ */
669
+ | {
670
+ type: "RunCrashed";
671
+ data: {
672
+ runId: RunId;
673
+ detectedAt: string;
674
+ lastCodonStatus: CodonStatus;
675
+ };
676
+ }
677
+ /**
678
+ * New codon starting in current run.
679
+ *
680
+ * Triggered by: User command or auto-advance
681
+ * State changes:
682
+ * - Adds new PreparingCodon to run.codons
683
+ * Validation: No other codon currently running
684
+ */
685
+ | {
686
+ type: "CodonStarted";
687
+ data: {
688
+ runId: RunId;
689
+ codonId: CodonId;
690
+ loopContext?: {
691
+ loopId: CodonId;
692
+ iteration: number;
693
+ codonIndexInLoop: number;
694
+ };
695
+ };
696
+ }
697
+ /**
698
+ * Codon status changed (main state machine).
699
+ *
700
+ * Triggered by: Various codon lifecycle events
701
+ * State changes:
702
+ * - Updates codon status
703
+ * - Sets relevant fields based on transition
704
+ * Validation: Transition must be in CodonTransitions map
705
+ */
706
+ | {
707
+ type: "CodonTransitioned";
708
+ data: {
709
+ runId: RunId;
710
+ codonId: CodonId;
711
+ from: CodonStatus;
712
+ to: CodonStatus;
713
+ metadata?: {
714
+ claudePid?: number;
715
+ claudeLogPath?: string;
716
+ previousSessionId?: SessionId;
717
+ claudeSessionId?: SessionId;
718
+ exitCode?: number;
719
+ failureReason?: FailureReason;
720
+ failedDuring?: CodonStatus;
721
+ skippedDuring?: CodonStatus;
722
+ resultMessageReceived?: boolean;
723
+ sentinelCount?: number;
724
+ sentinelIds?: string[];
725
+ checkpointSha?: string;
726
+ checkpointBranch?: string;
727
+ contextExceeded?: boolean;
728
+ extensionCount?: number;
729
+ budgetExceeded?: BudgetExceededData;
730
+ };
731
+ };
732
+ }
733
+ /**
734
+ * Token usage update from Claude.
735
+ * Can happen frequently during execution.
736
+ *
737
+ * Triggered by: Assistant messages with usage
738
+ * State changes:
739
+ * - Updates currentCost/currentTokens (if running)
740
+ * - Updates finalCost/finalTokens (if completing)
741
+ */
742
+ | {
743
+ type: "CostsUpdated";
744
+ data: {
745
+ runId: RunId;
746
+ codonId: CodonId;
747
+ cost: number;
748
+ tokens: TokenUsage;
749
+ };
750
+ }
751
+ /**
752
+ * Incremental token usage update from Claude.
753
+ * More resilient to race conditions than CostsUpdated.
754
+ *
755
+ * Triggered by: Assistant messages with usage (incremental approach)
756
+ * State changes:
757
+ * - Adds costDelta to currentCost (if running)
758
+ * - Adds tokensDelta to currentTokens (if running)
759
+ */
760
+ | {
761
+ type: "CostsIncremented";
762
+ data: {
763
+ runId: RunId;
764
+ codonId: CodonId;
765
+ costDelta: number;
766
+ tokensDelta: TokenUsage;
767
+ };
768
+ }
769
+ /**
770
+ * Assistant message count update.
771
+ * Incremented when Claude sends a message.
772
+ *
773
+ * Triggered by: Assistant messages in Claude logs
774
+ * State changes:
775
+ * - Increments assistantMessageCount (if running/completing)
776
+ */
777
+ | {
778
+ type: "AssistantMessageCountUpdated";
779
+ data: {
780
+ runId: RunId;
781
+ codonId: CodonId;
782
+ newCount: number;
783
+ };
784
+ }
785
+ /**
786
+ * Extension count update.
787
+ * Incremented when a codon extends.
788
+ *
789
+ * Triggered by: Extension trigger in hankweave-runtime
790
+ * State changes:
791
+ * - Updates extensionCount on RunningCodon
792
+ */
793
+ | {
794
+ type: "ExtensionCountUpdated";
795
+ data: {
796
+ runId: RunId;
797
+ codonId: CodonId;
798
+ extensionCount: number;
799
+ };
800
+ }
801
+ /**
802
+ * Git checkpoint created.
803
+ *
804
+ * Triggered by: Rig setup, completion, error, skip
805
+ * State changes:
806
+ * - Sets relevant checkpoint field in codon
807
+ */
808
+ | {
809
+ type: "CheckpointCreated";
810
+ data: {
811
+ runId: RunId;
812
+ codonId: CodonId;
813
+ checkpointType: "rig-setup" | "completed" | "error" | "skipped";
814
+ sha: string;
815
+ branch: string;
816
+ };
817
+ }
818
+ /**
819
+ * Initial checkpoint set for the project.
820
+ *
821
+ * Triggered by: Git repository initialization
822
+ * State changes:
823
+ * - Sets state.initialCheckpoint
824
+ */
825
+ | {
826
+ type: "InitialCheckpointSet";
827
+ data: {
828
+ sha: string;
829
+ };
830
+ }
831
+ /**
832
+ * Codon final cost set from Claude's result message.
833
+ * This ensures the authoritative cost from Claude's result message
834
+ * is stored before the codon completes.
835
+ *
836
+ * Triggered by: Claude result message with final cost
837
+ * State changes:
838
+ * - Updates currentCost and currentTokens in running codon
839
+ */
840
+ | {
841
+ type: "CodonFinalCostSet";
842
+ data: {
843
+ runId: RunId;
844
+ codonId: CodonId;
845
+ finalCost: number;
846
+ finalTokens: TokenUsage;
847
+ };
848
+ }
849
+ /**
850
+ * Sentinel states updated/initialized for a codon.
851
+ * Sets the initial sentinel state when sentinels load,
852
+ * or updates states before codon completion.
853
+ *
854
+ * Triggered by: After sentinels load, before completing-sentinels transition
855
+ * State changes:
856
+ * - Sets/updates RunningCodon.sentinels field
857
+ * - Updates CompletingSentinelsCodon.sentinels field
858
+ */
859
+ | {
860
+ type: "SentinelStatesUpdated";
861
+ data: {
862
+ runId: RunId;
863
+ codonId: CodonId;
864
+ sentinelStates: SentinelState[];
865
+ totalCost: number;
866
+ };
867
+ };
868
+ /**
869
+ * Extract the type field from StateTransition for use in schemas.
870
+ * This ensures type safety when creating state transition events.
871
+ */
872
+ export type StateTransitionType = StateTransition["type"];
873
+ /**
874
+ * Central state management for Hankweave.
875
+ * All state modifications go through this interface.
876
+ *
877
+ * Implementation notes:
878
+ * - Single instance per server
879
+ * - Persists to disk after each transition
880
+ * - Validates all transitions before applying
881
+ * - Provides type-safe queries
882
+ */
883
+ export interface StateManager {
884
+ /**
885
+ * Load state from disk or create new.
886
+ * Called once on server startup.
887
+ *
888
+ * Recovery logic:
889
+ * 1. Try to load state.json
890
+ * 2. If corrupted, try state.json.bak
891
+ * 3. If both fail, start fresh
892
+ * 4. Detect any crashed runs
893
+ */
894
+ initialize(): Promise<void>;
895
+ /**
896
+ * Get current state snapshot (immutable).
897
+ * This is the primary way to read state.
898
+ *
899
+ * Usage: const { runs, currentRunId } = stateManager.getState();
900
+ */
901
+ getState(): Readonly<HankweaveState>;
902
+ /**
903
+ * Apply a state transition.
904
+ * This is the ONLY way to modify state.
905
+ *
906
+ * Process:
907
+ * 1. Validate transition is legal
908
+ * 2. Apply transition (pure function)
909
+ * 3. Persist to disk atomically
910
+ * 4. Emit change event
911
+ *
912
+ * @throws {InvalidTransitionError} if transition is invalid
913
+ * @throws {PersistenceError} if save fails
914
+ */
915
+ transition(event: StateTransition): void;
916
+ /**
917
+ * Get the currently active run.
918
+ * @returns null if no server running
919
+ */
920
+ getCurrentRun(): Run | null;
921
+ /**
922
+ * Get the currently executing codon.
923
+ * @returns null if between codons or no run active
924
+ */
925
+ getCurrentlyRunningCodon(): CodonExecution | null;
926
+ /**
927
+ * Get specific codon in current run.
928
+ * Useful for checking if codon already executed.
929
+ *
930
+ * @param codonId - Codon to look for
931
+ * @returns null if codon not found or no current run
932
+ */
933
+ getCodonInCurrentRun(codonId: CodonId): CodonExecution | null;
934
+ /**
935
+ * Determine which codon should execute next.
936
+ * Handles both fresh runs and continuations.
937
+ *
938
+ * Logic:
939
+ * - For fresh runs: First codon in config
940
+ * - For continuations: Codon after the continuation point
941
+ * - If all codons complete: null
942
+ *
943
+ * @returns null if all codons completed
944
+ */
945
+ getNextCodonToExecute(): Promise<CodonId | null>;
946
+ /**
947
+ * Get any run by ID.
948
+ * Useful for rollback sources, history display.
949
+ *
950
+ * @returns null if run not found
951
+ */
952
+ getRun(runId: RunId): Run | null;
953
+ /**
954
+ * Calculate total cost of current run.
955
+ * Includes all codons (successful, failed, partial).
956
+ *
957
+ * @returns 0 if no current run
958
+ */
959
+ getCurrentRunCost(): number;
960
+ /**
961
+ * Calculate total cost across all runs.
962
+ * This is the "all time" cost.
963
+ *
964
+ * Note: Computed on demand, not stored
965
+ */
966
+ getTotalCost(): number;
967
+ /**
968
+ * Calculate cost from a specific run onwards.
969
+ * Useful for "cost since last success" queries.
970
+ *
971
+ * @param runId - Starting run (inclusive)
972
+ * @returns Total cost from that run to now
973
+ */
974
+ getCostSince(runId: RunId): number;
975
+ /**
976
+ * Check if we can continue from a specific point.
977
+ * Validates that the source run and codon exist.
978
+ *
979
+ * @param runId - Run to continue from
980
+ * @param afterCodon - Codon to continue after (null = from beginning)
981
+ * @returns true if valid continuation point
982
+ */
983
+ canContinueFrom(runId: RunId, afterCodon: CodonId | null): boolean;
984
+ /**
985
+ * Get the checkpoint SHA for a continuation point.
986
+ * This is what git should restore to.
987
+ *
988
+ * @returns null if invalid continuation point
989
+ */
990
+ getCheckpointForContinuation(runId: RunId, afterCodon: CodonId | null): string | null;
991
+ /**
992
+ * Force save current state to disk.
993
+ * Normally automatic after transitions.
994
+ *
995
+ * Process:
996
+ * 1. Copy current to .bak
997
+ * 2. Write to .tmp
998
+ * 3. Atomic rename to state.json
999
+ *
1000
+ * Note: fs.renameSync is atomic on POSIX systems
1001
+ */
1002
+ save(): Promise<void>;
1003
+ /**
1004
+ * Validate state file integrity.
1005
+ * Checks for corruption, invalid references, etc.
1006
+ *
1007
+ * @returns Validation results with any issues found
1008
+ */
1009
+ validate(state: unknown): StateValidation;
1010
+ /**
1011
+ * Detect and mark crashed runs on startup.
1012
+ * Finds runs with status="running" but server not running.
1013
+ *
1014
+ * Side effects:
1015
+ * - Transitions crashed runs to "crashed" status
1016
+ * - Marks running codons as failed
1017
+ *
1018
+ * Recovery strategy:
1019
+ * - Check for orphaned run folders not in state
1020
+ * - Validate PIDs in lock files
1021
+ * - Handle partial state writes (check for .tmp files)
1022
+ */
1023
+ detectCrashedRuns(): Promise<void>;
1024
+ /**
1025
+ * Attempt recovery from corrupted state.
1026
+ * Last resort if both state.json and backup fail.
1027
+ *
1028
+ * Options:
1029
+ * - Start fresh (data loss)
1030
+ * - Rebuild from Claude logs (deprecated)
1031
+ *
1032
+ * @returns Recovery results
1033
+ */
1034
+ recover(): Promise<RecoveryResult>;
1035
+ /**
1036
+ * Wait for all pending transitions during shutdown
1037
+ */
1038
+ waitForPendingTransitions(): Promise<void>;
1039
+ }
1040
+ export interface StateValidation {
1041
+ valid: boolean;
1042
+ errors: ValidationError[];
1043
+ warnings: ValidationWarning[];
1044
+ }
1045
+ export interface ValidationError {
1046
+ type: "missing_run" | "invalid_codon" | "corrupted_data";
1047
+ message: string;
1048
+ context?: unknown;
1049
+ }
1050
+ export interface ValidationWarning {
1051
+ type: "orphaned_folder" | "missing_checkpoint" | "cost_mismatch";
1052
+ message: string;
1053
+ }
1054
+ export interface RecoveryResult {
1055
+ success: boolean;
1056
+ method: "backup" | "fresh" | "logs";
1057
+ dataLoss: boolean;
1058
+ message: string;
1059
+ }
1060
+ /**
1061
+ * Information about the latest codon execution.
1062
+ * Used to determine the current position in the workflow.
1063
+ */
1064
+ export interface LatestCodonInfo {
1065
+ /**
1066
+ * The codon execution object containing all codon details
1067
+ */
1068
+ codon: CodonExecution;
1069
+ /**
1070
+ * Which run this codon belongs to
1071
+ */
1072
+ runId: RunId;
1073
+ /**
1074
+ * Current status of the codon (convenience field)
1075
+ */
1076
+ status: CodonStatus;
1077
+ /**
1078
+ * The next codon that should be executed (if any).
1079
+ * null means all codons are complete or a new run is needed.
1080
+ */
1081
+ nextCodonId: CodonId | null;
1082
+ /**
1083
+ * Whether to continue execution in the current run.
1084
+ * false means a new run needs to be started (e.g., after rollback).
1085
+ */
1086
+ continueInCurrentRun: boolean;
1087
+ }
1088
+ /**
1089
+ * Check if a codon status is terminal (no further transitions possible)
1090
+ */
1091
+ export declare function isTerminalCodonStatus(status: CodonStatus): boolean;
1092
+ /**
1093
+ * Calculate codon cost based on its status
1094
+ */
1095
+ export declare function getCodonCost(codon: CodonExecution): number;
1096
+ /**
1097
+ * Calculate codon tokens based on its status
1098
+ */
1099
+ export declare function getCodonTokens(codon: CodonExecution): TokenUsage;