@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.
Files changed (120) hide show
  1. package/package.json +5 -2
  2. package/packages/cli/dist/commands/doctor.d.ts +1 -0
  3. package/packages/cli/dist/commands/doctor.d.ts.map +1 -1
  4. package/packages/cli/dist/commands/doctor.js +5 -4
  5. package/packages/cli/dist/commands/doctor.js.map +1 -1
  6. package/packages/cli/dist/commands/init.d.ts.map +1 -1
  7. package/packages/cli/dist/commands/init.js +15 -6
  8. package/packages/cli/dist/commands/init.js.map +1 -1
  9. package/packages/cli/dist/commands/list.js +8 -1
  10. package/packages/cli/dist/commands/list.js.map +1 -1
  11. package/packages/cli/dist/commands/run.d.ts.map +1 -1
  12. package/packages/cli/dist/commands/run.js +17 -4
  13. package/packages/cli/dist/commands/run.js.map +1 -1
  14. package/packages/cli/dist/commands/skill.d.ts.map +1 -1
  15. package/packages/cli/dist/commands/skill.js +14 -2
  16. package/packages/cli/dist/commands/skill.js.map +1 -1
  17. package/packages/cli/dist/index.js +8 -2
  18. package/packages/cli/dist/index.js.map +1 -1
  19. package/packages/cli/dist/mcp/server.d.ts +22 -0
  20. package/packages/cli/dist/mcp/server.d.ts.map +1 -1
  21. package/packages/cli/dist/mcp/server.js +311 -20
  22. package/packages/cli/dist/mcp/server.js.map +1 -1
  23. package/packages/cli/dist/server/routes/runs.d.ts.map +1 -1
  24. package/packages/cli/dist/server/routes/runs.js +7 -1
  25. package/packages/cli/dist/server/routes/runs.js.map +1 -1
  26. package/packages/cli/dist/server/routes/workflows.d.ts.map +1 -1
  27. package/packages/cli/dist/server/routes/workflows.js +3 -0
  28. package/packages/cli/dist/server/routes/workflows.js.map +1 -1
  29. package/packages/cli/dist/server/services/execution-manager.d.ts.map +1 -1
  30. package/packages/cli/dist/server/services/execution-manager.js +68 -41
  31. package/packages/cli/dist/server/services/execution-manager.js.map +1 -1
  32. package/packages/cli/dist/server/services/sse-manager.d.ts.map +1 -1
  33. package/packages/cli/dist/server/services/sse-manager.js +7 -2
  34. package/packages/cli/dist/server/services/sse-manager.js.map +1 -1
  35. package/packages/core/dist/commands/command-loader.d.ts.map +1 -1
  36. package/packages/core/dist/commands/command-loader.js +3 -0
  37. package/packages/core/dist/commands/command-loader.js.map +1 -1
  38. package/packages/core/dist/engine/condition-evaluator.js +3 -2
  39. package/packages/core/dist/engine/condition-evaluator.js.map +1 -1
  40. package/packages/core/dist/engine/dag-executor.d.ts +28 -1
  41. package/packages/core/dist/engine/dag-executor.d.ts.map +1 -1
  42. package/packages/core/dist/engine/dag-executor.js +279 -131
  43. package/packages/core/dist/engine/dag-executor.js.map +1 -1
  44. package/packages/core/dist/engine/dag-parser.d.ts.map +1 -1
  45. package/packages/core/dist/engine/dag-parser.js +2 -0
  46. package/packages/core/dist/engine/dag-parser.js.map +1 -1
  47. package/packages/core/dist/engine/node-runner.d.ts.map +1 -1
  48. package/packages/core/dist/engine/node-runner.js +12 -1
  49. package/packages/core/dist/engine/node-runner.js.map +1 -1
  50. package/packages/core/dist/engine/variable-resolver.d.ts +1 -1
  51. package/packages/core/dist/engine/variable-resolver.d.ts.map +1 -1
  52. package/packages/core/dist/engine/variable-resolver.js +21 -11
  53. package/packages/core/dist/engine/variable-resolver.js.map +1 -1
  54. package/packages/core/dist/index.d.ts +5 -1
  55. package/packages/core/dist/index.d.ts.map +1 -1
  56. package/packages/core/dist/index.js +13 -3
  57. package/packages/core/dist/index.js.map +1 -1
  58. package/packages/core/dist/isolation/artifact-store.d.ts.map +1 -1
  59. package/packages/core/dist/isolation/artifact-store.js +30 -5
  60. package/packages/core/dist/isolation/artifact-store.js.map +1 -1
  61. package/packages/core/dist/isolation/workspace-manager.d.ts +2 -0
  62. package/packages/core/dist/isolation/workspace-manager.d.ts.map +1 -1
  63. package/packages/core/dist/isolation/workspace-manager.js +81 -7
  64. package/packages/core/dist/isolation/workspace-manager.js.map +1 -1
  65. package/packages/core/dist/schema/workflow-schema.d.ts +10 -0
  66. package/packages/core/dist/schema/workflow-schema.d.ts.map +1 -1
  67. package/packages/core/dist/schema/workflow-schema.js +5 -3
  68. package/packages/core/dist/schema/workflow-schema.js.map +1 -1
  69. package/packages/core/dist/skills/skill-loader.d.ts.map +1 -1
  70. package/packages/core/dist/skills/skill-loader.js +7 -0
  71. package/packages/core/dist/skills/skill-loader.js.map +1 -1
  72. package/packages/core/dist/store/atomic.d.ts +11 -0
  73. package/packages/core/dist/store/atomic.d.ts.map +1 -0
  74. package/packages/core/dist/store/atomic.js +51 -0
  75. package/packages/core/dist/store/atomic.js.map +1 -0
  76. package/packages/core/dist/store/recovery.d.ts +3 -0
  77. package/packages/core/dist/store/recovery.d.ts.map +1 -0
  78. package/packages/core/dist/store/recovery.js +206 -0
  79. package/packages/core/dist/store/recovery.js.map +1 -0
  80. package/packages/core/dist/store/run-lock.d.ts +9 -0
  81. package/packages/core/dist/store/run-lock.d.ts.map +1 -0
  82. package/packages/core/dist/store/run-lock.js +62 -0
  83. package/packages/core/dist/store/run-lock.js.map +1 -0
  84. package/packages/core/dist/store/run-store.d.ts +20 -7
  85. package/packages/core/dist/store/run-store.d.ts.map +1 -1
  86. package/packages/core/dist/store/run-store.js +175 -34
  87. package/packages/core/dist/store/run-store.js.map +1 -1
  88. package/packages/core/dist/store/snapshot.d.ts +4 -0
  89. package/packages/core/dist/store/snapshot.d.ts.map +1 -0
  90. package/packages/core/dist/store/snapshot.js +59 -0
  91. package/packages/core/dist/store/snapshot.js.map +1 -0
  92. package/packages/core/dist/store/types.d.ts +89 -4
  93. package/packages/core/dist/store/types.d.ts.map +1 -1
  94. package/packages/core/dist/store/types.js +14 -0
  95. package/packages/core/dist/store/types.js.map +1 -1
  96. package/packages/core/dist/store/wal.d.ts +39 -0
  97. package/packages/core/dist/store/wal.d.ts.map +1 -0
  98. package/packages/core/dist/store/wal.js +203 -0
  99. package/packages/core/dist/store/wal.js.map +1 -0
  100. package/packages/core/dist/types/dag.d.ts +2 -0
  101. package/packages/core/dist/types/dag.d.ts.map +1 -1
  102. package/packages/core/dist/types/workflow.d.ts +5 -3
  103. package/packages/core/dist/types/workflow.d.ts.map +1 -1
  104. package/packages/web/dist/web/3rdpartylicenses.txt +614 -0
  105. package/packages/web/dist/web/browser/chunk-2QJBTGYU.js +3 -0
  106. package/packages/web/dist/web/browser/chunk-3VYLP4FZ.js +1 -0
  107. package/packages/web/dist/web/browser/chunk-6HRQZQXD.js +1 -0
  108. package/packages/web/dist/web/browser/chunk-7PK6Q4UU.js +1 -0
  109. package/packages/web/dist/web/browser/chunk-O7TQGEFF.js +8 -0
  110. package/packages/web/dist/web/browser/chunk-PWF76NCM.js +1 -0
  111. package/packages/web/dist/web/browser/favicon.ico +0 -0
  112. package/packages/web/dist/web/browser/index.html +13 -0
  113. package/packages/web/dist/web/browser/main-AZU5W3KI.js +1 -0
  114. package/packages/web/dist/web/browser/polyfills-YMBILSHJ.js +2 -0
  115. package/packages/web/dist/web/browser/styles-JBPZVY54.css +1 -0
  116. package/packages/web/dist/web/prerendered-routes.json +3 -0
  117. package/packages/core/dist/store/event-log.d.ts +0 -8
  118. package/packages/core/dist/store/event-log.d.ts.map +0 -1
  119. package/packages/core/dist/store/event-log.js +0 -30
  120. 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,9 @@
1
+ export declare class RunLock {
2
+ private readonly storageDir;
3
+ constructor(storageDir: string);
4
+ acquire(runId: string): boolean;
5
+ release(runId: string): void;
6
+ private tryRecoverStaleLock;
7
+ private acquireFresh;
8
+ }
9
+ //# sourceMappingURL=run-lock.d.ts.map
@@ -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, WorkflowEvent } from './types.js';
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 logs;
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>): void;
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
- getEvents(runId: string): WorkflowEvent[];
15
- private getLog;
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":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIzE,qBAAa,QAAQ;IAIP,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,IAAI,CAAkC;IAC9C,OAAO,CAAC,IAAI,CAA+B;gBAEd,OAAO,EAAE,MAAM;IAI5C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW;IAatH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI;IAe5E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAEzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ7B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQzB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAS5C,OAAO,IAAI,WAAW,EAAE;IAUxB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE;IAIzC,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,iBAAiB;CAS1B"}
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 event_log_js_1 = require("./event-log.js");
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
- logs = new Map();
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.persist(run);
25
- this.getLog(runId).append({ type: 'run:create', data: { workflow, args } });
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
- this.getLog(runId).append({
35
- type: eventType,
36
- nodeId,
37
- data: result.error ? { error: result.error } : undefined,
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) { this.persist(this.getRun(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.persist(run);
48
- this.getLog(runId).append({ type: 'run:complete' });
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.persist(run);
55
- this.getLog(runId).append({ type: 'run:fail' });
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
- const filePath = (0, path_1.join)(this.baseDir, runId, 'state.json');
61
- if (!(0, fs_1.existsSync)(filePath))
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 = JSON.parse((0, fs_1.readFileSync)(filePath, 'utf-8'));
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
- getEvents(runId) {
79
- return this.getLog(runId).readAll();
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
- getLog(runId) {
82
- let log = this.logs.get(runId);
83
- if (!log) {
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
- log = new event_log_js_1.EventLog(runDir);
87
- this.logs.set(runId, log);
186
+ wal = new wal_js_1.WAL(runDir);
187
+ this.wals.set(runId, wal);
88
188
  }
89
- return log;
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