astrocode-workflow 0.3.0 → 0.3.2
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/index.js +6 -0
- package/dist/shared/metrics.d.ts +66 -0
- package/dist/shared/metrics.js +112 -0
- package/dist/src/agents/commands.d.ts +9 -0
- package/dist/src/agents/commands.js +121 -0
- package/dist/src/agents/prompts.d.ts +3 -0
- package/dist/src/agents/prompts.js +232 -0
- package/dist/src/agents/registry.d.ts +6 -0
- package/dist/src/agents/registry.js +242 -0
- package/dist/src/agents/types.d.ts +14 -0
- package/dist/src/agents/types.js +8 -0
- package/dist/src/config/config-handler.d.ts +4 -0
- package/dist/src/config/config-handler.js +46 -0
- package/dist/src/config/defaults.d.ts +3 -0
- package/dist/src/config/defaults.js +3 -0
- package/dist/src/config/loader.d.ts +11 -0
- package/dist/src/config/loader.js +82 -0
- package/dist/src/config/schema.d.ts +194 -0
- package/dist/src/config/schema.js +223 -0
- package/dist/src/hooks/continuation-enforcer.d.ts +34 -0
- package/dist/src/hooks/continuation-enforcer.js +190 -0
- package/dist/src/hooks/inject-provider.d.ts +22 -0
- package/dist/src/hooks/inject-provider.js +120 -0
- package/dist/src/hooks/tool-output-truncator.d.ts +25 -0
- package/dist/src/hooks/tool-output-truncator.js +57 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +308 -0
- package/dist/src/shared/deep-merge.d.ts +8 -0
- package/dist/src/shared/deep-merge.js +25 -0
- package/dist/src/shared/hash.d.ts +1 -0
- package/dist/src/shared/hash.js +4 -0
- package/dist/src/shared/log.d.ts +7 -0
- package/dist/src/shared/log.js +24 -0
- package/dist/src/shared/metrics.d.ts +66 -0
- package/dist/src/shared/metrics.js +112 -0
- package/dist/src/shared/model-tuning.d.ts +9 -0
- package/dist/src/shared/model-tuning.js +28 -0
- package/dist/src/shared/paths.d.ts +19 -0
- package/dist/src/shared/paths.js +64 -0
- package/dist/src/shared/text.d.ts +4 -0
- package/dist/src/shared/text.js +19 -0
- package/dist/src/shared/time.d.ts +1 -0
- package/dist/src/shared/time.js +3 -0
- package/dist/src/state/adapters/index.d.ts +41 -0
- package/dist/src/state/adapters/index.js +115 -0
- package/dist/src/state/db.d.ts +16 -0
- package/dist/src/state/db.js +225 -0
- package/dist/src/state/ids.d.ts +8 -0
- package/dist/src/state/ids.js +25 -0
- package/dist/src/state/repo-lock.d.ts +3 -0
- package/dist/src/state/repo-lock.js +29 -0
- package/dist/src/state/schema.d.ts +2 -0
- package/dist/src/state/schema.js +251 -0
- package/dist/src/state/types.d.ts +71 -0
- package/dist/src/state/types.js +1 -0
- package/dist/src/tools/artifacts.d.ts +18 -0
- package/dist/src/tools/artifacts.js +71 -0
- package/dist/src/tools/health.d.ts +8 -0
- package/dist/src/tools/health.js +119 -0
- package/dist/src/tools/index.d.ts +20 -0
- package/dist/src/tools/index.js +94 -0
- package/dist/src/tools/init.d.ts +17 -0
- package/dist/src/tools/init.js +96 -0
- package/dist/src/tools/injects.d.ts +53 -0
- package/dist/src/tools/injects.js +325 -0
- package/dist/src/tools/metrics.d.ts +7 -0
- package/dist/src/tools/metrics.js +61 -0
- package/dist/src/tools/repair.d.ts +8 -0
- package/dist/src/tools/repair.js +25 -0
- package/dist/src/tools/reset.d.ts +8 -0
- package/dist/src/tools/reset.js +92 -0
- package/dist/src/tools/run.d.ts +13 -0
- package/dist/src/tools/run.js +54 -0
- package/dist/src/tools/spec.d.ts +12 -0
- package/dist/src/tools/spec.js +44 -0
- package/dist/src/tools/stage.d.ts +23 -0
- package/dist/src/tools/stage.js +371 -0
- package/dist/src/tools/status.d.ts +8 -0
- package/dist/src/tools/status.js +125 -0
- package/dist/src/tools/story.d.ts +23 -0
- package/dist/src/tools/story.js +85 -0
- package/dist/src/tools/workflow.d.ts +13 -0
- package/dist/src/tools/workflow.js +355 -0
- package/dist/src/ui/inject.d.ts +12 -0
- package/dist/src/ui/inject.js +107 -0
- package/dist/src/ui/toasts.d.ts +13 -0
- package/dist/src/ui/toasts.js +39 -0
- package/dist/src/workflow/artifacts.d.ts +24 -0
- package/dist/src/workflow/artifacts.js +45 -0
- package/dist/src/workflow/baton.d.ts +72 -0
- package/dist/src/workflow/baton.js +166 -0
- package/dist/src/workflow/context.d.ts +20 -0
- package/dist/src/workflow/context.js +113 -0
- package/dist/src/workflow/directives.d.ts +39 -0
- package/dist/src/workflow/directives.js +137 -0
- package/dist/src/workflow/repair.d.ts +8 -0
- package/dist/src/workflow/repair.js +99 -0
- package/dist/src/workflow/state-machine.d.ts +86 -0
- package/dist/src/workflow/state-machine.js +216 -0
- package/dist/src/workflow/story-helpers.d.ts +9 -0
- package/dist/src/workflow/story-helpers.js +13 -0
- package/dist/state/db.d.ts +1 -0
- package/dist/state/db.js +9 -0
- package/dist/state/repo-lock.d.ts +3 -0
- package/dist/state/repo-lock.js +29 -0
- package/dist/test/integration/db-transactions.test.d.ts +1 -0
- package/dist/test/integration/db-transactions.test.js +126 -0
- package/dist/test/integration/injection-metrics.test.d.ts +1 -0
- package/dist/test/integration/injection-metrics.test.js +129 -0
- package/dist/tools/health.d.ts +8 -0
- package/dist/tools/health.js +119 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/metrics.d.ts +7 -0
- package/dist/tools/metrics.js +61 -0
- package/dist/tools/reset.d.ts +8 -0
- package/dist/tools/reset.js +92 -0
- package/dist/tools/workflow.js +210 -215
- package/dist/ui/inject.d.ts +6 -0
- package/dist/ui/inject.js +86 -67
- package/dist/workflow/state-machine.d.ts +32 -32
- package/dist/workflow/state-machine.js +85 -170
- package/package.json +6 -3
- package/src/index.ts +8 -0
- package/src/shared/metrics.ts +148 -0
- package/src/state/db.ts +10 -1
- package/src/state/repo-lock.ts +158 -0
- package/src/tools/health.ts +128 -0
- package/src/tools/index.ts +12 -3
- package/src/tools/init.ts +26 -14
- package/src/tools/metrics.ts +71 -0
- package/src/tools/repair.ts +21 -8
- package/src/tools/reset.ts +100 -0
- package/src/tools/stage.ts +12 -0
- package/src/tools/status.ts +17 -3
- package/src/tools/story.ts +41 -15
- package/src/tools/workflow.ts +123 -121
- package/src/ui/inject.ts +113 -79
- package/src/workflow/state-machine.ts +123 -227
- package/src/tools/workflow.ts.backup +0 -681
package/dist/tools/workflow.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
// src/tools/workflow.ts
|
|
2
2
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
3
|
+
import { withTx } from "../state/db";
|
|
3
4
|
import { buildContextSnapshot } from "../workflow/context";
|
|
4
|
-
import { decideNextAction, createRunForStory, startStage, completeRun, getActiveRun, EVENT_TYPES } from "../workflow/state-machine";
|
|
5
|
+
import { decideNextAction, createRunForStory, startStage, completeRun, failRun, getActiveRun, EVENT_TYPES, } from "../workflow/state-machine";
|
|
5
6
|
import { buildStageDirective, directiveHash } from "../workflow/directives";
|
|
6
7
|
import { injectChatPrompt } from "../ui/inject";
|
|
7
8
|
import { nowISO } from "../shared/time";
|
|
8
9
|
import { newEventId } from "../state/ids";
|
|
9
10
|
import { debug } from "../shared/log";
|
|
10
11
|
import { createToastManager } from "../ui/toasts";
|
|
12
|
+
import { acquireRepoLock } from "../state/repo-lock";
|
|
11
13
|
// Agent name mapping for case-sensitive resolution
|
|
12
14
|
export const STAGE_TO_AGENT_MAP = {
|
|
13
15
|
frame: "Frame",
|
|
@@ -104,6 +106,46 @@ function buildDelegationPrompt(opts) {
|
|
|
104
106
|
debug(`Delegating stage ${stage_key} to agent ${stage_agent_name}`, { prompt_length: prompt.length });
|
|
105
107
|
return prompt;
|
|
106
108
|
}
|
|
109
|
+
function buildUiMessage(e) {
|
|
110
|
+
switch (e.kind) {
|
|
111
|
+
case "stage_started": {
|
|
112
|
+
const agent = e.agent_name ? ` (${e.agent_name})` : "";
|
|
113
|
+
const title = "Astrocode";
|
|
114
|
+
const message = `Stage started: ${e.stage_key}${agent}`;
|
|
115
|
+
const chatText = [
|
|
116
|
+
`[SYSTEM DIRECTIVE: ASTROCODE — STAGE_STARTED]`,
|
|
117
|
+
``,
|
|
118
|
+
`Run: ${e.run_id}`,
|
|
119
|
+
`Stage: ${e.stage_key}${agent}`,
|
|
120
|
+
].join("\n");
|
|
121
|
+
return { title, message, variant: "info", chatText };
|
|
122
|
+
}
|
|
123
|
+
case "run_completed": {
|
|
124
|
+
const title = "Astrocode";
|
|
125
|
+
const message = `Run completed: ${e.run_id}`;
|
|
126
|
+
const chatText = [
|
|
127
|
+
`[SYSTEM DIRECTIVE: ASTROCODE — RUN_COMPLETED]`,
|
|
128
|
+
``,
|
|
129
|
+
`Run: ${e.run_id}`,
|
|
130
|
+
`Story: ${e.story_key}`,
|
|
131
|
+
].join("\n");
|
|
132
|
+
return { title, message, variant: "success", chatText };
|
|
133
|
+
}
|
|
134
|
+
case "run_failed": {
|
|
135
|
+
const title = "Astrocode";
|
|
136
|
+
const message = `Run failed: ${e.run_id} (${e.stage_key})`;
|
|
137
|
+
const chatText = [
|
|
138
|
+
`[SYSTEM DIRECTIVE: ASTROCODE — RUN_FAILED]`,
|
|
139
|
+
``,
|
|
140
|
+
`Run: ${e.run_id}`,
|
|
141
|
+
`Story: ${e.story_key}`,
|
|
142
|
+
`Stage: ${e.stage_key}`,
|
|
143
|
+
`Error: ${e.error_text}`,
|
|
144
|
+
].join("\n");
|
|
145
|
+
return { title, message, variant: "error", chatText };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
107
149
|
export function createAstroWorkflowProceedTool(opts) {
|
|
108
150
|
const { ctx, config, db, agents } = opts;
|
|
109
151
|
const toasts = createToastManager({ ctx, throttleMs: config.ui.toasts.throttle_ms });
|
|
@@ -114,247 +156,200 @@ export function createAstroWorkflowProceedTool(opts) {
|
|
|
114
156
|
max_steps: tool.schema.number().int().positive().default(config.workflow.default_max_steps),
|
|
115
157
|
},
|
|
116
158
|
execute: async ({ mode, max_steps }) => {
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
// Acquire repo lock to ensure no concurrent workflow operations
|
|
160
|
+
const lockPath = `${ctx.directory}/.astro/astro.lock`;
|
|
161
|
+
const repoLock = acquireRepoLock(lockPath);
|
|
162
|
+
try {
|
|
163
|
+
const sessionId = ctx.sessionID;
|
|
164
|
+
const steps = Math.min(max_steps, config.workflow.loop_max_steps_hard_cap);
|
|
165
|
+
const actions = [];
|
|
166
|
+
const warnings = [];
|
|
167
|
+
const startedAt = nowISO();
|
|
168
|
+
// Collect UI events emitted inside state-machine functions, then flush AFTER tx.
|
|
169
|
+
const uiEvents = [];
|
|
170
|
+
const emit = (e) => uiEvents.push(e);
|
|
171
|
+
for (let i = 0; i < steps; i++) {
|
|
172
|
+
const next = decideNextAction(db, config);
|
|
173
|
+
if (next.kind === "idle") {
|
|
174
|
+
actions.push("idle: no approved stories");
|
|
175
|
+
break;
|
|
134
176
|
}
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
``,
|
|
143
|
-
`Run started: \`${run_id}\``,
|
|
144
|
-
`Story: \`${next.story_key}\``,
|
|
145
|
-
``,
|
|
146
|
-
`Next: call **astro_workflow_proceed** again to delegate the first stage.`,
|
|
147
|
-
].join("\n"),
|
|
148
|
-
});
|
|
149
|
-
actions.push(`injected run started message for ${run_id}`);
|
|
177
|
+
if (next.kind === "start_run") {
|
|
178
|
+
// SINGLE tx boundary: caller owns tx, state-machine is pure.
|
|
179
|
+
const { run_id } = withTx(db, () => createRunForStory(db, config, next.story_key));
|
|
180
|
+
actions.push(`started run ${run_id} for story ${next.story_key}`);
|
|
181
|
+
if (mode === "step")
|
|
182
|
+
break;
|
|
183
|
+
continue;
|
|
150
184
|
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
completeRun(db, next.run_id);
|
|
158
|
-
actions.push(`completed run ${next.run_id}`);
|
|
159
|
-
if (config.ui.toasts.enabled && config.ui.toasts.show_run_completed) {
|
|
160
|
-
await toasts.show({ title: "Astrocode", message: `Run completed (${next.run_id})`, variant: "success" });
|
|
185
|
+
if (next.kind === "complete_run") {
|
|
186
|
+
withTx(db, () => completeRun(db, next.run_id, emit));
|
|
187
|
+
actions.push(`completed run ${next.run_id}`);
|
|
188
|
+
if (mode === "step")
|
|
189
|
+
break;
|
|
190
|
+
continue;
|
|
161
191
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`[SYSTEM DIRECTIVE: ASTROCODE — RUN_COMPLETED]`,
|
|
170
|
-
``,
|
|
171
|
-
`Run \`${next.run_id}\` completed.`,
|
|
172
|
-
``,
|
|
173
|
-
`Next: call **astro_workflow_proceed** (mode=step) to start the next approved story (if any).`,
|
|
174
|
-
].join("\n"),
|
|
175
|
-
});
|
|
176
|
-
actions.push(`injected run completed message for ${next.run_id}`);
|
|
192
|
+
if (next.kind === "failed") {
|
|
193
|
+
// Ensure DB state reflects failure in one tx; emit UI event.
|
|
194
|
+
withTx(db, () => failRun(db, next.run_id, next.stage_key, next.error_text, emit));
|
|
195
|
+
actions.push(`failed: ${next.stage_key} — ${next.error_text}`);
|
|
196
|
+
if (mode === "step")
|
|
197
|
+
break;
|
|
198
|
+
continue;
|
|
177
199
|
}
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
if (knownStageAgents.includes(name))
|
|
194
|
-
return true;
|
|
195
|
-
return false;
|
|
196
|
-
};
|
|
197
|
-
if (!agentExists(agentName)) {
|
|
198
|
-
const originalAgent = agentName;
|
|
199
|
-
console.warn(`[Astrocode] Agent ${agentName} not found. Falling back to orchestrator.`);
|
|
200
|
-
agentName = config.agents?.orchestrator_name || "Astro";
|
|
200
|
+
if (next.kind === "delegate_stage") {
|
|
201
|
+
const active = getActiveRun(db);
|
|
202
|
+
if (!active)
|
|
203
|
+
throw new Error("Invariant: delegate_stage but no active run.");
|
|
204
|
+
const run = db.prepare("SELECT * FROM runs WHERE run_id=?").get(active.run_id);
|
|
205
|
+
const story = db.prepare("SELECT * FROM stories WHERE story_key=?").get(run.story_key);
|
|
206
|
+
let agentName = resolveAgentName(next.stage_key, config, agents, warnings);
|
|
207
|
+
const agentExists = (name) => {
|
|
208
|
+
if (agents && agents[name])
|
|
209
|
+
return true;
|
|
210
|
+
const knownStageAgents = ["Frame", "Plan", "Spec", "Implement", "Review", "Verify", "Close", "General", "Astro", "general"];
|
|
211
|
+
if (knownStageAgents.includes(name))
|
|
212
|
+
return true;
|
|
213
|
+
return false;
|
|
214
|
+
};
|
|
201
215
|
if (!agentExists(agentName)) {
|
|
202
|
-
|
|
203
|
-
agentName
|
|
216
|
+
const originalAgent = agentName;
|
|
217
|
+
console.warn(`[Astrocode] Agent ${agentName} not found. Falling back to orchestrator.`);
|
|
218
|
+
agentName = config.agents?.orchestrator_name || "Astro";
|
|
204
219
|
if (!agentExists(agentName)) {
|
|
205
|
-
|
|
220
|
+
console.warn(`[Astrocode] Orchestrator ${agentName} not available. Falling back to General.`);
|
|
221
|
+
agentName = "General";
|
|
222
|
+
if (!agentExists(agentName)) {
|
|
223
|
+
throw new Error(`Critical: No agents available for delegation. Primary: ${originalAgent}, Orchestrator: ${config.agents?.orchestrator_name || "Astro"}, General: unavailable`);
|
|
224
|
+
}
|
|
206
225
|
}
|
|
207
226
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
actions.push(`stage started: ${next.stage_key}`);
|
|
212
|
-
if (config.ui.toasts.enabled && config.ui.toasts.show_stage_started) {
|
|
213
|
-
await toasts.show({ title: "Astrocode", message: `Stage started: ${next.stage_key}`, variant: "info" });
|
|
214
|
-
}
|
|
215
|
-
// ✅ explicit injection on startStage (requested)
|
|
216
|
-
if (sessionId) {
|
|
217
|
-
await injectChatPrompt({
|
|
218
|
-
ctx,
|
|
219
|
-
sessionId,
|
|
220
|
-
agent: "Astro",
|
|
221
|
-
text: [
|
|
222
|
-
`[SYSTEM DIRECTIVE: ASTROCODE — STAGE_STARTED]`,
|
|
223
|
-
``,
|
|
224
|
-
`Run: \`${active.run_id}\``,
|
|
225
|
-
`Stage: \`${next.stage_key}\``,
|
|
226
|
-
`Delegated to: \`${agentName}\``,
|
|
227
|
-
].join("\n"),
|
|
227
|
+
// NOTE: startStage owns its own tx (state-machine.ts).
|
|
228
|
+
withTx(db, () => {
|
|
229
|
+
startStage(db, active.run_id, next.stage_key, { subagent_type: agentName }, emit);
|
|
228
230
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
});
|
|
254
|
-
// Best-effort: continuations table may not exist on older DBs.
|
|
255
|
-
try {
|
|
231
|
+
const context = buildContextSnapshot({
|
|
232
|
+
db,
|
|
233
|
+
config,
|
|
234
|
+
run_id: active.run_id,
|
|
235
|
+
next_action: `delegate stage ${next.stage_key}`,
|
|
236
|
+
});
|
|
237
|
+
const stageDirective = buildStageDirective({
|
|
238
|
+
config,
|
|
239
|
+
stage_key: next.stage_key,
|
|
240
|
+
run_id: active.run_id,
|
|
241
|
+
story_key: run.story_key,
|
|
242
|
+
story_title: story?.title ?? "(missing)",
|
|
243
|
+
stage_agent_name: agentName,
|
|
244
|
+
stage_goal: stageGoal(next.stage_key, config),
|
|
245
|
+
stage_constraints: stageConstraints(next.stage_key, config),
|
|
246
|
+
context_snapshot_md: context,
|
|
247
|
+
}).body;
|
|
248
|
+
const delegatePrompt = buildDelegationPrompt({
|
|
249
|
+
stageDirective,
|
|
250
|
+
run_id: active.run_id,
|
|
251
|
+
stage_key: next.stage_key,
|
|
252
|
+
stage_agent_name: agentName,
|
|
253
|
+
});
|
|
254
|
+
// Record continuation (best-effort; no tx wrapper needed but safe either way)
|
|
256
255
|
const h = directiveHash(delegatePrompt);
|
|
257
256
|
const now = nowISO();
|
|
258
257
|
if (sessionId) {
|
|
258
|
+
// This assumes continuations table exists in vNext schema.
|
|
259
259
|
db.prepare("INSERT INTO continuations (session_id, run_id, directive_hash, kind, reason, created_at) VALUES (?, ?, ?, 'stage', ?, ?)").run(sessionId, active.run_id, h, `delegate ${next.stage_key}`, now);
|
|
260
260
|
}
|
|
261
|
+
// Visible injection so user can see state (awaited)
|
|
262
|
+
if (sessionId) {
|
|
263
|
+
await injectChatPrompt({ ctx, sessionId, text: delegatePrompt, agent: "Astro" });
|
|
264
|
+
const continueMessage = [
|
|
265
|
+
`[SYSTEM DIRECTIVE: ASTROCODE — AWAIT_STAGE_COMPLETION]`,
|
|
266
|
+
``,
|
|
267
|
+
`Stage \`${next.stage_key}\` delegated to \`${agentName}\`.`,
|
|
268
|
+
``,
|
|
269
|
+
`When \`${agentName}\` completes, call:`,
|
|
270
|
+
`astro_stage_complete(run_id="${active.run_id}", stage_key="${next.stage_key}", output_text="[paste subagent output here]")`,
|
|
271
|
+
``,
|
|
272
|
+
`This advances the workflow.`,
|
|
273
|
+
].join("\n");
|
|
274
|
+
await injectChatPrompt({ ctx, sessionId, text: continueMessage, agent: "Astro" });
|
|
275
|
+
}
|
|
276
|
+
actions.push(`delegated stage ${next.stage_key} via ${agentName}`);
|
|
277
|
+
// Stop here; subagent needs to run.
|
|
278
|
+
break;
|
|
261
279
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
actions.push(`delegated stage ${next.stage_key} via ${agentName}`);
|
|
281
|
-
// Stop here; subagent needs to run.
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
if (next.kind === "await_stage_completion") {
|
|
285
|
-
actions.push(`await stage completion: ${next.stage_key}`);
|
|
286
|
-
if (sessionId) {
|
|
287
|
-
const context = buildContextSnapshot({
|
|
288
|
-
db,
|
|
289
|
-
config,
|
|
290
|
-
run_id: next.run_id,
|
|
291
|
-
next_action: `complete stage ${next.stage_key}`,
|
|
292
|
-
});
|
|
293
|
-
const prompt = [
|
|
294
|
-
`[SYSTEM DIRECTIVE: ASTROCODE — AWAIT_STAGE_OUTPUT]`,
|
|
295
|
-
``,
|
|
296
|
-
`Run \`${next.run_id}\` is waiting for stage \`${next.stage_key}\` output.`,
|
|
297
|
-
`If you have the subagent output, call astro_stage_complete with output_text=the FULL output.`,
|
|
298
|
-
``,
|
|
299
|
-
`Context snapshot:`,
|
|
300
|
-
context,
|
|
301
|
-
].join("\n").trim();
|
|
302
|
-
try {
|
|
280
|
+
if (next.kind === "await_stage_completion") {
|
|
281
|
+
actions.push(`await stage completion: ${next.stage_key}`);
|
|
282
|
+
if (sessionId) {
|
|
283
|
+
const context = buildContextSnapshot({
|
|
284
|
+
db,
|
|
285
|
+
config,
|
|
286
|
+
run_id: next.run_id,
|
|
287
|
+
next_action: `complete stage ${next.stage_key}`,
|
|
288
|
+
});
|
|
289
|
+
const prompt = [
|
|
290
|
+
`[SYSTEM DIRECTIVE: ASTROCODE — AWAIT_STAGE_OUTPUT]`,
|
|
291
|
+
``,
|
|
292
|
+
`Run \`${next.run_id}\` is waiting for stage \`${next.stage_key}\` output.`,
|
|
293
|
+
`If you have the subagent output, call astro_stage_complete with output_text=the FULL output.`,
|
|
294
|
+
``,
|
|
295
|
+
`Context snapshot:`,
|
|
296
|
+
context,
|
|
297
|
+
].join("\n").trim();
|
|
303
298
|
const h = directiveHash(prompt);
|
|
304
299
|
const now = nowISO();
|
|
305
300
|
db.prepare("INSERT INTO continuations (session_id, run_id, directive_hash, kind, reason, created_at) VALUES (?, ?, ?, 'continue', ?, ?)").run(sessionId, next.run_id, h, `await ${next.stage_key}`, now);
|
|
301
|
+
await injectChatPrompt({ ctx, sessionId, text: prompt, agent: "Astro" });
|
|
306
302
|
}
|
|
307
|
-
|
|
308
|
-
warnings.push(`continuations insert failed (non-fatal): ${String(e)}`);
|
|
309
|
-
}
|
|
310
|
-
await injectChatPrompt({ ctx, sessionId, text: prompt, agent: "Astro" });
|
|
303
|
+
break;
|
|
311
304
|
}
|
|
305
|
+
actions.push(`unhandled next action: ${next.kind}`);
|
|
312
306
|
break;
|
|
313
307
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
308
|
+
// Flush UI events (toast + prompt) AFTER state transitions
|
|
309
|
+
if (uiEvents.length > 0) {
|
|
310
|
+
for (const e of uiEvents) {
|
|
311
|
+
const msg = buildUiMessage(e);
|
|
312
|
+
if (config.ui.toasts.enabled) {
|
|
313
|
+
await toasts.show({
|
|
314
|
+
title: msg.title,
|
|
315
|
+
message: msg.message,
|
|
316
|
+
variant: msg.variant,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (ctx?.sessionID) {
|
|
320
|
+
await injectChatPrompt({
|
|
321
|
+
ctx,
|
|
322
|
+
sessionId: ctx.sessionID,
|
|
323
|
+
text: msg.chatText,
|
|
324
|
+
agent: "Astro",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
329
327
|
}
|
|
330
|
-
|
|
328
|
+
actions.push(`ui: flushed ${uiEvents.length} event(s)`);
|
|
331
329
|
}
|
|
332
|
-
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
// Housekeeping event (best-effort)
|
|
336
|
-
try {
|
|
330
|
+
// Housekeeping event
|
|
337
331
|
db.prepare("INSERT INTO events (event_id, run_id, stage_key, type, body_json, created_at) VALUES (?, NULL, NULL, ?, ?, ?)").run(newEventId(), EVENT_TYPES.WORKFLOW_PROCEED, JSON.stringify({ started_at: startedAt, mode, max_steps: steps, actions }), nowISO());
|
|
332
|
+
const active = getActiveRun(db);
|
|
333
|
+
const lines = [];
|
|
334
|
+
lines.push(`# astro_workflow_proceed`);
|
|
335
|
+
lines.push(`- mode: ${mode}`);
|
|
336
|
+
lines.push(`- steps requested: ${max_steps} (cap=${steps})`);
|
|
337
|
+
if (active)
|
|
338
|
+
lines.push(`- active run: \`${active.run_id}\` (stage=${active.current_stage_key ?? "?"})`);
|
|
339
|
+
lines.push(``, `## Actions`);
|
|
340
|
+
for (const a of actions)
|
|
341
|
+
lines.push(`- ${a}`);
|
|
342
|
+
if (warnings.length > 0) {
|
|
343
|
+
lines.push(``, `## Warnings`);
|
|
344
|
+
for (const w of warnings)
|
|
345
|
+
lines.push(`⚠️ ${w}`);
|
|
346
|
+
}
|
|
347
|
+
return lines.join("\n").trim();
|
|
338
348
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const active = getActiveRun(db);
|
|
343
|
-
const lines = [];
|
|
344
|
-
lines.push(`# astro_workflow_proceed`);
|
|
345
|
-
lines.push(`- mode: ${mode}`);
|
|
346
|
-
lines.push(`- steps requested: ${max_steps} (cap=${steps})`);
|
|
347
|
-
if (active)
|
|
348
|
-
lines.push(`- active run: \`${active.run_id}\` (stage=${active.current_stage_key ?? "?"})`);
|
|
349
|
-
lines.push(``, `## Actions`);
|
|
350
|
-
for (const a of actions)
|
|
351
|
-
lines.push(`- ${a}`);
|
|
352
|
-
if (warnings.length > 0) {
|
|
353
|
-
lines.push(``, `## Warnings`);
|
|
354
|
-
for (const w of warnings)
|
|
355
|
-
lines.push(`⚠️ ${w}`);
|
|
349
|
+
finally {
|
|
350
|
+
// Always release the lock
|
|
351
|
+
repoLock.release();
|
|
356
352
|
}
|
|
357
|
-
return lines.join("\n").trim();
|
|
358
353
|
},
|
|
359
354
|
});
|
|
360
355
|
}
|
package/dist/ui/inject.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inject a visible prompt into the conversation.
|
|
3
|
+
* - Deterministic ordering per session
|
|
4
|
+
* - Correct SDK binding (prevents `this._client` undefined)
|
|
5
|
+
* - Awaitable: resolves when delivered, rejects after max retries
|
|
6
|
+
*/
|
|
1
7
|
export declare function injectChatPrompt(opts: {
|
|
2
8
|
ctx: any;
|
|
3
9
|
sessionId?: string;
|