@ngocsangairvds/vsaf 4.0.17 → 4.1.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.
- package/package.json +5 -2
- package/packages/cli/dist/commands/doctor.d.ts +1 -0
- package/packages/cli/dist/commands/doctor.d.ts.map +1 -1
- package/packages/cli/dist/commands/doctor.js +5 -4
- package/packages/cli/dist/commands/doctor.js.map +1 -1
- package/packages/cli/dist/commands/init.d.ts.map +1 -1
- package/packages/cli/dist/commands/init.js +15 -6
- package/packages/cli/dist/commands/init.js.map +1 -1
- package/packages/cli/dist/commands/list.js +8 -1
- package/packages/cli/dist/commands/list.js.map +1 -1
- package/packages/cli/dist/commands/run.d.ts.map +1 -1
- package/packages/cli/dist/commands/run.js +17 -4
- package/packages/cli/dist/commands/run.js.map +1 -1
- package/packages/cli/dist/commands/skill.d.ts.map +1 -1
- package/packages/cli/dist/commands/skill.js +14 -2
- package/packages/cli/dist/commands/skill.js.map +1 -1
- package/packages/cli/dist/index.js +8 -2
- package/packages/cli/dist/index.js.map +1 -1
- package/packages/cli/dist/mcp/server.d.ts +22 -0
- package/packages/cli/dist/mcp/server.d.ts.map +1 -1
- package/packages/cli/dist/mcp/server.js +311 -20
- package/packages/cli/dist/mcp/server.js.map +1 -1
- package/packages/cli/dist/server/routes/runs.d.ts.map +1 -1
- package/packages/cli/dist/server/routes/runs.js +7 -1
- package/packages/cli/dist/server/routes/runs.js.map +1 -1
- package/packages/cli/dist/server/routes/workflows.d.ts.map +1 -1
- package/packages/cli/dist/server/routes/workflows.js +3 -0
- package/packages/cli/dist/server/routes/workflows.js.map +1 -1
- package/packages/cli/dist/server/services/execution-manager.d.ts.map +1 -1
- package/packages/cli/dist/server/services/execution-manager.js +68 -41
- package/packages/cli/dist/server/services/execution-manager.js.map +1 -1
- package/packages/cli/dist/server/services/sse-manager.d.ts.map +1 -1
- package/packages/cli/dist/server/services/sse-manager.js +7 -2
- package/packages/cli/dist/server/services/sse-manager.js.map +1 -1
- package/packages/core/dist/commands/command-loader.d.ts.map +1 -1
- package/packages/core/dist/commands/command-loader.js +3 -0
- package/packages/core/dist/commands/command-loader.js.map +1 -1
- package/packages/core/dist/engine/condition-evaluator.js +3 -2
- package/packages/core/dist/engine/condition-evaluator.js.map +1 -1
- package/packages/core/dist/engine/dag-executor.d.ts +28 -1
- package/packages/core/dist/engine/dag-executor.d.ts.map +1 -1
- package/packages/core/dist/engine/dag-executor.js +279 -131
- package/packages/core/dist/engine/dag-executor.js.map +1 -1
- package/packages/core/dist/engine/dag-parser.d.ts.map +1 -1
- package/packages/core/dist/engine/dag-parser.js +2 -0
- package/packages/core/dist/engine/dag-parser.js.map +1 -1
- package/packages/core/dist/engine/node-runner.d.ts.map +1 -1
- package/packages/core/dist/engine/node-runner.js +12 -1
- package/packages/core/dist/engine/node-runner.js.map +1 -1
- package/packages/core/dist/engine/variable-resolver.d.ts +1 -1
- package/packages/core/dist/engine/variable-resolver.d.ts.map +1 -1
- package/packages/core/dist/engine/variable-resolver.js +21 -11
- package/packages/core/dist/engine/variable-resolver.js.map +1 -1
- package/packages/core/dist/index.d.ts +5 -1
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +13 -3
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/isolation/artifact-store.d.ts.map +1 -1
- package/packages/core/dist/isolation/artifact-store.js +30 -5
- package/packages/core/dist/isolation/artifact-store.js.map +1 -1
- package/packages/core/dist/isolation/workspace-manager.d.ts +2 -0
- package/packages/core/dist/isolation/workspace-manager.d.ts.map +1 -1
- package/packages/core/dist/isolation/workspace-manager.js +81 -7
- package/packages/core/dist/isolation/workspace-manager.js.map +1 -1
- package/packages/core/dist/schema/workflow-schema.d.ts +10 -0
- package/packages/core/dist/schema/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/schema/workflow-schema.js +5 -3
- package/packages/core/dist/schema/workflow-schema.js.map +1 -1
- package/packages/core/dist/skills/skill-loader.d.ts.map +1 -1
- package/packages/core/dist/skills/skill-loader.js +7 -0
- package/packages/core/dist/skills/skill-loader.js.map +1 -1
- package/packages/core/dist/store/atomic.d.ts +11 -0
- package/packages/core/dist/store/atomic.d.ts.map +1 -0
- package/packages/core/dist/store/atomic.js +51 -0
- package/packages/core/dist/store/atomic.js.map +1 -0
- package/packages/core/dist/store/recovery.d.ts +3 -0
- package/packages/core/dist/store/recovery.d.ts.map +1 -0
- package/packages/core/dist/store/recovery.js +206 -0
- package/packages/core/dist/store/recovery.js.map +1 -0
- package/packages/core/dist/store/run-lock.d.ts +9 -0
- package/packages/core/dist/store/run-lock.d.ts.map +1 -0
- package/packages/core/dist/store/run-lock.js +62 -0
- package/packages/core/dist/store/run-lock.js.map +1 -0
- package/packages/core/dist/store/run-store.d.ts +20 -7
- package/packages/core/dist/store/run-store.d.ts.map +1 -1
- package/packages/core/dist/store/run-store.js +175 -34
- package/packages/core/dist/store/run-store.js.map +1 -1
- package/packages/core/dist/store/snapshot.d.ts +4 -0
- package/packages/core/dist/store/snapshot.d.ts.map +1 -0
- package/packages/core/dist/store/snapshot.js +59 -0
- package/packages/core/dist/store/snapshot.js.map +1 -0
- package/packages/core/dist/store/types.d.ts +89 -4
- package/packages/core/dist/store/types.d.ts.map +1 -1
- package/packages/core/dist/store/types.js +14 -0
- package/packages/core/dist/store/types.js.map +1 -1
- package/packages/core/dist/store/wal.d.ts +39 -0
- package/packages/core/dist/store/wal.d.ts.map +1 -0
- package/packages/core/dist/store/wal.js +203 -0
- package/packages/core/dist/store/wal.js.map +1 -0
- package/packages/core/dist/types/dag.d.ts +2 -0
- package/packages/core/dist/types/dag.d.ts.map +1 -1
- package/packages/core/dist/types/workflow.d.ts +5 -3
- package/packages/core/dist/types/workflow.d.ts.map +1 -1
- package/packages/web/dist/web/3rdpartylicenses.txt +614 -0
- package/packages/web/dist/web/browser/chunk-2QJBTGYU.js +3 -0
- package/packages/web/dist/web/browser/chunk-3VYLP4FZ.js +1 -0
- package/packages/web/dist/web/browser/chunk-6HRQZQXD.js +1 -0
- package/packages/web/dist/web/browser/chunk-7PK6Q4UU.js +1 -0
- package/packages/web/dist/web/browser/chunk-O7TQGEFF.js +8 -0
- package/packages/web/dist/web/browser/chunk-PWF76NCM.js +1 -0
- package/packages/web/dist/web/browser/favicon.ico +0 -0
- package/packages/web/dist/web/browser/index.html +13 -0
- package/packages/web/dist/web/browser/main-AZU5W3KI.js +1 -0
- package/packages/web/dist/web/browser/polyfills-YMBILSHJ.js +2 -0
- package/packages/web/dist/web/browser/styles-JBPZVY54.css +1 -0
- package/packages/web/dist/web/prerendered-routes.json +3 -0
- package/packages/core/dist/store/event-log.d.ts +0 -8
- package/packages/core/dist/store/event-log.d.ts.map +0 -1
- package/packages/core/dist/store/event-log.js +0 -30
- package/packages/core/dist/store/event-log.js.map +0 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recoverState = recoverState;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const wal_js_1 = require("./wal.js");
|
|
7
|
+
const snapshot_js_1 = require("./snapshot.js");
|
|
8
|
+
function recoverState(runDir, allNodeIds) {
|
|
9
|
+
const walPath = (0, path_1.join)(runDir, 'wal.jsonl');
|
|
10
|
+
if (!(0, fs_1.existsSync)(walPath))
|
|
11
|
+
return null;
|
|
12
|
+
const wal = new wal_js_1.WAL(runDir);
|
|
13
|
+
// Try snapshot for base state
|
|
14
|
+
const snapshot = (0, snapshot_js_1.loadSnapshot)(runDir);
|
|
15
|
+
let baseSeq = 0;
|
|
16
|
+
const state = {
|
|
17
|
+
runId: '',
|
|
18
|
+
workflow: '',
|
|
19
|
+
workflowYaml: '',
|
|
20
|
+
args: '',
|
|
21
|
+
workspacePath: '',
|
|
22
|
+
artifactsPath: '',
|
|
23
|
+
projectPath: '',
|
|
24
|
+
branchName: undefined,
|
|
25
|
+
startedAt: '',
|
|
26
|
+
completedAt: undefined,
|
|
27
|
+
pending: new Set(),
|
|
28
|
+
completed: new Set(),
|
|
29
|
+
failed: new Set(),
|
|
30
|
+
skipped: new Set(),
|
|
31
|
+
nodeResults: {},
|
|
32
|
+
retryCounts: new Map(),
|
|
33
|
+
walSeq: 0,
|
|
34
|
+
};
|
|
35
|
+
// Apply snapshot as base
|
|
36
|
+
if (snapshot) {
|
|
37
|
+
baseSeq = snapshot.walSeq;
|
|
38
|
+
state.runId = snapshot.runId;
|
|
39
|
+
state.workflow = snapshot.workflow;
|
|
40
|
+
state.workflowYaml = snapshot.workflowYaml ?? state.workflowYaml;
|
|
41
|
+
state.args = snapshot.args;
|
|
42
|
+
state.workspacePath = snapshot.workspacePath;
|
|
43
|
+
state.artifactsPath = snapshot.artifactsPath;
|
|
44
|
+
state.projectPath = snapshot.projectPath;
|
|
45
|
+
state.branchName = snapshot.branchName;
|
|
46
|
+
state.startedAt = snapshot.startedAt;
|
|
47
|
+
state.completedAt = snapshot.completedAt;
|
|
48
|
+
if (snapshot.status === 'completed' || snapshot.status === 'failed') {
|
|
49
|
+
state.runStatus = snapshot.status;
|
|
50
|
+
}
|
|
51
|
+
for (const [nodeId, nodeSnap] of Object.entries(snapshot.nodes)) {
|
|
52
|
+
const outputStr = typeof nodeSnap.outputRef === 'string'
|
|
53
|
+
? nodeSnap.outputRef
|
|
54
|
+
: nodeSnap.outputRef != null ? wal.resolveOutput(nodeSnap.outputRef) : undefined;
|
|
55
|
+
const structuredOut = nodeSnap.structuredOutputRef != null
|
|
56
|
+
? (typeof nodeSnap.structuredOutputRef === 'object' && !('ref' in nodeSnap.structuredOutputRef) && !('__vsaf_ref' in nodeSnap.structuredOutputRef)
|
|
57
|
+
? nodeSnap.structuredOutputRef
|
|
58
|
+
: wal.resolveStructuredOutput(nodeSnap.structuredOutputRef))
|
|
59
|
+
: undefined;
|
|
60
|
+
state.nodeResults[nodeId] = {
|
|
61
|
+
status: nodeSnap.status,
|
|
62
|
+
output: outputStr,
|
|
63
|
+
structuredOutput: structuredOut,
|
|
64
|
+
startedAt: nodeSnap.startedAt,
|
|
65
|
+
completedAt: nodeSnap.completedAt,
|
|
66
|
+
error: nodeSnap.error,
|
|
67
|
+
};
|
|
68
|
+
switch (nodeSnap.status) {
|
|
69
|
+
case 'completed':
|
|
70
|
+
state.completed.add(nodeId);
|
|
71
|
+
break;
|
|
72
|
+
case 'failed':
|
|
73
|
+
state.failed.add(nodeId);
|
|
74
|
+
break;
|
|
75
|
+
case 'skipped':
|
|
76
|
+
state.skipped.add(nodeId);
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
state.pending.add(nodeId);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (nodeSnap.retryCount) {
|
|
83
|
+
state.retryCounts.set(nodeId, nodeSnap.retryCount);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Replay WAL events after snapshot
|
|
88
|
+
const events = wal.replay(baseSeq);
|
|
89
|
+
// Track which nodes have "started" for crash detection
|
|
90
|
+
const startedNodes = new Set();
|
|
91
|
+
for (const event of events) {
|
|
92
|
+
state.walSeq = event.seq;
|
|
93
|
+
switch (event.type) {
|
|
94
|
+
case 'run:create':
|
|
95
|
+
state.workflow = event.data?.workflow ?? state.workflow;
|
|
96
|
+
state.workflowYaml = event.data?.workflowYaml ?? state.workflowYaml;
|
|
97
|
+
state.args = event.data?.args ?? state.args;
|
|
98
|
+
state.workspacePath = event.data?.workspacePath ?? state.workspacePath;
|
|
99
|
+
state.artifactsPath = event.data?.artifactsPath ?? state.artifactsPath;
|
|
100
|
+
state.projectPath = event.data?.projectPath ?? state.projectPath;
|
|
101
|
+
state.branchName = event.data?.branchName ?? state.branchName;
|
|
102
|
+
state.startedAt = event.ts;
|
|
103
|
+
break;
|
|
104
|
+
case 'node:start':
|
|
105
|
+
if (event.nodeId) {
|
|
106
|
+
startedNodes.add(event.nodeId);
|
|
107
|
+
// Clear previous terminal state — handles restart after fail (loop retry)
|
|
108
|
+
state.failed.delete(event.nodeId);
|
|
109
|
+
state.completed.delete(event.nodeId);
|
|
110
|
+
state.skipped.delete(event.nodeId);
|
|
111
|
+
state.nodeResults[event.nodeId] = {
|
|
112
|
+
...state.nodeResults[event.nodeId],
|
|
113
|
+
status: 'running',
|
|
114
|
+
startedAt: event.data?.startedAt ?? event.ts,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
case 'node:complete':
|
|
119
|
+
if (event.nodeId) {
|
|
120
|
+
startedNodes.delete(event.nodeId);
|
|
121
|
+
state.completed.add(event.nodeId);
|
|
122
|
+
state.pending.delete(event.nodeId);
|
|
123
|
+
state.failed.delete(event.nodeId);
|
|
124
|
+
const output = event.data?.output != null
|
|
125
|
+
? (typeof event.data.output === 'string'
|
|
126
|
+
? event.data.output
|
|
127
|
+
: wal.resolveOutput(event.data.output))
|
|
128
|
+
: undefined;
|
|
129
|
+
const structured = event.data?.structuredOutput != null
|
|
130
|
+
? (typeof event.data.structuredOutput === 'object' && !('ref' in event.data.structuredOutput) && !('__vsaf_ref' in event.data.structuredOutput)
|
|
131
|
+
? event.data.structuredOutput
|
|
132
|
+
: wal.resolveStructuredOutput(event.data.structuredOutput))
|
|
133
|
+
: undefined;
|
|
134
|
+
state.nodeResults[event.nodeId] = {
|
|
135
|
+
status: 'completed',
|
|
136
|
+
output,
|
|
137
|
+
structuredOutput: structured,
|
|
138
|
+
startedAt: state.nodeResults[event.nodeId]?.startedAt,
|
|
139
|
+
completedAt: event.data?.completedAt ?? event.ts,
|
|
140
|
+
durationMs: event.data?.durationMs,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
case 'node:fail':
|
|
145
|
+
if (event.nodeId) {
|
|
146
|
+
startedNodes.delete(event.nodeId);
|
|
147
|
+
state.failed.add(event.nodeId);
|
|
148
|
+
state.pending.delete(event.nodeId);
|
|
149
|
+
state.completed.delete(event.nodeId);
|
|
150
|
+
state.nodeResults[event.nodeId] = {
|
|
151
|
+
status: 'failed',
|
|
152
|
+
error: event.data?.error,
|
|
153
|
+
startedAt: state.nodeResults[event.nodeId]?.startedAt,
|
|
154
|
+
completedAt: event.data?.completedAt ?? event.ts,
|
|
155
|
+
durationMs: event.data?.durationMs,
|
|
156
|
+
};
|
|
157
|
+
if (event.data?.retryCount !== undefined) {
|
|
158
|
+
state.retryCounts.set(event.nodeId, event.data.retryCount);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
case 'node:skip':
|
|
163
|
+
if (event.nodeId) {
|
|
164
|
+
startedNodes.delete(event.nodeId);
|
|
165
|
+
state.skipped.add(event.nodeId);
|
|
166
|
+
state.pending.delete(event.nodeId);
|
|
167
|
+
state.nodeResults[event.nodeId] = { status: 'skipped' };
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
case 'node:reset':
|
|
171
|
+
if (event.nodeId) {
|
|
172
|
+
startedNodes.delete(event.nodeId);
|
|
173
|
+
state.pending.add(event.nodeId);
|
|
174
|
+
state.completed.delete(event.nodeId);
|
|
175
|
+
state.failed.delete(event.nodeId);
|
|
176
|
+
state.skipped.delete(event.nodeId);
|
|
177
|
+
delete state.nodeResults[event.nodeId];
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
case 'run:complete':
|
|
181
|
+
state.runStatus = 'completed';
|
|
182
|
+
state.completedAt = event.ts;
|
|
183
|
+
break;
|
|
184
|
+
case 'run:fail':
|
|
185
|
+
state.runStatus = 'failed';
|
|
186
|
+
state.completedAt = event.ts;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Crash recovery: nodes with start but no completion → pending
|
|
191
|
+
for (const nodeId of startedNodes) {
|
|
192
|
+
if (!state.completed.has(nodeId) && !state.failed.has(nodeId) && !state.skipped.has(nodeId)) {
|
|
193
|
+
state.pending.add(nodeId);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Reconstruct pending set from graph when node list provided
|
|
197
|
+
if (allNodeIds) {
|
|
198
|
+
for (const nodeId of allNodeIds) {
|
|
199
|
+
if (!state.completed.has(nodeId) && !state.failed.has(nodeId) && !state.skipped.has(nodeId)) {
|
|
200
|
+
state.pending.add(nodeId);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return state;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../src/store/recovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lock.d.ts","sourceRoot":"","sources":["../../src/store/run-lock.ts"],"names":[],"mappings":"AAGA,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,MAAM;IAE/C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAW/B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ5B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,YAAY;CAUrB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RunLock = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
class RunLock {
|
|
7
|
+
storageDir;
|
|
8
|
+
constructor(storageDir) {
|
|
9
|
+
this.storageDir = storageDir;
|
|
10
|
+
}
|
|
11
|
+
acquire(runId) {
|
|
12
|
+
const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
|
|
13
|
+
try {
|
|
14
|
+
(0, fs_1.mkdirSync)(lockDir); // mkdir is atomic across all OS
|
|
15
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(lockDir, 'pid'), String(process.pid));
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return this.tryRecoverStaleLock(runId);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
release(runId) {
|
|
23
|
+
const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
|
|
24
|
+
try {
|
|
25
|
+
(0, fs_1.rmSync)(lockDir, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
catch { /* ignore */ }
|
|
28
|
+
}
|
|
29
|
+
// Note: TOCTOU race between release() and acquireFresh() — another process
|
|
30
|
+
// could acquire between these calls. acquireFresh() returns false in that case.
|
|
31
|
+
// Safe for single-process MCP server. Multi-process use would need flock().
|
|
32
|
+
tryRecoverStaleLock(runId) {
|
|
33
|
+
const pidFile = (0, path_1.join)(this.storageDir, runId, '.lock', 'pid');
|
|
34
|
+
try {
|
|
35
|
+
const pid = parseInt((0, fs_1.readFileSync)(pidFile, 'utf-8').trim(), 10);
|
|
36
|
+
process.kill(pid, 0); // Check if alive — throws ESRCH if dead
|
|
37
|
+
return false; // Process alive → genuine contention
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const e = err;
|
|
41
|
+
if (e.code === 'ESRCH' || e.code === 'ENOENT') {
|
|
42
|
+
// Dead process or missing pid file → stale lock
|
|
43
|
+
this.release(runId);
|
|
44
|
+
return this.acquireFresh(runId);
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
acquireFresh(runId) {
|
|
50
|
+
const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
|
|
51
|
+
try {
|
|
52
|
+
(0, fs_1.mkdirSync)(lockDir);
|
|
53
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(lockDir, 'pid'), String(process.pid));
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.RunLock = RunLock;
|
|
62
|
+
//# sourceMappingURL=run-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lock.js","sourceRoot":"","sources":["../../src/store/run-lock.ts"],"names":[],"mappings":";;;AAAA,2BAAoE;AACpE,+BAA4B;AAE5B,MAAa,OAAO;IACW;IAA7B,YAA6B,UAAkB;QAAlB,eAAU,GAAV,UAAU,CAAQ;IAAG,CAAC;IAEnD,OAAO,CAAC,KAAa;QACnB,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,IAAA,cAAS,EAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC;YACpD,IAAA,kBAAa,EAAC,IAAA,WAAI,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,KAAa;QACnB,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACtD,IAAI,CAAC;YAAC,IAAA,WAAM,EAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACtE,CAAC;IAED,2EAA2E;IAC3E,gFAAgF;IAChF,4EAA4E;IACpE,mBAAmB,CAAC,KAAa;QACvC,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC7D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAA,iBAAY,EAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,wCAAwC;YAC9D,OAAO,KAAK,CAAC,CAAC,qCAAqC;QACrD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,GAA4B,CAAC;YACvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC9C,gDAAgD;gBAChD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,IAAA,cAAS,EAAC,OAAO,CAAC,CAAC;YACnB,IAAA,kBAAa,EAAC,IAAA,WAAI,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF;AAjDD,0BAiDC"}
|
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
import type { WorkflowRun, NodeResult,
|
|
1
|
+
import type { WorkflowRun, NodeResult, RecoveredState } from './types.js';
|
|
2
2
|
export declare class RunStore {
|
|
3
3
|
private readonly baseDir;
|
|
4
|
+
private wals;
|
|
4
5
|
private runs;
|
|
5
|
-
private
|
|
6
|
+
private appendCount;
|
|
7
|
+
private retryCounts;
|
|
6
8
|
constructor(baseDir: string);
|
|
7
|
-
create(workflow: string, args: string, workspacePath: string, artifactsPath: string, projectPath: string): WorkflowRun;
|
|
8
|
-
updateNode(runId: string, nodeId: string, result: Partial<NodeResult
|
|
9
|
+
create(workflow: string, args: string, workspacePath: string, artifactsPath: string, projectPath: string, workflowYaml?: string, branchName?: string): WorkflowRun;
|
|
10
|
+
updateNode(runId: string, nodeId: string, result: Partial<NodeResult>, opts?: {
|
|
11
|
+
retryCount?: number;
|
|
12
|
+
}): void;
|
|
9
13
|
save(runId: string): void;
|
|
10
14
|
complete(runId: string): void;
|
|
11
15
|
fail(runId: string): void;
|
|
16
|
+
resetNode(runId: string, nodeId: string): void;
|
|
12
17
|
load(runId: string): WorkflowRun | undefined;
|
|
18
|
+
recover(runId: string): RecoveredState | null;
|
|
13
19
|
listAll(): WorkflowRun[];
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
listResumable(): Array<{
|
|
21
|
+
runId: string;
|
|
22
|
+
workflow: string;
|
|
23
|
+
status: string;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
}>;
|
|
26
|
+
snapshotSync(runId: string): void;
|
|
27
|
+
private getWAL;
|
|
16
28
|
private getRun;
|
|
17
|
-
private persist;
|
|
18
29
|
private statusToEventType;
|
|
30
|
+
private maybeSnapshot;
|
|
31
|
+
private writeSnapshotNow;
|
|
19
32
|
}
|
|
20
33
|
//# sourceMappingURL=run-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/store/run-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/store/run-store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAA8B,cAAc,EAAgB,MAAM,YAAY,CAAC;AAKpH,qBAAa,QAAQ;IAMP,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,WAAW,CAA6B;gBAEnB,OAAO,EAAE,MAAM;IAI5C,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAClB,WAAW;IAkBd,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA6B5G,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAS7B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IASzB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAO9C,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IA4B5C,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAK7C,OAAO,IAAI,WAAW,EAAE;IAWxB,aAAa,IAAI,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA0C9F,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIjC,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,gBAAgB;CAuCzB"}
|
|
@@ -4,89 +4,189 @@ exports.RunStore = void 0;
|
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
7
|
-
const
|
|
7
|
+
const wal_js_1 = require("./wal.js");
|
|
8
|
+
const snapshot_js_1 = require("./snapshot.js");
|
|
9
|
+
const recovery_js_1 = require("./recovery.js");
|
|
10
|
+
const SNAPSHOT_INTERVAL = 25;
|
|
8
11
|
class RunStore {
|
|
9
12
|
baseDir;
|
|
13
|
+
wals = new Map();
|
|
10
14
|
runs = new Map();
|
|
11
|
-
|
|
15
|
+
appendCount = new Map();
|
|
16
|
+
retryCounts = new Map();
|
|
12
17
|
constructor(baseDir) {
|
|
13
18
|
this.baseDir = baseDir;
|
|
14
19
|
(0, fs_1.mkdirSync)(baseDir, { recursive: true });
|
|
15
20
|
}
|
|
16
|
-
create(workflow, args, workspacePath, artifactsPath, projectPath) {
|
|
21
|
+
create(workflow, args, workspacePath, artifactsPath, projectPath, workflowYaml, branchName) {
|
|
17
22
|
const runId = `run-${(0, crypto_1.randomBytes)(6).toString('hex')}`;
|
|
18
23
|
const run = {
|
|
19
|
-
runId, workflow, status: 'running', args,
|
|
20
|
-
workspacePath, artifactsPath, projectPath,
|
|
24
|
+
runId, workflow, workflowYaml, status: 'running', args,
|
|
25
|
+
workspacePath, artifactsPath, projectPath, branchName,
|
|
21
26
|
startedAt: new Date().toISOString(), nodes: {},
|
|
22
27
|
};
|
|
23
28
|
this.runs.set(runId, run);
|
|
24
|
-
this.
|
|
25
|
-
|
|
29
|
+
const wal = this.getWAL(runId);
|
|
30
|
+
wal.append({
|
|
31
|
+
type: 'run:create',
|
|
32
|
+
data: { workflow, args, workflowYaml, workspacePath, artifactsPath, projectPath, branchName },
|
|
33
|
+
});
|
|
26
34
|
return run;
|
|
27
35
|
}
|
|
28
|
-
updateNode(runId, nodeId, result) {
|
|
36
|
+
updateNode(runId, nodeId, result, opts) {
|
|
29
37
|
const run = this.getRun(runId);
|
|
30
38
|
run.nodes[nodeId] = { ...run.nodes[nodeId], ...result };
|
|
31
39
|
if (result.status) {
|
|
40
|
+
const wal = this.getWAL(runId);
|
|
32
41
|
const eventType = this.statusToEventType(result.status);
|
|
33
42
|
if (eventType) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
nodeId,
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const data = {};
|
|
44
|
+
if (result.output != null) {
|
|
45
|
+
data.output = wal.persistOutput(nodeId, result.output);
|
|
46
|
+
}
|
|
47
|
+
if (result.structuredOutput != null) {
|
|
48
|
+
data.structuredOutput = wal.persistStructuredOutput(nodeId, result.structuredOutput);
|
|
49
|
+
}
|
|
50
|
+
if (result.error != null)
|
|
51
|
+
data.error = result.error;
|
|
52
|
+
if (result.startedAt)
|
|
53
|
+
data.startedAt = result.startedAt;
|
|
54
|
+
if (result.completedAt)
|
|
55
|
+
data.completedAt = result.completedAt;
|
|
56
|
+
if (result.durationMs !== undefined)
|
|
57
|
+
data.durationMs = result.durationMs;
|
|
58
|
+
if (opts?.retryCount !== undefined) {
|
|
59
|
+
data.retryCount = opts.retryCount;
|
|
60
|
+
this.retryCounts.set(`${runId}:${nodeId}`, opts.retryCount);
|
|
61
|
+
}
|
|
62
|
+
wal.append({ type: eventType, nodeId, data: Object.keys(data).length > 0 ? data : undefined });
|
|
63
|
+
this.maybeSnapshot(runId);
|
|
39
64
|
}
|
|
40
65
|
}
|
|
41
66
|
}
|
|
42
|
-
save(runId) {
|
|
67
|
+
save(runId) {
|
|
68
|
+
// In WAL-based store, save is a no-op — state is persisted via WAL append
|
|
69
|
+
// Kept for API compatibility
|
|
70
|
+
}
|
|
43
71
|
complete(runId) {
|
|
44
72
|
const run = this.getRun(runId);
|
|
45
73
|
run.status = 'completed';
|
|
46
74
|
run.completedAt = new Date().toISOString();
|
|
47
|
-
this.
|
|
48
|
-
|
|
75
|
+
const wal = this.getWAL(runId);
|
|
76
|
+
wal.append({ type: 'run:complete' });
|
|
77
|
+
this.writeSnapshotNow(runId);
|
|
49
78
|
}
|
|
50
79
|
fail(runId) {
|
|
51
80
|
const run = this.getRun(runId);
|
|
52
81
|
run.status = 'failed';
|
|
53
82
|
run.completedAt = new Date().toISOString();
|
|
54
|
-
this.
|
|
55
|
-
|
|
83
|
+
const wal = this.getWAL(runId);
|
|
84
|
+
wal.append({ type: 'run:fail' });
|
|
85
|
+
this.writeSnapshotNow(runId);
|
|
86
|
+
}
|
|
87
|
+
resetNode(runId, nodeId) {
|
|
88
|
+
const run = this.getRun(runId);
|
|
89
|
+
delete run.nodes[nodeId];
|
|
90
|
+
const wal = this.getWAL(runId);
|
|
91
|
+
wal.append({ type: 'node:reset', nodeId });
|
|
56
92
|
}
|
|
57
93
|
load(runId) {
|
|
58
94
|
if (this.runs.has(runId))
|
|
59
95
|
return this.runs.get(runId);
|
|
60
|
-
|
|
61
|
-
|
|
96
|
+
// Try to recover from WAL
|
|
97
|
+
const runDir = (0, path_1.join)(this.baseDir, runId);
|
|
98
|
+
if (!(0, fs_1.existsSync)(runDir))
|
|
99
|
+
return undefined;
|
|
100
|
+
const state = (0, recovery_js_1.recoverState)(runDir);
|
|
101
|
+
if (!state)
|
|
62
102
|
return undefined;
|
|
63
|
-
const run =
|
|
103
|
+
const run = {
|
|
104
|
+
runId: state.runId || runId,
|
|
105
|
+
workflow: state.workflow,
|
|
106
|
+
workflowYaml: state.workflowYaml,
|
|
107
|
+
status: state.runStatus ?? 'running',
|
|
108
|
+
args: state.args,
|
|
109
|
+
workspacePath: state.workspacePath,
|
|
110
|
+
artifactsPath: state.artifactsPath,
|
|
111
|
+
projectPath: state.projectPath,
|
|
112
|
+
branchName: state.branchName,
|
|
113
|
+
startedAt: state.startedAt,
|
|
114
|
+
completedAt: state.completedAt,
|
|
115
|
+
nodes: state.nodeResults,
|
|
116
|
+
};
|
|
64
117
|
this.runs.set(runId, run);
|
|
65
118
|
return run;
|
|
66
119
|
}
|
|
120
|
+
recover(runId) {
|
|
121
|
+
const runDir = (0, path_1.join)(this.baseDir, runId);
|
|
122
|
+
return (0, recovery_js_1.recoverState)(runDir);
|
|
123
|
+
}
|
|
67
124
|
listAll() {
|
|
68
125
|
const runs = [];
|
|
69
126
|
if (!(0, fs_1.existsSync)(this.baseDir))
|
|
70
127
|
return runs;
|
|
71
128
|
for (const dir of (0, fs_1.readdirSync)(this.baseDir)) {
|
|
129
|
+
if (!dir.startsWith('run-'))
|
|
130
|
+
continue;
|
|
72
131
|
const run = this.load(dir);
|
|
73
132
|
if (run)
|
|
74
133
|
runs.push(run);
|
|
75
134
|
}
|
|
76
135
|
return runs;
|
|
77
136
|
}
|
|
78
|
-
|
|
79
|
-
|
|
137
|
+
listResumable() {
|
|
138
|
+
const results = [];
|
|
139
|
+
if (!(0, fs_1.existsSync)(this.baseDir))
|
|
140
|
+
return results;
|
|
141
|
+
for (const dir of (0, fs_1.readdirSync)(this.baseDir)) {
|
|
142
|
+
if (!dir.startsWith('run-'))
|
|
143
|
+
continue;
|
|
144
|
+
const runDir = (0, path_1.join)(this.baseDir, dir);
|
|
145
|
+
// Try snapshot first (fast path)
|
|
146
|
+
const snap = (0, snapshot_js_1.loadSnapshot)(runDir);
|
|
147
|
+
if (snap) {
|
|
148
|
+
if (snap.status !== 'running') {
|
|
149
|
+
continue; // Terminal status in snapshot — skip
|
|
150
|
+
}
|
|
151
|
+
// Check WAL for terminal events after this snapshot
|
|
152
|
+
if (wal_js_1.WAL.hasTerminalAfter(runDir, snap.walSeq)) {
|
|
153
|
+
continue; // Run finished after snapshot — skip
|
|
154
|
+
}
|
|
155
|
+
results.push({
|
|
156
|
+
runId: snap.runId,
|
|
157
|
+
workflow: snap.workflow,
|
|
158
|
+
status: snap.status,
|
|
159
|
+
startedAt: snap.startedAt,
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
// Fall back to WAL replay for runs without snapshots
|
|
164
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(runDir, 'wal.jsonl'))) {
|
|
165
|
+
const state = (0, recovery_js_1.recoverState)(runDir);
|
|
166
|
+
if (state && (!state.runStatus || state.runStatus === 'running')) {
|
|
167
|
+
results.push({
|
|
168
|
+
runId: state.runId || dir,
|
|
169
|
+
workflow: state.workflow,
|
|
170
|
+
status: 'running',
|
|
171
|
+
startedAt: state.startedAt,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
snapshotSync(runId) {
|
|
179
|
+
this.writeSnapshotNow(runId);
|
|
80
180
|
}
|
|
81
|
-
|
|
82
|
-
let
|
|
83
|
-
if (!
|
|
181
|
+
getWAL(runId) {
|
|
182
|
+
let wal = this.wals.get(runId);
|
|
183
|
+
if (!wal) {
|
|
84
184
|
const runDir = (0, path_1.join)(this.baseDir, runId);
|
|
85
185
|
(0, fs_1.mkdirSync)(runDir, { recursive: true });
|
|
86
|
-
|
|
87
|
-
this.
|
|
186
|
+
wal = new wal_js_1.WAL(runDir);
|
|
187
|
+
this.wals.set(runId, wal);
|
|
88
188
|
}
|
|
89
|
-
return
|
|
189
|
+
return wal;
|
|
90
190
|
}
|
|
91
191
|
getRun(runId) {
|
|
92
192
|
const run = this.runs.get(runId);
|
|
@@ -94,11 +194,6 @@ class RunStore {
|
|
|
94
194
|
throw new Error(`Run not found: ${runId}`);
|
|
95
195
|
return run;
|
|
96
196
|
}
|
|
97
|
-
persist(run) {
|
|
98
|
-
const runDir = (0, path_1.join)(this.baseDir, run.runId);
|
|
99
|
-
(0, fs_1.mkdirSync)(runDir, { recursive: true });
|
|
100
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(runDir, 'state.json'), JSON.stringify(run, null, 2), 'utf-8');
|
|
101
|
-
}
|
|
102
197
|
statusToEventType(status) {
|
|
103
198
|
switch (status) {
|
|
104
199
|
case 'running': return 'node:start';
|
|
@@ -108,6 +203,52 @@ class RunStore {
|
|
|
108
203
|
default: return null;
|
|
109
204
|
}
|
|
110
205
|
}
|
|
206
|
+
maybeSnapshot(runId) {
|
|
207
|
+
const count = (this.appendCount.get(runId) ?? 0) + 1;
|
|
208
|
+
this.appendCount.set(runId, count);
|
|
209
|
+
if (count >= SNAPSHOT_INTERVAL) {
|
|
210
|
+
this.writeSnapshotNow(runId);
|
|
211
|
+
this.appendCount.set(runId, 0);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
writeSnapshotNow(runId) {
|
|
215
|
+
const run = this.runs.get(runId);
|
|
216
|
+
if (!run)
|
|
217
|
+
return;
|
|
218
|
+
const wal = this.wals.get(runId);
|
|
219
|
+
if (!wal)
|
|
220
|
+
return;
|
|
221
|
+
const snapshot = {
|
|
222
|
+
runId: run.runId,
|
|
223
|
+
workflow: run.workflow,
|
|
224
|
+
workflowYaml: run.workflowYaml,
|
|
225
|
+
status: run.status,
|
|
226
|
+
walSeq: wal.currentSeq,
|
|
227
|
+
args: run.args,
|
|
228
|
+
workspacePath: run.workspacePath,
|
|
229
|
+
artifactsPath: run.artifactsPath,
|
|
230
|
+
projectPath: run.projectPath,
|
|
231
|
+
branchName: run.branchName,
|
|
232
|
+
startedAt: run.startedAt,
|
|
233
|
+
completedAt: run.completedAt,
|
|
234
|
+
nodes: {},
|
|
235
|
+
};
|
|
236
|
+
for (const [nodeId, result] of Object.entries(run.nodes)) {
|
|
237
|
+
const retryCount = this.retryCounts.get(`${runId}:${nodeId}`);
|
|
238
|
+
snapshot.nodes[nodeId] = {
|
|
239
|
+
status: result.status,
|
|
240
|
+
outputRef: result.output != null ? wal.getOutputRef(nodeId, result.output) : undefined,
|
|
241
|
+
structuredOutputRef: result.structuredOutput != null
|
|
242
|
+
? wal.getStructuredOutputRef(nodeId, result.structuredOutput)
|
|
243
|
+
: undefined,
|
|
244
|
+
startedAt: result.startedAt,
|
|
245
|
+
completedAt: result.completedAt,
|
|
246
|
+
error: result.error,
|
|
247
|
+
retryCount,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
(0, snapshot_js_1.writeSnapshot)((0, path_1.join)(this.baseDir, runId), snapshot);
|
|
251
|
+
}
|
|
111
252
|
}
|
|
112
253
|
exports.RunStore = RunStore;
|
|
113
254
|
//# sourceMappingURL=run-store.js.map
|