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.
- package/.claude-plugin/README.md +26 -0
- package/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +24 -0
- package/LICENSE +21 -0
- package/README.ja-JP.md +834 -0
- package/README.ko-KR.md +823 -0
- package/README.md +806 -0
- package/README.pt-BR.md +452 -0
- package/README.zh-CN.md +800 -0
- package/agents/cap-architect.md +269 -0
- package/agents/cap-brainstormer.md +207 -0
- package/agents/cap-curator.md +276 -0
- package/agents/cap-debugger.md +365 -0
- package/agents/cap-designer.md +246 -0
- package/agents/cap-historian.md +464 -0
- package/agents/cap-migrator.md +291 -0
- package/agents/cap-prototyper.md +197 -0
- package/agents/cap-validator.md +308 -0
- package/bin/install.js +5433 -0
- package/cap/bin/cap-tools.cjs +853 -0
- package/cap/bin/lib/arc-scanner.cjs +344 -0
- package/cap/bin/lib/cap-affinity-engine.cjs +862 -0
- package/cap/bin/lib/cap-anchor.cjs +228 -0
- package/cap/bin/lib/cap-annotation-writer.cjs +340 -0
- package/cap/bin/lib/cap-checkpoint.cjs +434 -0
- package/cap/bin/lib/cap-cluster-detect.cjs +945 -0
- package/cap/bin/lib/cap-cluster-display.cjs +52 -0
- package/cap/bin/lib/cap-cluster-format.cjs +245 -0
- package/cap/bin/lib/cap-cluster-helpers.cjs +295 -0
- package/cap/bin/lib/cap-cluster-io.cjs +212 -0
- package/cap/bin/lib/cap-completeness.cjs +540 -0
- package/cap/bin/lib/cap-deps.cjs +583 -0
- package/cap/bin/lib/cap-design-families.cjs +332 -0
- package/cap/bin/lib/cap-design.cjs +966 -0
- package/cap/bin/lib/cap-divergence-detector.cjs +400 -0
- package/cap/bin/lib/cap-doctor.cjs +752 -0
- package/cap/bin/lib/cap-feature-map-internals.cjs +19 -0
- package/cap/bin/lib/cap-feature-map-migrate.cjs +335 -0
- package/cap/bin/lib/cap-feature-map-monorepo.cjs +885 -0
- package/cap/bin/lib/cap-feature-map-shard.cjs +315 -0
- package/cap/bin/lib/cap-feature-map.cjs +1943 -0
- package/cap/bin/lib/cap-fitness-score.cjs +1075 -0
- package/cap/bin/lib/cap-impact-analysis.cjs +652 -0
- package/cap/bin/lib/cap-learn-review.cjs +1072 -0
- package/cap/bin/lib/cap-learning-signals.cjs +627 -0
- package/cap/bin/lib/cap-loader.cjs +227 -0
- package/cap/bin/lib/cap-logger.cjs +57 -0
- package/cap/bin/lib/cap-memory-bridge.cjs +764 -0
- package/cap/bin/lib/cap-memory-confidence.cjs +452 -0
- package/cap/bin/lib/cap-memory-dir.cjs +987 -0
- package/cap/bin/lib/cap-memory-engine.cjs +698 -0
- package/cap/bin/lib/cap-memory-extends.cjs +398 -0
- package/cap/bin/lib/cap-memory-graph.cjs +790 -0
- package/cap/bin/lib/cap-memory-migrate.cjs +2015 -0
- package/cap/bin/lib/cap-memory-pin.cjs +183 -0
- package/cap/bin/lib/cap-memory-platform.cjs +490 -0
- package/cap/bin/lib/cap-memory-prune.cjs +707 -0
- package/cap/bin/lib/cap-memory-schema.cjs +812 -0
- package/cap/bin/lib/cap-migrate-tags.cjs +309 -0
- package/cap/bin/lib/cap-migrate.cjs +540 -0
- package/cap/bin/lib/cap-pattern-apply.cjs +1203 -0
- package/cap/bin/lib/cap-pattern-pipeline.cjs +1034 -0
- package/cap/bin/lib/cap-plugin-manifest.cjs +80 -0
- package/cap/bin/lib/cap-realtime-affinity.cjs +399 -0
- package/cap/bin/lib/cap-reconcile.cjs +570 -0
- package/cap/bin/lib/cap-research-gate.cjs +218 -0
- package/cap/bin/lib/cap-scope-filter.cjs +402 -0
- package/cap/bin/lib/cap-semantic-pipeline.cjs +1038 -0
- package/cap/bin/lib/cap-session-extract.cjs +987 -0
- package/cap/bin/lib/cap-session.cjs +445 -0
- package/cap/bin/lib/cap-snapshot-linkage.cjs +963 -0
- package/cap/bin/lib/cap-stack-docs.cjs +646 -0
- package/cap/bin/lib/cap-tag-observer.cjs +371 -0
- package/cap/bin/lib/cap-tag-scanner.cjs +1766 -0
- package/cap/bin/lib/cap-telemetry.cjs +466 -0
- package/cap/bin/lib/cap-test-audit.cjs +1438 -0
- package/cap/bin/lib/cap-thread-migrator.cjs +307 -0
- package/cap/bin/lib/cap-thread-synthesis.cjs +545 -0
- package/cap/bin/lib/cap-thread-tracker.cjs +519 -0
- package/cap/bin/lib/cap-trace.cjs +399 -0
- package/cap/bin/lib/cap-trust-mode.cjs +336 -0
- package/cap/bin/lib/cap-ui-design-editor.cjs +642 -0
- package/cap/bin/lib/cap-ui-mind-map.cjs +712 -0
- package/cap/bin/lib/cap-ui-thread-nav.cjs +693 -0
- package/cap/bin/lib/cap-ui.cjs +1245 -0
- package/cap/bin/lib/cap-upgrade.cjs +1028 -0
- package/cap/bin/lib/cli/arg-helpers.cjs +49 -0
- package/cap/bin/lib/cli/frontmatter-router.cjs +31 -0
- package/cap/bin/lib/cli/init-router.cjs +68 -0
- package/cap/bin/lib/cli/phase-router.cjs +102 -0
- package/cap/bin/lib/cli/state-router.cjs +61 -0
- package/cap/bin/lib/cli/template-router.cjs +37 -0
- package/cap/bin/lib/cli/uat-router.cjs +29 -0
- package/cap/bin/lib/cli/validation-router.cjs +26 -0
- package/cap/bin/lib/cli/verification-router.cjs +31 -0
- package/cap/bin/lib/cli/workstream-router.cjs +39 -0
- package/cap/bin/lib/commands.cjs +961 -0
- package/cap/bin/lib/config.cjs +467 -0
- package/cap/bin/lib/convention-reader.cjs +258 -0
- package/cap/bin/lib/core.cjs +1241 -0
- package/cap/bin/lib/feature-aggregator.cjs +423 -0
- package/cap/bin/lib/frontmatter.cjs +337 -0
- package/cap/bin/lib/init.cjs +1443 -0
- package/cap/bin/lib/manifest-generator.cjs +383 -0
- package/cap/bin/lib/milestone.cjs +253 -0
- package/cap/bin/lib/model-profiles.cjs +69 -0
- package/cap/bin/lib/monorepo-context.cjs +226 -0
- package/cap/bin/lib/monorepo-migrator.cjs +509 -0
- package/cap/bin/lib/phase.cjs +889 -0
- package/cap/bin/lib/profile-output.cjs +989 -0
- package/cap/bin/lib/profile-pipeline.cjs +540 -0
- package/cap/bin/lib/roadmap.cjs +330 -0
- package/cap/bin/lib/security.cjs +394 -0
- package/cap/bin/lib/session-manager.cjs +292 -0
- package/cap/bin/lib/skeleton-generator.cjs +179 -0
- package/cap/bin/lib/state.cjs +1032 -0
- package/cap/bin/lib/template.cjs +231 -0
- package/cap/bin/lib/test-detector.cjs +62 -0
- package/cap/bin/lib/uat.cjs +283 -0
- package/cap/bin/lib/verify.cjs +889 -0
- package/cap/bin/lib/workspace-detector.cjs +371 -0
- package/cap/bin/lib/workstream.cjs +492 -0
- package/cap/commands/gsd/workstreams.md +63 -0
- package/cap/references/arc-standard.md +315 -0
- package/cap/references/cap-agent-architecture.md +101 -0
- package/cap/references/cap-gitignore-template +9 -0
- package/cap/references/cap-zero-deps.md +158 -0
- package/cap/references/checkpoints.md +778 -0
- package/cap/references/continuation-format.md +249 -0
- package/cap/references/contract-test-templates.md +312 -0
- package/cap/references/feature-map-template.md +25 -0
- package/cap/references/git-integration.md +295 -0
- package/cap/references/git-planning-commit.md +38 -0
- package/cap/references/model-profiles.md +174 -0
- package/cap/references/phase-numbering.md +126 -0
- package/cap/references/planning-config.md +202 -0
- package/cap/references/property-test-templates.md +316 -0
- package/cap/references/security-test-templates.md +347 -0
- package/cap/references/session-template.json +8 -0
- package/cap/references/tdd.md +263 -0
- package/cap/references/user-profiling.md +681 -0
- package/cap/references/verification-patterns.md +612 -0
- package/cap/templates/UAT.md +265 -0
- package/cap/templates/claude-md.md +175 -0
- package/cap/templates/codebase/architecture.md +255 -0
- package/cap/templates/codebase/concerns.md +310 -0
- package/cap/templates/codebase/conventions.md +307 -0
- package/cap/templates/codebase/integrations.md +280 -0
- package/cap/templates/codebase/stack.md +186 -0
- package/cap/templates/codebase/structure.md +285 -0
- package/cap/templates/codebase/testing.md +480 -0
- package/cap/templates/config.json +44 -0
- package/cap/templates/context.md +352 -0
- package/cap/templates/continue-here.md +78 -0
- package/cap/templates/copilot-instructions.md +7 -0
- package/cap/templates/debug-subagent-prompt.md +91 -0
- package/cap/templates/discussion-log.md +63 -0
- package/cap/templates/milestone-archive.md +123 -0
- package/cap/templates/milestone.md +115 -0
- package/cap/templates/phase-prompt.md +610 -0
- package/cap/templates/planner-subagent-prompt.md +117 -0
- package/cap/templates/project.md +186 -0
- package/cap/templates/requirements.md +231 -0
- package/cap/templates/research-project/ARCHITECTURE.md +204 -0
- package/cap/templates/research-project/FEATURES.md +147 -0
- package/cap/templates/research-project/PITFALLS.md +200 -0
- package/cap/templates/research-project/STACK.md +120 -0
- package/cap/templates/research-project/SUMMARY.md +170 -0
- package/cap/templates/research.md +552 -0
- package/cap/templates/roadmap.md +202 -0
- package/cap/templates/state.md +176 -0
- package/cap/templates/summary.md +364 -0
- package/cap/templates/user-preferences.md +498 -0
- package/cap/templates/verification-report.md +322 -0
- package/cap/workflows/add-phase.md +112 -0
- package/cap/workflows/add-tests.md +351 -0
- package/cap/workflows/add-todo.md +158 -0
- package/cap/workflows/audit-milestone.md +340 -0
- package/cap/workflows/audit-uat.md +109 -0
- package/cap/workflows/autonomous.md +891 -0
- package/cap/workflows/check-todos.md +177 -0
- package/cap/workflows/cleanup.md +152 -0
- package/cap/workflows/complete-milestone.md +767 -0
- package/cap/workflows/diagnose-issues.md +231 -0
- package/cap/workflows/discovery-phase.md +289 -0
- package/cap/workflows/discuss-phase-assumptions.md +653 -0
- package/cap/workflows/discuss-phase.md +1049 -0
- package/cap/workflows/do.md +104 -0
- package/cap/workflows/execute-phase.md +846 -0
- package/cap/workflows/execute-plan.md +514 -0
- package/cap/workflows/fast.md +105 -0
- package/cap/workflows/forensics.md +265 -0
- package/cap/workflows/health.md +181 -0
- package/cap/workflows/help.md +660 -0
- package/cap/workflows/insert-phase.md +130 -0
- package/cap/workflows/list-phase-assumptions.md +178 -0
- package/cap/workflows/list-workspaces.md +56 -0
- package/cap/workflows/manager.md +362 -0
- package/cap/workflows/map-codebase.md +377 -0
- package/cap/workflows/milestone-summary.md +223 -0
- package/cap/workflows/new-milestone.md +486 -0
- package/cap/workflows/new-project.md +1250 -0
- package/cap/workflows/new-workspace.md +237 -0
- package/cap/workflows/next.md +97 -0
- package/cap/workflows/node-repair.md +92 -0
- package/cap/workflows/note.md +156 -0
- package/cap/workflows/pause-work.md +176 -0
- package/cap/workflows/plan-milestone-gaps.md +273 -0
- package/cap/workflows/plan-phase.md +857 -0
- package/cap/workflows/plant-seed.md +169 -0
- package/cap/workflows/pr-branch.md +129 -0
- package/cap/workflows/profile-user.md +449 -0
- package/cap/workflows/progress.md +507 -0
- package/cap/workflows/quick.md +757 -0
- package/cap/workflows/remove-phase.md +155 -0
- package/cap/workflows/remove-workspace.md +90 -0
- package/cap/workflows/research-phase.md +82 -0
- package/cap/workflows/resume-project.md +326 -0
- package/cap/workflows/review.md +228 -0
- package/cap/workflows/session-report.md +146 -0
- package/cap/workflows/settings.md +283 -0
- package/cap/workflows/ship.md +228 -0
- package/cap/workflows/stats.md +60 -0
- package/cap/workflows/transition.md +671 -0
- package/cap/workflows/ui-phase.md +298 -0
- package/cap/workflows/ui-review.md +161 -0
- package/cap/workflows/update.md +323 -0
- package/cap/workflows/validate-phase.md +170 -0
- package/cap/workflows/verify-phase.md +254 -0
- package/cap/workflows/verify-work.md +637 -0
- package/commands/cap/annotate.md +165 -0
- package/commands/cap/brainstorm.md +393 -0
- package/commands/cap/checkpoint.md +106 -0
- package/commands/cap/completeness.md +94 -0
- package/commands/cap/continue.md +72 -0
- package/commands/cap/debug.md +588 -0
- package/commands/cap/deps.md +169 -0
- package/commands/cap/design.md +479 -0
- package/commands/cap/init.md +354 -0
- package/commands/cap/iterate.md +249 -0
- package/commands/cap/learn.md +459 -0
- package/commands/cap/memory.md +275 -0
- package/commands/cap/migrate-feature-map.md +91 -0
- package/commands/cap/migrate-memory.md +108 -0
- package/commands/cap/migrate-tags.md +91 -0
- package/commands/cap/migrate.md +131 -0
- package/commands/cap/prototype.md +510 -0
- package/commands/cap/reconcile.md +121 -0
- package/commands/cap/review.md +360 -0
- package/commands/cap/save.md +72 -0
- package/commands/cap/scan.md +404 -0
- package/commands/cap/start.md +356 -0
- package/commands/cap/status.md +118 -0
- package/commands/cap/test-audit.md +262 -0
- package/commands/cap/test.md +394 -0
- package/commands/cap/trace.md +133 -0
- package/commands/cap/ui.md +167 -0
- package/hooks/dist/cap-check-update.js +115 -0
- package/hooks/dist/cap-context-monitor.js +185 -0
- package/hooks/dist/cap-learn-review-hook.js +114 -0
- package/hooks/dist/cap-learning-hook.js +192 -0
- package/hooks/dist/cap-memory.js +299 -0
- package/hooks/dist/cap-prompt-guard.js +97 -0
- package/hooks/dist/cap-statusline.js +157 -0
- package/hooks/dist/cap-tag-observer.js +115 -0
- package/hooks/dist/cap-version-check.js +112 -0
- package/hooks/dist/cap-workflow-guard.js +175 -0
- package/hooks/hooks.json +55 -0
- package/package.json +58 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +93 -0
- package/scripts/cap-removal-checklist.md +202 -0
- package/scripts/prompt-injection-scan.sh +199 -0
- package/scripts/run-tests.cjs +181 -0
- 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
|
+
};
|