beth-copilot 1.0.12 → 1.0.14
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/CHANGELOG.md +47 -0
- package/README.md +173 -32
- package/bin/cli.js +111 -193
- package/dist/cli/commands/doctor.d.ts +25 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +238 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/doctor.test.d.ts +6 -0
- package/dist/cli/commands/doctor.test.d.ts.map +1 -0
- package/dist/cli/commands/doctor.test.js +137 -0
- package/dist/cli/commands/doctor.test.js.map +1 -0
- package/dist/cli/commands/index.d.ts +7 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +10 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/quickstart.d.ts +18 -0
- package/dist/cli/commands/quickstart.d.ts.map +1 -0
- package/dist/cli/commands/quickstart.js +141 -0
- package/dist/cli/commands/quickstart.js.map +1 -0
- package/dist/core/agents/index.d.ts +6 -0
- package/dist/core/agents/index.d.ts.map +1 -0
- package/dist/core/agents/index.js +6 -0
- package/dist/core/agents/index.js.map +1 -0
- package/dist/core/agents/loader.d.ts +49 -0
- package/dist/core/agents/loader.d.ts.map +1 -0
- package/dist/core/agents/loader.js +217 -0
- package/dist/core/agents/loader.js.map +1 -0
- package/dist/core/agents/loader.test.d.ts +7 -0
- package/dist/core/agents/loader.test.d.ts.map +1 -0
- package/dist/core/agents/loader.test.js +144 -0
- package/dist/core/agents/loader.test.js.map +1 -0
- package/dist/core/agents/types.d.ts +77 -0
- package/dist/core/agents/types.d.ts.map +1 -0
- package/dist/core/agents/types.js +8 -0
- package/dist/core/agents/types.js.map +1 -0
- package/dist/core/agents/types.test.d.ts +6 -0
- package/dist/core/agents/types.test.d.ts.map +1 -0
- package/dist/core/agents/types.test.js +254 -0
- package/dist/core/agents/types.test.js.map +1 -0
- package/dist/core/skills/index.d.ts +6 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/skills/index.js +6 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/core/skills/loader.d.ts +69 -0
- package/dist/core/skills/loader.d.ts.map +1 -0
- package/dist/core/skills/loader.js +243 -0
- package/dist/core/skills/loader.js.map +1 -0
- package/dist/core/skills/loader.test.d.ts +7 -0
- package/dist/core/skills/loader.test.d.ts.map +1 -0
- package/dist/core/skills/loader.test.js +184 -0
- package/dist/core/skills/loader.test.js.map +1 -0
- package/dist/core/skills/types.d.ts +58 -0
- package/dist/core/skills/types.d.ts.map +1 -0
- package/dist/core/skills/types.js +8 -0
- package/dist/core/skills/types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/index.d.ts +7 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/pathValidation.d.ts +69 -0
- package/dist/lib/pathValidation.d.ts.map +1 -0
- package/dist/lib/pathValidation.js +185 -0
- package/dist/lib/pathValidation.js.map +1 -0
- package/dist/lib/pathValidation.test.d.ts +9 -0
- package/dist/lib/pathValidation.test.d.ts.map +1 -0
- package/dist/lib/pathValidation.test.js +195 -0
- package/dist/lib/pathValidation.test.js.map +1 -0
- package/package.json +15 -3
- package/templates/.github/agents/developer.agent.md +9 -0
- package/templates/.github/agents/product-manager.agent.md +9 -0
- package/templates/.github/agents/researcher.agent.md +9 -0
- package/templates/.github/agents/security-reviewer.agent.md +9 -2
- package/templates/.github/agents/tester.agent.md +9 -0
- package/templates/.github/agents/ux-designer.agent.md +9 -0
- package/templates/.github/copilot-instructions.md +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,53 @@ All notable changes to Beth are documented here. Format based on [Keep a Changel
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.0.14] - 2026-02-04
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **User-friendly error messages** — CLI errors now display formatted boxes with clear problem descriptions, fix instructions, and the exact command to run. No more raw stack traces.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## [1.0.13] - 2026-02-04
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **ENOTDIR crash during init** — Fixed `copyDirRecursive` crashing when destination path exists as a file instead of a directory. Now properly detects the conflict and provides a clear error message (or removes the file with `--force`).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## [Unreleased]
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- **CLI TypeScript foundation** — Migrated CLI to TypeScript with proper build system
|
|
27
|
+
- **Doctor command** — `beth doctor` validates installation and configuration
|
|
28
|
+
- **Quickstart command** — `beth quickstart` for guided setup
|
|
29
|
+
- **Agent schema types** — TypeScript types for agent definitions
|
|
30
|
+
- **Unit tests** — 86 tests passing for CLI commands and path validation
|
|
31
|
+
- **Architecture diagrams** — Interactive mermaid diagrams with zoom in README
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- **DEMO.md** — Rewritten with Beth's personality and beads integration
|
|
35
|
+
- **P2 backlog completed** — Beth orchestrator references added to all agents, MCP skills updated, documentation fixes
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- Removed unnecessary backlog.md CLI dependency
|
|
39
|
+
- Fixed security-reviewer.agent.md syntax errors
|
|
40
|
+
- Corrected agent/skill counts in help output
|
|
41
|
+
- Allowlisted security documentation examples in Gitleaks config
|
|
42
|
+
|
|
43
|
+
### Documentation
|
|
44
|
+
- CLI Architecture guide (docs/CLI-ARCHITECTURE.md)
|
|
45
|
+
- CLI Implementation Plan (docs/CLI-IMPLEMENTATION-PLAN.md)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## [1.0.12] - 2026-02-01
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- Added CHANGELOG.md to npm package
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
9
56
|
## [1.0.11] - 2026-02-01
|
|
10
57
|
|
|
11
58
|
### Changed
|
package/README.md
CHANGED
|
@@ -80,44 +80,119 @@ Beth's team comes equipped:
|
|
|
80
80
|
|
|
81
81
|
She doesn't micromanage. She delegates to specialists and holds them accountable.
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
### Architecture
|
|
84
|
+
|
|
85
|
+
```mermaid
|
|
86
|
+
flowchart TB
|
|
87
|
+
subgraph User["👤 User"]
|
|
88
|
+
Request[User Request]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
subgraph Orchestrator["🎯 Beth - The Orchestrator"]
|
|
92
|
+
Beth["@Beth<br/><i>'I don't speak dipshit'</i>"]
|
|
93
|
+
Assess[Assess Request]
|
|
94
|
+
Plan[Plan Workflow]
|
|
95
|
+
Route[Route to Specialists]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
subgraph Agents["🧑💼 Specialist Agents"]
|
|
99
|
+
PM["@product-manager<br/>WHAT to build"]
|
|
100
|
+
Researcher["@researcher<br/>User/Market Intel"]
|
|
101
|
+
Designer["@ux-designer<br/>HOW it works"]
|
|
102
|
+
Developer["@developer<br/>Implementation"]
|
|
103
|
+
Security["@security-reviewer<br/>Protection"]
|
|
104
|
+
Tester["@tester<br/>Quality Gate"]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
Request --> Beth
|
|
108
|
+
Beth --> Assess --> Plan --> Route
|
|
109
|
+
|
|
110
|
+
Route --> PM
|
|
111
|
+
Route --> Researcher
|
|
112
|
+
Route --> Designer
|
|
113
|
+
Route --> Developer
|
|
114
|
+
Route --> Security
|
|
115
|
+
Route --> Tester
|
|
116
|
+
|
|
117
|
+
style Beth fill:#1e3a5f,color:#fff
|
|
118
|
+
style Orchestrator fill:#f0f4f8
|
|
119
|
+
style Agents fill:#f8f4f0
|
|
103
120
|
```
|
|
104
121
|
|
|
105
122
|
### The Workflow
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
124
|
+
```mermaid
|
|
125
|
+
sequenceDiagram
|
|
126
|
+
participant U as User
|
|
127
|
+
participant B as Beth
|
|
128
|
+
participant PM as Product Manager
|
|
129
|
+
participant UX as UX Designer
|
|
130
|
+
participant D as Developer
|
|
131
|
+
participant S as Security
|
|
132
|
+
participant T as Tester
|
|
133
|
+
|
|
134
|
+
U->>B: "Build me a feature"
|
|
135
|
+
B->>B: Assess & Plan
|
|
136
|
+
B->>PM: Define requirements
|
|
137
|
+
PM-->>B: Requirements ready
|
|
138
|
+
B->>UX: Design the experience
|
|
139
|
+
UX-->>B: Design specs ready
|
|
140
|
+
B->>D: Implement feature
|
|
141
|
+
D-->>B: Implementation complete
|
|
142
|
+
B->>S: Security review
|
|
143
|
+
S-->>B: Security approved
|
|
144
|
+
B->>T: Test & verify
|
|
145
|
+
T-->>B: Quality verified
|
|
146
|
+
B->>U: Feature complete ✅
|
|
111
147
|
```
|
|
112
148
|
|
|
113
|
-
**Bug Hunt?**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
**Bug Hunt?** Tester → Developer → Security → Tester
|
|
150
|
+
**Security Audit?** Security → Developer → Tester → Security
|
|
151
|
+
|
|
152
|
+
### Agent Delegation
|
|
153
|
+
|
|
154
|
+
```mermaid
|
|
155
|
+
flowchart TB
|
|
156
|
+
subgraph Beth["Beth (Orchestrator)"]
|
|
157
|
+
BethCore["Routes all work<br/>Spawns subagents"]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
subgraph PM["Product Manager"]
|
|
161
|
+
PMCore["Requirements<br/>Priorities"]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
subgraph R["Researcher"]
|
|
165
|
+
RCore["User insights<br/>Market intel"]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
subgraph UX["UX Designer"]
|
|
169
|
+
UXCore["Component specs<br/>Design tokens"]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
subgraph D["Developer"]
|
|
173
|
+
DCore["React/TS/Next.js<br/>Implementation"]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
subgraph S["Security"]
|
|
177
|
+
SCore["Threat modeling<br/>Vulnerabilities"]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
subgraph T["Tester"]
|
|
181
|
+
TCore["QA & a11y<br/>Performance"]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
BethCore -->|"Product Strategy"| PMCore
|
|
185
|
+
BethCore -->|"User Research"| RCore
|
|
186
|
+
BethCore -->|"UX Design"| UXCore
|
|
187
|
+
BethCore -->|"Development"| DCore
|
|
188
|
+
BethCore -->|"Security Review"| SCore
|
|
189
|
+
BethCore -->|"Quality Assurance"| TCore
|
|
190
|
+
|
|
191
|
+
PMCore -.->|"subagent"| RCore
|
|
192
|
+
PMCore -.->|"subagent"| UXCore
|
|
193
|
+
UXCore -.->|"subagent"| DCore
|
|
194
|
+
DCore -.->|"subagent"| TCore
|
|
195
|
+
SCore -.->|"subagent"| DCore
|
|
121
196
|
```
|
|
122
197
|
|
|
123
198
|
## Quick Commands
|
|
@@ -174,6 +249,38 @@ Beth operates on a few principles:
|
|
|
174
249
|
3. **Move fast, break enemies** — Parallel execution, aggressive timelines.
|
|
175
250
|
4. **Loyalty earns trust** — Agents that perform get the good work.
|
|
176
251
|
|
|
252
|
+
### IDEO Design Thinking
|
|
253
|
+
|
|
254
|
+
Beth follows human-centered design methodology:
|
|
255
|
+
|
|
256
|
+
```mermaid
|
|
257
|
+
flowchart LR
|
|
258
|
+
subgraph Empathize["1. Empathize"]
|
|
259
|
+
E["@researcher<br/>User interviews<br/>Pain points"]
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
subgraph Define["2. Define"]
|
|
263
|
+
D["@product-manager<br/>Problem framing<br/>Requirements"]
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
subgraph Ideate["3. Ideate"]
|
|
267
|
+
I["@ux-designer<br/>Component specs<br/>Patterns"]
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
subgraph Prototype["4. Prototype"]
|
|
271
|
+
P["@developer<br/>Build to learn<br/>Feature spikes"]
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
subgraph Test["5. Test"]
|
|
275
|
+
T["@tester<br/>Validate<br/>Accessibility"]
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
E --> D --> I --> P --> T
|
|
279
|
+
T -.->|iterate| E
|
|
280
|
+
T -.->|iterate| D
|
|
281
|
+
T -.->|iterate| I
|
|
282
|
+
```
|
|
283
|
+
|
|
177
284
|
## Quality Standards
|
|
178
285
|
|
|
179
286
|
Beth doesn't ship garbage:
|
|
@@ -184,6 +291,39 @@ Beth doesn't ship garbage:
|
|
|
184
291
|
- **Type Safety**: Full TypeScript coverage. No `any` unless you want a lecture.
|
|
185
292
|
- **Test Coverage**: Unit, integration, E2E. If it's not tested, it's not done.
|
|
186
293
|
|
|
294
|
+
```mermaid
|
|
295
|
+
flowchart TB
|
|
296
|
+
subgraph Standards["Quality Standards"]
|
|
297
|
+
A11y["WCAG 2.1 AA<br/>Accessibility"]
|
|
298
|
+
Perf["Core Web Vitals<br/>LCP < 2.5s"]
|
|
299
|
+
Sec["OWASP Compliant<br/>Zero vulnerabilities"]
|
|
300
|
+
Type["Full TypeScript<br/>No any"]
|
|
301
|
+
Coverage["Test Coverage<br/>Unit + Integration + E2E"]
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
subgraph Gates["Enforcement"]
|
|
305
|
+
Designer["UX Designer<br/>reviews a11y specs"]
|
|
306
|
+
Developer["Developer<br/>implements patterns"]
|
|
307
|
+
Security["Security Reviewer<br/>audits code"]
|
|
308
|
+
Tester["Tester<br/>verifies all gates"]
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
A11y --> Designer
|
|
312
|
+
Perf --> Developer
|
|
313
|
+
Sec --> Security
|
|
314
|
+
Type --> Developer
|
|
315
|
+
Coverage --> Tester
|
|
316
|
+
|
|
317
|
+
Designer --> Ship{Ship?}
|
|
318
|
+
Developer --> Ship
|
|
319
|
+
Security --> Ship
|
|
320
|
+
Tester --> Ship
|
|
321
|
+
|
|
322
|
+
Ship -->|All Pass| Deploy["🚀 Deploy"]
|
|
323
|
+
Ship -->|Fail| Fix["🔧 Fix & Retry"]
|
|
324
|
+
Fix --> Gates
|
|
325
|
+
```
|
|
326
|
+
|
|
187
327
|
## Why Beth?
|
|
188
328
|
|
|
189
329
|
<p align="center">
|
|
@@ -225,6 +365,7 @@ Full details: [docs/MCP-SETUP.md](docs/MCP-SETUP.md)
|
|
|
225
365
|
|
|
226
366
|
- [Installation Guide](docs/INSTALLATION.md) — Full setup instructions
|
|
227
367
|
- [MCP Setup](docs/MCP-SETUP.md) — Optional server integrations
|
|
368
|
+
- [System Flow & Diagrams](docs/SYSTEM-FLOW.md) — Architecture and agent orchestration diagrams
|
|
228
369
|
- [Changelog](CHANGELOG.md) — Version history and updates
|
|
229
370
|
- [Security Policy](SECURITY.md) — Vulnerability reporting
|
|
230
371
|
|
package/bin/cli.js
CHANGED
|
@@ -2,16 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join, relative } from 'path';
|
|
5
|
-
import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync } from 'fs';
|
|
5
|
+
import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import { execSync, spawn } from 'child_process';
|
|
8
|
-
import { validateBeadsPath,
|
|
8
|
+
import { validateBeadsPath, validateBinaryPath } from './lib/pathValidation.js';
|
|
9
9
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
12
|
const __dirname = dirname(__filename);
|
|
13
13
|
const TEMPLATES_DIR = join(__dirname, '..', 'templates');
|
|
14
14
|
|
|
15
|
+
// TypeScript commands are in dist/ after build
|
|
16
|
+
const DIST_DIR = join(__dirname, '..', 'dist');
|
|
17
|
+
|
|
18
|
+
// Dynamic import for TypeScript commands (lazy loaded)
|
|
19
|
+
async function loadTsCommand(commandName) {
|
|
20
|
+
const commandPath = join(DIST_DIR, 'cli', 'commands', `${commandName}.js`);
|
|
21
|
+
if (!existsSync(commandPath)) {
|
|
22
|
+
console.error(`Command '${commandName}' not found. Run 'npm run build' first.`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
return import(commandPath);
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
// Get current package version
|
|
16
29
|
const packageJson = require('../package.json');
|
|
17
30
|
const CURRENT_VERSION = packageJson.version;
|
|
@@ -396,6 +409,54 @@ function logError(message) {
|
|
|
396
409
|
log(`✗ ${message}`, COLORS.red);
|
|
397
410
|
}
|
|
398
411
|
|
|
412
|
+
/**
|
|
413
|
+
* User-facing error with actionable fix instructions
|
|
414
|
+
*/
|
|
415
|
+
class UserError extends Error {
|
|
416
|
+
constructor(message, { problem, fix, command } = {}) {
|
|
417
|
+
super(message);
|
|
418
|
+
this.name = 'UserError';
|
|
419
|
+
this.problem = problem;
|
|
420
|
+
this.fix = fix;
|
|
421
|
+
this.command = command;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Display a user-friendly error with fix instructions
|
|
427
|
+
*/
|
|
428
|
+
function showUserError(error) {
|
|
429
|
+
console.log('');
|
|
430
|
+
console.log(`${COLORS.red}╔════════════════════════════════════════════════════════════╗${COLORS.reset}`);
|
|
431
|
+
console.log(`${COLORS.red}║${COLORS.reset} ${COLORS.bright}${COLORS.red}Installation Error${COLORS.reset} ${COLORS.red}║${COLORS.reset}`);
|
|
432
|
+
console.log(`${COLORS.red}╚════════════════════════════════════════════════════════════╝${COLORS.reset}`);
|
|
433
|
+
console.log('');
|
|
434
|
+
|
|
435
|
+
if (error.problem) {
|
|
436
|
+
console.log(`${COLORS.bright}Problem:${COLORS.reset}`);
|
|
437
|
+
console.log(` ${error.problem}`);
|
|
438
|
+
console.log('');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (error.fix) {
|
|
442
|
+
console.log(`${COLORS.bright}Fix:${COLORS.reset}`);
|
|
443
|
+
console.log(` ${error.fix}`);
|
|
444
|
+
console.log('');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (error.command) {
|
|
448
|
+
console.log(`${COLORS.bright}Run this command:${COLORS.reset}`);
|
|
449
|
+
console.log(` ${COLORS.cyan}${error.command}${COLORS.reset}`);
|
|
450
|
+
console.log('');
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (globalThis.VERBOSE) {
|
|
454
|
+
console.log(`${COLORS.dim}Stack trace:${COLORS.reset}`);
|
|
455
|
+
console.log(`${COLORS.dim}${error.stack}${COLORS.reset}`);
|
|
456
|
+
console.log('');
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
399
460
|
function logInfo(message) {
|
|
400
461
|
log(` ${message}`, COLORS.cyan);
|
|
401
462
|
}
|
|
@@ -457,48 +518,6 @@ async function checkForUpdates() {
|
|
|
457
518
|
}
|
|
458
519
|
}
|
|
459
520
|
|
|
460
|
-
function getBacklogPath() {
|
|
461
|
-
// Check if backlog is available in PATH
|
|
462
|
-
try {
|
|
463
|
-
logDebug('Checking if backlog is in PATH...');
|
|
464
|
-
execSync('backlog --version', { stdio: 'ignore' });
|
|
465
|
-
logDebug('Found backlog in PATH');
|
|
466
|
-
return 'backlog';
|
|
467
|
-
} catch {
|
|
468
|
-
logDebug('backlog not in PATH, checking common locations...');
|
|
469
|
-
// Check common installation paths
|
|
470
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
471
|
-
const isWindows = process.platform === 'win32';
|
|
472
|
-
|
|
473
|
-
const commonPaths = isWindows ? [
|
|
474
|
-
join(process.env.APPDATA || '', 'npm', 'backlog.cmd'),
|
|
475
|
-
join(homeDir, 'AppData', 'Roaming', 'npm', 'backlog.cmd'),
|
|
476
|
-
join(homeDir, 'AppData', 'Local', 'npm-global', 'backlog.cmd'),
|
|
477
|
-
] : [
|
|
478
|
-
join(homeDir, '.local', 'bin', 'backlog'),
|
|
479
|
-
join(homeDir, 'bin', 'backlog'),
|
|
480
|
-
'/usr/local/bin/backlog',
|
|
481
|
-
join(homeDir, '.npm-global', 'bin', 'backlog'),
|
|
482
|
-
join(homeDir, '.bun', 'bin', 'backlog'),
|
|
483
|
-
];
|
|
484
|
-
|
|
485
|
-
for (const backlogPath of commonPaths) {
|
|
486
|
-
logDebug(`Checking: ${backlogPath}`);
|
|
487
|
-
if (existsSync(backlogPath)) {
|
|
488
|
-
logDebug(`Found at: ${backlogPath}`);
|
|
489
|
-
return backlogPath;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
logDebug('backlog not found in any common location');
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function isBacklogCliInstalled() {
|
|
499
|
-
return getBacklogPath() !== null;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
521
|
function getBeadsPath() {
|
|
503
522
|
// Check if bd is available in PATH
|
|
504
523
|
try {
|
|
@@ -582,79 +601,6 @@ async function promptForInput(question) {
|
|
|
582
601
|
});
|
|
583
602
|
}
|
|
584
603
|
|
|
585
|
-
/**
|
|
586
|
-
* Installs the backlog.md CLI globally via npm.
|
|
587
|
-
*
|
|
588
|
-
* SECURITY NOTE - shell:true usage:
|
|
589
|
-
* - Required for cross-platform npm execution (npm.cmd on Windows, npm on Unix)
|
|
590
|
-
* - Arguments are HARDCODED - no user input is passed to the shell
|
|
591
|
-
* - Command injection risk: NONE (no dynamic/user-supplied values)
|
|
592
|
-
*
|
|
593
|
-
* Alternative considered: Using platform-specific binary names (npm.cmd vs npm)
|
|
594
|
-
* would eliminate shell:true but adds complexity and edge cases for non-standard installs.
|
|
595
|
-
*
|
|
596
|
-
* @returns {Promise<boolean>} True if installation succeeded and was verified
|
|
597
|
-
*/
|
|
598
|
-
async function installBacklogCli() {
|
|
599
|
-
const isWindows = process.platform === 'win32';
|
|
600
|
-
const isMac = process.platform === 'darwin';
|
|
601
|
-
|
|
602
|
-
log('\nInstalling backlog.md CLI via npm...', COLORS.cyan);
|
|
603
|
-
logInfo('npm install -g backlog.md');
|
|
604
|
-
|
|
605
|
-
// SECURITY: shell:true is required for cross-platform npm execution.
|
|
606
|
-
// All arguments are hardcoded constants - no user input reaches the shell.
|
|
607
|
-
return new Promise((resolve) => {
|
|
608
|
-
const child = spawn('npm', ['install', '-g', 'backlog.md'], {
|
|
609
|
-
stdio: 'inherit',
|
|
610
|
-
shell: true
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
child.on('close', (code) => {
|
|
614
|
-
if (code === 0) {
|
|
615
|
-
// CRITICAL: Verify installation actually worked before claiming success
|
|
616
|
-
const verifiedPath = getBacklogPath();
|
|
617
|
-
if (verifiedPath) {
|
|
618
|
-
logSuccess('backlog.md CLI installed and verified!');
|
|
619
|
-
resolve(true);
|
|
620
|
-
} else {
|
|
621
|
-
logWarning('npm reported success but backlog CLI not found in PATH.');
|
|
622
|
-
logInfo('This can happen if npm global bin is not in your PATH.');
|
|
623
|
-
if (globalThis.VERBOSE) {
|
|
624
|
-
showPathDiagnostics();
|
|
625
|
-
} else {
|
|
626
|
-
logInfo('Run with --verbose for PATH diagnostics.');
|
|
627
|
-
}
|
|
628
|
-
console.log('');
|
|
629
|
-
showBacklogAlternatives(isMac);
|
|
630
|
-
resolve(false);
|
|
631
|
-
}
|
|
632
|
-
} else {
|
|
633
|
-
logError('npm install failed.');
|
|
634
|
-
console.log('');
|
|
635
|
-
showBacklogAlternatives(isMac);
|
|
636
|
-
resolve(false);
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
child.on('error', () => {
|
|
641
|
-
logError('Failed to run npm.');
|
|
642
|
-
logInfo('Make sure npm is installed and in your PATH.');
|
|
643
|
-
resolve(false);
|
|
644
|
-
});
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
function showBacklogAlternatives(isMac) {
|
|
649
|
-
logInfo('Alternative installation methods:');
|
|
650
|
-
if (isMac) {
|
|
651
|
-
logInfo(' Homebrew: brew install backlog-md');
|
|
652
|
-
}
|
|
653
|
-
logInfo(' Bun: bun install -g backlog.md');
|
|
654
|
-
logInfo('');
|
|
655
|
-
logInfo('Learn more: https://github.com/MrLesk/Backlog.md');
|
|
656
|
-
}
|
|
657
|
-
|
|
658
604
|
/**
|
|
659
605
|
* Installs the beads CLI globally via npm.
|
|
660
606
|
*
|
|
@@ -793,6 +739,8 @@ function showHelp() {
|
|
|
793
739
|
|
|
794
740
|
${COLORS.bright}Usage:${COLORS.reset}
|
|
795
741
|
npx beth-copilot init [options] Initialize Beth in current directory
|
|
742
|
+
npx beth-copilot doctor Check system health and dependencies
|
|
743
|
+
npx beth-copilot quickstart Run init + doctor + beads setup
|
|
796
744
|
npx beth-copilot help Show this help message
|
|
797
745
|
|
|
798
746
|
${COLORS.bright}Options:${COLORS.reset}
|
|
@@ -805,10 +753,11 @@ ${COLORS.bright}Options:${COLORS.reset}
|
|
|
805
753
|
${COLORS.bright}Examples:${COLORS.reset}
|
|
806
754
|
npx beth-copilot init Set up Beth in current project
|
|
807
755
|
npx beth-copilot init --force Overwrite existing Beth files
|
|
756
|
+
npx beth-copilot doctor Verify installation health
|
|
808
757
|
|
|
809
758
|
${COLORS.bright}What gets installed:${COLORS.reset}
|
|
810
|
-
.github/agents/
|
|
811
|
-
.github/skills/
|
|
759
|
+
.github/agents/ 7 specialized AI agents
|
|
760
|
+
.github/skills/ 8 domain knowledge modules
|
|
812
761
|
.github/copilot-instructions.md Copilot configuration
|
|
813
762
|
.vscode/settings.json Recommended VS Code settings
|
|
814
763
|
AGENTS.md Workflow documentation
|
|
@@ -828,7 +777,26 @@ ${COLORS.bright}Documentation:${COLORS.reset}
|
|
|
828
777
|
function copyDirRecursive(src, dest, options = {}) {
|
|
829
778
|
const { force = false, copiedFiles = [] } = options;
|
|
830
779
|
|
|
831
|
-
if (
|
|
780
|
+
if (existsSync(dest)) {
|
|
781
|
+
const destStats = statSync(dest);
|
|
782
|
+
if (!destStats.isDirectory()) {
|
|
783
|
+
if (force) {
|
|
784
|
+
// Destination exists as a file but should be a directory - remove it
|
|
785
|
+
unlinkSync(dest);
|
|
786
|
+
mkdirSync(dest, { recursive: true });
|
|
787
|
+
} else {
|
|
788
|
+
const relativePath = relative(process.cwd(), dest);
|
|
789
|
+
throw new UserError(
|
|
790
|
+
`Path conflict: ${relativePath}`,
|
|
791
|
+
{
|
|
792
|
+
problem: `"${relativePath}" exists as a file, but Beth needs it to be a directory.`,
|
|
793
|
+
fix: 'Either remove the file manually, or use --force to let Beth handle it.',
|
|
794
|
+
command: 'npx beth-copilot@latest init --force'
|
|
795
|
+
}
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
832
800
|
mkdirSync(dest, { recursive: true });
|
|
833
801
|
}
|
|
834
802
|
|
|
@@ -1080,87 +1048,17 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1080
1048
|
logWarning('Skipped beads check (--skip-beads). Beth may not function correctly.');
|
|
1081
1049
|
}
|
|
1082
1050
|
|
|
1083
|
-
// Check for backlog.md CLI (REQUIRED for Beth)
|
|
1084
|
-
if (!skipBacklog) {
|
|
1085
|
-
console.log('');
|
|
1086
|
-
log('Checking backlog.md CLI (required for task management)...', COLORS.cyan);
|
|
1087
|
-
|
|
1088
|
-
let backlogPath = getBacklogPath();
|
|
1089
|
-
|
|
1090
|
-
// Loop until backlog.md is installed
|
|
1091
|
-
while (!backlogPath) {
|
|
1092
|
-
logWarning('backlog.md CLI is not installed.');
|
|
1093
|
-
logInfo('Beth requires backlog.md for human-readable task tracking and boards.');
|
|
1094
|
-
logInfo('Learn more: https://github.com/MrLesk/Backlog.md');
|
|
1095
|
-
console.log('');
|
|
1096
|
-
|
|
1097
|
-
const shouldInstall = await promptYesNo('Install backlog.md CLI now? (required)');
|
|
1098
|
-
if (shouldInstall) {
|
|
1099
|
-
const installed = await installBacklogCli();
|
|
1100
|
-
if (installed) {
|
|
1101
|
-
// Re-check for backlog after installation
|
|
1102
|
-
backlogPath = getBacklogPath();
|
|
1103
|
-
if (!backlogPath) {
|
|
1104
|
-
console.log('');
|
|
1105
|
-
logWarning('backlog.md installed but not found in common paths.');
|
|
1106
|
-
logInfo('The installer may have placed it in a custom location.');
|
|
1107
|
-
console.log('');
|
|
1108
|
-
logInfo('Please try one of these options:');
|
|
1109
|
-
logInfo(' 1. Open a NEW terminal and run: npx beth-copilot init');
|
|
1110
|
-
logInfo(' 2. Run: source ~/.bashrc (or ~/.zshrc) then retry');
|
|
1111
|
-
console.log('');
|
|
1112
|
-
|
|
1113
|
-
const retryCheck = await promptYesNo('Retry detection?');
|
|
1114
|
-
if (retryCheck) {
|
|
1115
|
-
backlogPath = getBacklogPath();
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
} else {
|
|
1119
|
-
console.log('');
|
|
1120
|
-
logError('Installation failed.');
|
|
1121
|
-
logInfo('You can try installing manually:');
|
|
1122
|
-
logInfo(' npm install -g backlog.md');
|
|
1123
|
-
if (process.platform === 'darwin') {
|
|
1124
|
-
logInfo(' brew install backlog-md');
|
|
1125
|
-
}
|
|
1126
|
-
logInfo(' bun install -g backlog.md');
|
|
1127
|
-
console.log('');
|
|
1128
|
-
}
|
|
1129
|
-
} else {
|
|
1130
|
-
console.log('');
|
|
1131
|
-
logError('backlog.md is REQUIRED for Beth to function.');
|
|
1132
|
-
logInfo('Beth uses Backlog.md to maintain human-readable task history and boards.');
|
|
1133
|
-
logInfo('This complements beads for a complete task management workflow.');
|
|
1134
|
-
console.log('');
|
|
1135
|
-
|
|
1136
|
-
const tryAgain = await promptYesNo('Would you like to try installing backlog.md?');
|
|
1137
|
-
if (!tryAgain) {
|
|
1138
|
-
logError('Cannot continue without backlog.md. Exiting.');
|
|
1139
|
-
logInfo('Install manually and run "npx beth-copilot init" again:');
|
|
1140
|
-
logInfo(' npm install -g backlog.md');
|
|
1141
|
-
process.exit(1);
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
logSuccess('backlog.md CLI is installed');
|
|
1147
|
-
} else {
|
|
1148
|
-
logWarning('Skipped backlog check (--skip-backlog). Beth may not function correctly.');
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
1051
|
// Final verification
|
|
1152
1052
|
console.log('');
|
|
1153
1053
|
log('Verifying installation...', COLORS.cyan);
|
|
1154
1054
|
|
|
1155
1055
|
const finalBeadsOk = skipBeads || getBeadsPath();
|
|
1156
|
-
const finalBacklogOk = skipBacklog || getBacklogPath();
|
|
1157
1056
|
const finalBeadsInit = skipBeads || isBeadsInitialized(cwd);
|
|
1158
1057
|
|
|
1159
|
-
if (finalBeadsOk &&
|
|
1058
|
+
if (finalBeadsOk && finalBeadsInit) {
|
|
1160
1059
|
logSuccess('All dependencies installed and configured!');
|
|
1161
1060
|
} else {
|
|
1162
1061
|
if (!finalBeadsOk) logError('beads CLI not found');
|
|
1163
|
-
if (!finalBacklogOk) logError('backlog.md CLI not found');
|
|
1164
1062
|
if (!finalBeadsInit) logError('beads not initialized in project');
|
|
1165
1063
|
logError('Setup incomplete. Please resolve issues above and run init again.');
|
|
1166
1064
|
process.exit(1);
|
|
@@ -1183,7 +1081,7 @@ ${COLORS.cyan}"They broke my wings and forgot I had claws."${COLORS.reset}
|
|
|
1183
1081
|
}
|
|
1184
1082
|
|
|
1185
1083
|
// Input validation constants
|
|
1186
|
-
const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h'];
|
|
1084
|
+
const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h', 'doctor', 'quickstart'];
|
|
1187
1085
|
const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--skip-beads', '--verbose'];
|
|
1188
1086
|
const MAX_ARG_LENGTH = 50;
|
|
1189
1087
|
|
|
@@ -1230,7 +1128,27 @@ if (unknownFlags.length > 0) {
|
|
|
1230
1128
|
|
|
1231
1129
|
switch (command) {
|
|
1232
1130
|
case 'init':
|
|
1233
|
-
|
|
1131
|
+
try {
|
|
1132
|
+
await init(options);
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
if (error instanceof UserError) {
|
|
1135
|
+
showUserError(error);
|
|
1136
|
+
process.exit(1);
|
|
1137
|
+
}
|
|
1138
|
+
throw error;
|
|
1139
|
+
}
|
|
1140
|
+
break;
|
|
1141
|
+
case 'doctor':
|
|
1142
|
+
{
|
|
1143
|
+
const { doctor } = await loadTsCommand('doctor');
|
|
1144
|
+
await doctor(options);
|
|
1145
|
+
}
|
|
1146
|
+
break;
|
|
1147
|
+
case 'quickstart':
|
|
1148
|
+
{
|
|
1149
|
+
const { quickstart } = await loadTsCommand('quickstart');
|
|
1150
|
+
await quickstart(options);
|
|
1151
|
+
}
|
|
1234
1152
|
break;
|
|
1235
1153
|
case 'help':
|
|
1236
1154
|
case '--help':
|