astrocode-workflow 0.4.4 → 0.4.6
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/hooks/continuation-enforcer.d.ts +1 -9
- package/dist/src/hooks/continuation-enforcer.js +12 -2
- package/dist/src/hooks/inject-provider.d.ts +1 -9
- package/dist/src/hooks/inject-provider.js +14 -5
- package/dist/src/state/types.d.ts +9 -0
- package/dist/src/tools/artifacts.d.ts +4 -4
- package/dist/src/tools/artifacts.js +12 -3
- package/dist/src/tools/health.d.ts +2 -2
- package/dist/src/tools/health.js +18 -11
- package/dist/src/tools/index.js +27 -34
- package/dist/src/tools/injects.d.ts +8 -8
- package/dist/src/tools/injects.js +24 -6
- package/dist/src/tools/metrics.d.ts +6 -5
- package/dist/src/tools/repair.d.ts +2 -2
- package/dist/src/tools/repair.js +5 -1
- package/dist/src/tools/reset.d.ts +2 -2
- package/dist/src/tools/reset.js +9 -1
- package/dist/src/tools/run.d.ts +3 -3
- package/dist/src/tools/run.js +8 -2
- package/dist/src/tools/spec.d.ts +2 -2
- package/dist/src/tools/spec.js +3 -2
- package/dist/src/tools/stage.d.ts +5 -5
- package/dist/src/tools/stage.js +16 -4
- package/dist/src/tools/status.d.ts +2 -2
- package/dist/src/tools/status.js +25 -2
- package/dist/src/tools/story.d.ts +5 -5
- package/dist/src/tools/story.js +16 -4
- package/dist/src/tools/workflow.d.ts +2 -2
- package/dist/src/tools/workflow.js +5 -1
- package/package.json +1 -1
- package/src/hooks/continuation-enforcer.ts +11 -9
- package/src/hooks/inject-provider.ts +16 -12
- package/src/state/types.ts +11 -0
- package/src/tools/artifacts.ts +16 -7
- package/src/tools/health.ts +22 -13
- package/src/tools/index.ts +32 -40
- package/src/tools/injects.ts +32 -14
- package/src/tools/metrics.ts +3 -6
- package/src/tools/repair.ts +8 -4
- package/src/tools/reset.ts +11 -3
- package/src/tools/run.ts +11 -5
- package/src/tools/spec.ts +5 -4
- package/src/tools/stage.ts +22 -10
- package/src/tools/status.ts +28 -5
- package/src/tools/story.ts +21 -9
- package/src/tools/workflow.ts +8 -3
package/src/tools/artifacts.ts
CHANGED
|
@@ -2,12 +2,12 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
4
4
|
import type { AstrocodeConfig } from "../config/schema";
|
|
5
|
-
import type {
|
|
5
|
+
import type { RuntimeState } from "../state/types";
|
|
6
6
|
import { getAstroPaths } from "../shared/paths";
|
|
7
7
|
import { putArtifact, listArtifacts, getArtifact } from "../workflow/artifacts";
|
|
8
8
|
|
|
9
|
-
export function createAstroArtifactPutTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
10
|
-
const { ctx,
|
|
9
|
+
export function createAstroArtifactPutTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
10
|
+
const { ctx, runtime } = opts;
|
|
11
11
|
|
|
12
12
|
return tool({
|
|
13
13
|
description: "Write an artifact file under .astro and record it in the DB.",
|
|
@@ -20,6 +20,9 @@ export function createAstroArtifactPutTool(opts: { ctx: any; config: AstrocodeCo
|
|
|
20
20
|
meta_json: tool.schema.string().default("{}"),
|
|
21
21
|
},
|
|
22
22
|
execute: async ({ run_id, stage_key, type, rel_path, content, meta_json }) => {
|
|
23
|
+
const { db } = runtime;
|
|
24
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
25
|
+
|
|
23
26
|
const repoRoot = ctx.directory as string;
|
|
24
27
|
const meta = JSON.parse(meta_json || "{}") as Record<string, unknown>;
|
|
25
28
|
|
|
@@ -39,8 +42,8 @@ export function createAstroArtifactPutTool(opts: { ctx: any; config: AstrocodeCo
|
|
|
39
42
|
});
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export function createAstroArtifactListTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
43
|
-
const {
|
|
45
|
+
export function createAstroArtifactListTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
46
|
+
const { runtime } = opts;
|
|
44
47
|
|
|
45
48
|
return tool({
|
|
46
49
|
description: "List artifacts (optionally filtered by run_id, stage_key, type).",
|
|
@@ -50,14 +53,17 @@ export function createAstroArtifactListTool(opts: { ctx: any; config: AstrocodeC
|
|
|
50
53
|
type: tool.schema.string().optional(),
|
|
51
54
|
},
|
|
52
55
|
execute: async ({ run_id, stage_key, type }) => {
|
|
56
|
+
const { db } = runtime;
|
|
57
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
58
|
+
|
|
53
59
|
const rows = listArtifacts(db, { run_id, stage_key, type });
|
|
54
60
|
return JSON.stringify(rows, null, 2);
|
|
55
61
|
},
|
|
56
62
|
});
|
|
57
63
|
}
|
|
58
64
|
|
|
59
|
-
export function createAstroArtifactGetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
60
|
-
const { ctx,
|
|
65
|
+
export function createAstroArtifactGetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
66
|
+
const { ctx, runtime } = opts;
|
|
61
67
|
|
|
62
68
|
return tool({
|
|
63
69
|
description: "Get artifact metadata (and optionally file contents).",
|
|
@@ -67,6 +73,9 @@ export function createAstroArtifactGetTool(opts: { ctx: any; config: AstrocodeCo
|
|
|
67
73
|
max_body_chars: tool.schema.number().int().positive().default(50_000),
|
|
68
74
|
},
|
|
69
75
|
execute: async ({ artifact_id, include_body, max_body_chars }) => {
|
|
76
|
+
const { db } = runtime;
|
|
77
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
78
|
+
|
|
70
79
|
const row = getArtifact(db, artifact_id);
|
|
71
80
|
if (!row) throw new Error(`Artifact not found: ${artifact_id}`);
|
|
72
81
|
|
package/src/tools/health.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// src/tools/health.ts
|
|
2
2
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
3
3
|
import type { AstrocodeConfig } from "../config/schema";
|
|
4
|
-
import type {
|
|
4
|
+
import type { RuntimeState } from "../state/types";
|
|
5
5
|
import { getSchemaVersion } from "../state/db";
|
|
6
6
|
import { getActiveRun } from "../workflow/state-machine";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
|
|
10
|
-
export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
11
|
-
const { ctx, config,
|
|
10
|
+
export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
11
|
+
const { ctx, config, runtime } = opts;
|
|
12
12
|
|
|
13
13
|
return tool({
|
|
14
14
|
description: "Check Astrocode health: DB status, locks, schema, active runs, recent events.",
|
|
@@ -30,13 +30,24 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
30
30
|
const walExists = fs.existsSync(`${fullDbPath}-wal`);
|
|
31
31
|
const shmExists = fs.existsSync(`${fullDbPath}-shm`);
|
|
32
32
|
|
|
33
|
-
lines.push(
|
|
34
|
-
lines.push(
|
|
35
|
-
lines.push(
|
|
36
|
-
lines.push(` - SHM: ${shmExists ? "EXISTS" : "MISSING"}`);
|
|
33
|
+
lines.push(`## Database File`);
|
|
34
|
+
lines.push(`- Exists: ${dbExists ? "✅" : "❌"}`);
|
|
35
|
+
lines.push(`- WAL Mode Active: ${walExists ? "YES" : "NO"}`);
|
|
37
36
|
|
|
38
|
-
if (
|
|
39
|
-
|
|
37
|
+
if (dbExists) {
|
|
38
|
+
const stats = fs.statSync(fullDbPath);
|
|
39
|
+
lines.push(`- Size: ${Math.round(stats.size / 1024)} KB`);
|
|
40
|
+
lines.push(`- Last Modified: ${stats.mtime.toISOString()}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { db } = runtime;
|
|
44
|
+
|
|
45
|
+
if (!db) {
|
|
46
|
+
lines.push(``, `## Status`);
|
|
47
|
+
lines.push(`❌ DB not connected (Limited Mode)`);
|
|
48
|
+
if (runtime.limitedModeReason) {
|
|
49
|
+
lines.push(`- Reason: ${runtime.limitedModeReason.code}`);
|
|
50
|
+
}
|
|
40
51
|
return lines.join("\n");
|
|
41
52
|
}
|
|
42
53
|
|
|
@@ -46,8 +57,6 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
46
57
|
lines.push(`- Schema Version: ${schemaVersion}`);
|
|
47
58
|
} catch (e) {
|
|
48
59
|
lines.push(`- Schema Version: ERROR (${String(e)})`);
|
|
49
|
-
lines.push(`- STATUS: DB CORRUPTED`);
|
|
50
|
-
return lines.join("\n");
|
|
51
60
|
}
|
|
52
61
|
|
|
53
62
|
// Active run
|
|
@@ -59,7 +68,7 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
59
68
|
lines.push(` - Stage: ${activeRun.current_stage_key || "none"}`);
|
|
60
69
|
lines.push(` - Started: ${activeRun.started_at}`);
|
|
61
70
|
} else {
|
|
62
|
-
lines.push(`- Active Run:
|
|
71
|
+
lines.push(`- Active Run: *(none)*`);
|
|
63
72
|
}
|
|
64
73
|
} catch (e) {
|
|
65
74
|
lines.push(`- Active Run: ERROR (${String(e)})`);
|
|
@@ -90,7 +99,7 @@ export function createAstroHealthTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
90
99
|
lines.push(`✅ Schema valid`);
|
|
91
100
|
|
|
92
101
|
if (walExists || shmExists) {
|
|
93
|
-
lines.push(
|
|
102
|
+
lines.push(`ℹ️ SQLite temporary files present (normal during active use)`);
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
return lines.join("\n");
|
package/src/tools/index.ts
CHANGED
|
@@ -33,53 +33,45 @@ type CreateAstroToolsOptions = {
|
|
|
33
33
|
|
|
34
34
|
export function createAstroTools(opts: CreateAstroToolsOptions): Record<string, ToolDefinition> {
|
|
35
35
|
const { ctx, config, agents, runtime } = opts;
|
|
36
|
-
const { db } = runtime;
|
|
37
|
-
const hasDatabase = db !== null; // Source of truth: DB availability
|
|
38
36
|
|
|
39
37
|
const tools: Record<string, ToolDefinition> = {};
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
// Always available tools (work without database - guaranteed DB-independent)
|
|
40
|
+
tools.astro_status = createAstroStatusTool({ ctx, config, runtime });
|
|
41
|
+
tools.astro_spec_get = createAstroSpecGetTool({ ctx, config });
|
|
42
|
+
tools.astro_health = createAstroHealthTool({ ctx, config, runtime });
|
|
43
|
+
tools.astro_reset = createAstroResetTool({ ctx, config, runtime });
|
|
44
|
+
tools.astro_metrics = createAstroMetricsTool({ ctx, config });
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
// Recovery tool - available even in limited mode to allow DB initialization
|
|
47
|
+
tools.astro_init = createAstroInitTool({ ctx, config, runtime });
|
|
50
48
|
|
|
51
49
|
// Database-dependent tools
|
|
52
|
-
if
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
tools.astro_inject_get = createAstroInjectGetTool({ ctx, config, db });
|
|
77
|
-
tools.astro_inject_eligible = createAstroInjectEligibleTool({ ctx, config, db });
|
|
78
|
-
tools.astro_inject_debug_due = createAstroInjectDebugDueTool({ ctx, config, db });
|
|
79
|
-
tools.astro_repair = createAstroRepairTool({ ctx, config, db });
|
|
80
|
-
}
|
|
50
|
+
// We register these even if runtime.db is null, so they can become active if astro_init succeeds in-process.
|
|
51
|
+
// The tools themselves must handle the missing DB case gracefully (returning "not initialized").
|
|
52
|
+
tools.astro_story_queue = createAstroStoryQueueTool({ ctx, config, runtime });
|
|
53
|
+
tools.astro_story_approve = createAstroStoryApproveTool({ ctx, config, runtime });
|
|
54
|
+
tools.astro_story_board = createAstroStoryBoardTool({ ctx, config, runtime });
|
|
55
|
+
tools.astro_story_set_state = createAstroStorySetStateTool({ ctx, config, runtime });
|
|
56
|
+
tools.astro_spec_set = createAstroSpecSetTool({ ctx, config, runtime });
|
|
57
|
+
tools.astro_run_get = createAstroRunGetTool({ ctx, config, runtime });
|
|
58
|
+
tools.astro_run_abort = createAstroRunAbortTool({ ctx, config, runtime });
|
|
59
|
+
tools.astro_workflow_proceed = createAstroWorkflowProceedTool({ ctx, config, runtime, agents });
|
|
60
|
+
tools.astro_stage_start = createAstroStageStartTool({ ctx, config, runtime });
|
|
61
|
+
tools.astro_stage_complete = createAstroStageCompleteTool({ ctx, config, runtime });
|
|
62
|
+
tools.astro_stage_fail = createAstroStageFailTool({ ctx, config, runtime });
|
|
63
|
+
tools.astro_stage_reset = createAstroStageResetTool({ ctx, config, runtime });
|
|
64
|
+
tools.astro_artifact_put = createAstroArtifactPutTool({ ctx, config, runtime });
|
|
65
|
+
tools.astro_artifact_list = createAstroArtifactListTool({ ctx, config, runtime });
|
|
66
|
+
tools.astro_artifact_get = createAstroArtifactGetTool({ ctx, config, runtime });
|
|
67
|
+
tools.astro_inject_put = createAstroInjectPutTool({ ctx, config, runtime });
|
|
68
|
+
tools.astro_inject_list = createAstroInjectListTool({ ctx, config, runtime });
|
|
69
|
+
tools.astro_inject_search = createAstroInjectSearchTool({ ctx, config, runtime });
|
|
70
|
+
tools.astro_inject_get = createAstroInjectGetTool({ ctx, config, runtime });
|
|
71
|
+
tools.astro_inject_eligible = createAstroInjectEligibleTool({ ctx, config, runtime });
|
|
72
|
+
tools.astro_inject_debug_due = createAstroInjectDebugDueTool({ ctx, config, runtime });
|
|
73
|
+
tools.astro_repair = createAstroRepairTool({ ctx, config, runtime });
|
|
81
74
|
|
|
82
|
-
// Create aliases for backward compatibility
|
|
83
75
|
const aliases: Array<[string, string]> = [
|
|
84
76
|
["_astro_init", "astro_init"],
|
|
85
77
|
["_astro_status", "astro_status"],
|
package/src/tools/injects.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
2
2
|
import type { AstrocodeConfig } from "../config/schema";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RuntimeState } from "../state/types";
|
|
4
4
|
import { withTx } from "../state/db";
|
|
5
5
|
import { nowISO } from "../shared/time";
|
|
6
6
|
import { sha256Hex } from "../shared/hash";
|
|
@@ -54,8 +54,8 @@ function newInjectId(): string {
|
|
|
54
54
|
return `inj_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function createAstroInjectPutTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
58
|
-
const {
|
|
57
|
+
export function createAstroInjectPutTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
58
|
+
const { runtime } = opts;
|
|
59
59
|
|
|
60
60
|
return tool({
|
|
61
61
|
description: "Create/update an inject (note/policy) stored in the DB. Useful for persistent rules.",
|
|
@@ -71,6 +71,9 @@ export function createAstroInjectPutTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
71
71
|
expires_at: tool.schema.string().nullable().optional(),
|
|
72
72
|
},
|
|
73
73
|
execute: async ({ inject_id, type, title, body_md, tags_json, scope, source, priority, expires_at }) => {
|
|
74
|
+
const { db } = runtime;
|
|
75
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
76
|
+
|
|
74
77
|
const id = inject_id ?? newInjectId();
|
|
75
78
|
const now = nowISO();
|
|
76
79
|
const sha = sha256Hex(body_md);
|
|
@@ -132,8 +135,8 @@ export function createAstroInjectPutTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
132
135
|
});
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
export function createAstroInjectListTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
136
|
-
const {
|
|
138
|
+
export function createAstroInjectListTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
139
|
+
const { runtime } = opts;
|
|
137
140
|
|
|
138
141
|
return tool({
|
|
139
142
|
description: "List injects (optionally filtered by scope/type).",
|
|
@@ -143,6 +146,9 @@ export function createAstroInjectListTool(opts: { ctx: any; config: AstrocodeCon
|
|
|
143
146
|
limit: tool.schema.number().int().positive().default(50),
|
|
144
147
|
},
|
|
145
148
|
execute: async ({ scope, type, limit }) => {
|
|
149
|
+
const { db } = runtime;
|
|
150
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
151
|
+
|
|
146
152
|
const where: string[] = [];
|
|
147
153
|
const params: any[] = [];
|
|
148
154
|
|
|
@@ -172,8 +178,8 @@ export function createAstroInjectListTool(opts: { ctx: any; config: AstrocodeCon
|
|
|
172
178
|
});
|
|
173
179
|
}
|
|
174
180
|
|
|
175
|
-
export function createAstroInjectGetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
176
|
-
const {
|
|
181
|
+
export function createAstroInjectGetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
182
|
+
const { runtime } = opts;
|
|
177
183
|
|
|
178
184
|
return tool({
|
|
179
185
|
description: "Get an inject by id (full body).",
|
|
@@ -181,6 +187,9 @@ export function createAstroInjectGetTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
181
187
|
inject_id: tool.schema.string().min(1),
|
|
182
188
|
},
|
|
183
189
|
execute: async ({ inject_id }) => {
|
|
190
|
+
const { db } = runtime;
|
|
191
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
192
|
+
|
|
184
193
|
const row = db.prepare("SELECT * FROM injects WHERE inject_id=?").get(inject_id) as any;
|
|
185
194
|
if (!row) throw new Error(`Inject not found: ${inject_id}`);
|
|
186
195
|
return JSON.stringify(row, null, 2);
|
|
@@ -188,8 +197,8 @@ export function createAstroInjectGetTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
188
197
|
});
|
|
189
198
|
}
|
|
190
199
|
|
|
191
|
-
export function createAstroInjectSearchTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
192
|
-
const {
|
|
200
|
+
export function createAstroInjectSearchTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
201
|
+
const { runtime } = opts;
|
|
193
202
|
|
|
194
203
|
return tool({
|
|
195
204
|
description: "Search injects by query substring over title/body/tags. Returns matches ordered by priority/recency.",
|
|
@@ -199,6 +208,9 @@ export function createAstroInjectSearchTool(opts: { ctx: any; config: AstrocodeC
|
|
|
199
208
|
limit: tool.schema.number().int().positive().default(20),
|
|
200
209
|
},
|
|
201
210
|
execute: async ({ q, scope, limit }) => {
|
|
211
|
+
const { db } = runtime;
|
|
212
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
213
|
+
|
|
202
214
|
const like = `%${q}%`;
|
|
203
215
|
const where: string[] = ["(title LIKE ? OR body_md LIKE ? OR tags_json LIKE ?)"];
|
|
204
216
|
const params: any[] = [like, like, like];
|
|
@@ -238,7 +250,7 @@ export type InjectRow = {
|
|
|
238
250
|
};
|
|
239
251
|
|
|
240
252
|
export function selectEligibleInjects(
|
|
241
|
-
db:
|
|
253
|
+
db: any,
|
|
242
254
|
opts: {
|
|
243
255
|
nowIso: string;
|
|
244
256
|
scopeAllowlist: string[];
|
|
@@ -273,8 +285,8 @@ export function selectEligibleInjects(
|
|
|
273
285
|
return db.prepare(sql).all(...params) as InjectRow[];
|
|
274
286
|
}
|
|
275
287
|
|
|
276
|
-
export function createAstroInjectEligibleTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
277
|
-
const {
|
|
288
|
+
export function createAstroInjectEligibleTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
289
|
+
const { runtime } = opts;
|
|
278
290
|
|
|
279
291
|
return tool({
|
|
280
292
|
description: "Debug: show which injects are eligible right now for injection.",
|
|
@@ -284,6 +296,9 @@ export function createAstroInjectEligibleTool(opts: { ctx: any; config: Astrocod
|
|
|
284
296
|
limit: tool.schema.number().int().positive().default(50),
|
|
285
297
|
},
|
|
286
298
|
execute: async ({ scopes_json, types_json, limit }) => {
|
|
299
|
+
const { db } = runtime;
|
|
300
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
301
|
+
|
|
287
302
|
const now = nowISO();
|
|
288
303
|
const scopes = parseJsonStringArray("scopes_json", scopes_json);
|
|
289
304
|
const types = parseJsonStringArray("types_json", types_json);
|
|
@@ -303,8 +318,8 @@ export function createAstroInjectEligibleTool(opts: { ctx: any; config: Astrocod
|
|
|
303
318
|
});
|
|
304
319
|
}
|
|
305
320
|
|
|
306
|
-
export function createAstroInjectDebugDueTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
307
|
-
const {
|
|
321
|
+
export function createAstroInjectDebugDueTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
322
|
+
const { runtime } = opts;
|
|
308
323
|
|
|
309
324
|
return tool({
|
|
310
325
|
description: "Debug: show comprehensive injection diagnostics - why injects were selected/skipped.",
|
|
@@ -313,6 +328,9 @@ export function createAstroInjectDebugDueTool(opts: { ctx: any; config: Astrocod
|
|
|
313
328
|
types_json: tool.schema.string().default('["note","policy"]'),
|
|
314
329
|
},
|
|
315
330
|
execute: async ({ scopes_json, types_json }) => {
|
|
331
|
+
const { db } = runtime;
|
|
332
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
333
|
+
|
|
316
334
|
const now = nowISO();
|
|
317
335
|
const nowMs = Date.parse(now);
|
|
318
336
|
|
package/src/tools/metrics.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
// src/tools/metrics.ts
|
|
2
2
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
3
|
+
import type { AstrocodeConfig } from "../config/schema";
|
|
4
|
+
import type { RuntimeState } from "../state/types";
|
|
3
5
|
import { metrics } from "../shared/metrics";
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
ctx: any;
|
|
7
|
-
config: any;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export function createAstroMetricsTool(opts: CreateAstroMetricsToolOptions): ToolDefinition {
|
|
7
|
+
export function createAstroMetricsTool(opts: { ctx: any; config: AstrocodeConfig; runtime?: RuntimeState }): ToolDefinition {
|
|
11
8
|
return tool({
|
|
12
9
|
description: "Get performance metrics for Astrocode operations including transaction times, injection success rates, and error statistics.",
|
|
13
10
|
args: {},
|
package/src/tools/repair.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
3
2
|
import type { AstrocodeConfig } from "../config/schema";
|
|
4
|
-
import type {
|
|
3
|
+
import type { RuntimeState } from "../state/types";
|
|
5
4
|
import { withTx } from "../state/db";
|
|
6
5
|
import { repairState, formatRepairReport } from "../workflow/repair";
|
|
7
6
|
import { putArtifact } from "../workflow/artifacts";
|
|
8
7
|
import { nowISO } from "../shared/time";
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
export function createAstroRepairTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
12
|
-
const { ctx, config,
|
|
10
|
+
export function createAstroRepairTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
11
|
+
const { ctx, config, runtime } = opts;
|
|
13
12
|
|
|
14
13
|
return tool({
|
|
15
14
|
description: "Repair Astrocode invariants and recover from inconsistent DB state. Writes a repair report artifact.",
|
|
@@ -17,6 +16,11 @@ export function createAstroRepairTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
17
16
|
write_report_artifact: tool.schema.boolean().default(true),
|
|
18
17
|
},
|
|
19
18
|
execute: async ({ write_report_artifact }) => {
|
|
19
|
+
const { db } = runtime;
|
|
20
|
+
if (!db) {
|
|
21
|
+
return "⚠️ Cannot run repair: Astrocode is not initialized. Run **astro_init** first.";
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
const repoRoot = ctx.directory as string;
|
|
21
25
|
|
|
22
26
|
// Repair database state
|
package/src/tools/reset.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// src/tools/reset.ts
|
|
2
2
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
3
3
|
import type { AstrocodeConfig } from "../config/schema";
|
|
4
|
-
import type {
|
|
4
|
+
import type { RuntimeState } from "../state/types";
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
|
|
8
|
-
export function createAstroResetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
9
|
-
const { ctx, config,
|
|
8
|
+
export function createAstroResetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
9
|
+
const { ctx, config, runtime } = opts;
|
|
10
10
|
|
|
11
11
|
return tool({
|
|
12
12
|
description: "Reset Astrocode database: safely delete all DB files and WAL/SHM after killing concurrent processes.",
|
|
@@ -28,6 +28,14 @@ export function createAstroResetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
28
28
|
].join("\n");
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Close DB connection if open
|
|
32
|
+
if (runtime.db) {
|
|
33
|
+
try {
|
|
34
|
+
runtime.db.close();
|
|
35
|
+
} catch { /* ignore */ }
|
|
36
|
+
runtime.db = null;
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
const repoRoot = (ctx as any).directory || process.cwd();
|
|
32
40
|
const dbPath = config.db?.path || ".astro/astro.db";
|
|
33
41
|
const fullDbPath = path.resolve(repoRoot, dbPath);
|
package/src/tools/run.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
2
2
|
import type { AstrocodeConfig } from "../config/schema";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RuntimeState } from "../state/types";
|
|
4
4
|
import { abortRun, getActiveRun, getStageRuns, getStory } from "../workflow/state-machine";
|
|
5
5
|
|
|
6
|
-
export function createAstroRunGetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
7
|
-
const {
|
|
6
|
+
export function createAstroRunGetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
7
|
+
const { runtime } = opts;
|
|
8
8
|
|
|
9
9
|
return tool({
|
|
10
10
|
description: "Get run details (and stage run statuses). Defaults to active run if run_id omitted.",
|
|
@@ -13,6 +13,9 @@ export function createAstroRunGetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
13
13
|
include_stage_summaries: tool.schema.boolean().default(false),
|
|
14
14
|
},
|
|
15
15
|
execute: async ({ run_id, include_stage_summaries }) => {
|
|
16
|
+
const { db } = runtime;
|
|
17
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
18
|
+
|
|
16
19
|
const active = getActiveRun(db);
|
|
17
20
|
const rid = run_id ?? active?.run_id;
|
|
18
21
|
if (!rid) return "No active run.";
|
|
@@ -42,8 +45,8 @@ export function createAstroRunGetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
|
42
45
|
});
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
export function createAstroRunAbortTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
46
|
-
const {
|
|
48
|
+
export function createAstroRunAbortTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
49
|
+
const { runtime } = opts;
|
|
47
50
|
|
|
48
51
|
return tool({
|
|
49
52
|
description: "Abort a run and unlock its story (returns story to approved). Defaults to active run if run_id omitted.",
|
|
@@ -52,6 +55,9 @@ export function createAstroRunAbortTool(opts: { ctx: any; config: AstrocodeConfi
|
|
|
52
55
|
reason: tool.schema.string().default("aborted by user"),
|
|
53
56
|
},
|
|
54
57
|
execute: async ({ run_id, reason }) => {
|
|
58
|
+
const { db } = runtime;
|
|
59
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
60
|
+
|
|
55
61
|
const active = getActiveRun(db);
|
|
56
62
|
const rid = run_id ?? active?.run_id;
|
|
57
63
|
if (!rid) return "No active run to abort.";
|
package/src/tools/spec.ts
CHANGED
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
4
4
|
import type { AstrocodeConfig } from "../config/schema";
|
|
5
|
-
import type {
|
|
5
|
+
import type { RuntimeState } from "../state/types";
|
|
6
6
|
import { getAstroPaths, ensureAstroDirs } from "../shared/paths";
|
|
7
7
|
import { nowISO } from "../shared/time";
|
|
8
8
|
import { sha256Hex } from "../shared/hash";
|
|
@@ -25,8 +25,8 @@ export function createAstroSpecGetTool(opts: { ctx: any; config: AstrocodeConfig
|
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function createAstroSpecSetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
29
|
-
const { ctx, config,
|
|
28
|
+
export function createAstroSpecSetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
29
|
+
const { ctx, config, runtime } = opts;
|
|
30
30
|
|
|
31
31
|
return tool({
|
|
32
32
|
description: "Set/replace the project spec at .astro/spec.md and record its hash in the DB.",
|
|
@@ -34,8 +34,9 @@ export function createAstroSpecSetTool(opts: { ctx: any; config: AstrocodeConfig
|
|
|
34
34
|
spec_md: tool.schema.string().min(1),
|
|
35
35
|
},
|
|
36
36
|
execute: async ({ spec_md }) => {
|
|
37
|
+
const { db } = runtime;
|
|
37
38
|
if (!db) {
|
|
38
|
-
return "❌ Database not available. Cannot track spec hash. Astrocode is running in limited mode.";
|
|
39
|
+
return "❌ Database not available. Cannot track spec hash. Astrocode is running in limited mode. Run **astro_init** first.";
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
const repoRoot = ctx.directory as string;
|
package/src/tools/stage.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
4
4
|
import type { AstrocodeConfig } from "../config/schema";
|
|
5
|
-
import type {
|
|
5
|
+
import type { RuntimeState } from "../state/types";
|
|
6
6
|
import { withTx } from "../state/db";
|
|
7
7
|
import type { StageKey, StageRunRow } from "../state/types";
|
|
8
8
|
import { buildBatonSummary, parseStageOutputText } from "../workflow/baton";
|
|
@@ -28,7 +28,7 @@ function ensureStageMatches(run: any, stage_key: StageKey) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function splitTasksIntoStories(
|
|
31
|
-
db:
|
|
31
|
+
db: any,
|
|
32
32
|
tasks: any[],
|
|
33
33
|
run: any,
|
|
34
34
|
now: string,
|
|
@@ -82,8 +82,8 @@ function splitTasksIntoStories(
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
export function createAstroStageStartTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
86
|
-
const {
|
|
85
|
+
export function createAstroStageStartTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
86
|
+
const { runtime } = opts;
|
|
87
87
|
|
|
88
88
|
return tool({
|
|
89
89
|
description: "Start a stage for a run (sets stage_run.status=running). Usually called by astro_workflow_proceed.",
|
|
@@ -94,6 +94,9 @@ export function createAstroStageStartTool(opts: { ctx: any; config: AstrocodeCon
|
|
|
94
94
|
subagent_session_id: tool.schema.string().optional(),
|
|
95
95
|
},
|
|
96
96
|
execute: async ({ run_id, stage_key, subagent_type, subagent_session_id }) => {
|
|
97
|
+
const { db } = runtime;
|
|
98
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
99
|
+
|
|
97
100
|
const active = getActiveRun(db);
|
|
98
101
|
const rid = run_id ?? active?.run_id;
|
|
99
102
|
if (!rid) throw new Error("No active run and no run_id provided.");
|
|
@@ -111,8 +114,8 @@ export function createAstroStageStartTool(opts: { ctx: any; config: AstrocodeCon
|
|
|
111
114
|
});
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
export function createAstroStageCompleteTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
115
|
-
const { ctx, config,
|
|
117
|
+
export function createAstroStageCompleteTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
118
|
+
const { ctx, config, runtime } = opts;
|
|
116
119
|
|
|
117
120
|
return tool({
|
|
118
121
|
description:
|
|
@@ -128,6 +131,9 @@ export function createAstroStageCompleteTool(opts: { ctx: any; config: Astrocode
|
|
|
128
131
|
relation_reason: tool.schema.string().default("split from stage output"),
|
|
129
132
|
},
|
|
130
133
|
execute: async ({ run_id, stage_key, output_text, allow_new_stories, relation_reason }) => {
|
|
134
|
+
const { db } = runtime;
|
|
135
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
136
|
+
|
|
131
137
|
const repoRoot = ctx.directory as string;
|
|
132
138
|
const paths = getAstroPaths(repoRoot, config.db.path);
|
|
133
139
|
ensureAstroDirs(paths);
|
|
@@ -396,8 +402,8 @@ Ensure JSON has required fields (stage_key, status) and valid syntax.`;
|
|
|
396
402
|
});
|
|
397
403
|
}
|
|
398
404
|
|
|
399
|
-
export function createAstroStageFailTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
400
|
-
const {
|
|
405
|
+
export function createAstroStageFailTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
406
|
+
const { runtime } = opts;
|
|
401
407
|
|
|
402
408
|
return tool({
|
|
403
409
|
description: "Manually fail a stage and mark run failed.",
|
|
@@ -407,6 +413,9 @@ export function createAstroStageFailTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
407
413
|
error_text: tool.schema.string().min(1),
|
|
408
414
|
},
|
|
409
415
|
execute: async ({ run_id, stage_key, error_text }) => {
|
|
416
|
+
const { db } = runtime;
|
|
417
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
418
|
+
|
|
410
419
|
const active = getActiveRun(db);
|
|
411
420
|
const rid = run_id ?? active?.run_id;
|
|
412
421
|
if (!rid) throw new Error("No active run and no run_id provided.");
|
|
@@ -439,8 +448,8 @@ export function createAstroStageFailTool(opts: { ctx: any; config: AstrocodeConf
|
|
|
439
448
|
});
|
|
440
449
|
}
|
|
441
450
|
|
|
442
|
-
export function createAstroStageResetTool(opts: { ctx: any; config: AstrocodeConfig;
|
|
443
|
-
const {
|
|
451
|
+
export function createAstroStageResetTool(opts: { ctx: any; config: AstrocodeConfig; runtime: RuntimeState }): ToolDefinition {
|
|
452
|
+
const { runtime } = opts;
|
|
444
453
|
|
|
445
454
|
return tool({
|
|
446
455
|
description:
|
|
@@ -451,6 +460,9 @@ export function createAstroStageResetTool(opts: { ctx: any; config: AstrocodeCon
|
|
|
451
460
|
note: tool.schema.string().default("reset by user"),
|
|
452
461
|
},
|
|
453
462
|
execute: async ({ run_id, stage_key, note }) => {
|
|
463
|
+
const { db } = runtime;
|
|
464
|
+
if (!db) return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
465
|
+
|
|
454
466
|
const run = db.prepare("SELECT * FROM runs WHERE run_id=?").get(run_id) as any;
|
|
455
467
|
if (!run) throw new Error(`Run not found: ${run_id}`);
|
|
456
468
|
|