@wrongstack/core 0.5.5 → 0.5.6

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.
@@ -452,6 +452,22 @@ declare function setPlanItemStatus(plan: PlanFile, idOrIndex: string, status: Pl
452
452
  declare function clearPlan(plan: PlanFile): PlanFile;
453
453
  /** Render the plan as a short markdown-ish string suitable for slash output. */
454
454
  declare function formatPlan(plan: PlanFile): string;
455
+ /**
456
+ * Promote a plan item to a set of todo items.
457
+ * The plan item is marked 'in_progress' (if not already done) and its
458
+ * title + details become the first todo; additional subtasks are appended.
459
+ * Returns the derived todo list so the caller can pass it to `todoTool`
460
+ * or `ctx.state.replaceTodos()`.
461
+ */
462
+ declare function deriveTodosFromPlanItem(plan: PlanFile, idOrIndex: string, subtasks?: string[]): {
463
+ plan: PlanFile;
464
+ todos: Array<{
465
+ id: string;
466
+ content: string;
467
+ status: 'pending' | 'in_progress' | 'completed';
468
+ activeForm?: string;
469
+ }>;
470
+ } | null;
455
471
  /**
456
472
  * Optional: attach a state-listener so meta operations (storing a plan
457
473
  * id on ctx.meta) trigger a save. Currently a stub — plans don't live
@@ -461,79 +477,24 @@ declare function formatPlan(plan: PlanFile): string;
461
477
  declare function attachPlanCheckpoint(_state: ConversationState, _filePath: string, _sessionId: string): () => void;
462
478
 
463
479
  /**
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()`.
480
+ * Plan templatespre-defined plan skeletons for common workflows.
467
481
  *
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.
482
+ * Templates are stored in-memory (no disk I/O). Users instantiate them
483
+ * via `/plan template use <name>` or `planTool(action: 'template_use')`.
484
+ * Each template is a function that returns an array of item titles, so
485
+ * dynamic content (dates, project names) can be injected later.
511
486
  */
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;
487
+ interface PlanTemplate {
488
+ name: string;
489
+ description: string;
490
+ category: 'development' | 'release' | 'maintenance' | 'infrastructure';
491
+ items: Array<{
492
+ title: string;
493
+ details?: string;
494
+ }>;
537
495
  }
496
+ declare function listPlanTemplates(): PlanTemplate[];
497
+ declare function getPlanTemplate(name: string): PlanTemplate | undefined;
498
+ declare function formatPlanTemplates(): string;
538
499
 
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 };
500
+ 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, type MigrationContext as j, type MigrationResult as k, type PlanFile as l, type PlanItem as m, type PlanTemplate as n, type RecoveryLockOptions as o, type SessionStoreOptions as p, addPlanItem as q, attachPlanCheckpoint as r, attachTodosCheckpoint as s, clearPlan as t, deriveTodosFromPlanItem as u, emptyPlan as v, formatPlan as w, formatPlanTemplates as x, getPlanTemplate as y, listPlanTemplates as z };
@@ -1,6 +1,7 @@
1
- export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, j as DirectorStateCheckpoint, k as DirectorStateSnapshot, l as DirectorSubagentState, m as DirectorTaskState, M as MemoryStoreOptions, n as MigrationContext, o as MigrationResult, P as PersistedQueueItem, p as PlanFile, q as PlanItem, Q as QueueStore, R as RecoveryLock, r as RecoveryLockOptions, S as SessionAnalyzer, s as SessionStoreOptions, T as TodosCheckpointFile, t as addPlanItem, u as attachPlanCheckpoint, v as attachTodosCheckpoint, w as clearPlan, x as emptyPlan, y as formatPlan, z as loadDirectorState, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../director-state-BUxlqkOa.js';
1
+ export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-DaxTCPfk.js';
2
2
  export { D as DefaultSessionReader } from '../session-reader-4jxsYLZ8.js';
3
3
  import { S as SessionRewinder, C as CheckpointInfo, a as RewindResultExtended } from '../session-rewinder-C9HnMkhP.js';
4
+ export { D as DirectorStateCheckpoint, a as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from '../director-state-BmYi3DGA.js';
4
5
  import '../events-qnDZbrtb.js';
5
6
  import '../context-CLZXPPYk.js';
6
7
  import '../memory-CEXuo7sz.js';
@@ -3,7 +3,12 @@ import * as fsp from 'fs/promises';
3
3
  import * as path2 from 'path';
4
4
  import * as os from 'os';
5
5
 
6
- // src/storage/session-store.ts
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
7
12
  async function atomicWrite(targetPath, content, opts = {}) {
8
13
  const dir = path2.dirname(targetPath);
9
14
  await fsp.mkdir(dir, { recursive: true });
@@ -2182,9 +2187,149 @@ function matchIndex(plan, idOrIndex) {
2182
2187
  const lower = idOrIndex.toLowerCase();
2183
2188
  return plan.items.findIndex((it) => it.title.toLowerCase().includes(lower));
2184
2189
  }
2190
+ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
2191
+ const idx = matchIndex(plan, idOrIndex);
2192
+ if (idx === -1) return null;
2193
+ const item = plan.items[idx];
2194
+ if (!item) return null;
2195
+ let updatedPlan = plan;
2196
+ if (item.status !== "done") {
2197
+ updatedPlan = setPlanItemStatus(plan, idOrIndex, "in_progress");
2198
+ }
2199
+ const todos = [];
2200
+ todos.push({
2201
+ id: `todo_${Date.now()}_plan`,
2202
+ content: item.title,
2203
+ status: "in_progress",
2204
+ activeForm: item.title
2205
+ });
2206
+ if (subtasks && subtasks.length > 0) {
2207
+ for (const st of subtasks) {
2208
+ todos.push({
2209
+ id: `todo_${Date.now()}_${randomUUID().slice(0, 6)}`,
2210
+ content: st,
2211
+ status: "pending"
2212
+ });
2213
+ }
2214
+ }
2215
+ return { plan: updatedPlan, todos };
2216
+ }
2185
2217
  function attachPlanCheckpoint(_state, _filePath, _sessionId) {
2186
2218
  return () => void 0;
2187
2219
  }
2220
+
2221
+ // src/storage/plan-templates.ts
2222
+ var templates = {
2223
+ "new-feature": {
2224
+ name: "new-feature",
2225
+ description: "Standard workflow for adding a new feature",
2226
+ category: "development",
2227
+ items: [
2228
+ { title: "Write specification / design doc", details: "Define scope, acceptance criteria, edge cases" },
2229
+ { title: "Set up feature branch", details: "git checkout -b feature/..." },
2230
+ { title: "Implement core logic", details: "TDD preferred \u2014 write tests first" },
2231
+ { title: "Add unit tests", details: ">= 80% coverage for new code" },
2232
+ { title: "Add integration tests", details: "End-to-end happy path + error paths" },
2233
+ { title: "Update documentation", details: "README, API docs, changelog" },
2234
+ { title: "Code review", details: "Self-review before requesting review" },
2235
+ { title: "Merge and deploy", details: "CI green, tag release" }
2236
+ ]
2237
+ },
2238
+ "bug-fix": {
2239
+ name: "bug-fix",
2240
+ description: "Systematic approach to fixing bugs",
2241
+ category: "maintenance",
2242
+ items: [
2243
+ { title: "Reproduce the bug", details: "Minimal reproduction case" },
2244
+ { title: "Root cause analysis", details: "Trace through logs, debugger" },
2245
+ { title: "Write failing test", details: "Test must fail before fix" },
2246
+ { title: "Implement fix", details: "Smallest possible change" },
2247
+ { title: "Verify fix", details: "Test passes, reproduction no longer fails" },
2248
+ { title: "Regression test", details: "Ensure no related tests broken" },
2249
+ { title: "Document in changelog", details: "Brief description + issue link" }
2250
+ ]
2251
+ },
2252
+ "refactor": {
2253
+ name: "refactor",
2254
+ description: "Safe refactoring workflow",
2255
+ category: "maintenance",
2256
+ items: [
2257
+ { title: "Identify refactoring target", details: "Code smell, performance bottleneck, or tech debt" },
2258
+ { title: "Ensure test coverage", details: "Existing tests must pass before and after" },
2259
+ { title: "Write characterization tests", details: "Capture current behavior if tests weak" },
2260
+ { title: "Apply refactoring", details: "Small steps, frequent commits" },
2261
+ { title: "Run full test suite", details: "All tests must pass" },
2262
+ { title: "Performance check", details: "Ensure no regression" },
2263
+ { title: "Code review", details: "Explain the why, not just the what" }
2264
+ ]
2265
+ },
2266
+ "release": {
2267
+ name: "release",
2268
+ description: "Preparing a new release",
2269
+ category: "release",
2270
+ items: [
2271
+ { title: "Version bump", details: "package.json, lockfiles, tags" },
2272
+ { title: "Update changelog", details: "All changes since last release" },
2273
+ { title: "Run full test suite", details: "Unit + integration + e2e" },
2274
+ { title: "Build artifacts", details: "Docker images, bundles, binaries" },
2275
+ { title: "Staging smoke tests", details: "Deploy to staging, verify" },
2276
+ { title: "Production deploy", details: "Blue-green or canary" },
2277
+ { title: "Post-deploy verification", details: "Health checks, error rates" },
2278
+ { title: "Announce release", details: "Slack, email, GitHub release notes" }
2279
+ ]
2280
+ },
2281
+ "security-audit": {
2282
+ name: "security-audit",
2283
+ description: "Security review and hardening",
2284
+ category: "infrastructure",
2285
+ items: [
2286
+ { title: "Dependency audit", details: "npm audit, Snyk, Dependabot alerts" },
2287
+ { title: "Secret scan", details: "git-secrets, truffleHog, manual review" },
2288
+ { title: "Access control review", details: "IAM, roles, least privilege" },
2289
+ { title: "Input validation audit", details: "SQL injection, XSS, path traversal" },
2290
+ { title: "Authentication review", details: "Session management, MFA, password policy" },
2291
+ { title: "Logging and monitoring", details: "PII in logs, audit trails" },
2292
+ { title: "Incident response plan", details: "Runbooks, contacts, escalation" }
2293
+ ]
2294
+ },
2295
+ "onboarding": {
2296
+ name: "onboarding",
2297
+ description: "New developer onboarding checklist",
2298
+ category: "infrastructure",
2299
+ items: [
2300
+ { title: "Repository access", details: "GitHub/GitLab permissions" },
2301
+ { title: "Local environment setup", details: "Docker, dependencies, env files" },
2302
+ { title: "Run tests locally", details: "Verify green suite" },
2303
+ { title: "Read architecture docs", details: "ADR, README, onboarding guide" },
2304
+ { title: "First commit", details: "Docs fix or small improvement" },
2305
+ { title: "Pair programming session", details: "Walk through codebase with buddy" },
2306
+ { title: "Deploy to staging", details: "Verify CI/CD access" }
2307
+ ]
2308
+ }
2309
+ };
2310
+ function listPlanTemplates() {
2311
+ return Object.values(templates);
2312
+ }
2313
+ function getPlanTemplate(name) {
2314
+ return templates[name];
2315
+ }
2316
+ function formatPlanTemplates() {
2317
+ const cats = /* @__PURE__ */ new Map();
2318
+ for (const t of Object.values(templates)) {
2319
+ const arr = cats.get(t.category) ?? [];
2320
+ arr.push(t);
2321
+ cats.set(t.category, arr);
2322
+ }
2323
+ const lines = ["Available plan templates:"];
2324
+ for (const [cat, items] of cats) {
2325
+ lines.push(`
2326
+ ${cat}:`);
2327
+ for (const t of items) {
2328
+ lines.push(` ${t.name.padEnd(18)} \u2014 ${t.description}`);
2329
+ }
2330
+ }
2331
+ return lines.join("\n");
2332
+ }
2188
2333
  async function loadDirectorState(filePath) {
2189
2334
  let raw;
2190
2335
  try {
@@ -2200,15 +2345,48 @@ async function loadDirectorState(filePath) {
2200
2345
  return null;
2201
2346
  }
2202
2347
  }
2348
+ async function acquireDirectorStateLock(lockPath, processId = process.pid) {
2349
+ let existing;
2350
+ try {
2351
+ existing = await fsp.readFile(lockPath, "utf8");
2352
+ } catch {
2353
+ }
2354
+ if (existing) {
2355
+ try {
2356
+ const lock2 = JSON.parse(existing);
2357
+ try {
2358
+ process.kill(lock2.pid, 0);
2359
+ return false;
2360
+ } catch {
2361
+ }
2362
+ } catch {
2363
+ }
2364
+ }
2365
+ const lock = {
2366
+ pid: processId,
2367
+ hostname: __require("os").hostname(),
2368
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
2369
+ };
2370
+ await atomicWrite(lockPath, JSON.stringify(lock), { mode: 384 });
2371
+ return true;
2372
+ }
2373
+ async function releaseDirectorStateLock(lockPath) {
2374
+ try {
2375
+ await fsp.unlink(lockPath);
2376
+ } catch {
2377
+ }
2378
+ }
2203
2379
  var DirectorStateCheckpoint = class {
2204
2380
  snapshot;
2205
2381
  filePath;
2382
+ lockPath;
2206
2383
  timer = null;
2207
2384
  debounceMs;
2208
2385
  writing = false;
2209
2386
  rewriteRequested = false;
2210
2387
  constructor(filePath, init, debounceMs = 250) {
2211
2388
  this.filePath = filePath;
2389
+ this.lockPath = `${filePath}.lock`;
2212
2390
  this.debounceMs = debounceMs;
2213
2391
  this.snapshot = {
2214
2392
  version: 1,
@@ -2218,10 +2396,36 @@ var DirectorStateCheckpoint = class {
2218
2396
  maxSpawns: init.maxSpawns,
2219
2397
  spawnDepth: init.spawnDepth,
2220
2398
  maxSpawnDepth: init.maxSpawnDepth,
2399
+ directorBudget: init.directorBudget,
2221
2400
  subagents: [],
2222
2401
  tasks: []
2223
2402
  };
2224
2403
  }
2404
+ /**
2405
+ * Attempt to acquire the lock for this checkpoint. Call this before
2406
+ * resuming a crashed director run. If it returns false, another
2407
+ * director process is still running this fleet — do not resume.
2408
+ */
2409
+ async acquireLock() {
2410
+ return acquireDirectorStateLock(this.lockPath);
2411
+ }
2412
+ /**
2413
+ * Release the lock on graceful shutdown. Call `flush()` first to ensure
2414
+ * the final checkpoint state is on disk before removing the lock.
2415
+ * Without this, the next resume will see a stale-lock and refuse.
2416
+ */
2417
+ async releaseLock() {
2418
+ return releaseDirectorStateLock(this.lockPath);
2419
+ }
2420
+ /**
2421
+ * Resume from a snapshot previously loaded via `loadDirectorState()`.
2422
+ * Use this when `--resume <runId>` is triggered — the snapshot has
2423
+ * the full fleet state (subagents, tasks) from before the crash; the
2424
+ * checkpoint continues from there.
2425
+ */
2426
+ resume(snapshot) {
2427
+ this.snapshot = snapshot;
2428
+ }
2225
2429
  current() {
2226
2430
  return this.snapshot;
2227
2431
  }
@@ -2305,6 +2509,6 @@ var DirectorStateCheckpoint = class {
2305
2509
  }
2306
2510
  };
2307
2511
 
2308
- export { ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, QueueStore, RecoveryLock, SessionAnalyzer, addPlanItem, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, emptyPlan, formatPlan, loadDirectorState, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, savePlan, saveTodosCheckpoint, setPlanItemStatus };
2512
+ export { ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, QueueStore, RecoveryLock, SessionAnalyzer, addPlanItem, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, deriveTodosFromPlanItem, emptyPlan, formatPlan, formatPlanTemplates, getPlanTemplate, listPlanTemplates, loadDirectorState, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, savePlan, saveTodosCheckpoint, setPlanItemStatus };
2309
2513
  //# sourceMappingURL=index.js.map
2310
2514
  //# sourceMappingURL=index.js.map