astrocode-workflow 0.1.18 → 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.
- package/dist/agents/prompts.d.ts +1 -1
- package/dist/agents/prompts.js +24 -14
- package/dist/tools/stage.js +23 -1
- package/dist/tools/workflow.js +5 -1
- package/dist/workflow/baton.js +24 -5
- package/package.json +2 -2
- package/src/agents/prompts.ts +24 -14
- package/src/tools/stage.ts +23 -1
- package/src/tools/workflow.ts +7 -1
- package/src/workflow/baton.ts +25 -5
package/dist/agents/prompts.d.ts
CHANGED
|
@@ -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\
|
|
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";
|
package/dist/agents/prompts.js
CHANGED
|
@@ -17,28 +17,38 @@ 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
|
+
|
|
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:
|
|
21
27
|
|
|
22
|
-
Output exactly:
|
|
23
|
-
1) Baton markdown (short, structured)
|
|
24
|
-
2) Valid ASTRO JSON between markers with ALL required fields:
|
|
25
28
|
<!-- ASTRO_JSON_BEGIN -->
|
|
26
29
|
{
|
|
30
|
+
"schema_version": 1,
|
|
27
31
|
"stage_key": "CURRENT_STAGE",
|
|
28
32
|
"status": "ok",
|
|
29
|
-
"summary": "Brief summary
|
|
30
|
-
"decisions": [
|
|
31
|
-
"next_actions": [
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"new_stories": [
|
|
33
|
+
"summary": "Brief summary",
|
|
34
|
+
"decisions": [],
|
|
35
|
+
"next_actions": [],
|
|
36
|
+
"tasks": [],
|
|
37
|
+
"files": [],
|
|
38
|
+
"evidence": [],
|
|
39
|
+
"new_stories": [],
|
|
36
40
|
"questions": [],
|
|
37
|
-
"metrics": {
|
|
41
|
+
"metrics": {}
|
|
38
42
|
}
|
|
39
43
|
<!-- ASTRO_JSON_END -->
|
|
40
44
|
|
|
41
|
-
|
|
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
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
If blocked, set status="blocked" and put ONE question in questions array. Do not output anything else.
|
|
44
54
|
`;
|
package/dist/tools/stage.js
CHANGED
|
@@ -117,7 +117,29 @@ export function createAstroStageCompleteTool(opts) {
|
|
|
117
117
|
}
|
|
118
118
|
const parsed = parseStageOutputText(output_text);
|
|
119
119
|
if (parsed.error || !parsed.astro_json) {
|
|
120
|
-
return `❌ JSON Parse Error: ${parsed.error ?? "ASTRO JSON missing"}.
|
|
120
|
+
return `❌ JSON Parse Error: ${parsed.error ?? "ASTRO JSON missing"}.
|
|
121
|
+
|
|
122
|
+
Expected format:
|
|
123
|
+
1) Narrative summary (optional)
|
|
124
|
+
2) Valid JSON between markers:
|
|
125
|
+
<!-- ASTRO_JSON_BEGIN -->
|
|
126
|
+
{
|
|
127
|
+
"schema_version": 1,
|
|
128
|
+
"stage_key": "${sk}",
|
|
129
|
+
"status": "ok",
|
|
130
|
+
"summary": "Brief summary",
|
|
131
|
+
"decisions": [],
|
|
132
|
+
"next_actions": [],
|
|
133
|
+
"tasks": [],
|
|
134
|
+
"files": [],
|
|
135
|
+
"evidence": [],
|
|
136
|
+
"new_stories": [],
|
|
137
|
+
"questions": [],
|
|
138
|
+
"metrics": {}
|
|
139
|
+
}
|
|
140
|
+
<!-- ASTRO_JSON_END -->
|
|
141
|
+
|
|
142
|
+
Ensure JSON has required fields (stage_key, status) and valid syntax.`;
|
|
121
143
|
}
|
|
122
144
|
if (parsed.astro_json.stage_key !== sk) {
|
|
123
145
|
return `❌ Stage Key Mismatch: ASTRO JSON has stage_key="${parsed.astro_json.stage_key}" but expected "${sk}". Update the JSON to match the current stage.`;
|
package/dist/tools/workflow.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/dist/workflow/baton.js
CHANGED
|
@@ -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
|
-
|
|
71
|
+
jsonRaw = norm.slice(beginIdx + ASTRO_JSON_BEGIN.length, endIdx).trim();
|
|
53
72
|
const after = norm.slice(endIdx + ASTRO_JSON_END.length).trim();
|
|
54
|
-
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@opencode-ai/plugin": "^1.1.19",
|
|
20
20
|
"@opencode-ai/sdk": "^1.1.19",
|
|
21
|
-
"astrocode-workflow": "^0.1.
|
|
21
|
+
"astrocode-workflow": "^0.1.18",
|
|
22
22
|
"jsonc-parser": "^3.2.0",
|
|
23
23
|
"zod": "4.1.8"
|
|
24
24
|
},
|
package/src/agents/prompts.ts
CHANGED
|
@@ -18,28 +18,38 @@ 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
|
+
|
|
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:
|
|
22
28
|
|
|
23
|
-
Output exactly:
|
|
24
|
-
1) Baton markdown (short, structured)
|
|
25
|
-
2) Valid ASTRO JSON between markers with ALL required fields:
|
|
26
29
|
<!-- ASTRO_JSON_BEGIN -->
|
|
27
30
|
{
|
|
31
|
+
"schema_version": 1,
|
|
28
32
|
"stage_key": "CURRENT_STAGE",
|
|
29
33
|
"status": "ok",
|
|
30
|
-
"summary": "Brief summary
|
|
31
|
-
"decisions": [
|
|
32
|
-
"next_actions": [
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"new_stories": [
|
|
34
|
+
"summary": "Brief summary",
|
|
35
|
+
"decisions": [],
|
|
36
|
+
"next_actions": [],
|
|
37
|
+
"tasks": [],
|
|
38
|
+
"files": [],
|
|
39
|
+
"evidence": [],
|
|
40
|
+
"new_stories": [],
|
|
37
41
|
"questions": [],
|
|
38
|
-
"metrics": {
|
|
42
|
+
"metrics": {}
|
|
39
43
|
}
|
|
40
44
|
<!-- ASTRO_JSON_END -->
|
|
41
45
|
|
|
42
|
-
|
|
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
|
|
43
53
|
|
|
44
|
-
|
|
54
|
+
If blocked, set status="blocked" and put ONE question in questions array. Do not output anything else.
|
|
45
55
|
`;
|
package/src/tools/stage.ts
CHANGED
|
@@ -153,7 +153,29 @@ export function createAstroStageCompleteTool(opts: { ctx: any; config: Astrocode
|
|
|
153
153
|
|
|
154
154
|
const parsed = parseStageOutputText(output_text);
|
|
155
155
|
if (parsed.error || !parsed.astro_json) {
|
|
156
|
-
|
|
156
|
+
return `❌ JSON Parse Error: ${parsed.error ?? "ASTRO JSON missing"}.
|
|
157
|
+
|
|
158
|
+
Expected format:
|
|
159
|
+
1) Narrative summary (optional)
|
|
160
|
+
2) Valid JSON between markers:
|
|
161
|
+
<!-- ASTRO_JSON_BEGIN -->
|
|
162
|
+
{
|
|
163
|
+
"schema_version": 1,
|
|
164
|
+
"stage_key": "${sk}",
|
|
165
|
+
"status": "ok",
|
|
166
|
+
"summary": "Brief summary",
|
|
167
|
+
"decisions": [],
|
|
168
|
+
"next_actions": [],
|
|
169
|
+
"tasks": [],
|
|
170
|
+
"files": [],
|
|
171
|
+
"evidence": [],
|
|
172
|
+
"new_stories": [],
|
|
173
|
+
"questions": [],
|
|
174
|
+
"metrics": {}
|
|
175
|
+
}
|
|
176
|
+
<!-- ASTRO_JSON_END -->
|
|
177
|
+
|
|
178
|
+
Ensure JSON has required fields (stage_key, status) and valid syntax.`;
|
|
157
179
|
}
|
|
158
180
|
|
|
159
181
|
if (parsed.astro_json.stage_key !== sk) {
|
package/src/tools/workflow.ts
CHANGED
|
@@ -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
|
-
|
|
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";
|
package/src/workflow/baton.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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.`,
|