astrocode-workflow 0.4.1 → 0.4.3
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/src/astro/workflow-runner.d.ts +1 -5
- package/dist/src/astro/workflow-runner.js +6 -17
- package/dist/src/hooks/inject-provider.js +23 -0
- package/dist/src/index.js +0 -6
- package/dist/src/tools/health.js +0 -31
- package/dist/src/tools/index.js +0 -3
- package/dist/src/tools/repair.js +4 -37
- package/dist/src/tools/workflow.js +192 -209
- package/package.json +1 -1
- package/src/astro/workflow-runner.ts +5 -25
- package/src/hooks/inject-provider.ts +24 -0
- package/src/index.ts +0 -7
- package/src/tools/health.ts +0 -29
- package/src/tools/index.ts +2 -5
- package/src/tools/repair.ts +4 -38
- package/src/tools/workflow.ts +25 -44
- package/src/state/repo-lock.ts +0 -706
- package/src/state/workflow-repo-lock.ts +0 -111
- package/src/tools/lock.ts +0 -75
package/src/tools/repair.ts
CHANGED
|
@@ -6,56 +6,22 @@ import { withTx } from "../state/db";
|
|
|
6
6
|
import { repairState, formatRepairReport } from "../workflow/repair";
|
|
7
7
|
import { putArtifact } from "../workflow/artifacts";
|
|
8
8
|
import { nowISO } from "../shared/time";
|
|
9
|
-
import { getLockStatus, tryRemoveStaleLock } from "../state/repo-lock";
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
export function createAstroRepairTool(opts: { ctx: any; config: AstrocodeConfig; db: SqliteDb }): ToolDefinition {
|
|
13
12
|
const { ctx, config, db } = opts;
|
|
14
13
|
|
|
15
14
|
return tool({
|
|
16
|
-
description: "Repair Astrocode invariants and recover from inconsistent DB state.
|
|
15
|
+
description: "Repair Astrocode invariants and recover from inconsistent DB state. Writes a repair report artifact.",
|
|
17
16
|
args: {
|
|
18
17
|
write_report_artifact: tool.schema.boolean().default(true),
|
|
19
|
-
repair_lock: tool.schema.boolean().default(true).describe("Attempt to remove stale/dead lock files"),
|
|
20
18
|
},
|
|
21
|
-
execute: async ({ write_report_artifact
|
|
19
|
+
execute: async ({ write_report_artifact }) => {
|
|
22
20
|
const repoRoot = ctx.directory as string;
|
|
23
|
-
const lockPath = path.join(repoRoot, ".astro", "astro.lock");
|
|
24
21
|
|
|
25
|
-
//
|
|
26
|
-
const lockLines: string[] = [];
|
|
27
|
-
const lockStatus = getLockStatus(lockPath);
|
|
28
|
-
|
|
29
|
-
if (lockStatus.exists) {
|
|
30
|
-
lockLines.push("## Lock Status");
|
|
31
|
-
lockLines.push(`- Lock found: ${lockPath}`);
|
|
32
|
-
lockLines.push(`- PID: ${lockStatus.pid} (${lockStatus.pidAlive ? 'alive' : 'dead'})`);
|
|
33
|
-
lockLines.push(`- Age: ${lockStatus.ageMs ? Math.floor(lockStatus.ageMs / 1000) : '?'}s`);
|
|
34
|
-
lockLines.push(`- Status: ${lockStatus.isStale ? 'stale' : 'fresh'}`);
|
|
35
|
-
|
|
36
|
-
if (repair_lock) {
|
|
37
|
-
const result = tryRemoveStaleLock(lockPath);
|
|
38
|
-
if (result.removed) {
|
|
39
|
-
lockLines.push(`- **Removed**: ${result.reason}`);
|
|
40
|
-
} else {
|
|
41
|
-
lockLines.push(`- **Not removed**: ${result.reason}`);
|
|
42
|
-
}
|
|
43
|
-
} else {
|
|
44
|
-
if (!lockStatus.pidAlive || lockStatus.isStale) {
|
|
45
|
-
lockLines.push(`- **Recommendation**: Run with repair_lock=true to remove this ${!lockStatus.pidAlive ? 'dead' : 'stale'} lock`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
lockLines.push("");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Then repair database state
|
|
22
|
+
// Repair database state
|
|
52
23
|
const report = withTx(db, () => repairState(db, config));
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
// Combine lock and DB repair
|
|
56
|
-
const fullMd = lockLines.length > 0
|
|
57
|
-
? `# Astrocode Repair Report\n\n${lockLines.join("\n")}\n${dbMd.replace(/^# Astrocode repair report\n*/i, "")}`
|
|
58
|
-
: dbMd;
|
|
24
|
+
const fullMd = formatRepairReport(report);
|
|
59
25
|
|
|
60
26
|
if (write_report_artifact) {
|
|
61
27
|
const rel = `.astro/repair/repair_${nowISO().replace(/[:.]/g, "-")}.md`;
|
package/src/tools/workflow.ts
CHANGED
|
@@ -24,8 +24,6 @@ import { newEventId } from "../state/ids";
|
|
|
24
24
|
import { debug } from "../shared/log";
|
|
25
25
|
import { createToastManager } from "../ui/toasts";
|
|
26
26
|
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
27
|
-
import { acquireRepoLock } from "../state/repo-lock";
|
|
28
|
-
import { workflowRepoLock } from "../state/workflow-repo-lock";
|
|
29
27
|
|
|
30
28
|
// Agent name mapping for case-sensitive resolution
|
|
31
29
|
export const STAGE_TO_AGENT_MAP: Record<string, string> = {
|
|
@@ -140,36 +138,33 @@ function buildUiMessage(e: UiEmitEvent): { title: string; message: string; varia
|
|
|
140
138
|
case "stage_started": {
|
|
141
139
|
const agent = e.agent_name ? ` (${e.agent_name})` : "";
|
|
142
140
|
const title = "Astrocode";
|
|
143
|
-
const message =
|
|
141
|
+
const message = `▶ Stage started: ${e.stage_key}${agent}`;
|
|
144
142
|
const chatText = [
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
`Stage: ${e.stage_key}${agent}`,
|
|
143
|
+
`### ▶ ASTROCODE: STAGE_STARTED`,
|
|
144
|
+
`**Run:** \`${e.run_id}\` `,
|
|
145
|
+
`**Stage:** \`${e.stage_key}\`${agent}`,
|
|
149
146
|
].join("\n");
|
|
150
147
|
return { title, message, variant: "info", chatText };
|
|
151
148
|
}
|
|
152
149
|
case "run_completed": {
|
|
153
150
|
const title = "Astrocode";
|
|
154
|
-
const message =
|
|
151
|
+
const message = `✓ Run completed: ${e.run_id}`;
|
|
155
152
|
const chatText = [
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`Story: ${e.story_key}`,
|
|
153
|
+
`### ✓ ASTROCODE: RUN_COMPLETED`,
|
|
154
|
+
`**Run:** \`${e.run_id}\` `,
|
|
155
|
+
`**Story:** \`${e.story_key}\``,
|
|
160
156
|
].join("\n");
|
|
161
157
|
return { title, message, variant: "success", chatText };
|
|
162
158
|
}
|
|
163
159
|
case "run_failed": {
|
|
164
160
|
const title = "Astrocode";
|
|
165
|
-
const message =
|
|
161
|
+
const message = `✖ Run failed: ${e.run_id} (${e.stage_key})`;
|
|
166
162
|
const chatText = [
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`Error: ${e.error_text}`,
|
|
163
|
+
`### ✖ ASTROCODE: RUN_FAILED`,
|
|
164
|
+
`**Run:** \`${e.run_id}\` `,
|
|
165
|
+
`**Story:** \`${e.story_key}\` `,
|
|
166
|
+
`**Stage:** \`${e.stage_key}\` `,
|
|
167
|
+
`**Error:** ${e.error_text}`,
|
|
173
168
|
].join("\n");
|
|
174
169
|
return { title, message, variant: "error", chatText };
|
|
175
170
|
}
|
|
@@ -188,20 +183,8 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
|
|
|
188
183
|
max_steps: tool.schema.number().int().positive().default(config.workflow.default_max_steps),
|
|
189
184
|
},
|
|
190
185
|
execute: async ({ mode, max_steps }) => {
|
|
191
|
-
const repoRoot = (ctx as any).directory as string;
|
|
192
|
-
const lockPath = path.join(repoRoot, ".astro", "astro.lock");
|
|
193
186
|
const sessionId = (ctx as any).sessionID as string | undefined;
|
|
194
|
-
|
|
195
|
-
return workflowRepoLock(
|
|
196
|
-
{ acquireRepoLock },
|
|
197
|
-
{
|
|
198
|
-
lockPath,
|
|
199
|
-
repoRoot,
|
|
200
|
-
sessionId,
|
|
201
|
-
owner: "astro_workflow_proceed",
|
|
202
|
-
advisory: true, // Advisory mode: warn instead of blocking on lock contention
|
|
203
|
-
fn: async () => {
|
|
204
|
-
const steps = Math.min(max_steps, config.workflow.loop_max_steps_hard_cap);
|
|
187
|
+
const steps = Math.min(max_steps, config.workflow.loop_max_steps_hard_cap);
|
|
205
188
|
|
|
206
189
|
const actions: string[] = [];
|
|
207
190
|
const warnings: string[] = [];
|
|
@@ -322,14 +305,14 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
|
|
|
322
305
|
await injectChatPrompt({ ctx, sessionId, text: delegatePrompt, agent: "Astro" });
|
|
323
306
|
|
|
324
307
|
const continueMessage = [
|
|
325
|
-
|
|
326
|
-
``,
|
|
308
|
+
`### ⏳ ASTROCODE: AWAITING COMPLETION`,
|
|
327
309
|
`Stage \`${next.stage_key}\` delegated to \`${agentName}\`.`,
|
|
328
310
|
``,
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
311
|
+
`**Action Required:** When \`${agentName}\` completes, call:`,
|
|
312
|
+
`\`\`\`bash`,
|
|
313
|
+
`astro_stage_complete(run_id="${active.run_id}", stage_key="${next.stage_key}", output_text="...")`,
|
|
314
|
+
`\`\`\``,
|
|
315
|
+
`*Then run \`astro_workflow_proceed\` to continue.*`,
|
|
333
316
|
].join("\n");
|
|
334
317
|
|
|
335
318
|
await injectChatPrompt({ ctx, sessionId, text: continueMessage, agent: "Astro" });
|
|
@@ -353,12 +336,12 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
|
|
|
353
336
|
});
|
|
354
337
|
|
|
355
338
|
const prompt = [
|
|
356
|
-
|
|
357
|
-
``,
|
|
339
|
+
`### 📥 ASTROCODE: AWAITING OUTPUT`,
|
|
358
340
|
`Run \`${next.run_id}\` is waiting for stage \`${next.stage_key}\` output.`,
|
|
359
|
-
`If you have the subagent output, call astro_stage_complete with output_text=the FULL output.`,
|
|
360
341
|
``,
|
|
361
|
-
|
|
342
|
+
`**Action Required:** If you have the subagent output, call \`astro_stage_complete\` with \`output_text=the FULL output\`.`,
|
|
343
|
+
``,
|
|
344
|
+
`#### Context Snapshot`,
|
|
362
345
|
context,
|
|
363
346
|
].join("\n").trim();
|
|
364
347
|
|
|
@@ -424,8 +407,6 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
|
|
|
424
407
|
}
|
|
425
408
|
|
|
426
409
|
return lines.join("\n").trim();
|
|
427
|
-
},
|
|
428
|
-
});
|
|
429
410
|
},
|
|
430
411
|
});
|
|
431
412
|
}
|