@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.
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/agents/implementer.md +30 -0
- package/agents/reviewer.md +29 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +57 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +1 -0
- package/dist/commands/auth.js +89 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/history.d.ts +8 -0
- package/dist/commands/history.js +185 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +241 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/run.d.ts +15 -0
- package/dist/commands/run.js +321 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +1 -0
- package/dist/commands/scan.js +50 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sync.d.ts +20 -0
- package/dist/commands/sync.js +149 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/vision.d.ts +1 -0
- package/dist/commands/vision.js +194 -0
- package/dist/commands/vision.js.map +1 -0
- package/dist/engine/agents.d.ts +41 -0
- package/dist/engine/agents.js +90 -0
- package/dist/engine/agents.js.map +1 -0
- package/dist/engine/config.d.ts +71 -0
- package/dist/engine/config.js +73 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/prerequisites.d.ts +34 -0
- package/dist/engine/prerequisites.js +90 -0
- package/dist/engine/prerequisites.js.map +1 -0
- package/dist/lib/agent.d.ts +25 -0
- package/dist/lib/agent.js +97 -0
- package/dist/lib/agent.js.map +1 -0
- package/dist/lib/config.d.ts +35 -0
- package/dist/lib/config.js +179 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/context.d.ts +17 -0
- package/dist/lib/context.js +96 -0
- package/dist/lib/context.js.map +1 -0
- package/dist/lib/github.d.ts +61 -0
- package/dist/lib/github.js +313 -0
- package/dist/lib/github.js.map +1 -0
- package/dist/lib/learning.d.ts +43 -0
- package/dist/lib/learning.js +207 -0
- package/dist/lib/learning.js.map +1 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +28 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/pipeline.d.ts +18 -0
- package/dist/lib/pipeline.js +456 -0
- package/dist/lib/pipeline.js.map +1 -0
- package/dist/lib/preflight.d.ts +33 -0
- package/dist/lib/preflight.js +123 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/prerequisites.d.ts +12 -0
- package/dist/lib/prerequisites.js +54 -0
- package/dist/lib/prerequisites.js.map +1 -0
- package/dist/lib/prompts.d.ts +44 -0
- package/dist/lib/prompts.js +102 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/session.d.ts +28 -0
- package/dist/lib/session.js +173 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/shell.d.ts +32 -0
- package/dist/lib/shell.js +95 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/testing.d.ts +10 -0
- package/dist/lib/testing.js +51 -0
- package/dist/lib/testing.js.map +1 -0
- package/dist/lib/verify.d.ts +18 -0
- package/dist/lib/verify.js +235 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/vision.d.ts +9 -0
- package/dist/lib/vision.js +21 -0
- package/dist/lib/vision.js.map +1 -0
- package/dist/lib/worktree.d.ts +29 -0
- package/dist/lib/worktree.js +153 -0
- package/dist/lib/worktree.js.map +1 -0
- package/package.json +63 -0
- package/templates/agents/implementer.md +34 -0
- package/templates/agents/reviewer.md +48 -0
- package/templates/skills/code-review/SKILL.md +58 -0
- package/templates/skills/git-workflow/SKILL.md +53 -0
- package/templates/skills/implementation-planning/SKILL.md +64 -0
- package/templates/skills/security-analysis/SKILL.md +560 -0
- package/templates/skills/security-analysis/scripts/security-scanner.sh +227 -0
- package/templates/skills/test-robustness/SKILL.md +897 -0
- package/templates/skills/testing-patterns/SKILL.md +75 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { commandExists, execAsync } from './shell.js';
|
|
2
|
+
const AGENT_INSTALL_URLS = {
|
|
3
|
+
claude: 'https://claude.ai/code',
|
|
4
|
+
codex: 'https://github.com/openai/codex',
|
|
5
|
+
opencode: 'https://github.com/sst/opencode',
|
|
6
|
+
};
|
|
7
|
+
export class PrerequisiteError extends Error {
|
|
8
|
+
errors;
|
|
9
|
+
constructor(errors) {
|
|
10
|
+
super(errors.join('\n'));
|
|
11
|
+
this.errors = errors;
|
|
12
|
+
this.name = 'PrerequisiteError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Verify required tools are installed: gh, git, and the configured agent CLI.
|
|
17
|
+
* Throws PrerequisiteError with all failures if any checks fail.
|
|
18
|
+
*/
|
|
19
|
+
export async function checkPrerequisites(config) {
|
|
20
|
+
const errors = [];
|
|
21
|
+
// Check git
|
|
22
|
+
if (!commandExists('git')) {
|
|
23
|
+
errors.push('git not found. Please install git.');
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// Check we're in a git repo
|
|
27
|
+
const gitCheck = await execAsync('git rev-parse --git-dir');
|
|
28
|
+
if (gitCheck.exitCode !== 0) {
|
|
29
|
+
errors.push('Not in a git repository.');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Check gh CLI
|
|
33
|
+
if (!commandExists('gh')) {
|
|
34
|
+
errors.push('gh CLI not found. Install: https://cli.github.com/');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Check gh auth
|
|
38
|
+
const authCheck = await execAsync('gh auth status');
|
|
39
|
+
if (authCheck.exitCode !== 0) {
|
|
40
|
+
errors.push('gh not authenticated. Run: gh auth login');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check agent CLI
|
|
44
|
+
const agent = config.agent;
|
|
45
|
+
if (!commandExists(agent)) {
|
|
46
|
+
const installUrl = AGENT_INSTALL_URLS[agent] ?? '';
|
|
47
|
+
const installHint = installUrl ? ` Install: ${installUrl}` : '';
|
|
48
|
+
errors.push(`${agent} CLI not found.${installHint}`);
|
|
49
|
+
}
|
|
50
|
+
if (errors.length > 0) {
|
|
51
|
+
throw new PrerequisiteError(errors);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=prerequisites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prerequisites.js","sourceRoot":"","sources":["../../src/lib/prerequisites.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMtD,MAAM,kBAAkB,GAA2B;IACjD,MAAM,EAAE,wBAAwB;IAChC,KAAK,EAAE,iCAAiC;IACxC,QAAQ,EAAE,iCAAiC;CAC5C,CAAC;AAEF,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACd;IAA5B,YAA4B,MAAgB;QAC1C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QADC,WAAM,GAAN,MAAM,CAAU;QAE1C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAA0B;IACjE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,YAAY;IACZ,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,4BAA4B;QAC5B,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAC5D,IAAI,QAAQ,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,eAAe;IACf,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,gBAAgB;QAChB,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACpD,IAAI,SAAS,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,aAAa,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,kBAAkB,WAAW,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder — construct prompts for AI agents.
|
|
3
|
+
* Pure string template functions with no side effects.
|
|
4
|
+
*/
|
|
5
|
+
export type ImplementPromptOptions = {
|
|
6
|
+
issueNum: number;
|
|
7
|
+
title: string;
|
|
8
|
+
body: string;
|
|
9
|
+
visionContext?: string;
|
|
10
|
+
projectContext?: string;
|
|
11
|
+
previousResult?: string;
|
|
12
|
+
learningContext?: string;
|
|
13
|
+
};
|
|
14
|
+
export type ReviewPromptOptions = {
|
|
15
|
+
issueNum: number;
|
|
16
|
+
title: string;
|
|
17
|
+
body: string;
|
|
18
|
+
baseBranch: string;
|
|
19
|
+
visionContext?: string;
|
|
20
|
+
};
|
|
21
|
+
export type LearnPromptOptions = {
|
|
22
|
+
issueNum: number;
|
|
23
|
+
title: string;
|
|
24
|
+
status: string;
|
|
25
|
+
retries: number;
|
|
26
|
+
duration: number;
|
|
27
|
+
diff: string;
|
|
28
|
+
testOutput: string;
|
|
29
|
+
reviewOutput: string;
|
|
30
|
+
verifyOutput: string;
|
|
31
|
+
body?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Build the implementation prompt for an AI agent.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildImplementPrompt(options: ImplementPromptOptions): string;
|
|
37
|
+
/**
|
|
38
|
+
* Build the code review prompt for an AI agent.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildReviewPrompt(options: ReviewPromptOptions): string;
|
|
41
|
+
/**
|
|
42
|
+
* Build the learning extraction prompt.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildLearnPrompt(options: LearnPromptOptions): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Builder — construct prompts for AI agents.
|
|
3
|
+
* Pure string template functions with no side effects.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Build the implementation prompt for an AI agent.
|
|
7
|
+
*/
|
|
8
|
+
export function buildImplementPrompt(options) {
|
|
9
|
+
const { issueNum, title, body, visionContext, projectContext, previousResult, learningContext } = options;
|
|
10
|
+
const sections = [
|
|
11
|
+
`Implement GitHub issue #${issueNum}: ${title}`,
|
|
12
|
+
'',
|
|
13
|
+
body,
|
|
14
|
+
];
|
|
15
|
+
if (visionContext) {
|
|
16
|
+
sections.push('', '', '## Product Vision', visionContext);
|
|
17
|
+
}
|
|
18
|
+
if (projectContext) {
|
|
19
|
+
sections.push('', '', '## Technical Context', projectContext);
|
|
20
|
+
}
|
|
21
|
+
if (previousResult) {
|
|
22
|
+
sections.push('', '', previousResult);
|
|
23
|
+
}
|
|
24
|
+
if (learningContext) {
|
|
25
|
+
sections.push('', '', learningContext);
|
|
26
|
+
}
|
|
27
|
+
sections.push('', '## Before You Start', '1. Read the product vision and technical context above', '2. Make decisions that align with the target users and current priority', '3. Understand how your changes connect to existing code', "4. If you're creating new files, make sure they're wired into the appropriate entry points", '', '## After Implementing', '1. Write tests for your changes', '2. Run the test command to verify', `3. Commit with: git commit -m "feat: ${title} (closes #${issueNum})"`);
|
|
28
|
+
return sections.join('\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the code review prompt for an AI agent.
|
|
32
|
+
*/
|
|
33
|
+
export function buildReviewPrompt(options) {
|
|
34
|
+
const { issueNum, title, body, baseBranch, visionContext } = options;
|
|
35
|
+
const sections = [
|
|
36
|
+
`Review the code changes for issue #${issueNum}: ${title}`,
|
|
37
|
+
'',
|
|
38
|
+
`Run git diff origin/${baseBranch}...HEAD to see what changed. Then read the actual files that were modified.`,
|
|
39
|
+
'',
|
|
40
|
+
'Original requirements:',
|
|
41
|
+
body,
|
|
42
|
+
];
|
|
43
|
+
if (visionContext) {
|
|
44
|
+
sections.push('', '', '## Product Vision (guide your review decisions)', visionContext);
|
|
45
|
+
}
|
|
46
|
+
sections.push('', '## Review Checklist', '', '### 1. Functional Completeness (MOST IMPORTANT)', '- Does the implementation FULLY address the issue requirements?', '- Are there any acceptance criteria that were NOT implemented?', '- If backend API endpoints were created, are they called from the frontend?', '- If frontend components were created, do they have working backend endpoints?', '- Are there any dead code paths (created but never wired in)?', '- Does the feature work end-to-end (data flows from UI → API → database → back to UI)?', '', '### 2. Integration Gaps', '- Are new routes/endpoints registered in the server entry point?', '- Are new components imported and rendered in the app?', '- Are new database tables/columns used by the API?', '- Are there missing imports, missing route registrations, or orphaned files?', '', '### 3. Code Quality', '- Security issues (injection, XSS, auth bypass)', '- Missing error handling for user-facing operations', '- Missing tests for new functionality', '- Code follows project conventions', '', '### 4. UX Review', '- Do UI changes match the target user profile?', '- Are error states handled (loading, empty, error)?', '- Is the feature discoverable (can users find it)?', '', '## Actions', '', 'For any issues you find:', `- CRITICAL (gaps, missing wiring, broken features): FIX THEM directly, run tests, commit with "fix: address review findings for #${issueNum}"`, '- WARNING (quality, security): FIX THEM directly if possible', '- INFO (suggestions, minor improvements): Note them in your report but don\'t block', '', 'After fixing, output a structured review report:', '', '### Findings Fixed', '- (list what you found and fixed)', '', '### Remaining Gaps', '- (anything you couldn\'t fix — these need human attention)', '', '### Verification Notes', '- (what a human should manually check)');
|
|
47
|
+
return sections.join('\n');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build the learning extraction prompt.
|
|
51
|
+
*/
|
|
52
|
+
export function buildLearnPrompt(options) {
|
|
53
|
+
const { issueNum, title, status, retries, duration, diff, testOutput, reviewOutput, verifyOutput, body, } = options;
|
|
54
|
+
const today = new Date().toISOString().split('T')[0];
|
|
55
|
+
return `Analyze this completed development run. Output ONLY a markdown document with the exact structure below. Keep each section to 2-3 bullet points max. Be factual and concise -- no creative writing.
|
|
56
|
+
|
|
57
|
+
## Run Info
|
|
58
|
+
- Issue: #${issueNum} "${title}"
|
|
59
|
+
- Status: ${status}
|
|
60
|
+
- Retries: ${retries}
|
|
61
|
+
- Duration: ${duration}s
|
|
62
|
+
|
|
63
|
+
## Issue Requirements
|
|
64
|
+
${body || '(no description)'}
|
|
65
|
+
|
|
66
|
+
## Code Changes
|
|
67
|
+
${diff || '(no diff available)'}
|
|
68
|
+
|
|
69
|
+
## Test Results
|
|
70
|
+
${testOutput || '(no test output)'}
|
|
71
|
+
|
|
72
|
+
## Review Findings
|
|
73
|
+
${reviewOutput || '(no review output)'}
|
|
74
|
+
|
|
75
|
+
## Verification Results
|
|
76
|
+
${verifyOutput || '(no verification output)'}
|
|
77
|
+
|
|
78
|
+
Output ONLY this markdown structure, nothing else:
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
issue: ${issueNum}
|
|
82
|
+
status: ${status}
|
|
83
|
+
retries: ${retries}
|
|
84
|
+
duration: ${duration}
|
|
85
|
+
date: ${today}
|
|
86
|
+
---
|
|
87
|
+
## What Worked
|
|
88
|
+
- (list what went well)
|
|
89
|
+
|
|
90
|
+
## What Failed
|
|
91
|
+
- (list what went wrong, or "Nothing" if all passed)
|
|
92
|
+
|
|
93
|
+
## Patterns
|
|
94
|
+
- (reusable patterns discovered)
|
|
95
|
+
|
|
96
|
+
## Anti-Patterns
|
|
97
|
+
- (mistakes to avoid in future)
|
|
98
|
+
|
|
99
|
+
## Suggested Skill Updates
|
|
100
|
+
- (specific skill file changes, or "None")`;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
import type { PipelineResult } from './pipeline.js';
|
|
3
|
+
export type SessionContext = {
|
|
4
|
+
name: string;
|
|
5
|
+
branch: string;
|
|
6
|
+
resultsDir: string;
|
|
7
|
+
logsDir: string;
|
|
8
|
+
results: PipelineResult[];
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Create a new session context with timestamp-based name.
|
|
12
|
+
* Optionally creates a session branch when autoMerge is enabled.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSession(config: Config): SessionContext;
|
|
15
|
+
/**
|
|
16
|
+
* Save a pipeline result to the session directory as JSON.
|
|
17
|
+
*/
|
|
18
|
+
export declare function saveResult(session: SessionContext, result: PipelineResult): void;
|
|
19
|
+
/**
|
|
20
|
+
* Get the previous issue result formatted for prompt context.
|
|
21
|
+
* Returns null if no previous results exist.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getPreviousResult(session: SessionContext): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Finalize session: commit learnings to session branch, create session PR.
|
|
26
|
+
* Only runs when autoMerge is enabled and issues were processed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function finalizeSession(session: SessionContext, config: Config): Promise<string | null>;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Management — create sessions, save results, finalize with PR.
|
|
3
|
+
*/
|
|
4
|
+
import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { log } from './logger.js';
|
|
7
|
+
import { exec, formatTimestamp } from './shell.js';
|
|
8
|
+
import { createPR } from './github.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create a new session context with timestamp-based name.
|
|
11
|
+
* Optionally creates a session branch when autoMerge is enabled.
|
|
12
|
+
*/
|
|
13
|
+
export function createSession(config) {
|
|
14
|
+
const now = new Date();
|
|
15
|
+
const timestamp = formatTimestamp(now);
|
|
16
|
+
const name = `session/${timestamp}`;
|
|
17
|
+
const branch = config.mergeTo || name;
|
|
18
|
+
const projectDir = process.cwd();
|
|
19
|
+
const resultsDir = join(projectDir, '.alpha-loop', 'sessions', name);
|
|
20
|
+
const logsDir = join(resultsDir, 'logs');
|
|
21
|
+
mkdirSync(resultsDir, { recursive: true });
|
|
22
|
+
mkdirSync(logsDir, { recursive: true });
|
|
23
|
+
// Create session branch and draft PR if auto-merge is enabled
|
|
24
|
+
if (config.autoMerge && !config.dryRun) {
|
|
25
|
+
// Fetch latest to ensure we have remote refs
|
|
26
|
+
exec('git fetch origin', { cwd: projectDir });
|
|
27
|
+
const branchExists = exec(`git rev-parse --verify "${branch}"`, { cwd: projectDir });
|
|
28
|
+
if (branchExists.exitCode !== 0) {
|
|
29
|
+
// Create from remote base branch first, fall back to local
|
|
30
|
+
const fromRemote = exec(`git checkout -b "${branch}" "origin/${config.baseBranch}"`, { cwd: projectDir });
|
|
31
|
+
if (fromRemote.exitCode !== 0) {
|
|
32
|
+
exec(`git checkout -b "${branch}" "${config.baseBranch}"`, { cwd: projectDir });
|
|
33
|
+
}
|
|
34
|
+
// Push session branch to remote so PRs can target it
|
|
35
|
+
exec(`git push origin "${branch}"`, { cwd: projectDir });
|
|
36
|
+
// Switch back to the original branch
|
|
37
|
+
exec(`git checkout -`, { cwd: projectDir });
|
|
38
|
+
log.info(`Created session branch: ${branch}`);
|
|
39
|
+
// Create a draft PR immediately so the session is visible in GitHub
|
|
40
|
+
try {
|
|
41
|
+
const draftPR = createPR({
|
|
42
|
+
repo: config.repo,
|
|
43
|
+
base: config.baseBranch,
|
|
44
|
+
head: branch,
|
|
45
|
+
title: `Session: ${name}`,
|
|
46
|
+
body: `## Session In Progress\n\n**Branch:** ${branch}\n**Started:** ${new Date().toISOString()}\n\nThis PR will be updated as issues are processed.\n\n---\n*Automated by alpha-loop*`,
|
|
47
|
+
cwd: projectDir,
|
|
48
|
+
});
|
|
49
|
+
log.success(`Session PR (draft): ${draftPR}`);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Non-fatal — PR can be created later during finalization
|
|
53
|
+
log.warn('Could not create draft session PR — will create during finalization');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
log.info(`Session branch already exists: ${branch}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { name, branch, resultsDir, logsDir, results: [] };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Save a pipeline result to the session directory as JSON.
|
|
64
|
+
*/
|
|
65
|
+
export function saveResult(session, result) {
|
|
66
|
+
const filePath = join(session.resultsDir, `result-${result.issueNum}.json`);
|
|
67
|
+
writeFileSync(filePath, JSON.stringify(result, null, 2) + '\n');
|
|
68
|
+
log.info(`Session result saved: ${filePath}`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the previous issue result formatted for prompt context.
|
|
72
|
+
* Returns null if no previous results exist.
|
|
73
|
+
*/
|
|
74
|
+
export function getPreviousResult(session) {
|
|
75
|
+
if (session.results.length === 0)
|
|
76
|
+
return null;
|
|
77
|
+
const prev = session.results[session.results.length - 1];
|
|
78
|
+
return `## Previous Issue in This Session
|
|
79
|
+
- Issue #${prev.issueNum}: ${prev.title}
|
|
80
|
+
- Status: ${prev.status}
|
|
81
|
+
- Tests: ${prev.testsPassing ? 'PASSING' : 'FAILING'}
|
|
82
|
+
- Files changed: ${prev.filesChanged}
|
|
83
|
+
- Duration: ${prev.duration}s
|
|
84
|
+
${prev.prUrl ? `- PR: ${prev.prUrl}` : ''}
|
|
85
|
+
|
|
86
|
+
Build on what was already done. Avoid duplicating work.`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Finalize session: commit learnings to session branch, create session PR.
|
|
90
|
+
* Only runs when autoMerge is enabled and issues were processed.
|
|
91
|
+
*/
|
|
92
|
+
export async function finalizeSession(session, config) {
|
|
93
|
+
if (!config.autoMerge)
|
|
94
|
+
return null;
|
|
95
|
+
if (session.branch === config.baseBranch)
|
|
96
|
+
return null;
|
|
97
|
+
if (session.results.length === 0)
|
|
98
|
+
return null;
|
|
99
|
+
if (config.dryRun) {
|
|
100
|
+
log.dry(`Would finalize session: ${session.branch} -> ${config.baseBranch}`);
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
log.step(`Finalizing session: ${session.branch}`);
|
|
104
|
+
const projectDir = process.cwd();
|
|
105
|
+
// Ensure we're on the session branch
|
|
106
|
+
exec('git fetch origin', { cwd: projectDir });
|
|
107
|
+
const checkout = exec(`git checkout "${session.branch}"`, { cwd: projectDir });
|
|
108
|
+
if (checkout.exitCode !== 0) {
|
|
109
|
+
log.warn('Could not checkout session branch for finalization');
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
// Stage learnings
|
|
113
|
+
const learningsDir = join(projectDir, '.alpha-loop', 'learnings');
|
|
114
|
+
if (existsSync(learningsDir)) {
|
|
115
|
+
exec('git add .alpha-loop/learnings/', { cwd: projectDir });
|
|
116
|
+
}
|
|
117
|
+
// Commit if there are staged changes
|
|
118
|
+
const diffResult = exec('git diff --cached --quiet', { cwd: projectDir });
|
|
119
|
+
if (diffResult.exitCode !== 0) {
|
|
120
|
+
const commitIssueCount = session.results.length;
|
|
121
|
+
exec(`git commit -m "chore: learnings from ${session.name}\n\nProcessed ${commitIssueCount} issue(s) in this session."`, { cwd: projectDir });
|
|
122
|
+
exec(`git push origin "${session.branch}"`, { cwd: projectDir });
|
|
123
|
+
}
|
|
124
|
+
// Create or update session PR
|
|
125
|
+
const issueCount = session.results.length;
|
|
126
|
+
const successCount = session.results.filter((r) => r.status === 'success').length;
|
|
127
|
+
const failureCount = issueCount - successCount;
|
|
128
|
+
const totalDuration = session.results.reduce((sum, r) => sum + r.duration, 0);
|
|
129
|
+
const prTitle = `Session: ${session.name} — ${successCount}/${issueCount} succeeded`;
|
|
130
|
+
const prBody = `## Session Summary
|
|
131
|
+
|
|
132
|
+
**Branch:** ${session.branch}
|
|
133
|
+
**Issues processed:** ${issueCount} (${successCount} succeeded, ${failureCount} failed)
|
|
134
|
+
**Total duration:** ${Math.round(totalDuration / 60)} minutes
|
|
135
|
+
**Completed:** ${new Date().toISOString()}
|
|
136
|
+
|
|
137
|
+
### Issues
|
|
138
|
+
${session.results.map((r) => `- #${r.issueNum}: ${r.title} — ${r.status === 'success' ? 'SUCCESS' : 'FAILURE'}${r.prUrl ? ` ([PR](${r.prUrl}))` : ''}`).join('\n')}
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
This PR collects all changes from this session for final review before merging to ${config.baseBranch}.
|
|
142
|
+
|
|
143
|
+
Automated by alpha-loop`;
|
|
144
|
+
try {
|
|
145
|
+
const prUrl = createPR({
|
|
146
|
+
repo: config.repo,
|
|
147
|
+
base: config.baseBranch,
|
|
148
|
+
head: session.branch,
|
|
149
|
+
title: prTitle,
|
|
150
|
+
body: prBody,
|
|
151
|
+
cwd: projectDir,
|
|
152
|
+
});
|
|
153
|
+
log.success(`Session PR: ${prUrl}`);
|
|
154
|
+
return prUrl;
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
// If createPR failed (e.g. nothing to compare), try creating via gh directly
|
|
158
|
+
log.warn(`createPR failed: ${err instanceof Error ? err.message : err}`);
|
|
159
|
+
try {
|
|
160
|
+
const fallback = exec(`gh pr create --repo "${config.repo}" --base "${config.baseBranch}" --head "${session.branch}" --title "${prTitle}" --body "Session finalization — see branch for details"`, { cwd: projectDir });
|
|
161
|
+
if (fallback.exitCode === 0 && fallback.stdout.trim()) {
|
|
162
|
+
log.success(`Session PR (fallback): ${fallback.stdout.trim()}`);
|
|
163
|
+
return fallback.stdout.trim();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Fall through
|
|
168
|
+
}
|
|
169
|
+
log.warn('Could not create session PR — check branch manually');
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/lib/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type ExecResult = {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
exitCode: number;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Execute a shell command synchronously and return structured result.
|
|
8
|
+
* Does not throw on non-zero exit — returns exitCode instead.
|
|
9
|
+
*/
|
|
10
|
+
export declare function exec(command: string, options?: {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
env?: Record<string, string>;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}): ExecResult;
|
|
15
|
+
/**
|
|
16
|
+
* Run a shell command asynchronously. Does not throw on non-zero exit.
|
|
17
|
+
*/
|
|
18
|
+
export declare function execAsync(cmd: string, cwd?: string): Promise<ExecResult>;
|
|
19
|
+
/** Run a command with streaming output. Returns exit code. */
|
|
20
|
+
export declare function run(cmd: string, args: string[], options?: {
|
|
21
|
+
cwd?: string;
|
|
22
|
+
onStdout?: (line: string) => void;
|
|
23
|
+
onStderr?: (line: string) => void;
|
|
24
|
+
}): Promise<number>;
|
|
25
|
+
/**
|
|
26
|
+
* Check whether a command exists on the system PATH.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Format a Date as YYYYMMDD-HHMMSS for filenames and session names.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatTimestamp(date: Date): string;
|
|
32
|
+
export declare function commandExists(cmd: string): boolean;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell execution helpers.
|
|
3
|
+
*/
|
|
4
|
+
import { execSync as nodeExecSync, exec as nodeExec, spawn } from 'node:child_process';
|
|
5
|
+
import * as readline from 'node:readline';
|
|
6
|
+
/** Max buffer for async exec output (10 MB). */
|
|
7
|
+
const EXEC_MAX_BUFFER = 10 * 1024 * 1024;
|
|
8
|
+
/**
|
|
9
|
+
* Execute a shell command synchronously and return structured result.
|
|
10
|
+
* Does not throw on non-zero exit — returns exitCode instead.
|
|
11
|
+
*/
|
|
12
|
+
export function exec(command, options) {
|
|
13
|
+
try {
|
|
14
|
+
const stdout = nodeExecSync(command, {
|
|
15
|
+
cwd: options?.cwd,
|
|
16
|
+
env: options?.env ? { ...process.env, ...options.env } : undefined,
|
|
17
|
+
timeout: options?.timeout,
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
20
|
+
});
|
|
21
|
+
return { stdout: stdout.trim(), stderr: '', exitCode: 0 };
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const e = err;
|
|
25
|
+
return {
|
|
26
|
+
stdout: (e.stdout ?? '').toString().trim(),
|
|
27
|
+
stderr: (e.stderr ?? '').toString().trim(),
|
|
28
|
+
exitCode: e.status ?? 1,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Run a shell command asynchronously. Does not throw on non-zero exit.
|
|
34
|
+
*/
|
|
35
|
+
export async function execAsync(cmd, cwd) {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
nodeExec(cmd, { cwd, maxBuffer: EXEC_MAX_BUFFER }, (error, stdout, stderr) => {
|
|
38
|
+
let exitCode = 0;
|
|
39
|
+
if (error) {
|
|
40
|
+
const execErr = error;
|
|
41
|
+
exitCode = typeof execErr.code === 'number' ? execErr.code : 1;
|
|
42
|
+
}
|
|
43
|
+
resolve({
|
|
44
|
+
stdout: stdout?.toString() ?? '',
|
|
45
|
+
stderr: stderr?.toString() ?? '',
|
|
46
|
+
exitCode,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Run a command with streaming output. Returns exit code. */
|
|
52
|
+
export function run(cmd, args, options) {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
const child = spawn(cmd, args, {
|
|
55
|
+
cwd: options?.cwd,
|
|
56
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
+
});
|
|
58
|
+
if (child.stdout) {
|
|
59
|
+
const rl = readline.createInterface({ input: child.stdout });
|
|
60
|
+
rl.on('line', (line) => options?.onStdout?.(line));
|
|
61
|
+
}
|
|
62
|
+
if (child.stderr) {
|
|
63
|
+
const rl = readline.createInterface({ input: child.stderr });
|
|
64
|
+
rl.on('line', (line) => options?.onStderr?.(line));
|
|
65
|
+
}
|
|
66
|
+
child.on('close', (code) => resolve(code ?? 1));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check whether a command exists on the system PATH.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* Format a Date as YYYYMMDD-HHMMSS for filenames and session names.
|
|
74
|
+
*/
|
|
75
|
+
export function formatTimestamp(date) {
|
|
76
|
+
const y = date.getFullYear();
|
|
77
|
+
const mo = String(date.getMonth() + 1).padStart(2, '0');
|
|
78
|
+
const d = String(date.getDate()).padStart(2, '0');
|
|
79
|
+
const h = String(date.getHours()).padStart(2, '0');
|
|
80
|
+
const mi = String(date.getMinutes()).padStart(2, '0');
|
|
81
|
+
const s = String(date.getSeconds()).padStart(2, '0');
|
|
82
|
+
return `${y}${mo}${d}-${h}${mi}${s}`;
|
|
83
|
+
}
|
|
84
|
+
export function commandExists(cmd) {
|
|
85
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(cmd))
|
|
86
|
+
return false;
|
|
87
|
+
try {
|
|
88
|
+
nodeExecSync(`command -v "${cmd}"`, { stdio: 'ignore' });
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/lib/shell.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
export type TestResult = {
|
|
3
|
+
passed: boolean;
|
|
4
|
+
output: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Run the configured test command in a worktree.
|
|
8
|
+
* Returns structured result instead of throwing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runTests(worktree: string, config: Config, logFile: string): TestResult;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Runner — execute tests in worktrees with retry support.
|
|
3
|
+
*/
|
|
4
|
+
import { appendFileSync } from 'node:fs';
|
|
5
|
+
import { exec } from './shell.js';
|
|
6
|
+
import { log } from './logger.js';
|
|
7
|
+
/** Test runner timeout (5 minutes). */
|
|
8
|
+
const TEST_TIMEOUT_MS = 300_000;
|
|
9
|
+
/**
|
|
10
|
+
* Run the configured test command in a worktree.
|
|
11
|
+
* Returns structured result instead of throwing.
|
|
12
|
+
*/
|
|
13
|
+
export function runTests(worktree, config, logFile) {
|
|
14
|
+
if (config.skipTests) {
|
|
15
|
+
log.info('Tests skipped (skipTests=true)');
|
|
16
|
+
return { passed: true, output: 'Tests skipped' };
|
|
17
|
+
}
|
|
18
|
+
if (config.dryRun) {
|
|
19
|
+
log.dry('Would run tests in worktree');
|
|
20
|
+
return { passed: true, output: 'Tests skipped (dry run)' };
|
|
21
|
+
}
|
|
22
|
+
log.step(`Running tests: ${config.testCommand}`);
|
|
23
|
+
const env = {};
|
|
24
|
+
if (config.runFull) {
|
|
25
|
+
env.RECORD_FIXTURES = 'true';
|
|
26
|
+
}
|
|
27
|
+
const result = exec(config.testCommand, {
|
|
28
|
+
cwd: worktree,
|
|
29
|
+
env: Object.keys(env).length > 0 ? env : undefined,
|
|
30
|
+
timeout: TEST_TIMEOUT_MS,
|
|
31
|
+
});
|
|
32
|
+
// Append test output to log file
|
|
33
|
+
if (logFile) {
|
|
34
|
+
try {
|
|
35
|
+
appendFileSync(logFile, `\n--- Test Output ---\n${result.stdout}\n${result.stderr}\n`);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Log file write failure is non-fatal
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const output = result.stdout + (result.stderr ? `\n${result.stderr}` : '');
|
|
42
|
+
if (result.exitCode === 0) {
|
|
43
|
+
log.success('All tests passed');
|
|
44
|
+
return { passed: true, output };
|
|
45
|
+
}
|
|
46
|
+
log.warn(`Tests failed (exit code ${result.exitCode})`);
|
|
47
|
+
return { passed: false, output };
|
|
48
|
+
}
|
|
49
|
+
// Note: Live verification (playwright-cli) is in src/lib/verify.ts
|
|
50
|
+
// This module only handles unit/integration test execution.
|
|
51
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/lib/testing.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,uCAAuC;AACvC,MAAM,eAAe,GAAG,OAAO,CAAC;AAOhC;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB,EAAE,MAAc,EAAE,OAAe;IACxE,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC3C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACnD,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,GAAG,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACvC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC;IAC7D,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC;IAC/B,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;QACtC,GAAG,EAAE,QAAQ;QACb,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QAClD,OAAO,EAAE,eAAe;KACzB,CAAC,CAAC;IAEH,iCAAiC;IACjC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,cAAc,CAAC,OAAO,EAAE,0BAA0B,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;QACzF,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE3E,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC1B,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IACxD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACnC,CAAC;AAED,mEAAmE;AACnE,4DAA4D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
export type VerifyResult = {
|
|
3
|
+
passed: boolean;
|
|
4
|
+
output: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Run live verification using playwright-cli.
|
|
8
|
+
* Starts the app, sends agent to test it, returns result.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runVerify(options: {
|
|
11
|
+
worktree: string;
|
|
12
|
+
logFile: string;
|
|
13
|
+
issueNum: number;
|
|
14
|
+
title: string;
|
|
15
|
+
body: string;
|
|
16
|
+
config: Config;
|
|
17
|
+
sessionDir: string;
|
|
18
|
+
}): Promise<VerifyResult>;
|