@wrongstack/core 0.5.0 → 0.5.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 (44) hide show
  1. package/dist/{agent-bridge-BkjOkSkD.d.ts → agent-bridge-EiUFe3if.d.ts} +1 -1
  2. package/dist/{compactor-CTHjZAwf.d.ts → compactor-BP4xhKVi.d.ts} +1 -1
  3. package/dist/{config-DO2eCKgq.d.ts → config-BOD_HQBw.d.ts} +1 -1
  4. package/dist/{context-P207fTpo.d.ts → context-PH4DvBZV.d.ts} +49 -1
  5. package/dist/coordination/index.d.ts +9 -9
  6. package/dist/coordination/index.js +93 -2
  7. package/dist/coordination/index.js.map +1 -1
  8. package/dist/defaults/index.d.ts +18 -18
  9. package/dist/defaults/index.js +93 -2
  10. package/dist/defaults/index.js.map +1 -1
  11. package/dist/director-state-CVzkjKRZ.d.ts +539 -0
  12. package/dist/{events-DYAbU84e.d.ts → events-oxn-Wkub.d.ts} +18 -1
  13. package/dist/execution/index.d.ts +11 -11
  14. package/dist/extension/index.d.ts +6 -6
  15. package/dist/{index-BHL8QDCL.d.ts → index-CcbWbcpy.d.ts} +5 -5
  16. package/dist/{index-BNzUUDVR.d.ts → index-a12jc7-r.d.ts} +5 -5
  17. package/dist/index.d.ts +27 -25
  18. package/dist/index.js +266 -23
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +6 -6
  21. package/dist/kernel/index.d.ts +9 -9
  22. package/dist/kernel/index.js.map +1 -1
  23. package/dist/{mcp-servers-CLkhKdnF.d.ts → mcp-servers-uPmBxZ1B.d.ts} +3 -3
  24. package/dist/models/index.d.ts +2 -2
  25. package/dist/{multi-agent-B1Nn9eC0.d.ts → multi-agent-D6S4Z7H8.d.ts} +2 -2
  26. package/dist/observability/index.d.ts +2 -2
  27. package/dist/{path-resolver-mPccVA0l.d.ts → path-resolver-CprD5DhS.d.ts} +2 -2
  28. package/dist/{provider-runner-D7lHu07L.d.ts → provider-runner-DGisz_lG.d.ts} +3 -3
  29. package/dist/{retry-policy-CnYVKGPv.d.ts → retry-policy-DUJ8-Qc_.d.ts} +1 -1
  30. package/dist/sdd/index.d.ts +3 -3
  31. package/dist/{secret-scrubber-Buo9zLGs.d.ts → secret-scrubber-CB11A2P7.d.ts} +1 -1
  32. package/dist/{secret-scrubber-BSgec8CU.d.ts → secret-scrubber-EqFa0SyI.d.ts} +1 -1
  33. package/dist/security/index.d.ts +3 -3
  34. package/dist/{selector-B-CGOshv.d.ts → selector-yqyxt-Ii.d.ts} +1 -1
  35. package/dist/{session-reader-DmOEmSkq.d.ts → session-reader-1tOyoY1s.d.ts} +1 -1
  36. package/dist/session-rewinder-C9HnMkhP.d.ts +23 -0
  37. package/dist/storage/index.d.ts +21 -534
  38. package/dist/storage/index.js +246 -3
  39. package/dist/storage/index.js.map +1 -1
  40. package/dist/{system-prompt-CzY1zrbC.d.ts → system-prompt-BJlzKGO6.d.ts} +1 -1
  41. package/dist/{tool-executor-CYe5cp5U.d.ts → tool-executor-B6kRcWeF.d.ts} +4 -4
  42. package/dist/types/index.d.ts +16 -15
  43. package/dist/utils/index.d.ts +1 -1
  44. package/package.json +1 -1
@@ -0,0 +1,539 @@
1
+ import { E as EventBus } from './events-oxn-Wkub.js';
2
+ import { o as SessionStore, n as SessionMetadata, q as SessionWriter, k as ResumedSession, S as SessionData, p as SessionSummary, b as ContentBlock, m as SessionEvent, ab as TodoItem, a5 as ConversationState } from './context-PH4DvBZV.js';
3
+ import { e as AttachmentStore, A as AddAttachmentInput, d as AttachmentRef, a as Attachment } from './session-reader-1tOyoY1s.js';
4
+ import { b as MemoryStore, a as MemoryScope } from './memory-CEXuo7sz.js';
5
+ import { a as WstackPaths } from './wstack-paths-BGu2INTm.js';
6
+ import { c as ConfigStore, a as Config, b as ConfigLoader } from './config-BOD_HQBw.js';
7
+ import { S as SecretVault } from './secret-vault-DoISxaKO.js';
8
+
9
+ interface SessionStoreOptions {
10
+ dir: string;
11
+ /** Optional EventBus for emitting session diagnostics. */
12
+ events?: EventBus;
13
+ }
14
+ declare class DefaultSessionStore implements SessionStore {
15
+ private readonly dir;
16
+ private readonly events?;
17
+ constructor(opts: SessionStoreOptions);
18
+ create(meta: Omit<SessionMetadata, 'startedAt'>): Promise<SessionWriter>;
19
+ resume(id: string): Promise<ResumedSession>;
20
+ load(id: string): Promise<SessionData>;
21
+ list(limit?: number): Promise<SessionSummary[]>;
22
+ private summaryFor;
23
+ delete(id: string): Promise<void>;
24
+ private summarize;
25
+ private metaFromEvents;
26
+ private replay;
27
+ }
28
+
29
+ /**
30
+ * The persisted form of a single queued user message. The TUI's
31
+ * in-memory QueueItem has a render id; that's pure UI bookkeeping, so
32
+ * we drop it when serializing — fresh ids are assigned on rehydrate.
33
+ */
34
+ interface PersistedQueueItem {
35
+ displayText: string;
36
+ blocks: ContentBlock[];
37
+ }
38
+ /**
39
+ * Side-file storage for a session's pending input queue. Lives at
40
+ * `<sessionDir>/queue.json` next to the attachment spool. Reads are
41
+ * tolerant (missing/malformed file → empty array); writes are atomic
42
+ * (tmp + rename) so a crash mid-write can never leave a partial file
43
+ * the next launch would choke on.
44
+ *
45
+ * The contract is "snapshot replacement": every mutation hands the
46
+ * full queue and we rewrite the file. The queue is small (rarely more
47
+ * than a handful of messages), so this is cheaper than delta logging
48
+ * and avoids the replay complexity.
49
+ */
50
+ declare class QueueStore {
51
+ private readonly file;
52
+ constructor(opts: {
53
+ dir: string;
54
+ });
55
+ write(items: PersistedQueueItem[]): Promise<void>;
56
+ read(): Promise<PersistedQueueItem[]>;
57
+ clear(): Promise<void>;
58
+ }
59
+
60
+ interface AttachmentStoreOptions {
61
+ /**
62
+ * Directory for spooling payloads larger than `spoolThresholdBytes`.
63
+ * When omitted, all payloads stay in memory.
64
+ */
65
+ spoolDir?: string;
66
+ spoolThresholdBytes?: number;
67
+ }
68
+ /**
69
+ * In-memory attachment store with optional disk spool. Placeholder syntax
70
+ * is `[<kind> #<seq>]` where kind is `pasted` / `image` / `file`. Unknown
71
+ * placeholders are passed through as-is so users can write that literal
72
+ * text without losing it.
73
+ */
74
+ declare class DefaultAttachmentStore implements AttachmentStore {
75
+ private readonly items;
76
+ private readonly refs;
77
+ private nextSeq;
78
+ private readonly spoolDir;
79
+ private readonly spoolThreshold;
80
+ constructor(opts?: AttachmentStoreOptions);
81
+ add(input: AddAttachmentInput): Promise<AttachmentRef>;
82
+ get(id: string): Promise<Attachment | undefined>;
83
+ list(): AttachmentRef[];
84
+ expand(text: string): Promise<ContentBlock[]>;
85
+ clear(): Promise<void>;
86
+ private toBlock;
87
+ }
88
+
89
+ interface MemoryStoreOptions {
90
+ paths: WstackPaths;
91
+ }
92
+ /**
93
+ * Three scopes:
94
+ * project-agents → <project>/.wrongstack/AGENTS.md (committed)
95
+ * project-memory → ~/.wrongstack/projects/<hash>/memory.md (per-project agent notes)
96
+ * user-memory → ~/.wrongstack/memory.md (global personal memory)
97
+ */
98
+ declare class DefaultMemoryStore implements MemoryStore {
99
+ private readonly files;
100
+ /**
101
+ * Per-scope serialization queue. `remember` / `forget` / `consolidate` /
102
+ * `clear` are read-modify-write against a single file; without a lock,
103
+ * two concurrent calls on the same scope can read the same baseline and
104
+ * the later write silently drops the earlier entry. We chain each
105
+ * mutation onto the prior promise for the same scope so they run in
106
+ * issue order. Different scopes still proceed in parallel.
107
+ *
108
+ * The chain tracks only the last pending write. If a write fails, its
109
+ * error is caught and swallowed (line 43) so the chain stays alive for
110
+ * subsequent calls. A crash between atomicWrite() and backup copy leaves
111
+ * the file at its new content with no backup — acceptable for an optional
112
+ * backup whose worst case is losing a memory consolidation pass.
113
+ */
114
+ private readonly writeChain;
115
+ constructor(opts: MemoryStoreOptions);
116
+ private runSerialized;
117
+ readAll(): Promise<string>;
118
+ read(scope: MemoryScope): Promise<string>;
119
+ remember(text: string, scope?: MemoryScope): Promise<void>;
120
+ forget(query: string, scope?: MemoryScope): Promise<number>;
121
+ private forgetUnsafe;
122
+ consolidate(scope: MemoryScope): Promise<void>;
123
+ private consolidateUnsafe;
124
+ clear(scope?: MemoryScope): Promise<void>;
125
+ }
126
+
127
+ /**
128
+ * Reference implementation of `ConfigStore`. Stores a single frozen Config
129
+ * and notifies watchers synchronously on every update. Updates use a deep
130
+ * clone so callers can mutate their `partial` argument freely without
131
+ * tainting state.
132
+ *
133
+ * For the CLI: instantiate once at boot, pass the store (not the Config)
134
+ * to subsystems that care about runtime changes (provider switching,
135
+ * extension reload).
136
+ */
137
+ declare class DefaultConfigStore implements ConfigStore {
138
+ private current;
139
+ private watchers;
140
+ constructor(initial: Config);
141
+ get(): Readonly<Config>;
142
+ getSection<K extends keyof Config>(key: K): Readonly<Config[K]>;
143
+ getExtension(pluginName: string): Readonly<Record<string, unknown>>;
144
+ update(partial: Partial<Config>): Readonly<Config>;
145
+ watch(cb: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void;
146
+ }
147
+
148
+ /**
149
+ * A single config source. Higher priority wins in merges.
150
+ * Sources are applied in priority order (lowest first), so a source
151
+ * with priority=10 overrides one with priority=1.
152
+ */
153
+ interface ConfigSource {
154
+ /** Unique name for debugging and error messages. */
155
+ name: string;
156
+ /** Lower numbers merge first, higher numbers override lower. Default: 50. */
157
+ priority?: number;
158
+ /**
159
+ * Read the raw config patch. Return an empty object if unavailable.
160
+ * Errors are surfaced but do not abort loading — the source is skipped.
161
+ */
162
+ read(): Promise<Partial<Config>>;
163
+ }
164
+ interface ConfigLoaderOptions {
165
+ paths: WstackPaths;
166
+ strict?: boolean;
167
+ vault?: SecretVault;
168
+ /** Extra sources merged after the built-in layers. */
169
+ sources?: ConfigSource[];
170
+ }
171
+ declare class DefaultConfigLoader implements ConfigLoader {
172
+ private readonly paths;
173
+ private readonly strict;
174
+ private readonly vault;
175
+ private readonly extraSources;
176
+ constructor(opts: ConfigLoaderOptions);
177
+ load(opts?: {
178
+ cliFlags?: Partial<Config>;
179
+ cwd?: string;
180
+ }): Promise<Config>;
181
+ private readJson;
182
+ private validateBehavior;
183
+ private validateIdentity;
184
+ }
185
+
186
+ /**
187
+ * L2-D: Config version migration framework. Pure functions, decoupled
188
+ * from disk/CLI — caller passes a parsed JSON object and gets back the
189
+ * up-to-date `Config` shape (or a structured error explaining why
190
+ * migration failed).
191
+ *
192
+ * Migrations are registered as `{ from, to, migrate }` triples and run
193
+ * sequentially. Each migration is independently testable. Adding a new
194
+ * version means appending one migration; existing user configs are
195
+ * upgraded in place at load time.
196
+ */
197
+ interface MigrationContext {
198
+ /**
199
+ * Original on-disk version of the input. Migrations may use this to
200
+ * decide between in-place patches and rewrites.
201
+ */
202
+ fromVersion: number;
203
+ /**
204
+ * Set when the migration writes back to disk. Callers persist the
205
+ * migrated config when this is true so the user doesn't see the same
206
+ * migration banner on every boot.
207
+ */
208
+ shouldPersist: boolean;
209
+ }
210
+ interface ConfigMigration {
211
+ /** Version of the input this migration accepts. */
212
+ from: number;
213
+ /** Version of the output it produces. */
214
+ to: number;
215
+ /** Pure transform — no I/O. */
216
+ migrate(input: Record<string, unknown>, ctx: MigrationContext): Record<string, unknown>;
217
+ /** Optional human-readable description for migration logs / banners. */
218
+ describe?: string;
219
+ }
220
+ interface MigrationResult {
221
+ /** Final config (still typed as `unknown`-keyed — caller validates). */
222
+ config: Record<string, unknown>;
223
+ /** Ordered list of `from→to` versions that ran. */
224
+ applied: string[];
225
+ /** True when at least one migration produced changes worth persisting. */
226
+ shouldPersist: boolean;
227
+ }
228
+ declare class ConfigMigrationError extends Error {
229
+ readonly fromVersion: number;
230
+ readonly targetVersion: number;
231
+ readonly missingStep: number | null;
232
+ constructor(opts: {
233
+ message: string;
234
+ fromVersion: number;
235
+ targetVersion: number;
236
+ missingStep: number | null;
237
+ });
238
+ }
239
+ /**
240
+ * Run registered migrations until the input reaches `targetVersion`.
241
+ *
242
+ * Resolution rules:
243
+ * 1. If `input.version === targetVersion`, no migrations run; `shouldPersist`
244
+ * is false.
245
+ * 2. Otherwise walk the migration chain from `input.version` upward,
246
+ * picking the migration whose `from` matches the current version.
247
+ * 3. Stop when `current.version === targetVersion`.
248
+ * 4. If no migration matches at some point, throw `ConfigMigrationError`
249
+ * with the missing step recorded for diagnostics.
250
+ *
251
+ * Migrations may be downward (e.g. for staged rollouts), but `targetVersion`
252
+ * must be reachable strictly via the registered chain — there's no implicit
253
+ * "skip" or transitive resolution.
254
+ */
255
+ declare function runConfigMigrations(input: Record<string, unknown>, targetVersion: number, migrations: readonly ConfigMigration[]): MigrationResult;
256
+ /**
257
+ * Default empty migration registry. Real migrations are appended as new
258
+ * Config versions are introduced. Example (when v2 lands):
259
+ *
260
+ * export const CONFIG_MIGRATIONS: readonly ConfigMigration[] = [
261
+ * {
262
+ * from: 1, to: 2, describe: 'rename `apiKey` → `auth.apiKey`',
263
+ * migrate(cfg) {
264
+ * const apiKey = cfg.apiKey;
265
+ * delete cfg.apiKey;
266
+ * return { ...cfg, auth: { ...(cfg.auth ?? {}), apiKey } };
267
+ * },
268
+ * },
269
+ * ];
270
+ */
271
+ declare const DEFAULT_CONFIG_MIGRATIONS: readonly ConfigMigration[];
272
+
273
+ /**
274
+ * Per-project lockfile used for crash detection. The CLI writes one of
275
+ * these alongside the session JSONLs (`<projectSessions>/active.json`)
276
+ * when an interactive run starts, and deletes it on clean exit. If we
277
+ * find one on the next launch whose owning PID is dead (or whose host
278
+ * doesn't match), we know the previous run was killed mid-flight and
279
+ * the session it was writing to is a recovery candidate.
280
+ *
281
+ * The lockfile is intentionally per-project (already isolated by
282
+ * `wpaths.projectSessions`), so two TUIs in two different repos do not
283
+ * fight each other.
284
+ */
285
+ interface RecoveryLockOptions {
286
+ /** Directory the lockfile lives in. Usually `wpaths.projectSessions`. */
287
+ dir: string;
288
+ /** This process's PID. Default: `process.pid`. */
289
+ pid?: number;
290
+ /** Hostname recorded for the lock. Default: `os.hostname()`. */
291
+ hostname?: string;
292
+ /** Locks older than this are considered orphaned (disk wiped, etc.). Default 24h. */
293
+ maxAgeMs?: number;
294
+ /** Used to check whether the abandoned session was actually closed cleanly. */
295
+ sessionStore?: SessionStore;
296
+ /**
297
+ * Override the PID-liveness probe. Default: `process.kill(pid, 0)` —
298
+ * succeeds (or throws EPERM) when the PID is alive, throws ESRCH when
299
+ * it is gone. Tests inject a deterministic stub.
300
+ */
301
+ isPidAlive?: (pid: number) => boolean;
302
+ }
303
+ interface AbandonedSession {
304
+ sessionId: string;
305
+ pid: number;
306
+ startedAt: string;
307
+ /** Lockfile age in ms at the time of the check. */
308
+ ageMs: number;
309
+ /** Number of messages already on disk for this session. */
310
+ messageCount: number;
311
+ }
312
+ declare class RecoveryLock {
313
+ private readonly file;
314
+ private readonly pid;
315
+ private readonly hostname;
316
+ private readonly maxAgeMs;
317
+ private readonly sessionStore?;
318
+ private readonly probe;
319
+ constructor(opts: RecoveryLockOptions);
320
+ /**
321
+ * Examine the lockfile and decide whether it represents an abandoned
322
+ * session. Returns `null` if the file is missing, points to a live
323
+ * instance, references a clean-closed session, is too old, or is
324
+ * malformed. Otherwise returns enough detail to prompt the user.
325
+ *
326
+ * Important: this is a read-only check. We never delete an active
327
+ * lock from here — if another wstack instance is alive, the caller
328
+ * should bail or run with a fresh session instead.
329
+ */
330
+ checkAbandoned(): Promise<AbandonedSession | null>;
331
+ /**
332
+ * Claim the lock for the given session. Overwrites any existing lock
333
+ * — the caller should have already handled abandonment (via
334
+ * `checkAbandoned`) before calling this.
335
+ */
336
+ write(sessionId: string): Promise<void>;
337
+ /**
338
+ * Release the lock. Idempotent — silently succeeds if the file is
339
+ * already gone (e.g. someone else cleared it, or the directory was
340
+ * wiped).
341
+ */
342
+ clear(): Promise<void>;
343
+ private readLock;
344
+ }
345
+
346
+ interface QueryFilter {
347
+ eventTypes?: string[];
348
+ toolNames?: string[];
349
+ timeRange?: {
350
+ start: string;
351
+ end: string;
352
+ };
353
+ }
354
+ interface ModeChange {
355
+ ts: string;
356
+ from: string;
357
+ to: string;
358
+ }
359
+ interface TaskSummary {
360
+ taskId: string;
361
+ title: string;
362
+ status: string;
363
+ createdAt: string;
364
+ completedAt?: string;
365
+ }
366
+ interface SessionAnalysis {
367
+ sessionId: string;
368
+ totalDuration: number;
369
+ toolUsageCount: Record<string, number>;
370
+ errorCount: number;
371
+ modeChanges: ModeChange[];
372
+ tasks: TaskSummary[];
373
+ }
374
+ declare class SessionAnalyzer {
375
+ analyze(events: SessionEvent[]): SessionAnalysis;
376
+ query(events: SessionEvent[], filter: QueryFilter): SessionEvent[];
377
+ private calcDuration;
378
+ }
379
+
380
+ /**
381
+ * On-disk checkpoint for `ctx.todos`. Written atomically every time the
382
+ * todo list changes, read once on session resume. This is the missing
383
+ * piece that lets `wstack resume <id>` rehydrate where the previous run
384
+ * stopped instead of starting with an empty board.
385
+ *
386
+ * Schema is intentionally small — a single JSON object so a future
387
+ * format bump is easy. The `version` field is the only contract; the
388
+ * shape under `todos` mirrors `TodoItem` so reading is a straight assign.
389
+ */
390
+ interface TodosCheckpointFile {
391
+ version: 1;
392
+ sessionId: string;
393
+ updatedAt: string;
394
+ todos: TodoItem[];
395
+ }
396
+ type TodosCheckpointDetach = () => Promise<void>;
397
+ /** Read a checkpoint from disk. Returns null when the file doesn't
398
+ * exist or is corrupt — callers treat both cases as "no prior state".
399
+ */
400
+ declare function loadTodosCheckpoint(filePath: string): Promise<TodoItem[] | null>;
401
+ /** Write the checkpoint atomically. Best-effort: a write failure is
402
+ * logged but does not throw — losing one checkpoint shouldn't bring
403
+ * down the agent run.
404
+ */
405
+ declare function saveTodosCheckpoint(filePath: string, sessionId: string, todos: readonly TodoItem[]): Promise<void>;
406
+ /**
407
+ * Subscribe a `ConversationState` so every `todos_replaced` mutation
408
+ * triggers an atomic write to disk. Returns the unsubscribe function.
409
+ *
410
+ * Writes are debounced by 150ms so a flurry of edits (e.g. the LLM
411
+ * marking three items done in the same tool call) coalesces into one
412
+ * disk hit.
413
+ */
414
+ declare function attachTodosCheckpoint(state: ConversationState, filePath: string, sessionId: string): TodosCheckpointDetach;
415
+
416
+ /**
417
+ * Plan items are the strategic counterpart to todos. Where `ctx.todos`
418
+ * is the moment-to-moment task board the LLM mutates per-turn, a plan
419
+ * captures the higher-level approach — the steps the user (or LLM)
420
+ * laid out before any work began.
421
+ *
422
+ * Plans persist by default (per session) so a resumed session can show
423
+ * "you were on step 3 of 5". Todos are derived/transient. Both can
424
+ * coexist: think roadmap (plan) vs. sprint board (todos).
425
+ */
426
+ interface PlanItem {
427
+ id: string;
428
+ title: string;
429
+ /** Optional longer-form context or rationale. */
430
+ details?: string;
431
+ status: 'open' | 'in_progress' | 'done';
432
+ createdAt: string;
433
+ updatedAt: string;
434
+ }
435
+ interface PlanFile {
436
+ version: 1;
437
+ sessionId: string;
438
+ title?: string;
439
+ updatedAt: string;
440
+ items: PlanItem[];
441
+ }
442
+ declare function loadPlan(filePath: string): Promise<PlanFile | null>;
443
+ declare function savePlan(filePath: string, plan: PlanFile): Promise<void>;
444
+ /** Create a new PlanFile when none exists on disk. */
445
+ declare function emptyPlan(sessionId: string, title?: string): PlanFile;
446
+ declare function addPlanItem(plan: PlanFile, title: string, details?: string): {
447
+ plan: PlanFile;
448
+ item: PlanItem;
449
+ };
450
+ declare function removePlanItem(plan: PlanFile, idOrIndex: string): PlanFile;
451
+ declare function setPlanItemStatus(plan: PlanFile, idOrIndex: string, status: PlanItem['status']): PlanFile;
452
+ declare function clearPlan(plan: PlanFile): PlanFile;
453
+ /** Render the plan as a short markdown-ish string suitable for slash output. */
454
+ declare function formatPlan(plan: PlanFile): string;
455
+ /**
456
+ * Optional: attach a state-listener so meta operations (storing a plan
457
+ * id on ctx.meta) trigger a save. Currently a stub — plans don't live
458
+ * on Context, but this keeps the API surface symmetric with the todos
459
+ * checkpoint so future refactors can flip plans into Context if needed.
460
+ */
461
+ declare function attachPlanCheckpoint(_state: ConversationState, _filePath: string, _sessionId: string): () => void;
462
+
463
+ /**
464
+ * Director state checkpoint — written incrementally throughout a fleet
465
+ * run so a crashed director can be inspected (and eventually resumed)
466
+ * instead of leaving only a final `fleet.json` manifest after `shutdown()`.
467
+ *
468
+ * Schema is JSON-friendly and deliberately denormalized. Each mutation
469
+ * triggers an atomic-write of the whole file — small payloads (typically
470
+ * < 10 KB even with dozens of subagents) make this cheap.
471
+ */
472
+ interface DirectorSubagentState {
473
+ id: string;
474
+ name?: string;
475
+ role?: string;
476
+ provider?: string;
477
+ model?: string;
478
+ spawnedAt: string;
479
+ }
480
+ interface DirectorTaskState {
481
+ taskId: string;
482
+ subagentId?: string;
483
+ description?: string;
484
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'stopped' | 'timeout';
485
+ assignedAt?: string;
486
+ completedAt?: string;
487
+ iterations?: number;
488
+ toolCalls?: number;
489
+ durationMs?: number;
490
+ error?: string;
491
+ }
492
+ interface DirectorStateSnapshot {
493
+ version: 1;
494
+ directorRunId: string;
495
+ updatedAt: string;
496
+ spawnCount: number;
497
+ maxSpawns?: number;
498
+ spawnDepth: number;
499
+ maxSpawnDepth: number;
500
+ subagents: DirectorSubagentState[];
501
+ tasks: DirectorTaskState[];
502
+ /** Aggregated usage snapshot. Optional — populated by the Director on save when available. */
503
+ usage?: unknown;
504
+ }
505
+ declare function loadDirectorState(filePath: string): Promise<DirectorStateSnapshot | null>;
506
+ /**
507
+ * In-memory accumulator with atomic-write checkpoint. The Director keeps
508
+ * an instance, mutates it on every spawn/assign/complete/fail event, and
509
+ * the instance debounces writes so a burst of activity collapses into a
510
+ * single disk hit.
511
+ */
512
+ declare class DirectorStateCheckpoint {
513
+ private snapshot;
514
+ private readonly filePath;
515
+ private timer;
516
+ private readonly debounceMs;
517
+ private writing;
518
+ private rewriteRequested;
519
+ constructor(filePath: string, init: {
520
+ directorRunId: string;
521
+ maxSpawns?: number;
522
+ spawnDepth: number;
523
+ maxSpawnDepth: number;
524
+ }, debounceMs?: number);
525
+ current(): DirectorStateSnapshot;
526
+ recordSpawn(sub: DirectorSubagentState, spawnCount: number): void;
527
+ recordTaskAssigned(task: DirectorTaskState): void;
528
+ recordTaskStatus(taskId: string, patch: Partial<DirectorTaskState> & {
529
+ status: DirectorTaskState['status'];
530
+ }): void;
531
+ setUsage(usage: unknown): void;
532
+ /** Force a synchronous flush — used by Director.shutdown(). */
533
+ flush(): Promise<void>;
534
+ private bumpUpdatedAt;
535
+ private schedule;
536
+ private persist;
537
+ }
538
+
539
+ export { type AbandonedSession as A, loadPlan as B, type ConfigLoaderOptions as C, DEFAULT_CONFIG_MIGRATIONS as D, loadTodosCheckpoint as E, removePlanItem as F, runConfigMigrations as G, savePlan as H, saveTodosCheckpoint as I, setPlanItemStatus as J, type MemoryStoreOptions as M, type PersistedQueueItem as P, QueueStore as Q, RecoveryLock as R, SessionAnalyzer as S, type TodosCheckpointFile as T, type AttachmentStoreOptions as a, type ConfigMigration as b, ConfigMigrationError as c, type ConfigSource as d, DefaultAttachmentStore as e, DefaultConfigLoader as f, DefaultConfigStore as g, DefaultMemoryStore as h, DefaultSessionStore as i, DirectorStateCheckpoint as j, type DirectorStateSnapshot as k, type DirectorSubagentState as l, type DirectorTaskState as m, type MigrationContext as n, type MigrationResult as o, type PlanFile as p, type PlanItem as q, type RecoveryLockOptions as r, type SessionStoreOptions as s, addPlanItem as t, attachPlanCheckpoint as u, attachTodosCheckpoint as v, clearPlan as w, emptyPlan as x, formatPlan as y, loadDirectorState as z };
@@ -1,4 +1,4 @@
1
- import { U as Usage, a0 as Context, y as ToolProgressEvent, u as Tool } from './context-P207fTpo.js';
1
+ import { U as Usage, a1 as Context, y as ToolProgressEvent, u as Tool } from './context-PH4DvBZV.js';
2
2
 
3
3
  /**
4
4
  * EventBus — observe-only typed event bus.
@@ -317,6 +317,23 @@ interface EventMap {
317
317
  'token.cost_estimate_unavailable': {
318
318
  model: string;
319
319
  };
320
+ /** Fired by SessionWriter.writeCheckpoint() after the checkpoint event is appended to JSONL. */
321
+ 'checkpoint.written': {
322
+ promptIndex: number;
323
+ promptPreview: string;
324
+ ts: string;
325
+ fileCount: number;
326
+ };
327
+ /**
328
+ * Fired after a session rewind completes: files are reverted and the session
329
+ * history is truncated. The TUI listens to this to update its checkpoint
330
+ * list and clear history entries that are now invalid.
331
+ */
332
+ 'session.rewound': {
333
+ toPromptIndex: number;
334
+ revertedFiles: string[];
335
+ removedEvents: number;
336
+ };
320
337
  error: {
321
338
  err: Error;
322
339
  phase: string;
@@ -1,19 +1,19 @@
1
- export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-CYe5cp5U.js';
2
- import { g as Provider, a0 as Context } from '../context-P207fTpo.js';
3
- import { a as Compactor, C as CompactReport } from '../compactor-CTHjZAwf.js';
4
- import { M as MessageSelector } from '../selector-B-CGOshv.js';
5
- import { E as EventBus } from '../events-DYAbU84e.js';
6
- import { c as MiddlewareHandler } from '../system-prompt-CzY1zrbC.js';
7
- import { e as ContextWindowAggressiveOn, i as ContextWindowPolicy } from '../config-DO2eCKgq.js';
8
- import { r as Agent, R as RunResult } from '../index-BNzUUDVR.js';
9
- import { D as DoneCondition } from '../multi-agent-B1Nn9eC0.js';
1
+ export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-B6kRcWeF.js';
2
+ import { g as Provider, a1 as Context } from '../context-PH4DvBZV.js';
3
+ import { a as Compactor, C as CompactReport } from '../compactor-BP4xhKVi.js';
4
+ import { M as MessageSelector } from '../selector-yqyxt-Ii.js';
5
+ import { E as EventBus } from '../events-oxn-Wkub.js';
6
+ import { c as MiddlewareHandler } from '../system-prompt-BJlzKGO6.js';
7
+ import { e as ContextWindowAggressiveOn, i as ContextWindowPolicy } from '../config-BOD_HQBw.js';
8
+ import { r as Agent, R as RunResult } from '../index-a12jc7-r.js';
9
+ import { D as DoneCondition } from '../multi-agent-D6S4Z7H8.js';
10
10
  import { a as SkillLoader, b as SkillManifest, S as SkillEntry } from '../skill-CxuWrsKK.js';
11
11
  import { a as WstackPaths } from '../wstack-paths-BGu2INTm.js';
12
- import '../retry-policy-CnYVKGPv.js';
12
+ import '../retry-policy-DUJ8-Qc_.js';
13
13
  import '../models-registry-Y2xbog0E.js';
14
14
  import '../logger-BMQgxvdy.js';
15
15
  import '../observability-BhnVLBLS.js';
16
- import '../secret-scrubber-Buo9zLGs.js';
16
+ import '../secret-scrubber-CB11A2P7.js';
17
17
 
18
18
  interface SkillLoaderOptions {
19
19
  paths: WstackPaths;
@@ -1,9 +1,9 @@
1
- export { A as AfterIterationHook, p as AfterRunHook, q as AfterToolExecutionHook, s as AgentExtension, B as BeforeIterationHook, w as BeforeRunHook, x as BeforeToolExecutionHook, E as ExtensionRegistry, O as OnErrorHook, G as ProviderRunnerFn, z as ProviderRunnerWrapper } from '../index-BNzUUDVR.js';
2
- import '../context-P207fTpo.js';
1
+ export { A as AfterIterationHook, p as AfterRunHook, q as AfterToolExecutionHook, s as AgentExtension, B as BeforeIterationHook, w as BeforeRunHook, x as BeforeToolExecutionHook, E as ExtensionRegistry, O as OnErrorHook, G as ProviderRunnerFn, z as ProviderRunnerWrapper } from '../index-a12jc7-r.js';
2
+ import '../context-PH4DvBZV.js';
3
3
  import '../logger-BMQgxvdy.js';
4
- import '../system-prompt-CzY1zrbC.js';
4
+ import '../system-prompt-BJlzKGO6.js';
5
5
  import '../observability-BhnVLBLS.js';
6
- import '../events-DYAbU84e.js';
7
- import '../secret-scrubber-Buo9zLGs.js';
8
- import '../config-DO2eCKgq.js';
6
+ import '../events-oxn-Wkub.js';
7
+ import '../secret-scrubber-CB11A2P7.js';
8
+ import '../config-BOD_HQBw.js';
9
9
  import '../models-registry-Y2xbog0E.js';
@@ -1,9 +1,9 @@
1
- import { M as MultiAgentConfig, i as SubagentRunner, c as SubagentConfig, k as TaskSpec, j as TaskResult, a as CoordinatorStatus, b as MultiAgentCoordinator, S as SpawnResult, l as BridgeMessage, A as AgentBridge } from './multi-agent-B1Nn9eC0.js';
2
- import { q as SessionWriter, u as Tool, o as SessionStore } from './context-P207fTpo.js';
3
- import { I as InMemoryAgentBridge } from './agent-bridge-BkjOkSkD.js';
4
- import { E as EventBus } from './events-DYAbU84e.js';
1
+ import { M as MultiAgentConfig, i as SubagentRunner, c as SubagentConfig, k as TaskSpec, j as TaskResult, a as CoordinatorStatus, b as MultiAgentCoordinator, S as SpawnResult, l as BridgeMessage, A as AgentBridge } from './multi-agent-D6S4Z7H8.js';
2
+ import { q as SessionWriter, u as Tool, o as SessionStore } from './context-PH4DvBZV.js';
3
+ import { I as InMemoryAgentBridge } from './agent-bridge-EiUFe3if.js';
4
+ import { E as EventBus } from './events-oxn-Wkub.js';
5
5
  import { EventEmitter } from 'node:events';
6
- import { r as Agent, u as AgentInput } from './index-BNzUUDVR.js';
6
+ import { r as Agent, u as AgentInput } from './index-a12jc7-r.js';
7
7
 
8
8
  /**
9
9
  * Single fleet-wide event with subagent attribution. Whatever a child
@@ -1,10 +1,10 @@
1
- import { u as Tool, z as ToolResultBlock, T as TextBlock, a0 as Context, R as Request, j as Response, D as ToolUseBlock, g as Provider, W as WrongStackError, b as ContentBlock, a7 as RunOptions, J as JSONSchema } from './context-P207fTpo.js';
1
+ import { u as Tool, z as ToolResultBlock, T as TextBlock, a1 as Context, R as Request, j as Response, D as ToolUseBlock, g as Provider, W as WrongStackError, b as ContentBlock, a8 as RunOptions, J as JSONSchema } from './context-PH4DvBZV.js';
2
2
  import { L as Logger } from './logger-BMQgxvdy.js';
3
- import { R as Renderer, B as BuildContext, C as Container, P as Pipeline, e as ReadonlyPipeline } from './system-prompt-CzY1zrbC.js';
3
+ import { R as Renderer, B as BuildContext, C as Container, P as Pipeline, e as ReadonlyPipeline } from './system-prompt-BJlzKGO6.js';
4
4
  import { T as Tracer } from './observability-BhnVLBLS.js';
5
- import { E as EventBus, a as EventName, L as Listener } from './events-DYAbU84e.js';
6
- import { a as PermissionPolicy, S as SecretScrubber } from './secret-scrubber-Buo9zLGs.js';
7
- import { l as ProviderConfig, a as Config } from './config-DO2eCKgq.js';
5
+ import { E as EventBus, a as EventName, L as Listener } from './events-oxn-Wkub.js';
6
+ import { a as PermissionPolicy, S as SecretScrubber } from './secret-scrubber-CB11A2P7.js';
7
+ import { l as ProviderConfig, a as Config } from './config-BOD_HQBw.js';
8
8
  import { W as WireFamily } from './models-registry-Y2xbog0E.js';
9
9
 
10
10
  /**