forgedock 1.0.0 → 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.
Files changed (42) hide show
  1. package/README.md +19 -2
  2. package/bin/forgedock.mjs +286 -10
  3. package/commands/analytics.md +129 -52
  4. package/commands/audit-agents.md +29 -5
  5. package/commands/audit.md +55 -17
  6. package/commands/autopilot.md +11 -6
  7. package/commands/cleanup.md +44 -24
  8. package/commands/deploy-info.md +7 -3
  9. package/commands/forge-stats.md +13 -4
  10. package/commands/forgedock-init.md +534 -0
  11. package/commands/geo-audit.md +114 -26
  12. package/commands/incident-response.md +4 -1
  13. package/commands/issue.md +26 -25
  14. package/commands/milestone.md +80 -59
  15. package/commands/orchestrate.md +38 -21
  16. package/commands/pipeline-health.md +26 -15
  17. package/commands/qa-sweep.md +68 -5
  18. package/commands/quality-gate.md +18 -0
  19. package/commands/review-pr-agents.md +58 -90
  20. package/commands/review-pr.md +58 -16
  21. package/commands/rollback.md +8 -5
  22. package/commands/security-audit.md +68 -12
  23. package/commands/sync-ecosystem.md +196 -156
  24. package/commands/validate.md +1 -1
  25. package/commands/work-on/build/architect.md +2 -2
  26. package/commands/work-on/build/context.md +2 -2
  27. package/commands/work-on/build/implement.md +3 -3
  28. package/commands/work-on/build/validate.md +3 -3
  29. package/commands/work-on/build.md +6 -6
  30. package/commands/work-on/close.md +59 -30
  31. package/commands/work-on/decompose.md +6 -6
  32. package/commands/work-on/investigate.md +16 -20
  33. package/commands/work-on/review.md +4 -4
  34. package/commands/work-on-monolithic.md +15 -16
  35. package/commands/work-on.md +45 -33
  36. package/docs/CODEX.md +1 -1
  37. package/docs/CONFIG.md +398 -0
  38. package/docs/WORKFLOW.md +115 -72
  39. package/package.json +2 -2
  40. package/scripts/verify-host-headers.sh +14 -9
  41. package/scripts/verify-route-registration.sh +10 -10
  42. 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
- That's it. One command — installs all pipeline commands into your Claude Code environment.
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/). ForgeDock reads your project's `CLAUDE.md` for conventions — no extra config needed.
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 { existsSync, appendFileSync, readFileSync } from "fs";
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(` Installed via npm. Run ${CYAN}npm update -g forgedock${RESET} to update.`);
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(`${BOLD}ForgeDock${RESET} — GitHub as a knowledge graph for AI agents`);
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(` ${CYAN}npx forgedock${RESET} Install commands (default)`);
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(` ${CYAN}npx forgedock update${RESET} Pull latest & reinstall`);
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;