@entelligentsia/forgecli 1.0.21 → 1.0.36

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 (218) hide show
  1. package/CHANGELOG.md +346 -0
  2. package/README.md +2 -0
  3. package/dist/CHANGELOG-forge-plugin.md +281 -0
  4. package/dist/bin/argv.d.ts +2 -2
  5. package/dist/bin/argv.js +25 -0
  6. package/dist/bin/argv.js.map +1 -1
  7. package/dist/bin/forge.js +12 -0
  8. package/dist/bin/forge.js.map +1 -1
  9. package/dist/bin/init.d.ts +23 -0
  10. package/dist/bin/init.js +123 -0
  11. package/dist/bin/init.js.map +1 -0
  12. package/dist/bin/uninstall.d.ts +20 -0
  13. package/dist/bin/uninstall.js +141 -0
  14. package/dist/bin/uninstall.js.map +1 -0
  15. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.d.ts +40 -0
  16. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js +593 -0
  17. package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js.map +1 -0
  18. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.d.ts +46 -0
  19. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js +245 -0
  20. package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js.map +1 -0
  21. package/dist/extensions/forgecli/claude-bootstrap/uninstall.d.ts +23 -0
  22. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js +215 -0
  23. package/dist/extensions/forgecli/claude-bootstrap/uninstall.js.map +1 -0
  24. package/dist/extensions/forgecli/dashboard/component.js +10 -7
  25. package/dist/extensions/forgecli/dashboard/component.js.map +1 -1
  26. package/dist/extensions/forgecli/forge-tools.d.ts +1 -0
  27. package/dist/extensions/forgecli/forge-tools.js +73 -0
  28. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  29. package/dist/extensions/forgecli/lib/forge-root.d.ts +5 -0
  30. package/dist/extensions/forgecli/lib/forge-root.js +14 -1
  31. package/dist/extensions/forgecli/lib/forge-root.js.map +1 -1
  32. package/dist/extensions/forgecli/orchestrators/bug/bug-body.d.ts +1 -0
  33. package/dist/extensions/forgecli/orchestrators/bug/bug-body.js +65 -0
  34. package/dist/extensions/forgecli/orchestrators/bug/bug-body.js.map +1 -0
  35. package/dist/extensions/forgecli/orchestrators/bug/bug-id.d.ts +23 -0
  36. package/dist/extensions/forgecli/orchestrators/bug/bug-id.js +140 -0
  37. package/dist/extensions/forgecli/orchestrators/bug/bug-id.js.map +1 -0
  38. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.d.ts +54 -0
  39. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js +349 -0
  40. package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js.map +1 -0
  41. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.d.ts +8 -0
  42. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js +60 -0
  43. package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js.map +1 -0
  44. package/dist/extensions/forgecli/orchestrators/bug/bug-state.d.ts +14 -0
  45. package/dist/extensions/forgecli/orchestrators/bug/bug-state.js +100 -0
  46. package/dist/extensions/forgecli/orchestrators/bug/bug-state.js.map +1 -0
  47. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.d.ts +72 -0
  48. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js +204 -0
  49. package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js.map +1 -0
  50. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.d.ts +38 -0
  51. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js +166 -0
  52. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js.map +1 -0
  53. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.d.ts +3 -0
  54. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js +55 -0
  55. package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js.map +1 -0
  56. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.d.ts +7 -0
  57. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js +293 -0
  58. package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js.map +1 -0
  59. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.d.ts +2 -0
  60. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js +501 -0
  61. package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js.map +1 -0
  62. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.d.ts +41 -0
  63. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js +5 -0
  64. package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js.map +1 -0
  65. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.d.ts +43 -0
  66. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js +85 -0
  67. package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js.map +1 -0
  68. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.d.ts +8 -0
  69. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js +37 -0
  70. package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js.map +1 -0
  71. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.d.ts +28 -0
  72. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js +45 -0
  73. package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js.map +1 -0
  74. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.d.ts +26 -0
  75. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js +75 -0
  76. package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js.map +1 -0
  77. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.d.ts +24 -0
  78. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js +37 -0
  79. package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js.map +1 -0
  80. package/dist/extensions/forgecli/orchestrators/fix-bug.d.ts +9 -92
  81. package/dist/extensions/forgecli/orchestrators/fix-bug.js +23 -1695
  82. package/dist/extensions/forgecli/orchestrators/fix-bug.js.map +1 -1
  83. package/dist/extensions/forgecli/orchestrators/run-sprint.d.ts +3 -12
  84. package/dist/extensions/forgecli/orchestrators/run-sprint.js +97 -270
  85. package/dist/extensions/forgecli/orchestrators/run-sprint.js.map +1 -1
  86. package/dist/extensions/forgecli/orchestrators/run-task.d.ts +10 -214
  87. package/dist/extensions/forgecli/orchestrators/run-task.js +31 -1481
  88. package/dist/extensions/forgecli/orchestrators/run-task.js.map +1 -1
  89. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.d.ts +33 -0
  90. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js +135 -0
  91. package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js.map +1 -0
  92. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.d.ts +18 -0
  93. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js +55 -0
  94. package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js.map +1 -0
  95. package/dist/extensions/forgecli/orchestrators/task/run-task-command.d.ts +9 -0
  96. package/dist/extensions/forgecli/orchestrators/task/run-task-command.js +174 -0
  97. package/dist/extensions/forgecli/orchestrators/task/run-task-command.js.map +1 -0
  98. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.d.ts +2 -0
  99. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js +494 -0
  100. package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js.map +1 -0
  101. package/dist/extensions/forgecli/orchestrators/task/run-task-types.d.ts +62 -0
  102. package/dist/extensions/forgecli/orchestrators/task/run-task-types.js +5 -0
  103. package/dist/extensions/forgecli/orchestrators/task/run-task-types.js.map +1 -0
  104. package/dist/extensions/forgecli/orchestrators/task/task-body.d.ts +4 -0
  105. package/dist/extensions/forgecli/orchestrators/task/task-body.js +48 -0
  106. package/dist/extensions/forgecli/orchestrators/task/task-body.js.map +1 -0
  107. package/dist/extensions/forgecli/orchestrators/task/task-events.d.ts +63 -0
  108. package/dist/extensions/forgecli/orchestrators/task/task-events.js +185 -0
  109. package/dist/extensions/forgecli/orchestrators/task/task-events.js.map +1 -0
  110. package/dist/extensions/forgecli/orchestrators/task/task-gates.d.ts +34 -0
  111. package/dist/extensions/forgecli/orchestrators/task/task-gates.js +78 -0
  112. package/dist/extensions/forgecli/orchestrators/task/task-gates.js.map +1 -0
  113. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.d.ts +42 -0
  114. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js +370 -0
  115. package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js.map +1 -0
  116. package/dist/extensions/forgecli/orchestrators/task/task-phases.d.ts +14 -0
  117. package/dist/extensions/forgecli/orchestrators/task/task-phases.js +26 -0
  118. package/dist/extensions/forgecli/orchestrators/task/task-phases.js.map +1 -0
  119. package/dist/extensions/forgecli/orchestrators/task/task-record.d.ts +9 -0
  120. package/dist/extensions/forgecli/orchestrators/task/task-record.js +58 -0
  121. package/dist/extensions/forgecli/orchestrators/task/task-record.js.map +1 -0
  122. package/dist/extensions/forgecli/orchestrators/task/task-state.d.ts +14 -0
  123. package/dist/extensions/forgecli/orchestrators/task/task-state.js +35 -0
  124. package/dist/extensions/forgecli/orchestrators/task/task-state.js.map +1 -0
  125. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.d.ts +36 -0
  126. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js +152 -0
  127. package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js.map +1 -0
  128. package/dist/extensions/forgecli/update/forge-update-command.js +10 -7
  129. package/dist/extensions/forgecli/update/forge-update-command.js.map +1 -1
  130. package/dist/forge-payload/.base-pack/commands/approve.md +2 -2
  131. package/dist/forge-payload/.base-pack/commands/check-agent.md +2 -2
  132. package/dist/forge-payload/.base-pack/commands/collate.md +2 -2
  133. package/dist/forge-payload/.base-pack/commands/commit.md +2 -2
  134. package/dist/forge-payload/.base-pack/commands/enhance.md +2 -2
  135. package/dist/forge-payload/.base-pack/commands/fix-bug.md +2 -2
  136. package/dist/forge-payload/.base-pack/commands/implement.md +2 -2
  137. package/dist/forge-payload/.base-pack/commands/init.md +278 -0
  138. package/dist/forge-payload/.base-pack/commands/new-sprint.md +2 -2
  139. package/dist/forge-payload/.base-pack/commands/plan-sprint.md +2 -2
  140. package/dist/forge-payload/.base-pack/commands/plan.md +2 -2
  141. package/dist/forge-payload/.base-pack/commands/retro.md +2 -2
  142. package/dist/forge-payload/.base-pack/commands/review-code.md +2 -2
  143. package/dist/forge-payload/.base-pack/commands/review-plan.md +2 -2
  144. package/dist/forge-payload/.base-pack/commands/run-sprint.md +2 -2
  145. package/dist/forge-payload/.base-pack/commands/run-task.md +2 -2
  146. package/dist/forge-payload/.base-pack/commands/validate.md +2 -2
  147. package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +4 -0
  148. package/dist/forge-payload/.base-pack/workflows/_fragments/event-vocabulary.md +88 -0
  149. package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -6
  150. package/dist/forge-payload/.base-pack/workflows/commit_task.md +41 -38
  151. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -3
  152. package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +1 -1
  153. package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +42 -6
  154. package/dist/forge-payload/.base-pack/workflows-js/wfl-init.js +449 -0
  155. package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +32 -1
  156. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  157. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  158. package/dist/forge-payload/.schemas/event.schema.json +8 -3
  159. package/dist/forge-payload/.schemas/migrations.json +141 -0
  160. package/dist/forge-payload/commands/add-pipeline.md +1 -1
  161. package/dist/forge-payload/commands/add-task.md +3 -3
  162. package/dist/forge-payload/commands/ask.md +1 -1
  163. package/dist/forge-payload/commands/check-agent.md +1 -1
  164. package/dist/forge-payload/commands/config.md +1 -1
  165. package/dist/forge-payload/commands/health.md +1 -1
  166. package/dist/forge-payload/commands/init.md +62 -7
  167. package/dist/forge-payload/commands/rebuild.md +3 -3
  168. package/dist/forge-payload/commands/remove.md +1 -1
  169. package/dist/forge-payload/commands/repair.md +1 -1
  170. package/dist/forge-payload/commands/report-bug.md +1 -1
  171. package/dist/forge-payload/commands/status.md +1 -1
  172. package/dist/forge-payload/commands/update.md +3 -3
  173. package/dist/forge-payload/hooks/lib/common.cjs +228 -0
  174. package/dist/forge-payload/hooks/lib/plugin-detection.cjs +106 -0
  175. package/dist/forge-payload/hooks/lib/update-msg.cjs +23 -0
  176. package/dist/forge-payload/hooks/lib/update-url.cjs +46 -0
  177. package/dist/forge-payload/hooks/lib/write-registry.js +53 -0
  178. package/dist/forge-payload/init/discovery/discover-database.md +32 -0
  179. package/dist/forge-payload/init/discovery/discover-processes.md +31 -0
  180. package/dist/forge-payload/init/discovery/discover-routing.md +31 -0
  181. package/dist/forge-payload/init/discovery/discover-stack.md +33 -0
  182. package/dist/forge-payload/init/discovery/discover-testing.md +34 -0
  183. package/dist/forge-payload/init/generation/generate-commands.md +171 -0
  184. package/dist/forge-payload/init/generation/generate-kb-doc.md +60 -0
  185. package/dist/forge-payload/init/generation/generate-knowledge-base.md +56 -0
  186. package/dist/forge-payload/init/generation/generate-persona.md +73 -0
  187. package/dist/forge-payload/init/generation/generate-personas.md +54 -0
  188. package/dist/forge-payload/init/generation/generate-skill.md +66 -0
  189. package/dist/forge-payload/init/generation/generate-skills.md +36 -0
  190. package/dist/forge-payload/init/generation/generate-template.md +60 -0
  191. package/dist/forge-payload/init/generation/generate-templates.md +39 -0
  192. package/dist/forge-payload/init/generation/generate-tools.md +133 -0
  193. package/dist/forge-payload/init/generation/generate-workflows.md +78 -0
  194. package/dist/forge-payload/init/phases/phase-1-collect.md +10 -2
  195. package/dist/forge-payload/init/phases/phase-3-materialize.md +1 -1
  196. package/dist/forge-payload/init/phases/phase-4-register.md +8 -0
  197. package/dist/forge-payload/init/workflow-gen-plan.json +17 -0
  198. package/dist/forge-payload/integrity.json +16 -16
  199. package/dist/forge-payload/meta/store-schema/event.schema.md +7 -0
  200. package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +4 -0
  201. package/dist/forge-payload/meta/workflows/_fragments/event-vocabulary.md +88 -0
  202. package/dist/forge-payload/meta/workflows/meta-collate.md +5 -6
  203. package/dist/forge-payload/meta/workflows/meta-commit.md +46 -43
  204. package/dist/forge-payload/meta/workflows/meta-fix-bug.md +7 -2
  205. package/dist/forge-payload/meta/workflows/meta-implement.md +3 -3
  206. package/dist/forge-payload/meta/workflows/meta-migrate.md +1 -1
  207. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +4 -1
  208. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  209. package/dist/forge-payload/schemas/event.schema.json +8 -3
  210. package/dist/forge-payload/schemas/structure-manifest.json +5 -12
  211. package/dist/forge-payload/tools/commit-task.cjs +218 -0
  212. package/dist/forge-payload/tools/forge-preflight.cjs +268 -0
  213. package/dist/forge-payload/tools/lib/paths.cjs +12 -11
  214. package/dist/forge-payload/tools/lib/pricing.cjs +31 -11
  215. package/dist/forge-payload/tools/query-logger.cjs +34 -0
  216. package/dist/forge-payload/tools/store-cli.cjs +6 -1
  217. package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -6
  218. package/package.json +2 -2
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+ // hooks/lib/plugin-detection.cjs — extracted from check-update.js (H-2a, FORGE-S25-T14)
3
+ //
4
+ // Provides Forge plugin distribution detection and installation scanning.
5
+ // Extracted to improve testability — each function can be imported and
6
+ // tested independently without requiring the full check-update module.
7
+ //
8
+ // Uses only Node.js built-ins — no npm dependencies required.
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const os = require('os');
13
+
14
+ // Distribution detection — derived from plugin path at runtime.
15
+ // The cache path encodes the marketplace name, making this more reliable than
16
+ // reading fields from plugin.json (which may be stale after a switch).
17
+ function detectDistribution(root) {
18
+ return root.includes('/cache/skillforge/forge/') || root.includes('/marketplaces/skillforge/forge/')
19
+ ? 'forge@skillforge' : 'forge@forge';
20
+ }
21
+
22
+ // Check if forge plugin is enabled in settings files.
23
+ // Returns true if no explicit disable found, false if disabled.
24
+ function isPluginEnabled(pluginPath, scope, homeDir, cwd) {
25
+ try {
26
+ // Check user settings: ~/.claude/settings.json
27
+ const userSettingsPath = path.join(homeDir, '.claude', 'settings.json');
28
+ if (fs.existsSync(userSettingsPath)) {
29
+ const userSettings = JSON.parse(fs.readFileSync(userSettingsPath, 'utf8'));
30
+ if (userSettings.disablePlugin === true) return false;
31
+ // Check for per-plugin disable (if supported in future)
32
+ if (userSettings.plugins && userSettings.plugins.forge === false) return false;
33
+ }
34
+
35
+ // Check project settings: ./.claude/settings.local.json
36
+ const projectSettingsPath = path.join(cwd, '.claude', 'settings.local.json');
37
+ if (fs.existsSync(projectSettingsPath)) {
38
+ const projectSettings = JSON.parse(fs.readFileSync(projectSettingsPath, 'utf8'));
39
+ if (projectSettings.disablePlugin === true) return false;
40
+ if (projectSettings.plugins && projectSettings.plugins.forge === false) return false;
41
+ }
42
+
43
+ return true; // Default: enabled
44
+ } catch (e) {
45
+ return true; // Non-fatal — assume enabled if cannot read settings
46
+ }
47
+ }
48
+
49
+ // Scans all known plugin locations to detect multiple Forge installations.
50
+ // Returns array of installation records with version, distribution, scope, enabled status.
51
+ // Optional parameters for dependency injection (testing).
52
+ function scanPluginInstallations(options) {
53
+ const installations = [];
54
+ const homeDir = (options && options.homeDir) || os.homedir();
55
+ const cwd = (options && options.cwd) || process.cwd();
56
+
57
+ // Candidate paths — user scope (global) and project scope (local)
58
+ // Also scan skillforge subdirectory variant (skillforge/forge/forge)
59
+ const basePaths = [
60
+ path.join(homeDir, '.claude', 'plugins'),
61
+ path.join(cwd, '.claude', 'plugins'),
62
+ ];
63
+ const variants = ['cache', 'marketplaces'];
64
+ const pluginNames = ['forge/forge', 'skillforge/forge/forge'];
65
+
66
+ const candidates = [];
67
+ for (const basePath of basePaths) {
68
+ for (const variant of variants) {
69
+ for (const pluginName of pluginNames) {
70
+ candidates.push(path.join(basePath, variant, pluginName));
71
+ }
72
+ }
73
+ }
74
+
75
+ for (const candidate of candidates) {
76
+ try {
77
+ const pluginJsonPath = path.join(candidate, '.claude-plugin', 'plugin.json');
78
+ if (!fs.existsSync(pluginJsonPath)) continue;
79
+
80
+ const manifest = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
81
+ // Determine scope: user-scope paths start with homeDir/.claude, project-scope start with cwd/.claude
82
+ // Use cwd-relative check first to avoid false positives when cwd is subdir of homeDir
83
+ const isProjectScope = candidate.startsWith(path.join(cwd, '.claude'));
84
+ const isUserScope = candidate.startsWith(path.join(homeDir, '.claude'));
85
+ const scope = isProjectScope ? 'project' : (isUserScope ? 'user' : 'unknown');
86
+ const enabled = isPluginEnabled(candidate, scope, homeDir, cwd);
87
+
88
+ // Avoid duplicates — skip if same path already recorded
89
+ if (installations.some(i => i.path === candidate)) continue;
90
+
91
+ installations.push({
92
+ path: candidate,
93
+ version: manifest.version || 'unknown',
94
+ distribution: detectDistribution(candidate),
95
+ scope: scope,
96
+ enabled: enabled,
97
+ });
98
+ } catch (e) {
99
+ // Non-fatal — skip broken installations silently
100
+ }
101
+ }
102
+
103
+ return installations;
104
+ }
105
+
106
+ module.exports = { detectDistribution, isPluginEnabled, scanPluginInstallations };
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+ // hooks/lib/update-msg.cjs — extracted from check-update.js (H-2c, FORGE-S25-T14)
3
+ //
4
+ // Provides update message construction and emission.
5
+ // Extracted to improve testability — buildUpdateMsg and emit can be tested
6
+ // without executing the full check-update session logic.
7
+ //
8
+ // Uses only Node.js built-ins — no npm dependencies required.
9
+
10
+ function buildUpdateMsg(remoteVersion, local) {
11
+ return remoteVersion && remoteVersion !== local
12
+ ? `Forge ${remoteVersion} available (you have ${local}). Run /forge:update to review changes and update.`
13
+ : '';
14
+ }
15
+
16
+ function emit(forgeCtx, updateMsg) {
17
+ if (!forgeCtx && !updateMsg) return;
18
+ const combined = [forgeCtx, updateMsg].filter(Boolean).join(' ');
19
+ const escaped = combined.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, ' ');
20
+ process.stdout.write(`{"additionalContext":"${escaped}"}\n`);
21
+ }
22
+
23
+ module.exports = { buildUpdateMsg, emit };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+ // hooks/lib/update-url.cjs — extracted from check-update.js (H-2b, FORGE-S25-T14)
3
+ //
4
+ // Provides update-check URL resolution and validation.
5
+ // Reads process.env.CLAUDE_PLUGIN_ROOT directly (option b from plan) so
6
+ // the module is self-contained — no pluginRoot argument needed at call sites.
7
+ //
8
+ // Uses only Node.js built-ins — no npm dependencies required.
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+
13
+ // Determine the correct update-check URL for this distribution.
14
+ // Each distribution's plugin.json carries its own updateUrl pointing at the
15
+ // branch it was installed from (main for forge@forge, release for forge@skillforge),
16
+ // so we read it directly — no hardcoded per-distribution URLs needed.
17
+ const FALLBACK_UPDATE_URL = 'https://raw.githubusercontent.com/Entelligentsia/forge/main/forge/.claude-plugin/plugin.json';
18
+
19
+ const ALLOWED_DOMAINS = ['raw.githubusercontent.com'];
20
+
21
+ function validateUpdateUrl(url) {
22
+ try {
23
+ const parsed = new URL(url);
24
+ const hostname = parsed.hostname.toLowerCase();
25
+ if (!ALLOWED_DOMAINS.some(d => hostname === d || hostname.endsWith('.' + d))) {
26
+ process.stderr.write(`forge-update: rejected update URL with disallowed domain '${hostname}', falling back\n`);
27
+ return FALLBACK_UPDATE_URL;
28
+ }
29
+ return url;
30
+ } catch {
31
+ return FALLBACK_UPDATE_URL;
32
+ }
33
+ }
34
+
35
+ // Reads updateUrl from the installed plugin.json.
36
+ // Uses process.env.CLAUDE_PLUGIN_ROOT (option b) with a fallback of '' so
37
+ // the function is self-contained. Falls back to FALLBACK_UPDATE_URL on any error.
38
+ function getUpdateUrl() {
39
+ try {
40
+ const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || '';
41
+ const manifest = JSON.parse(fs.readFileSync(path.join(pluginRoot, '.claude-plugin', 'plugin.json'), 'utf8'));
42
+ return validateUpdateUrl(manifest.updateUrl || FALLBACK_UPDATE_URL);
43
+ } catch { return FALLBACK_UPDATE_URL; }
44
+ }
45
+
46
+ module.exports = { FALLBACK_UPDATE_URL, ALLOWED_DOMAINS, validateUpdateUrl, getUpdateUrl };
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ // Write-boundary registry: maps Forge-owned filesystem path patterns to the
4
+ // schema (and kind) that the write-boundary hook enforces on Write/Edit/
5
+ // MultiEdit. FIRST match wins, so order matters — place more specific
6
+ // patterns before their generalizations (sidecar before event).
7
+ //
8
+ // Patterns are anchored to absolute-path suffixes so they match whether the
9
+ // tool invocation used an absolute or project-relative path. Every pattern
10
+ // assumes the Forge store lives at `.forge/store/` (the installed default).
11
+ //
12
+ // If NO pattern matches a write, the hook is a no-op: Forge does not validate
13
+ // non-Forge-owned files. The registry is an allowlist of paths we claim, not
14
+ // a denylist of paths we reject.
15
+
16
+ const REGISTRY = [
17
+ // Core store entities — flat files under .forge/store/{kind}s/<id>.json
18
+ { pattern: /(?:^|\/)\.forge\/store\/features\/[^/]+\.json$/, schema: 'feature.schema.json', kind: 'feature' },
19
+ { pattern: /(?:^|\/)\.forge\/store\/sprints\/[^/]+\.json$/, schema: 'sprint.schema.json', kind: 'sprint' },
20
+ { pattern: /(?:^|\/)\.forge\/store\/tasks\/[^/]+\.json$/, schema: 'task.schema.json', kind: 'task' },
21
+ { pattern: /(?:^|\/)\.forge\/store\/bugs\/[^/]+\.json$/, schema: 'bug.schema.json', kind: 'bug' },
22
+
23
+ // Event sidecars — prefixed with `_` and suffixed with `_usage.json`.
24
+ // Must come BEFORE the general event pattern so the leading `_` file is
25
+ // classified as a sidecar, not an event with a malformed id.
26
+ { pattern: /(?:^|\/)\.forge\/store\/events\/[^/]+\/_[^/]+_usage\.json$/, schema: 'event-sidecar.schema.json', kind: 'event-sidecar' },
27
+
28
+ // Canonical events — any other .json under events/<bucket>/ that does NOT
29
+ // start with an underscore. (Ghost events are not written through Write/Edit
30
+ // tools, so we don't special-case them here.)
31
+ { pattern: /(?:^|\/)\.forge\/store\/events\/[^/]+\/[^_/][^/]*\.json$/, schema: 'event.schema.json', kind: 'event' },
32
+
33
+ // Collation watermark
34
+ { pattern: /(?:^|\/)\.forge\/store\/COLLATION_STATE\.json$/, schema: 'collation-state.schema.json', kind: 'collation-state' },
35
+
36
+ // Progress log — line-oriented, not JSON. The hook's parser splits newly
37
+ // appended lines and validates each as a pipe-delimited progress entry.
38
+ { pattern: /(?:^|\/)\.forge\/store\/events\/[^/]+\/progress\.log$/, schema: 'progress-entry.schema.json', kind: 'progress-line', format: 'line-pipe-delimited' },
39
+ ];
40
+
41
+ function matchRegistry(absPath) {
42
+ if (!absPath || typeof absPath !== 'string') return null;
43
+ for (const entry of REGISTRY) {
44
+ if (entry.pattern.test(absPath)) return entry;
45
+ }
46
+ return null;
47
+ }
48
+
49
+ // REGISTRY is intentionally not exported — it is a private implementation detail
50
+ // of this module. Callers use matchRegistry() for lookups. Exporting REGISTRY
51
+ // would expose internal pattern structures to external consumers and create
52
+ // coupling that makes future pattern changes harder. (H-3, FORGE-S25-T14)
53
+ module.exports = { matchRegistry };
@@ -0,0 +1,32 @@
1
+ # Discovery: Database
2
+
3
+ ## Purpose
4
+
5
+ Detect the project's data model: entities, relationships, field types,
6
+ and migration patterns.
7
+
8
+ ## Scan Targets
9
+
10
+ | Pattern | What It Reveals |
11
+ |---------|----------------|
12
+ | Django: `models.py` files | ORM models, fields, relationships |
13
+ | Rails: `app/models/*.rb` | ActiveRecord models |
14
+ | Prisma: `schema.prisma` | Prisma schema |
15
+ | TypeORM: `*.entity.ts` | TypeORM entities |
16
+ | Sequelize: `models/*.js` | Sequelize models |
17
+ | Go: `*_model.go` | Go struct definitions |
18
+ | SQL: `migrations/` / `schema.sql` | Raw schema |
19
+ | MongoDB: Mongoose schemas | Document models |
20
+
21
+ ## Tools
22
+
23
+ Use Grep to find model/entity definitions, Read to parse them.
24
+
25
+ ## Output
26
+
27
+ Structured report:
28
+ - Entity inventory (name, field count, key relationships)
29
+ - Database type (PostgreSQL, MySQL, MongoDB, SQLite, etc.)
30
+ - ORM/query layer in use
31
+ - Migration framework and directory
32
+ - Seed data presence
@@ -0,0 +1,31 @@
1
+ # Discovery: Processes
2
+
3
+ ## Purpose
4
+
5
+ Detect the project's service topology, build tools, and deployment configuration.
6
+
7
+ ## Scan Targets
8
+
9
+ | File | What It Reveals |
10
+ |------|----------------|
11
+ | `docker-compose.yml` | Service topology, dependencies, ports |
12
+ | `Procfile` | Process types (web, worker, etc.) |
13
+ | `ecosystem.config.js` | PM2 process management |
14
+ | `systemd/*.service` | System service definitions |
15
+ | `.github/workflows/*.yml` | CI/CD pipeline |
16
+ | `.gitlab-ci.yml` | CI/CD pipeline |
17
+ | `Jenkinsfile` | CI/CD pipeline |
18
+ | `vercel.json` / `netlify.toml` | Deployment platform |
19
+
20
+ ## Tools
21
+
22
+ Use Glob to find these files, Read to parse them.
23
+
24
+ ## Output
25
+
26
+ Structured report:
27
+ - Services and their roles (web, worker, database, cache, etc.)
28
+ - Build command(s)
29
+ - Deploy command(s) or platform
30
+ - CI/CD pipeline structure
31
+ - Environment variables referenced (names only, not values)
@@ -0,0 +1,31 @@
1
+ # Discovery: Routing
2
+
3
+ ## Purpose
4
+
5
+ Detect the project's API surface, authentication strategy, and middleware.
6
+
7
+ ## Scan Targets
8
+
9
+ | Pattern | What It Reveals |
10
+ |---------|----------------|
11
+ | Django: `urls.py`, `views.py` | URL patterns, view functions/classes |
12
+ | Express: `router.get/post/...` | Route definitions |
13
+ | Rails: `routes.rb` | Route definitions |
14
+ | FastAPI: `@app.get/post` | Endpoint decorators |
15
+ | Go: `http.HandleFunc` / mux | Route handlers |
16
+ | Auth decorators/middleware | `@login_required`, `authenticate`, `IsAuthenticated` |
17
+ | API docs: `openapi.yaml` / `swagger.json` | API specification |
18
+
19
+ ## Tools
20
+
21
+ Use Grep to find route definitions and auth patterns, Read to parse them.
22
+
23
+ ## Output
24
+
25
+ Structured report:
26
+ - Route count (approximate)
27
+ - Auth strategy (decorator-based, middleware, JWT, session, etc.)
28
+ - Public vs protected route ratio
29
+ - URL namespace structure
30
+ - API versioning (if any)
31
+ - Middleware chain
@@ -0,0 +1,33 @@
1
+ # Discovery: Stack
2
+
3
+ ## Purpose
4
+
5
+ Detect the project's programming languages, frameworks, versions, and runtime.
6
+
7
+ ## Scan Targets
8
+
9
+ | File | What It Reveals |
10
+ |------|----------------|
11
+ | `package.json` | Node.js, npm dependencies, scripts |
12
+ | `requirements.txt` / `Pipfile` / `pyproject.toml` | Python, pip dependencies |
13
+ | `go.mod` | Go, module dependencies |
14
+ | `Cargo.toml` | Rust, crate dependencies |
15
+ | `Gemfile` | Ruby, gem dependencies |
16
+ | `Dockerfile` | Runtime, base image, build steps |
17
+ | `Makefile` | Build commands, task aliases |
18
+ | `*.sln` / `*.csproj` | .NET, C# |
19
+
20
+ ## Tools
21
+
22
+ Use Glob to find these files, Read to parse them.
23
+
24
+ ## Output
25
+
26
+ Structured report:
27
+ - Primary language(s)
28
+ - Framework(s) with versions
29
+ - Frontend framework (if any)
30
+ - Database (if detectable from dependencies)
31
+ - Task queue (if any)
32
+ - Containerisation (if any)
33
+ - Runtime version constraints
@@ -0,0 +1,34 @@
1
+ # Discovery: Testing
2
+
3
+ ## Purpose
4
+
5
+ Detect the project's test framework, test commands, build commands,
6
+ and lint configuration.
7
+
8
+ ## Scan Targets
9
+
10
+ | Pattern | What It Reveals |
11
+ |---------|----------------|
12
+ | `test/` / `tests/` / `__tests__/` / `*_test.go` | Test directory structure |
13
+ | `jest.config.*` / `vitest.config.*` | JS test framework config |
14
+ | `pytest.ini` / `setup.cfg` / `pyproject.toml [tool.pytest]` | Python test config |
15
+ | `package.json scripts.test` | Test command |
16
+ | `.eslintrc*` / `ruff.toml` / `.golangci.yml` | Lint configuration |
17
+ | `.github/workflows/*.yml` | CI test/build/lint commands |
18
+ | `coverage/` / `.coveragerc` / `lcov.info` | Coverage configuration |
19
+
20
+ ## Tools
21
+
22
+ Use Glob to find config files, Read to parse them. Use Bash to verify
23
+ commands work (e.g., `npm test --help` or `pytest --co -q | head`).
24
+
25
+ ## Output
26
+
27
+ Structured report:
28
+ - Test framework(s) and version
29
+ - Test command (exact command to run tests)
30
+ - Build command (exact command to build)
31
+ - Lint command (exact command to lint)
32
+ - Syntax check command per language
33
+ - Coverage tooling (if any)
34
+ - Approximate test count
@@ -0,0 +1,171 @@
1
+ # Generation: Commands
2
+
3
+ ## Purpose
4
+
5
+ Generate standalone slash commands in `.claude/commands/forge/` that serve as
6
+ entry points to the generated workflows. The namespace is FIXED to `forge`
7
+ (CLI-first redesign): every project gets the same `/forge:*` surface, matching
8
+ what the `4ge` bootstrap vendors. Project-prefix namespaces (`/acme:*`,
9
+ `/ember:*`) are retired — they existed to avoid collisions with the Forge
10
+ *plugin's* own commands, moot now that the plugin mechanism is retired.
11
+
12
+ ## Inputs
13
+
14
+ - Generated workflows (from Phase 5) — their exact filenames and paths
15
+ - `.forge/config.json` — paths (project prefix no longer affects the command namespace)
16
+
17
+ ## Outputs
18
+
19
+ `.claude/commands/forge/` with the fixed-namespace commands:
20
+ - `new-sprint.md` → `/forge:new-sprint`
21
+ - `plan.md` → `/forge:plan {TASK_ID}`
22
+ - `review-plan.md` → `/forge:review-plan {TASK_ID}`
23
+ - `implement.md` → `/forge:implement {TASK_ID}`
24
+ - `review-code.md` → `/forge:review-code {TASK_ID}`
25
+ - `fix-bug.md` → `/forge:fix-bug {BUG_ID}`
26
+ - `plan-sprint.md` → `/forge:plan-sprint`
27
+ - `run-task.md` → `/forge:run-task {TASK_ID}`
28
+ - `run-sprint.md` → `/forge:run-sprint {SPRINT_ID} [--parallel]`
29
+ - `collate.md` → `/forge:collate [SPRINT_ID]`
30
+ - `retro.md` → `/forge:retro {SPRINT_ID}`
31
+ - `approve.md` → `/forge:approve {TASK_ID}`
32
+ - `commit.md` → `/forge:commit {TASK_ID}`
33
+ - `check-agent.md` → `/forge:check-agent $ARGUMENTS`
34
+ - `enhance.md` → `/forge:enhance $ARGUMENTS`
35
+ - `validate.md` → `/forge:validate {TASK_ID}`
36
+
37
+ ## Instructions
38
+
39
+ **Scope boundary:** Only ever read, write, or delete files in the explicit output list above (16 files).
40
+ Never touch any other file in `.claude/commands/` — custom commands, project-specific
41
+ wrappers, and unrecognised files must be left completely untouched.
42
+
43
+ **Pre-generation check (idempotency):** For each command file listed above, before writing:
44
+ 1. Check first whether the file exists at the **flat path** `.claude/commands/{filename}.md`
45
+ (old non-namespaced location). If it does, treat it as non-conformant — overwrite into
46
+ the namespaced path and log: `Replaced flat command (now namespaced): <filename>`.
47
+ 2. If the file does not exist at either path — write it fresh to the namespaced path.
48
+ 3. If the file exists at the namespaced path `.claude/commands/forge/{filename}.md` — read it
49
+ and extract the workflow path it references (the `.forge/workflows/` path).
50
+ - If it does NOT reference `.forge/workflows/` — overwrite and log: `Replaced stale command: <filename>`.
51
+ - If it references `.forge/workflows/` but that workflow file **does not exist on disk** — overwrite and log: `Replaced command pointing to missing workflow: <filename>`.
52
+ - If it references `.forge/workflows/` and the workflow file exists — check whether the file matches the template format. If it is missing `effort:` frontmatter, contains `model:` frontmatter, contains a MASTER_INDEX read line, or uses old workflow naming (`engineer_*`, `supervisor_*`) — overwrite and log: `Replaced non-conformant command: <filename>`.
53
+ - **wfl: dispatch rung (scoped to three filenames only):** If the filename is one of `run-task.md`, `run-sprint.md`, or `fix-bug.md` — and the file body contains `Read .forge/workflows/` — it is non-conformant (it should use `wfl:` dispatch instead). Overwrite it with the `workflow('wfl:run-task'|'wfl:run-sprint'|'wfl:fix-bug', $ARGUMENTS)` body and log: `Replaced non-conformant command: <filename>`. Do NOT apply this rung to any other command — the other 13 commands legitimately use `Read .forge/workflows/` and must not be flagged.
54
+ - If it matches the template format and the workflow exists — skip it (already up to date).
55
+
56
+ This ensures any workflow that has been renamed or replaced causes its command wrapper to be regenerated rather than silently left pointing at a missing file.
57
+
58
+ Each command file MUST follow this exact template — no variations, no additions:
59
+
60
+ ```markdown
61
+ ---
62
+ description: {{description}}
63
+ effort: {{effort}}
64
+ ---
65
+ Read `.forge/workflows/{{workflow}}.md` and follow it exactly.
66
+ {{argument_line}}
67
+ <!-- AUTO-GENERATED by /forge:init -->
68
+ ```
69
+
70
+ Where:
71
+ - `{{description}}` — from the descriptions table below (fixed, not model-generated)
72
+ - `{{effort}}` — from the effort table below (fixed mapping, not model choice)
73
+ - `{{workflow}}` — the exact filename of the generated workflow (no path prefix, no `engineer_`/`supervisor_` role prefix)
74
+ - `{{argument_line}}` — one of: `Task ID: $ARGUMENTS`, `Sprint ID: $ARGUMENTS`, `Bug ID: $ARGUMENTS`, or `Arguments: $ARGUMENTS`
75
+
76
+ **Do NOT deviate from this template.** Specifically:
77
+ - Do NOT include a `Read {KB_PATH}/MASTER_INDEX.md` line. The workflow loads MASTER_INDEX as its first step — pre-loading it gives the model enough context to rationalise skipping the workflow entirely and doing the work inline. Workflow first, always.
78
+ - Do NOT include `model:` frontmatter (use `effort:` instead — model-agnostic).
79
+ - Do NOT add numbered step lists, explanations, or any content beyond the template.
80
+ - Do NOT add a `Also read` line for any file — the workflow controls all context loading.
81
+
82
+ **Per-command descriptions** (fixed, not model-generated):
83
+
84
+ | Command | description |
85
+ |---|---|
86
+ | `plan.md` | Design and document the implementation plan for a task |
87
+ | `review-plan.md` | Architectural review of a task implementation plan |
88
+ | `implement.md` | Execute the approved implementation plan for a task |
89
+ | `review-code.md` | Code quality review of a completed task implementation |
90
+ | `fix-bug.md` | Triage, diagnose, and fix a bug |
91
+ | `approve.md` | Final architect approval gate for a completed task |
92
+ | `commit.md` | Stage and commit completed task artifacts |
93
+ | `run-task.md` | Orchestrate the full plan→implement→review→approve pipeline for a task |
94
+ | `run-sprint.md` | Execute all tasks in a sprint (sequential or parallel) |
95
+ | `new-sprint.md` | Elicit and structure requirements for a new sprint |
96
+ | `plan-sprint.md` | Decompose sprint requirements into tasks with dependencies |
97
+ | `collate.md` | Regenerate KB documents from the JSON store |
98
+ | `retro.md` | Produce sprint retrospective and lessons-learned document |
99
+ | `check-agent.md` | Verify an agent has read and understood the project KB before high-stakes tasks |
100
+ | `enhance.md` | Progressive project-specific enrichment of structural elements |
101
+ | `validate.md` | Validate that a task implementation satisfies acceptance criteria |
102
+
103
+ **Effort levels** — use `effort:` frontmatter (capability request, model-agnostic):
104
+
105
+ | Command | effort | Rationale |
106
+ |---|---|---|
107
+ | `review-plan.md` | `max` | Architectural gate — needs deepest reasoning |
108
+ | `review-code.md` | `max` | Quality gate — needs deepest reasoning |
109
+ | `approve.md` | `max` | Final approval gate |
110
+ | `plan.md` | `high` | Design work with broad codebase context |
111
+ | `implement.md` | `high` | Non-trivial code generation |
112
+ | `fix-bug.md` | `high` | Diagnosis + fix |
113
+ | `plan-sprint.md` | `high` | Decomposition and dependency analysis |
114
+ | `run-task.md` | `high` | Full task orchestration |
115
+ | `run-sprint.md` | `high` | Multi-task orchestration |
116
+ | `new-sprint.md` | `high` | Structured requirements elicitation |
117
+ | `retro.md` | `medium` | Reflection and summary |
118
+ | `collate.md` | `low` | Mechanical markdown regeneration |
119
+ | `commit.md` | `low` | Staging and committing completed work |
120
+ | `check-agent.md` | `medium` | Short factual quiz — moderate reasoning, no deep codebase traversal |
121
+ | `enhance.md` | `high` | Enhancement agent — broad structural enrichment |
122
+ | `validate.md` | `max` | Validation gate — needs deepest reasoning |
123
+
124
+ Do **not** include `model:` frontmatter — that directive pins a specific model and is
125
+ not appropriate for user command files.
126
+
127
+ After writing each command file, record it in the generation manifest:
128
+ ```sh
129
+ node "$FORGE_ROOT/tools/generation-manifest.cjs" record {paths.commands}/forge/{filename}.md
130
+ ```
131
+
132
+ (`FORGE_ROOT` is available from the parent init flow; tool invocations use `$FORGE_ROOT/tools/` throughout.)
133
+
134
+ ## Post-generation: flat-file cleanup
135
+
136
+ After all 16 command files have been written and recorded, scan for pre-v0.13.0
137
+ flat command files that were never namespaced. These are the **13 known flat filenames**:
138
+
139
+ ```
140
+ new-sprint.md plan-sprint.md run-task.md run-sprint.md plan.md
141
+ review-plan.md implement.md review-code.md fix-bug.md approve.md
142
+ commit.md collate.md retro.md
143
+ ```
144
+
145
+ Check for each at `.claude/commands/{filename}.md` (the flat path, NOT the namespaced
146
+ subdirectory).
147
+
148
+ **Logic:**
149
+
150
+ - If **none** of the 13 files exist at the flat path — skip silently. No prompt.
151
+
152
+ - If **one or more** exist, display the list:
153
+ ```
154
+ Found pre-v0.13.0 flat command files that are no longer used:
155
+ .claude/commands/plan.md
156
+ .claude/commands/implement.md
157
+ ... (list each found file)
158
+
159
+ These have been replaced by namespaced commands under .claude/commands/forge/.
160
+ Remove them now? (yes / skip)
161
+ ```
162
+
163
+ - **On `yes`:** Delete each found file. For each deletion, print:
164
+ `Removed: .claude/commands/{filename}.md`
165
+ When done: `Flat command cleanup complete.`
166
+
167
+ - **On `skip`:** Print:
168
+ `Skipped. Remember to delete these files manually to avoid command name collisions.`
169
+
170
+ **Do NOT delete any file that is not in the 13-filename list above.** Custom commands,
171
+ project-specific wrappers, and unrecognised files are strictly off-limits.
@@ -0,0 +1,60 @@
1
+ # Knowledge Base Doc Generation — Per-Subagent Instructions
2
+
3
+ You are generating **ONE** knowledge base document. You have been given:
4
+
5
+ 1. A **discovery context** — the raw findings from Phase 1 discovery scans,
6
+ passed inline in your prompt
7
+ 2. A **doc spec** — which file to write and what it should contain
8
+ 3. A **project brief** (`.forge/init-context.md`) — for names and paths
9
+
10
+ Your job is to produce exactly one file and return a one-line status.
11
+
12
+ ---
13
+
14
+ ## Rules
15
+
16
+ 1. **Write EXACTLY ONE file** at the path specified in your doc spec.
17
+
18
+ 2. **Confidence header** — every generated doc must open with:
19
+ ```
20
+ <!-- AUTO-GENERATED by /forge:init — confidence: N% -->
21
+ ```
22
+ Set N% based on how much evidence the discovery context provided:
23
+ - 90–100%: directly observed in code/config
24
+ - 70–89%: inferred from conventions or partial evidence
25
+ - below 70%: limited evidence, many `[?]` markers expected
26
+
27
+ 3. **Uncertainty markers** — any fact not directly observed in the discovery
28
+ context must be marked with `[?]`. Do not invent values.
29
+
30
+ 4. **Entity names** — use entity names exactly as they appear in the brief's
31
+ `## Domain Entities` section. Do not rename or abbreviate.
32
+
33
+ 5. **Scope discipline** — generate only what the doc spec prescribes.
34
+ Do not add sections not listed in the spec. Do not cross-reference
35
+ other KB docs that do not yet exist.
36
+
37
+ 6. **`architecture/INDEX.md` and `business-domain/INDEX.md`** — if your
38
+ assigned doc is an INDEX file, link only to docs that exist on disk at
39
+ the time you write. Do not anticipate files that may not have been written.
40
+
41
+ ---
42
+
43
+ ## Self-check (mandatory last step)
44
+
45
+ After writing the file, verify before returning:
46
+
47
+ 1. Read back the written file
48
+ 2. Confirm the confidence header is present on the first line
49
+ 3. Confirm no `{placeholder}` tokens remain
50
+ 4. Record in the manifest:
51
+ ```sh
52
+ node "$FORGE_ROOT/tools/generation-manifest.cjs" record "{output_path}"
53
+ ```
54
+ (If generation-manifest.cjs is not yet installed, skip silently.)
55
+
56
+ 5. Return **exactly one line**:
57
+ - `done: <first 80 chars of the written file>` — on success
58
+ - `FAILED: <reason>` — if any step above failed or the file could not be written
59
+
60
+ Do not output anything else after the status line.