forgedock 1.0.1 → 1.0.2
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 +19 -2
- package/bin/forgedock.mjs +286 -10
- package/commands/analytics.md +129 -52
- package/commands/audit-agents.md +29 -5
- package/commands/audit.md +55 -17
- package/commands/autopilot.md +11 -6
- package/commands/cleanup.md +44 -24
- package/commands/deploy-info.md +7 -3
- package/commands/forge-stats.md +13 -4
- package/commands/forgedock-init.md +534 -0
- package/commands/geo-audit.md +114 -26
- package/commands/incident-response.md +4 -1
- package/commands/issue.md +26 -25
- package/commands/milestone.md +80 -59
- package/commands/orchestrate.md +38 -21
- package/commands/pipeline-health.md +26 -15
- package/commands/qa-sweep.md +68 -5
- package/commands/quality-gate.md +18 -0
- package/commands/review-pr-agents.md +58 -90
- package/commands/review-pr.md +58 -16
- package/commands/rollback.md +8 -5
- package/commands/security-audit.md +68 -12
- package/commands/sync-ecosystem.md +196 -156
- package/commands/work-on/build/architect.md +2 -2
- package/commands/work-on/build/context.md +2 -2
- package/commands/work-on/build/implement.md +3 -3
- package/commands/work-on/build/validate.md +3 -3
- package/commands/work-on/build.md +6 -6
- package/commands/work-on/close.md +59 -30
- package/commands/work-on/decompose.md +6 -6
- package/commands/work-on/investigate.md +16 -20
- package/commands/work-on/review.md +4 -4
- package/commands/work-on-monolithic.md +15 -16
- package/commands/work-on.md +45 -33
- package/docs/CODEX.md +1 -1
- package/docs/CONFIG.md +398 -0
- package/docs/WORKFLOW.md +115 -72
- package/package.json +1 -1
- package/scripts/verify-host-headers.sh +14 -9
- package/scripts/verify-route-registration.sh +10 -10
- package/commands/failure-recon.md +0 -375
package/README.md
CHANGED
|
@@ -217,19 +217,36 @@ The path from here to there is incremental. Each piece — the knowledge store,
|
|
|
217
217
|
|
|
218
218
|
## Install
|
|
219
219
|
|
|
220
|
+
**Step 1: Install commands**
|
|
221
|
+
|
|
220
222
|
```bash
|
|
221
223
|
npx forgedock
|
|
222
224
|
```
|
|
223
225
|
|
|
224
|
-
|
|
226
|
+
This symlinks all pipeline commands into your Claude Code environment (`~/.claude/commands/`).
|
|
227
|
+
|
|
228
|
+
**Step 2: Generate config**
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npx forgedock init # Auto-detects your repo, owner, and branches
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Creates `forge.yaml` in your project root — the config file that makes ForgeDock work with your repo instead of a hardcoded one. Edit it to fill in your project details.
|
|
235
|
+
|
|
236
|
+
**Step 3: AI-powered setup (optional)**
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
/forgedock-init # Inside Claude Code — guided full config walkthrough
|
|
240
|
+
```
|
|
225
241
|
|
|
226
|
-
Requires [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [GitHub CLI](https://cli.github.com/).
|
|
242
|
+
Requires [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [GitHub CLI](https://cli.github.com/).
|
|
227
243
|
|
|
228
244
|
**Other commands:**
|
|
229
245
|
|
|
230
246
|
```bash
|
|
231
247
|
npx forgedock update # Pull latest commands
|
|
232
248
|
npx forgedock uninstall # Remove all commands
|
|
249
|
+
npx forgedock help # Show all commands
|
|
233
250
|
```
|
|
234
251
|
|
|
235
252
|
---
|
package/bin/forgedock.mjs
CHANGED
|
@@ -3,13 +3,27 @@
|
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { dirname, join, relative } from "path";
|
|
5
5
|
import { mkdir, symlink, readlink, lstat, readdir, stat } from "fs/promises";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
existsSync,
|
|
8
|
+
appendFileSync,
|
|
9
|
+
readFileSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
} from "fs";
|
|
7
13
|
import { execSync } from "child_process";
|
|
8
14
|
|
|
9
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
16
|
const __dirname = dirname(__filename);
|
|
11
17
|
const FORGE_HOME = dirname(__dirname);
|
|
12
18
|
const COMMANDS_DIR = join(FORGE_HOME, "commands");
|
|
19
|
+
|
|
20
|
+
if (!process.env.HOME) {
|
|
21
|
+
console.error(
|
|
22
|
+
"Error: HOME environment variable is not set. Cannot determine install location.",
|
|
23
|
+
);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
const TARGET_DIR = join(process.env.HOME, ".claude", "commands");
|
|
14
28
|
|
|
15
29
|
const args = process.argv.slice(2);
|
|
@@ -73,7 +87,7 @@ async function install() {
|
|
|
73
87
|
}
|
|
74
88
|
} else {
|
|
75
89
|
console.log(
|
|
76
|
-
` ${YELLOW}WARNING${RESET}: ${rel} is a regular file — skipping (remove it manually to let ForgeDock manage it)
|
|
90
|
+
` ${YELLOW}WARNING${RESET}: ${rel} is a regular file — skipping (remove it manually to let ForgeDock manage it)`,
|
|
77
91
|
);
|
|
78
92
|
skipped++;
|
|
79
93
|
}
|
|
@@ -87,7 +101,7 @@ async function install() {
|
|
|
87
101
|
|
|
88
102
|
console.log("");
|
|
89
103
|
console.log(
|
|
90
|
-
`Done. ${GREEN}Installed: ${installed}${RESET}, Updated: ${updated}, Skipped: ${skipped}
|
|
104
|
+
`Done. ${GREEN}Installed: ${installed}${RESET}, Updated: ${updated}, Skipped: ${skipped}`,
|
|
91
105
|
);
|
|
92
106
|
console.log("");
|
|
93
107
|
|
|
@@ -102,7 +116,7 @@ async function install() {
|
|
|
102
116
|
if (!content.includes("FORGE_HOME")) {
|
|
103
117
|
appendFileSync(
|
|
104
118
|
profile,
|
|
105
|
-
`\n# ForgeDock — autonomous development pipeline\nexport FORGE_HOME="${FORGE_HOME}"\n
|
|
119
|
+
`\n# ForgeDock — autonomous development pipeline\nexport FORGE_HOME="${FORGE_HOME}"\n`,
|
|
106
120
|
);
|
|
107
121
|
console.log(` Added FORGE_HOME to ${profile}`);
|
|
108
122
|
profileUpdated = true;
|
|
@@ -111,9 +125,19 @@ async function install() {
|
|
|
111
125
|
}
|
|
112
126
|
|
|
113
127
|
console.log(
|
|
114
|
-
`${GREEN}ForgeDock commands are now available as slash commands in any Claude Code session.${RESET}
|
|
128
|
+
`${GREEN}ForgeDock commands are now available as slash commands in any Claude Code session.${RESET}`,
|
|
115
129
|
);
|
|
116
130
|
console.log("");
|
|
131
|
+
|
|
132
|
+
// forge.yaml advisory — guide users to run init if config is missing
|
|
133
|
+
const forgeYamlPath = join(process.cwd(), "forge.yaml");
|
|
134
|
+
if (!existsSync(forgeYamlPath)) {
|
|
135
|
+
console.log(`${YELLOW}No forge.yaml found in current directory.${RESET}`);
|
|
136
|
+
console.log(
|
|
137
|
+
` Run ${CYAN}npx forgedock init${RESET} in your project root to generate forge.yaml`,
|
|
138
|
+
);
|
|
139
|
+
console.log("");
|
|
140
|
+
}
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
async function uninstall() {
|
|
@@ -188,24 +212,273 @@ async function update() {
|
|
|
188
212
|
}
|
|
189
213
|
} catch (err) {
|
|
190
214
|
console.log(
|
|
191
|
-
` ${YELLOW}Cannot fast-forward — local changes exist. Skipping.${RESET}
|
|
215
|
+
` ${YELLOW}Cannot fast-forward — local changes exist. Skipping.${RESET}`,
|
|
192
216
|
);
|
|
193
217
|
}
|
|
194
218
|
} else {
|
|
195
|
-
console.log(
|
|
219
|
+
console.log(
|
|
220
|
+
` Installed via npm. Run ${CYAN}npm update -g forgedock${RESET} to update.`,
|
|
221
|
+
);
|
|
196
222
|
}
|
|
197
223
|
console.log("");
|
|
198
224
|
}
|
|
199
225
|
|
|
226
|
+
async function init() {
|
|
227
|
+
console.log("");
|
|
228
|
+
console.log(`${BOLD}ForgeDock${RESET} — Generating forge.yaml`);
|
|
229
|
+
console.log("");
|
|
230
|
+
|
|
231
|
+
const cwd = process.cwd();
|
|
232
|
+
const worktreeBase = join(cwd, ".claude", "worktrees");
|
|
233
|
+
const outputPath = join(cwd, "forge.yaml");
|
|
234
|
+
|
|
235
|
+
// --- Detect git remote URL and parse owner/repo ---
|
|
236
|
+
let owner = "your-github-org";
|
|
237
|
+
let repo = "your-repo-name";
|
|
238
|
+
let remoteDetected = false;
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const remoteUrl = execSync("git remote get-url origin", {
|
|
242
|
+
cwd,
|
|
243
|
+
encoding: "utf-8",
|
|
244
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
245
|
+
}).trim();
|
|
246
|
+
|
|
247
|
+
// SSH: git@github.com:owner/repo.git
|
|
248
|
+
const sshMatch = remoteUrl.match(/^git@[^:]+:([^/]+)\/(.+?)(?:\.git)?$/);
|
|
249
|
+
// HTTPS: https://github.com/owner/repo.git
|
|
250
|
+
const httpsMatch = remoteUrl.match(
|
|
251
|
+
/^https?:\/\/[^/]+\/([^/]+)\/(.+?)(?:\.git)?$/,
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if (sshMatch) {
|
|
255
|
+
owner = sshMatch[1];
|
|
256
|
+
repo = sshMatch[2];
|
|
257
|
+
remoteDetected = true;
|
|
258
|
+
} else if (httpsMatch) {
|
|
259
|
+
owner = httpsMatch[1];
|
|
260
|
+
repo = httpsMatch[2];
|
|
261
|
+
remoteDetected = true;
|
|
262
|
+
} else {
|
|
263
|
+
console.log(
|
|
264
|
+
` ${YELLOW}Warning${RESET}: Could not parse git remote URL — using placeholder values`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
} catch {
|
|
268
|
+
console.log(
|
|
269
|
+
` ${YELLOW}Warning${RESET}: No git remote found — using placeholder values`,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (remoteDetected) {
|
|
274
|
+
console.log(` Detected repo: ${CYAN}${owner}/${repo}${RESET}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// --- Detect default branch ---
|
|
278
|
+
let defaultBranch = "main";
|
|
279
|
+
try {
|
|
280
|
+
const headRef = execSync("git symbolic-ref refs/remotes/origin/HEAD", {
|
|
281
|
+
cwd,
|
|
282
|
+
encoding: "utf-8",
|
|
283
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
284
|
+
}).trim();
|
|
285
|
+
// refs/remotes/origin/main → main
|
|
286
|
+
defaultBranch = headRef.replace(/^refs\/remotes\/origin\//, "");
|
|
287
|
+
console.log(` Default branch: ${CYAN}${defaultBranch}${RESET}`);
|
|
288
|
+
} catch {
|
|
289
|
+
// Fallback: try git rev-parse
|
|
290
|
+
try {
|
|
291
|
+
defaultBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
292
|
+
cwd,
|
|
293
|
+
encoding: "utf-8",
|
|
294
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
295
|
+
}).trim();
|
|
296
|
+
if (defaultBranch === "HEAD") defaultBranch = "main";
|
|
297
|
+
console.log(
|
|
298
|
+
` Default branch: ${CYAN}${defaultBranch}${RESET} (from current branch)`,
|
|
299
|
+
);
|
|
300
|
+
} catch {
|
|
301
|
+
console.log(
|
|
302
|
+
` ${YELLOW}Warning${RESET}: Could not detect default branch — defaulting to "main"`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// --- Detect staging branch ---
|
|
308
|
+
let stagingBranch = "staging";
|
|
309
|
+
try {
|
|
310
|
+
const remoteBranches = execSync("git branch -r", {
|
|
311
|
+
cwd,
|
|
312
|
+
encoding: "utf-8",
|
|
313
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
314
|
+
});
|
|
315
|
+
if (remoteBranches.includes("origin/staging")) {
|
|
316
|
+
stagingBranch = "staging";
|
|
317
|
+
console.log(` Staging branch: ${CYAN}staging${RESET} (detected)`);
|
|
318
|
+
} else {
|
|
319
|
+
stagingBranch = defaultBranch;
|
|
320
|
+
console.log(
|
|
321
|
+
` Staging branch: ${CYAN}${defaultBranch}${RESET} (no staging branch found — using default)`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
} catch {
|
|
325
|
+
console.log(
|
|
326
|
+
` ${YELLOW}Warning${RESET}: Could not read remote branches — defaulting staging to "${defaultBranch}"`,
|
|
327
|
+
);
|
|
328
|
+
stagingBranch = defaultBranch;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// --- Handle existing forge.yaml ---
|
|
332
|
+
if (existsSync(outputPath)) {
|
|
333
|
+
const baseBak = join(cwd, "forge.yaml.bak");
|
|
334
|
+
const backupPath = existsSync(baseBak)
|
|
335
|
+
? join(
|
|
336
|
+
cwd,
|
|
337
|
+
`forge.yaml.bak.${new Date().toISOString().replace(/[:.]/g, "-")}`,
|
|
338
|
+
)
|
|
339
|
+
: baseBak;
|
|
340
|
+
const backupName = backupPath.split("/").pop();
|
|
341
|
+
renameSync(outputPath, backupPath);
|
|
342
|
+
console.log(` ${YELLOW}Backed up${RESET}: forge.yaml → ${backupName}`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// --- Generate forge.yaml content ---
|
|
346
|
+
const projectName = repo
|
|
347
|
+
.split(/[-_]/)
|
|
348
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
349
|
+
.join(" ");
|
|
350
|
+
|
|
351
|
+
const content = `# forge.yaml — ForgeDock Configuration
|
|
352
|
+
#
|
|
353
|
+
# Auto-generated by: npx forgedock init
|
|
354
|
+
# Edit this file with your project details.
|
|
355
|
+
#
|
|
356
|
+
# Required sections: project, paths, branches
|
|
357
|
+
# Optional sections: repos, project_board, services, review, verification
|
|
358
|
+
#
|
|
359
|
+
# See docs/CONFIG.md for full reference.
|
|
360
|
+
|
|
361
|
+
# =============================================================================
|
|
362
|
+
# PROJECT (REQUIRED)
|
|
363
|
+
# =============================================================================
|
|
364
|
+
|
|
365
|
+
project:
|
|
366
|
+
name: "${projectName}"
|
|
367
|
+
owner: "${owner}"
|
|
368
|
+
repo: "${repo}"
|
|
369
|
+
description: ""
|
|
370
|
+
|
|
371
|
+
# =============================================================================
|
|
372
|
+
# PATHS (REQUIRED)
|
|
373
|
+
# =============================================================================
|
|
374
|
+
|
|
375
|
+
paths:
|
|
376
|
+
root: "${cwd}"
|
|
377
|
+
worktree_base: "${worktreeBase}"
|
|
378
|
+
|
|
379
|
+
# =============================================================================
|
|
380
|
+
# BRANCHES (REQUIRED)
|
|
381
|
+
# =============================================================================
|
|
382
|
+
|
|
383
|
+
branches:
|
|
384
|
+
default: "${defaultBranch}"
|
|
385
|
+
staging: "${stagingBranch}"
|
|
386
|
+
feature_pattern: "milestone/{slug}"
|
|
387
|
+
|
|
388
|
+
# =============================================================================
|
|
389
|
+
# REPOS (OPTIONAL)
|
|
390
|
+
# Multi-repo configuration. Remove the # to enable.
|
|
391
|
+
# =============================================================================
|
|
392
|
+
|
|
393
|
+
# repos:
|
|
394
|
+
# default:
|
|
395
|
+
# repo: "${owner}/${repo}"
|
|
396
|
+
# staging_branch: "${stagingBranch}"
|
|
397
|
+
# satellites:
|
|
398
|
+
# - prefix: "mcp"
|
|
399
|
+
# repo: "${owner}/your-satellite-repo"
|
|
400
|
+
# staging_branch: "main"
|
|
401
|
+
# local_path: "${join(cwd, "..", "your-satellite-repo")}"
|
|
402
|
+
|
|
403
|
+
# =============================================================================
|
|
404
|
+
# PROJECT BOARD (OPTIONAL)
|
|
405
|
+
# GitHub Projects v2 integration.
|
|
406
|
+
# To find IDs: gh project list --owner ${owner}
|
|
407
|
+
# =============================================================================
|
|
408
|
+
|
|
409
|
+
# project_board:
|
|
410
|
+
# owner: "${owner}"
|
|
411
|
+
# project_number: 1
|
|
412
|
+
# project_id: "PVT_kwHOxxxxxxxxxxxxxxxx"
|
|
413
|
+
# field_ids:
|
|
414
|
+
# status: "PVTSSF_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
415
|
+
# lane: "PVTSSF_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
416
|
+
# component: "PVTSSF_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
417
|
+
# priority: "PVTSSF_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
418
|
+
# workflow: "PVTSSF_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
419
|
+
|
|
420
|
+
# =============================================================================
|
|
421
|
+
# REVIEW (OPTIONAL)
|
|
422
|
+
# Context injected into review agent prompts.
|
|
423
|
+
# =============================================================================
|
|
424
|
+
|
|
425
|
+
# review:
|
|
426
|
+
# tech_stack: "Node.js, TypeScript, PostgreSQL"
|
|
427
|
+
# context: |
|
|
428
|
+
# Describe your repo structure and any unusual conventions here.
|
|
429
|
+
|
|
430
|
+
# =============================================================================
|
|
431
|
+
# VERIFICATION (OPTIONAL)
|
|
432
|
+
# Health-check patterns for quality gate and validate commands.
|
|
433
|
+
# =============================================================================
|
|
434
|
+
|
|
435
|
+
# verification:
|
|
436
|
+
# health_endpoint: "https://api.${repo}.io/health"
|
|
437
|
+
# health_patterns:
|
|
438
|
+
# - '"status": "ok"'
|
|
439
|
+
`;
|
|
440
|
+
|
|
441
|
+
writeFileSync(outputPath, content, "utf-8");
|
|
442
|
+
|
|
443
|
+
console.log(` ${GREEN}Created${RESET}: forge.yaml`);
|
|
444
|
+
console.log("");
|
|
445
|
+
console.log(`${BOLD}Next steps:${RESET}`);
|
|
446
|
+
console.log(
|
|
447
|
+
` 1. Edit ${CYAN}forge.yaml${RESET} — fill in your project details`,
|
|
448
|
+
);
|
|
449
|
+
console.log(` Required: project.name, project.description`);
|
|
450
|
+
if (!remoteDetected) {
|
|
451
|
+
console.log(
|
|
452
|
+
` Required: project.owner, project.repo (could not auto-detect)`,
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
console.log(
|
|
456
|
+
` 2. Add ${CYAN}forge.yaml${RESET} to ${CYAN}.gitignore${RESET} if it contains sensitive paths`,
|
|
457
|
+
);
|
|
458
|
+
console.log(
|
|
459
|
+
` 3. Run ${CYAN}/forgedock-init${RESET} inside Claude Code for guided AI-powered setup`,
|
|
460
|
+
);
|
|
461
|
+
console.log("");
|
|
462
|
+
}
|
|
463
|
+
|
|
200
464
|
function help() {
|
|
201
465
|
console.log("");
|
|
202
|
-
console.log(
|
|
466
|
+
console.log(
|
|
467
|
+
`${BOLD}ForgeDock${RESET} — GitHub as a knowledge graph for AI agents`,
|
|
468
|
+
);
|
|
203
469
|
console.log("");
|
|
204
470
|
console.log("Usage:");
|
|
205
|
-
console.log(
|
|
471
|
+
console.log(
|
|
472
|
+
` ${CYAN}npx forgedock${RESET} Install commands (default)`,
|
|
473
|
+
);
|
|
206
474
|
console.log(` ${CYAN}npx forgedock install${RESET} Install commands`);
|
|
475
|
+
console.log(
|
|
476
|
+
` ${CYAN}npx forgedock init${RESET} Generate forge.yaml config for your project`,
|
|
477
|
+
);
|
|
207
478
|
console.log(` ${CYAN}npx forgedock uninstall${RESET} Remove commands`);
|
|
208
|
-
console.log(
|
|
479
|
+
console.log(
|
|
480
|
+
` ${CYAN}npx forgedock update${RESET} Pull latest & reinstall`,
|
|
481
|
+
);
|
|
209
482
|
console.log(` ${CYAN}npx forgedock help${RESET} Show this help`);
|
|
210
483
|
console.log("");
|
|
211
484
|
}
|
|
@@ -214,6 +487,9 @@ switch (command) {
|
|
|
214
487
|
case "install":
|
|
215
488
|
await install();
|
|
216
489
|
break;
|
|
490
|
+
case "init":
|
|
491
|
+
await init();
|
|
492
|
+
break;
|
|
217
493
|
case "uninstall":
|
|
218
494
|
await uninstall();
|
|
219
495
|
break;
|