astrocode-workflow 0.1.20 → 0.1.24

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.
@@ -42,9 +42,21 @@ export function assertInsideAstro(repoRoot, filePath) {
42
42
  const absRepo = path.resolve(repoRoot);
43
43
  const abs = path.resolve(filePath);
44
44
  const astroRoot = path.resolve(path.join(repoRoot, ".astro"));
45
+ // Allow writing certain files in the repo root
46
+ const relPath = path.relative(repoRoot, filePath);
47
+ const allowedOutside = [
48
+ "stories.md",
49
+ "README.md",
50
+ "CHANGELOG.md",
51
+ "CONTRIBUTING.md",
52
+ "LICENSE",
53
+ ".gitignore"
54
+ ];
45
55
  if (!abs.startsWith(astroRoot + path.sep) && abs !== astroRoot) {
46
- const relPath = path.relative(repoRoot, filePath);
47
- throw new Error(`Refusing to write outside .astro: ${filePath} (relative: ${relPath}, astroRoot: ${astroRoot})`);
56
+ // Check if it's an allowed file in repo root
57
+ if (!allowedOutside.includes(relPath)) {
58
+ throw new Error(`Refusing to write outside .astro: ${filePath} (relative: ${relPath}, astroRoot: ${astroRoot})`);
59
+ }
48
60
  }
49
61
  if (!abs.startsWith(absRepo + path.sep) && abs !== absRepo) {
50
62
  throw new Error(`Refusing to write outside repo root: ${filePath}`);
@@ -154,16 +154,12 @@ export function createAstroWorkflowProceedTool(opts) {
154
154
  return false;
155
155
  };
156
156
  if (!agentExists(agentName)) {
157
- console.warn(`[Astrocode] Agent ${agentName} not found in config. Falling back to General.`);
157
+ console.warn(`[Astrocode] Agent ${agentName} not found in config. Falling back to orchestrator instead of General.`);
158
158
  console.warn(`[Astrocode] Agent check: config.agent exists: ${!!systemConfig.agent}, agentName in config: ${systemConfig.agent ? agentName in systemConfig.agent : 'N/A'}`);
159
- agentName = "General";
160
- // Second fallback to orchestrator if General also unavailable
159
+ // Skip General fallback for stage agents to avoid malformed output
160
+ agentName = config.agents?.orchestrator_name || "Astro";
161
161
  if (!agentExists(agentName)) {
162
- console.warn(`[Astrocode] General agent also unavailable. Falling back to orchestrator.`);
163
- agentName = config.agents?.orchestrator_name || "Astro";
164
- if (!agentExists(agentName)) {
165
- throw new Error(`Critical: No agents available for delegation. Primary: ${resolveAgentName(next.stage_key, config)}, General, Orchestrator: ${agentName}`);
166
- }
162
+ throw new Error(`Critical: No agents available for delegation. Primary: ${resolveAgentName(next.stage_key, config)}, Orchestrator: ${agentName}`);
167
163
  }
168
164
  }
169
165
  console.log(`[Astrocode] Delegating stage ${next.stage_key} to agent: ${agentName}`);
package/dist/ui/inject.js CHANGED
@@ -2,9 +2,11 @@ let isInjecting = false;
2
2
  let queuedInjection = null;
3
3
  export async function injectChatPrompt(opts) {
4
4
  const { ctx, sessionId, text } = opts;
5
+ // Prefix to clearly indicate source as Astro agent
6
+ const prefixedText = `[Astro Agent]\n\n${text}`;
5
7
  if (isInjecting) {
6
8
  // Replace any existing queued injection (keep only latest)
7
- queuedInjection = opts;
9
+ queuedInjection = { ...opts, text: prefixedText };
8
10
  return;
9
11
  }
10
12
  isInjecting = true;
@@ -12,7 +14,7 @@ export async function injectChatPrompt(opts) {
12
14
  await ctx.client.session.prompt({
13
15
  path: { id: sessionId },
14
16
  body: {
15
- parts: [{ type: "text", text }],
17
+ parts: [{ type: "text", text: prefixedText }],
16
18
  },
17
19
  });
18
20
  }
@@ -23,7 +25,7 @@ export async function injectChatPrompt(opts) {
23
25
  const next = queuedInjection;
24
26
  queuedInjection = null;
25
27
  // Schedule next injection asynchronously to prevent recursion
26
- setImmediate(() => injectChatPrompt(next));
28
+ setImmediate(() => injectChatPrompt({ ...queuedInjection, text: prefixedText }));
27
29
  }
28
30
  }
29
31
  }
@@ -10,6 +10,8 @@ export function buildContinueDirective(opts) {
10
10
  const body = clampChars(normalizeNewlines([
11
11
  `[SYSTEM DIRECTIVE: ASTROCODE — CONTINUE]`,
12
12
  ``,
13
+ `This directive is injected by the Astro agent to continue the workflow.`,
14
+ ``,
13
15
  `Run: \`${run_id}\`${stage_key ? ` Stage: \`${stage_key}\`` : ""}`,
14
16
  ``,
15
17
  `Next action: ${next_action}`,
@@ -34,6 +36,8 @@ export function buildBlockedDirective(opts) {
34
36
  const body = normalizeNewlines([
35
37
  `[SYSTEM DIRECTIVE: ASTROCODE — BLOCKED]`,
36
38
  ``,
39
+ `This directive is injected by the Astro agent indicating the workflow is blocked.`,
40
+ ``,
37
41
  `Run: \`${run_id}\` Stage: \`${stage_key}\``,
38
42
  ``,
39
43
  `You are blocked. Ask the user exactly ONE question (below), then stop.`,
@@ -54,6 +58,8 @@ export function buildRepairDirective(opts) {
54
58
  const body = normalizeNewlines([
55
59
  `[SYSTEM DIRECTIVE: ASTROCODE — REPAIR]`,
56
60
  ``,
61
+ `This directive is injected by the Astro agent after performing a repair pass.`,
62
+ ``,
57
63
  `Astrocode performed a repair pass. Summarize in <= 10 lines and continue.`,
58
64
  ``,
59
65
  `Repair report:`,
@@ -75,6 +81,8 @@ export function buildStageDirective(opts) {
75
81
  const body = clampChars(normalizeNewlines([
76
82
  `[SYSTEM DIRECTIVE: ASTROCODE — STAGE_${stageKeyUpper}]`,
77
83
  ``,
84
+ `This directive is injected by the Astro agent to delegate the stage task.`,
85
+ ``,
78
86
  `You are: \`${stage_agent_name}\``,
79
87
  `Run: \`${run_id}\``,
80
88
  `Story: \`${story_key}\` — ${story_title}`,
@@ -90,7 +98,6 @@ export function buildStageDirective(opts) {
90
98
  ` "schema_version": 1,`,
91
99
  ` "stage_key": "${stage_key}",`,
92
100
  ` "status": "ok",`,
93
- ` "summary": "Brief summary of work done",`,
94
101
  ` ...`,
95
102
  ` }`,
96
103
  ` ${"<!-- ASTRO_JSON_END -->"}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astrocode-workflow",
3
- "version": "0.1.20",
3
+ "version": "0.1.24",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -61,10 +61,25 @@ export function assertInsideAstro(repoRoot: string, filePath: string) {
61
61
  const absRepo = path.resolve(repoRoot);
62
62
  const abs = path.resolve(filePath);
63
63
  const astroRoot = path.resolve(path.join(repoRoot, ".astro"));
64
+
65
+ // Allow writing certain files in the repo root
66
+ const relPath = path.relative(repoRoot, filePath);
67
+ const allowedOutside = [
68
+ "stories.md",
69
+ "README.md",
70
+ "CHANGELOG.md",
71
+ "CONTRIBUTING.md",
72
+ "LICENSE",
73
+ ".gitignore"
74
+ ];
75
+
64
76
  if (!abs.startsWith(astroRoot + path.sep) && abs !== astroRoot) {
65
- const relPath = path.relative(repoRoot, filePath);
66
- throw new Error(`Refusing to write outside .astro: ${filePath} (relative: ${relPath}, astroRoot: ${astroRoot})`);
77
+ // Check if it's an allowed file in repo root
78
+ if (!allowedOutside.includes(relPath)) {
79
+ throw new Error(`Refusing to write outside .astro: ${filePath} (relative: ${relPath}, astroRoot: ${astroRoot})`);
80
+ }
67
81
  }
82
+
68
83
  if (!abs.startsWith(absRepo + path.sep) && abs !== absRepo) {
69
84
  throw new Error(`Refusing to write outside repo root: ${filePath}`);
70
85
  }
@@ -187,19 +187,15 @@ export function createAstroWorkflowProceedTool(opts: { ctx: any; config: Astroco
187
187
  return false;
188
188
  };
189
189
 
190
- if (!agentExists(agentName)) {
191
- console.warn(`[Astrocode] Agent ${agentName} not found in config. Falling back to General.`);
192
- console.warn(`[Astrocode] Agent check: config.agent exists: ${!!systemConfig.agent}, agentName in config: ${systemConfig.agent ? agentName in systemConfig.agent : 'N/A'}`);
193
- agentName = "General";
194
- // Second fallback to orchestrator if General also unavailable
195
- if (!agentExists(agentName)) {
196
- console.warn(`[Astrocode] General agent also unavailable. Falling back to orchestrator.`);
197
- agentName = config.agents?.orchestrator_name || "Astro";
198
- if (!agentExists(agentName)) {
199
- throw new Error(`Critical: No agents available for delegation. Primary: ${resolveAgentName(next.stage_key, config)}, General, Orchestrator: ${agentName}`);
200
- }
201
- }
202
- }
190
+ if (!agentExists(agentName)) {
191
+ console.warn(`[Astrocode] Agent ${agentName} not found in config. Falling back to orchestrator instead of General.`);
192
+ console.warn(`[Astrocode] Agent check: config.agent exists: ${!!systemConfig.agent}, agentName in config: ${systemConfig.agent ? agentName in systemConfig.agent : 'N/A'}`);
193
+ // Skip General fallback for stage agents to avoid malformed output
194
+ agentName = config.agents?.orchestrator_name || "Astro";
195
+ if (!agentExists(agentName)) {
196
+ throw new Error(`Critical: No agents available for delegation. Primary: ${resolveAgentName(next.stage_key, config)}, Orchestrator: ${agentName}`);
197
+ }
198
+ }
203
199
 
204
200
  console.log(`[Astrocode] Delegating stage ${next.stage_key} to agent: ${agentName}`);
205
201
 
package/src/ui/inject.ts CHANGED
@@ -8,9 +8,12 @@ export async function injectChatPrompt(opts: {
8
8
  }) {
9
9
  const { ctx, sessionId, text } = opts;
10
10
 
11
+ // Prefix to clearly indicate source as Astro agent
12
+ const prefixedText = `[Astro Agent]\n\n${text}`;
13
+
11
14
  if (isInjecting) {
12
15
  // Replace any existing queued injection (keep only latest)
13
- queuedInjection = opts;
16
+ queuedInjection = { ...opts, text: prefixedText };
14
17
  return;
15
18
  }
16
19
 
@@ -20,7 +23,7 @@ export async function injectChatPrompt(opts: {
20
23
  await ctx.client.session.prompt({
21
24
  path: { id: sessionId },
22
25
  body: {
23
- parts: [{ type: "text", text }],
26
+ parts: [{ type: "text", text: prefixedText }],
24
27
  },
25
28
  });
26
29
  } finally {
@@ -30,7 +33,7 @@ export async function injectChatPrompt(opts: {
30
33
  const next = queuedInjection;
31
34
  queuedInjection = null;
32
35
  // Schedule next injection asynchronously to prevent recursion
33
- setImmediate(() => injectChatPrompt(next));
36
+ setImmediate(() => injectChatPrompt({ ...queuedInjection, text: prefixedText }));
34
37
  }
35
38
  }
36
39
  }
@@ -32,6 +32,8 @@ export function buildContinueDirective(opts: {
32
32
  [
33
33
  `[SYSTEM DIRECTIVE: ASTROCODE — CONTINUE]`,
34
34
  ``,
35
+ `This directive is injected by the Astro agent to continue the workflow.`,
36
+ ``,
35
37
  `Run: \`${run_id}\`${stage_key ? ` Stage: \`${stage_key}\`` : ""}`,
36
38
  ``,
37
39
  `Next action: ${next_action}`,
@@ -67,6 +69,8 @@ export function buildBlockedDirective(opts: {
67
69
  [
68
70
  `[SYSTEM DIRECTIVE: ASTROCODE — BLOCKED]`,
69
71
  ``,
72
+ `This directive is injected by the Astro agent indicating the workflow is blocked.`,
73
+ ``,
70
74
  `Run: \`${run_id}\` Stage: \`${stage_key}\``,
71
75
  ``,
72
76
  `You are blocked. Ask the user exactly ONE question (below), then stop.`,
@@ -91,6 +95,8 @@ export function buildRepairDirective(opts: { report_md: string }): BuiltDirectiv
91
95
  [
92
96
  `[SYSTEM DIRECTIVE: ASTROCODE — REPAIR]`,
93
97
  ``,
98
+ `This directive is injected by the Astro agent after performing a repair pass.`,
99
+ ``,
94
100
  `Astrocode performed a repair pass. Summarize in <= 10 lines and continue.`,
95
101
  ``,
96
102
  `Repair report:`,
@@ -130,6 +136,8 @@ export function buildStageDirective(opts: {
130
136
  [
131
137
  `[SYSTEM DIRECTIVE: ASTROCODE — STAGE_${stageKeyUpper}]`,
132
138
  ``,
139
+ `This directive is injected by the Astro agent to delegate the stage task.`,
140
+ ``,
133
141
  `You are: \`${stage_agent_name}\``,
134
142
  `Run: \`${run_id}\``,
135
143
  `Story: \`${story_key}\` — ${story_title}`,
@@ -145,7 +153,6 @@ export function buildStageDirective(opts: {
145
153
  ` "schema_version": 1,`,
146
154
  ` "stage_key": "${stage_key}",`,
147
155
  ` "status": "ok",`,
148
- ` "summary": "Brief summary of work done",`,
149
156
  ` ...`,
150
157
  ` }`,
151
158
  ` ${"<!-- ASTRO_JSON_END -->"}`,