@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.
- package/README.md +175 -0
- package/bin/forge.js +2 -0
- package/dist/addons/index.d.ts +25 -0
- package/dist/addons/index.js +139 -0
- package/dist/addons/index.js.map +1 -0
- package/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.js +61 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +177 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/ingest.d.ts +24 -0
- package/dist/commands/ingest.js +316 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +557 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/remove.d.ts +1 -0
- package/dist/commands/remove.js +42 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +48 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.d.ts +5 -0
- package/dist/commands/upgrade.js +190 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/detect/features.d.ts +10 -0
- package/dist/detect/features.js +33 -0
- package/dist/detect/features.js.map +1 -0
- package/dist/detect/go.d.ts +3 -0
- package/dist/detect/go.js +38 -0
- package/dist/detect/go.js.map +1 -0
- package/dist/detect/index.d.ts +25 -0
- package/dist/detect/index.js +32 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/detect/node.d.ts +3 -0
- package/dist/detect/node.js +99 -0
- package/dist/detect/node.js.map +1 -0
- package/dist/detect/python.d.ts +3 -0
- package/dist/detect/python.js +86 -0
- package/dist/detect/python.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/render/engine.d.ts +8 -0
- package/dist/render/engine.js +71 -0
- package/dist/render/engine.js.map +1 -0
- package/dist/render/merge.d.ts +5 -0
- package/dist/render/merge.js +33 -0
- package/dist/render/merge.js.map +1 -0
- package/dist/utils/fs.d.ts +8 -0
- package/dist/utils/fs.js +42 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/git.d.ts +3 -0
- package/dist/utils/git.js +31 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/hash.d.ts +8 -0
- package/dist/utils/hash.js +22 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/yaml.d.ts +3 -0
- package/dist/utils/yaml.js +12 -0
- package/dist/utils/yaml.js.map +1 -0
- package/package.json +53 -0
- package/templates/addons/beads-dolt-backend/files/dolt-setup.sh +267 -0
- package/templates/addons/beads-dolt-backend/manifest.yaml +13 -0
- package/templates/addons/browser-testing/files/browser-smoke.sh +196 -0
- package/templates/addons/browser-testing/files/visual-qa.md +103 -0
- package/templates/addons/browser-testing/manifest.yaml +20 -0
- package/templates/addons/compliance-hipaa/files/hipaa-checks.sh +184 -0
- package/templates/addons/compliance-hipaa/files/hipaa-context.md +91 -0
- package/templates/addons/compliance-hipaa/manifest.yaml +15 -0
- package/templates/addons/compliance-soc2/files/soc2-checks.sh +232 -0
- package/templates/addons/compliance-soc2/files/soc2-context.md +147 -0
- package/templates/addons/compliance-soc2/manifest.yaml +15 -0
- package/templates/core/CLAUDE.md.hbs +70 -0
- package/templates/core/agents/architect.md.hbs +68 -0
- package/templates/core/agents/backend.md.hbs +27 -0
- package/templates/core/agents/frontend.md.hbs +25 -0
- package/templates/core/agents/quality.md.hbs +40 -0
- package/templates/core/agents/security.md.hbs +53 -0
- package/templates/core/context/project.md.hbs +60 -0
- package/templates/core/forge.yaml.hbs +69 -0
- package/templates/core/hooks/post-edit.sh.hbs +8 -0
- package/templates/core/hooks/pre-edit.sh.hbs +41 -0
- package/templates/core/hooks/session-start.sh.hbs +34 -0
- package/templates/core/pipeline/classify.sh.hbs +159 -0
- package/templates/core/pipeline/decompose.md.hbs +100 -0
- package/templates/core/pipeline/deliver.sh.hbs +171 -0
- package/templates/core/pipeline/execute.md.hbs +138 -0
- package/templates/core/pipeline/intake.sh.hbs +152 -0
- package/templates/core/pipeline/orchestrator.sh.hbs +361 -0
- package/templates/core/pipeline/verify.sh.hbs +160 -0
- package/templates/core/settings.json.hbs +55 -0
- package/templates/core/skill-creator.md.hbs +151 -0
- package/templates/core/skill-deliver.md.hbs +46 -0
- package/templates/core/skill-ingest.md.hbs +245 -0
- package/templates/presets/go/stack.md.hbs +133 -0
- package/templates/presets/python-fastapi/stack.md.hbs +101 -0
- package/templates/presets/react-next-ts/stack.md.hbs +77 -0
- 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,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":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQrD,MAAM,CAAC,KAAK,UAAU,MAAM;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAEpC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAExC,oCAAoC;IACpC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,QAAQ,CAA0B,aAAa,CAAC,CAAC;YACtE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAY,MAAM,CAAC,OAAkC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAC5H,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QAC5E,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,sBAAsB;IACtB,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC5C,MAAM,EAAE,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;KACxE,CAAC,CAAC;IAEH,0BAA0B;IAC1B,MAAM,aAAa,GAAG;QACrB,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc;QAC7D,YAAY,EAAE,WAAW,EAAE,YAAY;KACvC,CAAC;IACF,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,eAAe,EAAE,CAAC;QACnB,CAAC;IACF,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,eAAe,KAAK,CAAC;QAC7B,MAAM,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,UAAU,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,WAAW;KAC/F,CAAC,CAAC;IAEH,4BAA4B;IAC5B,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACrE,CAAC;QAAC,MAAM,CAAC;YACR,aAAa,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,aAAa,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACtE,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACR,aAAa,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,aAAa,KAAK,CAAC;QAC3B,MAAM,EAAE,aAAa,GAAG,CAAC;YACxB,CAAC,CAAC,GAAG,aAAa,+EAA+E;YACjG,CAAC,CAAC,gBAAgB;KACnB,CAAC,CAAC;IAEH,uBAAuB;IACvB,IAAI,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAA0B,aAAa,CAAC,CAAC;QACtE,MAAM,MAAM,GAAI,MAAM,CAAC,MAAmB,IAAI,EAAE,CAAC;QACjD,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,aAAa,EAAE,CAAC;YACjB,CAAC;QACF,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,aAAa,KAAK,CAAC;YAC3B,MAAM,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,YAAY;SACrF,CAAC,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;KAChE,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;KAClE,CAAC,CAAC;IAEH,0CAA0C;IAC1C,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,CAAC;QACJ,QAAQ,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,WAAW,GAAG,IAAI,CAAC;QACnB,aAAa,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,WAAW;YAClB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,qDAAqD,CAAC;YACvG,CAAC,CAAC,4CAA4C;KAC/C,CAAC,CAAC;IAEH,0BAA0B;IAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IAC3D,IAAI,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;YAC1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,uBAAuB;gBAC7B,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,qBAAqB;aAC7D,CAAC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QACvF,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,kBAAkB;IAClB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC;QACJ,QAAQ,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,WAAW,GAAG,IAAI,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,yDAAyD;KAC3F,CAAC,CAAC;IAEH,uBAAuB;IACvB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC;QACJ,QAAQ,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,WAAW,GAAG,IAAI,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,oDAAoD;KACtF,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAErC,kBAAkB;IAClB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IAEtD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,MAAM,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;IAEzC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,YAAY,MAAM,SAAS,CAAC,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACP,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,MAAM,gBAAgB,CAAC,CAAC,CAAC;IACrD,CAAC;AACF,CAAC"}
|
|
@@ -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 {};
|