wiggum-cli 0.16.0 → 0.17.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/bin/ralph.js +0 -0
- package/dist/agent/memory/ingest.d.ts +14 -0
- package/dist/agent/memory/ingest.js +77 -0
- package/dist/agent/memory/store.d.ts +15 -0
- package/dist/agent/memory/store.js +98 -0
- package/dist/agent/memory/types.d.ts +16 -0
- package/dist/agent/memory/types.js +14 -0
- package/dist/agent/orchestrator.d.ts +7 -0
- package/dist/agent/orchestrator.js +266 -0
- package/dist/agent/resolve-config.d.ts +26 -0
- package/dist/agent/resolve-config.js +43 -0
- package/dist/agent/tools/backlog.d.ts +27 -0
- package/dist/agent/tools/backlog.js +51 -0
- package/dist/agent/tools/dry-run.d.ts +106 -0
- package/dist/agent/tools/dry-run.js +119 -0
- package/dist/agent/tools/execution.d.ts +51 -0
- package/dist/agent/tools/execution.js +256 -0
- package/dist/agent/tools/feature-state.d.ts +43 -0
- package/dist/agent/tools/feature-state.js +184 -0
- package/dist/agent/tools/introspection.d.ts +23 -0
- package/dist/agent/tools/introspection.js +40 -0
- package/dist/agent/tools/memory.d.ts +44 -0
- package/dist/agent/tools/memory.js +99 -0
- package/dist/agent/tools/preflight.d.ts +7 -0
- package/dist/agent/tools/preflight.js +137 -0
- package/dist/agent/tools/reporting.d.ts +58 -0
- package/dist/agent/tools/reporting.js +119 -0
- package/dist/agent/tools/schemas.d.ts +2 -0
- package/dist/agent/tools/schemas.js +3 -0
- package/dist/agent/types.d.ts +45 -0
- package/dist/agent/types.js +1 -0
- package/dist/ai/conversation/conversation-manager.js +8 -0
- package/dist/ai/conversation/url-fetcher.js +27 -0
- package/dist/ai/providers.js +5 -5
- package/dist/commands/agent.d.ts +17 -0
- package/dist/commands/agent.js +114 -0
- package/dist/commands/monitor.js +50 -183
- package/dist/commands/new-auto.d.ts +15 -0
- package/dist/commands/new-auto.js +237 -0
- package/dist/commands/run.js +20 -10
- package/dist/commands/sync.d.ts +15 -0
- package/dist/commands/sync.js +68 -0
- package/dist/generator/config.d.ts +1 -41
- package/dist/generator/config.js +7 -0
- package/dist/generator/index.d.ts +2 -2
- package/dist/generator/templates.d.ts +2 -0
- package/dist/generator/templates.js +9 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +115 -4
- package/dist/repl/command-parser.d.ts +5 -0
- package/dist/repl/command-parser.js +5 -0
- package/dist/templates/prompts/PROMPT.md.tmpl +13 -10
- package/dist/templates/prompts/PROMPT_e2e.md.tmpl +13 -7
- package/dist/templates/prompts/PROMPT_feature.md.tmpl +16 -3
- package/dist/templates/prompts/PROMPT_review_auto.md.tmpl +32 -12
- package/dist/templates/prompts/PROMPT_review_manual.md.tmpl +4 -1
- package/dist/templates/prompts/PROMPT_review_merge.md.tmpl +39 -14
- package/dist/templates/prompts/PROMPT_verify.md.tmpl +5 -2
- package/dist/templates/scripts/feature-loop.sh.tmpl +441 -69
- package/dist/tui/app.d.ts +19 -2
- package/dist/tui/app.js +22 -4
- package/dist/tui/components/IssuePicker.d.ts +27 -0
- package/dist/tui/components/IssuePicker.js +64 -0
- package/dist/tui/components/RunCompletionSummary.js +6 -3
- package/dist/tui/hooks/useAgentOrchestrator.d.ts +29 -0
- package/dist/tui/hooks/useAgentOrchestrator.js +453 -0
- package/dist/tui/orchestration/interview-orchestrator.d.ts +5 -1
- package/dist/tui/orchestration/interview-orchestrator.js +27 -6
- package/dist/tui/screens/AgentScreen.d.ts +21 -0
- package/dist/tui/screens/AgentScreen.js +159 -0
- package/dist/tui/screens/InitScreen.js +4 -0
- package/dist/tui/screens/InterviewScreen.d.ts +3 -1
- package/dist/tui/screens/InterviewScreen.js +146 -10
- package/dist/tui/screens/MainShell.d.ts +1 -1
- package/dist/tui/screens/MainShell.js +36 -1
- package/dist/tui/screens/RunScreen.js +38 -6
- package/dist/tui/utils/build-run-summary.d.ts +1 -1
- package/dist/tui/utils/build-run-summary.js +40 -84
- package/dist/tui/utils/clear-screen.d.ts +14 -0
- package/dist/tui/utils/clear-screen.js +16 -0
- package/dist/tui/utils/loop-status.d.ts +41 -1
- package/dist/tui/utils/loop-status.js +243 -35
- package/dist/tui/utils/pr-summary.d.ts +3 -2
- package/dist/tui/utils/pr-summary.js +41 -6
- package/dist/utils/config.d.ts +8 -0
- package/dist/utils/config.js +8 -0
- package/dist/utils/github.d.ts +32 -0
- package/dist/utils/github.js +106 -0
- package/package.json +4 -1
- package/src/templates/prompts/PROMPT.md.tmpl +13 -10
- package/src/templates/prompts/PROMPT_e2e.md.tmpl +13 -7
- package/src/templates/prompts/PROMPT_feature.md.tmpl +16 -3
- package/src/templates/prompts/PROMPT_review_auto.md.tmpl +32 -12
- package/src/templates/prompts/PROMPT_review_manual.md.tmpl +4 -1
- package/src/templates/prompts/PROMPT_review_merge.md.tmpl +39 -14
- package/src/templates/prompts/PROMPT_verify.md.tmpl +5 -2
- package/src/templates/scripts/feature-loop.sh.tmpl +441 -69
|
@@ -24,11 +24,12 @@ export interface IssueInfo {
|
|
|
24
24
|
export declare function getPrForBranch(projectRoot: string, branchName: string): PrInfo | null;
|
|
25
25
|
/**
|
|
26
26
|
* Get linked issue for a branch by parsing the PR body for closing keywords
|
|
27
|
-
* (Closes/Fixes/Resolves #N).
|
|
27
|
+
* (Closes/Fixes/Resolves #N), with fallbacks for spec file and feature name search.
|
|
28
28
|
*
|
|
29
29
|
* @param projectRoot - Root directory of the git repository
|
|
30
30
|
* @param branchName - Branch name to look up
|
|
31
31
|
* @param prInfo - Optional pre-fetched PR info to avoid redundant gh call
|
|
32
|
+
* @param featureName - Optional feature name for fallback issue detection
|
|
32
33
|
* @returns Issue info object, or null if not found or gh not available
|
|
33
34
|
*/
|
|
34
|
-
export declare function getLinkedIssue(projectRoot: string, branchName: string, prInfo?: PrInfo | null): IssueInfo | null;
|
|
35
|
+
export declare function getLinkedIssue(projectRoot: string, branchName: string, prInfo?: PrInfo | null, featureName?: string): IssueInfo | null;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* PR and Issue utilities for enhanced run summary.
|
|
3
3
|
*/
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
5
7
|
import { logger } from '../../utils/logger.js';
|
|
6
8
|
/**
|
|
7
9
|
* Get PR information for a branch.
|
|
@@ -33,16 +35,51 @@ export function getPrForBranch(projectRoot, branchName) {
|
|
|
33
35
|
title: pr.title,
|
|
34
36
|
};
|
|
35
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Extract issue number from PR body closing keywords or fallback strategies.
|
|
40
|
+
*/
|
|
41
|
+
function findIssueNumber(body, featureName, projectRoot) {
|
|
42
|
+
// Strategy 1: Closing keywords in PR body (Closes/Fixes/Resolves #N)
|
|
43
|
+
const issueMatch = body.match(/(?:closes|fixes|resolves)\s+#(\d+)/i);
|
|
44
|
+
if (issueMatch) {
|
|
45
|
+
return parseInt(issueMatch[1], 10);
|
|
46
|
+
}
|
|
47
|
+
// Strategy 2: Bare "#N" references in the body (e.g., "Closes #7" without keyword before it)
|
|
48
|
+
// Look for "# N" patterns that are likely issue references (not markdown headers)
|
|
49
|
+
const hashRefMatch = body.match(/(?:^|\s)#(\d+)\b/m);
|
|
50
|
+
if (hashRefMatch) {
|
|
51
|
+
return parseInt(hashRefMatch[1], 10);
|
|
52
|
+
}
|
|
53
|
+
// Strategy 3: Read spec file for issue reference
|
|
54
|
+
if (featureName && projectRoot) {
|
|
55
|
+
try {
|
|
56
|
+
const specPath = join(projectRoot, '.ralph', 'specs', `${featureName}.md`);
|
|
57
|
+
if (existsSync(specPath)) {
|
|
58
|
+
const specContent = readFileSync(specPath, 'utf-8');
|
|
59
|
+
// Look for "Issue: #N", "Source Issue: #N", "GitHub Issue: #N", or issue URLs
|
|
60
|
+
const specIssueMatch = specContent.match(/(?:issue|source|github)[:\s]*#(\d+)/i) || specContent.match(/github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/i);
|
|
61
|
+
if (specIssueMatch) {
|
|
62
|
+
return parseInt(specIssueMatch[1], 10);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// spec read failure is non-fatal
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
36
72
|
/**
|
|
37
73
|
* Get linked issue for a branch by parsing the PR body for closing keywords
|
|
38
|
-
* (Closes/Fixes/Resolves #N).
|
|
74
|
+
* (Closes/Fixes/Resolves #N), with fallbacks for spec file and feature name search.
|
|
39
75
|
*
|
|
40
76
|
* @param projectRoot - Root directory of the git repository
|
|
41
77
|
* @param branchName - Branch name to look up
|
|
42
78
|
* @param prInfo - Optional pre-fetched PR info to avoid redundant gh call
|
|
79
|
+
* @param featureName - Optional feature name for fallback issue detection
|
|
43
80
|
* @returns Issue info object, or null if not found or gh not available
|
|
44
81
|
*/
|
|
45
|
-
export function getLinkedIssue(projectRoot, branchName, prInfo) {
|
|
82
|
+
export function getLinkedIssue(projectRoot, branchName, prInfo, featureName) {
|
|
46
83
|
try {
|
|
47
84
|
// Use provided PR info or fetch it
|
|
48
85
|
const pr = prInfo !== undefined ? prInfo : getPrForBranch(projectRoot, branchName);
|
|
@@ -57,12 +94,10 @@ export function getLinkedIssue(projectRoot, branchName, prInfo) {
|
|
|
57
94
|
}).trim();
|
|
58
95
|
const prData = JSON.parse(prBody);
|
|
59
96
|
const body = prData.body || '';
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!issueMatch) {
|
|
97
|
+
const issueNumber = findIssueNumber(body, featureName, projectRoot);
|
|
98
|
+
if (!issueNumber) {
|
|
63
99
|
return null;
|
|
64
100
|
}
|
|
65
|
-
const issueNumber = parseInt(issueMatch[1], 10);
|
|
66
101
|
// Fetch the issue details
|
|
67
102
|
const issueOutput = execFileSync('gh', ['issue', 'view', String(issueNumber), '--json', 'number,url,state,title'], {
|
|
68
103
|
cwd: projectRoot,
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -50,6 +50,13 @@ export interface LoopConfig {
|
|
|
50
50
|
planningModel: string;
|
|
51
51
|
reviewMode: 'manual' | 'auto' | 'merge';
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Agent configuration in ralph.config.cjs
|
|
55
|
+
*/
|
|
56
|
+
export interface AgentSectionConfig {
|
|
57
|
+
defaultProvider: string;
|
|
58
|
+
defaultModel: string;
|
|
59
|
+
}
|
|
53
60
|
/**
|
|
54
61
|
* Full ralph.config.cjs structure
|
|
55
62
|
*/
|
|
@@ -59,6 +66,7 @@ export interface RalphConfig {
|
|
|
59
66
|
commands: CommandsConfig;
|
|
60
67
|
paths: PathsConfig;
|
|
61
68
|
loop: LoopConfig;
|
|
69
|
+
agent: AgentSectionConfig;
|
|
62
70
|
}
|
|
63
71
|
/**
|
|
64
72
|
* Default configuration values
|
package/dist/utils/config.js
CHANGED
|
@@ -47,6 +47,10 @@ export const DEFAULT_CONFIG = {
|
|
|
47
47
|
planningModel: 'opus',
|
|
48
48
|
reviewMode: 'manual',
|
|
49
49
|
},
|
|
50
|
+
agent: {
|
|
51
|
+
defaultProvider: '',
|
|
52
|
+
defaultModel: '',
|
|
53
|
+
},
|
|
50
54
|
};
|
|
51
55
|
/**
|
|
52
56
|
* Load ralph.config.cjs from a project directory
|
|
@@ -104,6 +108,10 @@ export async function loadConfigWithDefaults(projectRoot) {
|
|
|
104
108
|
...DEFAULT_CONFIG.loop,
|
|
105
109
|
...config.loop,
|
|
106
110
|
},
|
|
111
|
+
agent: {
|
|
112
|
+
...DEFAULT_CONFIG.agent,
|
|
113
|
+
...config?.agent,
|
|
114
|
+
},
|
|
107
115
|
};
|
|
108
116
|
}
|
|
109
117
|
/**
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare function isGhInstalled(): Promise<boolean>;
|
|
2
|
+
export declare function _resetGhCache(): void;
|
|
3
|
+
export interface GitHubIssueDetail {
|
|
4
|
+
title: string;
|
|
5
|
+
body: string;
|
|
6
|
+
labels: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function fetchGitHubIssue(owner: string, repo: string, number: number): Promise<GitHubIssueDetail | null>;
|
|
9
|
+
export interface GitHubIssueListItem {
|
|
10
|
+
number: number;
|
|
11
|
+
title: string;
|
|
12
|
+
state: 'open' | 'closed';
|
|
13
|
+
labels: string[];
|
|
14
|
+
createdAt: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ListIssuesResult {
|
|
17
|
+
issues: GitHubIssueListItem[];
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function listRepoIssues(owner: string, repo: string, search?: string, limit?: number): Promise<ListIssuesResult>;
|
|
21
|
+
export declare function detectGitHubRemote(projectRoot: string): Promise<GitHubRepo | null>;
|
|
22
|
+
export interface ParsedGitHubIssue {
|
|
23
|
+
owner: string;
|
|
24
|
+
repo: string;
|
|
25
|
+
number: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function isGitHubIssueUrl(input: string): ParsedGitHubIssue | null;
|
|
28
|
+
export interface GitHubRepo {
|
|
29
|
+
owner: string;
|
|
30
|
+
repo: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function parseGitHubRemote(remoteUrl: string): GitHubRepo | null;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { execFile as execFileCb } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Safe command execution using execFile (no shell, array-based args).
|
|
4
|
+
*/
|
|
5
|
+
function safeExec(cmd, args, cwd) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
execFileCb(cmd, args, { cwd, timeout: 10000 }, (error, stdout) => {
|
|
8
|
+
if (error)
|
|
9
|
+
reject(error);
|
|
10
|
+
else
|
|
11
|
+
resolve(String(stdout));
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
let ghInstalledCache = null;
|
|
16
|
+
export async function isGhInstalled() {
|
|
17
|
+
if (ghInstalledCache !== null)
|
|
18
|
+
return ghInstalledCache;
|
|
19
|
+
try {
|
|
20
|
+
await safeExec('gh', ['--version']);
|
|
21
|
+
ghInstalledCache = true;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
ghInstalledCache = false;
|
|
25
|
+
}
|
|
26
|
+
return ghInstalledCache;
|
|
27
|
+
}
|
|
28
|
+
export function _resetGhCache() {
|
|
29
|
+
ghInstalledCache = null;
|
|
30
|
+
}
|
|
31
|
+
export async function fetchGitHubIssue(owner, repo, number) {
|
|
32
|
+
try {
|
|
33
|
+
const stdout = await safeExec('gh', [
|
|
34
|
+
'issue', 'view', String(number),
|
|
35
|
+
'--repo', `${owner}/${repo}`,
|
|
36
|
+
'--json', 'title,body,labels',
|
|
37
|
+
]);
|
|
38
|
+
const data = JSON.parse(stdout);
|
|
39
|
+
return {
|
|
40
|
+
title: data.title ?? '',
|
|
41
|
+
body: data.body ?? '',
|
|
42
|
+
labels: (data.labels ?? []).map((l) => l.name),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function listRepoIssues(owner, repo, search, limit = 20) {
|
|
50
|
+
try {
|
|
51
|
+
const args = [
|
|
52
|
+
'issue', 'list',
|
|
53
|
+
'--repo', `${owner}/${repo}`,
|
|
54
|
+
'--limit', String(limit),
|
|
55
|
+
'--json', 'number,title,state,labels,createdAt',
|
|
56
|
+
'--state', 'open',
|
|
57
|
+
];
|
|
58
|
+
if (search) {
|
|
59
|
+
args.push('--search', search);
|
|
60
|
+
}
|
|
61
|
+
const stdout = await safeExec('gh', args);
|
|
62
|
+
const data = JSON.parse(stdout);
|
|
63
|
+
const issues = data.map((item) => ({
|
|
64
|
+
number: item.number,
|
|
65
|
+
title: item.title,
|
|
66
|
+
state: item.state.toLowerCase(),
|
|
67
|
+
labels: (item.labels ?? []).map((l) => l.name),
|
|
68
|
+
createdAt: item.createdAt ?? '',
|
|
69
|
+
}));
|
|
70
|
+
return { issues };
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
if (msg.includes('auth') || msg.includes('login') || msg.includes('not logged')) {
|
|
75
|
+
return { issues: [], error: 'Run "gh auth login" to enable issue browsing' };
|
|
76
|
+
}
|
|
77
|
+
return { issues: [] };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function detectGitHubRemote(projectRoot) {
|
|
81
|
+
try {
|
|
82
|
+
const stdout = await safeExec('git', ['remote', 'get-url', 'origin'], projectRoot);
|
|
83
|
+
return parseGitHubRemote(stdout.trim());
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const GITHUB_ISSUE_RE = /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/(issues|pull)\/(\d+)\/?/;
|
|
90
|
+
export function isGitHubIssueUrl(input) {
|
|
91
|
+
const match = input.match(GITHUB_ISSUE_RE);
|
|
92
|
+
if (!match)
|
|
93
|
+
return null;
|
|
94
|
+
return { owner: match[1], repo: match[2], number: parseInt(match[4], 10) };
|
|
95
|
+
}
|
|
96
|
+
const SSH_REMOTE_RE = /^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/;
|
|
97
|
+
const HTTPS_REMOTE_RE = /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/;
|
|
98
|
+
export function parseGitHubRemote(remoteUrl) {
|
|
99
|
+
const ssh = remoteUrl.match(SSH_REMOTE_RE);
|
|
100
|
+
if (ssh)
|
|
101
|
+
return { owner: ssh[1], repo: ssh[2] };
|
|
102
|
+
const https = remoteUrl.match(HTTPS_REMOTE_RE);
|
|
103
|
+
if (https)
|
|
104
|
+
return { owner: https[1], repo: https[2] };
|
|
105
|
+
return null;
|
|
106
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wiggum-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "AI-powered feature development loop CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -61,6 +61,9 @@
|
|
|
61
61
|
"react": "^18.3.1",
|
|
62
62
|
"zod": "^4.3.5"
|
|
63
63
|
},
|
|
64
|
+
"overrides": {
|
|
65
|
+
"minimatch": ">=10.2.1"
|
|
66
|
+
},
|
|
64
67
|
"devDependencies": {
|
|
65
68
|
"@types/node": "^20.10.0",
|
|
66
69
|
"@types/react": "^19.2.9",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## Context
|
|
2
|
-
|
|
2
|
+
If @.ralph/guides/AGENTS.md exists, study it for commands and patterns.
|
|
3
3
|
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
4
|
Study @.ralph/specs/$FEATURE-implementation-plan.md for current tasks.
|
|
5
5
|
{{#if frameworkVariant}}For detailed architecture, see @{{appDir}}/.claude/CLAUDE.md{{/if}}
|
|
@@ -18,10 +18,10 @@ Key patterns: parallel fetches, direct imports, React.cache(), lazy loading.
|
|
|
18
18
|
- Search codebase before assuming something doesn't exist
|
|
19
19
|
|
|
20
20
|
## Task
|
|
21
|
-
|
|
21
|
+
Work through ALL incomplete tasks in the implementation plan in a single session.
|
|
22
22
|
**Skip E2E tasks** (tasks starting with `E2E:`) - those are handled in a separate phase.
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
For each task: implement it, write tests, validate, commit, then move to the next task.
|
|
24
|
+
Do not stop after one task — keep going until all non-E2E tasks are complete.
|
|
25
25
|
|
|
26
26
|
## Validation
|
|
27
27
|
After changes, ALL must pass:
|
|
@@ -36,7 +36,8 @@ If any validation fails, fix the issue before proceeding.
|
|
|
36
36
|
Before committing, review your changes against @.ralph/guides/SECURITY.md:
|
|
37
37
|
1. **Quick scan**: Input validation, injection prevention, auth checks, data exposure
|
|
38
38
|
2. **Run**: `cd {{appDir}} && {{packageManager}} audit` (check for vulnerable dependencies)
|
|
39
|
-
3. **Check**: `mcp__supabase__get_advisors` with type "security" (RLS policies)
|
|
39
|
+
{{#if hasSupabase}}3. **Check**: `mcp__supabase__get_advisors` with type "security" (RLS policies)
|
|
40
|
+
{{/if}}
|
|
40
41
|
4. **Red team**: Can auth be bypassed? Can other users' data be accessed?
|
|
41
42
|
|
|
42
43
|
Flag any security issues in the implementation plan and fix before committing.
|
|
@@ -54,7 +55,7 @@ If any check fails, fix before committing.
|
|
|
54
55
|
|
|
55
56
|
## Completion
|
|
56
57
|
When ALL validations pass:
|
|
57
|
-
1. Update @.ralph/specs/$FEATURE-implementation-plan.md
|
|
58
|
+
1. Update @.ralph/specs/$FEATURE-implementation-plan.md — change the task's `- [ ]` to `- [x]` and append the commit hash (e.g., `- [x] Task description - abc1234`). The harness tracks progress by counting checkboxes, so this step is mandatory.
|
|
58
59
|
2. `git -C {{appDir}} add -A`
|
|
59
60
|
3. `git -C {{appDir}} commit -m "type(scope): description"`
|
|
60
61
|
4. `git -C {{appDir}} push origin feat/$FEATURE`
|
|
@@ -69,9 +70,11 @@ If this iteration revealed something useful, append to @.ralph/LEARNINGS.md:
|
|
|
69
70
|
Format: `- [YYYY-MM-DD] [$FEATURE] Brief description`
|
|
70
71
|
|
|
71
72
|
## Rules
|
|
72
|
-
-
|
|
73
|
+
- Complete ALL remaining non-E2E tasks before ending the session
|
|
74
|
+
- Commit after each task so progress is preserved if the session is interrupted
|
|
73
75
|
- Tests are mandatory - no task is complete without tests
|
|
74
76
|
- Search codebase before assuming something doesn't exist
|
|
75
|
-
- If blocked, document in implementation plan and move to next task
|
|
76
|
-
- Use Supabase MCP for database operations
|
|
77
|
-
- Use PostHog MCP for analytics queries
|
|
77
|
+
- If blocked on a task, document in implementation plan and move to the next task
|
|
78
|
+
{{#if hasSupabase}}- Use Supabase MCP for database operations
|
|
79
|
+
{{/if}}{{#if hasPosthog}}- Use PostHog MCP for analytics queries
|
|
80
|
+
{{/if}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## Context
|
|
2
|
-
|
|
2
|
+
If @.ralph/guides/AGENTS.md exists, study it for commands and patterns.
|
|
3
3
|
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
4
|
Study @.ralph/specs/$FEATURE-implementation-plan.md for E2E test scenarios.
|
|
5
5
|
{{#if frameworkVariant}}For detailed architecture, see @{{appDir}}/.claude/CLAUDE.md{{/if}}
|
|
@@ -21,6 +21,7 @@ If either fails, fix issues before proceeding with E2E tests.
|
|
|
21
21
|
{{#if isTui}}
|
|
22
22
|
## Task
|
|
23
23
|
Execute automated E2E tests for the completed TUI feature using the xterm.js bridge and agent-browser.
|
|
24
|
+
Run ALL scenarios in a single session — do not end between scenarios.
|
|
24
25
|
|
|
25
26
|
### Step 1: Start Bridge
|
|
26
27
|
Check the bridge is running:
|
|
@@ -149,11 +150,11 @@ When all scenarios are executed:
|
|
|
149
150
|
2. Update the Implementation Summary status to `[PASSED]` if all passed
|
|
150
151
|
3. **Commit the updated implementation plan:**
|
|
151
152
|
```bash
|
|
152
|
-
git add -A && git commit -m "test($FEATURE): E2E tests passed via agent-browser"
|
|
153
|
+
git -C {{appDir}} add -A && git -C {{appDir}} commit -m "test($FEATURE): E2E tests passed via agent-browser"
|
|
153
154
|
```
|
|
154
155
|
4. **Push to remote:**
|
|
155
156
|
```bash
|
|
156
|
-
git push origin feat/$FEATURE
|
|
157
|
+
git -C {{appDir}} push origin feat/$FEATURE
|
|
157
158
|
```
|
|
158
159
|
5. If all passed: signal ready for PR phase
|
|
159
160
|
6. If any failed: failures documented, loop will retry after fix iteration
|
|
@@ -168,6 +169,7 @@ Format: `- [YYYY-MM-DD] [$FEATURE] Brief description`
|
|
|
168
169
|
{{else}}
|
|
169
170
|
## Task
|
|
170
171
|
Execute automated E2E tests for the completed feature using Playwright MCP tools.
|
|
172
|
+
Run ALL scenarios in a single session — do not end between scenarios.
|
|
171
173
|
|
|
172
174
|
### Step 1: Check Dev Server
|
|
173
175
|
Verify dev server is running at http://localhost:3000. If not accessible, start it:
|
|
@@ -176,7 +178,7 @@ cd {{appDir}} && {{devCommand}} &
|
|
|
176
178
|
```
|
|
177
179
|
Wait ~10 seconds for server startup, then verify with a simple browser_navigate.
|
|
178
180
|
|
|
179
|
-
### Step 1.5: Seed Test Data (if needed)
|
|
181
|
+
{{#if hasSupabase}}### Step 1.5: Seed Test Data (if needed)
|
|
180
182
|
|
|
181
183
|
Check if test scenarios require specific data volumes (e.g., pagination needs >10 rows).
|
|
182
184
|
|
|
@@ -199,6 +201,7 @@ query: "DELETE FROM table_name WHERE data->>'_test' = 'true';"
|
|
|
199
201
|
```
|
|
200
202
|
|
|
201
203
|
**If seeding is impractical:** Document in implementation plan that E2E was skipped but unit tests provide coverage.
|
|
204
|
+
{{/if}}
|
|
202
205
|
|
|
203
206
|
### Step 2: Parse E2E Test Scenarios
|
|
204
207
|
Read E2E test scenarios from @.ralph/specs/$FEATURE-implementation-plan.md.
|
|
@@ -246,7 +249,7 @@ For each E2E test scenario:
|
|
|
246
249
|
- Check console: `browser_console_messages` for JS errors
|
|
247
250
|
- Document failure details
|
|
248
251
|
|
|
249
|
-
### Step 4: Database Verification
|
|
252
|
+
{{#if hasSupabase}}### Step 4: Database Verification
|
|
250
253
|
For scenarios with database checks, use Supabase MCP:
|
|
251
254
|
```
|
|
252
255
|
mcp__plugin_supabase_supabase__execute_sql
|
|
@@ -255,6 +258,7 @@ query: "SELECT * FROM survey_responses WHERE ..."
|
|
|
255
258
|
```
|
|
256
259
|
|
|
257
260
|
Verify returned data matches expected state.
|
|
261
|
+
{{/if}}
|
|
258
262
|
|
|
259
263
|
### Unique Test Data (for Parallel Execution)
|
|
260
264
|
When creating test data, use unique identifiers to avoid conflicts with other loops:
|
|
@@ -315,11 +319,12 @@ Update @.ralph/specs/$FEATURE-implementation-plan.md for each scenario:
|
|
|
315
319
|
2. Verify URL contains expected path/params
|
|
316
320
|
```
|
|
317
321
|
|
|
318
|
-
### Database State
|
|
322
|
+
{{#if hasSupabase}}### Database State
|
|
319
323
|
```
|
|
320
324
|
1. mcp__plugin_supabase_supabase__execute_sql with SELECT query
|
|
321
325
|
2. Verify row count, column values match expectations
|
|
322
326
|
```
|
|
327
|
+
{{/if}}
|
|
323
328
|
|
|
324
329
|
## Browser State Management
|
|
325
330
|
|
|
@@ -364,8 +369,9 @@ If code changes don't appear in the browser:
|
|
|
364
369
|
|
|
365
370
|
### Stale Data
|
|
366
371
|
- Clear browser storage: Use `browser_close` between scenarios
|
|
367
|
-
- Check Supabase for stale test data from previous runs
|
|
372
|
+
{{#if hasSupabase}}- Check Supabase for stale test data from previous runs
|
|
368
373
|
- Delete test data: `DELETE FROM table WHERE data->>'_test' = 'true'`
|
|
374
|
+
{{/if}}
|
|
369
375
|
|
|
370
376
|
## Rules
|
|
371
377
|
- Always get a fresh `browser_snapshot` after actions before making assertions
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## Context
|
|
2
|
-
|
|
2
|
+
If @.ralph/guides/AGENTS.md exists, study it for commands and patterns.
|
|
3
3
|
Study @.ralph/specs/README.md for spec structure.
|
|
4
4
|
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
5
5
|
{{#if frameworkVariant}}For detailed architecture, see @{{appDir}}/.claude/CLAUDE.md{{/if}}
|
|
@@ -96,9 +96,22 @@ Example E2E scenario:
|
|
|
96
96
|
- [x] E2E: Scenario name - PASSED
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
## CRITICAL CONSTRAINT — PLANNING ONLY
|
|
100
|
+
**You are in the PLANNING phase. Your ONLY job is to produce an implementation plan.**
|
|
101
|
+
- Do NOT write any source code, test code, or configuration files
|
|
102
|
+
- Do NOT create, modify, or touch any files outside `.ralph/specs/`
|
|
103
|
+
- Do NOT run build, test, or lint commands
|
|
104
|
+
- Do NOT make git commits
|
|
105
|
+
- If you feel the urge to "just implement a small piece", STOP — that is a phase violation
|
|
106
|
+
- The implementation phase runs AFTER this session ends, in a separate session
|
|
107
|
+
- Violation of this constraint wastes tokens and breaks the harness automation
|
|
108
|
+
|
|
99
109
|
## Rules
|
|
100
|
-
-
|
|
101
|
-
-
|
|
110
|
+
- You MUST use `- [ ]` checkbox syntax for every task in the plan
|
|
111
|
+
- Do NOT use heading-based task formats (e.g., `#### Task 1:`) for individual tasks
|
|
112
|
+
- The harness parses `- [ ]` lines to track progress — other formats will break automation
|
|
113
|
+
- Use `### Phase N:` headings only for phase grouping, not for individual tasks
|
|
114
|
+
- One task = one commit-sized unit of work (but tasks can be grouped into phases for batch implementation)
|
|
102
115
|
- Every implementation task needs a corresponding test task
|
|
103
116
|
- Use Supabase MCP to check existing schema
|
|
104
117
|
- Use PostHog MCP to check existing analytics setup
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## Context
|
|
2
|
-
|
|
2
|
+
If @.ralph/guides/AGENTS.md exists, study it for commands and patterns.
|
|
3
3
|
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
4
|
Study @.ralph/specs/$FEATURE-implementation-plan.md for completed tasks.
|
|
5
5
|
|
|
@@ -9,6 +9,7 @@ Capture any review feedback patterns for future iterations.
|
|
|
9
9
|
|
|
10
10
|
## Task
|
|
11
11
|
All implementation and E2E tasks are complete. Create PR and request review.
|
|
12
|
+
Complete ALL steps in a single pass — do not end the session between steps.
|
|
12
13
|
|
|
13
14
|
### Step 1: Verify Ready State
|
|
14
15
|
1. Check all tasks are complete in implementation plan (no `- [ ]` items)
|
|
@@ -52,12 +53,14 @@ cd {{appDir}} && gh pr create --base main --head feat/$FEATURE \
|
|
|
52
53
|
[Read from implementation plan - list completed phases]
|
|
53
54
|
|
|
54
55
|
## Testing
|
|
55
|
-
- [x] Unit/integration tests:
|
|
56
|
-
- [x] E2E tests: All scenarios passed
|
|
56
|
+
- [x] Unit/integration tests: passing
|
|
57
|
+
- [x] E2E tests: All scenarios passed
|
|
57
58
|
- [x] Build succeeds
|
|
58
59
|
|
|
59
60
|
## E2E Test Results
|
|
60
|
-
[Copy from implementation plan
|
|
61
|
+
[Copy from implementation plan E2E section]
|
|
62
|
+
|
|
63
|
+
Closes #[Read the source issue number from the spec file metadata or context section]
|
|
61
64
|
|
|
62
65
|
Generated with Claude Code
|
|
63
66
|
EOF
|
|
@@ -88,17 +91,27 @@ Review the git diff against main and check:
|
|
|
88
91
|
|
|
89
92
|
Run: git diff main
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
This line is parsed by the automation — do not omit it."
|
|
94
|
+
Then:
|
|
95
|
+
1. Post your complete review as a comment on the PR using:
|
|
96
|
+
gh pr comment --body '<your review in markdown>'
|
|
97
|
+
Format the comment with: a summary, specific issues with file:line refs (if any), and the verdict.
|
|
98
|
+
2. Print your final verdict as the LAST line of stdout. Print exactly one of:
|
|
99
|
+
VERDICT: APPROVED
|
|
100
|
+
VERDICT: NOT APPROVED
|
|
101
|
+
This line is parsed by the automation — do not omit it."
|
|
99
102
|
fi
|
|
100
103
|
```
|
|
101
104
|
|
|
105
|
+
After the review completes, check its output:
|
|
106
|
+
- If it contains "VERDICT: APPROVED", echo that line so the automation detects it:
|
|
107
|
+
```bash
|
|
108
|
+
echo "VERDICT: APPROVED"
|
|
109
|
+
```
|
|
110
|
+
- If issues were found, echo:
|
|
111
|
+
```bash
|
|
112
|
+
echo "VERDICT: NOT APPROVED"
|
|
113
|
+
```
|
|
114
|
+
|
|
102
115
|
**Handle review feedback:**
|
|
103
116
|
- If Claude outputs "VERDICT: APPROVED" -> Done. The PR is ready for manual merge by the user.
|
|
104
117
|
- If Claude lists issues:
|
|
@@ -113,8 +126,15 @@ After review is complete (approved or max iterations reached):
|
|
|
113
126
|
1. Post a summary comment on the PR with the review outcome
|
|
114
127
|
2. Do NOT merge — the user will review and merge manually
|
|
115
128
|
|
|
129
|
+
## IMPORTANT: Review scope
|
|
130
|
+
If you discover that no implementation code exists (empty diff, no source files changed),
|
|
131
|
+
do NOT implement the feature yourself. Instead, report "VERDICT: NOT APPROVED —
|
|
132
|
+
no implementation found" so the harness can trigger a new implementation iteration.
|
|
133
|
+
|
|
116
134
|
## Rules
|
|
135
|
+
- **NEVER approve if any tests are failing.** Output "VERDICT: NOT APPROVED — test failures" if any tests fail.
|
|
117
136
|
- Do NOT merge the PR — auto mode only reviews, the user merges
|
|
137
|
+
- Do NOT implement missing features — only review and fix minor issues
|
|
118
138
|
- Address ALL review comments before marking as approved
|
|
119
139
|
- If gh CLI fails, check authentication: `gh auth status`
|
|
120
140
|
- Keep review conversation focused and professional
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
## Context
|
|
2
|
-
|
|
2
|
+
If @.ralph/guides/AGENTS.md exists, study it for commands and patterns.
|
|
3
3
|
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
4
|
Study @.ralph/specs/$FEATURE-implementation-plan.md for completed tasks.
|
|
5
5
|
|
|
@@ -9,6 +9,7 @@ Capture any review feedback patterns for future iterations.
|
|
|
9
9
|
|
|
10
10
|
## Task
|
|
11
11
|
All implementation and E2E tasks are complete. Create PR for manual review.
|
|
12
|
+
Complete ALL steps in a single pass — do not end the session between steps.
|
|
12
13
|
|
|
13
14
|
### Step 1: Verify Ready State
|
|
14
15
|
1. Check all tasks are complete in implementation plan (no `- [ ]` items)
|
|
@@ -59,6 +60,8 @@ cd {{appDir}} && gh pr create --base main --head feat/$FEATURE \
|
|
|
59
60
|
## E2E Test Results
|
|
60
61
|
[Copy from implementation plan if E2E phase exists]
|
|
61
62
|
|
|
63
|
+
Closes #[Read the source issue number from the spec file metadata or context section]
|
|
64
|
+
|
|
62
65
|
Generated with Claude Code
|
|
63
66
|
EOF
|
|
64
67
|
)"
|