@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.
- package/LICENSE +21 -0
- package/README.md +115 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +483 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/daemon/daemon-entry.d.ts +2 -0
- package/dist/daemon/daemon-entry.js +8 -0
- package/dist/daemon/daemon-entry.js.map +1 -0
- package/dist/daemon/daemon.d.ts +9 -0
- package/dist/daemon/daemon.js +88 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/daemon/runner.d.ts +3 -0
- package/dist/daemon/runner.js +310 -0
- package/dist/daemon/runner.js.map +1 -0
- package/dist/db/database.d.ts +95 -0
- package/dist/db/database.js +277 -0
- package/dist/db/database.js.map +1 -0
- package/dist/executors/claude-code.d.ts +9 -0
- package/dist/executors/claude-code.js +86 -0
- package/dist/executors/claude-code.js.map +1 -0
- package/dist/executors/codex.d.ts +9 -0
- package/dist/executors/codex.js +66 -0
- package/dist/executors/codex.js.map +1 -0
- package/dist/executors/openclaw.d.ts +10 -0
- package/dist/executors/openclaw.js +19 -0
- package/dist/executors/openclaw.js.map +1 -0
- package/dist/executors/registry.d.ts +4 -0
- package/dist/executors/registry.js +20 -0
- package/dist/executors/registry.js.map +1 -0
- package/dist/executors/self.d.ts +10 -0
- package/dist/executors/self.js +25 -0
- package/dist/executors/self.js.map +1 -0
- package/dist/executors/types.d.ts +41 -0
- package/dist/executors/types.js +2 -0
- package/dist/executors/types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/logger.d.ts +7 -0
- package/dist/lib/logger.js +56 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/worktree.d.ts +30 -0
- package/dist/lib/worktree.js +131 -0
- package/dist/lib/worktree.js.map +1 -0
- package/dist/workflow/parser.d.ts +2 -0
- package/dist/workflow/parser.js +95 -0
- package/dist/workflow/parser.js.map +1 -0
- package/dist/workflow/template.d.ts +14 -0
- package/dist/workflow/template.js +71 -0
- package/dist/workflow/template.js.map +1 -0
- package/dist/workflow/types.d.ts +65 -0
- package/dist/workflow/types.js +2 -0
- package/dist/workflow/types.js.map +1 -0
- package/package.json +46 -0
- 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,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[];
|