@ghostwater/soulforge 0.1.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/dist/cli/cli.d.ts +2 -0
  4. package/dist/cli/cli.js +483 -0
  5. package/dist/cli/cli.js.map +1 -0
  6. package/dist/daemon/daemon-entry.d.ts +2 -0
  7. package/dist/daemon/daemon-entry.js +8 -0
  8. package/dist/daemon/daemon-entry.js.map +1 -0
  9. package/dist/daemon/daemon.d.ts +9 -0
  10. package/dist/daemon/daemon.js +88 -0
  11. package/dist/daemon/daemon.js.map +1 -0
  12. package/dist/daemon/runner.d.ts +3 -0
  13. package/dist/daemon/runner.js +310 -0
  14. package/dist/daemon/runner.js.map +1 -0
  15. package/dist/db/database.d.ts +95 -0
  16. package/dist/db/database.js +277 -0
  17. package/dist/db/database.js.map +1 -0
  18. package/dist/executors/claude-code.d.ts +9 -0
  19. package/dist/executors/claude-code.js +86 -0
  20. package/dist/executors/claude-code.js.map +1 -0
  21. package/dist/executors/codex.d.ts +9 -0
  22. package/dist/executors/codex.js +66 -0
  23. package/dist/executors/codex.js.map +1 -0
  24. package/dist/executors/openclaw.d.ts +10 -0
  25. package/dist/executors/openclaw.js +19 -0
  26. package/dist/executors/openclaw.js.map +1 -0
  27. package/dist/executors/registry.d.ts +4 -0
  28. package/dist/executors/registry.js +20 -0
  29. package/dist/executors/registry.js.map +1 -0
  30. package/dist/executors/self.d.ts +10 -0
  31. package/dist/executors/self.js +25 -0
  32. package/dist/executors/self.js.map +1 -0
  33. package/dist/executors/types.d.ts +41 -0
  34. package/dist/executors/types.js +2 -0
  35. package/dist/executors/types.js.map +1 -0
  36. package/dist/index.d.ts +6 -0
  37. package/dist/index.js +7 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/lib/logger.d.ts +7 -0
  40. package/dist/lib/logger.js +56 -0
  41. package/dist/lib/logger.js.map +1 -0
  42. package/dist/lib/worktree.d.ts +30 -0
  43. package/dist/lib/worktree.js +131 -0
  44. package/dist/lib/worktree.js.map +1 -0
  45. package/dist/workflow/parser.d.ts +2 -0
  46. package/dist/workflow/parser.js +95 -0
  47. package/dist/workflow/parser.js.map +1 -0
  48. package/dist/workflow/template.d.ts +14 -0
  49. package/dist/workflow/template.js +71 -0
  50. package/dist/workflow/template.js.map +1 -0
  51. package/dist/workflow/types.d.ts +65 -0
  52. package/dist/workflow/types.js +2 -0
  53. package/dist/workflow/types.js.map +1 -0
  54. package/package.json +46 -0
  55. package/workflows/feature-dev/workflow.yml +169 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-entry.js","sourceRoot":"","sources":["../../src/daemon/daemon-entry.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function isDaemonRunning(): {
2
+ running: boolean;
3
+ pid?: number;
4
+ };
5
+ export declare function startDaemonForeground(): void;
6
+ export declare function startDaemonBackground(): {
7
+ pid: number;
8
+ };
9
+ export declare function stopDaemon(): boolean;
@@ -0,0 +1,88 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { spawn } from "node:child_process";
4
+ import { fileURLToPath } from "node:url";
5
+ import { startRunner, stopRunner } from "./runner.js";
6
+ import { logger } from "../lib/logger.js";
7
+ import { closeDb, getDataDir } from "../db/database.js";
8
+ const PID_FILE = path.join(getDataDir(), "daemon.pid");
9
+ export function isDaemonRunning() {
10
+ try {
11
+ const pid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
12
+ // Check if process exists
13
+ process.kill(pid, 0);
14
+ return { running: true, pid };
15
+ }
16
+ catch {
17
+ // Clean up stale PID file
18
+ try {
19
+ fs.unlinkSync(PID_FILE);
20
+ }
21
+ catch { }
22
+ return { running: false };
23
+ }
24
+ }
25
+ export function startDaemonForeground() {
26
+ // Write PID file
27
+ fs.mkdirSync(path.dirname(PID_FILE), { recursive: true });
28
+ fs.writeFileSync(PID_FILE, String(process.pid));
29
+ logger.info(`Daemon started (PID ${process.pid})`);
30
+ console.log(`Soulforge daemon started (PID ${process.pid})`);
31
+ // Handle shutdown
32
+ const shutdown = () => {
33
+ logger.info("Daemon shutting down");
34
+ stopRunner();
35
+ closeDb();
36
+ try {
37
+ fs.unlinkSync(PID_FILE);
38
+ }
39
+ catch { }
40
+ process.exit(0);
41
+ };
42
+ process.on("SIGTERM", shutdown);
43
+ process.on("SIGINT", shutdown);
44
+ // Start the runner
45
+ startRunner().catch((err) => {
46
+ logger.error(`Runner crashed: ${err}`);
47
+ shutdown();
48
+ });
49
+ }
50
+ export function startDaemonBackground() {
51
+ const status = isDaemonRunning();
52
+ if (status.running) {
53
+ console.log(`Daemon already running (PID ${status.pid})`);
54
+ return { pid: status.pid };
55
+ }
56
+ const __filename = fileURLToPath(import.meta.url);
57
+ const daemonEntry = path.join(path.dirname(__filename), "daemon-entry.js");
58
+ const logPath = path.join(getDataDir(), "daemon.log");
59
+ const outFd = fs.openSync(logPath, "a");
60
+ const child = spawn(process.execPath, [daemonEntry], {
61
+ detached: true,
62
+ stdio: ["ignore", outFd, outFd],
63
+ env: { ...process.env, SOULFORGE_DAEMON: "1" },
64
+ });
65
+ child.unref();
66
+ fs.closeSync(outFd);
67
+ console.log(`Soulforge daemon started (PID ${child.pid})`);
68
+ return { pid: child.pid };
69
+ }
70
+ export function stopDaemon() {
71
+ const status = isDaemonRunning();
72
+ if (!status.running || !status.pid) {
73
+ return false;
74
+ }
75
+ try {
76
+ process.kill(status.pid, "SIGTERM");
77
+ // Wait briefly for clean shutdown
78
+ try {
79
+ fs.unlinkSync(PID_FILE);
80
+ }
81
+ catch { }
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/daemon/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function isRunnerRunning(): boolean;
2
+ export declare function startRunner(): Promise<void>;
3
+ export declare function stopRunner(): void;
@@ -0,0 +1,310 @@
1
+ import { getDb, getNextPendingStep, updateStepStatus, updateRunStatus, updateRunContext, advancePipeline, insertEvent, insertStories, getStoriesForRun, getNextPendingStory, updateStoryStatus, incrementStepRetry, incrementStoryRetry, } from "../db/database.js";
2
+ import { getExecutor } from "../executors/registry.js";
3
+ import { resolveTemplate, parseStoriesJson } from "../workflow/template.js";
4
+ import { logger } from "../lib/logger.js";
5
+ const POLL_INTERVAL_MS = 2000;
6
+ let running = false;
7
+ async function fireCallback(run, event) {
8
+ if (!run.callback)
9
+ return;
10
+ const callback = JSON.parse(run.callback);
11
+ const body = {
12
+ ...callback.bodyTemplate,
13
+ message: event.summary,
14
+ event: event.type,
15
+ runId: run.id,
16
+ workflowId: run.workflow_id,
17
+ task: run.task,
18
+ details: event.details,
19
+ };
20
+ try {
21
+ await fetch(callback.url, {
22
+ method: callback.method ?? 'POST',
23
+ headers: { 'Content-Type': 'application/json', ...callback.headers },
24
+ body: JSON.stringify(body),
25
+ });
26
+ }
27
+ catch (err) {
28
+ logger.warn(`Callback failed: ${err}`, { runId: run.id.slice(0, 8) });
29
+ }
30
+ }
31
+ export function isRunnerRunning() {
32
+ return running;
33
+ }
34
+ export async function startRunner() {
35
+ if (running)
36
+ return;
37
+ running = true;
38
+ logger.info("Runner started");
39
+ // Recover any interrupted runs
40
+ recoverInterruptedRuns();
41
+ while (running) {
42
+ try {
43
+ await tick();
44
+ }
45
+ catch (err) {
46
+ logger.error("Runner tick error", { error: String(err) });
47
+ }
48
+ await sleep(POLL_INTERVAL_MS);
49
+ }
50
+ }
51
+ export function stopRunner() {
52
+ running = false;
53
+ logger.info("Runner stopping");
54
+ }
55
+ async function tick() {
56
+ const db = getDb();
57
+ // Find runs with pending steps
58
+ const activeRuns = db.prepare("SELECT DISTINCT r.* FROM runs r JOIN steps s ON s.run_id = r.id WHERE r.status IN ('running', 'pending') AND s.status = 'pending'").all();
59
+ for (const run of activeRuns) {
60
+ // Ensure run is marked as running
61
+ if (run.status === "pending") {
62
+ updateRunStatus(run.id, "running");
63
+ }
64
+ const step = getNextPendingStep(run.id);
65
+ if (!step)
66
+ continue;
67
+ await executeStep(run, step);
68
+ }
69
+ }
70
+ async function executeStep(run, step) {
71
+ const context = JSON.parse(run.context);
72
+ const executor = getExecutor(step.executor);
73
+ logger.info(`Executing step "${step.step_id}" with ${step.executor}`, {
74
+ runId: run.id.slice(0, 8),
75
+ model: step.model,
76
+ });
77
+ // Handle loop steps
78
+ if (step.type === "loop") {
79
+ await executeLoopStep(run, step, context);
80
+ return;
81
+ }
82
+ // Resolve template
83
+ const resolvedInput = resolveTemplate(step.input_template, context);
84
+ const workdir = step.workdir ? resolveTemplate(step.workdir, context) : process.cwd();
85
+ // Mark as running
86
+ updateStepStatus(step.id, "running");
87
+ insertEvent(run.id, "step_started", `Step "${step.step_id}" started (${step.executor})`, step.step_id);
88
+ try {
89
+ const result = await executor.execute({
90
+ input: resolvedInput,
91
+ workdir,
92
+ model: step.model ?? undefined,
93
+ timeout: 600, // 10 min default; TODO: store per-step timeout in DB
94
+ expects: step.expects ?? undefined,
95
+ step,
96
+ run,
97
+ });
98
+ if (result.success) {
99
+ // Check for self executor checkpoint
100
+ if (step.executor === "self") {
101
+ // Step is already set to waiting_approval by the self executor
102
+ logger.info(`Step "${step.step_id}" waiting for approval`, { runId: run.id.slice(0, 8) });
103
+ await fireCallback(run, { type: "waiting_approval", summary: `Step "${step.step_id}" waiting for approval` });
104
+ return;
105
+ }
106
+ // Merge context
107
+ const newContext = { ...context, ...result.context };
108
+ updateRunContext(run.id, newContext);
109
+ // Check for STORIES_JSON in output
110
+ try {
111
+ const stories = parseStoriesJson(result.output);
112
+ if (stories) {
113
+ insertStories(run.id, stories);
114
+ newContext["stories_json"] = JSON.stringify(stories);
115
+ updateRunContext(run.id, newContext);
116
+ logger.info(`Parsed ${stories.length} stories from step output`, { runId: run.id.slice(0, 8) });
117
+ }
118
+ }
119
+ catch (err) {
120
+ logger.warn(`Failed to parse STORIES_JSON: ${err}`, { runId: run.id.slice(0, 8) });
121
+ }
122
+ // Mark done and advance
123
+ updateStepStatus(step.id, "done", { output: result.output, duration_ms: result.durationMs });
124
+ insertEvent(run.id, "step_complete", `Step "${step.step_id}" completed (${result.durationMs}ms)`, step.step_id);
125
+ const { runCompleted } = advancePipeline(run.id);
126
+ if (runCompleted) {
127
+ insertEvent(run.id, "run_complete", `Run completed: "${run.task}"`);
128
+ logger.info("Run completed", { runId: run.id.slice(0, 8) });
129
+ await fireCallback(run, { type: "run_complete", summary: `Run completed: "${run.task}"` });
130
+ }
131
+ }
132
+ else {
133
+ await handleStepFailure(run, step, result.error ?? "Unknown error", result.output, result.durationMs);
134
+ }
135
+ }
136
+ catch (err) {
137
+ await handleStepFailure(run, step, String(err), "", 0);
138
+ }
139
+ }
140
+ async function executeLoopStep(run, step, context) {
141
+ const loopConfig = step.loop_config ? JSON.parse(step.loop_config) : null;
142
+ if (!loopConfig || loopConfig.over !== "stories") {
143
+ await handleStepFailure(run, step, "Invalid loop config", "", 0);
144
+ return;
145
+ }
146
+ // Find next pending story
147
+ const story = getNextPendingStory(run.id);
148
+ if (!story) {
149
+ // All stories done — mark step done and advance
150
+ updateStepStatus(step.id, "done");
151
+ const { runCompleted } = advancePipeline(run.id);
152
+ if (runCompleted) {
153
+ insertEvent(run.id, "run_complete", `Run completed: "${run.task}"`);
154
+ logger.info("Run completed", { runId: run.id.slice(0, 8) });
155
+ await fireCallback(run, { type: "run_complete", summary: `Run completed: "${run.task}"` });
156
+ }
157
+ return;
158
+ }
159
+ // Build story context
160
+ const allStories = getStoriesForRun(run.id);
161
+ const ac = JSON.parse(story.acceptance_criteria);
162
+ const storyText = `Story ${story.story_id}: ${story.title}\n\n${story.description}\n\nAcceptance Criteria:\n${ac.map((c, i) => ` ${i + 1}. ${c}`).join("\n")}`;
163
+ const completedStories = allStories
164
+ .filter((s) => s.status === "done")
165
+ .map((s) => `- ${s.story_id}: ${s.title}`)
166
+ .join("\n") || "(none yet)";
167
+ const pendingCount = allStories.filter((s) => s.status === "pending" || s.status === "running").length;
168
+ const storyContext = {
169
+ ...context,
170
+ current_story: storyText,
171
+ current_story_id: story.story_id,
172
+ current_story_title: story.title,
173
+ completed_stories: completedStories,
174
+ stories_remaining: String(pendingCount),
175
+ verify_feedback: context.verify_feedback ?? "",
176
+ };
177
+ // Resolve template
178
+ const resolvedInput = resolveTemplate(step.input_template, storyContext);
179
+ const workdir = step.workdir ? resolveTemplate(step.workdir, storyContext) : process.cwd();
180
+ // Mark step and story as running
181
+ updateStepStatus(step.id, "running", { current_story_id: story.id });
182
+ updateStoryStatus(story.id, "running");
183
+ updateRunContext(run.id, storyContext);
184
+ const executor = getExecutor(step.executor);
185
+ logger.info(`Executing loop step "${step.step_id}" — story ${story.story_id}: ${story.title}`, {
186
+ runId: run.id.slice(0, 8),
187
+ });
188
+ insertEvent(run.id, "step_started", `Story ${story.story_id}: ${story.title}`, step.step_id);
189
+ try {
190
+ const result = await executor.execute({
191
+ input: resolvedInput,
192
+ workdir,
193
+ model: step.model ?? undefined,
194
+ expects: step.expects ?? undefined,
195
+ step,
196
+ run,
197
+ });
198
+ if (result.success) {
199
+ // Merge context
200
+ const newContext = { ...storyContext, ...result.context };
201
+ updateRunContext(run.id, newContext);
202
+ // Mark story done
203
+ updateStoryStatus(story.id, "done", result.output);
204
+ updateStepStatus(step.id, "running", { output: result.output, current_story_id: null, duration_ms: result.durationMs });
205
+ // Check for verify_each
206
+ if (loopConfig.verifyEach && loopConfig.verifyStep) {
207
+ // Set verify step to pending
208
+ const db = getDb();
209
+ const verifyStep = db.prepare("SELECT id FROM steps WHERE run_id = ? AND step_id = ? LIMIT 1").get(run.id, loopConfig.verifyStep);
210
+ if (verifyStep) {
211
+ updateStepStatus(verifyStep.id, "pending");
212
+ logger.info(`Verify step "${loopConfig.verifyStep}" triggered for story ${story.story_id}`);
213
+ return;
214
+ }
215
+ }
216
+ // No verify — check for more stories
217
+ continueLoop(run.id, step.id);
218
+ }
219
+ else {
220
+ // Story failed
221
+ await handleLoopStepFailure(run, step, story, result.error ?? "Unknown error");
222
+ }
223
+ }
224
+ catch (err) {
225
+ await handleLoopStepFailure(run, step, story, String(err));
226
+ }
227
+ }
228
+ function continueLoop(runId, loopStepId) {
229
+ const next = getNextPendingStory(runId);
230
+ if (next) {
231
+ // More stories — set loop step back to pending
232
+ updateStepStatus(loopStepId, "pending", { current_story_id: null });
233
+ }
234
+ else {
235
+ // All done — mark loop step done and advance
236
+ updateStepStatus(loopStepId, "done");
237
+ // Also mark verify step done if it exists
238
+ const step = getDb().prepare("SELECT loop_config FROM steps WHERE id = ?").get(loopStepId);
239
+ if (step?.loop_config) {
240
+ const lc = JSON.parse(step.loop_config);
241
+ if (lc.verifyEach && lc.verifyStep) {
242
+ const db = getDb();
243
+ const run = db.prepare("SELECT run_id FROM steps WHERE id = ?").get(loopStepId);
244
+ db.prepare("UPDATE steps SET status = 'done', updated_at = ? WHERE run_id = ? AND step_id = ?").run(new Date().toISOString(), run.run_id, lc.verifyStep);
245
+ }
246
+ }
247
+ const { runCompleted } = advancePipeline(runId);
248
+ if (runCompleted) {
249
+ insertEvent(runId, "run_complete", `Run completed`);
250
+ logger.info("Run completed", { runId: runId.slice(0, 8) });
251
+ }
252
+ }
253
+ }
254
+ async function handleStepFailure(run, step, error, output, durationMs) {
255
+ const newRetry = incrementStepRetry(step.id);
256
+ logger.warn(`Step "${step.step_id}" failed (attempt ${newRetry}/${step.max_retries})`, {
257
+ runId: run.id.slice(0, 8),
258
+ error: error.slice(0, 200),
259
+ });
260
+ if (newRetry > step.max_retries) {
261
+ updateStepStatus(step.id, "failed", { output, error, duration_ms: durationMs });
262
+ updateRunStatus(run.id, "failed");
263
+ insertEvent(run.id, "step_failed", `Step "${step.step_id}" failed: ${error.slice(0, 200)}`, step.step_id, error);
264
+ insertEvent(run.id, "run_failed", `Run failed at step "${step.step_id}"`);
265
+ logger.error(`Run failed at step "${step.step_id}"`, { runId: run.id.slice(0, 8) });
266
+ await fireCallback(run, { type: "step_failed", summary: `Step "${step.step_id}" failed after max retries`, details: error });
267
+ await fireCallback(run, { type: "run_failed", summary: `Run failed at step "${step.step_id}"`, details: error });
268
+ }
269
+ else {
270
+ // Retry — set back to pending
271
+ updateStepStatus(step.id, "pending", { error });
272
+ insertEvent(run.id, "step_retry", `Step "${step.step_id}" retrying (${newRetry}/${step.max_retries})`, step.step_id);
273
+ }
274
+ }
275
+ async function handleLoopStepFailure(run, step, story, error) {
276
+ const newRetry = incrementStoryRetry(story.id);
277
+ logger.warn(`Story ${story.story_id} failed (attempt ${newRetry}/${story.max_retries})`, {
278
+ runId: run.id.slice(0, 8),
279
+ });
280
+ if (newRetry > story.max_retries) {
281
+ updateStoryStatus(story.id, "failed");
282
+ updateStepStatus(step.id, "failed", { error, current_story_id: null });
283
+ updateRunStatus(run.id, "failed");
284
+ insertEvent(run.id, "step_failed", `Story ${story.story_id} failed: ${error.slice(0, 200)}`, step.step_id, error);
285
+ insertEvent(run.id, "run_failed", `Run failed at story "${story.story_id}"`);
286
+ }
287
+ else {
288
+ // Retry story
289
+ updateStoryStatus(story.id, "pending");
290
+ updateStepStatus(step.id, "pending", { current_story_id: null });
291
+ insertEvent(run.id, "step_retry", `Story ${story.story_id} retrying (${newRetry}/${story.max_retries})`, step.step_id);
292
+ }
293
+ }
294
+ function recoverInterruptedRuns() {
295
+ const db = getDb();
296
+ // Reset any running steps back to pending (daemon restarted mid-execution)
297
+ const runningSteps = db.prepare("SELECT id, step_id, run_id, current_story_id FROM steps WHERE status = 'running'").all();
298
+ for (const step of runningSteps) {
299
+ updateStepStatus(step.id, "pending", { current_story_id: null });
300
+ // If it had a running story, reset that too
301
+ if (step.current_story_id) {
302
+ updateStoryStatus(step.current_story_id, "pending");
303
+ }
304
+ logger.info(`Recovered interrupted step "${step.step_id}"`, { runId: step.run_id.slice(0, 8) });
305
+ }
306
+ }
307
+ function sleep(ms) {
308
+ return new Promise((resolve) => setTimeout(resolve, ms));
309
+ }
310
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/daemon/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import type { ExecutorType, WorkflowSpec, CallbackConfig } from "../workflow/types.js";
3
+ export declare const EVENTS_DIR: string;
4
+ export declare function getDataDir(): string;
5
+ export declare function getDb(): DatabaseSync;
6
+ export declare function closeDb(): void;
7
+ export interface RunRecord {
8
+ id: string;
9
+ workflow_id: string;
10
+ workflow_path: string;
11
+ task: string;
12
+ status: string;
13
+ context: string;
14
+ callback: string | null;
15
+ worktree: string | null;
16
+ created_at: string;
17
+ updated_at: string;
18
+ }
19
+ export interface StepRecord {
20
+ id: string;
21
+ run_id: string;
22
+ step_id: string;
23
+ executor: ExecutorType;
24
+ model: string | null;
25
+ agent_id: string | null;
26
+ step_index: number;
27
+ input_template: string;
28
+ expects: string | null;
29
+ status: string;
30
+ output: string | null;
31
+ error: string | null;
32
+ retry_count: number;
33
+ max_retries: number;
34
+ duration_ms: number | null;
35
+ type: string;
36
+ loop_config: string | null;
37
+ current_story_id: string | null;
38
+ workdir: string | null;
39
+ created_at: string;
40
+ updated_at: string;
41
+ }
42
+ export interface StoryRecord {
43
+ id: string;
44
+ run_id: string;
45
+ story_index: number;
46
+ story_id: string;
47
+ title: string;
48
+ description: string;
49
+ acceptance_criteria: string;
50
+ status: string;
51
+ output: string | null;
52
+ retry_count: number;
53
+ max_retries: number;
54
+ created_at: string;
55
+ updated_at: string;
56
+ }
57
+ export interface EventRecord {
58
+ id: number;
59
+ run_id: string;
60
+ step_id: string | null;
61
+ type: string;
62
+ summary: string;
63
+ details: string | null;
64
+ created_at: string;
65
+ }
66
+ export declare function createRun(workflowSpec: WorkflowSpec, workflowPath: string, task: string, callback?: CallbackConfig, worktreeMetadata?: {
67
+ originalRepo: string;
68
+ worktreePath: string;
69
+ branch: string;
70
+ }): RunRecord;
71
+ export declare function getRun(runId: string): RunRecord | null;
72
+ export declare function listRuns(limit?: number): RunRecord[];
73
+ export declare function updateRunStatus(runId: string, status: string): void;
74
+ export declare function updateRunContext(runId: string, context: Record<string, string>): void;
75
+ export declare function getStepsForRun(runId: string): StepRecord[];
76
+ export declare function getStep(stepId: string): StepRecord | null;
77
+ export declare function getNextPendingStep(runId: string): StepRecord | null;
78
+ export declare function updateStepStatus(stepId: string, status: string, extra?: {
79
+ output?: string;
80
+ error?: string;
81
+ duration_ms?: number;
82
+ current_story_id?: string | null;
83
+ }): void;
84
+ export declare function incrementStepRetry(stepId: string): number;
85
+ export declare function advancePipeline(runId: string): {
86
+ advanced: boolean;
87
+ runCompleted: boolean;
88
+ };
89
+ export declare function insertStories(runId: string, stories: any[]): void;
90
+ export declare function getStoriesForRun(runId: string): StoryRecord[];
91
+ export declare function getNextPendingStory(runId: string): StoryRecord | null;
92
+ export declare function updateStoryStatus(storyId: string, status: string, output?: string): void;
93
+ export declare function incrementStoryRetry(storyId: string): number;
94
+ export declare function insertEvent(runId: string, type: string, summary: string, stepId?: string, details?: string): void;
95
+ export declare function getEvents(runId?: string, limit?: number): EventRecord[];