popeye-cli 1.9.4 → 1.10.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/cheatsheet.md +65 -0
- package/dist/cli/commands/debug-context.d.ts +64 -0
- package/dist/cli/commands/debug-context.d.ts.map +1 -0
- package/dist/cli/commands/debug-context.js +221 -0
- package/dist/cli/commands/debug-context.js.map +1 -0
- package/dist/cli/commands/debug-prompts.d.ts +25 -0
- package/dist/cli/commands/debug-prompts.d.ts.map +1 -0
- package/dist/cli/commands/debug-prompts.js +80 -0
- package/dist/cli/commands/debug-prompts.js.map +1 -0
- package/dist/cli/commands/debug.d.ts +68 -0
- package/dist/cli/commands/debug.d.ts.map +1 -0
- package/dist/cli/commands/debug.js +543 -0
- package/dist/cli/commands/debug.js.map +1 -0
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +25 -0
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/all.d.ts.map +1 -1
- package/dist/generators/all.js +3 -0
- package/dist/generators/all.js.map +1 -1
- package/dist/generators/templates/database-docker.d.ts.map +1 -1
- package/dist/generators/templates/database-docker.js +11 -0
- package/dist/generators/templates/database-docker.js.map +1 -1
- package/dist/generators/templates/fullstack.d.ts +4 -1
- package/dist/generators/templates/fullstack.d.ts.map +1 -1
- package/dist/generators/templates/fullstack.js +6 -2
- package/dist/generators/templates/fullstack.js.map +1 -1
- package/package.json +1 -1
- package/skills/ARBITRATOR.md +137 -0
- package/skills/ARCHITECT.md +167 -0
- package/skills/AUDITOR.md +128 -0
- package/skills/AUDIT_REPORT_SCHEMA.md +20 -0
- package/skills/BACKEND_PROGRAMMER.md +95 -0
- package/skills/CONSENSUS_PACKET_SCHEMA.md +166 -0
- package/skills/DB_EXPERT.md +106 -0
- package/skills/DEBUGGER.md +286 -0
- package/skills/DISPATCHER.md +157 -0
- package/skills/FRONTEND_PROGRAMMER.md +84 -0
- package/skills/JOURNALIST.md +247 -0
- package/skills/MARKETING_EXPERT.md +23 -0
- package/skills/PHASE_GATE_ENGINE_SPEC.md +78 -0
- package/skills/PLAN_PACKET_SCHEMA.md +222 -0
- package/skills/POPEYE_CONSTITUTION.md +177 -0
- package/skills/POPEYE_FULL_AUTONOMY_PIPELINE.md +484 -0
- package/skills/PRODUCTION_READINESS_SCHEMA.md +19 -0
- package/skills/QA_TESTER.md +40 -0
- package/skills/RCA_PACKET_SCHEMA.md +22 -0
- package/skills/RELEASE_MANAGER.md +60 -0
- package/skills/REVIEWER.md +133 -0
- package/skills/SOCIAL_EXPERT.md +22 -0
- package/skills/UI_UX_SPECIALIST.md +22 -0
- package/skills/WEBSITE_PROGRAMMER.md +37 -0
- package/src/cli/commands/debug-context.ts +265 -0
- package/src/cli/commands/debug-prompts.ts +91 -0
- package/src/cli/commands/debug.ts +662 -0
- package/src/cli/commands/index.ts +1 -0
- package/src/cli/index.ts +2 -0
- package/src/cli/interactive.ts +27 -0
- package/src/generators/all.ts +3 -0
- package/src/generators/templates/database-docker.ts +11 -0
- package/src/generators/templates/fullstack.ts +6 -2
- package/tests/cli/commands/debug.test.ts +376 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# RCA PACKET SCHEMA
|
|
2
|
+
Purpose: Machine-verifiable root cause analysis artifact.
|
|
3
|
+
|
|
4
|
+
Required Fields:
|
|
5
|
+
|
|
6
|
+
- rca_id (UUID)
|
|
7
|
+
- timestamp
|
|
8
|
+
- incident_type
|
|
9
|
+
- severity
|
|
10
|
+
- reproduction_steps
|
|
11
|
+
- affected_files[]
|
|
12
|
+
- execution_trace
|
|
13
|
+
- root_cause_statement
|
|
14
|
+
- responsible_layer
|
|
15
|
+
- origin_phase
|
|
16
|
+
- governance_gap
|
|
17
|
+
- recommended_fix_owner
|
|
18
|
+
- requires_consensus (boolean)
|
|
19
|
+
- requires_change_request (boolean)
|
|
20
|
+
|
|
21
|
+
No vague root cause allowed.
|
|
22
|
+
Must identify structural origin.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Skill: RELEASE MANAGER
|
|
2
|
+
Role Type: Production Readiness Authority
|
|
3
|
+
Authority Level: Final Deployment Validator
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Objective
|
|
8
|
+
|
|
9
|
+
Ensure system is ready for deployment and produce final release artifacts.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Responsibilities
|
|
14
|
+
|
|
15
|
+
- Validate Production Gate results
|
|
16
|
+
- Generate Release Notes
|
|
17
|
+
- Generate Deployment Instructions
|
|
18
|
+
- Verify versioning
|
|
19
|
+
- Verify changelog
|
|
20
|
+
- Tag release version (conceptually)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Required Inputs
|
|
25
|
+
|
|
26
|
+
- Production Readiness Report
|
|
27
|
+
- Audit Report
|
|
28
|
+
- Repo Snapshot
|
|
29
|
+
- Final Plan Packet
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
|
|
35
|
+
# RELEASE PACKAGE
|
|
36
|
+
|
|
37
|
+
## Version
|
|
38
|
+
Semantic version increment
|
|
39
|
+
|
|
40
|
+
## Included Features
|
|
41
|
+
List from Master Plan
|
|
42
|
+
|
|
43
|
+
## Known Risks
|
|
44
|
+
Must be empty for PASS
|
|
45
|
+
|
|
46
|
+
## Deployment Steps
|
|
47
|
+
- Build commands
|
|
48
|
+
- Env var setup
|
|
49
|
+
- DB migration command
|
|
50
|
+
- Start commands
|
|
51
|
+
|
|
52
|
+
## Rollback Plan
|
|
53
|
+
Clear rollback steps
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Definition of Done
|
|
58
|
+
|
|
59
|
+
Release package stored under:
|
|
60
|
+
`/docs/release/`
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Skill: REVIEWER (PLAN CONSENSUS REVIEWER)
|
|
2
|
+
Role Type: Independent Plan Auditor
|
|
3
|
+
Authority Level: Gatekeeper for Consensus Approval
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Objective
|
|
8
|
+
|
|
9
|
+
Review a proposed plan produced by Dispatcher/Popeye using an independent LLM perspective,
|
|
10
|
+
detect gaps/hallucinations/shortcuts, and issue a structured vote that can be used for consensus.
|
|
11
|
+
|
|
12
|
+
Reviewer is NOT an implementer.
|
|
13
|
+
Reviewer is NOT a co-author (unless explicitly requested by Arbitrator to propose minimal corrections).
|
|
14
|
+
Reviewer is an evidence-based plan auditor.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Required Input: PLAN PACKET (Mandatory)
|
|
19
|
+
|
|
20
|
+
Reviewer only operates on a "Plan Packet" containing:
|
|
21
|
+
|
|
22
|
+
1) **Master Plan (approved version)**
|
|
23
|
+
2) **Proposed Plan** (the artifact under review)
|
|
24
|
+
3) **Repo Snapshot Summary** (what exists now)
|
|
25
|
+
4) **Constraints** (tech stack, env, policies)
|
|
26
|
+
5) **Constitution** (governing rules)
|
|
27
|
+
6) **Acceptance Criteria / Definition of Done**
|
|
28
|
+
|
|
29
|
+
If any component is missing → Reviewer must return **BLOCKED: Missing Inputs**.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Primary Responsibilities
|
|
34
|
+
|
|
35
|
+
- Validate alignment with the Master Plan and Constitution
|
|
36
|
+
- Validate completeness: all scenarios, edge cases, and integration paths addressed
|
|
37
|
+
- Validate feasibility: steps are implementable in the repo as it exists
|
|
38
|
+
- Detect hallucinations: invented files, APIs, schema, env vars, services
|
|
39
|
+
- Detect shortcuts: mocks, TODOs, “later” wiring, vague testing
|
|
40
|
+
- Verify roles are correctly assigned and synchronized
|
|
41
|
+
- Verify artifacts + phase gates are present (architecture, DB, QA, review)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Non-Responsibilities
|
|
46
|
+
|
|
47
|
+
- Does NOT implement
|
|
48
|
+
- Does NOT rewrite the whole plan
|
|
49
|
+
- Does NOT change scope without a Change Request
|
|
50
|
+
- Does NOT relax consensus rules
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Review Method (Must Follow)
|
|
55
|
+
|
|
56
|
+
1) **Coverage Scan**
|
|
57
|
+
- Does the plan cover 100% of Master Plan deliverables?
|
|
58
|
+
- Are all roles accounted for (Architect/DB/BE/FE/QA/etc.)?
|
|
59
|
+
|
|
60
|
+
2) **Integration Scan**
|
|
61
|
+
- FE↔BE wiring explicit?
|
|
62
|
+
- DB↔BE wiring explicit?
|
|
63
|
+
- Auth, env vars, migrations, deployment accounted for?
|
|
64
|
+
|
|
65
|
+
3) **Evidence Scan**
|
|
66
|
+
- Does it reference repo paths and existing modules accurately?
|
|
67
|
+
- Does it specify new files to be created deterministically?
|
|
68
|
+
|
|
69
|
+
4) **Risk & Scenario Scan**
|
|
70
|
+
- Failure modes covered? (timeouts, validation errors, empty states, rate limits, migrations fail, etc.)
|
|
71
|
+
- “Same resolution” comparisons, backward compat, rollback?
|
|
72
|
+
|
|
73
|
+
5) **Testability Scan**
|
|
74
|
+
- Are tests specified as executable steps? (not “write tests”)
|
|
75
|
+
- Are critical paths and integration tests listed?
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Output: REVIEW VOTE (Strict Format)
|
|
80
|
+
|
|
81
|
+
Reviewer MUST output the following structure:
|
|
82
|
+
|
|
83
|
+
### 1) Verdict
|
|
84
|
+
- **APPROVE**
|
|
85
|
+
- **APPROVE WITH MINOR CHANGES**
|
|
86
|
+
- **REJECT**
|
|
87
|
+
- **BLOCKED: MISSING INPUTS**
|
|
88
|
+
|
|
89
|
+
### 2) Score (0–100)
|
|
90
|
+
A numeric score representing confidence the plan can be executed without shortcuts/hallucinations.
|
|
91
|
+
|
|
92
|
+
### 3) Blocking Issues (if any)
|
|
93
|
+
Each blocking issue must include:
|
|
94
|
+
- **ID**
|
|
95
|
+
- **Problem**
|
|
96
|
+
- **Why it violates Master Plan/Constitution**
|
|
97
|
+
- **Exact fix requirement**
|
|
98
|
+
- **Where it should be fixed (which artifact/role)**
|
|
99
|
+
|
|
100
|
+
### 4) Non-Blocking Improvements
|
|
101
|
+
Concrete improvements that strengthen the plan.
|
|
102
|
+
|
|
103
|
+
### 5) Evidence & Consistency Notes
|
|
104
|
+
List any suspected hallucinations or ambiguous references.
|
|
105
|
+
|
|
106
|
+
### 6) Minimal Patch Suggestions (Optional)
|
|
107
|
+
If "Approve with minor changes", provide minimal diffs / bullet edits.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Automatic Rejection Triggers
|
|
112
|
+
|
|
113
|
+
Return **REJECT** if any exist:
|
|
114
|
+
|
|
115
|
+
- Implementation begins before architecture/DB/QA plans are gated
|
|
116
|
+
- Any plan step relies on "mock", "placeholder", "TODO" without explicit approval
|
|
117
|
+
- Unowned decisions (e.g. schema by BE, architecture by FE)
|
|
118
|
+
- Missing end-to-end integration steps
|
|
119
|
+
- Vague test plan (no named tests, no commands, no expected outcomes)
|
|
120
|
+
- Invented repo state (files/routes/env vars that don’t exist)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Definition of Done
|
|
125
|
+
|
|
126
|
+
Reviewer is done when:
|
|
127
|
+
- A valid structured vote is returned
|
|
128
|
+
- Issues are categorized as blocking vs non-blocking
|
|
129
|
+
- Fix directives are precise enough for Dispatcher/Arbitrator to act on
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
End of Skill.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Skill: SOCIAL EXPERT
|
|
2
|
+
Role Type: Distribution Strategist
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Objective
|
|
7
|
+
|
|
8
|
+
Translate product and marketing strategy into platform-native content.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Responsibilities
|
|
13
|
+
|
|
14
|
+
- Platform strategy
|
|
15
|
+
- Content formats
|
|
16
|
+
- Community guidelines alignment
|
|
17
|
+
- Engagement loops
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Definition of Done:
|
|
22
|
+
Distribution plan aligned with marketing strategy.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Skill: UI/UX SPECIALIST
|
|
2
|
+
Role Type: Experience Authority
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Objective
|
|
7
|
+
|
|
8
|
+
Ensure usability, clarity, accessibility, and design coherence.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Responsibilities
|
|
13
|
+
|
|
14
|
+
- UX flows
|
|
15
|
+
- Design system alignment
|
|
16
|
+
- Accessibility review
|
|
17
|
+
- Interaction validation
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Anti-Shortcut:
|
|
22
|
+
No cosmetic-only review — must evaluate usability.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Skill: WEBSITE PROGRAMMER
|
|
2
|
+
Role Type: Marketing Site Implementer
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Objective
|
|
7
|
+
|
|
8
|
+
Implement production-grade website aligned with:
|
|
9
|
+
|
|
10
|
+
- Brand
|
|
11
|
+
- Product positioning
|
|
12
|
+
- Architecture (if integrated)
|
|
13
|
+
- Marketing strategy
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Responsibilities
|
|
18
|
+
|
|
19
|
+
- Landing pages
|
|
20
|
+
- Pricing pages
|
|
21
|
+
- Documentation pages
|
|
22
|
+
- SEO structure
|
|
23
|
+
- Analytics integration
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Anti-Shortcut Rules
|
|
28
|
+
|
|
29
|
+
- No generic template text
|
|
30
|
+
- No placeholder copy
|
|
31
|
+
- No mismatched branding
|
|
32
|
+
- No default theme if brand colors defined
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
Definition of Done:
|
|
37
|
+
Website reflects actual product capabilities and branding.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug context helpers
|
|
3
|
+
* Deterministic functions for error analysis and smart file selection.
|
|
4
|
+
* Pure functions, easily testable.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Entry in the lightweight file index (paths + metadata, no content).
|
|
11
|
+
*/
|
|
12
|
+
export interface FileIndexEntry {
|
|
13
|
+
relativePath: string;
|
|
14
|
+
size: number;
|
|
15
|
+
mtime: number;
|
|
16
|
+
isConfig: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Config file patterns that are always considered relevant */
|
|
20
|
+
const CONFIG_PATTERNS = [
|
|
21
|
+
'package.json', 'package-lock.json', 'tsconfig.json', 'vite.config',
|
|
22
|
+
'pyproject.toml', 'requirements.txt', 'Pipfile',
|
|
23
|
+
'docker-compose.yml', 'docker-compose.yaml', 'Dockerfile',
|
|
24
|
+
'.env.example', '.env.local', 'alembic.ini',
|
|
25
|
+
'next.config', 'tailwind.config', 'postcss.config',
|
|
26
|
+
'jest.config', 'vitest.config', 'pytest.ini', 'setup.cfg',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if a file path matches a config pattern.
|
|
31
|
+
*
|
|
32
|
+
* @param filePath - Relative path to check.
|
|
33
|
+
* @returns True if the file is a known config file.
|
|
34
|
+
*/
|
|
35
|
+
export function isConfigFile(filePath: string): boolean {
|
|
36
|
+
const basename = path.basename(filePath);
|
|
37
|
+
return CONFIG_PATTERNS.some((p) => basename.startsWith(p));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Extract file paths mentioned in stack traces.
|
|
42
|
+
* Supports Python tracebacks, TypeScript/JS errors, and generic path patterns.
|
|
43
|
+
*
|
|
44
|
+
* @param text - Error text or stack trace.
|
|
45
|
+
* @returns Deduplicated array of file paths found in the text.
|
|
46
|
+
*/
|
|
47
|
+
export function extractPathsFromError(text: string): string[] {
|
|
48
|
+
const paths = new Set<string>();
|
|
49
|
+
|
|
50
|
+
// Python traceback: File "/app/src/module/file.py", line 42
|
|
51
|
+
const pyPattern = /File "([^"]+\.py[cw]?)", line \d+/g;
|
|
52
|
+
for (const match of text.matchAll(pyPattern)) {
|
|
53
|
+
paths.add(normalizePath(match[1]));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// TS/JS errors: src/components/App.tsx(15,3) or src/components/App.tsx:15:3
|
|
57
|
+
const tsPattern = /([a-zA-Z0-9_./\\-]+\.(?:ts|tsx|js|jsx|mjs|cjs))[\s:(]/g;
|
|
58
|
+
for (const match of text.matchAll(tsPattern)) {
|
|
59
|
+
paths.add(normalizePath(match[1]));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Docker / generic paths: /app/src/..., ./src/...
|
|
63
|
+
const genericPattern = /(?:\/app\/|\.\/)((?:src|app|lib|tests?|config)\/[a-zA-Z0-9_./-]+\.\w+)/g;
|
|
64
|
+
for (const match of text.matchAll(genericPattern)) {
|
|
65
|
+
paths.add(normalizePath(match[1]));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Module not found patterns: Cannot find module './foo/bar'
|
|
69
|
+
const modulePattern = /Cannot find module ['"]([^'"]+)['"]/g;
|
|
70
|
+
for (const match of text.matchAll(modulePattern)) {
|
|
71
|
+
const mod = match[1];
|
|
72
|
+
if (mod.startsWith('.') || mod.startsWith('/')) {
|
|
73
|
+
paths.add(normalizePath(mod));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ModuleNotFoundError: No module named 'src.foo.bar'
|
|
78
|
+
const pyModulePattern = /No module named ['"]([^'"]+)['"]/g;
|
|
79
|
+
for (const match of text.matchAll(pyModulePattern)) {
|
|
80
|
+
const dotPath = match[1].replace(/\./g, '/');
|
|
81
|
+
paths.add(dotPath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Array.from(paths);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Tech keyword map: keyword -> tags */
|
|
88
|
+
const TECH_KEYWORDS: Record<string, string[]> = {
|
|
89
|
+
'alembic': ['alembic', 'database', 'migration'],
|
|
90
|
+
'sqlalchemy': ['sqlalchemy', 'database', 'orm'],
|
|
91
|
+
'prisma': ['prisma', 'database', 'orm'],
|
|
92
|
+
'docker': ['docker', 'container'],
|
|
93
|
+
'docker-compose': ['docker', 'container', 'compose'],
|
|
94
|
+
'vite': ['vite', 'bundler', 'frontend'],
|
|
95
|
+
'webpack': ['webpack', 'bundler', 'frontend'],
|
|
96
|
+
'next': ['nextjs', 'react', 'frontend'],
|
|
97
|
+
'fastapi': ['fastapi', 'backend', 'python'],
|
|
98
|
+
'flask': ['flask', 'backend', 'python'],
|
|
99
|
+
'express': ['express', 'backend', 'node'],
|
|
100
|
+
'postgres': ['postgres', 'database'],
|
|
101
|
+
'redis': ['redis', 'cache'],
|
|
102
|
+
'tailwind': ['tailwind', 'css', 'frontend'],
|
|
103
|
+
'pytest': ['pytest', 'testing', 'python'],
|
|
104
|
+
'jest': ['jest', 'testing', 'node'],
|
|
105
|
+
'vitest': ['vitest', 'testing', 'node'],
|
|
106
|
+
'nginx': ['nginx', 'proxy'],
|
|
107
|
+
'cors': ['cors', 'api'],
|
|
108
|
+
'migration': ['migration', 'database'],
|
|
109
|
+
'celery': ['celery', 'queue', 'python'],
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Detect framework/tech keywords from error text.
|
|
114
|
+
*
|
|
115
|
+
* @param text - Error text or stack trace.
|
|
116
|
+
* @returns Object with deduplicated tags array.
|
|
117
|
+
*/
|
|
118
|
+
export function detectTechFromError(text: string): { tags: string[] } {
|
|
119
|
+
const tags = new Set<string>();
|
|
120
|
+
const lower = text.toLowerCase();
|
|
121
|
+
|
|
122
|
+
for (const [keyword, keywordTags] of Object.entries(TECH_KEYWORDS)) {
|
|
123
|
+
if (lower.includes(keyword)) {
|
|
124
|
+
for (const tag of keywordTags) {
|
|
125
|
+
tags.add(tag);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { tags: Array.from(tags) };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Select relevant files from the project index based on error paths and tech tags.
|
|
135
|
+
* Returns file paths sorted by relevance (direct matches first, then config, then nearby).
|
|
136
|
+
*
|
|
137
|
+
* @param fileIndex - Lightweight file index.
|
|
138
|
+
* @param errorPaths - Paths extracted from the error.
|
|
139
|
+
* @param tags - Tech tags detected from the error.
|
|
140
|
+
* @returns Array of relative paths to load.
|
|
141
|
+
*/
|
|
142
|
+
export function selectRelevantFiles(
|
|
143
|
+
fileIndex: FileIndexEntry[],
|
|
144
|
+
errorPaths: string[],
|
|
145
|
+
tags: string[]
|
|
146
|
+
): string[] {
|
|
147
|
+
if (fileIndex.length === 0) return [];
|
|
148
|
+
|
|
149
|
+
const selected = new Set<string>();
|
|
150
|
+
const MAX_FILES = 15;
|
|
151
|
+
|
|
152
|
+
// 1. Direct matches: files mentioned in the error
|
|
153
|
+
for (const errorPath of errorPaths) {
|
|
154
|
+
for (const entry of fileIndex) {
|
|
155
|
+
if (
|
|
156
|
+
entry.relativePath.endsWith(errorPath) ||
|
|
157
|
+
entry.relativePath === errorPath ||
|
|
158
|
+
entry.relativePath.includes(errorPath)
|
|
159
|
+
) {
|
|
160
|
+
selected.add(entry.relativePath);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 2. Sibling files: files in the same directory as matches
|
|
166
|
+
const matchedDirs = new Set<string>();
|
|
167
|
+
for (const sel of selected) {
|
|
168
|
+
matchedDirs.add(path.dirname(sel));
|
|
169
|
+
}
|
|
170
|
+
for (const dir of matchedDirs) {
|
|
171
|
+
for (const entry of fileIndex) {
|
|
172
|
+
if (path.dirname(entry.relativePath) === dir && selected.size < MAX_FILES) {
|
|
173
|
+
selected.add(entry.relativePath);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 3. Tag-based: config files related to detected tech
|
|
179
|
+
if (tags.includes('database') || tags.includes('migration')) {
|
|
180
|
+
for (const entry of fileIndex) {
|
|
181
|
+
if (
|
|
182
|
+
entry.relativePath.includes('alembic') ||
|
|
183
|
+
entry.relativePath.includes('migration') ||
|
|
184
|
+
entry.relativePath.includes('prisma') ||
|
|
185
|
+
entry.relativePath.includes('schema.sql')
|
|
186
|
+
) {
|
|
187
|
+
if (selected.size < MAX_FILES) selected.add(entry.relativePath);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (tags.includes('docker') || tags.includes('compose')) {
|
|
192
|
+
for (const entry of fileIndex) {
|
|
193
|
+
if (
|
|
194
|
+
entry.relativePath.includes('docker') ||
|
|
195
|
+
entry.relativePath.includes('Dockerfile')
|
|
196
|
+
) {
|
|
197
|
+
if (selected.size < MAX_FILES) selected.add(entry.relativePath);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 4. Fallback: always include config files if we have few matches
|
|
203
|
+
if (selected.size < 5) {
|
|
204
|
+
for (const entry of fileIndex) {
|
|
205
|
+
if (entry.isConfig && selected.size < MAX_FILES) {
|
|
206
|
+
selected.add(entry.relativePath);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return Array.from(selected).slice(0, MAX_FILES);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Image file extensions that Claude can read via the Read tool */
|
|
215
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg']);
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Extract image/screenshot file paths from user input text.
|
|
219
|
+
* Detects both quoted and unquoted absolute/relative paths ending in image extensions.
|
|
220
|
+
*
|
|
221
|
+
* @param text - User input text.
|
|
222
|
+
* @returns Array of image file paths found in the text.
|
|
223
|
+
*/
|
|
224
|
+
export function extractImagePaths(text: string): string[] {
|
|
225
|
+
const paths = new Set<string>();
|
|
226
|
+
|
|
227
|
+
// Quoted paths: '/path/to/image.png' or "/path/to/image.png"
|
|
228
|
+
const quotedPattern = /['"]([^'"]+\.(?:png|jpg|jpeg|gif|webp|bmp|svg))['"]/gi;
|
|
229
|
+
for (const match of text.matchAll(quotedPattern)) {
|
|
230
|
+
paths.add(match[1]);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Unquoted absolute paths: /path/to/image.png (no spaces allowed in unquoted)
|
|
234
|
+
const absolutePattern = /(\/[^\s'"]+\.(?:png|jpg|jpeg|gif|webp|bmp|svg))/gi;
|
|
235
|
+
for (const match of text.matchAll(absolutePattern)) {
|
|
236
|
+
paths.add(match[1]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return Array.from(paths);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Check if a file path points to an image file.
|
|
244
|
+
*
|
|
245
|
+
* @param filePath - File path to check.
|
|
246
|
+
* @returns True if the file has an image extension.
|
|
247
|
+
*/
|
|
248
|
+
export function isImageFile(filePath: string): boolean {
|
|
249
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
250
|
+
return IMAGE_EXTENSIONS.has(ext);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Normalize a file path by stripping common prefixes (/app/, ./, etc.).
|
|
255
|
+
*
|
|
256
|
+
* @param p - Raw file path from error text.
|
|
257
|
+
* @returns Normalized relative path.
|
|
258
|
+
*/
|
|
259
|
+
function normalizePath(p: string): string {
|
|
260
|
+
let normalized = p.replace(/\\/g, '/');
|
|
261
|
+
// Strip common container prefixes
|
|
262
|
+
normalized = normalized.replace(/^\/app\//, '');
|
|
263
|
+
normalized = normalized.replace(/^\.\//, '');
|
|
264
|
+
return normalized;
|
|
265
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug session prompts
|
|
3
|
+
* System prompt with strict output contract and conversation history formatting.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Message in the debug conversation history.
|
|
8
|
+
*/
|
|
9
|
+
export interface DebugMessage {
|
|
10
|
+
role: 'user' | 'assistant';
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build the system prompt for the debug session.
|
|
16
|
+
*
|
|
17
|
+
* @returns The system prompt instructing Claude on debug response format.
|
|
18
|
+
*/
|
|
19
|
+
export function getDebugSystemPrompt(): string {
|
|
20
|
+
return `You are an expert debugger embedded in the Popeye CLI. Your role is to diagnose
|
|
21
|
+
errors in projects generated by Popeye (full-stack apps, backends, frontends, websites).
|
|
22
|
+
|
|
23
|
+
You have access to the project's file system through your tools. When the user pastes an error,
|
|
24
|
+
diagnose it using the project context provided and the files you can read.
|
|
25
|
+
|
|
26
|
+
## Response Format
|
|
27
|
+
|
|
28
|
+
You MUST structure every response with these sections:
|
|
29
|
+
|
|
30
|
+
### Diagnosis
|
|
31
|
+
Explain what is wrong and why it is happening. Be specific -- reference exact module names,
|
|
32
|
+
configuration keys, or missing dependencies.
|
|
33
|
+
|
|
34
|
+
### Evidence
|
|
35
|
+
List the specific files and lines that confirm your diagnosis. Use the format:
|
|
36
|
+
- \`path/to/file.ts:42\` -- description of what you found
|
|
37
|
+
|
|
38
|
+
### Proposed Fix
|
|
39
|
+
Provide the exact changes needed. Show file paths and the code to add, modify, or remove.
|
|
40
|
+
Use diff-style formatting when helpful:
|
|
41
|
+
\`\`\`diff
|
|
42
|
+
- old line
|
|
43
|
+
+ new line
|
|
44
|
+
\`\`\`
|
|
45
|
+
|
|
46
|
+
### Commands to Verify
|
|
47
|
+
List shell commands the user should run to confirm the fix works. For example:
|
|
48
|
+
\`\`\`bash
|
|
49
|
+
docker-compose up --build
|
|
50
|
+
npm run dev
|
|
51
|
+
pytest tests/ -v
|
|
52
|
+
\`\`\`
|
|
53
|
+
|
|
54
|
+
### Ready to Apply?
|
|
55
|
+
End with a short note reminding the user they can type \`/fix\` in the debug session
|
|
56
|
+
to have Popeye apply the proposed changes automatically.
|
|
57
|
+
|
|
58
|
+
## Screenshots and Images
|
|
59
|
+
- Users may paste file paths to screenshots or images (e.g., \`/path/to/Screenshot.png\`).
|
|
60
|
+
- When you see an image path in the user's message, use the **Read** tool to view it.
|
|
61
|
+
The Read tool supports PNG, JPG, GIF, WebP, and other image formats.
|
|
62
|
+
- After viewing the screenshot, analyze what it shows (UI bugs, missing elements, error dialogs,
|
|
63
|
+
browser console errors, terminal output, etc.) and include your visual findings in the Diagnosis.
|
|
64
|
+
- If the image path is invalid or unreadable, tell the user and ask them to verify the path.
|
|
65
|
+
|
|
66
|
+
## Rules
|
|
67
|
+
- Never guess. If you need more context, ask the user or read additional files.
|
|
68
|
+
- Reference actual file paths from the project, not hypothetical ones.
|
|
69
|
+
- When multiple issues exist, address the root cause first.
|
|
70
|
+
- Keep explanations concise -- developers are your audience.
|
|
71
|
+
- If the error is outside the project (e.g., a system-level issue), say so clearly.`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Format conversation history for inclusion in the prompt.
|
|
76
|
+
*
|
|
77
|
+
* @param history - Array of debug messages.
|
|
78
|
+
* @returns Formatted string of conversation history.
|
|
79
|
+
*/
|
|
80
|
+
export function formatConversationHistory(history: DebugMessage[]): string {
|
|
81
|
+
if (history.length === 0) return '';
|
|
82
|
+
|
|
83
|
+
const lines: string[] = ['## Previous Conversation'];
|
|
84
|
+
|
|
85
|
+
for (const msg of history) {
|
|
86
|
+
const role = msg.role === 'user' ? 'User' : 'Assistant';
|
|
87
|
+
lines.push(`\n**${role}:**\n${msg.content}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|