@bradtaylorsf/alpha-loop 1.0.0

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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +294 -0
  3. package/agents/implementer.md +30 -0
  4. package/agents/reviewer.md +29 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +57 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/auth.d.ts +1 -0
  9. package/dist/commands/auth.js +89 -0
  10. package/dist/commands/auth.js.map +1 -0
  11. package/dist/commands/history.d.ts +8 -0
  12. package/dist/commands/history.js +185 -0
  13. package/dist/commands/history.js.map +1 -0
  14. package/dist/commands/init.d.ts +1 -0
  15. package/dist/commands/init.js +241 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/commands/run.d.ts +15 -0
  18. package/dist/commands/run.js +321 -0
  19. package/dist/commands/run.js.map +1 -0
  20. package/dist/commands/scan.d.ts +1 -0
  21. package/dist/commands/scan.js +50 -0
  22. package/dist/commands/scan.js.map +1 -0
  23. package/dist/commands/sync.d.ts +20 -0
  24. package/dist/commands/sync.js +149 -0
  25. package/dist/commands/sync.js.map +1 -0
  26. package/dist/commands/vision.d.ts +1 -0
  27. package/dist/commands/vision.js +194 -0
  28. package/dist/commands/vision.js.map +1 -0
  29. package/dist/engine/agents.d.ts +41 -0
  30. package/dist/engine/agents.js +90 -0
  31. package/dist/engine/agents.js.map +1 -0
  32. package/dist/engine/config.d.ts +71 -0
  33. package/dist/engine/config.js +73 -0
  34. package/dist/engine/config.js.map +1 -0
  35. package/dist/engine/prerequisites.d.ts +34 -0
  36. package/dist/engine/prerequisites.js +90 -0
  37. package/dist/engine/prerequisites.js.map +1 -0
  38. package/dist/lib/agent.d.ts +25 -0
  39. package/dist/lib/agent.js +97 -0
  40. package/dist/lib/agent.js.map +1 -0
  41. package/dist/lib/config.d.ts +35 -0
  42. package/dist/lib/config.js +179 -0
  43. package/dist/lib/config.js.map +1 -0
  44. package/dist/lib/context.d.ts +17 -0
  45. package/dist/lib/context.js +96 -0
  46. package/dist/lib/context.js.map +1 -0
  47. package/dist/lib/github.d.ts +61 -0
  48. package/dist/lib/github.js +313 -0
  49. package/dist/lib/github.js.map +1 -0
  50. package/dist/lib/learning.d.ts +43 -0
  51. package/dist/lib/learning.js +207 -0
  52. package/dist/lib/learning.js.map +1 -0
  53. package/dist/lib/logger.d.ts +9 -0
  54. package/dist/lib/logger.js +28 -0
  55. package/dist/lib/logger.js.map +1 -0
  56. package/dist/lib/pipeline.d.ts +18 -0
  57. package/dist/lib/pipeline.js +456 -0
  58. package/dist/lib/pipeline.js.map +1 -0
  59. package/dist/lib/preflight.d.ts +33 -0
  60. package/dist/lib/preflight.js +123 -0
  61. package/dist/lib/preflight.js.map +1 -0
  62. package/dist/lib/prerequisites.d.ts +12 -0
  63. package/dist/lib/prerequisites.js +54 -0
  64. package/dist/lib/prerequisites.js.map +1 -0
  65. package/dist/lib/prompts.d.ts +44 -0
  66. package/dist/lib/prompts.js +102 -0
  67. package/dist/lib/prompts.js.map +1 -0
  68. package/dist/lib/session.d.ts +28 -0
  69. package/dist/lib/session.js +173 -0
  70. package/dist/lib/session.js.map +1 -0
  71. package/dist/lib/shell.d.ts +32 -0
  72. package/dist/lib/shell.js +95 -0
  73. package/dist/lib/shell.js.map +1 -0
  74. package/dist/lib/testing.d.ts +10 -0
  75. package/dist/lib/testing.js +51 -0
  76. package/dist/lib/testing.js.map +1 -0
  77. package/dist/lib/verify.d.ts +18 -0
  78. package/dist/lib/verify.js +235 -0
  79. package/dist/lib/verify.js.map +1 -0
  80. package/dist/lib/vision.d.ts +9 -0
  81. package/dist/lib/vision.js +21 -0
  82. package/dist/lib/vision.js.map +1 -0
  83. package/dist/lib/worktree.d.ts +29 -0
  84. package/dist/lib/worktree.js +153 -0
  85. package/dist/lib/worktree.js.map +1 -0
  86. package/package.json +63 -0
  87. package/templates/agents/implementer.md +34 -0
  88. package/templates/agents/reviewer.md +48 -0
  89. package/templates/skills/code-review/SKILL.md +58 -0
  90. package/templates/skills/git-workflow/SKILL.md +53 -0
  91. package/templates/skills/implementation-planning/SKILL.md +64 -0
  92. package/templates/skills/security-analysis/SKILL.md +560 -0
  93. package/templates/skills/security-analysis/scripts/security-scanner.sh +227 -0
  94. package/templates/skills/test-robustness/SKILL.md +897 -0
  95. package/templates/skills/testing-patterns/SKILL.md +75 -0
@@ -0,0 +1,194 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import * as readline from 'node:readline';
4
+ import { exec } from '../lib/shell.js';
5
+ import { assertSafeShellArg, loadConfig } from '../lib/config.js';
6
+ import { log } from '../lib/logger.js';
7
+ function ask(rl, question) {
8
+ return new Promise((resolve) => {
9
+ rl.question(question, (answer) => resolve(answer.trim()));
10
+ });
11
+ }
12
+ const USER_TYPES = {
13
+ '1': 'Technical users (developers, engineers)',
14
+ '2': 'Semi-technical (power users, admins)',
15
+ '3': 'Non-technical (general consumers, elderly, caregivers) \u2014 UI must be simple, accessible, and forgiving',
16
+ '4': 'Mixed audience \u2014 needs both simple and advanced interfaces',
17
+ };
18
+ const STAGES = {
19
+ '1': 'Brand new / greenfield \u2014 focus on getting core architecture right',
20
+ '2': 'MVP / early development \u2014 focus on core flows working end-to-end',
21
+ '3': 'Working product \u2014 adding features without breaking existing functionality',
22
+ '4': 'Mature product \u2014 maintenance, optimization, and careful changes',
23
+ };
24
+ const PRIORITIES = {
25
+ '1': 'Core functionality \u2014 make it work reliably before making it pretty',
26
+ '2': 'User experience \u2014 the product works, now make it delightful',
27
+ '3': 'Scale and performance \u2014 handle more load, optimize bottlenecks',
28
+ '4': 'Security and compliance \u2014 harden, audit, meet regulatory requirements',
29
+ };
30
+ export async function visionCommand() {
31
+ if (!process.stdin.isTTY) {
32
+ log.info('Not running in an interactive terminal. Skipping vision setup.');
33
+ return;
34
+ }
35
+ const projectDir = process.cwd();
36
+ const contextDir = path.join(projectDir, '.alpha-loop');
37
+ const visionFile = path.join(contextDir, 'vision.md');
38
+ const config = loadConfig();
39
+ fs.mkdirSync(contextDir, { recursive: true });
40
+ const rl = readline.createInterface({
41
+ input: process.stdin,
42
+ output: process.stdout,
43
+ });
44
+ try {
45
+ // Check if vision exists
46
+ if (fs.existsSync(visionFile)) {
47
+ console.log('');
48
+ console.log('\x1b[1mCurrent project vision:\x1b[0m');
49
+ console.log('');
50
+ console.log(fs.readFileSync(visionFile, 'utf-8'));
51
+ console.log('');
52
+ const updateChoice = await ask(rl, 'Update this vision? [y/N]: ');
53
+ if (updateChoice.toLowerCase() !== 'y') {
54
+ return;
55
+ }
56
+ }
57
+ else {
58
+ console.log('');
59
+ console.log('\x1b[1m\x1b[36mNo project vision found. Let\'s set one up.\x1b[0m');
60
+ console.log('This helps the agent understand what it\'s building and make better decisions.');
61
+ console.log('');
62
+ }
63
+ // Question 1: What is this project?
64
+ console.log('\x1b[1mWhat is this project?\x1b[0m (1-2 sentences)');
65
+ const projectDescription = await ask(rl, '> ');
66
+ console.log('');
67
+ // Question 2: Target users
68
+ console.log('\x1b[1mWho are the target users?\x1b[0m');
69
+ console.log(' [1] Technical users (developers, engineers)');
70
+ console.log(' [2] Semi-technical (power users, admins)');
71
+ console.log(' [3] Non-technical (general consumers, elderly, caregivers)');
72
+ console.log(' [4] Mixed audience');
73
+ const userTypeChoice = await ask(rl, '> ');
74
+ const userType = USER_TYPES[userTypeChoice] ?? userTypeChoice;
75
+ console.log('');
76
+ // Question 3: Project stage
77
+ console.log('\x1b[1mWhat stage is the project in?\x1b[0m');
78
+ console.log(' [1] Brand new / greenfield');
79
+ console.log(' [2] MVP / early development');
80
+ console.log(' [3] Working product, adding features');
81
+ console.log(' [4] Mature product, maintenance mode');
82
+ const stageChoice = await ask(rl, '> ');
83
+ const projectStage = STAGES[stageChoice] ?? stageChoice;
84
+ console.log('');
85
+ // Question 4: Current priority
86
+ console.log('\x1b[1mWhat matters most right now?\x1b[0m');
87
+ console.log(' [1] Core functionality works reliably');
88
+ console.log(' [2] User experience and polish');
89
+ console.log(' [3] Scale and performance');
90
+ console.log(' [4] Security and compliance');
91
+ console.log(' [5] Something else (type it)');
92
+ const priorityChoice = await ask(rl, '> ');
93
+ const priority = PRIORITIES[priorityChoice] ?? priorityChoice;
94
+ console.log('');
95
+ // Question 5: UX/design guidelines
96
+ console.log('\x1b[1mAny UX or design guidelines?\x1b[0m (press Enter to skip)');
97
+ console.log(" Examples: 'mobile-first', 'dark mode', 'WCAG AA accessible', 'minimal UI'");
98
+ const uxGuidelines = await ask(rl, '> ');
99
+ console.log('');
100
+ // Question 6: North star issue
101
+ console.log('\x1b[1mLink a north star issue or paste additional context?\x1b[0m');
102
+ console.log(' Paste a GitHub issue URL, issue number, or freeform text (Enter to skip)');
103
+ const northStarInput = await ask(rl, '> ');
104
+ console.log('');
105
+ let northStarContent = '';
106
+ if (northStarInput) {
107
+ const issueMatch = northStarInput.match(/^(\d+)$/) ?? northStarInput.match(/issues\/(\d+)/);
108
+ if (issueMatch) {
109
+ const issueNum = issueMatch[1];
110
+ log.info(`Fetching issue #${issueNum}...`);
111
+ const repo = assertSafeShellArg(config.repo, 'repo');
112
+ const result = exec(`gh issue view ${issueNum} --repo ${repo} --json title,body`);
113
+ if (result.exitCode === 0 && result.stdout) {
114
+ const issueData = JSON.parse(result.stdout);
115
+ northStarContent = `### North Star: #${issueNum} \u2014 ${issueData.title}\n\n${issueData.body}`;
116
+ log.success(`Fetched issue #${issueNum}: ${issueData.title}`);
117
+ }
118
+ else {
119
+ log.warn(`Could not fetch issue #${issueNum}`);
120
+ northStarContent = northStarInput;
121
+ }
122
+ }
123
+ else {
124
+ northStarContent = northStarInput;
125
+ }
126
+ }
127
+ // Question 7: Anything else?
128
+ console.log('\x1b[1mAnything else the agent should always keep in mind?\x1b[0m (Enter to skip)');
129
+ const additionalContext = await ask(rl, '> ');
130
+ console.log('');
131
+ // Synthesize with Claude
132
+ log.step('Generating project vision...');
133
+ const visionPrompt = `Synthesize the following inputs into a concise project vision document. This will be read by AI agents before every task to guide their decisions.
134
+
135
+ Project description: ${projectDescription}
136
+ Target users: ${userType}
137
+ Project stage: ${projectStage}
138
+ Current priority: ${priority}
139
+ UX guidelines: ${uxGuidelines || 'None specified'}
140
+ Additional context: ${additionalContext || 'None'}
141
+ ${northStarContent ? `\nNorth star context:\n${northStarContent}` : ''}
142
+
143
+ Output ONLY this markdown structure. Be specific and actionable. Under 500 words total.
144
+
145
+ ## What We're Building
146
+ (2-3 sentences synthesizing the project description and north star)
147
+
148
+ ## Who It's For
149
+ (Target users and what that means for UX/design decisions)
150
+
151
+ ## Current Stage & Priority
152
+ (Where the project is and what matters most right now)
153
+
154
+ ## Decision Guidelines
155
+ (5-7 bullet points the agent should follow when making choices about implementation, UX, what to build vs defer, etc. Derived from all inputs above.)
156
+
157
+ ## What Good Looks Like
158
+ (3-4 bullet points describing the quality bar — what a successful implementation looks like for this project)`;
159
+ const model = assertSafeShellArg(config.model ?? 'opus', 'model');
160
+ const visionResult = exec(`echo ${JSON.stringify(visionPrompt)} | claude -p --model ${model} --dangerously-skip-permissions --output-format text 2>/dev/null`, { cwd: projectDir });
161
+ if (visionResult.exitCode === 0 && visionResult.stdout) {
162
+ fs.writeFileSync(visionFile, visionResult.stdout + '\n');
163
+ }
164
+ else {
165
+ // Fallback: write raw inputs
166
+ log.warn('Claude synthesis failed, saving raw inputs');
167
+ const raw = [
168
+ '## What We\'re Building',
169
+ projectDescription,
170
+ '',
171
+ '## Who It\'s For',
172
+ userType,
173
+ '',
174
+ '## Current Stage & Priority',
175
+ projectStage,
176
+ `Priority: ${priority}`,
177
+ '',
178
+ '## UX Guidelines',
179
+ uxGuidelines || 'None specified',
180
+ '',
181
+ ...(northStarContent ? ['## North Star', northStarContent, ''] : []),
182
+ ...(additionalContext ? ['## Additional Context', additionalContext, ''] : []),
183
+ ].join('\n');
184
+ fs.writeFileSync(visionFile, raw + '\n');
185
+ }
186
+ log.success(`Project vision saved to ${visionFile}`);
187
+ console.log('');
188
+ console.log(fs.readFileSync(visionFile, 'utf-8'));
189
+ }
190
+ finally {
191
+ rl.close();
192
+ }
193
+ }
194
+ //# sourceMappingURL=vision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.js","sourceRoot":"","sources":["../../src/commands/vision.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Agent Spawn Module
3
+ * ==================
4
+ *
5
+ * Handles spawning different AI CLI agents (Claude, Codex, OpenCode)
6
+ * with the correct CLI flags per agent type.
7
+ *
8
+ * Adding a new agent: add a case to AGENT_CLI_MAP and buildAgentArgs().
9
+ */
10
+ import { type ChildProcess } from 'node:child_process';
11
+ import type { AgentConfig } from './config.js';
12
+ /**
13
+ * CLI reference for each supported agent.
14
+ * Extend this map to add new agent types.
15
+ */
16
+ export declare const AGENT_CLI_MAP: Record<string, {
17
+ command: string;
18
+ promptFlag: string;
19
+ modelFlag: string;
20
+ permissionFlag?: string;
21
+ supportsMaxTurns: boolean;
22
+ maxTurnsFlag?: string;
23
+ }>;
24
+ export interface AgentArgs {
25
+ command: string;
26
+ args: string[];
27
+ }
28
+ /**
29
+ * Constructs the CLI command and arguments for spawning an agent.
30
+ * Throws if the agent type is not recognized.
31
+ */
32
+ export declare function buildAgentArgs(config: AgentConfig & {
33
+ model: string;
34
+ }, prompt: string): AgentArgs;
35
+ /**
36
+ * Spawns an agent subprocess with the correct CLI flags.
37
+ * Returns the ChildProcess for the caller to manage (listen to events, pipe stdio, etc.).
38
+ */
39
+ export declare function spawnAgent(config: AgentConfig & {
40
+ model: string;
41
+ }, prompt: string, cwd: string): ChildProcess;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Agent Spawn Module
3
+ * ==================
4
+ *
5
+ * Handles spawning different AI CLI agents (Claude, Codex, OpenCode)
6
+ * with the correct CLI flags per agent type.
7
+ *
8
+ * Adding a new agent: add a case to AGENT_CLI_MAP and buildAgentArgs().
9
+ */
10
+ import { spawn } from 'node:child_process';
11
+ // ============================================================================
12
+ // Agent CLI Mapping
13
+ // ============================================================================
14
+ /**
15
+ * CLI reference for each supported agent.
16
+ * Extend this map to add new agent types.
17
+ */
18
+ export const AGENT_CLI_MAP = {
19
+ claude: {
20
+ command: 'claude',
21
+ promptFlag: '-p',
22
+ modelFlag: '--model',
23
+ permissionFlag: '--dangerously-skip-permissions',
24
+ supportsMaxTurns: true,
25
+ maxTurnsFlag: '--max-turns',
26
+ },
27
+ codex: {
28
+ command: 'codex',
29
+ promptFlag: '-q',
30
+ modelFlag: '--model',
31
+ permissionFlag: '--auto-edit',
32
+ supportsMaxTurns: false,
33
+ },
34
+ opencode: {
35
+ command: 'opencode',
36
+ promptFlag: 'run',
37
+ modelFlag: '--model',
38
+ supportsMaxTurns: false,
39
+ },
40
+ };
41
+ /**
42
+ * Constructs the CLI command and arguments for spawning an agent.
43
+ * Throws if the agent type is not recognized.
44
+ */
45
+ export function buildAgentArgs(config, prompt) {
46
+ const agentDef = AGENT_CLI_MAP[config.agent];
47
+ if (!agentDef) {
48
+ throw new Error(`Unknown agent type: "${config.agent}". Supported agents: ${Object.keys(AGENT_CLI_MAP).join(', ')}`);
49
+ }
50
+ const args = [];
51
+ // For opencode, "run" is a subcommand, not a flag
52
+ if (config.agent === 'opencode') {
53
+ args.push(agentDef.promptFlag); // 'run'
54
+ }
55
+ // Model flag
56
+ args.push(agentDef.modelFlag, config.model);
57
+ // Permission flag (if agent supports it)
58
+ if (agentDef.permissionFlag) {
59
+ args.push(agentDef.permissionFlag);
60
+ }
61
+ // Max turns (only if agent supports it and value is provided)
62
+ if (config.maxTurns != null && agentDef.supportsMaxTurns && agentDef.maxTurnsFlag) {
63
+ args.push(agentDef.maxTurnsFlag, String(config.maxTurns));
64
+ }
65
+ // Prompt flag — for claude/codex it's a flag before the prompt text
66
+ if (config.agent !== 'opencode') {
67
+ args.push(agentDef.promptFlag, prompt);
68
+ }
69
+ else {
70
+ // opencode takes prompt as a positional arg after 'run'
71
+ args.push(prompt);
72
+ }
73
+ return { command: agentDef.command, args };
74
+ }
75
+ // ============================================================================
76
+ // Spawn Agent
77
+ // ============================================================================
78
+ /**
79
+ * Spawns an agent subprocess with the correct CLI flags.
80
+ * Returns the ChildProcess for the caller to manage (listen to events, pipe stdio, etc.).
81
+ */
82
+ export function spawnAgent(config, prompt, cwd) {
83
+ const { command, args } = buildAgentArgs(config, prompt);
84
+ return spawn(command, args, {
85
+ cwd,
86
+ stdio: ['pipe', 'pipe', 'pipe'],
87
+ env: { ...process.env },
88
+ });
89
+ }
90
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/engine/agents.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAG9D,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAOrB;IACH,MAAM,EAAE;QACN,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,SAAS;QACpB,cAAc,EAAE,gCAAgC;QAChD,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,aAAa;KAC5B;IACD,KAAK,EAAE;QACL,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,SAAS;QACpB,cAAc,EAAE,aAAa;QAC7B,gBAAgB,EAAE,KAAK;KACxB;IACD,QAAQ,EAAE;QACR,OAAO,EAAE,UAAU;QACnB,UAAU,EAAE,KAAK;QACjB,SAAS,EAAE,SAAS;QACpB,gBAAgB,EAAE,KAAK;KACxB;CACF,CAAC;AAWF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAuC,EAAE,MAAc;IACpF,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,CAAC,KAAK,wBAAwB,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpG,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,kDAAkD;IAClD,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ;IAC1C,CAAC;IAED,aAAa;IACb,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAE5C,yCAAyC;IACzC,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IAED,8DAA8D;IAC9D,IAAI,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QAClF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,oEAAoE;IACpE,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,wDAAwD;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAuC,EAAE,MAAc,EAAE,GAAW;IAC7F,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEzD,OAAO,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QAC1B,GAAG;QACH,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QAC/B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;KACxB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Configuration Module
3
+ * ====================
4
+ *
5
+ * Loads and validates .alpha-loop.yaml with per-stage agent/model configuration.
6
+ * Uses Zod for schema validation with sensible defaults.
7
+ */
8
+ import { z } from 'zod';
9
+ export declare const STAGE_NAMES: readonly ["implement", "fix", "review", "verify", "learn", "aggregate"];
10
+ export type StageName = (typeof STAGE_NAMES)[number];
11
+ export declare const DEFAULT_AGENT = "claude";
12
+ export declare const DEFAULT_MODEL = "opus";
13
+ export declare const AgentConfigSchema: z.ZodObject<{
14
+ agent: z.ZodDefault<z.ZodString>;
15
+ model: z.ZodOptional<z.ZodString>;
16
+ maxTurns: z.ZodOptional<z.ZodNumber>;
17
+ }, z.core.$strip>;
18
+ export type AgentConfig = z.infer<typeof AgentConfigSchema>;
19
+ export declare const ConfigSchema: z.ZodObject<{
20
+ repo: z.ZodString;
21
+ project: z.ZodOptional<z.ZodNumber>;
22
+ model: z.ZodDefault<z.ZodString>;
23
+ review_model: z.ZodOptional<z.ZodString>;
24
+ max_turns: z.ZodOptional<z.ZodNumber>;
25
+ label: z.ZodDefault<z.ZodString>;
26
+ base_branch: z.ZodDefault<z.ZodString>;
27
+ test_command: z.ZodDefault<z.ZodString>;
28
+ poll_interval: z.ZodDefault<z.ZodNumber>;
29
+ stages: z.ZodDefault<z.ZodOptional<z.ZodObject<{
30
+ implement: z.ZodOptional<z.ZodObject<{
31
+ agent: z.ZodDefault<z.ZodString>;
32
+ model: z.ZodOptional<z.ZodString>;
33
+ maxTurns: z.ZodOptional<z.ZodNumber>;
34
+ }, z.core.$strip>>;
35
+ fix: z.ZodOptional<z.ZodObject<{
36
+ agent: z.ZodDefault<z.ZodString>;
37
+ model: z.ZodOptional<z.ZodString>;
38
+ maxTurns: z.ZodOptional<z.ZodNumber>;
39
+ }, z.core.$strip>>;
40
+ review: z.ZodOptional<z.ZodObject<{
41
+ agent: z.ZodDefault<z.ZodString>;
42
+ model: z.ZodOptional<z.ZodString>;
43
+ maxTurns: z.ZodOptional<z.ZodNumber>;
44
+ }, z.core.$strip>>;
45
+ verify: z.ZodOptional<z.ZodObject<{
46
+ agent: z.ZodDefault<z.ZodString>;
47
+ model: z.ZodOptional<z.ZodString>;
48
+ maxTurns: z.ZodOptional<z.ZodNumber>;
49
+ }, z.core.$strip>>;
50
+ learn: z.ZodOptional<z.ZodObject<{
51
+ agent: z.ZodDefault<z.ZodString>;
52
+ model: z.ZodOptional<z.ZodString>;
53
+ maxTurns: z.ZodOptional<z.ZodNumber>;
54
+ }, z.core.$strip>>;
55
+ aggregate: z.ZodOptional<z.ZodObject<{
56
+ agent: z.ZodDefault<z.ZodString>;
57
+ model: z.ZodOptional<z.ZodString>;
58
+ maxTurns: z.ZodOptional<z.ZodNumber>;
59
+ }, z.core.$strip>>;
60
+ }, z.core.$strict>>>;
61
+ }, z.core.$strip>;
62
+ export type Config = z.infer<typeof ConfigSchema>;
63
+ export declare function loadConfig(cwd: string): Config;
64
+ /**
65
+ * Resolves the agent configuration for a given pipeline stage.
66
+ * Merges stage-specific config with global defaults:
67
+ * - agent: stage.agent → 'claude'
68
+ * - model: stage.model → config.model → 'opus'
69
+ * - maxTurns: stage.maxTurns → config.max_turns → undefined
70
+ */
71
+ export declare function resolveStageConfig(config: Config, stage: StageName): Required<Pick<AgentConfig, 'agent' | 'model'>> & Pick<AgentConfig, 'maxTurns'>;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Configuration Module
3
+ * ====================
4
+ *
5
+ * Loads and validates .alpha-loop.yaml with per-stage agent/model configuration.
6
+ * Uses Zod for schema validation with sensible defaults.
7
+ */
8
+ import { readFileSync } from 'node:fs';
9
+ import { resolve } from 'node:path';
10
+ import { z } from 'zod';
11
+ import { parse as parseYaml } from 'yaml';
12
+ // ============================================================================
13
+ // Constants
14
+ // ============================================================================
15
+ export const STAGE_NAMES = ['implement', 'fix', 'review', 'verify', 'learn', 'aggregate'];
16
+ export const DEFAULT_AGENT = 'claude';
17
+ export const DEFAULT_MODEL = 'opus';
18
+ // ============================================================================
19
+ // Schemas
20
+ // ============================================================================
21
+ export const AgentConfigSchema = z.object({
22
+ agent: z.string().default(DEFAULT_AGENT),
23
+ model: z.string().optional(),
24
+ maxTurns: z.number().optional(),
25
+ });
26
+ const StagesSchema = z.object({
27
+ implement: AgentConfigSchema.optional(),
28
+ fix: AgentConfigSchema.optional(),
29
+ review: AgentConfigSchema.optional(),
30
+ verify: AgentConfigSchema.optional(),
31
+ learn: AgentConfigSchema.optional(),
32
+ aggregate: AgentConfigSchema.optional(),
33
+ }).strict().optional().default({});
34
+ export const ConfigSchema = z.object({
35
+ repo: z.string(),
36
+ project: z.number().optional(),
37
+ model: z.string().default(DEFAULT_MODEL),
38
+ review_model: z.string().optional(),
39
+ max_turns: z.number().optional(),
40
+ label: z.string().default('ready'),
41
+ base_branch: z.string().default('master'),
42
+ test_command: z.string().default('pnpm test'),
43
+ poll_interval: z.number().default(60),
44
+ stages: StagesSchema,
45
+ });
46
+ // ============================================================================
47
+ // Config Loading
48
+ // ============================================================================
49
+ export function loadConfig(cwd) {
50
+ const configPath = resolve(cwd, '.alpha-loop.yaml');
51
+ const raw = readFileSync(configPath, 'utf-8');
52
+ const parsed = parseYaml(raw);
53
+ return ConfigSchema.parse(parsed);
54
+ }
55
+ // ============================================================================
56
+ // Stage Config Resolution
57
+ // ============================================================================
58
+ /**
59
+ * Resolves the agent configuration for a given pipeline stage.
60
+ * Merges stage-specific config with global defaults:
61
+ * - agent: stage.agent → 'claude'
62
+ * - model: stage.model → config.model → 'opus'
63
+ * - maxTurns: stage.maxTurns → config.max_turns → undefined
64
+ */
65
+ export function resolveStageConfig(config, stage) {
66
+ const stageConfig = config.stages[stage];
67
+ return {
68
+ agent: stageConfig?.agent ?? DEFAULT_AGENT,
69
+ model: stageConfig?.model ?? config.model ?? DEFAULT_MODEL,
70
+ maxTurns: stageConfig?.maxTurns ?? config.max_turns,
71
+ };
72
+ }
73
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/engine/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Prerequisites Module
3
+ * ====================
4
+ *
5
+ * Verifies that all configured AI CLI agents are installed before starting the pipeline.
6
+ * Groups stages by agent for clear diagnostic output.
7
+ */
8
+ import { type Config, type StageName } from './config.js';
9
+ export interface AgentCheckResult {
10
+ agent: string;
11
+ installed: boolean;
12
+ stages: StageName[];
13
+ }
14
+ export interface PrerequisiteResult {
15
+ ok: boolean;
16
+ results: AgentCheckResult[];
17
+ }
18
+ /**
19
+ * Checks whether a CLI command is available on the system PATH.
20
+ */
21
+ export declare function isCommandAvailable(command: string): boolean;
22
+ /**
23
+ * Checks all agents configured across pipeline stages.
24
+ * Returns structured results showing which agents are installed and which stages they serve.
25
+ */
26
+ export declare function checkAgents(config: Config): PrerequisiteResult;
27
+ /**
28
+ * Formats the prerequisite check results for console output.
29
+ */
30
+ export declare function formatCheckResults(result: PrerequisiteResult): string;
31
+ /**
32
+ * Formats the pipeline startup summary showing per-stage configuration.
33
+ */
34
+ export declare function formatPipelineSummary(config: Config): string;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Prerequisites Module
3
+ * ====================
4
+ *
5
+ * Verifies that all configured AI CLI agents are installed before starting the pipeline.
6
+ * Groups stages by agent for clear diagnostic output.
7
+ */
8
+ import { execSync } from 'node:child_process';
9
+ import { STAGE_NAMES, resolveStageConfig } from './config.js';
10
+ // ============================================================================
11
+ // Agent Check
12
+ // ============================================================================
13
+ /**
14
+ * Checks whether a CLI command is available on the system PATH.
15
+ */
16
+ export function isCommandAvailable(command) {
17
+ // Validate command name to prevent shell injection from user-controlled config
18
+ if (!/^[a-zA-Z0-9_-]+$/.test(command)) {
19
+ return false;
20
+ }
21
+ try {
22
+ execSync(`which ${command}`, { stdio: 'ignore' });
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ /**
30
+ * Checks all agents configured across pipeline stages.
31
+ * Returns structured results showing which agents are installed and which stages they serve.
32
+ */
33
+ export function checkAgents(config) {
34
+ // Collect stages grouped by agent
35
+ const agentStages = new Map();
36
+ for (const stage of STAGE_NAMES) {
37
+ const { agent } = resolveStageConfig(config, stage);
38
+ const stages = agentStages.get(agent) ?? [];
39
+ stages.push(stage);
40
+ agentStages.set(agent, stages);
41
+ }
42
+ // Check each unique agent
43
+ const results = [];
44
+ for (const [agent, stages] of agentStages) {
45
+ results.push({
46
+ agent,
47
+ installed: isCommandAvailable(agent),
48
+ stages,
49
+ });
50
+ }
51
+ return {
52
+ ok: results.every(r => r.installed),
53
+ results,
54
+ };
55
+ }
56
+ // ============================================================================
57
+ // Formatting
58
+ // ============================================================================
59
+ /**
60
+ * Formats the prerequisite check results for console output.
61
+ */
62
+ export function formatCheckResults(result) {
63
+ const lines = ['Checking agents...'];
64
+ for (const r of result.results) {
65
+ const icon = r.installed ? '\u2713' : '\u2717';
66
+ const stageList = r.stages.join(', ');
67
+ lines.push(` ${icon} ${r.agent} (${stageList})`);
68
+ }
69
+ if (!result.ok) {
70
+ const missing = result.results.filter(r => !r.installed);
71
+ for (const m of missing) {
72
+ lines.push(`\nError: "${m.agent}" is not installed. Affected stages: ${m.stages.join(', ')}`);
73
+ }
74
+ }
75
+ return lines.join('\n');
76
+ }
77
+ /**
78
+ * Formats the pipeline startup summary showing per-stage configuration.
79
+ */
80
+ export function formatPipelineSummary(config) {
81
+ const lines = ['Pipeline:'];
82
+ for (const stage of STAGE_NAMES) {
83
+ const sc = resolveStageConfig(config, stage);
84
+ const turns = sc.maxTurns ? ` (${sc.maxTurns} turns)` : '';
85
+ const padded = `${stage}:`.padEnd(14);
86
+ lines.push(` ${padded}${sc.agent}/${sc.model}${turns}`);
87
+ }
88
+ return lines.join('\n');
89
+ }
90
+ //# sourceMappingURL=prerequisites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerequisites.js","sourceRoot":"","sources":["../../src/engine/prerequisites.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export type AgentResult = {
2
+ exitCode: number;
3
+ output: string;
4
+ duration: number;
5
+ };
6
+ export type AgentOptions = {
7
+ agent: 'claude' | 'codex' | 'opencode';
8
+ model: string;
9
+ prompt: string;
10
+ cwd: string;
11
+ logFile?: string;
12
+ verbose?: boolean;
13
+ };
14
+ /**
15
+ * Build CLI command and args for a given agent type.
16
+ */
17
+ export declare function buildAgentArgs(options: AgentOptions): {
18
+ command: string;
19
+ args: string[];
20
+ };
21
+ /**
22
+ * Spawn an AI agent with a prompt.
23
+ * Streams output to terminal in real-time while capturing it.
24
+ */
25
+ export declare function spawnAgent(options: AgentOptions): Promise<AgentResult>;