cap-pro 1.0.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.
Files changed (275) hide show
  1. package/.claude-plugin/README.md +26 -0
  2. package/.claude-plugin/marketplace.json +24 -0
  3. package/.claude-plugin/plugin.json +24 -0
  4. package/LICENSE +21 -0
  5. package/README.ja-JP.md +834 -0
  6. package/README.ko-KR.md +823 -0
  7. package/README.md +806 -0
  8. package/README.pt-BR.md +452 -0
  9. package/README.zh-CN.md +800 -0
  10. package/agents/cap-architect.md +269 -0
  11. package/agents/cap-brainstormer.md +207 -0
  12. package/agents/cap-curator.md +276 -0
  13. package/agents/cap-debugger.md +365 -0
  14. package/agents/cap-designer.md +246 -0
  15. package/agents/cap-historian.md +464 -0
  16. package/agents/cap-migrator.md +291 -0
  17. package/agents/cap-prototyper.md +197 -0
  18. package/agents/cap-validator.md +308 -0
  19. package/bin/install.js +5433 -0
  20. package/cap/bin/cap-tools.cjs +853 -0
  21. package/cap/bin/lib/arc-scanner.cjs +344 -0
  22. package/cap/bin/lib/cap-affinity-engine.cjs +862 -0
  23. package/cap/bin/lib/cap-anchor.cjs +228 -0
  24. package/cap/bin/lib/cap-annotation-writer.cjs +340 -0
  25. package/cap/bin/lib/cap-checkpoint.cjs +434 -0
  26. package/cap/bin/lib/cap-cluster-detect.cjs +945 -0
  27. package/cap/bin/lib/cap-cluster-display.cjs +52 -0
  28. package/cap/bin/lib/cap-cluster-format.cjs +245 -0
  29. package/cap/bin/lib/cap-cluster-helpers.cjs +295 -0
  30. package/cap/bin/lib/cap-cluster-io.cjs +212 -0
  31. package/cap/bin/lib/cap-completeness.cjs +540 -0
  32. package/cap/bin/lib/cap-deps.cjs +583 -0
  33. package/cap/bin/lib/cap-design-families.cjs +332 -0
  34. package/cap/bin/lib/cap-design.cjs +966 -0
  35. package/cap/bin/lib/cap-divergence-detector.cjs +400 -0
  36. package/cap/bin/lib/cap-doctor.cjs +752 -0
  37. package/cap/bin/lib/cap-feature-map-internals.cjs +19 -0
  38. package/cap/bin/lib/cap-feature-map-migrate.cjs +335 -0
  39. package/cap/bin/lib/cap-feature-map-monorepo.cjs +885 -0
  40. package/cap/bin/lib/cap-feature-map-shard.cjs +315 -0
  41. package/cap/bin/lib/cap-feature-map.cjs +1943 -0
  42. package/cap/bin/lib/cap-fitness-score.cjs +1075 -0
  43. package/cap/bin/lib/cap-impact-analysis.cjs +652 -0
  44. package/cap/bin/lib/cap-learn-review.cjs +1072 -0
  45. package/cap/bin/lib/cap-learning-signals.cjs +627 -0
  46. package/cap/bin/lib/cap-loader.cjs +227 -0
  47. package/cap/bin/lib/cap-logger.cjs +57 -0
  48. package/cap/bin/lib/cap-memory-bridge.cjs +764 -0
  49. package/cap/bin/lib/cap-memory-confidence.cjs +452 -0
  50. package/cap/bin/lib/cap-memory-dir.cjs +987 -0
  51. package/cap/bin/lib/cap-memory-engine.cjs +698 -0
  52. package/cap/bin/lib/cap-memory-extends.cjs +398 -0
  53. package/cap/bin/lib/cap-memory-graph.cjs +790 -0
  54. package/cap/bin/lib/cap-memory-migrate.cjs +2015 -0
  55. package/cap/bin/lib/cap-memory-pin.cjs +183 -0
  56. package/cap/bin/lib/cap-memory-platform.cjs +490 -0
  57. package/cap/bin/lib/cap-memory-prune.cjs +707 -0
  58. package/cap/bin/lib/cap-memory-schema.cjs +812 -0
  59. package/cap/bin/lib/cap-migrate-tags.cjs +309 -0
  60. package/cap/bin/lib/cap-migrate.cjs +540 -0
  61. package/cap/bin/lib/cap-pattern-apply.cjs +1203 -0
  62. package/cap/bin/lib/cap-pattern-pipeline.cjs +1034 -0
  63. package/cap/bin/lib/cap-plugin-manifest.cjs +80 -0
  64. package/cap/bin/lib/cap-realtime-affinity.cjs +399 -0
  65. package/cap/bin/lib/cap-reconcile.cjs +570 -0
  66. package/cap/bin/lib/cap-research-gate.cjs +218 -0
  67. package/cap/bin/lib/cap-scope-filter.cjs +402 -0
  68. package/cap/bin/lib/cap-semantic-pipeline.cjs +1038 -0
  69. package/cap/bin/lib/cap-session-extract.cjs +987 -0
  70. package/cap/bin/lib/cap-session.cjs +445 -0
  71. package/cap/bin/lib/cap-snapshot-linkage.cjs +963 -0
  72. package/cap/bin/lib/cap-stack-docs.cjs +646 -0
  73. package/cap/bin/lib/cap-tag-observer.cjs +371 -0
  74. package/cap/bin/lib/cap-tag-scanner.cjs +1766 -0
  75. package/cap/bin/lib/cap-telemetry.cjs +466 -0
  76. package/cap/bin/lib/cap-test-audit.cjs +1438 -0
  77. package/cap/bin/lib/cap-thread-migrator.cjs +307 -0
  78. package/cap/bin/lib/cap-thread-synthesis.cjs +545 -0
  79. package/cap/bin/lib/cap-thread-tracker.cjs +519 -0
  80. package/cap/bin/lib/cap-trace.cjs +399 -0
  81. package/cap/bin/lib/cap-trust-mode.cjs +336 -0
  82. package/cap/bin/lib/cap-ui-design-editor.cjs +642 -0
  83. package/cap/bin/lib/cap-ui-mind-map.cjs +712 -0
  84. package/cap/bin/lib/cap-ui-thread-nav.cjs +693 -0
  85. package/cap/bin/lib/cap-ui.cjs +1245 -0
  86. package/cap/bin/lib/cap-upgrade.cjs +1028 -0
  87. package/cap/bin/lib/cli/arg-helpers.cjs +49 -0
  88. package/cap/bin/lib/cli/frontmatter-router.cjs +31 -0
  89. package/cap/bin/lib/cli/init-router.cjs +68 -0
  90. package/cap/bin/lib/cli/phase-router.cjs +102 -0
  91. package/cap/bin/lib/cli/state-router.cjs +61 -0
  92. package/cap/bin/lib/cli/template-router.cjs +37 -0
  93. package/cap/bin/lib/cli/uat-router.cjs +29 -0
  94. package/cap/bin/lib/cli/validation-router.cjs +26 -0
  95. package/cap/bin/lib/cli/verification-router.cjs +31 -0
  96. package/cap/bin/lib/cli/workstream-router.cjs +39 -0
  97. package/cap/bin/lib/commands.cjs +961 -0
  98. package/cap/bin/lib/config.cjs +467 -0
  99. package/cap/bin/lib/convention-reader.cjs +258 -0
  100. package/cap/bin/lib/core.cjs +1241 -0
  101. package/cap/bin/lib/feature-aggregator.cjs +423 -0
  102. package/cap/bin/lib/frontmatter.cjs +337 -0
  103. package/cap/bin/lib/init.cjs +1443 -0
  104. package/cap/bin/lib/manifest-generator.cjs +383 -0
  105. package/cap/bin/lib/milestone.cjs +253 -0
  106. package/cap/bin/lib/model-profiles.cjs +69 -0
  107. package/cap/bin/lib/monorepo-context.cjs +226 -0
  108. package/cap/bin/lib/monorepo-migrator.cjs +509 -0
  109. package/cap/bin/lib/phase.cjs +889 -0
  110. package/cap/bin/lib/profile-output.cjs +989 -0
  111. package/cap/bin/lib/profile-pipeline.cjs +540 -0
  112. package/cap/bin/lib/roadmap.cjs +330 -0
  113. package/cap/bin/lib/security.cjs +394 -0
  114. package/cap/bin/lib/session-manager.cjs +292 -0
  115. package/cap/bin/lib/skeleton-generator.cjs +179 -0
  116. package/cap/bin/lib/state.cjs +1032 -0
  117. package/cap/bin/lib/template.cjs +231 -0
  118. package/cap/bin/lib/test-detector.cjs +62 -0
  119. package/cap/bin/lib/uat.cjs +283 -0
  120. package/cap/bin/lib/verify.cjs +889 -0
  121. package/cap/bin/lib/workspace-detector.cjs +371 -0
  122. package/cap/bin/lib/workstream.cjs +492 -0
  123. package/cap/commands/gsd/workstreams.md +63 -0
  124. package/cap/references/arc-standard.md +315 -0
  125. package/cap/references/cap-agent-architecture.md +101 -0
  126. package/cap/references/cap-gitignore-template +9 -0
  127. package/cap/references/cap-zero-deps.md +158 -0
  128. package/cap/references/checkpoints.md +778 -0
  129. package/cap/references/continuation-format.md +249 -0
  130. package/cap/references/contract-test-templates.md +312 -0
  131. package/cap/references/feature-map-template.md +25 -0
  132. package/cap/references/git-integration.md +295 -0
  133. package/cap/references/git-planning-commit.md +38 -0
  134. package/cap/references/model-profiles.md +174 -0
  135. package/cap/references/phase-numbering.md +126 -0
  136. package/cap/references/planning-config.md +202 -0
  137. package/cap/references/property-test-templates.md +316 -0
  138. package/cap/references/security-test-templates.md +347 -0
  139. package/cap/references/session-template.json +8 -0
  140. package/cap/references/tdd.md +263 -0
  141. package/cap/references/user-profiling.md +681 -0
  142. package/cap/references/verification-patterns.md +612 -0
  143. package/cap/templates/UAT.md +265 -0
  144. package/cap/templates/claude-md.md +175 -0
  145. package/cap/templates/codebase/architecture.md +255 -0
  146. package/cap/templates/codebase/concerns.md +310 -0
  147. package/cap/templates/codebase/conventions.md +307 -0
  148. package/cap/templates/codebase/integrations.md +280 -0
  149. package/cap/templates/codebase/stack.md +186 -0
  150. package/cap/templates/codebase/structure.md +285 -0
  151. package/cap/templates/codebase/testing.md +480 -0
  152. package/cap/templates/config.json +44 -0
  153. package/cap/templates/context.md +352 -0
  154. package/cap/templates/continue-here.md +78 -0
  155. package/cap/templates/copilot-instructions.md +7 -0
  156. package/cap/templates/debug-subagent-prompt.md +91 -0
  157. package/cap/templates/discussion-log.md +63 -0
  158. package/cap/templates/milestone-archive.md +123 -0
  159. package/cap/templates/milestone.md +115 -0
  160. package/cap/templates/phase-prompt.md +610 -0
  161. package/cap/templates/planner-subagent-prompt.md +117 -0
  162. package/cap/templates/project.md +186 -0
  163. package/cap/templates/requirements.md +231 -0
  164. package/cap/templates/research-project/ARCHITECTURE.md +204 -0
  165. package/cap/templates/research-project/FEATURES.md +147 -0
  166. package/cap/templates/research-project/PITFALLS.md +200 -0
  167. package/cap/templates/research-project/STACK.md +120 -0
  168. package/cap/templates/research-project/SUMMARY.md +170 -0
  169. package/cap/templates/research.md +552 -0
  170. package/cap/templates/roadmap.md +202 -0
  171. package/cap/templates/state.md +176 -0
  172. package/cap/templates/summary.md +364 -0
  173. package/cap/templates/user-preferences.md +498 -0
  174. package/cap/templates/verification-report.md +322 -0
  175. package/cap/workflows/add-phase.md +112 -0
  176. package/cap/workflows/add-tests.md +351 -0
  177. package/cap/workflows/add-todo.md +158 -0
  178. package/cap/workflows/audit-milestone.md +340 -0
  179. package/cap/workflows/audit-uat.md +109 -0
  180. package/cap/workflows/autonomous.md +891 -0
  181. package/cap/workflows/check-todos.md +177 -0
  182. package/cap/workflows/cleanup.md +152 -0
  183. package/cap/workflows/complete-milestone.md +767 -0
  184. package/cap/workflows/diagnose-issues.md +231 -0
  185. package/cap/workflows/discovery-phase.md +289 -0
  186. package/cap/workflows/discuss-phase-assumptions.md +653 -0
  187. package/cap/workflows/discuss-phase.md +1049 -0
  188. package/cap/workflows/do.md +104 -0
  189. package/cap/workflows/execute-phase.md +846 -0
  190. package/cap/workflows/execute-plan.md +514 -0
  191. package/cap/workflows/fast.md +105 -0
  192. package/cap/workflows/forensics.md +265 -0
  193. package/cap/workflows/health.md +181 -0
  194. package/cap/workflows/help.md +660 -0
  195. package/cap/workflows/insert-phase.md +130 -0
  196. package/cap/workflows/list-phase-assumptions.md +178 -0
  197. package/cap/workflows/list-workspaces.md +56 -0
  198. package/cap/workflows/manager.md +362 -0
  199. package/cap/workflows/map-codebase.md +377 -0
  200. package/cap/workflows/milestone-summary.md +223 -0
  201. package/cap/workflows/new-milestone.md +486 -0
  202. package/cap/workflows/new-project.md +1250 -0
  203. package/cap/workflows/new-workspace.md +237 -0
  204. package/cap/workflows/next.md +97 -0
  205. package/cap/workflows/node-repair.md +92 -0
  206. package/cap/workflows/note.md +156 -0
  207. package/cap/workflows/pause-work.md +176 -0
  208. package/cap/workflows/plan-milestone-gaps.md +273 -0
  209. package/cap/workflows/plan-phase.md +857 -0
  210. package/cap/workflows/plant-seed.md +169 -0
  211. package/cap/workflows/pr-branch.md +129 -0
  212. package/cap/workflows/profile-user.md +449 -0
  213. package/cap/workflows/progress.md +507 -0
  214. package/cap/workflows/quick.md +757 -0
  215. package/cap/workflows/remove-phase.md +155 -0
  216. package/cap/workflows/remove-workspace.md +90 -0
  217. package/cap/workflows/research-phase.md +82 -0
  218. package/cap/workflows/resume-project.md +326 -0
  219. package/cap/workflows/review.md +228 -0
  220. package/cap/workflows/session-report.md +146 -0
  221. package/cap/workflows/settings.md +283 -0
  222. package/cap/workflows/ship.md +228 -0
  223. package/cap/workflows/stats.md +60 -0
  224. package/cap/workflows/transition.md +671 -0
  225. package/cap/workflows/ui-phase.md +298 -0
  226. package/cap/workflows/ui-review.md +161 -0
  227. package/cap/workflows/update.md +323 -0
  228. package/cap/workflows/validate-phase.md +170 -0
  229. package/cap/workflows/verify-phase.md +254 -0
  230. package/cap/workflows/verify-work.md +637 -0
  231. package/commands/cap/annotate.md +165 -0
  232. package/commands/cap/brainstorm.md +393 -0
  233. package/commands/cap/checkpoint.md +106 -0
  234. package/commands/cap/completeness.md +94 -0
  235. package/commands/cap/continue.md +72 -0
  236. package/commands/cap/debug.md +588 -0
  237. package/commands/cap/deps.md +169 -0
  238. package/commands/cap/design.md +479 -0
  239. package/commands/cap/init.md +354 -0
  240. package/commands/cap/iterate.md +249 -0
  241. package/commands/cap/learn.md +459 -0
  242. package/commands/cap/memory.md +275 -0
  243. package/commands/cap/migrate-feature-map.md +91 -0
  244. package/commands/cap/migrate-memory.md +108 -0
  245. package/commands/cap/migrate-tags.md +91 -0
  246. package/commands/cap/migrate.md +131 -0
  247. package/commands/cap/prototype.md +510 -0
  248. package/commands/cap/reconcile.md +121 -0
  249. package/commands/cap/review.md +360 -0
  250. package/commands/cap/save.md +72 -0
  251. package/commands/cap/scan.md +404 -0
  252. package/commands/cap/start.md +356 -0
  253. package/commands/cap/status.md +118 -0
  254. package/commands/cap/test-audit.md +262 -0
  255. package/commands/cap/test.md +394 -0
  256. package/commands/cap/trace.md +133 -0
  257. package/commands/cap/ui.md +167 -0
  258. package/hooks/dist/cap-check-update.js +115 -0
  259. package/hooks/dist/cap-context-monitor.js +185 -0
  260. package/hooks/dist/cap-learn-review-hook.js +114 -0
  261. package/hooks/dist/cap-learning-hook.js +192 -0
  262. package/hooks/dist/cap-memory.js +299 -0
  263. package/hooks/dist/cap-prompt-guard.js +97 -0
  264. package/hooks/dist/cap-statusline.js +157 -0
  265. package/hooks/dist/cap-tag-observer.js +115 -0
  266. package/hooks/dist/cap-version-check.js +112 -0
  267. package/hooks/dist/cap-workflow-guard.js +175 -0
  268. package/hooks/hooks.json +55 -0
  269. package/package.json +58 -0
  270. package/scripts/base64-scan.sh +262 -0
  271. package/scripts/build-hooks.js +93 -0
  272. package/scripts/cap-removal-checklist.md +202 -0
  273. package/scripts/prompt-injection-scan.sh +199 -0
  274. package/scripts/run-tests.cjs +181 -0
  275. package/scripts/secret-scan.sh +227 -0
@@ -0,0 +1,227 @@
1
+ // @cap-feature(feature:F-020) Resilient Module Loading with Error Recovery
2
+ // @cap-decision Loader wraps require() with error detection, self-repair, and retry.
3
+ // @cap-history(sessions:2, edits:9, since:2026-04-02, learned:2026-04-03) Frequently modified — 2 sessions, 9 edits
4
+ // @cap-pitfall(learned:2026-04-02) Never silently fall back — always produce visible errors
5
+ 4.
6
+ // @cap-pitfall(learned:2026-04-02) The failure is: `Error: CAP module load failed: nonexistent-xyz.cjs` — it's using the real `require` because the test passes `installDir: LIB_DIR` but not `_require`.
7
+ // @cap-pitfall(learned:2026-04-02) Line 4061 is in the manifest generation — it only hashes `cap-` files for the manifest, which is correct (we don't want gsd files in the manifest).
8
+ // Bootstrap problem: if cap-loader.cjs itself is missing, callers need an inline try/catch
9
+ // to show the basic "run npx code-as-plan@latest --force" message. This module handles
10
+ // all other module failures once it is loaded.
11
+ // @cap-constraint Zero external dependencies — uses only Node.js built-ins.
12
+
13
+ 'use strict';
14
+
15
+ const { execSync } = require('node:child_process');
16
+ const fs = require('node:fs');
17
+ const path = require('node:path');
18
+ const os = require('node:os');
19
+
20
+ const REPAIR_COMMAND = 'npx code-as-plan@latest --force';
21
+
22
+ // @cap-todo(ac:F-020/AC-1) Display specific error naming the missing module and its expected path
23
+ /**
24
+ * Format a clear error message for a failed module load.
25
+ * @param {string} moduleName - Module filename (e.g., 'cap-feature-map.cjs')
26
+ * @param {string} fullPath - Absolute path where the module was expected
27
+ * @param {Error} originalError - The original require() error
28
+ * @returns {string} Formatted error message
29
+ */
30
+ function formatLoadError(moduleName, fullPath, originalError) {
31
+ const reason = originalError.code === 'MODULE_NOT_FOUND'
32
+ ? 'File not found'
33
+ : `Load error: ${originalError.message.split('\n')[0]}`;
34
+
35
+ return [
36
+ `[CAP] Failed to load module: ${moduleName}`,
37
+ ` Expected path: ${fullPath}`,
38
+ ` Reason: ${reason}`,
39
+ ` Repair: ${REPAIR_COMMAND}`,
40
+ ].join('\n');
41
+ }
42
+
43
+ /**
44
+ * Detect the CAP install directory.
45
+ * Checks the global install path first, then falls back to this file's directory.
46
+ * @cap-decision Intentionally duplicates cap-doctor.cjs:detectInstallDir(). cap-loader must be
47
+ * self-contained — it cannot require() cap-doctor because cap-loader is the module that handles
48
+ * require() failures. Extracting to a shared utility would create a bootstrap dependency.
49
+ * @returns {string} Absolute path to cap/bin/lib/
50
+ */
51
+ function detectInstallDir() {
52
+ const homeDir = process.env.HOME || os.homedir();
53
+ const globalDir = path.join(homeDir, '.claude', 'cap', 'cap', 'bin', 'lib');
54
+ if (fs.existsSync(globalDir)) {
55
+ return globalDir;
56
+ }
57
+ return __dirname;
58
+ }
59
+
60
+ // @cap-todo(ac:F-020/AC-4) Offer automatic self-repair by re-running the installer
61
+ /**
62
+ * Attempt to repair the CAP installation by re-running the installer.
63
+ * Runs `npx code-as-plan@latest --force` via execSync (blocking, up to 120s).
64
+ * If _repair() throws, the error propagates intentionally — callers should not
65
+ * catch unexpected failures from the repair mechanism itself.
66
+ * @returns {{ ok: boolean, error?: string }} Repair result
67
+ */
68
+ function attemptSelfRepair() {
69
+ // @cap-todo(ac:F-020/AC-3) Never silently fall back — always produce visible output
70
+ process.stderr.write('[CAP] Attempting self-repair: ' + REPAIR_COMMAND + '\n');
71
+
72
+ try {
73
+ execSync(REPAIR_COMMAND, {
74
+ encoding: 'utf8',
75
+ timeout: 120000, // 2 minute timeout for npm install
76
+ stdio: ['pipe', 'pipe', 'pipe'],
77
+ });
78
+ process.stderr.write('[CAP] Self-repair completed successfully.\n');
79
+ return { ok: true };
80
+ } catch (err) {
81
+ const msg = err.stderr
82
+ ? err.stderr.split('\n')[0]
83
+ : err.message.split('\n')[0];
84
+ return { ok: false, error: msg };
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Clear a module from Node's require cache so a fresh require() picks up repaired files.
90
+ * @param {string} fullPath - Absolute path to clear from cache
91
+ */
92
+ function clearRequireCache(fullPath) {
93
+ const resolved = path.resolve(fullPath);
94
+ delete require.cache[resolved];
95
+ }
96
+
97
+ // @cap-todo(ac:F-020/AC-2) Error message shall suggest running repair command
98
+ // @cap-todo(ac:F-020/AC-5) If self-repair succeeds, retry the original operation
99
+ // @cap-todo(ac:F-020/AC-6) If self-repair fails, exit with non-zero code
100
+ /**
101
+ * Load a CAP module with resilient error handling and optional self-repair.
102
+ *
103
+ * @param {string} moduleName - Module name without path (e.g., 'cap-feature-map' or 'cap-feature-map.cjs')
104
+ * @param {Object} [options]
105
+ * @param {string} [options.installDir] - Override install directory (for testing)
106
+ * @param {boolean} [options.autoRepair=false] - Attempt self-repair on failure
107
+ * @param {boolean} [options.exitOnFailure=true] - Call process.exit(1) if load fails after repair
108
+ * @param {function} [options._require] - Override require function (for testing)
109
+ * @param {function} [options._repair] - Override repair function (for testing)
110
+ * @param {function} [options._exit] - Override exit function (for testing)
111
+ * @param {function} [options._stderr] - Override stderr write function (for testing)
112
+ * @returns {*} The loaded module exports
113
+ * @throws {Error} If module cannot be loaded and exitOnFailure is false
114
+ */
115
+ function load(moduleName, options = {}) {
116
+ const {
117
+ installDir,
118
+ autoRepair = false,
119
+ exitOnFailure = true,
120
+ _require = require,
121
+ _repair = attemptSelfRepair,
122
+ _exit = (code) => process.exit(code),
123
+ _stderr = (msg) => process.stderr.write(msg),
124
+ } = options;
125
+
126
+ // Normalize module name: ensure .cjs extension
127
+ const fileName = moduleName.endsWith('.cjs') ? moduleName : `${moduleName}.cjs`;
128
+ const dir = installDir || detectInstallDir();
129
+ const fullPath = path.join(dir, fileName);
130
+
131
+ // @cap-todo(ac:F-020/AC-3) Never silently fall back — always produce a visible error
132
+ // First attempt
133
+ try {
134
+ return _require(path.resolve(fullPath));
135
+ } catch (firstError) {
136
+ const errorMsg = formatLoadError(fileName, fullPath, firstError);
137
+ _stderr(errorMsg + '\n');
138
+
139
+ // @cap-todo(ac:F-020/AC-4) Automatic self-repair option
140
+ if (!autoRepair) {
141
+ if (exitOnFailure) {
142
+ _stderr(`[CAP] Run "${REPAIR_COMMAND}" to repair your installation.\n`);
143
+ _exit(1);
144
+ return; // process.exit halts; return guards against overridden _exit in tests
145
+ }
146
+ const err = new Error(`CAP module load failed: ${fileName} at ${fullPath}`);
147
+ err.code = 'CAP_MODULE_LOAD_FAILED';
148
+ err.moduleName = fileName;
149
+ err.modulePath = fullPath;
150
+ err.originalError = firstError;
151
+ throw err;
152
+ }
153
+
154
+ // @cap-todo(ac:F-020/AC-4) Attempt self-repair
155
+ const repairResult = _repair();
156
+
157
+ if (repairResult.ok) {
158
+ // @cap-todo(ac:F-020/AC-5) Retry after successful repair
159
+ clearRequireCache(fullPath);
160
+ try {
161
+ const mod = _require(path.resolve(fullPath));
162
+ _stderr(`[CAP] Module ${fileName} loaded successfully after repair.\n`);
163
+ return mod;
164
+ } catch (retryError) {
165
+ // Repair ran but module still won't load
166
+ const retryMsg = formatLoadError(fileName, fullPath, retryError);
167
+ _stderr(retryMsg + '\n');
168
+ _stderr('[CAP] Self-repair completed but module still fails to load.\n');
169
+ _stderr(`[CAP] Reinstall manually: ${REPAIR_COMMAND}\n`);
170
+ if (exitOnFailure) {
171
+ _exit(1);
172
+ return;
173
+ }
174
+ const err = new Error(`CAP module load failed after repair: ${fileName}`);
175
+ err.code = 'CAP_MODULE_LOAD_FAILED_AFTER_REPAIR';
176
+ err.moduleName = fileName;
177
+ err.modulePath = fullPath;
178
+ err.originalError = retryError;
179
+ throw err;
180
+ }
181
+ }
182
+
183
+ // @cap-todo(ac:F-020/AC-6) Repair failed — exit with non-zero code
184
+ _stderr(`[CAP] Self-repair failed: ${repairResult.error || 'unknown error'}\n`);
185
+ _stderr(`[CAP] Reinstall manually: ${REPAIR_COMMAND}\n`);
186
+ if (exitOnFailure) {
187
+ _exit(1);
188
+ return;
189
+ }
190
+ const err = new Error(`CAP self-repair failed for module: ${fileName}`);
191
+ err.code = 'CAP_REPAIR_FAILED';
192
+ err.moduleName = fileName;
193
+ err.modulePath = fullPath;
194
+ err.repairError = repairResult.error;
195
+ throw err;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Load multiple CAP modules at once. Fails fast on the first missing module.
201
+ *
202
+ * @param {string[]} moduleNames - Array of module names
203
+ * @param {Object} [options] - Same options as load()
204
+ * @returns {Object} Map of moduleName -> exports
205
+ */
206
+ function loadAll(moduleNames, options = {}) {
207
+ const result = {};
208
+ for (const name of moduleNames) {
209
+ const key = name.replace(/\.cjs$/, '');
210
+ const mod = load(name, options);
211
+ // load() returns undefined only when _exit() was called (real process.exit halts,
212
+ // but overridden _exit in tests returns control). Stop iterating in either case.
213
+ if (mod === undefined) break;
214
+ result[key] = mod;
215
+ }
216
+ return result;
217
+ }
218
+
219
+ module.exports = {
220
+ load,
221
+ loadAll,
222
+ detectInstallDir,
223
+ formatLoadError,
224
+ attemptSelfRepair,
225
+ clearRequireCache,
226
+ REPAIR_COMMAND,
227
+ };
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ // @cap-feature(feature:F-050) Tiny zero-dependency debug logger gated on CAP_DEBUG env var.
4
+ // @cap-decision Implemented as a 1-file zero-dep helper rather than adopting a logging library — CAP's
5
+ // constraint forbids runtime dependencies. Output is gated on process.env.CAP_DEBUG so production runs are silent.
6
+ // @cap-decision Use console.warn (not console.log) so logger output goes to stderr and never pollutes
7
+ // stdout pipelines (e.g. /cap:status output consumed by other tools).
8
+
9
+ /**
10
+ * @typedef {Object} DiagnosticPayload
11
+ * @property {string} op - Operation name (e.g. 'loadClusterData', 'loadGraph')
12
+ * @property {string} [file] - Affected file path (when applicable)
13
+ * @property {string} errorType - err.code or err.constructor.name
14
+ * @property {string} errorMessage - err.message (single line)
15
+ * @property {string} recoveryAction - What the caller did to recover (e.g. 'returning empty array')
16
+ */
17
+
18
+ /**
19
+ * Emit a structured debug diagnostic when CAP_DEBUG is truthy. No-op otherwise.
20
+ *
21
+ * Output format is single-line JSON for grep-friendliness, prefixed with [cap:debug] for visibility.
22
+ *
23
+ * @param {DiagnosticPayload} payload - Structured diagnostic record
24
+ * @returns {void}
25
+ */
26
+ function debug(payload) {
27
+ if (!process.env.CAP_DEBUG) return;
28
+ try {
29
+ // eslint-disable-next-line no-console
30
+ console.warn(`[cap:debug] ${JSON.stringify(payload)}`);
31
+ } catch (_e) {
32
+ // Never let logging errors break the caller. Worst case: silent drop.
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Build a structured payload from an Error and op metadata.
38
+ *
39
+ * @param {string} op - Operation name
40
+ * @param {Error} err - The caught error
41
+ * @param {Object} [extra] - Additional fields (file, recoveryAction, etc.)
42
+ * @returns {DiagnosticPayload}
43
+ */
44
+ function fromError(op, err, extra) {
45
+ const e = err || {};
46
+ return {
47
+ op,
48
+ errorType: e.code || (e.constructor && e.constructor.name) || 'Error',
49
+ errorMessage: typeof e.message === 'string' ? e.message.split('\n')[0] : String(e),
50
+ ...(extra || {}),
51
+ };
52
+ }
53
+
54
+ module.exports = {
55
+ debug,
56
+ fromError,
57
+ };