@hasna/loops 0.3.60 → 0.4.1

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 (63) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/LICENSE +197 -13
  3. package/README.md +95 -85
  4. package/dist/api/index.d.ts +11 -0
  5. package/dist/api/index.js +333 -0
  6. package/dist/cli/index.js +8013 -6659
  7. package/dist/daemon/control.d.ts +21 -1
  8. package/dist/daemon/daemon.d.ts +5 -0
  9. package/dist/daemon/index.js +2836 -1222
  10. package/dist/daemon/install.d.ts +1 -1
  11. package/dist/index.d.ts +23 -8
  12. package/dist/index.js +5715 -4541
  13. package/dist/lib/accounts.d.ts +6 -1
  14. package/dist/lib/agent-adapter.d.ts +74 -0
  15. package/dist/lib/backup.d.ts +25 -0
  16. package/dist/lib/errors.d.ts +21 -0
  17. package/dist/lib/executor.d.ts +10 -1
  18. package/dist/lib/goal/metadata.d.ts +16 -0
  19. package/dist/lib/goal/model-factory.d.ts +1 -0
  20. package/dist/lib/goal/prompts.d.ts +3 -1
  21. package/dist/lib/goal/types.d.ts +3 -0
  22. package/dist/lib/health.d.ts +1 -1
  23. package/dist/lib/ids.d.ts +8 -1
  24. package/dist/lib/machines.d.ts +6 -0
  25. package/dist/lib/mode.d.ts +48 -0
  26. package/dist/lib/mode.js +260 -0
  27. package/dist/lib/process-identity.d.ts +16 -0
  28. package/dist/lib/{schedule.d.ts → recurrence.d.ts} +1 -0
  29. package/dist/lib/redact.d.ts +21 -0
  30. package/dist/lib/route/cursors.d.ts +18 -0
  31. package/dist/lib/route/drain.d.ts +6 -0
  32. package/dist/lib/route/fields.d.ts +27 -0
  33. package/dist/lib/route/gates.d.ts +26 -0
  34. package/dist/lib/route/index.d.ts +18 -0
  35. package/dist/lib/route/options.d.ts +31 -0
  36. package/dist/lib/route/parse.d.ts +8 -0
  37. package/dist/lib/route/pr-review.d.ts +11 -0
  38. package/dist/lib/route/provider.d.ts +41 -0
  39. package/dist/lib/route/route-event.d.ts +23 -0
  40. package/dist/lib/route/route-tasks.d.ts +75 -0
  41. package/dist/lib/route/throttle.d.ts +47 -0
  42. package/dist/lib/route/todos-cli.d.ts +21 -0
  43. package/dist/lib/route/types.d.ts +88 -0
  44. package/dist/lib/run-artifacts.d.ts +17 -2
  45. package/dist/lib/run-envelope.d.ts +41 -0
  46. package/dist/lib/scheduler.d.ts +78 -2
  47. package/dist/lib/store.d.ts +63 -0
  48. package/dist/lib/store.js +1007 -287
  49. package/dist/lib/template-kit.d.ts +70 -0
  50. package/dist/lib/templates-custom.d.ts +34 -0
  51. package/dist/lib/templates.d.ts +13 -81
  52. package/dist/lib/workflow-runner.d.ts +2 -0
  53. package/dist/mcp/index.d.ts +3 -0
  54. package/dist/mcp/index.js +3231 -1382
  55. package/dist/runner/index.d.ts +9 -0
  56. package/dist/runner/index.js +295 -0
  57. package/dist/sdk/index.d.ts +29 -3
  58. package/dist/sdk/index.js +2743 -1044
  59. package/dist/test-helpers.d.ts +37 -0
  60. package/dist/types.d.ts +3 -1
  61. package/docs/DEPLOYMENT_MODES.md +140 -0
  62. package/docs/USAGE.md +102 -46
  63. package/package.json +23 -5
@@ -46,6 +46,35 @@ export interface CreateGoalPlanNodeInput {
46
46
  priority?: number;
47
47
  tokenBudget?: number;
48
48
  }
49
+ export interface RecordRunProcessInput {
50
+ pid: number;
51
+ pgid?: number;
52
+ processStartedAt?: string;
53
+ }
54
+ export interface RecoverExpiredRunLeasesResult {
55
+ /** Runs whose lease expired with no live process; marked abandoned. */
56
+ abandoned: LoopRun[];
57
+ /** Runs whose lease expired while their process (group) is still alive; lease deferred. */
58
+ deferred: LoopRun[];
59
+ }
60
+ export interface PruneHistoryOptions {
61
+ /** Delete terminal runs whose created_at is older than this many days. */
62
+ maxAgeDays?: number;
63
+ /** Always retain at least this many of the most recent runs per loop. */
64
+ keepPerLoop?: number;
65
+ /** Report what would be deleted without deleting anything. */
66
+ dryRun?: boolean;
67
+ /** Injectable clock for tests. */
68
+ now?: Date;
69
+ }
70
+ export interface PruneHistorySummary {
71
+ dryRun: boolean;
72
+ cutoff?: string;
73
+ keepPerLoop?: number;
74
+ loopRuns: number;
75
+ workflowRuns: number;
76
+ goalRuns: number;
77
+ }
49
78
  export interface RecordGoalEventInput {
50
79
  goalId: string;
51
80
  turn?: number;
@@ -61,6 +90,8 @@ export declare class Store {
61
90
  private rootDir;
62
91
  constructor(path?: string);
63
92
  private migrate;
93
+ private migrations;
94
+ private createBaseSchema;
64
95
  /**
65
96
  * Add a column only if it does not already exist. Idempotent — avoids the
66
97
  * "duplicate column name" error that SQLite logs (via libsqlite3, before any
@@ -70,6 +101,8 @@ export declare class Store {
70
101
  */
71
102
  private addColumnIfMissing;
72
103
  private createWorkflowRunBackfillIndexes;
104
+ /** Run `fn` inside a write transaction unless the caller already opened one. */
105
+ private transact;
73
106
  private assertDaemonLeaseFence;
74
107
  private assertNoNestedWorkflowGoal;
75
108
  createLoop(input: CreateLoopInput, from?: Date): Loop;
@@ -179,6 +212,13 @@ export declare class Store {
179
212
  limit?: number;
180
213
  }): Goal[];
181
214
  createGoalPlanNodes(goalId: string, nodes: CreateGoalPlanNodeInput[], opts?: DaemonLeaseFence): GoalPlanNode[];
215
+ /**
216
+ * Insert a plan node, detecting (rather than silently ignoring) conflicts:
217
+ * an existing (plan_id, key) row means the node is already planned and is
218
+ * kept; a primary-key collision retries with a fresh id instead of dropping
219
+ * the node on the floor.
220
+ */
221
+ private insertGoalPlanNode;
182
222
  listGoalPlanNodes(goalIdOrPlanId: string): GoalPlanNode[];
183
223
  updateGoalStatus(goalId: string, status: GoalStatus, opts?: DaemonLeaseFence): Goal;
184
224
  addGoalUsage(goalId: string, tokens: number, timeUsedSeconds?: number, opts?: DaemonLeaseFence): Goal;
@@ -215,6 +255,11 @@ export declare class Store {
215
255
  hasRunningRun(loopId: string): boolean;
216
256
  hasRunningRunForSlot(loopId: string, scheduledFor: string): boolean;
217
257
  markRunPid(id: string, pid: number, claimedBy?: string, opts?: DaemonLeaseFence): LoopRun | undefined;
258
+ /**
259
+ * Record the spawned child's process identity (pid, process group id, start
260
+ * time) so recovery can signal the whole process group later.
261
+ */
262
+ recordRunProcess(runId: string, info: RecordRunProcessInput, opts?: DaemonLeaseFence): LoopRun | undefined;
218
263
  private hasLiveWorkflowStepProcesses;
219
264
  createSkippedRun(loop: Loop, scheduledFor: string, reason: string, opts?: DaemonLeaseFence): LoopRun;
220
265
  getRun(id: string): LoopRun | undefined;
@@ -237,12 +282,30 @@ export declare class Store {
237
282
  limit?: number;
238
283
  scanLimit?: number;
239
284
  }): LoopRun[];
285
+ /**
286
+ * Recover expired run leases and report both outcomes: runs abandoned (no
287
+ * live process) and runs deferred because their process (group) is still
288
+ * alive. Entries carry pid/pgid/processStartedAt so the daemon can signal
289
+ * orphaned process groups (SIGTERM then SIGKILL) after recovery.
290
+ */
291
+ recoverExpiredRunLeasesDetailed(now?: Date, opts?: DaemonLeaseFence & {
292
+ limit?: number;
293
+ scanLimit?: number;
294
+ }): RecoverExpiredRunLeasesResult;
240
295
  expireLoops(now?: Date, opts?: DaemonLeaseFence): Loop[];
241
296
  countLoops(status?: LoopStatus, opts?: {
242
297
  archived?: boolean;
243
298
  includeArchived?: boolean;
244
299
  }): number;
245
300
  countRuns(status?: RunStatus): number;
301
+ /**
302
+ * Delete old terminal run history: loop runs plus their attached workflow
303
+ * runs (step runs and events cascade), goal run events, and per-run manifest
304
+ * directories. At least one of maxAgeDays / keepPerLoop must be provided;
305
+ * when both are given a run is only deleted when it is older than the cutoff
306
+ * AND beyond the per-loop retention floor. Running runs are never touched.
307
+ */
308
+ pruneHistory(opts: PruneHistoryOptions): PruneHistorySummary;
246
309
  acquireDaemonLease(input: {
247
310
  id: string;
248
311
  pid: number;