astrocode-workflow 0.4.5 → 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 +11 -4
- 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 +12 -11
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AstrocodeConfig } from "../config/schema";
|
|
2
|
-
import type {
|
|
2
|
+
import type { RuntimeState } from "../state/types";
|
|
3
3
|
type ToolExecuteAfterInput = {
|
|
4
4
|
tool: string;
|
|
5
5
|
sessionID?: string;
|
|
@@ -14,14 +14,6 @@ type EventInput = {
|
|
|
14
14
|
properties: any;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
-
type RuntimeState = {
|
|
18
|
-
db: SqliteDb | null;
|
|
19
|
-
limitedMode: boolean;
|
|
20
|
-
limitedModeReason: null | {
|
|
21
|
-
code: "db_init_failed" | "schema_too_old" | "schema_downgrade" | "schema_migration_failed";
|
|
22
|
-
details: any;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
17
|
export declare function createContinuationEnforcer(opts: {
|
|
26
18
|
ctx: any;
|
|
27
19
|
config: AstrocodeConfig;
|
|
@@ -10,7 +10,6 @@ function msFromIso(iso) {
|
|
|
10
10
|
}
|
|
11
11
|
export function createContinuationEnforcer(opts) {
|
|
12
12
|
const { ctx, config, runtime } = opts;
|
|
13
|
-
const { db } = runtime;
|
|
14
13
|
const toasts = createToastManager({ ctx, throttleMs: config.ui.toasts.throttle_ms });
|
|
15
14
|
const sessions = new Map();
|
|
16
15
|
function getState(sessionId) {
|
|
@@ -61,6 +60,9 @@ export function createContinuationEnforcer(opts) {
|
|
|
61
60
|
}, interval);
|
|
62
61
|
}
|
|
63
62
|
function shouldDedupe(sessionId, directive) {
|
|
63
|
+
const { db } = runtime;
|
|
64
|
+
if (!db)
|
|
65
|
+
return false;
|
|
64
66
|
const s = getState(sessionId);
|
|
65
67
|
const now = Date.now();
|
|
66
68
|
// Memory window
|
|
@@ -78,6 +80,9 @@ export function createContinuationEnforcer(opts) {
|
|
|
78
80
|
return false;
|
|
79
81
|
}
|
|
80
82
|
async function recordContinuation(sessionId, runId, directive, reason) {
|
|
83
|
+
const { db } = runtime;
|
|
84
|
+
if (!db)
|
|
85
|
+
return;
|
|
81
86
|
db.prepare("INSERT INTO continuations (session_id, run_id, directive_hash, kind, reason, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(sessionId, runId, directive.hash, directive.kind, reason, nowISO());
|
|
82
87
|
const s = getState(sessionId);
|
|
83
88
|
const now = Date.now();
|
|
@@ -109,7 +114,8 @@ export function createContinuationEnforcer(opts) {
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
async function maybeInjectContinue(sessionId, reason) {
|
|
112
|
-
|
|
117
|
+
const { db } = runtime;
|
|
118
|
+
if (!config.continuation.enabled || !db)
|
|
113
119
|
return;
|
|
114
120
|
// Require active run
|
|
115
121
|
const active = getActiveRun(db);
|
|
@@ -154,6 +160,8 @@ export function createContinuationEnforcer(opts) {
|
|
|
154
160
|
const sessionId = input.sessionID ?? ctx.sessionID;
|
|
155
161
|
if (!sessionId)
|
|
156
162
|
return;
|
|
163
|
+
if (!config.continuation.enabled)
|
|
164
|
+
return;
|
|
157
165
|
if (!config.continuation.inject_on_tool_done_if_run_active)
|
|
158
166
|
return;
|
|
159
167
|
// Inject continuation immediately after any tool execution
|
|
@@ -161,6 +169,8 @@ export function createContinuationEnforcer(opts) {
|
|
|
161
169
|
scheduleIdleInjection(sessionId);
|
|
162
170
|
},
|
|
163
171
|
async onChatMessage(_input) {
|
|
172
|
+
if (!config.continuation.enabled)
|
|
173
|
+
return;
|
|
164
174
|
if (!config.continuation.inject_on_message_done_if_run_active)
|
|
165
175
|
return;
|
|
166
176
|
scheduleIdleInjection(_input.sessionID);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AstrocodeConfig } from "../config/schema";
|
|
2
|
-
import type {
|
|
2
|
+
import type { RuntimeState } from "../state/types";
|
|
3
3
|
type ChatMessageInput = {
|
|
4
4
|
sessionID: string;
|
|
5
5
|
agent: string;
|
|
@@ -8,14 +8,6 @@ type ToolExecuteAfterInput = {
|
|
|
8
8
|
tool: string;
|
|
9
9
|
sessionID?: string;
|
|
10
10
|
};
|
|
11
|
-
type RuntimeState = {
|
|
12
|
-
db: SqliteDb | null;
|
|
13
|
-
limitedMode: boolean;
|
|
14
|
-
limitedModeReason: null | {
|
|
15
|
-
code: "db_init_failed" | "schema_too_old" | "schema_downgrade" | "schema_migration_failed";
|
|
16
|
-
details: any;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
11
|
export declare function createInjectProvider(opts: {
|
|
20
12
|
ctx: any;
|
|
21
13
|
config: AstrocodeConfig;
|
|
@@ -4,7 +4,6 @@ import { nowISO } from "../shared/time";
|
|
|
4
4
|
import { getActiveRun } from "../workflow/state-machine";
|
|
5
5
|
export function createInjectProvider(opts) {
|
|
6
6
|
const { ctx, config, runtime } = opts;
|
|
7
|
-
const { db } = runtime;
|
|
8
7
|
// Cache to avoid re-injecting the same injects repeatedly
|
|
9
8
|
// Map of inject_id -> last injected timestamp
|
|
10
9
|
const injectedCache = new Map();
|
|
@@ -29,6 +28,9 @@ export function createInjectProvider(opts) {
|
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
function getInjectionDiagnostics(nowIso, scopeAllowlist, typeAllowlist) {
|
|
31
|
+
const { db } = runtime;
|
|
32
|
+
if (!db)
|
|
33
|
+
return null;
|
|
32
34
|
// Get ALL injects to analyze filtering
|
|
33
35
|
const allInjects = db.prepare("SELECT * FROM injects").all();
|
|
34
36
|
let total = allInjects.length;
|
|
@@ -72,6 +74,9 @@ export function createInjectProvider(opts) {
|
|
|
72
74
|
};
|
|
73
75
|
}
|
|
74
76
|
async function injectEligibleInjects(sessionId, context) {
|
|
77
|
+
const { db } = runtime;
|
|
78
|
+
if (!db)
|
|
79
|
+
return;
|
|
75
80
|
const now = nowISO();
|
|
76
81
|
const nowMs = Date.now();
|
|
77
82
|
// Get allowlists from config or defaults
|
|
@@ -90,7 +95,7 @@ export function createInjectProvider(opts) {
|
|
|
90
95
|
let skippedDeduped = 0;
|
|
91
96
|
if (eligibleInjects.length === 0) {
|
|
92
97
|
// Log when no injects are eligible
|
|
93
|
-
if (EMIT_TELEMETRY) {
|
|
98
|
+
if (EMIT_TELEMETRY && diagnostics) {
|
|
94
99
|
// eslint-disable-next-line no-console
|
|
95
100
|
console.log(`[Astrocode:inject] ${now} context=${context ?? 'unknown'} selected=0 injected=0 skipped={expired:${diagnostics.skipped.expired} scope:${diagnostics.skipped.scope} type:${diagnostics.skipped.type} deduped:0}`);
|
|
96
101
|
}
|
|
@@ -121,7 +126,7 @@ export function createInjectProvider(opts) {
|
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
// Log diagnostic summary
|
|
124
|
-
if (EMIT_TELEMETRY || injected > 0) {
|
|
129
|
+
if ((EMIT_TELEMETRY || injected > 0) && diagnostics) {
|
|
125
130
|
// eslint-disable-next-line no-console
|
|
126
131
|
console.log(`[Astrocode:inject] ${now} context=${context ?? 'unknown'} selected=${diagnostics.selected_eligible} injected=${injected} skipped={expired:${diagnostics.skipped.expired} scope:${diagnostics.skipped.scope} type:${diagnostics.skipped.type} deduped:${skippedDeduped}}`);
|
|
127
132
|
}
|
|
@@ -138,7 +143,8 @@ export function createInjectProvider(opts) {
|
|
|
138
143
|
]);
|
|
139
144
|
// Auto-approve queued stories if enabled
|
|
140
145
|
async function maybeAutoApprove(sessionId) {
|
|
141
|
-
|
|
146
|
+
const { db } = runtime;
|
|
147
|
+
if (!config.inject?.auto_approve_queued_stories || !db)
|
|
142
148
|
return;
|
|
143
149
|
try {
|
|
144
150
|
// Get all queued stories
|
|
@@ -192,6 +198,7 @@ export function createInjectProvider(opts) {
|
|
|
192
198
|
},
|
|
193
199
|
};
|
|
194
200
|
async function maybeInjectWorkflowPulse(sessionId) {
|
|
201
|
+
const { db } = runtime;
|
|
195
202
|
if (!db)
|
|
196
203
|
return;
|
|
197
204
|
try {
|
|
@@ -69,3 +69,12 @@ export type InjectRow = {
|
|
|
69
69
|
created_at: string;
|
|
70
70
|
updated_at: string;
|
|
71
71
|
};
|
|
72
|
+
import { SqliteDb } from "./db";
|
|
73
|
+
export type RuntimeState = {
|
|
74
|
+
db: SqliteDb | null;
|
|
75
|
+
limitedMode: boolean;
|
|
76
|
+
limitedModeReason: null | {
|
|
77
|
+
code: "db_init_failed" | "schema_too_old" | "schema_downgrade" | "schema_migration_failed";
|
|
78
|
+
details: any;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { 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
|
export declare function createAstroArtifactPutTool(opts: {
|
|
5
5
|
ctx: any;
|
|
6
6
|
config: AstrocodeConfig;
|
|
7
|
-
|
|
7
|
+
runtime: RuntimeState;
|
|
8
8
|
}): ToolDefinition;
|
|
9
9
|
export declare function createAstroArtifactListTool(opts: {
|
|
10
10
|
ctx: any;
|
|
11
11
|
config: AstrocodeConfig;
|
|
12
|
-
|
|
12
|
+
runtime: RuntimeState;
|
|
13
13
|
}): ToolDefinition;
|
|
14
14
|
export declare function createAstroArtifactGetTool(opts: {
|
|
15
15
|
ctx: any;
|
|
16
16
|
config: AstrocodeConfig;
|
|
17
|
-
|
|
17
|
+
runtime: RuntimeState;
|
|
18
18
|
}): ToolDefinition;
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
4
4
|
import { putArtifact, listArtifacts, getArtifact } from "../workflow/artifacts";
|
|
5
5
|
export function createAstroArtifactPutTool(opts) {
|
|
6
|
-
const { ctx,
|
|
6
|
+
const { ctx, runtime } = opts;
|
|
7
7
|
return tool({
|
|
8
8
|
description: "Write an artifact file under .astro and record it in the DB.",
|
|
9
9
|
args: {
|
|
@@ -15,6 +15,9 @@ export function createAstroArtifactPutTool(opts) {
|
|
|
15
15
|
meta_json: tool.schema.string().default("{}"),
|
|
16
16
|
},
|
|
17
17
|
execute: async ({ run_id, stage_key, type, rel_path, content, meta_json }) => {
|
|
18
|
+
const { db } = runtime;
|
|
19
|
+
if (!db)
|
|
20
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
18
21
|
const repoRoot = ctx.directory;
|
|
19
22
|
const meta = JSON.parse(meta_json || "{}");
|
|
20
23
|
const res = putArtifact({
|
|
@@ -32,7 +35,7 @@ export function createAstroArtifactPutTool(opts) {
|
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
37
|
export function createAstroArtifactListTool(opts) {
|
|
35
|
-
const {
|
|
38
|
+
const { runtime } = opts;
|
|
36
39
|
return tool({
|
|
37
40
|
description: "List artifacts (optionally filtered by run_id, stage_key, type).",
|
|
38
41
|
args: {
|
|
@@ -41,13 +44,16 @@ export function createAstroArtifactListTool(opts) {
|
|
|
41
44
|
type: tool.schema.string().optional(),
|
|
42
45
|
},
|
|
43
46
|
execute: async ({ run_id, stage_key, type }) => {
|
|
47
|
+
const { db } = runtime;
|
|
48
|
+
if (!db)
|
|
49
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
44
50
|
const rows = listArtifacts(db, { run_id, stage_key, type });
|
|
45
51
|
return JSON.stringify(rows, null, 2);
|
|
46
52
|
},
|
|
47
53
|
});
|
|
48
54
|
}
|
|
49
55
|
export function createAstroArtifactGetTool(opts) {
|
|
50
|
-
const { ctx,
|
|
56
|
+
const { ctx, runtime } = opts;
|
|
51
57
|
return tool({
|
|
52
58
|
description: "Get artifact metadata (and optionally file contents).",
|
|
53
59
|
args: {
|
|
@@ -56,6 +62,9 @@ export function createAstroArtifactGetTool(opts) {
|
|
|
56
62
|
max_body_chars: tool.schema.number().int().positive().default(50_000),
|
|
57
63
|
},
|
|
58
64
|
execute: async ({ artifact_id, include_body, max_body_chars }) => {
|
|
65
|
+
const { db } = runtime;
|
|
66
|
+
if (!db)
|
|
67
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
59
68
|
const row = getArtifact(db, artifact_id);
|
|
60
69
|
if (!row)
|
|
61
70
|
throw new Error(`Artifact not found: ${artifact_id}`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { 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
|
export declare function createAstroHealthTool(opts: {
|
|
5
5
|
ctx: any;
|
|
6
6
|
config: AstrocodeConfig;
|
|
7
|
-
|
|
7
|
+
runtime: RuntimeState;
|
|
8
8
|
}): ToolDefinition;
|
package/dist/src/tools/health.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getActiveRun } from "../workflow/state-machine";
|
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
export function createAstroHealthTool(opts) {
|
|
8
|
-
const { ctx, config,
|
|
8
|
+
const { ctx, config, runtime } = opts;
|
|
9
9
|
return tool({
|
|
10
10
|
description: "Check Astrocode health: DB status, locks, schema, active runs, recent events.",
|
|
11
11
|
args: {},
|
|
@@ -23,12 +23,21 @@ export function createAstroHealthTool(opts) {
|
|
|
23
23
|
const dbExists = fs.existsSync(fullDbPath);
|
|
24
24
|
const walExists = fs.existsSync(`${fullDbPath}-wal`);
|
|
25
25
|
const shmExists = fs.existsSync(`${fullDbPath}-shm`);
|
|
26
|
-
lines.push(
|
|
27
|
-
lines.push(
|
|
28
|
-
lines.push(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
lines.push(`-
|
|
26
|
+
lines.push(`## Database File`);
|
|
27
|
+
lines.push(`- Exists: ${dbExists ? "✅" : "❌"}`);
|
|
28
|
+
lines.push(`- WAL Mode Active: ${walExists ? "YES" : "NO"}`);
|
|
29
|
+
if (dbExists) {
|
|
30
|
+
const stats = fs.statSync(fullDbPath);
|
|
31
|
+
lines.push(`- Size: ${Math.round(stats.size / 1024)} KB`);
|
|
32
|
+
lines.push(`- Last Modified: ${stats.mtime.toISOString()}`);
|
|
33
|
+
}
|
|
34
|
+
const { db } = runtime;
|
|
35
|
+
if (!db) {
|
|
36
|
+
lines.push(``, `## Status`);
|
|
37
|
+
lines.push(`❌ DB not connected (Limited Mode)`);
|
|
38
|
+
if (runtime.limitedModeReason) {
|
|
39
|
+
lines.push(`- Reason: ${runtime.limitedModeReason.code}`);
|
|
40
|
+
}
|
|
32
41
|
return lines.join("\n");
|
|
33
42
|
}
|
|
34
43
|
// Schema version
|
|
@@ -38,8 +47,6 @@ export function createAstroHealthTool(opts) {
|
|
|
38
47
|
}
|
|
39
48
|
catch (e) {
|
|
40
49
|
lines.push(`- Schema Version: ERROR (${String(e)})`);
|
|
41
|
-
lines.push(`- STATUS: DB CORRUPTED`);
|
|
42
|
-
return lines.join("\n");
|
|
43
50
|
}
|
|
44
51
|
// Active run
|
|
45
52
|
try {
|
|
@@ -51,7 +58,7 @@ export function createAstroHealthTool(opts) {
|
|
|
51
58
|
lines.push(` - Started: ${activeRun.started_at}`);
|
|
52
59
|
}
|
|
53
60
|
else {
|
|
54
|
-
lines.push(`- Active Run:
|
|
61
|
+
lines.push(`- Active Run: *(none)*`);
|
|
55
62
|
}
|
|
56
63
|
}
|
|
57
64
|
catch (e) {
|
|
@@ -80,7 +87,7 @@ export function createAstroHealthTool(opts) {
|
|
|
80
87
|
lines.push(`✅ DB accessible`);
|
|
81
88
|
lines.push(`✅ Schema valid`);
|
|
82
89
|
if (walExists || shmExists) {
|
|
83
|
-
lines.push(
|
|
90
|
+
lines.push(`ℹ️ SQLite temporary files present (normal during active use)`);
|
|
84
91
|
}
|
|
85
92
|
return lines.join("\n");
|
|
86
93
|
},
|
package/dist/src/tools/index.js
CHANGED
|
@@ -13,47 +13,40 @@ import { createAstroResetTool } from "./reset";
|
|
|
13
13
|
import { createAstroMetricsTool } from "./metrics";
|
|
14
14
|
export function createAstroTools(opts) {
|
|
15
15
|
const { ctx, config, agents, runtime } = opts;
|
|
16
|
-
const { db } = runtime;
|
|
17
|
-
const hasDatabase = db !== null; // Source of truth: DB availability
|
|
18
16
|
const tools = {};
|
|
19
17
|
// Always available tools (work without database - guaranteed DB-independent)
|
|
20
|
-
tools.astro_status = createAstroStatusTool({ ctx, config });
|
|
18
|
+
tools.astro_status = createAstroStatusTool({ ctx, config, runtime });
|
|
21
19
|
tools.astro_spec_get = createAstroSpecGetTool({ ctx, config });
|
|
22
|
-
tools.astro_health = createAstroHealthTool({ ctx, config,
|
|
23
|
-
tools.astro_reset = createAstroResetTool({ ctx, config,
|
|
20
|
+
tools.astro_health = createAstroHealthTool({ ctx, config, runtime });
|
|
21
|
+
tools.astro_reset = createAstroResetTool({ ctx, config, runtime });
|
|
24
22
|
tools.astro_metrics = createAstroMetricsTool({ ctx, config });
|
|
25
23
|
// Recovery tool - available even in limited mode to allow DB initialization
|
|
26
24
|
tools.astro_init = createAstroInitTool({ ctx, config, runtime });
|
|
27
25
|
// Database-dependent tools
|
|
28
|
-
if
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
tools.astro_inject_eligible = createAstroInjectEligibleTool({ ctx, config, db });
|
|
53
|
-
tools.astro_inject_debug_due = createAstroInjectDebugDueTool({ ctx, config, db });
|
|
54
|
-
tools.astro_repair = createAstroRepairTool({ ctx, config, db });
|
|
55
|
-
}
|
|
56
|
-
// Create aliases for backward compatibility
|
|
26
|
+
// We register these even if runtime.db is null, so they can become active if astro_init succeeds in-process.
|
|
27
|
+
// The tools themselves must handle the missing DB case gracefully (returning "not initialized").
|
|
28
|
+
tools.astro_story_queue = createAstroStoryQueueTool({ ctx, config, runtime });
|
|
29
|
+
tools.astro_story_approve = createAstroStoryApproveTool({ ctx, config, runtime });
|
|
30
|
+
tools.astro_story_board = createAstroStoryBoardTool({ ctx, config, runtime });
|
|
31
|
+
tools.astro_story_set_state = createAstroStorySetStateTool({ ctx, config, runtime });
|
|
32
|
+
tools.astro_spec_set = createAstroSpecSetTool({ ctx, config, runtime });
|
|
33
|
+
tools.astro_run_get = createAstroRunGetTool({ ctx, config, runtime });
|
|
34
|
+
tools.astro_run_abort = createAstroRunAbortTool({ ctx, config, runtime });
|
|
35
|
+
tools.astro_workflow_proceed = createAstroWorkflowProceedTool({ ctx, config, runtime, agents });
|
|
36
|
+
tools.astro_stage_start = createAstroStageStartTool({ ctx, config, runtime });
|
|
37
|
+
tools.astro_stage_complete = createAstroStageCompleteTool({ ctx, config, runtime });
|
|
38
|
+
tools.astro_stage_fail = createAstroStageFailTool({ ctx, config, runtime });
|
|
39
|
+
tools.astro_stage_reset = createAstroStageResetTool({ ctx, config, runtime });
|
|
40
|
+
tools.astro_artifact_put = createAstroArtifactPutTool({ ctx, config, runtime });
|
|
41
|
+
tools.astro_artifact_list = createAstroArtifactListTool({ ctx, config, runtime });
|
|
42
|
+
tools.astro_artifact_get = createAstroArtifactGetTool({ ctx, config, runtime });
|
|
43
|
+
tools.astro_inject_put = createAstroInjectPutTool({ ctx, config, runtime });
|
|
44
|
+
tools.astro_inject_list = createAstroInjectListTool({ ctx, config, runtime });
|
|
45
|
+
tools.astro_inject_search = createAstroInjectSearchTool({ ctx, config, runtime });
|
|
46
|
+
tools.astro_inject_get = createAstroInjectGetTool({ ctx, config, runtime });
|
|
47
|
+
tools.astro_inject_eligible = createAstroInjectEligibleTool({ ctx, config, runtime });
|
|
48
|
+
tools.astro_inject_debug_due = createAstroInjectDebugDueTool({ ctx, config, runtime });
|
|
49
|
+
tools.astro_repair = createAstroRepairTool({ ctx, config, runtime });
|
|
57
50
|
const aliases = [
|
|
58
51
|
["_astro_init", "astro_init"],
|
|
59
52
|
["_astro_status", "astro_status"],
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { 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
|
export declare function createAstroInjectPutTool(opts: {
|
|
5
5
|
ctx: any;
|
|
6
6
|
config: AstrocodeConfig;
|
|
7
|
-
|
|
7
|
+
runtime: RuntimeState;
|
|
8
8
|
}): ToolDefinition;
|
|
9
9
|
export declare function createAstroInjectListTool(opts: {
|
|
10
10
|
ctx: any;
|
|
11
11
|
config: AstrocodeConfig;
|
|
12
|
-
|
|
12
|
+
runtime: RuntimeState;
|
|
13
13
|
}): ToolDefinition;
|
|
14
14
|
export declare function createAstroInjectGetTool(opts: {
|
|
15
15
|
ctx: any;
|
|
16
16
|
config: AstrocodeConfig;
|
|
17
|
-
|
|
17
|
+
runtime: RuntimeState;
|
|
18
18
|
}): ToolDefinition;
|
|
19
19
|
export declare function createAstroInjectSearchTool(opts: {
|
|
20
20
|
ctx: any;
|
|
21
21
|
config: AstrocodeConfig;
|
|
22
|
-
|
|
22
|
+
runtime: RuntimeState;
|
|
23
23
|
}): ToolDefinition;
|
|
24
24
|
export type InjectRow = {
|
|
25
25
|
inject_id: string;
|
|
@@ -35,7 +35,7 @@ export type InjectRow = {
|
|
|
35
35
|
created_at: string;
|
|
36
36
|
updated_at: string;
|
|
37
37
|
};
|
|
38
|
-
export declare function selectEligibleInjects(db:
|
|
38
|
+
export declare function selectEligibleInjects(db: any, opts: {
|
|
39
39
|
nowIso: string;
|
|
40
40
|
scopeAllowlist: string[];
|
|
41
41
|
typeAllowlist: string[];
|
|
@@ -44,10 +44,10 @@ export declare function selectEligibleInjects(db: SqliteDb, opts: {
|
|
|
44
44
|
export declare function createAstroInjectEligibleTool(opts: {
|
|
45
45
|
ctx: any;
|
|
46
46
|
config: AstrocodeConfig;
|
|
47
|
-
|
|
47
|
+
runtime: RuntimeState;
|
|
48
48
|
}): ToolDefinition;
|
|
49
49
|
export declare function createAstroInjectDebugDueTool(opts: {
|
|
50
50
|
ctx: any;
|
|
51
51
|
config: AstrocodeConfig;
|
|
52
|
-
|
|
52
|
+
runtime: RuntimeState;
|
|
53
53
|
}): ToolDefinition;
|
|
@@ -41,7 +41,7 @@ function newInjectId() {
|
|
|
41
41
|
return `inj_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
42
42
|
}
|
|
43
43
|
export function createAstroInjectPutTool(opts) {
|
|
44
|
-
const {
|
|
44
|
+
const { runtime } = opts;
|
|
45
45
|
return tool({
|
|
46
46
|
description: "Create/update an inject (note/policy) stored in the DB. Useful for persistent rules.",
|
|
47
47
|
args: {
|
|
@@ -56,6 +56,9 @@ export function createAstroInjectPutTool(opts) {
|
|
|
56
56
|
expires_at: tool.schema.string().nullable().optional(),
|
|
57
57
|
},
|
|
58
58
|
execute: async ({ inject_id, type, title, body_md, tags_json, scope, source, priority, expires_at }) => {
|
|
59
|
+
const { db } = runtime;
|
|
60
|
+
if (!db)
|
|
61
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
59
62
|
const id = inject_id ?? newInjectId();
|
|
60
63
|
const now = nowISO();
|
|
61
64
|
const sha = sha256Hex(body_md);
|
|
@@ -109,7 +112,7 @@ export function createAstroInjectPutTool(opts) {
|
|
|
109
112
|
});
|
|
110
113
|
}
|
|
111
114
|
export function createAstroInjectListTool(opts) {
|
|
112
|
-
const {
|
|
115
|
+
const { runtime } = opts;
|
|
113
116
|
return tool({
|
|
114
117
|
description: "List injects (optionally filtered by scope/type).",
|
|
115
118
|
args: {
|
|
@@ -118,6 +121,9 @@ export function createAstroInjectListTool(opts) {
|
|
|
118
121
|
limit: tool.schema.number().int().positive().default(50),
|
|
119
122
|
},
|
|
120
123
|
execute: async ({ scope, type, limit }) => {
|
|
124
|
+
const { db } = runtime;
|
|
125
|
+
if (!db)
|
|
126
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
121
127
|
const where = [];
|
|
122
128
|
const params = [];
|
|
123
129
|
if (scope) {
|
|
@@ -143,13 +149,16 @@ export function createAstroInjectListTool(opts) {
|
|
|
143
149
|
});
|
|
144
150
|
}
|
|
145
151
|
export function createAstroInjectGetTool(opts) {
|
|
146
|
-
const {
|
|
152
|
+
const { runtime } = opts;
|
|
147
153
|
return tool({
|
|
148
154
|
description: "Get an inject by id (full body).",
|
|
149
155
|
args: {
|
|
150
156
|
inject_id: tool.schema.string().min(1),
|
|
151
157
|
},
|
|
152
158
|
execute: async ({ inject_id }) => {
|
|
159
|
+
const { db } = runtime;
|
|
160
|
+
if (!db)
|
|
161
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
153
162
|
const row = db.prepare("SELECT * FROM injects WHERE inject_id=?").get(inject_id);
|
|
154
163
|
if (!row)
|
|
155
164
|
throw new Error(`Inject not found: ${inject_id}`);
|
|
@@ -158,7 +167,7 @@ export function createAstroInjectGetTool(opts) {
|
|
|
158
167
|
});
|
|
159
168
|
}
|
|
160
169
|
export function createAstroInjectSearchTool(opts) {
|
|
161
|
-
const {
|
|
170
|
+
const { runtime } = opts;
|
|
162
171
|
return tool({
|
|
163
172
|
description: "Search injects by query substring over title/body/tags. Returns matches ordered by priority/recency.",
|
|
164
173
|
args: {
|
|
@@ -167,6 +176,9 @@ export function createAstroInjectSearchTool(opts) {
|
|
|
167
176
|
limit: tool.schema.number().int().positive().default(20),
|
|
168
177
|
},
|
|
169
178
|
execute: async ({ q, scope, limit }) => {
|
|
179
|
+
const { db } = runtime;
|
|
180
|
+
if (!db)
|
|
181
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
170
182
|
const like = `%${q}%`;
|
|
171
183
|
const where = ["(title LIKE ? OR body_md LIKE ? OR tags_json LIKE ?)"];
|
|
172
184
|
const params = [like, like, like];
|
|
@@ -210,7 +222,7 @@ export function selectEligibleInjects(db, opts) {
|
|
|
210
222
|
return db.prepare(sql).all(...params);
|
|
211
223
|
}
|
|
212
224
|
export function createAstroInjectEligibleTool(opts) {
|
|
213
|
-
const {
|
|
225
|
+
const { runtime } = opts;
|
|
214
226
|
return tool({
|
|
215
227
|
description: "Debug: show which injects are eligible right now for injection.",
|
|
216
228
|
args: {
|
|
@@ -219,6 +231,9 @@ export function createAstroInjectEligibleTool(opts) {
|
|
|
219
231
|
limit: tool.schema.number().int().positive().default(50),
|
|
220
232
|
},
|
|
221
233
|
execute: async ({ scopes_json, types_json, limit }) => {
|
|
234
|
+
const { db } = runtime;
|
|
235
|
+
if (!db)
|
|
236
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
222
237
|
const now = nowISO();
|
|
223
238
|
const scopes = parseJsonStringArray("scopes_json", scopes_json);
|
|
224
239
|
const types = parseJsonStringArray("types_json", types_json);
|
|
@@ -236,7 +251,7 @@ export function createAstroInjectEligibleTool(opts) {
|
|
|
236
251
|
});
|
|
237
252
|
}
|
|
238
253
|
export function createAstroInjectDebugDueTool(opts) {
|
|
239
|
-
const {
|
|
254
|
+
const { runtime } = opts;
|
|
240
255
|
return tool({
|
|
241
256
|
description: "Debug: show comprehensive injection diagnostics - why injects were selected/skipped.",
|
|
242
257
|
args: {
|
|
@@ -244,6 +259,9 @@ export function createAstroInjectDebugDueTool(opts) {
|
|
|
244
259
|
types_json: tool.schema.string().default('["note","policy"]'),
|
|
245
260
|
},
|
|
246
261
|
execute: async ({ scopes_json, types_json }) => {
|
|
262
|
+
const { db } = runtime;
|
|
263
|
+
if (!db)
|
|
264
|
+
return "⚠️ Astrocode not initialized. Run **astro_init** first.";
|
|
247
265
|
const now = nowISO();
|
|
248
266
|
const nowMs = Date.parse(now);
|
|
249
267
|
const scopes = parseJsonStringArray("scopes_json", scopes_json);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ToolDefinition } from "@opencode-ai/plugin/tool";
|
|
2
|
-
type
|
|
2
|
+
import type { AstrocodeConfig } from "../config/schema";
|
|
3
|
+
import type { RuntimeState } from "../state/types";
|
|
4
|
+
export declare function createAstroMetricsTool(opts: {
|
|
3
5
|
ctx: any;
|
|
4
|
-
config:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export {};
|
|
6
|
+
config: AstrocodeConfig;
|
|
7
|
+
runtime?: RuntimeState;
|
|
8
|
+
}): ToolDefinition;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { 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
|
export declare function createAstroRepairTool(opts: {
|
|
5
5
|
ctx: any;
|
|
6
6
|
config: AstrocodeConfig;
|
|
7
|
-
|
|
7
|
+
runtime: RuntimeState;
|
|
8
8
|
}): ToolDefinition;
|
package/dist/src/tools/repair.js
CHANGED
|
@@ -4,13 +4,17 @@ import { repairState, formatRepairReport } from "../workflow/repair";
|
|
|
4
4
|
import { putArtifact } from "../workflow/artifacts";
|
|
5
5
|
import { nowISO } from "../shared/time";
|
|
6
6
|
export function createAstroRepairTool(opts) {
|
|
7
|
-
const { ctx, config,
|
|
7
|
+
const { ctx, config, runtime } = opts;
|
|
8
8
|
return tool({
|
|
9
9
|
description: "Repair Astrocode invariants and recover from inconsistent DB state. Writes a repair report artifact.",
|
|
10
10
|
args: {
|
|
11
11
|
write_report_artifact: tool.schema.boolean().default(true),
|
|
12
12
|
},
|
|
13
13
|
execute: async ({ write_report_artifact }) => {
|
|
14
|
+
const { db } = runtime;
|
|
15
|
+
if (!db) {
|
|
16
|
+
return "⚠️ Cannot run repair: Astrocode is not initialized. Run **astro_init** first.";
|
|
17
|
+
}
|
|
14
18
|
const repoRoot = ctx.directory;
|
|
15
19
|
// Repair database state
|
|
16
20
|
const report = withTx(db, () => repairState(db, config));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { 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
|
export declare function createAstroResetTool(opts: {
|
|
5
5
|
ctx: any;
|
|
6
6
|
config: AstrocodeConfig;
|
|
7
|
-
|
|
7
|
+
runtime: RuntimeState;
|
|
8
8
|
}): ToolDefinition;
|
package/dist/src/tools/reset.js
CHANGED
|
@@ -3,7 +3,7 @@ import { tool } from "@opencode-ai/plugin/tool";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
export function createAstroResetTool(opts) {
|
|
6
|
-
const { ctx, config,
|
|
6
|
+
const { ctx, config, runtime } = opts;
|
|
7
7
|
return tool({
|
|
8
8
|
description: "Reset Astrocode database: safely delete all DB files and WAL/SHM after killing concurrent processes.",
|
|
9
9
|
args: {
|
|
@@ -23,6 +23,14 @@ export function createAstroResetTool(opts) {
|
|
|
23
23
|
"To confirm: astro_reset(confirm=\"RESET\")",
|
|
24
24
|
].join("\n");
|
|
25
25
|
}
|
|
26
|
+
// Close DB connection if open
|
|
27
|
+
if (runtime.db) {
|
|
28
|
+
try {
|
|
29
|
+
runtime.db.close();
|
|
30
|
+
}
|
|
31
|
+
catch { /* ignore */ }
|
|
32
|
+
runtime.db = null;
|
|
33
|
+
}
|
|
26
34
|
const repoRoot = ctx.directory || process.cwd();
|
|
27
35
|
const dbPath = config.db?.path || ".astro/astro.db";
|
|
28
36
|
const fullDbPath = path.resolve(repoRoot, dbPath);
|