astrocode-workflow 0.1.19 → 0.1.20

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.
@@ -1,2 +1,2 @@
1
1
  export declare const BASE_ORCH_PROMPT = "You are Astro (Orchestrator) for Astrocode.\n\nMission:\n- Advance a deterministic pipeline: frame \u2192 plan \u2192 spec \u2192 implement \u2192 review \u2192 verify \u2192 close.\n- The SQLite DB is the source of truth. Prefer tools over prose.\n- Never narrate what prompts you received.\n- Keep outputs short; store large outputs as artifacts and reference paths.\n\nOperating rules:\n- Only start new runs when the user explicitly requests implementation, workflow management, or story processing.\n- Answer questions directly when possible without starting workflows.\n- Prefer calling astro_workflow_proceed (step/loop) and astro_status only when actively managing a workflow.\n- Delegate stage work only to the stage subagent matching the current stage.\n- If a stage subagent returns status=blocked, inject the BLOCKED directive and stop.\n- Never delegate from subagents (enforced by permissions).\n- Be discretionary: assess if the user's request requires workflow initiation or just information.\n";
2
- export declare const BASE_STAGE_PROMPT = "You are an Astro stage subagent.\n\nFollow the latest [SYSTEM DIRECTIVE: ASTROCODE \u2014 STAGE_*] you receive.\n\nOutput exactly in this order:\n1) Baton markdown (short, structured narrative summary)\n2) Valid ASTRO JSON between markers with ALL required fields (do not omit any):\n\n<!-- ASTRO_JSON_BEGIN -->\n{\n \"schema_version\": 1,\n \"stage_key\": \"CURRENT_STAGE\",\n \"status\": \"ok\",\n \"summary\": \"Brief summary of work done\",\n \"decisions\": [],\n \"next_actions\": [],\n \"tasks\": [],\n \"files\": [],\n \"evidence\": [],\n \"new_stories\": [],\n \"questions\": [],\n \"metrics\": {}\n}\n<!-- ASTRO_JSON_END -->\n\nCRITICAL REQUIREMENTS:\n- Include ALL fields shown above (even if empty arrays/objects)\n- stage_key must match the current stage exactly\n- status must be \"ok\", \"blocked\", or \"failed\"\n- summary must be a non-empty string describing the work\n- JSON must be valid syntax and parseable\n- Markers must be exact: <!-- ASTRO_JSON_BEGIN --> and <!-- ASTRO_JSON_END -->\n\nDo not narrate extra text. If blocked, set status=\"blocked\", ask exactly ONE question in questions array, and stop.\n";
2
+ export declare const BASE_STAGE_PROMPT = "You are an Astro stage subagent.\n\n***CRITICAL: Follow the latest [SYSTEM DIRECTIVE: ASTROCODE \u2014 STAGE_*] you receive EXACTLY.***\n\nYour output MUST be in this EXACT format (no deviations):\n\n1) First, a short baton markdown summary (1-3 sentences).\n\n2) Then, immediately after, the ASTRO JSON markers with valid JSON:\n\n<!-- ASTRO_JSON_BEGIN -->\n{\n \"schema_version\": 1,\n \"stage_key\": \"CURRENT_STAGE\",\n \"status\": \"ok\",\n \"summary\": \"Brief summary\",\n \"decisions\": [],\n \"next_actions\": [],\n \"tasks\": [],\n \"files\": [],\n \"evidence\": [],\n \"new_stories\": [],\n \"questions\": [],\n \"metrics\": {}\n}\n<!-- ASTRO_JSON_END -->\n\nMANDATORY RULES:\n- ALL fields above MUST be present (use empty arrays/objects if no data)\n- stage_key MUST be \"CURRENT_STAGE\" (will be replaced)\n- status MUST be \"ok\" unless blocked/failed\n- summary MUST be a string describing the work\n- JSON MUST be valid and parseable\n- Markers MUST be exact as shown\n\nIf blocked, set status=\"blocked\" and put ONE question in questions array. Do not output anything else.\n";
@@ -17,18 +17,20 @@ Operating rules:
17
17
  `;
18
18
  export const BASE_STAGE_PROMPT = `You are an Astro stage subagent.
19
19
 
20
- Follow the latest [SYSTEM DIRECTIVE: ASTROCODE — STAGE_*] you receive.
20
+ ***CRITICAL: Follow the latest [SYSTEM DIRECTIVE: ASTROCODE — STAGE_*] you receive EXACTLY.***
21
21
 
22
- Output exactly in this order:
23
- 1) Baton markdown (short, structured narrative summary)
24
- 2) Valid ASTRO JSON between markers with ALL required fields (do not omit any):
22
+ Your output MUST be in this EXACT format (no deviations):
23
+
24
+ 1) First, a short baton markdown summary (1-3 sentences).
25
+
26
+ 2) Then, immediately after, the ASTRO JSON markers with valid JSON:
25
27
 
26
28
  <!-- ASTRO_JSON_BEGIN -->
27
29
  {
28
30
  "schema_version": 1,
29
31
  "stage_key": "CURRENT_STAGE",
30
32
  "status": "ok",
31
- "summary": "Brief summary of work done",
33
+ "summary": "Brief summary",
32
34
  "decisions": [],
33
35
  "next_actions": [],
34
36
  "tasks": [],
@@ -40,13 +42,13 @@ Output exactly in this order:
40
42
  }
41
43
  <!-- ASTRO_JSON_END -->
42
44
 
43
- CRITICAL REQUIREMENTS:
44
- - Include ALL fields shown above (even if empty arrays/objects)
45
- - stage_key must match the current stage exactly
46
- - status must be "ok", "blocked", or "failed"
47
- - summary must be a non-empty string describing the work
48
- - JSON must be valid syntax and parseable
49
- - Markers must be exact: <!-- ASTRO_JSON_BEGIN --> and <!-- ASTRO_JSON_END -->
45
+ MANDATORY RULES:
46
+ - ALL fields above MUST be present (use empty arrays/objects if no data)
47
+ - stage_key MUST be "CURRENT_STAGE" (will be replaced)
48
+ - status MUST be "ok" unless blocked/failed
49
+ - summary MUST be a string describing the work
50
+ - JSON MUST be valid and parseable
51
+ - Markers MUST be exact as shown
50
52
 
51
- Do not narrate extra text. If blocked, set status="blocked", ask exactly ONE question in questions array, and stop.
53
+ If blocked, set status="blocked" and put ONE question in questions array. Do not output anything else.
52
54
  `;
@@ -6,6 +6,7 @@ import { buildStageDirective, directiveHash } from "../workflow/directives";
6
6
  import { injectChatPrompt } from "../ui/inject";
7
7
  import { nowISO } from "../shared/time";
8
8
  import { newEventId } from "../state/ids";
9
+ import { debug } from "../shared/log";
9
10
  import { createToastManager } from "../ui/toasts";
10
11
  // Agent name mapping for case-sensitive resolution
11
12
  const STAGE_TO_AGENT_MAP = {
@@ -63,7 +64,7 @@ function agentNameForStage(stage, cfg) {
63
64
  function buildDelegationPrompt(opts) {
64
65
  const { stageDirective, run_id, stage_key, stage_agent_name } = opts;
65
66
  const stageUpper = stage_key.toUpperCase();
66
- return [
67
+ const prompt = [
67
68
  `[SYSTEM DIRECTIVE: ASTROCODE — DELEGATE_STAGE_${stageUpper}]`,
68
69
  ``,
69
70
  `Do this now, in order:`,
@@ -81,6 +82,9 @@ function buildDelegationPrompt(opts) {
81
82
  ``,
82
83
  `Important: do NOT do any stage work yourself in orchestrator mode.`,
83
84
  ].join("\n").trim();
85
+ // Debug log the delegation prompt to troubleshoot agent output issues
86
+ debug(`Delegating stage ${stage_key} to agent ${stage_agent_name}`, { prompt_length: prompt.length });
87
+ return prompt;
84
88
  }
85
89
  export function createAstroWorkflowProceedTool(opts) {
86
90
  const { ctx, config, db, agents } = opts;
@@ -1,5 +1,6 @@
1
1
  import { clampLines, normalizeNewlines, stripCodeFences } from "../shared/text";
2
2
  import { z, ZodError } from "zod";
3
+ import { debug } from "../shared/log";
3
4
  export const ASTRO_JSON_BEGIN = "<!-- ASTRO_JSON_BEGIN -->";
4
5
  export const ASTRO_JSON_END = "<!-- ASTRO_JSON_END -->";
5
6
  export const StageKeySchema = z.enum(["frame", "plan", "spec", "implement", "review", "verify", "close"]);
@@ -40,28 +41,46 @@ export function parseStageOutputText(text) {
40
41
  const norm = normalizeNewlines(text ?? "").trim();
41
42
  const beginIdx = norm.indexOf(ASTRO_JSON_BEGIN);
42
43
  const endIdx = norm.indexOf(ASTRO_JSON_END);
44
+ let baton_md = "";
45
+ let jsonRaw = "";
46
+ let fallbackUsed = false;
43
47
  if (beginIdx === -1 || endIdx === -1 || endIdx <= beginIdx) {
48
+ // Fallback: if no markers, check if the entire text is JSON
49
+ try {
50
+ const parsed = JSON.parse(norm);
51
+ const astroJson = AstroJsonSchema.parse(parsed);
52
+ debug("Used JSON fallback parsing (no markers found)", { stage_key: astroJson.stage_key });
53
+ return {
54
+ baton_md: "",
55
+ astro_json: astroJson,
56
+ astro_json_raw: norm,
57
+ error: null
58
+ };
59
+ }
60
+ catch (e) {
61
+ // Not JSON, proceed with marker error
62
+ }
44
63
  return {
45
64
  baton_md: norm,
46
65
  astro_json: null,
47
66
  astro_json_raw: null,
48
- error: `Missing ASTRO JSON markers. Expected markers ${ASTRO_JSON_BEGIN} ... ${ASTRO_JSON_END}`,
67
+ error: `Missing ASTRO JSON markers. Expected markers ${ASTRO_JSON_BEGIN} ... ${ASTRO_JSON_END}. If output is pure JSON, ensure it's wrapped in markers.`,
49
68
  };
50
69
  }
51
70
  const before = norm.slice(0, beginIdx).trim();
52
- const jsonRaw = norm.slice(beginIdx + ASTRO_JSON_BEGIN.length, endIdx).trim();
71
+ jsonRaw = norm.slice(beginIdx + ASTRO_JSON_BEGIN.length, endIdx).trim();
53
72
  const after = norm.slice(endIdx + ASTRO_JSON_END.length).trim();
54
- const baton = [before, after].filter(Boolean).join("\n\n").trim();
73
+ baton_md = [before, after].filter(Boolean).join("\n\n").trim();
55
74
  try {
56
75
  const cleaned = stripCodeFences(jsonRaw).trim();
57
76
  const parsed = JSON.parse(cleaned);
58
77
  const astroJson = AstroJsonSchema.parse(parsed);
59
- return { baton_md: baton, astro_json: astroJson, astro_json_raw: cleaned, error: null };
78
+ return { baton_md, astro_json: astroJson, astro_json_raw: cleaned, error: null };
60
79
  }
61
80
  catch (e) {
62
81
  if (e instanceof ZodError) {
63
82
  return {
64
- baton_md: baton,
83
+ baton_md,
65
84
  astro_json: null,
66
85
  astro_json_raw: jsonRaw,
67
86
  error: `Schema validation failed: ${e.message}. Ensure JSON conforms to ASTRO schema with required fields like stage_key, status, etc.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astrocode-workflow",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,18 +18,20 @@ Operating rules:
18
18
 
19
19
  export const BASE_STAGE_PROMPT = `You are an Astro stage subagent.
20
20
 
21
- Follow the latest [SYSTEM DIRECTIVE: ASTROCODE — STAGE_*] you receive.
21
+ ***CRITICAL: Follow the latest [SYSTEM DIRECTIVE: ASTROCODE — STAGE_*] you receive EXACTLY.***
22
22
 
23
- Output exactly in this order:
24
- 1) Baton markdown (short, structured narrative summary)
25
- 2) Valid ASTRO JSON between markers with ALL required fields (do not omit any):
23
+ Your output MUST be in this EXACT format (no deviations):
24
+
25
+ 1) First, a short baton markdown summary (1-3 sentences).
26
+
27
+ 2) Then, immediately after, the ASTRO JSON markers with valid JSON:
26
28
 
27
29
  <!-- ASTRO_JSON_BEGIN -->
28
30
  {
29
31
  "schema_version": 1,
30
32
  "stage_key": "CURRENT_STAGE",
31
33
  "status": "ok",
32
- "summary": "Brief summary of work done",
34
+ "summary": "Brief summary",
33
35
  "decisions": [],
34
36
  "next_actions": [],
35
37
  "tasks": [],
@@ -41,13 +43,13 @@ Output exactly in this order:
41
43
  }
42
44
  <!-- ASTRO_JSON_END -->
43
45
 
44
- CRITICAL REQUIREMENTS:
45
- - Include ALL fields shown above (even if empty arrays/objects)
46
- - stage_key must match the current stage exactly
47
- - status must be "ok", "blocked", or "failed"
48
- - summary must be a non-empty string describing the work
49
- - JSON must be valid syntax and parseable
50
- - Markers must be exact: <!-- ASTRO_JSON_BEGIN --> and <!-- ASTRO_JSON_END -->
46
+ MANDATORY RULES:
47
+ - ALL fields above MUST be present (use empty arrays/objects if no data)
48
+ - stage_key MUST be "CURRENT_STAGE" (will be replaced)
49
+ - status MUST be "ok" unless blocked/failed
50
+ - summary MUST be a string describing the work
51
+ - JSON MUST be valid and parseable
52
+ - Markers MUST be exact as shown
51
53
 
52
- Do not narrate extra text. If blocked, set status="blocked", ask exactly ONE question in questions array, and stop.
54
+ If blocked, set status="blocked" and put ONE question in questions array. Do not output anything else.
53
55
  `;
@@ -9,6 +9,7 @@ import { buildStageDirective, directiveHash } from "../workflow/directives";
9
9
  import { injectChatPrompt } from "../ui/inject";
10
10
  import { nowISO } from "../shared/time";
11
11
  import { newEventId } from "../state/ids";
12
+ import { debug } from "../shared/log";
12
13
  import { createToastManager } from "../ui/toasts";
13
14
 
14
15
  // Agent name mapping for case-sensitive resolution
@@ -79,7 +80,7 @@ function buildDelegationPrompt(opts: {
79
80
  const { stageDirective, run_id, stage_key, stage_agent_name } = opts;
80
81
  const stageUpper = stage_key.toUpperCase();
81
82
 
82
- return [
83
+ const prompt = [
83
84
  `[SYSTEM DIRECTIVE: ASTROCODE — DELEGATE_STAGE_${stageUpper}]`,
84
85
  ``,
85
86
  `Do this now, in order:`,
@@ -97,6 +98,11 @@ function buildDelegationPrompt(opts: {
97
98
  ``,
98
99
  `Important: do NOT do any stage work yourself in orchestrator mode.`,
99
100
  ].join("\n").trim();
101
+
102
+ // Debug log the delegation prompt to troubleshoot agent output issues
103
+ debug(`Delegating stage ${stage_key} to agent ${stage_agent_name}`, { prompt_length: prompt.length });
104
+
105
+ return prompt;
100
106
  }
101
107
 
102
108
  import { AgentConfig } from "@opencode-ai/sdk";
@@ -2,6 +2,7 @@ import { tool } from "@opencode-ai/plugin/tool";
2
2
  import type { AstrocodeConfig } from "../config/schema";
3
3
  import { clampLines, normalizeNewlines, stripCodeFences } from "../shared/text";
4
4
  import { z, ZodError } from "zod";
5
+ import { debug } from "../shared/log";
5
6
 
6
7
  export const ASTRO_JSON_BEGIN = "<!-- ASTRO_JSON_BEGIN -->";
7
8
  export const ASTRO_JSON_END = "<!-- ASTRO_JSON_END -->";
@@ -74,30 +75,49 @@ export function parseStageOutputText(text: string): ParsedStageOutput {
74
75
  const beginIdx = norm.indexOf(ASTRO_JSON_BEGIN);
75
76
  const endIdx = norm.indexOf(ASTRO_JSON_END);
76
77
 
78
+ let baton_md = "";
79
+ let jsonRaw = "";
80
+ let fallbackUsed = false;
81
+
77
82
  if (beginIdx === -1 || endIdx === -1 || endIdx <= beginIdx) {
83
+ // Fallback: if no markers, check if the entire text is JSON
84
+ try {
85
+ const parsed = JSON.parse(norm) as unknown;
86
+ const astroJson = AstroJsonSchema.parse(parsed);
87
+ debug("Used JSON fallback parsing (no markers found)", { stage_key: astroJson.stage_key });
88
+ return {
89
+ baton_md: "",
90
+ astro_json: astroJson,
91
+ astro_json_raw: norm,
92
+ error: null
93
+ };
94
+ } catch (e) {
95
+ // Not JSON, proceed with marker error
96
+ }
97
+
78
98
  return {
79
99
  baton_md: norm,
80
100
  astro_json: null,
81
101
  astro_json_raw: null,
82
- error: `Missing ASTRO JSON markers. Expected markers ${ASTRO_JSON_BEGIN} ... ${ASTRO_JSON_END}`,
102
+ error: `Missing ASTRO JSON markers. Expected markers ${ASTRO_JSON_BEGIN} ... ${ASTRO_JSON_END}. If output is pure JSON, ensure it's wrapped in markers.`,
83
103
  };
84
104
  }
85
105
 
86
106
  const before = norm.slice(0, beginIdx).trim();
87
- const jsonRaw = norm.slice(beginIdx + ASTRO_JSON_BEGIN.length, endIdx).trim();
107
+ jsonRaw = norm.slice(beginIdx + ASTRO_JSON_BEGIN.length, endIdx).trim();
88
108
  const after = norm.slice(endIdx + ASTRO_JSON_END.length).trim();
89
109
 
90
- const baton = [before, after].filter(Boolean).join("\n\n").trim();
110
+ baton_md = [before, after].filter(Boolean).join("\n\n").trim();
91
111
 
92
112
  try {
93
113
  const cleaned = stripCodeFences(jsonRaw).trim();
94
114
  const parsed = JSON.parse(cleaned) as unknown;
95
115
  const astroJson = AstroJsonSchema.parse(parsed);
96
- return { baton_md: baton, astro_json: astroJson, astro_json_raw: cleaned, error: null };
116
+ return { baton_md, astro_json: astroJson, astro_json_raw: cleaned, error: null };
97
117
  } catch (e) {
98
118
  if (e instanceof ZodError) {
99
119
  return {
100
- baton_md: baton,
120
+ baton_md,
101
121
  astro_json: null,
102
122
  astro_json_raw: jsonRaw,
103
123
  error: `Schema validation failed: ${e.message}. Ensure JSON conforms to ASTRO schema with required fields like stage_key, status, etc.`,