forge-cc 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/.forge.json +5 -0
- package/AGENTS.md +42 -0
- package/README.md +283 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +148 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +44 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +57 -0
- package/dist/config/schema.js +15 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/gates/index.d.ts +11 -0
- package/dist/gates/index.js +106 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/lint-gate.d.ts +2 -0
- package/dist/gates/lint-gate.js +66 -0
- package/dist/gates/lint-gate.js.map +1 -0
- package/dist/gates/prd-gate.d.ts +7 -0
- package/dist/gates/prd-gate.js +193 -0
- package/dist/gates/prd-gate.js.map +1 -0
- package/dist/gates/runtime-gate.d.ts +5 -0
- package/dist/gates/runtime-gate.js +99 -0
- package/dist/gates/runtime-gate.js.map +1 -0
- package/dist/gates/tests-gate.d.ts +2 -0
- package/dist/gates/tests-gate.js +116 -0
- package/dist/gates/tests-gate.js.map +1 -0
- package/dist/gates/types-gate.d.ts +2 -0
- package/dist/gates/types-gate.js +59 -0
- package/dist/gates/types-gate.js.map +1 -0
- package/dist/gates/visual-gate.d.ts +6 -0
- package/dist/gates/visual-gate.js +118 -0
- package/dist/gates/visual-gate.js.map +1 -0
- package/dist/go/auto-chain.d.ts +107 -0
- package/dist/go/auto-chain.js +303 -0
- package/dist/go/auto-chain.js.map +1 -0
- package/dist/go/executor.d.ts +130 -0
- package/dist/go/executor.js +409 -0
- package/dist/go/executor.js.map +1 -0
- package/dist/go/finalize.d.ts +58 -0
- package/dist/go/finalize.js +200 -0
- package/dist/go/finalize.js.map +1 -0
- package/dist/go/linear-sync.d.ts +75 -0
- package/dist/go/linear-sync.js +239 -0
- package/dist/go/linear-sync.js.map +1 -0
- package/dist/go/verify-loop.d.ts +47 -0
- package/dist/go/verify-loop.js +172 -0
- package/dist/go/verify-loop.js.map +1 -0
- package/dist/hooks/pre-commit.d.ts +5 -0
- package/dist/hooks/pre-commit.js +69 -0
- package/dist/hooks/pre-commit.js.map +1 -0
- package/dist/linear/client.d.ts +108 -0
- package/dist/linear/client.js +388 -0
- package/dist/linear/client.js.map +1 -0
- package/dist/linear/issues.d.ts +20 -0
- package/dist/linear/issues.js +39 -0
- package/dist/linear/issues.js.map +1 -0
- package/dist/linear/milestones.d.ts +11 -0
- package/dist/linear/milestones.js +32 -0
- package/dist/linear/milestones.js.map +1 -0
- package/dist/linear/projects.d.ts +16 -0
- package/dist/linear/projects.js +50 -0
- package/dist/linear/projects.js.map +1 -0
- package/dist/reporter/human.d.ts +2 -0
- package/dist/reporter/human.js +63 -0
- package/dist/reporter/human.js.map +1 -0
- package/dist/reporter/json.d.ts +2 -0
- package/dist/reporter/json.js +4 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +109 -0
- package/dist/server.js.map +1 -0
- package/dist/spec/generator.d.ts +14 -0
- package/dist/spec/generator.js +206 -0
- package/dist/spec/generator.js.map +1 -0
- package/dist/spec/interview.d.ts +104 -0
- package/dist/spec/interview.js +342 -0
- package/dist/spec/interview.js.map +1 -0
- package/dist/spec/linear-sync.d.ts +48 -0
- package/dist/spec/linear-sync.js +125 -0
- package/dist/spec/linear-sync.js.map +1 -0
- package/dist/spec/scanner.d.ts +45 -0
- package/dist/spec/scanner.js +473 -0
- package/dist/spec/scanner.js.map +1 -0
- package/dist/spec/templates.d.ts +345 -0
- package/dist/spec/templates.js +86 -0
- package/dist/spec/templates.js.map +1 -0
- package/dist/state/reader.d.ts +29 -0
- package/dist/state/reader.js +116 -0
- package/dist/state/reader.js.map +1 -0
- package/dist/state/writer.d.ts +60 -0
- package/dist/state/writer.js +222 -0
- package/dist/state/writer.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/browser.d.ts +10 -0
- package/dist/utils/browser.js +89 -0
- package/dist/utils/browser.js.map +1 -0
- package/hooks/pre-commit-verify.js +103 -0
- package/package.json +68 -0
- package/skills/README.md +33 -0
- package/skills/forge-go.md +332 -0
- package/skills/forge-spec.md +251 -0
- package/skills/forge-triage.md +133 -0
package/.forge.json
ADDED
package/AGENTS.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# AGENTS.md -- forge-cc Instructions for Non-Claude Agents
|
|
2
|
+
|
|
3
|
+
forge-cc is a pre-PR verification tool. You must pass verification before committing code.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Run verification (required before every commit)
|
|
9
|
+
npx forge verify
|
|
10
|
+
|
|
11
|
+
# Check current status
|
|
12
|
+
npx forge status
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
- Run `npx forge verify` and confirm all gates pass before any `git commit`.
|
|
18
|
+
- If verification fails, fix the reported errors and re-run until it passes.
|
|
19
|
+
- Never commit directly to `main` or `master`. Always use a feature branch.
|
|
20
|
+
- Exit code `0` means pass. Exit code `1` means fail.
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
- Config file: `.forge.json` in project root.
|
|
25
|
+
- If no config exists, gates are auto-detected from `package.json`.
|
|
26
|
+
- Default gates: `types` (tsc), `lint` (biome), `tests` (npm test).
|
|
27
|
+
|
|
28
|
+
## Structured Output
|
|
29
|
+
|
|
30
|
+
Use `npx forge verify --json` for machine-readable JSON results.
|
|
31
|
+
|
|
32
|
+
## Run Specific Gates
|
|
33
|
+
|
|
34
|
+
Use `--gate` to run only certain gates:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx forge verify --gate types,lint
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## More Information
|
|
41
|
+
|
|
42
|
+
See `README.md` for full documentation.
|
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# forge-cc
|
|
2
|
+
|
|
3
|
+
Pre-PR verification harness and development workflow tool for Claude Code agents. Gate runner + CLI + MCP server + workflow skills.
|
|
4
|
+
|
|
5
|
+
<!-- Badges: npm version, CI status, license -->
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
- **Verification gates** -- runs TypeScript type-checking, linting, tests, visual screenshots, runtime endpoint validation, and PRD acceptance criteria checks against your project before you commit.
|
|
10
|
+
- **Mechanical enforcement** -- Claude Code PreToolUse hook and git pre-commit hook block commits that haven't passed verification. No discipline required; the machine enforces it.
|
|
11
|
+
- **Workflow skills** -- `/forge:triage` turns brain dumps into Linear projects, `/forge:spec` interviews you and generates a PRD with milestones, `/forge:go` executes milestones with wave-based agent teams.
|
|
12
|
+
- **Linear lifecycle** -- programmatic status transitions through Backlog, Planned, In Progress, In Review, and Done. Every skill keeps Linear in sync automatically.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Install
|
|
18
|
+
npm install forge-cc
|
|
19
|
+
|
|
20
|
+
# Run verification against current project
|
|
21
|
+
npx forge verify
|
|
22
|
+
|
|
23
|
+
# Check last verification status
|
|
24
|
+
npx forge status
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
On first run with no `.forge.json`, forge auto-detects gates from your `package.json`:
|
|
28
|
+
- Has `typescript` in dependencies? Enables the **types** gate.
|
|
29
|
+
- Has `@biomejs/biome` or `biome` in dependencies? Enables the **lint** gate.
|
|
30
|
+
- Has a `test` script? Enables the **tests** gate.
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
Create a `.forge.json` in your project root to customize behavior:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"gates": ["types", "lint", "tests"],
|
|
39
|
+
"maxIterations": 5,
|
|
40
|
+
"verifyFreshness": 600000,
|
|
41
|
+
"devServer": {
|
|
42
|
+
"command": "npm run dev",
|
|
43
|
+
"port": 3000,
|
|
44
|
+
"readyPattern": "ready on"
|
|
45
|
+
},
|
|
46
|
+
"prdPath": ".planning/prds/active.md",
|
|
47
|
+
"linearProject": "My Project"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Option | Type | Default | Description |
|
|
52
|
+
|--------|------|---------|-------------|
|
|
53
|
+
| `gates` | `string[]` | `["types", "lint", "tests"]` | Which verification gates to run |
|
|
54
|
+
| `maxIterations` | `number` | `5` | Max retry iterations for the verification pipeline |
|
|
55
|
+
| `verifyFreshness` | `number` | `600000` | How long (ms) a passing verification stays valid. Default: 10 minutes |
|
|
56
|
+
| `devServer.command` | `string` | -- | Command to start the dev server (for visual/runtime gates) |
|
|
57
|
+
| `devServer.port` | `number` | -- | Port the dev server listens on |
|
|
58
|
+
| `devServer.readyPattern` | `string` | -- | Stdout pattern indicating the server is ready |
|
|
59
|
+
| `prdPath` | `string` | -- | Path to PRD file for acceptance criteria checking |
|
|
60
|
+
| `linearProject` | `string` | -- | Linear project name for lifecycle tracking |
|
|
61
|
+
|
|
62
|
+
If no `.forge.json` exists, forge auto-detects from `package.json` (see Quick Start).
|
|
63
|
+
|
|
64
|
+
## CLI Commands
|
|
65
|
+
|
|
66
|
+
### `forge verify`
|
|
67
|
+
|
|
68
|
+
Run verification gates against the current project.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Run all configured gates
|
|
72
|
+
npx forge verify
|
|
73
|
+
|
|
74
|
+
# Run specific gates only
|
|
75
|
+
npx forge verify --gate types,lint
|
|
76
|
+
|
|
77
|
+
# Output structured JSON (for programmatic use)
|
|
78
|
+
npx forge verify --json
|
|
79
|
+
|
|
80
|
+
# Include PRD acceptance criteria check
|
|
81
|
+
npx forge verify --prd .planning/prds/active.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Flag | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `--gate <gates>` | Comma-separated list of gates to run (overrides config) |
|
|
87
|
+
| `--json` | Output structured JSON instead of human-readable markdown |
|
|
88
|
+
| `--prd <path>` | Path to PRD file for the `prd` gate |
|
|
89
|
+
|
|
90
|
+
Exit code: `0` if all gates pass, `1` if any gate fails.
|
|
91
|
+
|
|
92
|
+
Results are cached to `.forge/last-verify.json` for freshness checking by hooks.
|
|
93
|
+
|
|
94
|
+
### `forge status`
|
|
95
|
+
|
|
96
|
+
Print current project state: branch, last verification result, config source.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx forge status
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Output includes which gates passed/failed, how long ago verification ran, and whether config is from `.forge.json` or auto-detected.
|
|
103
|
+
|
|
104
|
+
## Verification Gates
|
|
105
|
+
|
|
106
|
+
| Gate | What It Checks | Requires |
|
|
107
|
+
|------|---------------|----------|
|
|
108
|
+
| `types` | TypeScript compilation (`tsc --noEmit`) | `typescript` in dependencies |
|
|
109
|
+
| `lint` | Biome linting (`biome check`) | `@biomejs/biome` in dependencies |
|
|
110
|
+
| `tests` | Test suite (`npm run test`) | A `test` script in `package.json` |
|
|
111
|
+
| `visual` | Playwright screenshots + console error detection | Dev server config, `playwright` |
|
|
112
|
+
| `runtime` | HTTP endpoint validation (status codes, response shape) | Dev server config, endpoint list |
|
|
113
|
+
| `prd` | Diff against PRD acceptance criteria | PRD file path, git history |
|
|
114
|
+
|
|
115
|
+
**Pipeline behavior:** Gates run in order. If all three core gates (types, lint, tests) fail, remaining gates are skipped. Each gate returns structured results with file paths, line numbers, and error messages.
|
|
116
|
+
|
|
117
|
+
## Enforcement
|
|
118
|
+
|
|
119
|
+
forge-cc provides two enforcement mechanisms that block commits without passing verification.
|
|
120
|
+
|
|
121
|
+
### Claude Code PreToolUse Hook
|
|
122
|
+
|
|
123
|
+
The recommended enforcement for Claude Code users. Intercepts `git commit` commands and checks:
|
|
124
|
+
|
|
125
|
+
1. **Branch protection** -- blocks commits directly to `main` or `master`.
|
|
126
|
+
2. **Verification required** -- blocks if no `.forge/last-verify.json` exists.
|
|
127
|
+
3. **Verification passed** -- blocks if the last run failed.
|
|
128
|
+
4. **Freshness** -- blocks if verification is older than `verifyFreshness` (default 10 min).
|
|
129
|
+
|
|
130
|
+
**Install:**
|
|
131
|
+
|
|
132
|
+
Add to your `.claude/settings.json`:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"hooks": {
|
|
137
|
+
"PreToolUse": [
|
|
138
|
+
{
|
|
139
|
+
"matcher": "Bash",
|
|
140
|
+
"hooks": [
|
|
141
|
+
{
|
|
142
|
+
"type": "command",
|
|
143
|
+
"command": "node node_modules/forge-cc/hooks/pre-commit-verify.js"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Git Pre-Commit Hook
|
|
153
|
+
|
|
154
|
+
Standard git hook for non-Claude-Code environments. Same four checks as the PreToolUse hook.
|
|
155
|
+
|
|
156
|
+
The hook logic lives in `src/hooks/pre-commit.ts` and can be wired into any git hook runner (husky, simple-git-hooks, etc.).
|
|
157
|
+
|
|
158
|
+
## MCP Server
|
|
159
|
+
|
|
160
|
+
forge-cc registers its gates as MCP tools so agents can call them programmatically.
|
|
161
|
+
|
|
162
|
+
**Configure in `.mcp.json`:**
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"mcpServers": {
|
|
167
|
+
"forge-cc": {
|
|
168
|
+
"command": "node",
|
|
169
|
+
"args": ["node_modules/forge-cc/dist/server.js"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Available MCP tools:**
|
|
176
|
+
|
|
177
|
+
| Tool | Description |
|
|
178
|
+
|------|-------------|
|
|
179
|
+
| `forge_verify_types` | Run TypeScript type checking |
|
|
180
|
+
| `forge_verify_lint` | Run Biome linting |
|
|
181
|
+
| `forge_verify_tests` | Run project test suite |
|
|
182
|
+
| `forge_verify_visual` | Take screenshots, check console errors |
|
|
183
|
+
| `forge_verify_runtime` | Validate API endpoints |
|
|
184
|
+
| `forge_verify_prd` | Check changes against PRD criteria |
|
|
185
|
+
| `forge_run_pipeline` | Run full verification pipeline |
|
|
186
|
+
|
|
187
|
+
All tools accept `projectDir` (absolute path) and return structured JSON results.
|
|
188
|
+
|
|
189
|
+
## Workflow Skills
|
|
190
|
+
|
|
191
|
+
Claude Code skills that drive the full development lifecycle. Invoke them with slash commands.
|
|
192
|
+
|
|
193
|
+
### `/forge:triage` -- Brain Dump to Linear Projects
|
|
194
|
+
|
|
195
|
+
Paste unstructured ideas, sticky notes, or stream-of-consciousness text. The skill extracts distinct projects, deduplicates against your existing Linear backlog, and creates them after your confirmation.
|
|
196
|
+
|
|
197
|
+
**Flow:** Input text -> extract projects -> deduplicate against Linear -> confirm -> create in Linear (Backlog state).
|
|
198
|
+
|
|
199
|
+
### `/forge:spec` -- Interview to PRD
|
|
200
|
+
|
|
201
|
+
Select a Linear project in Backlog state. The skill scans your codebase (structure, patterns, dependencies), conducts an adaptive interview (leading with recommendations, not blank-slate questions), generates a PRD with milestones, and syncs the plan back to Linear.
|
|
202
|
+
|
|
203
|
+
**Flow:** Select project -> scan codebase -> interview -> generate PRD -> create milestones + issues in Linear -> move project to Planned.
|
|
204
|
+
|
|
205
|
+
### `/forge:go` -- Execute Milestones
|
|
206
|
+
|
|
207
|
+
Execute the next pending milestone from your PRD with wave-based agent teams. Each wave runs parallel agents for independent work, with verification between waves. Supports `--auto` to chain all remaining milestones without manual intervention.
|
|
208
|
+
|
|
209
|
+
**Flow:** Orient (read state) -> pre-flight checks -> execute waves -> verify -> update state -> (optional) create PR.
|
|
210
|
+
|
|
211
|
+
## Linear Integration
|
|
212
|
+
|
|
213
|
+
forge-cc manages the full Linear project lifecycle:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Backlog -> Planned -> In Progress -> In Review -> Done
|
|
217
|
+
| | | | |
|
|
218
|
+
triage spec/PRD go/execute PR created PR merged
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Each skill transitions projects and issues to the appropriate status automatically. The Linear client (`src/linear/client.ts`) handles GraphQL queries, and dedicated modules manage projects, milestones, and issues.
|
|
222
|
+
|
|
223
|
+
## Multi-Developer Setup
|
|
224
|
+
|
|
225
|
+
For a new developer joining the team:
|
|
226
|
+
|
|
227
|
+
1. **Clone the repo** that uses forge-cc.
|
|
228
|
+
2. **Install dependencies:** `npm install` (forge-cc should be in `devDependencies`).
|
|
229
|
+
3. **Run verification:** `npx forge verify` -- confirms your environment is set up correctly.
|
|
230
|
+
4. **Check status:** `npx forge status` -- shows current branch and last verification.
|
|
231
|
+
5. **Install the hook** (optional but recommended): add the PreToolUse hook to `.claude/settings.json` (see Enforcement section above).
|
|
232
|
+
6. **Create a `.forge.json`** if the auto-detected gates don't match your needs.
|
|
233
|
+
|
|
234
|
+
That's it. The gates run the same commands your CI does, so if `npx forge verify` passes locally, CI will pass too.
|
|
235
|
+
|
|
236
|
+
## Project Structure
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
forge-cc/
|
|
240
|
+
src/
|
|
241
|
+
cli.ts # CLI entry point (npx forge)
|
|
242
|
+
server.ts # MCP server entry point
|
|
243
|
+
types.ts # Core type definitions
|
|
244
|
+
gates/ # Verification gates (types, lint, tests, visual, runtime, prd)
|
|
245
|
+
linear/ # Linear API client + lifecycle management
|
|
246
|
+
hooks/ # Pre-commit hook logic
|
|
247
|
+
config/ # .forge.json schema + auto-detection loader
|
|
248
|
+
reporter/ # Human (markdown) and JSON output formatting
|
|
249
|
+
state/ # Session state reader/writer (STATE.md, ROADMAP.md)
|
|
250
|
+
spec/ # Spec interview engine + PRD generation
|
|
251
|
+
go/ # Execution engine + verify loop + PR creation
|
|
252
|
+
skills/ # Claude Code skill definitions (/forge:triage, /forge:spec, /forge:go)
|
|
253
|
+
hooks/ # Installable hook files (PreToolUse)
|
|
254
|
+
tests/ # Test suite (vitest)
|
|
255
|
+
.forge.json # Default configuration
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Development
|
|
259
|
+
|
|
260
|
+
Working on forge-cc itself:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Install dependencies
|
|
264
|
+
npm install
|
|
265
|
+
|
|
266
|
+
# Build
|
|
267
|
+
npm run build
|
|
268
|
+
|
|
269
|
+
# Run tests
|
|
270
|
+
npm test
|
|
271
|
+
|
|
272
|
+
# Watch mode (rebuild on changes)
|
|
273
|
+
npm run dev
|
|
274
|
+
|
|
275
|
+
# Run verification on forge-cc itself
|
|
276
|
+
npm run verify
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Tech stack:** TypeScript (ES2022, strict), Node.js, `@modelcontextprotocol/sdk`, Commander, Playwright, Zod, Vitest.
|
|
280
|
+
|
|
281
|
+
## License
|
|
282
|
+
|
|
283
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { runPipeline } from "./gates/index.js";
|
|
7
|
+
import { loadConfig } from "./config/loader.js";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program
|
|
10
|
+
.name("forge")
|
|
11
|
+
.description("forge-cc — verification + workflow CLI for Claude Code agents")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
program
|
|
14
|
+
.command("verify")
|
|
15
|
+
.description("Run verification gates against the current project")
|
|
16
|
+
.option("--gate <gates>", "Comma-separated list of gates to run (e.g., types,lint,tests)")
|
|
17
|
+
.option("--json", "Output structured JSON instead of human-readable report")
|
|
18
|
+
.option("--prd <path>", "Path to PRD for acceptance criteria matching")
|
|
19
|
+
.action(async (opts) => {
|
|
20
|
+
try {
|
|
21
|
+
const projectDir = process.cwd();
|
|
22
|
+
const config = loadConfig(projectDir);
|
|
23
|
+
const gates = opts.gate ? opts.gate.split(",").map((g) => g.trim()) : config.gates;
|
|
24
|
+
const prdPath = opts.prd ?? config.prdPath;
|
|
25
|
+
const result = await runPipeline({
|
|
26
|
+
projectDir,
|
|
27
|
+
gates,
|
|
28
|
+
prdPath,
|
|
29
|
+
maxIterations: config.maxIterations,
|
|
30
|
+
devServerCommand: config.devServer?.command,
|
|
31
|
+
devServerPort: config.devServer?.port,
|
|
32
|
+
});
|
|
33
|
+
// Generate report if pipeline didn't produce one
|
|
34
|
+
if (!result.report) {
|
|
35
|
+
result.report = formatReport(result);
|
|
36
|
+
}
|
|
37
|
+
// Write verify cache (non-fatal if this fails)
|
|
38
|
+
try {
|
|
39
|
+
writeVerifyCache(projectDir, result);
|
|
40
|
+
}
|
|
41
|
+
catch (cacheErr) {
|
|
42
|
+
const msg = cacheErr instanceof Error ? cacheErr.message : String(cacheErr);
|
|
43
|
+
console.error(`Warning: Could not write verify cache: ${msg}`);
|
|
44
|
+
}
|
|
45
|
+
// Output
|
|
46
|
+
if (opts.json) {
|
|
47
|
+
console.log(JSON.stringify(result, null, 2));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log(result.report);
|
|
51
|
+
}
|
|
52
|
+
process.exit(result.passed ? 0 : 1);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
56
|
+
console.error(`Error: forge verify failed — ${message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
program
|
|
61
|
+
.command("status")
|
|
62
|
+
.description("Print current project state")
|
|
63
|
+
.action(() => {
|
|
64
|
+
const projectDir = process.cwd();
|
|
65
|
+
// Branch
|
|
66
|
+
let branch = "unknown";
|
|
67
|
+
try {
|
|
68
|
+
branch = execSync("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
69
|
+
}
|
|
70
|
+
catch { /* not a git repo */ }
|
|
71
|
+
console.log(`## Forge Status`);
|
|
72
|
+
console.log(`**Branch:** ${branch}`);
|
|
73
|
+
// Last verify
|
|
74
|
+
const cachePath = join(projectDir, ".forge", "last-verify.json");
|
|
75
|
+
if (existsSync(cachePath)) {
|
|
76
|
+
const cache = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
77
|
+
const status = cache.passed ? "PASSED" : "FAILED";
|
|
78
|
+
const age = Math.round((Date.now() - new Date(cache.timestamp).getTime()) / 60_000);
|
|
79
|
+
console.log(`**Last Verify:** ${status} (${age}min ago on ${cache.branch})`);
|
|
80
|
+
for (const gate of cache.gates) {
|
|
81
|
+
const icon = gate.passed ? "[x]" : "[ ]";
|
|
82
|
+
console.log(` - ${icon} ${gate.gate}: ${gate.passed ? "PASS" : "FAIL"}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log(`**Last Verify:** none`);
|
|
87
|
+
}
|
|
88
|
+
// Config
|
|
89
|
+
const configPath = join(projectDir, ".forge.json");
|
|
90
|
+
if (existsSync(configPath)) {
|
|
91
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
92
|
+
console.log(`**Config:** .forge.json (gates: ${config.gates?.join(", ") ?? "default"})`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log(`**Config:** auto-detected (no .forge.json)`);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
function writeVerifyCache(projectDir, result) {
|
|
99
|
+
const forgeDir = join(projectDir, ".forge");
|
|
100
|
+
mkdirSync(forgeDir, { recursive: true });
|
|
101
|
+
let branch = "unknown";
|
|
102
|
+
try {
|
|
103
|
+
branch = execSync("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
104
|
+
}
|
|
105
|
+
catch { /* not a git repo */ }
|
|
106
|
+
const cache = {
|
|
107
|
+
passed: result.passed,
|
|
108
|
+
timestamp: new Date().toISOString(),
|
|
109
|
+
gates: result.gates,
|
|
110
|
+
branch,
|
|
111
|
+
};
|
|
112
|
+
writeFileSync(join(forgeDir, "last-verify.json"), JSON.stringify(cache, null, 2));
|
|
113
|
+
}
|
|
114
|
+
function formatReport(result) {
|
|
115
|
+
const lines = [];
|
|
116
|
+
const status = result.passed ? "PASSED" : "FAILED";
|
|
117
|
+
lines.push("## Verification Report");
|
|
118
|
+
lines.push(`**Status:** ${status}`);
|
|
119
|
+
const totalMs = result.gates.reduce((sum, g) => sum + g.duration_ms, 0);
|
|
120
|
+
lines.push(`**Duration:** ${(totalMs / 1000).toFixed(1)}s`);
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push("### Gates");
|
|
123
|
+
for (const gate of result.gates) {
|
|
124
|
+
const icon = gate.passed ? "[x]" : "[ ]";
|
|
125
|
+
const dur = `${(gate.duration_ms / 1000).toFixed(1)}s`;
|
|
126
|
+
let suffix = "";
|
|
127
|
+
if (!gate.passed && gate.errors.length > 0) {
|
|
128
|
+
suffix = ` — ${gate.errors.length} error${gate.errors.length === 1 ? "" : "s"}`;
|
|
129
|
+
}
|
|
130
|
+
lines.push(`- ${icon} ${gate.gate}: ${gate.passed ? "PASS" : "FAIL"} (${dur})${suffix}`);
|
|
131
|
+
}
|
|
132
|
+
// Errors detail section
|
|
133
|
+
const withErrors = result.gates.filter(g => g.errors.length > 0);
|
|
134
|
+
if (withErrors.length > 0) {
|
|
135
|
+
lines.push("");
|
|
136
|
+
lines.push("### Errors");
|
|
137
|
+
for (const gate of withErrors) {
|
|
138
|
+
lines.push(`#### ${gate.gate}`);
|
|
139
|
+
for (const err of gate.errors) {
|
|
140
|
+
const loc = err.file ? `${err.file}${err.line ? `:${err.line}` : ""}` : "";
|
|
141
|
+
lines.push(`- ${loc ? `${loc}: ` : ""}${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return lines.join("\n");
|
|
146
|
+
}
|
|
147
|
+
program.parse();
|
|
148
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { forgeConfigSchema } from "./schema.js";
|
|
4
|
+
export function loadConfig(projectDir) {
|
|
5
|
+
const configPath = join(projectDir, ".forge.json");
|
|
6
|
+
if (existsSync(configPath)) {
|
|
7
|
+
try {
|
|
8
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
9
|
+
return forgeConfigSchema.parse(raw);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13
|
+
console.warn(`Warning: Failed to parse .forge.json (${message}). Falling back to auto-detect.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Auto-detect from package.json
|
|
17
|
+
return autoDetectConfig(projectDir);
|
|
18
|
+
}
|
|
19
|
+
function autoDetectConfig(projectDir) {
|
|
20
|
+
const gates = [];
|
|
21
|
+
try {
|
|
22
|
+
const pkgPath = join(projectDir, "package.json");
|
|
23
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
24
|
+
const allDeps = {
|
|
25
|
+
...pkg.dependencies,
|
|
26
|
+
...pkg.devDependencies,
|
|
27
|
+
};
|
|
28
|
+
if (allDeps.typescript)
|
|
29
|
+
gates.push("types");
|
|
30
|
+
if (allDeps["@biomejs/biome"] || allDeps.biome)
|
|
31
|
+
gates.push("lint");
|
|
32
|
+
if (pkg.scripts?.test)
|
|
33
|
+
gates.push("tests");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// No package.json or invalid — use defaults
|
|
37
|
+
gates.push("types", "lint", "tests");
|
|
38
|
+
}
|
|
39
|
+
if (gates.length === 0) {
|
|
40
|
+
gates.push("types", "lint", "tests");
|
|
41
|
+
}
|
|
42
|
+
return forgeConfigSchema.parse({ gates });
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAEnD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAC1D,OAAO,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,yCAAyC,OAAO,iCAAiC,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,OAAO,gBAAgB,CAAC,UAAU,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAEvD,MAAM,OAAO,GAAG;YACd,GAAG,GAAG,CAAC,YAAY;YACnB,GAAG,GAAG,CAAC,eAAe;SACvB,CAAC;QAEF,IAAI,OAAO,CAAC,UAAU;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,OAAO,CAAC,gBAAgB,CAAC,IAAI,OAAO,CAAC,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnE,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;QAC5C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,iBAAiB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const devServerSchema: z.ZodObject<{
|
|
3
|
+
command: z.ZodString;
|
|
4
|
+
port: z.ZodNumber;
|
|
5
|
+
readyPattern: z.ZodOptional<z.ZodString>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
port: number;
|
|
8
|
+
command: string;
|
|
9
|
+
readyPattern?: string | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
port: number;
|
|
12
|
+
command: string;
|
|
13
|
+
readyPattern?: string | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const forgeConfigSchema: z.ZodObject<{
|
|
16
|
+
gates: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
17
|
+
maxIterations: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
verifyFreshness: z.ZodDefault<z.ZodNumber>;
|
|
19
|
+
devServer: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
command: z.ZodString;
|
|
21
|
+
port: z.ZodNumber;
|
|
22
|
+
readyPattern: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
port: number;
|
|
25
|
+
command: string;
|
|
26
|
+
readyPattern?: string | undefined;
|
|
27
|
+
}, {
|
|
28
|
+
port: number;
|
|
29
|
+
command: string;
|
|
30
|
+
readyPattern?: string | undefined;
|
|
31
|
+
}>>;
|
|
32
|
+
prdPath: z.ZodOptional<z.ZodString>;
|
|
33
|
+
linearProject: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
gates: string[];
|
|
36
|
+
maxIterations: number;
|
|
37
|
+
verifyFreshness: number;
|
|
38
|
+
devServer?: {
|
|
39
|
+
port: number;
|
|
40
|
+
command: string;
|
|
41
|
+
readyPattern?: string | undefined;
|
|
42
|
+
} | undefined;
|
|
43
|
+
prdPath?: string | undefined;
|
|
44
|
+
linearProject?: string | undefined;
|
|
45
|
+
}, {
|
|
46
|
+
gates?: string[] | undefined;
|
|
47
|
+
maxIterations?: number | undefined;
|
|
48
|
+
verifyFreshness?: number | undefined;
|
|
49
|
+
devServer?: {
|
|
50
|
+
port: number;
|
|
51
|
+
command: string;
|
|
52
|
+
readyPattern?: string | undefined;
|
|
53
|
+
} | undefined;
|
|
54
|
+
prdPath?: string | undefined;
|
|
55
|
+
linearProject?: string | undefined;
|
|
56
|
+
}>;
|
|
57
|
+
export type ForgeConfigInput = z.input<typeof forgeConfigSchema>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const devServerSchema = z.object({
|
|
3
|
+
command: z.string(),
|
|
4
|
+
port: z.number().int().positive(),
|
|
5
|
+
readyPattern: z.string().optional(),
|
|
6
|
+
});
|
|
7
|
+
export const forgeConfigSchema = z.object({
|
|
8
|
+
gates: z.array(z.string()).default(["types", "lint", "tests"]),
|
|
9
|
+
maxIterations: z.number().int().positive().default(5),
|
|
10
|
+
verifyFreshness: z.number().int().positive().default(600_000),
|
|
11
|
+
devServer: devServerSchema.optional(),
|
|
12
|
+
prdPath: z.string().optional(),
|
|
13
|
+
linearProject: z.string().optional(),
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAC7D,SAAS,EAAE,eAAe,CAAC,QAAQ,EAAE;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACrC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GateResult, PipelineInput, PipelineResult } from "../types.js";
|
|
2
|
+
/** Gate registry -- maps gate name to its function */
|
|
3
|
+
export declare const gateRegistry: Record<string, (input: PipelineInput) => Promise<GateResult>>;
|
|
4
|
+
/** Run the full verification pipeline */
|
|
5
|
+
export declare function runPipeline(input: PipelineInput): Promise<PipelineResult>;
|
|
6
|
+
export { verifyTypes } from "./types-gate.js";
|
|
7
|
+
export { verifyLint } from "./lint-gate.js";
|
|
8
|
+
export { verifyTests } from "./tests-gate.js";
|
|
9
|
+
export { verifyVisual } from "./visual-gate.js";
|
|
10
|
+
export { verifyRuntime } from "./runtime-gate.js";
|
|
11
|
+
export { verifyPrd } from "./prd-gate.js";
|