astrocode-workflow 0.4.0 → 0.4.1

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.
Files changed (147) hide show
  1. package/dist/index.js +6 -0
  2. package/dist/shared/metrics.d.ts +66 -0
  3. package/dist/shared/metrics.js +112 -0
  4. package/dist/src/agents/commands.d.ts +9 -0
  5. package/dist/src/agents/commands.js +121 -0
  6. package/dist/src/agents/prompts.d.ts +3 -0
  7. package/dist/src/agents/prompts.js +232 -0
  8. package/dist/src/agents/registry.d.ts +6 -0
  9. package/dist/src/agents/registry.js +242 -0
  10. package/dist/src/agents/types.d.ts +14 -0
  11. package/dist/src/agents/types.js +8 -0
  12. package/dist/src/astro/workflow-runner.d.ts +15 -0
  13. package/dist/src/astro/workflow-runner.js +25 -0
  14. package/dist/src/config/config-handler.d.ts +4 -0
  15. package/dist/src/config/config-handler.js +46 -0
  16. package/dist/src/config/defaults.d.ts +3 -0
  17. package/dist/src/config/defaults.js +3 -0
  18. package/dist/src/config/loader.d.ts +11 -0
  19. package/dist/src/config/loader.js +82 -0
  20. package/dist/src/config/schema.d.ts +195 -0
  21. package/dist/src/config/schema.js +224 -0
  22. package/dist/src/hooks/continuation-enforcer.d.ts +34 -0
  23. package/dist/src/hooks/continuation-enforcer.js +190 -0
  24. package/dist/src/hooks/inject-provider.d.ts +27 -0
  25. package/dist/src/hooks/inject-provider.js +189 -0
  26. package/dist/src/hooks/tool-output-truncator.d.ts +25 -0
  27. package/dist/src/hooks/tool-output-truncator.js +57 -0
  28. package/dist/src/index.d.ts +3 -0
  29. package/dist/src/index.js +313 -0
  30. package/dist/src/shared/deep-merge.d.ts +8 -0
  31. package/dist/src/shared/deep-merge.js +25 -0
  32. package/dist/src/shared/hash.d.ts +1 -0
  33. package/dist/src/shared/hash.js +4 -0
  34. package/dist/src/shared/log.d.ts +7 -0
  35. package/dist/src/shared/log.js +24 -0
  36. package/dist/src/shared/metrics.d.ts +66 -0
  37. package/dist/src/shared/metrics.js +112 -0
  38. package/dist/src/shared/model-tuning.d.ts +9 -0
  39. package/dist/src/shared/model-tuning.js +28 -0
  40. package/dist/src/shared/paths.d.ts +19 -0
  41. package/dist/src/shared/paths.js +64 -0
  42. package/dist/src/shared/text.d.ts +4 -0
  43. package/dist/src/shared/text.js +19 -0
  44. package/dist/src/shared/time.d.ts +1 -0
  45. package/dist/src/shared/time.js +3 -0
  46. package/dist/src/state/adapters/index.d.ts +41 -0
  47. package/dist/src/state/adapters/index.js +115 -0
  48. package/dist/src/state/db.d.ts +16 -0
  49. package/dist/src/state/db.js +225 -0
  50. package/dist/src/state/ids.d.ts +8 -0
  51. package/dist/src/state/ids.js +25 -0
  52. package/dist/src/state/repo-lock.d.ts +67 -0
  53. package/dist/src/state/repo-lock.js +580 -0
  54. package/dist/src/state/schema.d.ts +2 -0
  55. package/dist/src/state/schema.js +258 -0
  56. package/dist/src/state/types.d.ts +71 -0
  57. package/dist/src/state/types.js +1 -0
  58. package/dist/src/state/workflow-repo-lock.d.ts +23 -0
  59. package/dist/src/state/workflow-repo-lock.js +83 -0
  60. package/dist/src/tools/artifacts.d.ts +18 -0
  61. package/dist/src/tools/artifacts.js +71 -0
  62. package/dist/src/tools/health.d.ts +8 -0
  63. package/dist/src/tools/health.js +119 -0
  64. package/dist/src/tools/index.d.ts +20 -0
  65. package/dist/src/tools/index.js +97 -0
  66. package/dist/src/tools/init.d.ts +17 -0
  67. package/dist/src/tools/init.js +96 -0
  68. package/dist/src/tools/injects.d.ts +53 -0
  69. package/dist/src/tools/injects.js +325 -0
  70. package/dist/src/tools/lock.d.ts +4 -0
  71. package/dist/src/tools/lock.js +78 -0
  72. package/dist/src/tools/metrics.d.ts +7 -0
  73. package/dist/src/tools/metrics.js +61 -0
  74. package/dist/src/tools/repair.d.ts +8 -0
  75. package/dist/src/tools/repair.js +59 -0
  76. package/dist/src/tools/reset.d.ts +8 -0
  77. package/dist/src/tools/reset.js +92 -0
  78. package/dist/src/tools/run.d.ts +13 -0
  79. package/dist/src/tools/run.js +54 -0
  80. package/dist/src/tools/spec.d.ts +12 -0
  81. package/dist/src/tools/spec.js +44 -0
  82. package/dist/src/tools/stage.d.ts +23 -0
  83. package/dist/src/tools/stage.js +371 -0
  84. package/dist/src/tools/status.d.ts +8 -0
  85. package/dist/src/tools/status.js +125 -0
  86. package/dist/src/tools/story.d.ts +23 -0
  87. package/dist/src/tools/story.js +85 -0
  88. package/dist/src/tools/workflow.d.ts +13 -0
  89. package/dist/src/tools/workflow.js +359 -0
  90. package/dist/src/ui/inject.d.ts +12 -0
  91. package/dist/src/ui/inject.js +107 -0
  92. package/dist/src/ui/toasts.d.ts +13 -0
  93. package/dist/src/ui/toasts.js +39 -0
  94. package/dist/src/workflow/artifacts.d.ts +24 -0
  95. package/dist/src/workflow/artifacts.js +45 -0
  96. package/dist/src/workflow/baton.d.ts +72 -0
  97. package/dist/src/workflow/baton.js +166 -0
  98. package/dist/src/workflow/context.d.ts +20 -0
  99. package/dist/src/workflow/context.js +113 -0
  100. package/dist/src/workflow/directives.d.ts +39 -0
  101. package/dist/src/workflow/directives.js +137 -0
  102. package/dist/src/workflow/repair.d.ts +8 -0
  103. package/dist/src/workflow/repair.js +99 -0
  104. package/dist/src/workflow/state-machine.d.ts +86 -0
  105. package/dist/src/workflow/state-machine.js +216 -0
  106. package/dist/src/workflow/story-helpers.d.ts +9 -0
  107. package/dist/src/workflow/story-helpers.js +13 -0
  108. package/dist/state/db.d.ts +1 -0
  109. package/dist/state/db.js +9 -0
  110. package/dist/state/repo-lock.d.ts +3 -0
  111. package/dist/state/repo-lock.js +29 -0
  112. package/dist/test/integration/db-transactions.test.d.ts +1 -0
  113. package/dist/test/integration/db-transactions.test.js +126 -0
  114. package/dist/test/integration/injection-metrics.test.d.ts +1 -0
  115. package/dist/test/integration/injection-metrics.test.js +129 -0
  116. package/dist/tools/health.d.ts +8 -0
  117. package/dist/tools/health.js +119 -0
  118. package/dist/tools/index.js +9 -0
  119. package/dist/tools/metrics.d.ts +7 -0
  120. package/dist/tools/metrics.js +61 -0
  121. package/dist/tools/reset.d.ts +8 -0
  122. package/dist/tools/reset.js +92 -0
  123. package/dist/tools/workflow.js +178 -168
  124. package/dist/ui/inject.js +21 -9
  125. package/package.json +6 -4
  126. package/src/astro/workflow-runner.ts +36 -0
  127. package/src/config/schema.ts +1 -0
  128. package/src/hooks/inject-provider.ts +94 -14
  129. package/src/index.ts +14 -0
  130. package/src/shared/metrics.ts +148 -0
  131. package/src/state/db.ts +10 -1
  132. package/src/state/repo-lock.ts +706 -0
  133. package/src/state/schema.ts +8 -1
  134. package/src/state/workflow-repo-lock.ts +111 -0
  135. package/src/tools/health.ts +128 -0
  136. package/src/tools/index.ts +15 -3
  137. package/src/tools/init.ts +7 -6
  138. package/src/tools/lock.ts +75 -0
  139. package/src/tools/metrics.ts +71 -0
  140. package/src/tools/repair.ts +44 -6
  141. package/src/tools/reset.ts +100 -0
  142. package/src/tools/stage.ts +1 -0
  143. package/src/tools/status.ts +2 -1
  144. package/src/tools/story.ts +1 -0
  145. package/src/tools/workflow.ts +19 -1
  146. package/src/ui/inject.ts +21 -9
  147. package/src/workflow/repair.ts +2 -2
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { createInjectProvider } from "./hooks/inject-provider";
9
9
  import { createToastManager } from "./ui/toasts";
10
10
  import { createAstroAgents } from "./agents/registry";
11
11
  import { info, warn } from "./shared/log";
12
+ import { acquireRepoLock } from "./state/repo-lock";
12
13
  // Safe config cloning with structuredClone preference (fallback for older Node versions)
13
14
  // CONTRACT: Config is guaranteed JSON-serializable (enforced by loadAstrocodeConfig validation)
14
15
  const cloneConfig = (v) => {
@@ -37,6 +38,9 @@ const Astrocode = async (ctx) => {
37
38
  throw new Error("Astrocode requires ctx.directory to be a string repo root.");
38
39
  }
39
40
  const repoRoot = ctx.directory;
41
+ // Acquire exclusive repo lock to prevent multiple processes from corrupting the database
42
+ const lockPath = `${repoRoot}/.astro/astro.lock`;
43
+ const repoLock = acquireRepoLock(lockPath);
40
44
  // Always load config first - this provides defaults even in limited mode
41
45
  let pluginConfig;
42
46
  try {
@@ -280,6 +284,8 @@ const Astrocode = async (ctx) => {
280
284
  },
281
285
  // Best-effort cleanup
282
286
  close: async () => {
287
+ // Release repo lock first (important for process termination)
288
+ repoLock.release();
283
289
  if (db && typeof db.close === "function") {
284
290
  try {
285
291
  db.close();
@@ -0,0 +1,66 @@
1
+ export interface TransactionMetrics {
2
+ startTime: number;
3
+ duration: number;
4
+ success: boolean;
5
+ nestedDepth: number;
6
+ operation?: string;
7
+ }
8
+ export interface InjectionMetrics {
9
+ sessionId: string;
10
+ attempts: number;
11
+ duration: number;
12
+ success: boolean;
13
+ agent?: string;
14
+ }
15
+ export interface SystemMetrics {
16
+ transactions: TransactionMetrics[];
17
+ injections: InjectionMetrics[];
18
+ errors: Array<{
19
+ type: string;
20
+ message: string;
21
+ timestamp: number;
22
+ }>;
23
+ }
24
+ declare class MetricsCollector {
25
+ private transactions;
26
+ private injections;
27
+ private errors;
28
+ private maxEntries;
29
+ recordTransaction(metrics: TransactionMetrics): void;
30
+ recordInjection(metrics: InjectionMetrics): void;
31
+ recordError(type: string, message: string): void;
32
+ getMetrics(): SystemMetrics;
33
+ getTransactionStats(): {
34
+ total: number;
35
+ successful: number;
36
+ failed: number;
37
+ successRate: number;
38
+ avgDuration: number;
39
+ avgNestedDepth: number;
40
+ minDuration: number;
41
+ maxDuration: number;
42
+ };
43
+ getInjectionStats(): {
44
+ total: number;
45
+ successful: number;
46
+ failed: number;
47
+ successRate: number;
48
+ avgAttempts: number;
49
+ avgDuration: number;
50
+ totalRetries: number;
51
+ };
52
+ clear(): void;
53
+ }
54
+ export declare const metrics: MetricsCollector;
55
+ export declare function recordTransaction(metricsData: Omit<TransactionMetrics, 'startTime' | 'duration' | 'success'>): any;
56
+ export declare function recordInjection(metricsData: Omit<InjectionMetrics, 'duration' | 'success'>): {
57
+ start(): {
58
+ startTime: number;
59
+ agent?: string;
60
+ sessionId: string;
61
+ attempts: number;
62
+ };
63
+ end(startData: any, success: boolean): void;
64
+ };
65
+ export declare function recordError(type: string, message: string): void;
66
+ export {};
@@ -0,0 +1,112 @@
1
+ // src/shared/metrics.ts
2
+ class MetricsCollector {
3
+ transactions = [];
4
+ injections = [];
5
+ errors = [];
6
+ maxEntries = 1000; // Keep last 1000 entries per type
7
+ recordTransaction(metrics) {
8
+ this.transactions.push(metrics);
9
+ if (this.transactions.length > this.maxEntries) {
10
+ this.transactions.shift();
11
+ }
12
+ }
13
+ recordInjection(metrics) {
14
+ this.injections.push(metrics);
15
+ if (this.injections.length > this.maxEntries) {
16
+ this.injections.shift();
17
+ }
18
+ }
19
+ recordError(type, message) {
20
+ this.errors.push({ type, message, timestamp: Date.now() });
21
+ if (this.errors.length > this.maxEntries) {
22
+ this.errors.shift();
23
+ }
24
+ }
25
+ getMetrics() {
26
+ return {
27
+ transactions: [...this.transactions],
28
+ injections: [...this.injections],
29
+ errors: [...this.errors],
30
+ };
31
+ }
32
+ getTransactionStats() {
33
+ const txs = this.transactions;
34
+ if (txs.length === 0)
35
+ return null;
36
+ const successful = txs.filter(t => t.success);
37
+ const failed = txs.filter(t => !t.success);
38
+ return {
39
+ total: txs.length,
40
+ successful: successful.length,
41
+ failed: failed.length,
42
+ successRate: successful.length / txs.length,
43
+ avgDuration: txs.reduce((sum, t) => sum + t.duration, 0) / txs.length,
44
+ avgNestedDepth: txs.reduce((sum, t) => sum + t.nestedDepth, 0) / txs.length,
45
+ minDuration: Math.min(...txs.map(t => t.duration)),
46
+ maxDuration: Math.max(...txs.map(t => t.duration)),
47
+ };
48
+ }
49
+ getInjectionStats() {
50
+ const injections = this.injections;
51
+ if (injections.length === 0)
52
+ return null;
53
+ const successful = injections.filter(i => i.success);
54
+ const failed = injections.filter(i => !i.success);
55
+ return {
56
+ total: injections.length,
57
+ successful: successful.length,
58
+ failed: failed.length,
59
+ successRate: successful.length / injections.length,
60
+ avgAttempts: injections.reduce((sum, i) => sum + i.attempts, 0) / injections.length,
61
+ avgDuration: injections.reduce((sum, i) => sum + i.duration, 0) / injections.length,
62
+ totalRetries: injections.reduce((sum, i) => sum + Math.max(0, i.attempts - 1), 0),
63
+ };
64
+ }
65
+ clear() {
66
+ this.transactions = [];
67
+ this.injections = [];
68
+ this.errors = [];
69
+ }
70
+ }
71
+ // Global singleton
72
+ export const metrics = new MetricsCollector();
73
+ // Convenience functions
74
+ export function recordTransaction(metricsData) {
75
+ return {
76
+ start() {
77
+ return {
78
+ ...metricsData,
79
+ startTime: Date.now(),
80
+ };
81
+ },
82
+ end(startData, success) {
83
+ const duration = Date.now() - startData.startTime;
84
+ metrics.recordTransaction({
85
+ ...startData,
86
+ duration,
87
+ success,
88
+ });
89
+ },
90
+ };
91
+ }
92
+ export function recordInjection(metricsData) {
93
+ return {
94
+ start() {
95
+ return {
96
+ ...metricsData,
97
+ startTime: Date.now(),
98
+ };
99
+ },
100
+ end(startData, success) {
101
+ const duration = Date.now() - startData.startTime;
102
+ metrics.recordInjection({
103
+ ...startData,
104
+ duration,
105
+ success,
106
+ });
107
+ },
108
+ };
109
+ }
110
+ export function recordError(type, message) {
111
+ metrics.recordError(type, message);
112
+ }
@@ -0,0 +1,9 @@
1
+ import type { AstrocodeConfig } from "../config/schema";
2
+ export type CommandDefinition = {
3
+ description: string;
4
+ template: string;
5
+ argumentHint?: string;
6
+ };
7
+ export declare function createAstroCommands(_opts: {
8
+ pluginConfig: AstrocodeConfig;
9
+ }): Record<string, CommandDefinition>;
@@ -0,0 +1,121 @@
1
+ export function createAstroCommands(_opts) {
2
+ // Keep templates very short: they just steer toward tools.
3
+ return {
4
+ "astro": {
5
+ description: "Astrocode help.",
6
+ argumentHint: "",
7
+ template: `<command-instruction>
8
+ You are using Astrocode vNext.
9
+ Show a short help message with the key commands:
10
+ - /astro-status
11
+ - /astro-init
12
+ - /astro-queue \"title\" --body=\"...\"
13
+ - /astro-approve S-123
14
+ - /astro-next
15
+ - /astro-loop --max-steps=50
16
+ - /astro-repair
17
+ </command-instruction>
18
+
19
+ <user-task>
20
+ $ARGUMENTS
21
+ </user-task>`,
22
+ },
23
+ "astro-status": {
24
+ description: "Show Astrocode status: current run, stage, blockers, next action.",
25
+ argumentHint: "",
26
+ template: `<command-instruction>
27
+ Call tool astro_status.
28
+ Return a compact dashboard.
29
+ </command-instruction>
30
+
31
+ <user-task>
32
+ $ARGUMENTS
33
+ </user-task>`,
34
+ },
35
+ "astro-init": {
36
+ description: "Initialize Astrocode (.astro directory + SQLite DB).",
37
+ argumentHint: "",
38
+ template: `<command-instruction>
39
+ Call tool astro_init.
40
+ Then call astro_status.
41
+ </command-instruction>
42
+
43
+ <user-task>
44
+ $ARGUMENTS
45
+ </user-task>`,
46
+ },
47
+ "astro-queue": {
48
+ description: "Create a queued story.",
49
+ argumentHint: "\"title\" --body=\"...\" --priority=50",
50
+ template: `<command-instruction>
51
+ Create a story using astro_story_queue.
52
+ Title is required. Body optional.
53
+ Return story_key.
54
+ </command-instruction>
55
+
56
+ <user-task>
57
+ $ARGUMENTS
58
+ </user-task>`,
59
+ },
60
+ "astro-approve": {
61
+ description: "Approve a story so it can be run.",
62
+ argumentHint: "S-123",
63
+ template: `<command-instruction>
64
+ Call astro_story_approve with story_key.
65
+ Then call astro_status.
66
+ </command-instruction>
67
+
68
+ <user-task>
69
+ $ARGUMENTS
70
+ </user-task>`,
71
+ },
72
+ "astro-next": {
73
+ description: "Advance Astrocode by one deterministic step.",
74
+ argumentHint: "",
75
+ template: `<command-instruction>
76
+ Call tool astro_workflow_proceed with mode=step.
77
+ If it injects a CONTINUE directive, obey it.
78
+ </command-instruction>
79
+
80
+ <user-task>
81
+ $ARGUMENTS
82
+ </user-task>`,
83
+ },
84
+ "astro-loop": {
85
+ description: "Run Astrocode loop for N steps (bounded).",
86
+ argumentHint: "--max-steps=N",
87
+ template: `<command-instruction>
88
+ Parse --max-steps (default 50).
89
+ Call tool astro_workflow_proceed with mode=loop and max_steps.
90
+ Stop if blocked.
91
+ </command-instruction>
92
+
93
+ <user-task>
94
+ $ARGUMENTS
95
+ </user-task>`,
96
+ },
97
+ "astro-repair": {
98
+ description: "Repair invariants / recover from inconsistent state.",
99
+ argumentHint: "",
100
+ template: `<command-instruction>
101
+ Call astro_repair.
102
+ Return repair report summary + pointers.
103
+ </command-instruction>
104
+
105
+ <user-task>
106
+ $ARGUMENTS
107
+ </user-task>`,
108
+ },
109
+ "astro-board": {
110
+ description: "Show story board grouped by state.",
111
+ argumentHint: "",
112
+ template: `<command-instruction>
113
+ Call astro_story_board.
114
+ </command-instruction>
115
+
116
+ <user-task>
117
+ $ARGUMENTS
118
+ </user-task>`,
119
+ },
120
+ };
121
+ }
@@ -0,0 +1,3 @@
1
+ export declare const BASE_ORCH_PROMPT = "You are Astro (Orchestrator) for Astrocode.\n\n Mission:\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\n Operating 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 - Follow [SYSTEM DIRECTIVE: ASTROCODE \u2014 CONTINUE] by calling astro_workflow_proceed(mode=\"step\", max_steps=1).\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\n***CRITICAL: Follow the latest [SYSTEM DIRECTIVE: ASTROCODE \u2014 STAGE_*] you receive EXACTLY.***\n\nYour output MUST be in this EXACT format:\n\n1) First, a short summary paragraph (1-3 sentences).\n\n2) Then, immediately after, the ASTRO JSON between markers:\n\n<!-- ASTRO_JSON_BEGIN -->\n{\n \"stage_key\": \"CURRENT_STAGE\",\n \"status\": \"ok\",\n \"summary\": \"Brief summary of work done\",\n \"tasks\": [],\n \"files\": [],\n \"questions\": []\n}\n<!-- ASTRO_JSON_END -->\n\nMANDATORY:\n- stage_key must be \"CURRENT_STAGE\"\n- status must be \"ok\", \"blocked\", or \"failed\"\n- summary must be a non-empty string\n- tasks, files, questions must be ARRAYS (use [] for empty)\n- JSON must be valid syntax\n- Use exact markers shown above\n\nARRAY FORMAT EXAMPLES:\n- tasks: [{\"title\": \"Task name\", \"complexity\": 3}]\n- files: [{\"path\": \"file.js\", \"kind\": \"file\"}]\n- questions: [\"What framework to use?\"]\n\nEXAMPLE OUTPUT:\nI analyzed the requirements and identified key components for implementation.\n\n<!-- ASTRO_JSON_BEGIN -->\n{\n \"stage_key\": \"plan\",\n \"status\": \"ok\",\n \"summary\": \"Created implementation plan with 5 main tasks\",\n \"tasks\": [\n {\"title\": \"Setup database\", \"complexity\": 3},\n {\"title\": \"Build API endpoints\", \"complexity\": 5}\n ],\n \"files\": [\n {\"path\": \"schema.prisma\", \"kind\": \"file\"}\n ],\n \"questions\": []\n}\n<!-- ASTRO_JSON_END -->\n\nIf blocked, set status=\"blocked\" and add ONE question to questions array. Do not deviate from this format.\n";
3
+ export declare const QA_AGENT_PROMPT = "\uD83C\uDF0D Global Engineering Review Prompt (LOCKED)\n\nUse this prompt when reviewing any codebase.\n\n1\uFE0F\u20E3 How every file review starts (MANDATORY)\n\nBefore discussing details, always answer:\n\nSimple question this file answers\n\nWhat decision, contract, or responsibility does this file define?\n\nThings you have at the end of running this code\n\nWhat objects, capabilities, state, guarantees, or invariants now exist?\n\nIf you can't answer these clearly, the file is already suspect.\n\n2\uFE0F\u20E3 Canonical RULE set (GLOBAL ENGINEERING INVARIANTS)\n\nThese are engineering physics laws.\nEvery serious bug maps to one of these.\nNo ad-hoc rules are allowed.\n\nenum RULE {\n CAPABILITY_GUARANTEE =\n \"Expose a capability only when you can guarantee it will execute safely under current runtime conditions.\",\n\n RECOVERY_STRICTER =\n \"Recovery/degraded paths must be simpler and more conservative than the normal path, and must not introduce new failure modes.\",\n\n SOURCE_OF_TRUTH =\n \"For any piece of state, define exactly one authoritative source and explicit precedence rules for any mirrors, caches, or derivations.\",\n\n LIFECYCLE_DETERMINISM =\n \"Initialization and lifecycle must be deterministic: single construction, stable ordering, controlled side effects, and repeatable outcomes.\",\n\n SECURITY_BOUNDARIES =\n \"Security, authorization, and trust boundaries must be explicit, enforced, and never inferred implicitly.\"\n}\n\nIf an issue does not violate one of these rules, it is not a P0/P1 blocker.\n\n3\uFE0F\u20E3 Severity model (WHAT \"P\" MEANS)\n\nSeverity is about trust, not annoyance.\n\nP0 \u2014 Trust break\n\nUnsafe execution\n\nCorrupted or ambiguous state\n\nNon-deterministic lifecycle\n\nBroken auditability / resumability\n\nSecurity boundary violations\n\nP1 \u2014 Reliability break\n\nRuntime crashes after successful boot\n\nCapabilities exposed but unusable\n\nDegraded mode that lies or half-works\n\nRecovery paths that add fragility\n\nP2 \u2014 Quality / polish\n\nReadability, ergonomics, maintainability\n\nNo RULE violated\n\n4\uFE0F\u20E3 Mandatory P0 / P1 Blocker Format (STRICT)\n\nEvery P0 / P1 must be written exactly like this:\n\nP{0|1} \u2014 <short human title>\n\nRule: RULE.<ONE_ENUM_VALUE>\n\nDescription:\nA human-readable explanation of how this specific code violates the rule in context.\nThis is situational and concrete \u2014 not a rule.\n\nWhat:\nThe exact defect or unsafe behavior.\n\nWhere:\nPrecise file + function + construct / lines.\n\nProposed fix:\nThe smallest possible change that restores the rule.\n(Code snippets if helpful.)\n\nWhy:\nHow this fix restores the invariant and what class of failures it prevents.\n\n5\uFE0F\u20E3 Recovery / Degraded Mode Lens (AUTO-APPLIED)\n\nWhenever code introduces:\n\nlimited mode\n\nfallback\n\ncatch-based recovery\n\npartial initialization\n\nAutomatically evaluate against:\n\nRULE.RECOVERY_STRICTER\n\nRULE.CAPABILITY_GUARANTEE\n\nRULE.LIFECYCLE_DETERMINISM\n\nIf recovery adds logic, validation, or ambiguity \u2192 it is a blocker.\n\nRecovery must:\n\nreduce capability surface\n\nfail earlier, not later\n\nbe simpler than the normal path\n\nprovide a clear path back to normal\n\n6\uFE0F\u20E3 How to ask for the next file (TEACHING MODE)\n\nBefore asking for the next file, always explain:\n\nWhat this next file likely does (human-readable)\n\n\"This file takes X, registers it with Y, then enforces Z...\"\n\nWhy this file matters next\n\nWhich RULE it is likely to uphold or violate, and why reviewing it now reduces risk.\n\n7\uFE0F\u20E3 What this frame teaches over time\n\nAfter repeated use, you stop seeing \"random bugs\" and start seeing patterns:\n\nCAPABILITY_GUARANTEE violations (exposed but unsafe APIs)\n\nRECOVERY_STRICTER violations (clever fallbacks that explode)\n\nSOURCE_OF_TRUTH drift (DB vs disk vs memory)\n\nLIFECYCLE_DETERMINISM failures (double init, racey wiring)\n\nSECURITY_BOUNDARIES leaks (implicit trust)\n\nAt that point, reviews become portable skills, not project-specific knowledge.";
@@ -0,0 +1,232 @@
1
+ export const BASE_ORCH_PROMPT = `You are Astro (Orchestrator) for Astrocode.
2
+
3
+ Mission:
4
+ - Advance a deterministic pipeline: frame → plan → spec → implement → review → verify → close.
5
+ - The SQLite DB is the source of truth. Prefer tools over prose.
6
+ - Never narrate what prompts you received.
7
+ - Keep outputs short; store large outputs as artifacts and reference paths.
8
+
9
+ Operating rules:
10
+ - Only start new runs when the user explicitly requests implementation, workflow management, or story processing.
11
+ - Answer questions directly when possible without starting workflows.
12
+ - Prefer calling astro_workflow_proceed (step/loop) and astro_status only when actively managing a workflow.
13
+ - Delegate stage work only to the stage subagent matching the current stage.
14
+ - If a stage subagent returns status=blocked, inject the BLOCKED directive and stop.
15
+ - Follow [SYSTEM DIRECTIVE: ASTROCODE — CONTINUE] by calling astro_workflow_proceed(mode="step", max_steps=1).
16
+ - Never delegate from subagents (enforced by permissions).
17
+ - Be discretionary: assess if the user's request requires workflow initiation or just information.
18
+ `;
19
+ export const BASE_STAGE_PROMPT = `You are an Astro stage subagent.
20
+
21
+ ***CRITICAL: Follow the latest [SYSTEM DIRECTIVE: ASTROCODE — STAGE_*] you receive EXACTLY.***
22
+
23
+ Your output MUST be in this EXACT format:
24
+
25
+ 1) First, a short summary paragraph (1-3 sentences).
26
+
27
+ 2) Then, immediately after, the ASTRO JSON between markers:
28
+
29
+ <!-- ASTRO_JSON_BEGIN -->
30
+ {
31
+ "stage_key": "CURRENT_STAGE",
32
+ "status": "ok",
33
+ "summary": "Brief summary of work done",
34
+ "tasks": [],
35
+ "files": [],
36
+ "questions": []
37
+ }
38
+ <!-- ASTRO_JSON_END -->
39
+
40
+ MANDATORY:
41
+ - stage_key must be "CURRENT_STAGE"
42
+ - status must be "ok", "blocked", or "failed"
43
+ - summary must be a non-empty string
44
+ - tasks, files, questions must be ARRAYS (use [] for empty)
45
+ - JSON must be valid syntax
46
+ - Use exact markers shown above
47
+
48
+ ARRAY FORMAT EXAMPLES:
49
+ - tasks: [{"title": "Task name", "complexity": 3}]
50
+ - files: [{"path": "file.js", "kind": "file"}]
51
+ - questions: ["What framework to use?"]
52
+
53
+ EXAMPLE OUTPUT:
54
+ I analyzed the requirements and identified key components for implementation.
55
+
56
+ <!-- ASTRO_JSON_BEGIN -->
57
+ {
58
+ "stage_key": "plan",
59
+ "status": "ok",
60
+ "summary": "Created implementation plan with 5 main tasks",
61
+ "tasks": [
62
+ {"title": "Setup database", "complexity": 3},
63
+ {"title": "Build API endpoints", "complexity": 5}
64
+ ],
65
+ "files": [
66
+ {"path": "schema.prisma", "kind": "file"}
67
+ ],
68
+ "questions": []
69
+ }
70
+ <!-- ASTRO_JSON_END -->
71
+
72
+ If blocked, set status="blocked" and add ONE question to questions array. Do not deviate from this format.
73
+ `;
74
+ export const QA_AGENT_PROMPT = `🌍 Global Engineering Review Prompt (LOCKED)
75
+
76
+ Use this prompt when reviewing any codebase.
77
+
78
+ 1️⃣ How every file review starts (MANDATORY)
79
+
80
+ Before discussing details, always answer:
81
+
82
+ Simple question this file answers
83
+
84
+ What decision, contract, or responsibility does this file define?
85
+
86
+ Things you have at the end of running this code
87
+
88
+ What objects, capabilities, state, guarantees, or invariants now exist?
89
+
90
+ If you can't answer these clearly, the file is already suspect.
91
+
92
+ 2️⃣ Canonical RULE set (GLOBAL ENGINEERING INVARIANTS)
93
+
94
+ These are engineering physics laws.
95
+ Every serious bug maps to one of these.
96
+ No ad-hoc rules are allowed.
97
+
98
+ enum RULE {
99
+ CAPABILITY_GUARANTEE =
100
+ "Expose a capability only when you can guarantee it will execute safely under current runtime conditions.",
101
+
102
+ RECOVERY_STRICTER =
103
+ "Recovery/degraded paths must be simpler and more conservative than the normal path, and must not introduce new failure modes.",
104
+
105
+ SOURCE_OF_TRUTH =
106
+ "For any piece of state, define exactly one authoritative source and explicit precedence rules for any mirrors, caches, or derivations.",
107
+
108
+ LIFECYCLE_DETERMINISM =
109
+ "Initialization and lifecycle must be deterministic: single construction, stable ordering, controlled side effects, and repeatable outcomes.",
110
+
111
+ SECURITY_BOUNDARIES =
112
+ "Security, authorization, and trust boundaries must be explicit, enforced, and never inferred implicitly."
113
+ }
114
+
115
+ If an issue does not violate one of these rules, it is not a P0/P1 blocker.
116
+
117
+ 3️⃣ Severity model (WHAT "P" MEANS)
118
+
119
+ Severity is about trust, not annoyance.
120
+
121
+ P0 — Trust break
122
+
123
+ Unsafe execution
124
+
125
+ Corrupted or ambiguous state
126
+
127
+ Non-deterministic lifecycle
128
+
129
+ Broken auditability / resumability
130
+
131
+ Security boundary violations
132
+
133
+ P1 — Reliability break
134
+
135
+ Runtime crashes after successful boot
136
+
137
+ Capabilities exposed but unusable
138
+
139
+ Degraded mode that lies or half-works
140
+
141
+ Recovery paths that add fragility
142
+
143
+ P2 — Quality / polish
144
+
145
+ Readability, ergonomics, maintainability
146
+
147
+ No RULE violated
148
+
149
+ 4️⃣ Mandatory P0 / P1 Blocker Format (STRICT)
150
+
151
+ Every P0 / P1 must be written exactly like this:
152
+
153
+ P{0|1} — <short human title>
154
+
155
+ Rule: RULE.<ONE_ENUM_VALUE>
156
+
157
+ Description:
158
+ A human-readable explanation of how this specific code violates the rule in context.
159
+ This is situational and concrete — not a rule.
160
+
161
+ What:
162
+ The exact defect or unsafe behavior.
163
+
164
+ Where:
165
+ Precise file + function + construct / lines.
166
+
167
+ Proposed fix:
168
+ The smallest possible change that restores the rule.
169
+ (Code snippets if helpful.)
170
+
171
+ Why:
172
+ How this fix restores the invariant and what class of failures it prevents.
173
+
174
+ 5️⃣ Recovery / Degraded Mode Lens (AUTO-APPLIED)
175
+
176
+ Whenever code introduces:
177
+
178
+ limited mode
179
+
180
+ fallback
181
+
182
+ catch-based recovery
183
+
184
+ partial initialization
185
+
186
+ Automatically evaluate against:
187
+
188
+ RULE.RECOVERY_STRICTER
189
+
190
+ RULE.CAPABILITY_GUARANTEE
191
+
192
+ RULE.LIFECYCLE_DETERMINISM
193
+
194
+ If recovery adds logic, validation, or ambiguity → it is a blocker.
195
+
196
+ Recovery must:
197
+
198
+ reduce capability surface
199
+
200
+ fail earlier, not later
201
+
202
+ be simpler than the normal path
203
+
204
+ provide a clear path back to normal
205
+
206
+ 6️⃣ How to ask for the next file (TEACHING MODE)
207
+
208
+ Before asking for the next file, always explain:
209
+
210
+ What this next file likely does (human-readable)
211
+
212
+ "This file takes X, registers it with Y, then enforces Z..."
213
+
214
+ Why this file matters next
215
+
216
+ Which RULE it is likely to uphold or violate, and why reviewing it now reduces risk.
217
+
218
+ 7️⃣ What this frame teaches over time
219
+
220
+ After repeated use, you stop seeing "random bugs" and start seeing patterns:
221
+
222
+ CAPABILITY_GUARANTEE violations (exposed but unsafe APIs)
223
+
224
+ RECOVERY_STRICTER violations (clever fallbacks that explode)
225
+
226
+ SOURCE_OF_TRUTH drift (DB vs disk vs memory)
227
+
228
+ LIFECYCLE_DETERMINISM failures (double init, racey wiring)
229
+
230
+ SECURITY_BOUNDARIES leaks (implicit trust)
231
+
232
+ At that point, reviews become portable skills, not project-specific knowledge.`;
@@ -0,0 +1,6 @@
1
+ import type { AgentConfig } from "@opencode-ai/sdk";
2
+ import type { AstrocodeConfig } from "../config/schema";
3
+ export declare function createAstroAgents(opts: {
4
+ systemDefaultModel?: string;
5
+ pluginConfig: AstrocodeConfig;
6
+ }): Record<string, AgentConfig>;