@hasna/loops 0.4.14 → 0.4.23
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.
- package/CHANGELOG.md +25 -0
- package/README.md +119 -29
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +825 -7
- package/dist/cli/index.js +5423 -2619
- package/dist/daemon/index.js +478 -84
- package/dist/generated/storage-kit/index.d.ts +1 -1
- package/dist/index.js +2521 -226
- package/dist/lib/cloud/mode.d.ts +17 -0
- package/dist/lib/cloud/resolve.d.ts +16 -0
- package/dist/lib/cloud/storage.d.ts +82 -0
- package/dist/lib/cloud/transport.d.ts +148 -0
- package/dist/lib/format.d.ts +2 -1
- package/dist/lib/migration.d.ts +40 -0
- package/dist/lib/mode.js +3 -3
- package/dist/lib/route/index.d.ts +2 -0
- package/dist/lib/route/policies.d.ts +51 -0
- package/dist/lib/route/provider-admission.d.ts +37 -0
- package/dist/lib/route/throttle.d.ts +4 -0
- package/dist/lib/route/types.d.ts +8 -0
- package/dist/lib/run-receipts.d.ts +14 -0
- package/dist/lib/storage/contract.d.ts +7 -1
- package/dist/lib/storage/index.js +710 -31
- package/dist/lib/storage/postgres-loop-storage.d.ts +6 -0
- package/dist/lib/storage/postgres-schema.js +29 -0
- package/dist/lib/storage/postgres.js +29 -0
- package/dist/lib/storage/sqlite.d.ts +6 -0
- package/dist/lib/storage/sqlite.js +412 -18
- package/dist/lib/store/index.d.ts +268 -0
- package/dist/lib/store.d.ts +48 -1
- package/dist/lib/store.js +396 -18
- package/dist/lib/template-kit.d.ts +25 -0
- package/dist/lib/templates.d.ts +16 -1
- package/dist/mcp/http.d.ts +16 -0
- package/dist/mcp/index.js +1658 -168
- package/dist/runner/index.js +76 -9
- package/dist/sdk/http.d.ts +67 -0
- package/dist/sdk/http.js +21 -0
- package/dist/sdk/index.d.ts +50 -17
- package/dist/sdk/index.js +1509 -132
- package/dist/serve/index.js +1598 -122
- package/dist/types.d.ts +49 -0
- package/docs/AUTOMATION_RUNTIME_DESIGN.md +442 -1
- package/docs/CUTOVER-RUNBOOK.md +73 -56
- package/docs/DEPLOYMENT_MODES.md +35 -18
- package/docs/RUNTIME_BOUNDARY.md +203 -0
- package/docs/USAGE.md +145 -27
- package/package.json +3 -3
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type { CreateLoopInput, CreateWorkflowInput, Loop, LoopRun, LoopStatus, RunReceipt, RunStatus, WorkflowEvent, WorkflowInvocation, WorkflowRun, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, WriteRunReceiptInput } from "../../types.js";
|
|
2
|
+
import type { Goal, GoalPlanNode, GoalRun, GoalStatus } from "../goal/types.js";
|
|
3
|
+
import type { HasnaStorageClient } from "../cloud/storage.js";
|
|
4
|
+
import type { Env } from "../cloud/mode.js";
|
|
5
|
+
import { Store } from "../store.js";
|
|
6
|
+
import type { PruneHistoryOptions, PruneHistorySummary } from "../store.js";
|
|
7
|
+
/** Which transport backs a resolved store (for banners/diagnostics only). */
|
|
8
|
+
export type StoreTransport = "local" | "cloud-http";
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when a command routed through the cloud ApiStore hits an operation that
|
|
11
|
+
* the hosted `/v1` API does not yet expose. Failing loudly here is deliberate:
|
|
12
|
+
* the alternative (silently reading/writing the on-box sqlite island while the
|
|
13
|
+
* machine is flipped to cloud) is exactly the split-brain bug we are removing.
|
|
14
|
+
*/
|
|
15
|
+
export declare class CloudUnsupportedError extends Error {
|
|
16
|
+
constructor(operation: string);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The single data interface for the OpenLoops client. Both {@link LocalStore}
|
|
20
|
+
* and {@link ApiStore} implement it; callers hold a `LoopStore` and never know
|
|
21
|
+
* (or branch on) which one. Every method is async so the two transports share
|
|
22
|
+
* one surface.
|
|
23
|
+
*/
|
|
24
|
+
export interface LoopStore {
|
|
25
|
+
readonly transport: StoreTransport;
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
createLoop(input: CreateLoopInput, from?: Date): Promise<Loop>;
|
|
28
|
+
getLoop(id: string): Promise<Loop | undefined>;
|
|
29
|
+
findLoopByName(name: string): Promise<Loop | undefined>;
|
|
30
|
+
requireLoop(idOrName: string): Promise<Loop>;
|
|
31
|
+
requireUniqueLoop(idOrName: string): Promise<Loop>;
|
|
32
|
+
listLoops(opts?: {
|
|
33
|
+
status?: LoopStatus;
|
|
34
|
+
limit?: number;
|
|
35
|
+
offset?: number;
|
|
36
|
+
archived?: boolean;
|
|
37
|
+
includeArchived?: boolean;
|
|
38
|
+
name?: string;
|
|
39
|
+
}): Promise<Loop[]>;
|
|
40
|
+
countLoops(status?: LoopStatus, opts?: {
|
|
41
|
+
archived?: boolean;
|
|
42
|
+
includeArchived?: boolean;
|
|
43
|
+
}): Promise<number>;
|
|
44
|
+
updateLoop(id: string, patch: Partial<Pick<Loop, "status" | "nextRunAt" | "retryScheduledFor" | "expiresAt">>): Promise<Loop>;
|
|
45
|
+
renameLoop(id: string, name: string): Promise<Loop>;
|
|
46
|
+
archiveLoop(idOrName: string): Promise<Loop>;
|
|
47
|
+
unarchiveLoop(idOrName: string): Promise<Loop>;
|
|
48
|
+
deleteLoop(idOrName: string): Promise<boolean>;
|
|
49
|
+
createWorkflow(input: CreateWorkflowInput): Promise<WorkflowSpec>;
|
|
50
|
+
getWorkflow(id: string): Promise<WorkflowSpec | undefined>;
|
|
51
|
+
findWorkflowByName(name: string): Promise<WorkflowSpec | undefined>;
|
|
52
|
+
requireWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
53
|
+
listWorkflows(opts?: {
|
|
54
|
+
status?: WorkflowSpec["status"];
|
|
55
|
+
limit?: number;
|
|
56
|
+
offset?: number;
|
|
57
|
+
}): Promise<WorkflowSpec[]>;
|
|
58
|
+
countWorkflows(opts?: {
|
|
59
|
+
status?: WorkflowSpec["status"];
|
|
60
|
+
}): Promise<number>;
|
|
61
|
+
archiveWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
62
|
+
getWorkflowRun(id: string): Promise<WorkflowRun | undefined>;
|
|
63
|
+
requireWorkflowRun(id: string): Promise<WorkflowRun>;
|
|
64
|
+
listWorkflowRuns(opts?: {
|
|
65
|
+
workflowId?: string;
|
|
66
|
+
loopRunId?: string;
|
|
67
|
+
limit?: number;
|
|
68
|
+
}): Promise<WorkflowRun[]>;
|
|
69
|
+
listWorkflowStepRuns(workflowRunId: string): Promise<WorkflowStepRun[]>;
|
|
70
|
+
listWorkflowEvents(workflowRunId: string, limit?: number): Promise<WorkflowEvent[]>;
|
|
71
|
+
recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{
|
|
72
|
+
run: WorkflowRun;
|
|
73
|
+
recoveredSteps: WorkflowStepRun[];
|
|
74
|
+
}>;
|
|
75
|
+
cancelWorkflowRun(workflowRunId: string, reason?: string): Promise<WorkflowRun>;
|
|
76
|
+
listWorkflowWorkItems(opts?: {
|
|
77
|
+
status?: WorkflowWorkItemStatus;
|
|
78
|
+
routeKey?: string;
|
|
79
|
+
limit?: number;
|
|
80
|
+
}): Promise<WorkflowWorkItem[]>;
|
|
81
|
+
getWorkflowWorkItem(id: string): Promise<WorkflowWorkItem | undefined>;
|
|
82
|
+
requeueWorkflowWorkItem(id: string, patch?: {
|
|
83
|
+
reason?: string;
|
|
84
|
+
}): Promise<WorkflowWorkItem>;
|
|
85
|
+
listWorkflowInvocations(opts?: {
|
|
86
|
+
limit?: number;
|
|
87
|
+
}): Promise<WorkflowInvocation[]>;
|
|
88
|
+
getWorkflowInvocation(id: string): Promise<WorkflowInvocation | undefined>;
|
|
89
|
+
getGoal(id: string): Promise<Goal | undefined>;
|
|
90
|
+
findGoalByLoop(idOrName: string): Promise<Goal | undefined>;
|
|
91
|
+
findGoalByRunId(id: string): Promise<Goal | undefined>;
|
|
92
|
+
listGoals(opts?: {
|
|
93
|
+
status?: GoalStatus;
|
|
94
|
+
limit?: number;
|
|
95
|
+
}): Promise<Goal[]>;
|
|
96
|
+
listGoalPlanNodes(goalIdOrPlanId: string): Promise<GoalPlanNode[]>;
|
|
97
|
+
listGoalRuns(opts?: {
|
|
98
|
+
goalId?: string;
|
|
99
|
+
runId?: string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
}): Promise<GoalRun[]>;
|
|
102
|
+
listRuns(opts?: {
|
|
103
|
+
loopId?: string;
|
|
104
|
+
status?: RunStatus;
|
|
105
|
+
limit?: number;
|
|
106
|
+
offset?: number;
|
|
107
|
+
}): Promise<LoopRun[]>;
|
|
108
|
+
getRun(id: string): Promise<LoopRun | undefined>;
|
|
109
|
+
writeRunReceipt(input: WriteRunReceiptInput): Promise<RunReceipt>;
|
|
110
|
+
getRunReceipt(runId: string): Promise<RunReceipt | undefined>;
|
|
111
|
+
listRunReceipts(opts?: {
|
|
112
|
+
loopId?: string;
|
|
113
|
+
repo?: string;
|
|
114
|
+
taskId?: string;
|
|
115
|
+
knowledgeId?: string;
|
|
116
|
+
status?: string;
|
|
117
|
+
limit?: number;
|
|
118
|
+
}): Promise<RunReceipt[]>;
|
|
119
|
+
pruneHistory(opts: PruneHistoryOptions): Promise<PruneHistorySummary>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* On-box SQLite transport. Wraps a single {@link Store} and awaits its
|
|
123
|
+
* synchronous methods so callers see the async {@link LoopStore} surface.
|
|
124
|
+
*/
|
|
125
|
+
export declare class LocalStore implements LoopStore {
|
|
126
|
+
readonly transport: "local";
|
|
127
|
+
private readonly store;
|
|
128
|
+
constructor(store?: Store);
|
|
129
|
+
/**
|
|
130
|
+
* The underlying on-box sqlite {@link Store}. Exposed ONLY for genuinely
|
|
131
|
+
* local-runtime operations that cannot route over HTTP — the scheduler
|
|
132
|
+
* (tick/run-now inline execution), migration import/export, and local
|
|
133
|
+
* diagnostics (doctor/health/daemon status). Callers must gate on
|
|
134
|
+
* `transport === "local"` first; the hosted ApiStore has no `raw` store, so
|
|
135
|
+
* these operations fail loudly in cloud mode instead of touching an island.
|
|
136
|
+
*/
|
|
137
|
+
get raw(): Store;
|
|
138
|
+
close(): Promise<void>;
|
|
139
|
+
createLoop(input: CreateLoopInput, from?: Date): Promise<Loop>;
|
|
140
|
+
getLoop(id: string): Promise<Loop | undefined>;
|
|
141
|
+
findLoopByName(name: string): Promise<Loop | undefined>;
|
|
142
|
+
requireLoop(idOrName: string): Promise<Loop>;
|
|
143
|
+
requireUniqueLoop(idOrName: string): Promise<Loop>;
|
|
144
|
+
listLoops(opts?: Parameters<Store["listLoops"]>[0]): Promise<Loop[]>;
|
|
145
|
+
countLoops(status?: LoopStatus, opts?: {
|
|
146
|
+
archived?: boolean;
|
|
147
|
+
includeArchived?: boolean;
|
|
148
|
+
}): Promise<number>;
|
|
149
|
+
updateLoop(id: string, patch: Partial<Pick<Loop, "status" | "nextRunAt" | "retryScheduledFor" | "expiresAt">>): Promise<Loop>;
|
|
150
|
+
renameLoop(id: string, name: string): Promise<Loop>;
|
|
151
|
+
archiveLoop(idOrName: string): Promise<Loop>;
|
|
152
|
+
unarchiveLoop(idOrName: string): Promise<Loop>;
|
|
153
|
+
deleteLoop(idOrName: string): Promise<boolean>;
|
|
154
|
+
createWorkflow(input: CreateWorkflowInput): Promise<WorkflowSpec>;
|
|
155
|
+
getWorkflow(id: string): Promise<WorkflowSpec | undefined>;
|
|
156
|
+
findWorkflowByName(name: string): Promise<WorkflowSpec | undefined>;
|
|
157
|
+
requireWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
158
|
+
listWorkflows(opts?: Parameters<Store["listWorkflows"]>[0]): Promise<WorkflowSpec[]>;
|
|
159
|
+
countWorkflows(opts?: {
|
|
160
|
+
status?: WorkflowSpec["status"];
|
|
161
|
+
}): Promise<number>;
|
|
162
|
+
archiveWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
163
|
+
getWorkflowRun(id: string): Promise<WorkflowRun | undefined>;
|
|
164
|
+
requireWorkflowRun(id: string): Promise<WorkflowRun>;
|
|
165
|
+
listWorkflowRuns(opts?: Parameters<Store["listWorkflowRuns"]>[0]): Promise<WorkflowRun[]>;
|
|
166
|
+
listWorkflowStepRuns(workflowRunId: string): Promise<WorkflowStepRun[]>;
|
|
167
|
+
listWorkflowEvents(workflowRunId: string, limit?: number): Promise<WorkflowEvent[]>;
|
|
168
|
+
recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{
|
|
169
|
+
run: WorkflowRun;
|
|
170
|
+
recoveredSteps: WorkflowStepRun[];
|
|
171
|
+
}>;
|
|
172
|
+
cancelWorkflowRun(workflowRunId: string, reason?: string): Promise<WorkflowRun>;
|
|
173
|
+
listWorkflowWorkItems(opts?: Parameters<Store["listWorkflowWorkItems"]>[0]): Promise<WorkflowWorkItem[]>;
|
|
174
|
+
getWorkflowWorkItem(id: string): Promise<WorkflowWorkItem | undefined>;
|
|
175
|
+
requeueWorkflowWorkItem(id: string, patch?: {
|
|
176
|
+
reason?: string;
|
|
177
|
+
}): Promise<WorkflowWorkItem>;
|
|
178
|
+
listWorkflowInvocations(opts?: Parameters<Store["listWorkflowInvocations"]>[0]): Promise<WorkflowInvocation[]>;
|
|
179
|
+
getWorkflowInvocation(id: string): Promise<WorkflowInvocation | undefined>;
|
|
180
|
+
getGoal(id: string): Promise<Goal | undefined>;
|
|
181
|
+
findGoalByLoop(idOrName: string): Promise<Goal | undefined>;
|
|
182
|
+
findGoalByRunId(id: string): Promise<Goal | undefined>;
|
|
183
|
+
listGoals(opts?: Parameters<Store["listGoals"]>[0]): Promise<Goal[]>;
|
|
184
|
+
listGoalPlanNodes(goalIdOrPlanId: string): Promise<GoalPlanNode[]>;
|
|
185
|
+
listGoalRuns(opts?: Parameters<Store["listGoalRuns"]>[0]): Promise<GoalRun[]>;
|
|
186
|
+
listRuns(opts?: Parameters<Store["listRuns"]>[0]): Promise<LoopRun[]>;
|
|
187
|
+
getRun(id: string): Promise<LoopRun | undefined>;
|
|
188
|
+
writeRunReceipt(input: WriteRunReceiptInput): Promise<RunReceipt>;
|
|
189
|
+
getRunReceipt(runId: string): Promise<RunReceipt | undefined>;
|
|
190
|
+
listRunReceipts(opts?: Parameters<Store["listRunReceipts"]>[0]): Promise<RunReceipt[]>;
|
|
191
|
+
pruneHistory(opts: PruneHistoryOptions): Promise<PruneHistorySummary>;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Self_hosted / cloud transport: routes every read+write through the hosted
|
|
195
|
+
* `/v1` API. Loop/name resolution (requireLoop/requireUniqueLoop/find*) is done
|
|
196
|
+
* client-side by listing and matching, mirroring the local Store behaviour, so a
|
|
197
|
+
* server that ignores a name filter can never return the wrong row.
|
|
198
|
+
*/
|
|
199
|
+
export declare class ApiStore implements LoopStore {
|
|
200
|
+
private readonly client;
|
|
201
|
+
readonly baseUrl: string;
|
|
202
|
+
readonly transport: "cloud-http";
|
|
203
|
+
constructor(client: HasnaStorageClient, baseUrl: string);
|
|
204
|
+
private get t();
|
|
205
|
+
close(): Promise<void>;
|
|
206
|
+
createLoop(input: CreateLoopInput): Promise<Loop>;
|
|
207
|
+
getLoop(id: string): Promise<Loop | undefined>;
|
|
208
|
+
findLoopByName(name: string): Promise<Loop | undefined>;
|
|
209
|
+
requireLoop(idOrName: string): Promise<Loop>;
|
|
210
|
+
requireUniqueLoop(idOrName: string): Promise<Loop>;
|
|
211
|
+
private resolveLoop;
|
|
212
|
+
listLoops(opts?: Parameters<LoopStore["listLoops"]>[0]): Promise<Loop[]>;
|
|
213
|
+
countLoops(status?: LoopStatus, opts?: {
|
|
214
|
+
archived?: boolean;
|
|
215
|
+
includeArchived?: boolean;
|
|
216
|
+
}): Promise<number>;
|
|
217
|
+
updateLoop(id: string, patch: Partial<Pick<Loop, "status" | "nextRunAt" | "retryScheduledFor" | "expiresAt">>): Promise<Loop>;
|
|
218
|
+
renameLoop(id: string, name: string): Promise<Loop>;
|
|
219
|
+
archiveLoop(idOrName: string): Promise<Loop>;
|
|
220
|
+
unarchiveLoop(idOrName: string): Promise<Loop>;
|
|
221
|
+
deleteLoop(idOrName: string): Promise<boolean>;
|
|
222
|
+
createWorkflow(input: CreateWorkflowInput): Promise<WorkflowSpec>;
|
|
223
|
+
getWorkflow(id: string): Promise<WorkflowSpec | undefined>;
|
|
224
|
+
findWorkflowByName(name: string): Promise<WorkflowSpec | undefined>;
|
|
225
|
+
requireWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
226
|
+
listWorkflows(opts?: Parameters<LoopStore["listWorkflows"]>[0]): Promise<WorkflowSpec[]>;
|
|
227
|
+
countWorkflows(opts?: {
|
|
228
|
+
status?: WorkflowSpec["status"];
|
|
229
|
+
}): Promise<number>;
|
|
230
|
+
archiveWorkflow(idOrName: string): Promise<WorkflowSpec>;
|
|
231
|
+
getWorkflowRun(id: string): Promise<WorkflowRun | undefined>;
|
|
232
|
+
requireWorkflowRun(id: string): Promise<WorkflowRun>;
|
|
233
|
+
listWorkflowRuns(opts?: Parameters<LoopStore["listWorkflowRuns"]>[0]): Promise<WorkflowRun[]>;
|
|
234
|
+
listWorkflowStepRuns(workflowRunId: string): Promise<WorkflowStepRun[]>;
|
|
235
|
+
listWorkflowEvents(workflowRunId: string, limit?: number): Promise<WorkflowEvent[]>;
|
|
236
|
+
recoverWorkflowRun(workflowRunId: string, reason?: string): Promise<{
|
|
237
|
+
run: WorkflowRun;
|
|
238
|
+
recoveredSteps: WorkflowStepRun[];
|
|
239
|
+
}>;
|
|
240
|
+
cancelWorkflowRun(_workflowRunId: string, _reason?: string): Promise<WorkflowRun>;
|
|
241
|
+
listWorkflowWorkItems(opts?: Parameters<LoopStore["listWorkflowWorkItems"]>[0]): Promise<WorkflowWorkItem[]>;
|
|
242
|
+
getWorkflowWorkItem(id: string): Promise<WorkflowWorkItem | undefined>;
|
|
243
|
+
requeueWorkflowWorkItem(_id: string, _patch?: {
|
|
244
|
+
reason?: string;
|
|
245
|
+
}): Promise<WorkflowWorkItem>;
|
|
246
|
+
listWorkflowInvocations(opts?: Parameters<LoopStore["listWorkflowInvocations"]>[0]): Promise<WorkflowInvocation[]>;
|
|
247
|
+
getWorkflowInvocation(id: string): Promise<WorkflowInvocation | undefined>;
|
|
248
|
+
getGoal(id: string): Promise<Goal | undefined>;
|
|
249
|
+
findGoalByLoop(idOrName: string): Promise<Goal | undefined>;
|
|
250
|
+
findGoalByRunId(id: string): Promise<Goal | undefined>;
|
|
251
|
+
listGoals(opts?: Parameters<LoopStore["listGoals"]>[0]): Promise<Goal[]>;
|
|
252
|
+
listGoalPlanNodes(goalIdOrPlanId: string): Promise<GoalPlanNode[]>;
|
|
253
|
+
listGoalRuns(opts?: Parameters<LoopStore["listGoalRuns"]>[0]): Promise<GoalRun[]>;
|
|
254
|
+
listRuns(opts?: Parameters<LoopStore["listRuns"]>[0]): Promise<LoopRun[]>;
|
|
255
|
+
getRun(id: string): Promise<LoopRun | undefined>;
|
|
256
|
+
writeRunReceipt(input: WriteRunReceiptInput): Promise<RunReceipt>;
|
|
257
|
+
getRunReceipt(runId: string): Promise<RunReceipt | undefined>;
|
|
258
|
+
listRunReceipts(opts?: Parameters<LoopStore["listRunReceipts"]>[0]): Promise<RunReceipt[]>;
|
|
259
|
+
pruneHistory(opts: PruneHistoryOptions): Promise<PruneHistorySummary>;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Resolve the client store for the current environment: an {@link ApiStore} when
|
|
263
|
+
* the client-flip contract resolves to cloud-http (self_hosted/cloud), else a
|
|
264
|
+
* {@link LocalStore}. Callers hold a {@link LoopStore} and never branch on mode.
|
|
265
|
+
*/
|
|
266
|
+
export declare function getStore(env?: Env): LoopStore;
|
|
267
|
+
/** True when the resolved store is the hosted HTTP transport (cloud/self_hosted). */
|
|
268
|
+
export declare function isCloudStore(env?: Env): boolean;
|
package/dist/lib/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateLoopInput, CreateWorkflowInvocationInput, CreateWorkflowInput, Goal, GoalAutoExecute, GoalPlanNode, GoalRun, GoalStatus, Loop, LoopRun, LoopStatus, RunStatus, TimeoutMs, WorkflowEvent, WorkflowInvocation, WorkflowRun, WorkflowRunStatus, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, UpsertWorkflowWorkItemInput } from "../types.js";
|
|
1
|
+
import type { CreateLoopInput, CreateWorkflowInvocationInput, CreateWorkflowInput, Goal, GoalAutoExecute, GoalPlanNode, GoalRun, GoalStatus, Loop, LoopRun, LoopStatus, RunReceipt, RunStatus, TimeoutMs, WriteRunReceiptInput, WorkflowEvent, WorkflowInvocation, WorkflowRun, WorkflowRunStatus, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, UpsertWorkflowWorkItemInput } from "../types.js";
|
|
2
2
|
interface DaemonLeaseFence {
|
|
3
3
|
daemonLeaseId?: string;
|
|
4
4
|
now?: Date;
|
|
@@ -51,6 +51,23 @@ export interface RunRow {
|
|
|
51
51
|
created_at: string;
|
|
52
52
|
updated_at: string;
|
|
53
53
|
}
|
|
54
|
+
export interface RunReceiptRow {
|
|
55
|
+
loop_id: string;
|
|
56
|
+
run_id: string;
|
|
57
|
+
machine_json: string;
|
|
58
|
+
repo: string;
|
|
59
|
+
task_ids_json: string;
|
|
60
|
+
knowledge_ids_json: string;
|
|
61
|
+
digest_id: string;
|
|
62
|
+
started_at: string | null;
|
|
63
|
+
finished_at: string | null;
|
|
64
|
+
status: string;
|
|
65
|
+
exit_code: number | null;
|
|
66
|
+
summary_json: string;
|
|
67
|
+
evidence_paths_json: string;
|
|
68
|
+
created_at: string;
|
|
69
|
+
updated_at: string;
|
|
70
|
+
}
|
|
54
71
|
export interface WorkflowRow {
|
|
55
72
|
id: string;
|
|
56
73
|
name: string;
|
|
@@ -111,6 +128,7 @@ export interface WorkflowWorkItemRow {
|
|
|
111
128
|
subject_ref: string;
|
|
112
129
|
project_key: string | null;
|
|
113
130
|
project_group: string | null;
|
|
131
|
+
machine_id: string | null;
|
|
114
132
|
route_scope: string | null;
|
|
115
133
|
priority: number;
|
|
116
134
|
status: string;
|
|
@@ -229,6 +247,7 @@ export interface LeaseRow {
|
|
|
229
247
|
}
|
|
230
248
|
export declare function rowToLoop(row: LoopRow): Loop;
|
|
231
249
|
export declare function rowToRun(row: RunRow): LoopRun;
|
|
250
|
+
export declare function rowToRunReceipt(row: RunReceiptRow): RunReceipt;
|
|
232
251
|
export declare function rowToWorkflow(row: WorkflowRow): WorkflowSpec;
|
|
233
252
|
export declare function rowToWorkflowRun(row: WorkflowRunRow): WorkflowRun;
|
|
234
253
|
export declare function rowToWorkflowInvocation(row: WorkflowInvocationRow): WorkflowInvocation;
|
|
@@ -349,6 +368,7 @@ export interface RecordGoalEventInput {
|
|
|
349
368
|
rawResponse?: unknown;
|
|
350
369
|
}
|
|
351
370
|
export declare function workItemStatusForLoopRun(status: RunStatus, attempt: number, maxAttempts: number | undefined): WorkflowWorkItemStatus | undefined;
|
|
371
|
+
export declare function scrubbedOrNull(value: string | undefined | null): string | null;
|
|
352
372
|
/** Scrub secrets then bound size before persisting run stdout/stderr. */
|
|
353
373
|
export declare function persistedRunOutput(value: string | undefined | null): string | null;
|
|
354
374
|
export declare class Store {
|
|
@@ -360,6 +380,7 @@ export declare class Store {
|
|
|
360
380
|
private migrate;
|
|
361
381
|
private migrations;
|
|
362
382
|
private createBaseSchema;
|
|
383
|
+
private createRunReceiptsSchema;
|
|
363
384
|
/**
|
|
364
385
|
* Add a column only if it does not already exist. Idempotent — avoids the
|
|
365
386
|
* "duplicate column name" error that SQLite logs (via libsqlite3, before any
|
|
@@ -381,8 +402,10 @@ export declare class Store {
|
|
|
381
402
|
listLoops(opts?: {
|
|
382
403
|
status?: LoopStatus;
|
|
383
404
|
limit?: number;
|
|
405
|
+
offset?: number;
|
|
384
406
|
archived?: boolean;
|
|
385
407
|
includeArchived?: boolean;
|
|
408
|
+
name?: string;
|
|
386
409
|
}): Loop[];
|
|
387
410
|
private withLatestRunSummaries;
|
|
388
411
|
dueLoops(now: Date, limit?: number): Loop[];
|
|
@@ -566,7 +589,20 @@ export declare class Store {
|
|
|
566
589
|
loopId?: string;
|
|
567
590
|
status?: RunStatus;
|
|
568
591
|
limit?: number;
|
|
592
|
+
offset?: number;
|
|
569
593
|
}): LoopRun[];
|
|
594
|
+
writeRunReceipt(input: WriteRunReceiptInput, opts?: {
|
|
595
|
+
now?: Date;
|
|
596
|
+
}): RunReceipt;
|
|
597
|
+
getRunReceipt(runId: string): RunReceipt | undefined;
|
|
598
|
+
listRunReceipts(opts?: {
|
|
599
|
+
loopId?: string;
|
|
600
|
+
repo?: string;
|
|
601
|
+
taskId?: string;
|
|
602
|
+
knowledgeId?: string;
|
|
603
|
+
status?: string;
|
|
604
|
+
limit?: number;
|
|
605
|
+
}): RunReceipt[];
|
|
570
606
|
private deferLiveExpiredRun;
|
|
571
607
|
recoverExpiredRunLeases(now?: Date, opts?: DaemonLeaseFence & {
|
|
572
608
|
limit?: number;
|
|
@@ -589,6 +625,17 @@ export declare class Store {
|
|
|
589
625
|
}): number;
|
|
590
626
|
countRuns(status?: RunStatus): number;
|
|
591
627
|
exportMigrationRows(opts?: StoreMigrationRowsOptions): StoreMigrationRows;
|
|
628
|
+
/**
|
|
629
|
+
* Page through loop_runs for a streaming export. A full `exportMigrationRows`
|
|
630
|
+
* loads every run's stdout/stderr into memory at once (hundreds of MB on a
|
|
631
|
+
* busy host); a self-hosted backfill instead pulls stable ordered pages so
|
|
632
|
+
* peak memory stays bounded. Order is deterministic (created_at, id) so
|
|
633
|
+
* offset paging over an immutable snapshot never skips or repeats a row.
|
|
634
|
+
*/
|
|
635
|
+
exportMigrationRunPage(opts: {
|
|
636
|
+
limit: number;
|
|
637
|
+
offset: number;
|
|
638
|
+
}): LoopRun[];
|
|
592
639
|
private countTable;
|
|
593
640
|
private migrationChecks;
|
|
594
641
|
upsertMigrationWorkflow(workflow: WorkflowSpec, opts?: StoreMigrationUpsertOptions): WorkflowSpec;
|