@hasna/loops 0.4.28 → 0.4.29

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 (77) hide show
  1. package/CHANGELOG.md +84 -1
  2. package/README.md +226 -49
  3. package/dist/api/index.d.ts +20 -19
  4. package/dist/api/index.js +6846 -1087
  5. package/dist/cli/index.js +2471 -885
  6. package/dist/cli/safe-error-context.d.ts +1 -0
  7. package/dist/daemon/daemon.d.ts +1 -0
  8. package/dist/daemon/index.js +1786 -493
  9. package/dist/generated/storage-kit/index.d.ts +1 -1
  10. package/dist/generated/storage-kit/mode.d.ts +6 -12
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +4778 -1016
  13. package/dist/lib/advancement.d.ts +52 -0
  14. package/dist/lib/agent-adapter.d.ts +20 -2
  15. package/dist/lib/auth/route-policy.d.ts +14 -0
  16. package/dist/lib/auth/tenant-auth.d.ts +38 -0
  17. package/dist/lib/cloud/mode.d.ts +2 -8
  18. package/dist/lib/cloud/storage.d.ts +1 -2
  19. package/dist/lib/cloud/transport.d.ts +4 -18
  20. package/dist/lib/errors.d.ts +43 -1
  21. package/dist/lib/format.d.ts +2 -2
  22. package/dist/lib/goal/runner.d.ts +36 -3
  23. package/dist/lib/health.d.ts +1 -1
  24. package/dist/lib/labels.d.ts +4 -0
  25. package/dist/lib/loop-status.d.ts +4 -0
  26. package/dist/lib/migration.d.ts +4 -17
  27. package/dist/lib/mode.d.ts +2 -5
  28. package/dist/lib/mode.js +27 -36
  29. package/dist/lib/route/index.d.ts +2 -2
  30. package/dist/lib/route/throttle.d.ts +7 -0
  31. package/dist/lib/route/types.d.ts +3 -0
  32. package/dist/lib/run-completion.d.ts +18 -0
  33. package/dist/lib/scheduler.d.ts +5 -11
  34. package/dist/lib/storage/contract.d.ts +15 -1
  35. package/dist/lib/storage/index.d.ts +1 -1
  36. package/dist/lib/storage/index.js +3864 -457
  37. package/dist/lib/storage/pg-executor.d.ts +10 -5
  38. package/dist/lib/storage/postgres-loop-storage.d.ts +50 -24
  39. package/dist/lib/storage/postgres-schema.d.ts +8 -0
  40. package/dist/lib/storage/postgres-schema.js +1323 -1
  41. package/dist/lib/storage/postgres.d.ts +3 -1
  42. package/dist/lib/storage/postgres.js +1353 -27
  43. package/dist/lib/storage/provider-credentials.d.ts +84 -0
  44. package/dist/lib/storage/shared-database-transfer.d.ts +136 -0
  45. package/dist/lib/storage/sqlite.d.ts +15 -2
  46. package/dist/lib/storage/sqlite.js +1299 -217
  47. package/dist/lib/storage/tenant-backfill-s3.d.ts +53 -0
  48. package/dist/lib/storage/tenant-backfill.d.ts +40 -0
  49. package/dist/lib/store/index.d.ts +11 -8
  50. package/dist/lib/store.d.ts +52 -7
  51. package/dist/lib/store.js +1266 -217
  52. package/dist/lib/templates.d.ts +11 -0
  53. package/dist/lib/workflow-events.d.ts +6 -0
  54. package/dist/lib/workflow-provenance.d.ts +8 -0
  55. package/dist/lib/workflow-runner.d.ts +52 -4
  56. package/dist/mcp/index.js +1961 -651
  57. package/dist/runner/index.d.ts +20 -2
  58. package/dist/runner/index.js +2113 -177
  59. package/dist/sdk/http.d.ts +211 -3
  60. package/dist/sdk/http.js +301 -0
  61. package/dist/sdk/index.d.ts +7 -2
  62. package/dist/sdk/index.js +1959 -711
  63. package/dist/serve/index.d.ts +14 -0
  64. package/dist/serve/index.js +12323 -1743
  65. package/dist/types.d.ts +64 -3
  66. package/docs/AUTOMATION_RUNTIME_DESIGN.md +32 -32
  67. package/docs/CUTOVER-RUNBOOK.md +158 -31
  68. package/docs/DEPLOYMENT_MODES.md +78 -56
  69. package/docs/RUNTIME_BOUNDARY.md +26 -26
  70. package/docs/SHARED-DATABASE-TRANSFER.md +95 -0
  71. package/docs/SHARED_KIT_EXTRACTION_INVENTORY.md +631 -0
  72. package/docs/TRANSCRIPT_LOOP_PATTERNS.md +3 -3
  73. package/docs/UNIFIED_PRODUCT_CONTRACT.md +365 -0
  74. package/docs/USAGE.md +143 -52
  75. package/docs/workflows/transcript-feedback-to-loops.json +2 -2
  76. package/package.json +7 -3
  77. package/dist/lib/storage/pg-runner-claim.d.ts +0 -40
@@ -0,0 +1,18 @@
1
+ export interface RunCompletionInput {
2
+ startedAt: string;
3
+ requestedFinishedAt?: string;
4
+ requestedDurationMs?: number;
5
+ serverNow: Date;
6
+ }
7
+ export interface NormalizedRunCompletion {
8
+ finishedAt: string;
9
+ durationMs: number | undefined;
10
+ updatedAt: string;
11
+ }
12
+ /**
13
+ * Treat the control-plane clock as authoritative while retaining a bounded
14
+ * runner timestamp as evidence. In the normal case, where startedAt is not
15
+ * ahead of the server clock, finishedAt is clamped into [startedAt, serverNow].
16
+ * A backwards server-clock jump fails safe at serverNow and yields duration 0.
17
+ */
18
+ export declare function normalizeRunCompletion(input: RunCompletionInput): NormalizedRunCompletion;
@@ -1,5 +1,7 @@
1
1
  import type { ExecutorResult, Loop, LoopRun } from "../types.js";
2
+ import { type CircuitBreakerThreshold } from "./advancement.js";
2
3
  import type { Store } from "./store.js";
4
+ export { CIRCUIT_BREAKER_REASON_PREFIX, DEFAULT_CIRCUIT_BREAKER_THRESHOLD, MAX_RETRY_DELAY_MS, retryBackoffDelayMs, } from "./advancement.js";
3
5
  export interface SchedulerDeps {
4
6
  store: Store;
5
7
  runnerId: string;
@@ -25,6 +27,7 @@ export interface TickResult {
25
27
  export interface ClaimedLoopRun {
26
28
  loop: Loop;
27
29
  run: LoopRun;
30
+ claimToken: string;
28
31
  }
29
32
  export interface ClaimDueRunsResult extends TickResult {
30
33
  claims: ClaimedLoopRun[];
@@ -90,21 +93,11 @@ export declare function runLoopNow(deps: RunLoopNowDeps & {
90
93
  export declare function runLoopNow(deps: RunLoopNowDeps & {
91
94
  mode?: "inline";
92
95
  }): Promise<RunLoopNowExecuted>;
93
- export declare const MAX_RETRY_DELAY_MS: number;
94
- export declare const DEFAULT_CIRCUIT_BREAKER_THRESHOLD = 5;
95
- export declare const CIRCUIT_BREAKER_REASON_PREFIX = "circuit breaker open";
96
96
  export declare const MAX_SKIPS_PER_LOOP_PER_TICK = 10;
97
- /**
98
- * Exponential retry backoff with jitter:
99
- * delay = retryDelayMs * 2^(attempt-1) * (0.5 + random), capped at 6h.
100
- * Failures classified as provider-gated back off 4x harder, since hammering
101
- * a throttled, misconfigured, or unavailable provider only makes things worse.
102
- */
103
- export declare function retryBackoffDelayMs(loop: Loop, run: LoopRun, random?: () => number): number;
104
97
  export interface AdvanceLoopOptions {
105
98
  daemonLeaseId?: string;
106
99
  random?: () => number;
107
- circuitBreakerThreshold?: number | ((loop: Loop) => number | undefined);
100
+ circuitBreakerThreshold?: CircuitBreakerThreshold;
108
101
  onRun?: (run: LoopRun) => void;
109
102
  }
110
103
  /**
@@ -123,6 +116,7 @@ export declare function advanceLoop(store: Store, loop: Loop, run: LoopRun, fini
123
116
  export declare function executeClaimedRun(deps: {
124
117
  store: Store;
125
118
  runnerId: string;
119
+ claimToken: string;
126
120
  loop: Loop;
127
121
  run: LoopRun;
128
122
  now?: () => Date;
@@ -1,6 +1,6 @@
1
1
  import type { Store } from "../store.js";
2
2
  export type LoopStorageBackend = "sqlite" | "postgres";
3
- export type LoopStorageMethodName = "createLoop" | "getLoop" | "findLoopByName" | "requireLoop" | "listLoops" | "dueLoops" | "updateLoop" | "renameLoop" | "archiveLoop" | "unarchiveLoop" | "deleteLoop" | "upsertMigrationLoop" | "upsertMigrationRun" | "upsertMigrationWorkflow" | "createWorkflow" | "getWorkflow" | "listWorkflows" | "countWorkflows" | "archiveWorkflow" | "createWorkflowInvocation" | "getWorkflowInvocation" | "listWorkflowInvocations" | "upsertWorkflowWorkItem" | "getWorkflowWorkItem" | "listWorkflowWorkItems" | "countActiveWorkflowWorkItems" | "admitWorkflowWorkItem" | "createGoal" | "getGoal" | "listGoals" | "createGoalPlanNodes" | "listGoalPlanNodes" | "updateGoalStatus" | "updateGoalPlanNode" | "recordGoalEvent" | "listGoalRuns" | "createWorkflowRun" | "getWorkflowRun" | "listWorkflowRuns" | "listWorkflowStepRuns" | "getWorkflowStepRun" | "startWorkflowStepRun" | "recoverWorkflowRun" | "finalizeWorkflowStepRun" | "finalizeWorkflowRun" | "appendWorkflowEvent" | "listWorkflowEvents" | "recordRunProcess" | "createSkippedRun" | "getRun" | "getRunBySlot" | "claimRun" | "finalizeRun" | "heartbeatRunLease" | "listRuns" | "writeRunReceipt" | "getRunReceipt" | "listRunReceipts" | "recoverExpiredRunLeases" | "recoverExpiredRunLeasesDetailed" | "countLoops" | "countRuns" | "pruneHistory" | "acquireDaemonLease" | "heartbeatDaemonLease" | "releaseDaemonLease" | "getDaemonLease";
3
+ export type LoopStorageMethodName = "createLoop" | "getLoop" | "findLoopByName" | "requireLoop" | "requireUniqueLoop" | "listLoops" | "dueLoops" | "updateLoop" | "advanceLoopIfCurrent" | "tripCircuitBreakerIfCurrent" | "renameLoop" | "archiveLoop" | "unarchiveLoop" | "deleteLoop" | "upsertMigrationLoop" | "upsertMigrationRun" | "upsertMigrationWorkflow" | "createWorkflow" | "getWorkflow" | "requireWorkflow" | "listWorkflows" | "countWorkflows" | "archiveWorkflow" | "createWorkflowInvocation" | "getWorkflowInvocation" | "listWorkflowInvocations" | "upsertWorkflowWorkItem" | "getWorkflowWorkItem" | "listWorkflowWorkItems" | "countActiveWorkflowWorkItems" | "admitWorkflowWorkItem" | "createGoal" | "getGoal" | "requireGoal" | "findGoalByContext" | "listGoals" | "createGoalPlanNodes" | "listGoalPlanNodes" | "updateGoalStatus" | "updateGoalPlanNode" | "recordGoalEvent" | "listGoalRuns" | "createWorkflowRun" | "getWorkflowRun" | "requireWorkflowRun" | "listWorkflowRuns" | "listWorkflowStepRuns" | "getWorkflowStepRun" | "isWorkflowRunTerminal" | "startWorkflowStepRun" | "markWorkflowStepPid" | "recordWorkflowStepProgress" | "recoverWorkflowRun" | "finalizeWorkflowStepRun" | "skipWorkflowStepRun" | "finalizeWorkflowRun" | "appendWorkflowEvent" | "listWorkflowEvents" | "recordRunProcess" | "createSkippedRun" | "getRun" | "getRunBySlot" | "nextRetryableRun" | "claimRun" | "finalizeRun" | "heartbeatRunLease" | "listRuns" | "listRecoveredLeaseRunsPage" | "writeRunReceipt" | "getRunReceipt" | "listRunReceipts" | "recoverExpiredRunLeases" | "recoverExpiredRunLeasesDetailed" | "countLoops" | "countRuns" | "pruneHistory" | "acquireDaemonLease" | "heartbeatDaemonLease" | "releaseDaemonLease" | "getDaemonLease";
4
4
  type AsyncStoreMethod<K extends LoopStorageMethodName> = Store[K] extends (...args: infer Args) => infer Result ? (...args: Args) => Promise<Result> : never;
5
5
  export interface LoopStorageContract extends Record<LoopStorageMethodName, (...args: never[]) => Promise<unknown>> {
6
6
  readonly backend: LoopStorageBackend;
@@ -10,9 +10,12 @@ export interface LoopStorageContract extends Record<LoopStorageMethodName, (...a
10
10
  getLoop: AsyncStoreMethod<"getLoop">;
11
11
  findLoopByName: AsyncStoreMethod<"findLoopByName">;
12
12
  requireLoop: AsyncStoreMethod<"requireLoop">;
13
+ requireUniqueLoop: AsyncStoreMethod<"requireUniqueLoop">;
13
14
  listLoops: AsyncStoreMethod<"listLoops">;
14
15
  dueLoops: AsyncStoreMethod<"dueLoops">;
15
16
  updateLoop: AsyncStoreMethod<"updateLoop">;
17
+ advanceLoopIfCurrent: AsyncStoreMethod<"advanceLoopIfCurrent">;
18
+ tripCircuitBreakerIfCurrent: AsyncStoreMethod<"tripCircuitBreakerIfCurrent">;
16
19
  renameLoop: AsyncStoreMethod<"renameLoop">;
17
20
  archiveLoop: AsyncStoreMethod<"archiveLoop">;
18
21
  unarchiveLoop: AsyncStoreMethod<"unarchiveLoop">;
@@ -22,6 +25,7 @@ export interface LoopStorageContract extends Record<LoopStorageMethodName, (...a
22
25
  upsertMigrationWorkflow: AsyncStoreMethod<"upsertMigrationWorkflow">;
23
26
  createWorkflow: AsyncStoreMethod<"createWorkflow">;
24
27
  getWorkflow: AsyncStoreMethod<"getWorkflow">;
28
+ requireWorkflow: AsyncStoreMethod<"requireWorkflow">;
25
29
  listWorkflows: AsyncStoreMethod<"listWorkflows">;
26
30
  countWorkflows: AsyncStoreMethod<"countWorkflows">;
27
31
  archiveWorkflow: AsyncStoreMethod<"archiveWorkflow">;
@@ -35,6 +39,8 @@ export interface LoopStorageContract extends Record<LoopStorageMethodName, (...a
35
39
  admitWorkflowWorkItem: AsyncStoreMethod<"admitWorkflowWorkItem">;
36
40
  createGoal: AsyncStoreMethod<"createGoal">;
37
41
  getGoal: AsyncStoreMethod<"getGoal">;
42
+ requireGoal: AsyncStoreMethod<"requireGoal">;
43
+ findGoalByContext: AsyncStoreMethod<"findGoalByContext">;
38
44
  listGoals: AsyncStoreMethod<"listGoals">;
39
45
  createGoalPlanNodes: AsyncStoreMethod<"createGoalPlanNodes">;
40
46
  listGoalPlanNodes: AsyncStoreMethod<"listGoalPlanNodes">;
@@ -44,12 +50,17 @@ export interface LoopStorageContract extends Record<LoopStorageMethodName, (...a
44
50
  listGoalRuns: AsyncStoreMethod<"listGoalRuns">;
45
51
  createWorkflowRun: AsyncStoreMethod<"createWorkflowRun">;
46
52
  getWorkflowRun: AsyncStoreMethod<"getWorkflowRun">;
53
+ requireWorkflowRun: AsyncStoreMethod<"requireWorkflowRun">;
47
54
  listWorkflowRuns: AsyncStoreMethod<"listWorkflowRuns">;
48
55
  listWorkflowStepRuns: AsyncStoreMethod<"listWorkflowStepRuns">;
49
56
  getWorkflowStepRun: AsyncStoreMethod<"getWorkflowStepRun">;
57
+ isWorkflowRunTerminal: AsyncStoreMethod<"isWorkflowRunTerminal">;
50
58
  startWorkflowStepRun: AsyncStoreMethod<"startWorkflowStepRun">;
59
+ markWorkflowStepPid: AsyncStoreMethod<"markWorkflowStepPid">;
60
+ recordWorkflowStepProgress: AsyncStoreMethod<"recordWorkflowStepProgress">;
51
61
  recoverWorkflowRun: AsyncStoreMethod<"recoverWorkflowRun">;
52
62
  finalizeWorkflowStepRun: AsyncStoreMethod<"finalizeWorkflowStepRun">;
63
+ skipWorkflowStepRun: AsyncStoreMethod<"skipWorkflowStepRun">;
53
64
  finalizeWorkflowRun: AsyncStoreMethod<"finalizeWorkflowRun">;
54
65
  appendWorkflowEvent: AsyncStoreMethod<"appendWorkflowEvent">;
55
66
  listWorkflowEvents: AsyncStoreMethod<"listWorkflowEvents">;
@@ -57,10 +68,12 @@ export interface LoopStorageContract extends Record<LoopStorageMethodName, (...a
57
68
  createSkippedRun: AsyncStoreMethod<"createSkippedRun">;
58
69
  getRun: AsyncStoreMethod<"getRun">;
59
70
  getRunBySlot: AsyncStoreMethod<"getRunBySlot">;
71
+ nextRetryableRun: AsyncStoreMethod<"nextRetryableRun">;
60
72
  claimRun: AsyncStoreMethod<"claimRun">;
61
73
  finalizeRun: AsyncStoreMethod<"finalizeRun">;
62
74
  heartbeatRunLease: AsyncStoreMethod<"heartbeatRunLease">;
63
75
  listRuns: AsyncStoreMethod<"listRuns">;
76
+ listRecoveredLeaseRunsPage: AsyncStoreMethod<"listRecoveredLeaseRunsPage">;
64
77
  writeRunReceipt: AsyncStoreMethod<"writeRunReceipt">;
65
78
  getRunReceipt: AsyncStoreMethod<"getRunReceipt">;
66
79
  listRunReceipts: AsyncStoreMethod<"listRunReceipts">;
@@ -100,6 +113,7 @@ export interface SchemaMigrationStorage {
100
113
  listAppliedMigrations(): Promise<AppliedStorageMigration[]>;
101
114
  migrate(opts?: {
102
115
  dryRun?: boolean;
116
+ through?: string;
103
117
  }): Promise<StorageMigrationResult>;
104
118
  close(): Promise<void>;
105
119
  }
@@ -2,6 +2,6 @@ export type { AppliedStorageMigration, AuditEventRecord, LoopStorageBackend, Loo
2
2
  export { SqliteLoopStorage, createSqliteLoopStorage } from "./sqlite.js";
3
3
  export { PostgresStorage, createPostgresStorage } from "./postgres.js";
4
4
  export type { PostgresQueryExecutor } from "./postgres.js";
5
- export { PostgresLoopStorage, createPostgresLoopStorage, NotImplementedError, } from "./postgres-loop-storage.js";
5
+ export { PostgresLoopStorage, createPostgresLoopStorage, } from "./postgres-loop-storage.js";
6
6
  export { POSTGRES_MIGRATION_LEDGER_TABLE, POSTGRES_STORAGE_MIGRATIONS, checksumStorageSql, } from "./postgres-schema.js";
7
7
  export { Store } from "../store.js";