@samahlstrom/forge-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +175 -0
  2. package/bin/forge.js +2 -0
  3. package/dist/addons/index.d.ts +25 -0
  4. package/dist/addons/index.js +139 -0
  5. package/dist/addons/index.js.map +1 -0
  6. package/dist/commands/add.d.ts +1 -0
  7. package/dist/commands/add.js +61 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/doctor.d.ts +1 -0
  10. package/dist/commands/doctor.js +177 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/ingest.d.ts +24 -0
  13. package/dist/commands/ingest.js +316 -0
  14. package/dist/commands/ingest.js.map +1 -0
  15. package/dist/commands/init.d.ts +8 -0
  16. package/dist/commands/init.js +557 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/remove.d.ts +1 -0
  19. package/dist/commands/remove.js +42 -0
  20. package/dist/commands/remove.js.map +1 -0
  21. package/dist/commands/status.d.ts +1 -0
  22. package/dist/commands/status.js +48 -0
  23. package/dist/commands/status.js.map +1 -0
  24. package/dist/commands/upgrade.d.ts +5 -0
  25. package/dist/commands/upgrade.js +190 -0
  26. package/dist/commands/upgrade.js.map +1 -0
  27. package/dist/detect/features.d.ts +10 -0
  28. package/dist/detect/features.js +33 -0
  29. package/dist/detect/features.js.map +1 -0
  30. package/dist/detect/go.d.ts +3 -0
  31. package/dist/detect/go.js +38 -0
  32. package/dist/detect/go.js.map +1 -0
  33. package/dist/detect/index.d.ts +25 -0
  34. package/dist/detect/index.js +32 -0
  35. package/dist/detect/index.js.map +1 -0
  36. package/dist/detect/node.d.ts +3 -0
  37. package/dist/detect/node.js +99 -0
  38. package/dist/detect/node.js.map +1 -0
  39. package/dist/detect/python.d.ts +3 -0
  40. package/dist/detect/python.js +86 -0
  41. package/dist/detect/python.js.map +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +51 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/render/engine.d.ts +8 -0
  46. package/dist/render/engine.js +71 -0
  47. package/dist/render/engine.js.map +1 -0
  48. package/dist/render/merge.d.ts +5 -0
  49. package/dist/render/merge.js +33 -0
  50. package/dist/render/merge.js.map +1 -0
  51. package/dist/utils/fs.d.ts +8 -0
  52. package/dist/utils/fs.js +42 -0
  53. package/dist/utils/fs.js.map +1 -0
  54. package/dist/utils/git.d.ts +3 -0
  55. package/dist/utils/git.js +31 -0
  56. package/dist/utils/git.js.map +1 -0
  57. package/dist/utils/hash.d.ts +8 -0
  58. package/dist/utils/hash.js +22 -0
  59. package/dist/utils/hash.js.map +1 -0
  60. package/dist/utils/yaml.d.ts +3 -0
  61. package/dist/utils/yaml.js +12 -0
  62. package/dist/utils/yaml.js.map +1 -0
  63. package/package.json +53 -0
  64. package/templates/addons/beads-dolt-backend/files/dolt-setup.sh +267 -0
  65. package/templates/addons/beads-dolt-backend/manifest.yaml +13 -0
  66. package/templates/addons/browser-testing/files/browser-smoke.sh +196 -0
  67. package/templates/addons/browser-testing/files/visual-qa.md +103 -0
  68. package/templates/addons/browser-testing/manifest.yaml +20 -0
  69. package/templates/addons/compliance-hipaa/files/hipaa-checks.sh +184 -0
  70. package/templates/addons/compliance-hipaa/files/hipaa-context.md +91 -0
  71. package/templates/addons/compliance-hipaa/manifest.yaml +15 -0
  72. package/templates/addons/compliance-soc2/files/soc2-checks.sh +232 -0
  73. package/templates/addons/compliance-soc2/files/soc2-context.md +147 -0
  74. package/templates/addons/compliance-soc2/manifest.yaml +15 -0
  75. package/templates/core/CLAUDE.md.hbs +70 -0
  76. package/templates/core/agents/architect.md.hbs +68 -0
  77. package/templates/core/agents/backend.md.hbs +27 -0
  78. package/templates/core/agents/frontend.md.hbs +25 -0
  79. package/templates/core/agents/quality.md.hbs +40 -0
  80. package/templates/core/agents/security.md.hbs +53 -0
  81. package/templates/core/context/project.md.hbs +60 -0
  82. package/templates/core/forge.yaml.hbs +69 -0
  83. package/templates/core/hooks/post-edit.sh.hbs +8 -0
  84. package/templates/core/hooks/pre-edit.sh.hbs +41 -0
  85. package/templates/core/hooks/session-start.sh.hbs +34 -0
  86. package/templates/core/pipeline/classify.sh.hbs +159 -0
  87. package/templates/core/pipeline/decompose.md.hbs +100 -0
  88. package/templates/core/pipeline/deliver.sh.hbs +171 -0
  89. package/templates/core/pipeline/execute.md.hbs +138 -0
  90. package/templates/core/pipeline/intake.sh.hbs +152 -0
  91. package/templates/core/pipeline/orchestrator.sh.hbs +361 -0
  92. package/templates/core/pipeline/verify.sh.hbs +160 -0
  93. package/templates/core/settings.json.hbs +55 -0
  94. package/templates/core/skill-creator.md.hbs +151 -0
  95. package/templates/core/skill-deliver.md.hbs +46 -0
  96. package/templates/core/skill-ingest.md.hbs +245 -0
  97. package/templates/presets/go/stack.md.hbs +133 -0
  98. package/templates/presets/python-fastapi/stack.md.hbs +101 -0
  99. package/templates/presets/react-next-ts/stack.md.hbs +77 -0
  100. package/templates/presets/sveltekit-ts/stack.md.hbs +116 -0
package/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # forge-cli
2
+
3
+ AI agent pipeline scaffolding for [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Turns any repository into an orchestrated, multi-agent workspace with decomposition, risk classification, parallel execution, and automated delivery.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx @samahlstrom/forge-cli init
9
+ ```
10
+
11
+ That's it. One command in any project directory.
12
+
13
+ ## What it does
14
+
15
+ `forge init` scans your project, asks a few questions about what you're building, and generates a complete `.forge/` harness with:
16
+
17
+ - **Pipeline scripts** — a state machine that routes work through intake, classification, decomposition, execution, verification, and delivery
18
+ - **Specialist agents** — architect, backend, frontend, quality, and security agents (only the ones your project needs)
19
+ - **Risk classification** — T1/T2/T3 tiers that determine how much decomposition and verification a task gets
20
+ - **Bead tracking** — every unit of work is tracked with file locking, checkpoints, and audit trails
21
+ - **Hooks** — pre-edit and post-edit hooks that enforce tracked work and log modifications
22
+ - **Skills** — `/deliver`, `/ingest`, and `/skill-creator` commands for Claude Code
23
+
24
+ ## Quick start
25
+
26
+ ### New project from scratch
27
+
28
+ ```bash
29
+ mkdir my-app && cd my-app && git init
30
+ npx @samahlstrom/forge-cli init
31
+ ```
32
+
33
+ The onboarding asks what language, framework, and project type you want, then generates everything.
34
+
35
+ ### Existing project
36
+
37
+ ```bash
38
+ cd my-existing-project
39
+ npx @samahlstrom/forge-cli init
40
+ ```
41
+
42
+ Forge auto-detects your stack (language, framework, test runner, linter) and generates a harness that matches.
43
+
44
+ ### From a spec document
45
+
46
+ ```bash
47
+ mkdir my-app && cd my-app && git init
48
+ npx @samahlstrom/forge-cli init --spec ~/Downloads/project-spec.pdf
49
+ ```
50
+
51
+ Forge analyzes the spec with Claude, extracts project metadata (language, modules, architecture, constraints), and pre-fills everything. No manual onboarding needed.
52
+
53
+ ## Usage
54
+
55
+ After init, open Claude Code in your project:
56
+
57
+ ### `/deliver` — execute tracked work
58
+
59
+ ```
60
+ /deliver "Add JWT authentication with role-based access"
61
+ ```
62
+
63
+ The pipeline:
64
+ 1. **Intake** — parses and scores the work description
65
+ 2. **Classify** — assigns risk tier (T1 low, T2 moderate, T3 critical)
66
+ 3. **Decompose** — breaks complex work into parallel-safe subtasks
67
+ 4. **Execute** — dispatches subtasks to specialist agents
68
+ 5. **Verify** — runs typecheck, lint, tests, anti-pattern checks
69
+ 6. **Deliver** — creates branch, commits, pushes, opens PR
70
+
71
+ ### `/ingest` — decompose a spec into a project plan
72
+
73
+ ```bash
74
+ # Add a spec to your project
75
+ npx @samahlstrom/forge-cli ingest ~/Downloads/platform-spec.pdf
76
+
77
+ # Then in Claude Code:
78
+ /ingest spec-a1b2
79
+ ```
80
+
81
+ Multi-pass analysis:
82
+ 1. **Extract** — sections, requirements, constraints, data entities
83
+ 2. **Map domains** — group into modules with dependency graph
84
+ 3. **Decompose** — epics, features, atomic tasks
85
+ 4. **Identify skills** — find repeated patterns worth automating
86
+
87
+ You review and refine the plan before any code is written. Then execute phase-by-phase through `/deliver`.
88
+
89
+ ### `/skill-creator` — generate custom skills
90
+
91
+ ```
92
+ /skill-creator
93
+ ```
94
+
95
+ Create new Claude Code skills for domain-specific workflows. The ingestion system can also auto-generate skills from patterns it finds in your spec.
96
+
97
+ ## Commands
98
+
99
+ | Command | Description |
100
+ |---|---|
101
+ | `forge init` | Initialize harness in current project |
102
+ | `forge init --spec <file>` | Initialize from a spec document (PDF, markdown, text) |
103
+ | `forge ingest <file>` | Add a spec to an existing project for analysis |
104
+ | `forge add <addon>` | Install an addon (browser-testing, compliance-hipaa, compliance-soc2) |
105
+ | `forge remove <addon>` | Remove an addon |
106
+ | `forge status` | Show harness status, agents, addons |
107
+ | `forge doctor` | Diagnose harness health |
108
+ | `forge upgrade` | Upgrade harness files to latest version |
109
+
110
+ ## What gets generated
111
+
112
+ ```
113
+ my-project/
114
+ ├── forge.yaml # Main configuration
115
+ ├── CLAUDE.md # Agent instructions
116
+ ├── .claude/
117
+ │ ├── settings.json # Permissions and hooks
118
+ │ └── skills/
119
+ │ ├── deliver/SKILL.md # /deliver command
120
+ │ ├── ingest/SKILL.md # /ingest command
121
+ │ └── skill-creator/SKILL.md # /skill-creator command
122
+ └── .forge/
123
+ ├── pipeline/ # State machine scripts
124
+ │ ├── orchestrator.sh
125
+ │ ├── intake.sh
126
+ │ ├── classify.sh
127
+ │ ├── decompose.md
128
+ │ ├── execute.md
129
+ │ ├── verify.sh
130
+ │ └── deliver.sh
131
+ ├── agents/ # Specialist agent definitions
132
+ │ ├── architect.md
133
+ │ ├── backend.md # (if project needs it)
134
+ │ ├── frontend.md # (if project needs it)
135
+ │ ├── quality.md
136
+ │ └── security.md
137
+ ├── context/ # Project knowledge
138
+ │ ├── stack.md # Tech stack conventions
139
+ │ └── project.md # Your project context
140
+ ├── hooks/ # Claude Code lifecycle hooks
141
+ ├── specs/ # Ingested spec documents
142
+ └── addons/ # Installed addon files
143
+ .beads/ # bd task tracking (Dolt database)
144
+ ```
145
+
146
+ ## Supported stacks
147
+
148
+ Forge auto-detects and has presets for:
149
+
150
+ - **TypeScript/JavaScript** — Next.js, SvelteKit
151
+ - **Python** — FastAPI, Django, Flask
152
+ - **Go** — Gin, Chi, Fiber
153
+
154
+ Works with any project regardless of stack — presets just provide stack-specific conventions.
155
+
156
+ ## Addons
157
+
158
+ ```bash
159
+ forge add browser-testing # Playwright visual QA
160
+ forge add compliance-hipaa # HIPAA security checks
161
+ forge add compliance-soc2 # SOC2 compliance verification
162
+ ```
163
+
164
+ ## Requirements
165
+
166
+ - Node.js 18+
167
+ - Git
168
+ - [`bd`](https://github.com/steveyegge/beads) (task tracking — `brew install beads`)
169
+ - `jq` (for JSON processing in pipeline scripts)
170
+ - `gh` CLI (for PR creation)
171
+ - Claude Code (to run the generated harness)
172
+
173
+ ## License
174
+
175
+ MIT
package/bin/forge.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,25 @@
1
+ export interface AddonManifest {
2
+ name: string;
3
+ description: string;
4
+ version: number;
5
+ requires?: {
6
+ commands?: Record<string, boolean>;
7
+ };
8
+ patches: {
9
+ forge_yaml?: Record<string, unknown>;
10
+ agents?: string[];
11
+ };
12
+ files: Array<{
13
+ source: string;
14
+ target: string;
15
+ }>;
16
+ post_install?: string[];
17
+ }
18
+ declare const ADDON_NAMES: readonly ["browser-testing", "compliance-hipaa", "compliance-soc2"];
19
+ export type AddonName = (typeof ADDON_NAMES)[number];
20
+ export declare function isValidAddon(name: string): name is AddonName;
21
+ export declare function listAvailableAddons(): readonly string[];
22
+ export declare function getAddonManifest(addonName: string): Promise<AddonManifest>;
23
+ export declare function installAddon(addonName: string, cwd: string): Promise<string[]>;
24
+ export declare function uninstallAddon(addonName: string, cwd: string): Promise<string[]>;
25
+ export {};
@@ -0,0 +1,139 @@
1
+ import { join } from 'node:path';
2
+ import { parse } from 'yaml';
3
+ import { readText, exists, writeText, ensureDir } from '../utils/fs.js';
4
+ import { resolveTemplatePath } from '../utils/fs.js';
5
+ import { readYaml, writeYaml } from '../utils/yaml.js';
6
+ import { hashContent, readHashes, writeHashes } from '../utils/hash.js';
7
+ const ADDON_NAMES = ['browser-testing', 'compliance-hipaa', 'compliance-soc2'];
8
+ export function isValidAddon(name) {
9
+ return ADDON_NAMES.includes(name);
10
+ }
11
+ export function listAvailableAddons() {
12
+ return ADDON_NAMES;
13
+ }
14
+ export async function getAddonManifest(addonName) {
15
+ const manifestPath = resolveTemplatePath('addons', addonName, 'manifest.yaml');
16
+ const text = await readText(manifestPath);
17
+ return parse(text);
18
+ }
19
+ export async function installAddon(addonName, cwd) {
20
+ const manifest = await getAddonManifest(addonName);
21
+ const installedFiles = [];
22
+ // Check requirements
23
+ if (manifest.requires?.commands) {
24
+ const forgeYaml = await readYaml(join(cwd, 'forge.yaml'));
25
+ const commands = forgeYaml.commands;
26
+ for (const [cmd, required] of Object.entries(manifest.requires.commands)) {
27
+ if (required && (!commands || !commands[cmd])) {
28
+ throw new Error(`Addon "${addonName}" requires the "${cmd}" command in forge.yaml. Add it and try again.`);
29
+ }
30
+ }
31
+ }
32
+ // Copy files
33
+ for (const file of manifest.files) {
34
+ const sourcePath = resolveTemplatePath('addons', addonName, 'files', file.source);
35
+ const targetPath = join(cwd, file.target);
36
+ const content = await readText(sourcePath);
37
+ await ensureDir(join(targetPath, '..'));
38
+ await writeText(targetPath, content);
39
+ installedFiles.push(file.target);
40
+ }
41
+ // Patch forge.yaml
42
+ await patchForgeYaml(cwd, manifest, 'add');
43
+ // Update hashes
44
+ const hashes = await readHashes(cwd);
45
+ for (const file of manifest.files) {
46
+ const targetPath = join(cwd, file.target);
47
+ const content = await readText(targetPath);
48
+ hashes.files[file.target] = hashContent(content);
49
+ }
50
+ await writeHashes(cwd, hashes);
51
+ return installedFiles;
52
+ }
53
+ export async function uninstallAddon(addonName, cwd) {
54
+ const manifest = await getAddonManifest(addonName);
55
+ const removedFiles = [];
56
+ const { unlink } = await import('node:fs/promises');
57
+ // Remove files
58
+ for (const file of manifest.files) {
59
+ const targetPath = join(cwd, file.target);
60
+ if (await exists(targetPath)) {
61
+ await unlink(targetPath);
62
+ removedFiles.push(file.target);
63
+ }
64
+ }
65
+ // Unpatch forge.yaml
66
+ await patchForgeYaml(cwd, manifest, 'remove');
67
+ // Remove from hashes
68
+ const hashes = await readHashes(cwd);
69
+ for (const file of manifest.files) {
70
+ delete hashes.files[file.target];
71
+ }
72
+ await writeHashes(cwd, hashes);
73
+ return removedFiles;
74
+ }
75
+ async function patchForgeYaml(cwd, manifest, action) {
76
+ const yamlPath = join(cwd, 'forge.yaml');
77
+ const config = await readYaml(yamlPath);
78
+ // Patch specific forge_yaml fields
79
+ if (manifest.patches.forge_yaml) {
80
+ for (const [dotPath, value] of Object.entries(manifest.patches.forge_yaml)) {
81
+ if (dotPath === 'addons') {
82
+ // Handle addons array specially
83
+ const addons = config.addons ?? [];
84
+ const addonEntry = value[0]?.replace('+', '');
85
+ if (action === 'add' && addonEntry && !addons.includes(addonEntry)) {
86
+ addons.push(addonEntry);
87
+ }
88
+ else if (action === 'remove' && addonEntry) {
89
+ const idx = addons.indexOf(addonEntry);
90
+ if (idx >= 0)
91
+ addons.splice(idx, 1);
92
+ }
93
+ config.addons = addons;
94
+ }
95
+ else {
96
+ // Set nested value via dot path
97
+ setNestedValue(config, dotPath, action === 'add' ? value : getDefaultForType(value));
98
+ }
99
+ }
100
+ }
101
+ // Patch agents array
102
+ if (manifest.patches.agents) {
103
+ const agents = config.agents ?? [];
104
+ for (const agentEntry of manifest.patches.agents) {
105
+ const agentName = agentEntry.replace('+', '');
106
+ if (action === 'add' && !agents.includes(agentName)) {
107
+ agents.push(agentName);
108
+ }
109
+ else if (action === 'remove') {
110
+ const idx = agents.indexOf(agentName);
111
+ if (idx >= 0)
112
+ agents.splice(idx, 1);
113
+ }
114
+ }
115
+ config.agents = agents;
116
+ }
117
+ await writeYaml(yamlPath, config);
118
+ }
119
+ function setNestedValue(obj, dotPath, value) {
120
+ const keys = dotPath.split('.');
121
+ let current = obj;
122
+ for (let i = 0; i < keys.length - 1; i++) {
123
+ if (!(keys[i] in current) || typeof current[keys[i]] !== 'object') {
124
+ current[keys[i]] = {};
125
+ }
126
+ current = current[keys[i]];
127
+ }
128
+ current[keys[keys.length - 1]] = value;
129
+ }
130
+ function getDefaultForType(value) {
131
+ if (typeof value === 'boolean')
132
+ return false;
133
+ if (typeof value === 'string')
134
+ return '';
135
+ if (typeof value === 'number')
136
+ return 0;
137
+ return null;
138
+ }
139
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/addons/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function add(addon: string): Promise<void>;
@@ -0,0 +1,61 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { execa } from 'execa';
4
+ import { join } from 'node:path';
5
+ import { exists } from '../utils/fs.js';
6
+ import { isValidAddon, listAvailableAddons, getAddonManifest, installAddon } from '../addons/index.js';
7
+ export async function add(addon) {
8
+ const cwd = process.cwd();
9
+ p.intro(chalk.bold(`forge add ${addon}`));
10
+ // Validate addon name
11
+ if (!isValidAddon(addon)) {
12
+ p.log.error(`Unknown addon: "${addon}"`);
13
+ p.log.message(`Available addons: ${listAvailableAddons().join(', ')}`);
14
+ process.exit(1);
15
+ }
16
+ // Check forge.yaml exists
17
+ if (!(await exists(join(cwd, 'forge.yaml')))) {
18
+ p.log.error('No forge.yaml found. Run `forge init` first.');
19
+ process.exit(1);
20
+ }
21
+ // Check if already installed
22
+ const { readYaml } = await import('../utils/yaml.js');
23
+ const config = await readYaml(join(cwd, 'forge.yaml'));
24
+ const addons = config.addons ?? [];
25
+ if (addons.includes(addon)) {
26
+ p.log.warn(`Addon "${addon}" is already installed.`);
27
+ process.exit(0);
28
+ }
29
+ const spinner = p.spinner();
30
+ spinner.start(`Installing ${addon}...`);
31
+ try {
32
+ const installedFiles = await installAddon(addon, cwd);
33
+ for (const file of installedFiles) {
34
+ p.log.success(`Created ${file}`);
35
+ }
36
+ p.log.success(`Updated forge.yaml`);
37
+ // Run post-install commands
38
+ const manifest = await getAddonManifest(addon);
39
+ if (manifest.post_install) {
40
+ for (const cmd of manifest.post_install) {
41
+ spinner.message(`Running: ${cmd}`);
42
+ try {
43
+ await execa(cmd, { shell: true, cwd, stdio: 'pipe' });
44
+ p.log.success(`Ran: ${cmd}`);
45
+ }
46
+ catch {
47
+ p.log.warn(`Post-install command failed: ${cmd}`);
48
+ p.log.message(' You may need to run this manually.');
49
+ }
50
+ }
51
+ }
52
+ spinner.stop(`${addon} installed`);
53
+ }
54
+ catch (err) {
55
+ spinner.stop('Installation failed');
56
+ p.log.error(String(err));
57
+ process.exit(1);
58
+ }
59
+ p.outro(chalk.green('Done!'));
60
+ }
61
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function doctor(): Promise<void>;
@@ -0,0 +1,177 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { join } from 'node:path';
4
+ import { exists, readText } from '../utils/fs.js';
5
+ import { readYaml } from '../utils/yaml.js';
6
+ import { access, constants } from 'node:fs/promises';
7
+ export async function doctor() {
8
+ const cwd = process.cwd();
9
+ const checks = [];
10
+ p.intro(chalk.bold('forge doctor'));
11
+ const spinner = p.spinner();
12
+ spinner.start('Running diagnostics...');
13
+ // 1. forge.yaml exists and is valid
14
+ const forgeYamlPath = join(cwd, 'forge.yaml');
15
+ if (await exists(forgeYamlPath)) {
16
+ try {
17
+ const config = await readYaml(forgeYamlPath);
18
+ checks.push({ name: 'forge.yaml', passed: true, detail: `preset: ${config.project?.preset}` });
19
+ }
20
+ catch {
21
+ checks.push({ name: 'forge.yaml', passed: false, detail: 'Invalid YAML' });
22
+ }
23
+ }
24
+ else {
25
+ checks.push({ name: 'forge.yaml', passed: false, detail: 'Not found. Run `forge init`' });
26
+ }
27
+ // 2. CLAUDE.md exists
28
+ checks.push({
29
+ name: 'CLAUDE.md',
30
+ passed: await exists(join(cwd, 'CLAUDE.md')),
31
+ detail: (await exists(join(cwd, 'CLAUDE.md'))) ? undefined : 'Not found',
32
+ });
33
+ // 3. Pipeline files exist
34
+ const pipelineFiles = [
35
+ 'orchestrator.sh', 'intake.sh', 'classify.sh', 'decompose.md',
36
+ 'execute.md', 'verify.sh', 'deliver.sh',
37
+ ];
38
+ let pipelineMissing = 0;
39
+ for (const file of pipelineFiles) {
40
+ if (!(await exists(join(cwd, '.forge', 'pipeline', file)))) {
41
+ pipelineMissing++;
42
+ }
43
+ }
44
+ checks.push({
45
+ name: 'Pipeline scripts',
46
+ passed: pipelineMissing === 0,
47
+ detail: pipelineMissing > 0 ? `${pipelineMissing} missing` : `${pipelineFiles.length} files OK`,
48
+ });
49
+ // 4. Scripts are executable
50
+ let nonExecutable = 0;
51
+ for (const file of pipelineFiles.filter((f) => f.endsWith('.sh'))) {
52
+ try {
53
+ await access(join(cwd, '.forge', 'pipeline', file), constants.X_OK);
54
+ }
55
+ catch {
56
+ nonExecutable++;
57
+ }
58
+ }
59
+ const hookFiles = ['pre-edit.sh', 'post-edit.sh', 'session-start.sh'];
60
+ for (const file of hookFiles) {
61
+ try {
62
+ await access(join(cwd, '.forge', 'hooks', file), constants.X_OK);
63
+ }
64
+ catch {
65
+ nonExecutable++;
66
+ }
67
+ }
68
+ checks.push({
69
+ name: 'Scripts executable',
70
+ passed: nonExecutable === 0,
71
+ detail: nonExecutable > 0
72
+ ? `${nonExecutable} scripts not executable. Run: chmod +x .forge/pipeline/*.sh .forge/hooks/*.sh`
73
+ : 'All executable',
74
+ });
75
+ // 5. Agent files exist
76
+ if (await exists(forgeYamlPath)) {
77
+ const config = await readYaml(forgeYamlPath);
78
+ const agents = config.agents ?? [];
79
+ let agentsMissing = 0;
80
+ for (const agent of agents) {
81
+ if (!(await exists(join(cwd, '.forge', 'agents', `${agent}.md`)))) {
82
+ agentsMissing++;
83
+ }
84
+ }
85
+ checks.push({
86
+ name: 'Agent definitions',
87
+ passed: agentsMissing === 0,
88
+ detail: agentsMissing > 0 ? `${agentsMissing} missing` : `${agents.length} agents OK`,
89
+ });
90
+ }
91
+ // 6. Context files
92
+ checks.push({
93
+ name: 'context/stack.md',
94
+ passed: await exists(join(cwd, '.forge', 'context', 'stack.md')),
95
+ });
96
+ checks.push({
97
+ name: 'context/project.md',
98
+ passed: await exists(join(cwd, '.forge', 'context', 'project.md')),
99
+ });
100
+ // 7. bd (beads) installed and initialized
101
+ const { execSync } = await import('node:child_process');
102
+ let bdInstalled = false;
103
+ let bdInitialized = false;
104
+ try {
105
+ execSync('which bd', { stdio: 'pipe' });
106
+ bdInstalled = true;
107
+ bdInitialized = await exists(join(cwd, '.beads'));
108
+ }
109
+ catch { }
110
+ checks.push({
111
+ name: 'bd (beads) installed',
112
+ passed: bdInstalled,
113
+ detail: bdInstalled
114
+ ? (bdInitialized ? 'Installed and initialized' : 'Installed but not initialized. Run: bd init --quiet')
115
+ : 'Not installed. Install: brew install beads',
116
+ });
117
+ // 8. Claude Code settings
118
+ const settingsPath = join(cwd, '.claude', 'settings.json');
119
+ if (await exists(settingsPath)) {
120
+ try {
121
+ const settings = JSON.parse(await readText(settingsPath));
122
+ const hasHooks = settings.hooks && Object.keys(settings.hooks).length > 0;
123
+ checks.push({
124
+ name: '.claude/settings.json',
125
+ passed: true,
126
+ detail: hasHooks ? 'Hooks registered' : 'No hooks registered',
127
+ });
128
+ }
129
+ catch {
130
+ checks.push({ name: '.claude/settings.json', passed: false, detail: 'Invalid JSON' });
131
+ }
132
+ }
133
+ else {
134
+ checks.push({ name: '.claude/settings.json', passed: false, detail: 'Not found' });
135
+ }
136
+ // 9. jq available
137
+ let jqAvailable = false;
138
+ try {
139
+ execSync('which jq', { stdio: 'pipe' });
140
+ jqAvailable = true;
141
+ }
142
+ catch { }
143
+ checks.push({
144
+ name: 'jq installed',
145
+ passed: jqAvailable,
146
+ detail: jqAvailable ? undefined : 'Required for pipeline scripts. Install: brew install jq',
147
+ });
148
+ // 10. gh CLI available
149
+ let ghAvailable = false;
150
+ try {
151
+ execSync('which gh', { stdio: 'pipe' });
152
+ ghAvailable = true;
153
+ }
154
+ catch { }
155
+ checks.push({
156
+ name: 'gh CLI installed',
157
+ passed: ghAvailable,
158
+ detail: ghAvailable ? undefined : 'Required for PR creation. Install: brew install gh',
159
+ });
160
+ spinner.stop('Diagnostics complete');
161
+ // Display results
162
+ const passed = checks.filter((c) => c.passed).length;
163
+ const failed = checks.filter((c) => !c.passed).length;
164
+ const lines = checks.map((c) => {
165
+ const icon = c.passed ? chalk.green('✓') : chalk.red('✗');
166
+ const detail = c.detail ? chalk.dim(` — ${c.detail}`) : '';
167
+ return ` ${icon} ${c.name}${detail}`;
168
+ });
169
+ p.note(lines.join('\n'), 'Health Check');
170
+ if (failed > 0) {
171
+ p.outro(chalk.yellow(`${passed} passed, ${failed} failed`));
172
+ }
173
+ else {
174
+ p.outro(chalk.green(`All ${passed} checks passed`));
175
+ }
176
+ }
177
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ interface IngestOptions {
2
+ chunkSize?: string;
3
+ resume?: string;
4
+ }
5
+ interface SpecAnalysis {
6
+ project_name: string;
7
+ description: string;
8
+ language: string;
9
+ framework: string | null;
10
+ project_type: string;
11
+ modules: string[];
12
+ architecture: string;
13
+ sensitive_areas: string;
14
+ domain_rules: string;
15
+ constraints: string[];
16
+ page_count: number | null;
17
+ }
18
+ export declare function ingest(files: string[], options: IngestOptions): Promise<void>;
19
+ /**
20
+ * Called from `forge init --spec <file>` to analyze a spec and return
21
+ * structured metadata that pre-fills the onboarding answers.
22
+ */
23
+ export declare function analyzeSpecForInit(specPath: string): Promise<SpecAnalysis | null>;
24
+ export {};