@portel/photon-core 1.3.0 → 1.4.0
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/dist/generator.d.ts +236 -2
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +30 -0
- package/dist/generator.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-client.d.ts +39 -0
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +213 -0
- package/dist/mcp-client.js.map +1 -1
- package/dist/photon-config.d.ts +86 -0
- package/dist/photon-config.d.ts.map +1 -0
- package/dist/photon-config.js +156 -0
- package/dist/photon-config.js.map +1 -0
- package/dist/schema-extractor.d.ts +99 -1
- package/dist/schema-extractor.d.ts.map +1 -1
- package/dist/schema-extractor.js +311 -5
- package/dist/schema-extractor.js.map +1 -1
- package/dist/stateful.d.ts +238 -0
- package/dist/stateful.d.ts.map +1 -0
- package/dist/stateful.js +469 -0
- package/dist/stateful.js.map +1 -0
- package/dist/types.d.ts +260 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -2
- package/src/generator.ts +270 -2
- package/src/index.ts +73 -1
- package/src/mcp-client.ts +254 -0
- package/src/photon-config.ts +201 -0
- package/src/schema-extractor.ts +353 -6
- package/src/stateful.ts +659 -0
- package/src/types.ts +289 -0
package/dist/stateful.js
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateful Workflow Execution with JSONL Persistence
|
|
3
|
+
*
|
|
4
|
+
* Enables photon workflows to be paused, resumed, and recovered across daemon restarts.
|
|
5
|
+
*
|
|
6
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
* DESIGN PHILOSOPHY
|
|
8
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
9
|
+
*
|
|
10
|
+
* Stateful workflows use an append-only JSONL log for persistence:
|
|
11
|
+
* - Each line is a self-contained JSON entry (start, emit, checkpoint, ask, answer, return, error)
|
|
12
|
+
* - Checkpoints mark safe resume points with accumulated state
|
|
13
|
+
* - Developer places checkpoint AFTER side effects to ensure idempotency
|
|
14
|
+
* - Resume loads log, reconstructs state from last checkpoint, continues
|
|
15
|
+
*
|
|
16
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
17
|
+
* CHECKPOINT PATTERN (Idempotent Resume)
|
|
18
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
19
|
+
*
|
|
20
|
+
* ```typescript
|
|
21
|
+
* async *workflow() {
|
|
22
|
+
* // Step 1: Side effect (e.g., posting to Slack)
|
|
23
|
+
* const posted = await this.slack.post_message({ channel: '#eng', text: 'Hello' });
|
|
24
|
+
* yield { checkpoint: true, state: { step: 1, messageTs: posted.ts } };
|
|
25
|
+
*
|
|
26
|
+
* // Step 2: Another side effect (e.g., creating GitHub issue)
|
|
27
|
+
* const issue = await this.github.create_issue({ ... });
|
|
28
|
+
* yield { checkpoint: true, state: { step: 2, messageTs: posted.ts, issueNumber: issue.number } };
|
|
29
|
+
*
|
|
30
|
+
* return { posted, issue };
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* On resume: Load state from last checkpoint, skip to that step, continue execution.
|
|
35
|
+
*
|
|
36
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
37
|
+
* JSONL LOG FORMAT
|
|
38
|
+
* ══════════════════════════════════════════════════════════════════════════════
|
|
39
|
+
*
|
|
40
|
+
* ~/.photon/runs/{runId}.jsonl
|
|
41
|
+
*
|
|
42
|
+
* ```jsonl
|
|
43
|
+
* {"t":"start","tool":"generate","params":{"week":"52"},"ts":1704067200}
|
|
44
|
+
* {"t":"emit","emit":"status","message":"Collecting data...","ts":1704067201}
|
|
45
|
+
* {"t":"checkpoint","id":"cp_1","state":{"commits":["a1b2c3"],"step":1},"ts":1704067205}
|
|
46
|
+
* {"t":"ask","id":"approve","ask":"confirm","message":"Continue?","ts":1704067211}
|
|
47
|
+
* {"t":"answer","id":"approve","value":true,"ts":1704067215}
|
|
48
|
+
* {"t":"return","value":{"status":"done"},"ts":1704067220}
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @module stateful
|
|
52
|
+
*/
|
|
53
|
+
import * as fs from 'fs/promises';
|
|
54
|
+
import * as path from 'path';
|
|
55
|
+
import * as os from 'os';
|
|
56
|
+
import { createReadStream } from 'fs';
|
|
57
|
+
import { createInterface } from 'readline';
|
|
58
|
+
import { isAskYield, isEmitYield, isAsyncGenerator, } from './generator.js';
|
|
59
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
60
|
+
// CONSTANTS
|
|
61
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
62
|
+
/**
|
|
63
|
+
* Default runs directory (~/.photon/runs)
|
|
64
|
+
*/
|
|
65
|
+
export const RUNS_DIR = path.join(os.homedir(), '.photon', 'runs');
|
|
66
|
+
/**
|
|
67
|
+
* Type guard for checkpoint yields
|
|
68
|
+
*/
|
|
69
|
+
export function isCheckpointYield(y) {
|
|
70
|
+
return 'checkpoint' in y && y.checkpoint === true;
|
|
71
|
+
}
|
|
72
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
73
|
+
// STATE LOG - JSONL Persistence
|
|
74
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
75
|
+
/**
|
|
76
|
+
* State log writer for a single workflow run
|
|
77
|
+
*/
|
|
78
|
+
export class StateLog {
|
|
79
|
+
runId;
|
|
80
|
+
logPath;
|
|
81
|
+
constructor(runId, runsDir) {
|
|
82
|
+
this.runId = runId;
|
|
83
|
+
this.logPath = path.join(runsDir || RUNS_DIR, `${runId}.jsonl`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Ensure runs directory exists
|
|
87
|
+
*/
|
|
88
|
+
async init() {
|
|
89
|
+
await fs.mkdir(path.dirname(this.logPath), { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Append an entry to the log
|
|
93
|
+
*/
|
|
94
|
+
async append(entry) {
|
|
95
|
+
const line = JSON.stringify({ ...entry, ts: Date.now() }) + '\n';
|
|
96
|
+
await fs.appendFile(this.logPath, line, 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Write start entry
|
|
100
|
+
*/
|
|
101
|
+
async writeStart(tool, params) {
|
|
102
|
+
await this.append({ t: 'start', tool, params });
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Write emit entry
|
|
106
|
+
*/
|
|
107
|
+
async writeEmit(emit, message, data) {
|
|
108
|
+
await this.append({ t: 'emit', emit, message, data });
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Write checkpoint entry
|
|
112
|
+
*/
|
|
113
|
+
async writeCheckpoint(id, state) {
|
|
114
|
+
await this.append({ t: 'checkpoint', id, state });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write ask entry
|
|
118
|
+
*/
|
|
119
|
+
async writeAsk(id, ask, message) {
|
|
120
|
+
await this.append({ t: 'ask', id, ask, message });
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Write answer entry
|
|
124
|
+
*/
|
|
125
|
+
async writeAnswer(id, value) {
|
|
126
|
+
await this.append({ t: 'answer', id, value });
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Write return entry
|
|
130
|
+
*/
|
|
131
|
+
async writeReturn(value) {
|
|
132
|
+
await this.append({ t: 'return', value });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Write error entry
|
|
136
|
+
*/
|
|
137
|
+
async writeError(message, stack) {
|
|
138
|
+
await this.append({ t: 'error', message, stack });
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Read all entries from the log
|
|
142
|
+
*/
|
|
143
|
+
async readAll() {
|
|
144
|
+
try {
|
|
145
|
+
const content = await fs.readFile(this.logPath, 'utf-8');
|
|
146
|
+
return content
|
|
147
|
+
.trim()
|
|
148
|
+
.split('\n')
|
|
149
|
+
.filter(line => line.length > 0)
|
|
150
|
+
.map(line => JSON.parse(line));
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error.code === 'ENOENT') {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Stream entries from the log (memory efficient for large logs)
|
|
161
|
+
*/
|
|
162
|
+
async *stream() {
|
|
163
|
+
const fileStream = createReadStream(this.logPath);
|
|
164
|
+
const rl = createInterface({ input: fileStream });
|
|
165
|
+
for await (const line of rl) {
|
|
166
|
+
if (line.trim()) {
|
|
167
|
+
yield JSON.parse(line);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get the log file path
|
|
173
|
+
*/
|
|
174
|
+
getPath() {
|
|
175
|
+
return this.logPath;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Parse a workflow log and reconstruct resume state
|
|
180
|
+
*/
|
|
181
|
+
export async function parseResumeState(runId, runsDir) {
|
|
182
|
+
const log = new StateLog(runId, runsDir);
|
|
183
|
+
const entries = await log.readAll();
|
|
184
|
+
if (entries.length === 0) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const state = {
|
|
188
|
+
tool: '',
|
|
189
|
+
params: {},
|
|
190
|
+
isComplete: false,
|
|
191
|
+
answers: {},
|
|
192
|
+
entries,
|
|
193
|
+
};
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
switch (entry.t) {
|
|
196
|
+
case 'start':
|
|
197
|
+
state.tool = entry.tool;
|
|
198
|
+
state.params = entry.params;
|
|
199
|
+
break;
|
|
200
|
+
case 'checkpoint':
|
|
201
|
+
state.lastCheckpoint = {
|
|
202
|
+
id: entry.id,
|
|
203
|
+
state: entry.state,
|
|
204
|
+
ts: entry.ts,
|
|
205
|
+
};
|
|
206
|
+
break;
|
|
207
|
+
case 'answer':
|
|
208
|
+
state.answers[entry.id] = entry.value;
|
|
209
|
+
break;
|
|
210
|
+
case 'return':
|
|
211
|
+
state.isComplete = true;
|
|
212
|
+
state.result = entry.value;
|
|
213
|
+
break;
|
|
214
|
+
case 'error':
|
|
215
|
+
state.isComplete = true;
|
|
216
|
+
state.error = entry.message;
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return state;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Generate a unique run ID
|
|
224
|
+
*/
|
|
225
|
+
export function generateRunId() {
|
|
226
|
+
const timestamp = Date.now().toString(36);
|
|
227
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
228
|
+
return `run_${timestamp}_${random}`;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Execute a stateful generator with checkpoint support
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* const result = await executeStatefulGenerator(workflow(), {
|
|
235
|
+
* photon: 'weekly-report',
|
|
236
|
+
* tool: 'generate',
|
|
237
|
+
* params: { week: 52 },
|
|
238
|
+
* inputProvider: cliInputProvider,
|
|
239
|
+
* outputHandler: (emit) => console.log(emit.message)
|
|
240
|
+
* });
|
|
241
|
+
*/
|
|
242
|
+
export async function executeStatefulGenerator(generatorFn, config) {
|
|
243
|
+
const runId = config.runId || generateRunId();
|
|
244
|
+
const log = new StateLog(runId, config.runsDir);
|
|
245
|
+
await log.init();
|
|
246
|
+
let resumed = false;
|
|
247
|
+
let resumeState = null;
|
|
248
|
+
let checkpointIndex = 0;
|
|
249
|
+
let askIndex = 0;
|
|
250
|
+
// Check if we should resume
|
|
251
|
+
if (config.resume) {
|
|
252
|
+
resumeState = await parseResumeState(runId, config.runsDir);
|
|
253
|
+
if (resumeState) {
|
|
254
|
+
resumed = true;
|
|
255
|
+
if (resumeState.isComplete) {
|
|
256
|
+
// Already complete, return cached result
|
|
257
|
+
return {
|
|
258
|
+
runId,
|
|
259
|
+
result: resumeState.result,
|
|
260
|
+
error: resumeState.error,
|
|
261
|
+
resumed: true,
|
|
262
|
+
status: resumeState.error ? 'failed' : 'completed',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Write start entry (only if not resuming)
|
|
268
|
+
if (!resumed) {
|
|
269
|
+
await log.writeStart(config.tool, config.params);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
// Call the function and check if it returns a generator or a promise
|
|
273
|
+
const maybeGenerator = generatorFn();
|
|
274
|
+
// Handle non-generator functions (regular async methods)
|
|
275
|
+
if (!isAsyncGenerator(maybeGenerator)) {
|
|
276
|
+
// It's a promise, await it directly
|
|
277
|
+
const finalValue = await maybeGenerator;
|
|
278
|
+
await log.writeReturn(finalValue);
|
|
279
|
+
return {
|
|
280
|
+
runId,
|
|
281
|
+
result: finalValue,
|
|
282
|
+
resumed,
|
|
283
|
+
status: 'completed',
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// It's a generator, proceed with generator execution
|
|
287
|
+
const generator = maybeGenerator;
|
|
288
|
+
let result = await generator.next();
|
|
289
|
+
// If resuming, fast-forward to last checkpoint
|
|
290
|
+
if (resumed && resumeState?.lastCheckpoint) {
|
|
291
|
+
const targetCheckpointId = resumeState.lastCheckpoint.id;
|
|
292
|
+
let foundCheckpoint = false;
|
|
293
|
+
// Fast-forward: run generator, skip until we hit the checkpoint
|
|
294
|
+
while (!result.done) {
|
|
295
|
+
const yielded = result.value;
|
|
296
|
+
if (isCheckpointYield(yielded)) {
|
|
297
|
+
const cpId = yielded.id || `cp_${checkpointIndex++}`;
|
|
298
|
+
if (cpId === targetCheckpointId) {
|
|
299
|
+
foundCheckpoint = true;
|
|
300
|
+
// Inject the saved state
|
|
301
|
+
result = await generator.next(resumeState.lastCheckpoint.state);
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
// Not our checkpoint, continue
|
|
305
|
+
result = await generator.next(yielded.state);
|
|
306
|
+
}
|
|
307
|
+
else if (isAskYield(yielded)) {
|
|
308
|
+
// Use saved answer
|
|
309
|
+
const askId = yielded.id || `ask_${askIndex++}`;
|
|
310
|
+
if (askId in resumeState.answers) {
|
|
311
|
+
result = await generator.next(resumeState.answers[askId]);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
// No saved answer, this shouldn't happen if log is consistent
|
|
315
|
+
throw new Error(`Resume error: missing answer for ask '${askId}'`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else if (isEmitYield(yielded)) {
|
|
319
|
+
// Skip emits during fast-forward
|
|
320
|
+
result = await generator.next();
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
result = await generator.next();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (!foundCheckpoint && !result.done) {
|
|
327
|
+
console.warn(`[stateful] Checkpoint '${targetCheckpointId}' not found during resume`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Normal execution loop
|
|
331
|
+
while (!result.done) {
|
|
332
|
+
const yielded = result.value;
|
|
333
|
+
if (isCheckpointYield(yielded)) {
|
|
334
|
+
const cpId = yielded.id || `cp_${checkpointIndex++}`;
|
|
335
|
+
await log.writeCheckpoint(cpId, yielded.state);
|
|
336
|
+
// Continue with the state (generator may use it)
|
|
337
|
+
result = await generator.next(yielded.state);
|
|
338
|
+
}
|
|
339
|
+
else if (isAskYield(yielded)) {
|
|
340
|
+
const askYield = yielded;
|
|
341
|
+
const askId = askYield.id || `ask_${askIndex++}`;
|
|
342
|
+
// Check for pre-answered (from resume state)
|
|
343
|
+
if (resumeState && askId in resumeState.answers) {
|
|
344
|
+
result = await generator.next(resumeState.answers[askId]);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
// Log ask and get input
|
|
348
|
+
await log.writeAsk(askId, askYield.ask, askYield.message);
|
|
349
|
+
const input = await config.inputProvider(askYield);
|
|
350
|
+
await log.writeAnswer(askId, input);
|
|
351
|
+
result = await generator.next(input);
|
|
352
|
+
}
|
|
353
|
+
else if (isEmitYield(yielded)) {
|
|
354
|
+
const emitYield = yielded;
|
|
355
|
+
await log.writeEmit(emitYield.emit, emitYield.message, emitYield);
|
|
356
|
+
if (config.outputHandler) {
|
|
357
|
+
await config.outputHandler(emitYield);
|
|
358
|
+
}
|
|
359
|
+
result = await generator.next();
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// Unknown yield, skip
|
|
363
|
+
result = await generator.next();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Write return entry
|
|
367
|
+
await log.writeReturn(result.value);
|
|
368
|
+
return {
|
|
369
|
+
runId,
|
|
370
|
+
result: result.value,
|
|
371
|
+
resumed,
|
|
372
|
+
status: 'completed',
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
await log.writeError(error.message, error.stack);
|
|
377
|
+
return {
|
|
378
|
+
runId,
|
|
379
|
+
error: error.message,
|
|
380
|
+
resumed,
|
|
381
|
+
status: 'failed',
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
386
|
+
// WORKFLOW RUN MANAGEMENT
|
|
387
|
+
// ══════════════════════════════════════════════════════════════════════════════
|
|
388
|
+
/**
|
|
389
|
+
* List all workflow runs
|
|
390
|
+
*/
|
|
391
|
+
export async function listRuns(runsDir) {
|
|
392
|
+
const dir = runsDir || RUNS_DIR;
|
|
393
|
+
const runs = [];
|
|
394
|
+
try {
|
|
395
|
+
const files = await fs.readdir(dir);
|
|
396
|
+
const jsonlFiles = files.filter(f => f.endsWith('.jsonl'));
|
|
397
|
+
for (const file of jsonlFiles) {
|
|
398
|
+
const runId = file.replace('.jsonl', '');
|
|
399
|
+
const run = await getRunInfo(runId, dir);
|
|
400
|
+
if (run) {
|
|
401
|
+
runs.push(run);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Sort by start time, most recent first
|
|
405
|
+
runs.sort((a, b) => b.startedAt - a.startedAt);
|
|
406
|
+
return runs;
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (error.code === 'ENOENT') {
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
throw error;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Get info about a specific run
|
|
417
|
+
*/
|
|
418
|
+
export async function getRunInfo(runId, runsDir) {
|
|
419
|
+
const state = await parseResumeState(runId, runsDir);
|
|
420
|
+
if (!state) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
const firstEntry = state.entries[0];
|
|
424
|
+
const lastEntry = state.entries[state.entries.length - 1];
|
|
425
|
+
// Determine status
|
|
426
|
+
let status = 'running';
|
|
427
|
+
if (state.isComplete) {
|
|
428
|
+
status = state.error ? 'failed' : 'completed';
|
|
429
|
+
}
|
|
430
|
+
else if (state.entries.some(e => e.t === 'ask' && !state.answers[e.id])) {
|
|
431
|
+
status = 'waiting';
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
runId,
|
|
435
|
+
photon: '', // Would need to be stored in start entry
|
|
436
|
+
tool: state.tool,
|
|
437
|
+
params: state.params,
|
|
438
|
+
status,
|
|
439
|
+
startedAt: firstEntry.ts,
|
|
440
|
+
updatedAt: lastEntry.ts,
|
|
441
|
+
completedAt: state.isComplete ? lastEntry.ts : undefined,
|
|
442
|
+
result: state.result,
|
|
443
|
+
error: state.error,
|
|
444
|
+
lastCheckpoint: state.lastCheckpoint,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Delete a workflow run
|
|
449
|
+
*/
|
|
450
|
+
export async function deleteRun(runId, runsDir) {
|
|
451
|
+
const logPath = path.join(runsDir || RUNS_DIR, `${runId}.jsonl`);
|
|
452
|
+
await fs.unlink(logPath);
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Clean up completed/failed runs older than specified age
|
|
456
|
+
*/
|
|
457
|
+
export async function cleanupRuns(maxAgeMs, runsDir) {
|
|
458
|
+
const runs = await listRuns(runsDir);
|
|
459
|
+
const cutoff = Date.now() - maxAgeMs;
|
|
460
|
+
let deleted = 0;
|
|
461
|
+
for (const run of runs) {
|
|
462
|
+
if ((run.status === 'completed' || run.status === 'failed') && run.updatedAt < cutoff) {
|
|
463
|
+
await deleteRun(run.runId, runsDir);
|
|
464
|
+
deleted++;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return deleted;
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=stateful.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateful.js","sourceRoot":"","sources":["../src/stateful.ts"],"names":[],"mappings":"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"}
|