@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,235 @@
1
+ /**
2
+ * Live Verification — start the app, use playwright-cli to test it like a real user.
3
+ *
4
+ * This is NOT running E2E test suites. This is an AI agent using playwright-cli
5
+ * to interactively verify that the implemented feature actually works by:
6
+ * 1. Starting the dev server
7
+ * 2. Opening the app in a browser via playwright-cli
8
+ * 3. Navigating, clicking, typing, taking screenshots
9
+ * 4. Reporting PASS or FAIL
10
+ */
11
+ import { existsSync, readFileSync, mkdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { exec } from './shell.js';
14
+ import { log } from './logger.js';
15
+ import { spawnAgent } from './agent.js';
16
+ /** Max seconds to wait for app to become ready. */
17
+ const APP_READY_TIMEOUT_S = 60;
18
+ /**
19
+ * Run live verification using playwright-cli.
20
+ * Starts the app, sends agent to test it, returns result.
21
+ */
22
+ export async function runVerify(options) {
23
+ const { worktree, logFile, issueNum, title, body, config, sessionDir } = options;
24
+ if (config.skipVerify) {
25
+ log.info('Verification skipped (skipVerify=true)');
26
+ return { passed: true, output: 'Verification skipped' };
27
+ }
28
+ if (config.dryRun) {
29
+ log.dry('Would run live verification');
30
+ return { passed: true, output: 'Verification skipped (dry run)' };
31
+ }
32
+ log.step(`Running live verification for issue #${issueNum}`);
33
+ // Check if playwright-cli is available
34
+ const whichResult = exec('which playwright-cli');
35
+ if (whichResult.exitCode !== 0) {
36
+ log.warn('playwright-cli not installed. Install with: npm install -g @anthropic-ai/claude-code');
37
+ log.info('Skipping live verification (no playwright-cli)');
38
+ return { passed: true, output: 'Verification skipped (playwright-cli not installed)' };
39
+ }
40
+ // Detect how to start the app
41
+ let devCmd = config.devCommand;
42
+ if (!devCmd) {
43
+ const pkgJsonPath = join(worktree, 'package.json');
44
+ if (existsSync(pkgJsonPath)) {
45
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
46
+ const scripts = pkg.scripts ?? {};
47
+ for (const name of ['dev', 'start', 'preview']) {
48
+ if (scripts[name]) {
49
+ devCmd = `pnpm ${name}`;
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ if (!devCmd) {
56
+ log.info('No dev/start/preview command found, skipping verification');
57
+ return { passed: true, output: 'Verification skipped (no start command)' };
58
+ }
59
+ const port = config.port ?? 3000;
60
+ // Start the app in the background
61
+ log.info(`Starting app with '${devCmd}' on port ${port}...`);
62
+ const { spawn } = await import('node:child_process');
63
+ const appProcess = spawn('sh', ['-c', `PORT=${port} ${devCmd}`], {
64
+ cwd: worktree,
65
+ stdio: ['ignore', 'pipe', 'pipe'],
66
+ detached: true,
67
+ });
68
+ const appPid = appProcess.pid;
69
+ // Wait for app to be ready
70
+ let ready = false;
71
+ for (let i = 0; i < APP_READY_TIMEOUT_S; i++) {
72
+ const check = exec(`curl -s -o /dev/null http://localhost:${port}`);
73
+ if (check.exitCode === 0) {
74
+ ready = true;
75
+ break;
76
+ }
77
+ // Check if process is still alive
78
+ try {
79
+ process.kill(appPid, 0);
80
+ }
81
+ catch {
82
+ log.error('App process exited before becoming ready');
83
+ return { passed: false, output: 'App failed to start' };
84
+ }
85
+ await new Promise((r) => setTimeout(r, 1000));
86
+ }
87
+ if (!ready) {
88
+ log.error(`App did not become ready on port ${port} within ${APP_READY_TIMEOUT_S}s`);
89
+ killProcess(appPid);
90
+ return { passed: false, output: `App failed to start on port ${port}` };
91
+ }
92
+ log.success(`App is ready on port ${port}`);
93
+ // Load saved auth state if it exists
94
+ const authStateDir = join(process.cwd(), '.alpha-loop', 'auth');
95
+ if (existsSync(join(authStateDir, 'state.json'))) {
96
+ log.info('Loading saved auth state...');
97
+ exec(`playwright-cli state-load "${authStateDir}/state.json"`);
98
+ }
99
+ // Save screenshots to session directory
100
+ const screenshotDir = join(sessionDir, 'screenshots', `issue-${issueNum}`);
101
+ mkdirSync(screenshotDir, { recursive: true });
102
+ // Get the diff to understand what changed
103
+ const diffStat = exec(`git diff --stat "origin/${config.baseBranch}...HEAD"`, { cwd: worktree });
104
+ // Get vision context
105
+ const visionFile = join(process.cwd(), '.alpha-loop', 'vision.md');
106
+ const visionContext = existsSync(visionFile) ? readFileSync(visionFile, 'utf-8') : '';
107
+ // Build the verification prompt
108
+ const verifyPrompt = `You are a QA tester verifying that issue #${issueNum} was implemented correctly.
109
+
110
+ ## Issue: ${title}
111
+
112
+ ${body}
113
+
114
+ ## What Changed
115
+ ${diffStat.stdout || 'No diff available'}
116
+
117
+ ${visionContext ? `## Product Vision\n${visionContext}\n` : ''}
118
+ ## Your Task
119
+
120
+ The app is running at http://localhost:${port}. Use the playwright-cli to test it.
121
+
122
+ ### Playwright CLI Commands Available
123
+ - \`playwright-cli open http://localhost:${port}\` — Open the app in a browser
124
+ - \`playwright-cli goto <url>\` — Navigate to a page
125
+ - \`playwright-cli snapshot\` — Get a snapshot of the current page with element refs
126
+ - \`playwright-cli click <ref>\` — Click an element (use ref from snapshot, e.g. \`e15\`)
127
+ - \`playwright-cli type <text>\` — Type text into the focused element
128
+ - \`playwright-cli screenshot --path <file>\` — Take a screenshot and save to file
129
+ - \`playwright-cli fill <ref> <text>\` — Fill a form field
130
+ - \`playwright-cli select <ref> <value>\` — Select a dropdown option
131
+ - \`playwright-cli wait <selector>\` — Wait for an element to appear
132
+ - \`playwright-cli console\` — Check browser console for errors
133
+ - \`playwright-cli network\` — Check network requests/responses
134
+
135
+ ### Testing Steps
136
+
137
+ 1. Open the app: \`playwright-cli open http://localhost:${port}\`
138
+ 2. Take a snapshot to see the page structure: \`playwright-cli snapshot\`
139
+ 3. Navigate to the feature that was changed
140
+ 4. Test the ACTUAL user flow described in the issue:
141
+ - Can you do what the issue says should work?
142
+ - Does the UI render correctly?
143
+ - Do form submissions work end-to-end?
144
+ - Check console for errors: \`playwright-cli console\`
145
+ - Check network for failed requests: \`playwright-cli network\`
146
+ 5. Take screenshots at key states (save to the screenshot directory below)
147
+ 6. Check for functional gaps:
148
+ - Is the backend wired to the frontend?
149
+ - Are there UI elements that don't respond?
150
+ - Does data persist after submission?
151
+
152
+ ### Auth / Login
153
+ ${existsSync(authStateDir) ? 'Auth state is pre-loaded. If you need to log in, use the credentials from the environment or .env file.' : 'No auth state saved.'}
154
+
155
+ ## Report
156
+
157
+ After testing, output a verification report:
158
+
159
+ ### Status: PASS or FAIL
160
+
161
+ ### What Was Tested
162
+ - (list each action you took with playwright-cli)
163
+
164
+ ### What Worked
165
+ - (list what functioned correctly)
166
+
167
+ ### What Failed
168
+ - (list what didn't work, with details and screenshots)
169
+
170
+ ### Console Errors
171
+ - (any browser console errors found)
172
+
173
+ ### Network Issues
174
+ - (any failed API calls or missing endpoints)
175
+
176
+ ### Gaps Found
177
+ - (any disconnects between frontend and backend, missing pieces, etc.)
178
+
179
+ ### Screenshots
180
+ Save screenshots to this directory: ${screenshotDir}
181
+ Use descriptive filenames:
182
+ - \`playwright-cli screenshot --path "${screenshotDir}/01-initial-load.png"\`
183
+ - \`playwright-cli screenshot --path "${screenshotDir}/02-after-action.png"\`
184
+ - \`playwright-cli screenshot --path "${screenshotDir}/03-final-state.png"\`
185
+
186
+ IMPORTANT: Use playwright-cli commands to actually interact with the app.
187
+ Navigate, click, type, submit forms. Verify the feature works as a real user would use it.`;
188
+ log.info(`Verification agent: claude + playwright-cli | Testing live at http://localhost:${port}`);
189
+ // Run the verification agent
190
+ const agentResult = await spawnAgent({
191
+ agent: 'claude',
192
+ model: config.model,
193
+ prompt: verifyPrompt,
194
+ cwd: worktree,
195
+ logFile,
196
+ });
197
+ const verifyOutput = agentResult.output;
198
+ // Kill the app process
199
+ log.info('Shutting down app...');
200
+ killProcess(appPid);
201
+ // Close playwright-cli browser sessions
202
+ exec('playwright-cli close-all');
203
+ // Check if verification passed based on agent output
204
+ if (/Status:.*FAIL/i.test(verifyOutput)) {
205
+ log.error('Live verification FAILED');
206
+ return { passed: false, output: verifyOutput };
207
+ }
208
+ else if (/Status:.*PASS/i.test(verifyOutput)) {
209
+ log.success('Live verification PASSED');
210
+ return { passed: true, output: verifyOutput };
211
+ }
212
+ else if (agentResult.exitCode === 0) {
213
+ log.success('Verification completed (agent exit 0)');
214
+ return { passed: true, output: verifyOutput };
215
+ }
216
+ else {
217
+ log.warn(`Verification unclear (agent exit ${agentResult.exitCode})`);
218
+ return { passed: false, output: verifyOutput };
219
+ }
220
+ }
221
+ function killProcess(pid) {
222
+ try {
223
+ // Kill process group (negative pid)
224
+ process.kill(-pid, 'SIGTERM');
225
+ }
226
+ catch {
227
+ try {
228
+ process.kill(pid, 'SIGTERM');
229
+ }
230
+ catch {
231
+ // Process already dead
232
+ }
233
+ }
234
+ }
235
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/lib/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Get vision context for prompt injection.
3
+ * Returns the contents of .alpha-loop/vision.md, or null if it doesn't exist.
4
+ */
5
+ export declare function getVisionContext(projectDir?: string): string | null;
6
+ /**
7
+ * Check if vision has been set up.
8
+ */
9
+ export declare function hasVision(projectDir?: string): boolean;
@@ -0,0 +1,21 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ const VISION_FILE = join('.alpha-loop', 'vision.md');
4
+ /**
5
+ * Get vision context for prompt injection.
6
+ * Returns the contents of .alpha-loop/vision.md, or null if it doesn't exist.
7
+ */
8
+ export function getVisionContext(projectDir = '.') {
9
+ const filePath = join(projectDir, VISION_FILE);
10
+ if (!existsSync(filePath)) {
11
+ return null;
12
+ }
13
+ return readFileSync(filePath, 'utf-8');
14
+ }
15
+ /**
16
+ * Check if vision has been set up.
17
+ */
18
+ export function hasVision(projectDir = '.') {
19
+ return existsSync(join(projectDir, VISION_FILE));
20
+ }
21
+ //# sourceMappingURL=vision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision.js","sourceRoot":"","sources":["../../src/lib/vision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,aAAqB,GAAG;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,aAAqB,GAAG;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,29 @@
1
+ export type WorktreeResult = {
2
+ path: string;
3
+ branch: string;
4
+ };
5
+ export type SetupWorktreeOptions = {
6
+ issueNum: number;
7
+ projectDir: string;
8
+ baseBranch: string;
9
+ sessionBranch?: string;
10
+ autoMerge?: boolean;
11
+ skipInstall?: boolean;
12
+ dryRun?: boolean;
13
+ };
14
+ export type CleanupWorktreeOptions = {
15
+ issueNum: number;
16
+ projectDir: string;
17
+ autoCleanup?: boolean;
18
+ dryRun?: boolean;
19
+ };
20
+ /**
21
+ * Create an isolated git worktree for processing an issue.
22
+ * When autoMerge is enabled and a session branch exists,
23
+ * branches from session branch so changes stack across issues.
24
+ */
25
+ export declare function setupWorktree(options: SetupWorktreeOptions): Promise<WorktreeResult>;
26
+ /**
27
+ * Remove a worktree. Keeps the branch (needed for PR).
28
+ */
29
+ export declare function cleanupWorktree(options: CleanupWorktreeOptions): Promise<void>;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Worktree Manager — create and clean up isolated git worktrees.
3
+ */
4
+ import { existsSync, mkdirSync, symlinkSync, readlinkSync, unlinkSync, readFileSync, writeFileSync, appendFileSync } from 'node:fs';
5
+ import { join, resolve, basename } from 'node:path';
6
+ import { exec } from './shell.js';
7
+ import { log } from './logger.js';
8
+ const ENV_FILES = ['.env', '.env.local', '.env.development', '.env.development.local'];
9
+ /**
10
+ * Create an isolated git worktree for processing an issue.
11
+ * When autoMerge is enabled and a session branch exists,
12
+ * branches from session branch so changes stack across issues.
13
+ */
14
+ export async function setupWorktree(options) {
15
+ const { issueNum, projectDir, baseBranch, sessionBranch, autoMerge, skipInstall, dryRun } = options;
16
+ const branch = `agent/issue-${issueNum}`;
17
+ const worktreesDir = resolve(projectDir, '.worktrees');
18
+ mkdirSync(worktreesDir, { recursive: true });
19
+ const worktreePath = resolve(worktreesDir, `issue-${issueNum}`);
20
+ log.info(`Creating worktree at ${worktreePath} (branch: ${branch})`);
21
+ if (dryRun) {
22
+ log.dry(`Would create worktree: ${worktreePath}`);
23
+ return { path: worktreePath, branch };
24
+ }
25
+ // Clean up existing worktree if present
26
+ if (existsSync(worktreePath)) {
27
+ log.warn(`Worktree already exists at ${worktreePath}, removing...`);
28
+ exec(`git worktree remove "${worktreePath}" --force`, { cwd: projectDir });
29
+ }
30
+ // Delete local branch from previous runs (may exist even without worktree)
31
+ exec(`git branch -D "${branch}"`, { cwd: projectDir });
32
+ // Delete remote branch from previous failed runs
33
+ exec(`git push origin --delete "${branch}"`, { cwd: projectDir });
34
+ // Determine source branch: use session branch when auto-merging and it exists
35
+ let fromBranch = baseBranch;
36
+ if (autoMerge && sessionBranch && sessionBranch !== baseBranch) {
37
+ const remoteCheck = exec(`git rev-parse --verify "origin/${sessionBranch}"`, { cwd: projectDir });
38
+ const localCheck = exec(`git rev-parse --verify "${sessionBranch}"`, { cwd: projectDir });
39
+ if (remoteCheck.exitCode === 0 || localCheck.exitCode === 0) {
40
+ fromBranch = sessionBranch;
41
+ }
42
+ }
43
+ // Fetch latest
44
+ exec('git fetch origin', { cwd: projectDir });
45
+ // Create worktree from the appropriate branch (try origin/ first, fall back to local)
46
+ log.info(`Branching worktree from: ${fromBranch}`);
47
+ const remoteResult = exec(`git worktree add "${worktreePath}" -b "${branch}" "origin/${fromBranch}"`, { cwd: projectDir });
48
+ if (remoteResult.exitCode !== 0) {
49
+ const localResult = exec(`git worktree add "${worktreePath}" -b "${branch}" "${fromBranch}"`, { cwd: projectDir });
50
+ if (localResult.exitCode !== 0) {
51
+ throw new Error(`Failed to create worktree from ${fromBranch}: ${localResult.stderr}`);
52
+ }
53
+ log.info(`Created worktree from local ${fromBranch}`);
54
+ }
55
+ else {
56
+ log.info(`Created worktree from origin/${fromBranch}`);
57
+ }
58
+ // Symlink env files from main repo to worktree (gitignored files don't exist in worktrees)
59
+ for (const envFile of ENV_FILES) {
60
+ const src = join(projectDir, envFile);
61
+ const dest = join(worktreePath, envFile);
62
+ if (existsSync(src)) {
63
+ // Remove existing file/symlink if present
64
+ if (existsSync(dest)) {
65
+ try {
66
+ unlinkSync(dest);
67
+ }
68
+ catch { /* ignore */ }
69
+ }
70
+ symlinkSync(src, dest);
71
+ log.info(`Symlinked ${envFile} to worktree`);
72
+ }
73
+ }
74
+ // Set COMPOSE_PROJECT_NAME so Docker doesn't use "issue-N" as project name
75
+ ensureComposeProjectName(worktreePath, projectDir);
76
+ // Install dependencies unless skipped
77
+ if (!skipInstall) {
78
+ log.info('Installing dependencies in worktree...');
79
+ const installResult = exec('pnpm install --frozen-lockfile', { cwd: worktreePath });
80
+ if (installResult.exitCode !== 0) {
81
+ // Fall back to regular install
82
+ const fallback = exec('pnpm install', { cwd: worktreePath });
83
+ if (fallback.exitCode !== 0) {
84
+ log.warn('pnpm install had issues, continuing anyway...');
85
+ }
86
+ }
87
+ }
88
+ log.info(`Worktree ready at ${worktreePath}`);
89
+ return { path: worktreePath, branch };
90
+ }
91
+ /**
92
+ * Remove a worktree. Keeps the branch (needed for PR).
93
+ */
94
+ export async function cleanupWorktree(options) {
95
+ const { issueNum, projectDir, autoCleanup = true, dryRun } = options;
96
+ const worktreePath = resolve(projectDir, '.worktrees', `issue-${issueNum}`);
97
+ if (!autoCleanup) {
98
+ log.info('Skipping worktree cleanup (autoCleanup=false)');
99
+ return;
100
+ }
101
+ if (dryRun) {
102
+ log.dry(`Would clean up worktree: ${worktreePath}`);
103
+ return;
104
+ }
105
+ if (existsSync(worktreePath)) {
106
+ log.info(`Removing worktree: ${worktreePath}`);
107
+ const result = exec(`git worktree remove "${worktreePath}" --force`, { cwd: projectDir });
108
+ if (result.exitCode !== 0) {
109
+ log.warn('Could not remove worktree cleanly, forcing...');
110
+ exec(`rm -rf "${worktreePath}"`, { cwd: projectDir });
111
+ exec('git worktree prune', { cwd: projectDir });
112
+ }
113
+ }
114
+ log.info('Worktree cleaned up');
115
+ }
116
+ /**
117
+ * Ensure COMPOSE_PROJECT_NAME is set in the worktree's .env file
118
+ * so Docker Compose doesn't use the worktree directory name (e.g., "issue-2")
119
+ * as the project name for containers.
120
+ */
121
+ function ensureComposeProjectName(worktreePath, projectDir) {
122
+ const repoName = basename(projectDir);
123
+ const envPath = join(worktreePath, '.env');
124
+ // Check if .env already has COMPOSE_PROJECT_NAME
125
+ if (existsSync(envPath)) {
126
+ // If it's a symlink, we can't modify it — check if the source has the var
127
+ try {
128
+ readlinkSync(envPath);
129
+ // It's a symlink — check if the source .env already has COMPOSE_PROJECT_NAME
130
+ const content = readFileSync(envPath, 'utf-8');
131
+ if (content.includes('COMPOSE_PROJECT_NAME'))
132
+ return;
133
+ // Source doesn't have it — create a .env.compose override instead
134
+ const composePath = join(worktreePath, '.env.compose');
135
+ writeFileSync(composePath, `COMPOSE_PROJECT_NAME=${repoName}\n`);
136
+ log.info(`Set COMPOSE_PROJECT_NAME=${repoName} in .env.compose`);
137
+ return;
138
+ }
139
+ catch {
140
+ // Not a symlink — safe to check/append
141
+ const content = readFileSync(envPath, 'utf-8') ?? '';
142
+ if (content.includes('COMPOSE_PROJECT_NAME'))
143
+ return;
144
+ appendFileSync(envPath, `\nCOMPOSE_PROJECT_NAME=${repoName}\n`);
145
+ log.info(`Added COMPOSE_PROJECT_NAME=${repoName} to .env`);
146
+ return;
147
+ }
148
+ }
149
+ // No .env at all — create one with just COMPOSE_PROJECT_NAME
150
+ writeFileSync(envPath, `COMPOSE_PROJECT_NAME=${repoName}\n`);
151
+ log.info(`Created .env with COMPOSE_PROJECT_NAME=${repoName}`);
152
+ }
153
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/lib/worktree.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACpI,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAwBlC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;AAEvF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA6B;IAC/D,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACpG,MAAM,MAAM,GAAG,eAAe,QAAQ,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC,CAAC;IAEhE,GAAG,CAAC,IAAI,CAAC,wBAAwB,YAAY,aAAa,MAAM,GAAG,CAAC,CAAC;IAErE,IAAI,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,GAAG,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IACxC,CAAC;IAED,wCAAwC;IACxC,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,8BAA8B,YAAY,eAAe,CAAC,CAAC;QACpE,IAAI,CAAC,wBAAwB,YAAY,WAAW,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,2EAA2E;IAC3E,IAAI,CAAC,kBAAkB,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAEvD,iDAAiD;IACjD,IAAI,CAAC,6BAA6B,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAElE,8EAA8E;IAC9E,IAAI,UAAU,GAAG,UAAU,CAAC;IAC5B,IAAI,SAAS,IAAI,aAAa,IAAI,aAAa,KAAK,UAAU,EAAE,CAAC;QAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,kCAAkC,aAAa,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAClG,MAAM,UAAU,GAAG,IAAI,CAAC,2BAA2B,aAAa,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1F,IAAI,WAAW,CAAC,QAAQ,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC5D,UAAU,GAAG,aAAa,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,eAAe;IACf,IAAI,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;IAE9C,sFAAsF;IACtF,GAAG,CAAC,IAAI,CAAC,4BAA4B,UAAU,EAAE,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,IAAI,CACvB,qBAAqB,YAAY,SAAS,MAAM,aAAa,UAAU,GAAG,EAC1E,EAAE,GAAG,EAAE,UAAU,EAAE,CACpB,CAAC;IACF,IAAI,YAAY,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,IAAI,CACtB,qBAAqB,YAAY,SAAS,MAAM,MAAM,UAAU,GAAG,EACnE,EAAE,GAAG,EAAE,UAAU,EAAE,CACpB,CAAC;QACF,IAAI,WAAW,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,kCAAkC,UAAU,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,gCAAgC,UAAU,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,2FAA2F;IAC3F,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,0CAA0C;YAC1C,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC;oBAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YAClD,CAAC;YACD,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,aAAa,OAAO,cAAc,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,wBAAwB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAEnD,sCAAsC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACnD,MAAM,aAAa,GAAG,IAAI,CAAC,gCAAgC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;QACpF,IAAI,aAAa,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACjC,+BAA+B;YAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YAC7D,IAAI,QAAQ,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC5B,GAAG,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAC;IAC9C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA+B;IACnE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACrE,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC,CAAC;IAE5E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,GAAG,CAAC,4BAA4B,YAAY,EAAE,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,sBAAsB,YAAY,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,wBAAwB,YAAY,WAAW,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1F,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;YAC1D,IAAI,CAAC,WAAW,YAAY,GAAG,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;YACtD,IAAI,CAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,YAAoB,EAAE,UAAkB;IACxE,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAE3C,iDAAiD;IACjD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,0EAA0E;QAC1E,IAAI,CAAC;YACH,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,6EAA6E;YAC7E,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,IAAI,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBAAE,OAAO;YACrD,kEAAkE;YAClE,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;YACvD,aAAa,CAAC,WAAW,EAAE,wBAAwB,QAAQ,IAAI,CAAC,CAAC;YACjE,GAAG,CAAC,IAAI,CAAC,4BAA4B,QAAQ,kBAAkB,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;YACvC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBAAE,OAAO;YACrD,cAAc,CAAC,OAAO,EAAE,0BAA0B,QAAQ,IAAI,CAAC,CAAC;YAChE,GAAG,CAAC,IAAI,CAAC,8BAA8B,QAAQ,UAAU,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,aAAa,CAAC,OAAO,EAAE,wBAAwB,QAAQ,IAAI,CAAC,CAAC;IAC7D,GAAG,CAAC,IAAI,CAAC,0CAA0C,QAAQ,EAAE,CAAC,CAAC;AACjE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@bradtaylorsf/alpha-loop",
3
+ "version": "1.0.0",
4
+ "description": "Agent-agnostic automated development loop: Plan → Build → Test → Review → Ship",
5
+ "type": "module",
6
+ "packageManager": "pnpm@9.0.0",
7
+ "bin": {
8
+ "alpha-loop": "./dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "templates",
13
+ "agents",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "postbuild": "chmod +x dist/cli.js",
20
+ "dev": "tsx src/cli.ts",
21
+ "test": "jest --runInBand",
22
+ "test:unit": "jest --runInBand",
23
+ "test:watch": "jest --watch",
24
+ "prepublishOnly": "pnpm build"
25
+ },
26
+ "keywords": [
27
+ "ai",
28
+ "agent",
29
+ "automation",
30
+ "development",
31
+ "loop",
32
+ "claude",
33
+ "codex",
34
+ "github"
35
+ ],
36
+ "engines": {
37
+ "node": ">=20"
38
+ },
39
+ "author": "Bradley Taylor",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/bradtaylorsf/alpha-loop.git"
44
+ },
45
+ "homepage": "https://github.com/bradtaylorsf/alpha-loop#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/bradtaylorsf/alpha-loop/issues"
48
+ },
49
+ "dependencies": {
50
+ "commander": "^14.0.3",
51
+ "yaml": "^2.8.3",
52
+ "zod": "^4.3.6"
53
+ },
54
+ "devDependencies": {
55
+ "@types/jest": "^29.5.11",
56
+ "@types/node": "^20.9.0",
57
+ "jest": "^29.7.0",
58
+ "ts-jest": "^29.1.1",
59
+ "ts-node": "^10.9.2",
60
+ "tsx": "^4.6.0",
61
+ "typescript": "^5.2.2"
62
+ }
63
+ }
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: implementer
3
+ description: Implements GitHub issues by writing code, tests, and committing. The primary coding agent in the loop.
4
+ tools: Read, Write, Edit, Glob, Grep, Bash
5
+ model: opus
6
+ skills: api-patterns, api-contracts, testing-patterns, jest-mock-patterns, implementation-planning, git-workflow, sqlite-patterns, security-analysis
7
+ ---
8
+
9
+ # Implementer Agent
10
+
11
+ You implement GitHub issues autonomously. You receive an issue description with acceptance criteria, and you produce working, tested, committed code.
12
+
13
+ ## Process
14
+
15
+ 1. **Read** the issue requirements and acceptance criteria carefully
16
+ 2. **Explore** the codebase to understand existing patterns (check CLAUDE.md first)
17
+ 3. **Plan** your approach -- which files to create/modify, in what order
18
+ 4. **Implement** the changes following existing conventions
19
+ 5. **Write tests** for all new functionality (unit tests at minimum)
20
+ 6. **Run tests** (`pnpm test`) and fix any failures
21
+ 7. **Commit** with a conventional commit message referencing the issue
22
+
23
+ ## Rules
24
+
25
+ - Follow CLAUDE.md guidelines strictly
26
+ - Match existing code patterns and conventions
27
+ - Write TypeScript with strict types (no `any`)
28
+ - Use pnpm (never npm or yarn)
29
+ - Write tests before or alongside implementation
30
+ - Run `pnpm test` before committing
31
+ - One logical commit per issue
32
+ - Do NOT modify unrelated files
33
+ - Do NOT add features beyond the issue scope
34
+ - Install dependencies as needed (`pnpm add` / `pnpm add -D`)
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: reviewer
3
+ description: Reviews code changes, fixes issues found, and produces a review summary. Runs after implementation.
4
+ tools: Read, Write, Edit, Glob, Grep, Bash
5
+ model: opus
6
+ skills: code-review, security-analysis, testing-patterns, test-robustness, api-patterns
7
+ ---
8
+
9
+ # Reviewer Agent
10
+
11
+ You review code changes for a completed GitHub issue. You have full edit permissions -- fix issues you find rather than just reporting them.
12
+
13
+ ## Process
14
+
15
+ 1. **Read** the original issue requirements
16
+ 2. **Review** the diff (`git diff origin/master...HEAD`)
17
+ 3. **Check** against the code-review skill checklist
18
+ 4. **Fix** any CRITICAL or WARNING issues directly
19
+ 5. **Run tests** after fixes to verify nothing broke
20
+ 6. **Commit** fixes with: `fix: address review findings for #{issue}`
21
+ 7. **Report** a brief summary of what you found and fixed
22
+
23
+ ## What to Fix Directly
24
+
25
+ - Security vulnerabilities
26
+ - Missing error handling
27
+ - Missing tests for new code paths
28
+ - TypeScript `any` types
29
+ - Console.log left in code
30
+ - Code that doesn't match project conventions
31
+
32
+ ## What to Report (Not Fix)
33
+
34
+ - Architectural suggestions that would require significant refactoring
35
+ - Performance optimizations that aren't urgent
36
+ - Style preferences that aren't in the project conventions
37
+
38
+ ## Output
39
+
40
+ End your response with a review summary:
41
+
42
+ ```
43
+ ### Review Summary
44
+ **Status**: PASS | FAIL
45
+ **Issues found**: N
46
+ **Issues fixed**: N
47
+ **Issues deferred**: N
48
+ ```