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,133 @@
1
+ ---
2
+ name: cap:trace
3
+ description: "Print the call graph for a single acceptance criterion across all contributing files. Resolves primary file via @cap-feature(...primary:true) or tag-density heuristic."
4
+ argument-hint: "<AC-N | F-NNN/AC-N> [--depth N] [--restrict] [--json]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ ---
9
+
10
+ <!-- @cap-context CAP v2.0 trace command -- shows where an AC is implemented across files and what it depends on. Read-only. -->
11
+ <!-- @cap-decision Trace is read-only -- no Feature Map writes, no session updates. Safe to run repeatedly. -->
12
+ <!-- @cap-feature(feature:F-045) /cap:trace renders TraceResult from cap-trace.cjs as a tree. -->
13
+ <!-- @cap-todo(ac:F-045/AC-4) /cap:trace AC-N shall print the call graph from the primary file across referenced files for a given acceptance criterion. -->
14
+
15
+ <objective>
16
+ Print a structured trace for a single acceptance criterion:
17
+
18
+ - Which file is the primary implementation (designated via `@cap-feature(...primary:true)` or inferred via tag density)
19
+ - Which other files contribute to the same AC
20
+ - Static call graph (require/import edges) walked outward from the primary file up to N hops
21
+
22
+ This makes multi-file ACs navigable when a single AC spans more than one source file.
23
+
24
+ **Argument formats:**
25
+ - `F-NNN/AC-M` -- fully qualified
26
+ - `AC-M` -- short form, requires an active feature in `.cap/SESSION.json`
27
+
28
+ **Flags:**
29
+ - `--depth N` -- max BFS depth for the call graph (default 3)
30
+ - `--restrict` -- only follow edges into other AC-contributing files (suppresses non-AC neighbors)
31
+ - `--json` -- emit raw `TraceResult` JSON instead of formatted output
32
+ </objective>
33
+
34
+ <context>
35
+ $ARGUMENTS
36
+
37
+ @.cap/SESSION.json
38
+ </context>
39
+
40
+ <process>
41
+
42
+ ## Step 0: Parse arguments
43
+
44
+ Read `$ARGUMENTS`. Extract:
45
+ - The first non-flag token as `ac_arg`
46
+ - `--depth N` -> `depth` (integer, default 3)
47
+ - `--restrict` -> `restrict_to_ac_files` (boolean)
48
+ - `--json` -> `json_output` (boolean)
49
+
50
+ If `ac_arg` is missing, print usage and stop:
51
+
52
+ ```
53
+ Usage: /cap:trace <AC-N | F-NNN/AC-N> [--depth N] [--restrict] [--json]
54
+ ```
55
+
56
+ ## Step 1: Resolve AC reference
57
+
58
+ If `ac_arg` already contains `/` (e.g. `F-045/AC-4`), use it as-is.
59
+
60
+ Otherwise, read the active feature from SESSION.json and prefix it:
61
+
62
+ ```bash
63
+ node -e "
64
+ const session = require('./cap/bin/lib/cap-session.cjs');
65
+ const s = session.loadSession(process.cwd());
66
+ console.log(s.activeFeature || '');
67
+ "
68
+ ```
69
+
70
+ If the active feature is empty, print:
71
+
72
+ ```
73
+ No active feature in SESSION.json. Pass a fully-qualified AC reference like F-045/AC-1, or run /cap:start to set an active feature.
74
+ ```
75
+
76
+ and stop. Otherwise build `ac_ref = "<activeFeature>/<ac_arg>"`.
77
+
78
+ ## Step 2: Run the trace
79
+
80
+ ```bash
81
+ node -e "
82
+ const tr = require('./cap/bin/lib/cap-trace.cjs');
83
+ const acRef = process.argv[1];
84
+ const _parsedDepth = parseInt(process.argv[2], 10);
85
+ const depth = Number.isFinite(_parsedDepth) ? _parsedDepth : tr.DEFAULT_MAX_DEPTH;
86
+ const restrict = process.argv[3] === 'true';
87
+ const result = tr.traceAc(process.cwd(), acRef, { maxDepth: depth, restrictToAcFiles: restrict });
88
+ const json = process.argv[4] === 'true';
89
+ if (json) {
90
+ console.log(JSON.stringify(result, null, 2));
91
+ } else {
92
+ console.log(tr.formatTraceResult(result));
93
+ }
94
+ " '<AC_REF>' '<DEPTH>' '<RESTRICT>' '<JSON>'
95
+ ```
96
+
97
+ Display the output verbatim.
98
+
99
+ ## Step 2b: Append Design-Usage for the AC's feature (F-063)
100
+
101
+ <!-- @cap-todo(ac:F-063/AC-5) /cap:trace shall emit a Design-Usage line per feature whose usesDesign is non-empty. -->
102
+
103
+ ```bash
104
+ node -e "
105
+ const fm = require('./cap/bin/lib/cap-feature-map.cjs');
106
+ const d = require('./cap/bin/lib/cap-design.cjs');
107
+ const trace = require('./cap/bin/lib/cap-trace.cjs');
108
+ const featureId = process.argv[1];
109
+ // @cap-todo(ac:F-081/AC-4 iter:2) Migrated to {safe: true} opt-in to preserve CLI on duplicate-ID FEATURE-MAP.
110
+ // @cap-decision(F-081/iter2) Warn on parseError; continue with partial map for read-only display.
111
+ const map = fm.readFeatureMap(process.cwd(), undefined, { safe: true });
112
+ if (map && map.parseError) {
113
+ console.warn('cap: trace — duplicate feature ID detected, lookup uses partial map: ' + String(map.parseError.message).trim());
114
+ }
115
+ const feature = map.features.find(f => f.id === featureId);
116
+ if (!feature) process.exit(0);
117
+ const design = d.readDesignMd(process.cwd());
118
+ const designIdx = design ? d.parseDesignIds(design) : { byToken: {}, byComponent: {} };
119
+ const line = trace.formatDesignUsage(feature, designIdx);
120
+ if (line) console.log('Design-Usage: ' + line);
121
+ " '<FEATURE_ID>'
122
+ ```
123
+
124
+ ## Step 3: Suggest next action (only when not in --json mode)
125
+
126
+ Inspect the trace result and suggest one of:
127
+
128
+ - If `primary.role === 'inferred'` AND `allFiles.length > 1` -> "Designate the canonical file with `@cap-feature(feature:<id>, primary:true)` to suppress the heuristic warning."
129
+ - If `allFiles.length === 0` -> "No tags reference this AC. Add `@cap-todo(ac:<ref>)` at the implementation site, then re-run /cap:scan."
130
+ - If `callGraph.length === 0` AND `primary.file` is set -> "Primary file has no resolvable internal imports. The AC may be self-contained, or imports use dynamic require() / TS path aliases that the static walker cannot resolve."
131
+ - Otherwise -> "Trace looks complete."
132
+
133
+ </process>
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: cap:ui
3
+ description: CAP-UI local read-only server (--serve, default) or standalone HTML snapshot (--share) of Feature Map, Memory, Threads and DESIGN.md. Optional --editable unlocks DESIGN.md write endpoints (F-068). Zero deps. Node-builtin http + SSE only.
4
+ argument-hint: "[--serve | --share] [--port N] [--editable]"
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ ---
11
+
12
+ <!-- @cap-context CAP F-065 /cap:ui command — orchestrates cap-ui.cjs. No agent is spawned: this is deterministic infrastructure with no wizard. -->
13
+ <!-- @cap-context CAP F-068 adds a --editable flag to --serve. It unlocks a DESIGN.md-only write surface (color picker, spacing sliders, component variants). FEATURE-MAP.md and Memory stay read-only even in edit mode. -->
14
+ <!-- @cap-decision Command layer parses flags and calls cap-ui.cjs directly. No Task()/agent spawn — there is nothing conversational here. -->
15
+ <!-- @cap-decision --serve is the default because developers running /cap:ui interactively expect a browser view, not a snapshot-only export. -->
16
+ <!-- @cap-decision(F-068) --editable is opt-in. Default --serve stays fully read-only to match F-065/AC-5. --share never embeds the edit UI (no server to write to). -->
17
+ <!-- @cap-constraint Zero external deps. Do not introduce npm packages at any point in this command. -->
18
+ <!-- @cap-constraint SECURITY: --editable exposes DESIGN.md PUT/DELETE endpoints on localhost. Do NOT use on shared hosts, tunnels (ngrok), or anywhere the loopback is reachable by other users. -->
19
+
20
+ <!-- @cap-feature(feature:F-065) CAP-UI Core — Local Server + Static Export -->
21
+ <!-- @cap-feature(feature:F-068) CAP-UI Visual Design Editor — DESIGN.md-only edit surface -->
22
+
23
+ <objective>
24
+ <!-- @cap-todo(ac:F-065/AC-1) /cap:ui --serve starts local Node http server on configurable port (default 4747), zero deps, node builtins only. -->
25
+ <!-- @cap-todo(ac:F-065/AC-2) The served UI renders Feature-Map + Memory + Threads + DESIGN.md as a readable HTML view. -->
26
+ <!-- @cap-todo(ac:F-065/AC-3) File-watcher observes FEATURE-MAP.md, DESIGN.md, .cap/memory/, .cap/SESSION.json → UI refreshes via SSE. -->
27
+ <!-- @cap-todo(ac:F-065/AC-4) /cap:ui --share generates standalone HTML snapshot at .cap/ui/snapshot.html with inline CSS/JS. -->
28
+ <!-- @cap-todo(ac:F-065/AC-5) UI is read-only for Feature-Map and Memory; DESIGN.md edit capability is introduced in F-068. -->
29
+ <!-- @cap-todo(ac:F-065/AC-6) Server logs all events (start, SSE connect, file changes) on stdout with ISO timestamps. -->
30
+
31
+ Runs one of two flows:
32
+ - `--serve` (default) — starts a local HTTP server on port 4747 (or `--port N`) that renders the Feature Map, Memory, Threads, and DESIGN.md. Broadcasts file changes to the browser via Server-Sent Events.
33
+ - `--share` — writes a standalone HTML snapshot to `.cap/ui/snapshot.html` with inline CSS/JS, safe to share via PR/Slack.
34
+
35
+ Optional flags:
36
+ - `--editable` (F-068, only valid with `--serve`) — unlocks the DESIGN.md Visual Editor:
37
+ - Color-pickers for each DT-NNN color token
38
+ - Range sliders for spacing + typography scales
39
+ - Variant add/remove per DC-NNN component
40
+ - Edits are atomic (temp+rename), Git-friendly (single-line diffs), and restricted to DESIGN.md.
41
+ - FEATURE-MAP.md and Memory remain read-only even in edit mode.
42
+ - **Security**: write endpoints are exposed on localhost. Do not use on shared hosts, tunnels, or multi-user machines.
43
+
44
+ **Key guarantees:**
45
+ - Zero runtime dependencies. Only `node:` builtins (`http`, `fs`, `path`, `url`, `os`).
46
+ - Read-only by default: no POST/PUT/DELETE routes, no forms, no edit endpoints without `--editable` (F-065/AC-5).
47
+ - `--editable` only unlocks `/api/design/*` PUT/DELETE; FEATURE-MAP + Memory always 405 on writes (F-068/AC-6).
48
+ - SSE-only for live updates (no WebSockets).
49
+ - Port auto-increments up to +10 if the default is taken; fails loudly otherwise.
50
+ - `--share` snapshot contains no external URLs (no Google Fonts, no CDN, no fetch calls) — safe for offline sharing.
51
+ - `--share` NEVER embeds the edit UI, even when run in a session where `--editable` was set — snapshots are static and have no server to write against.
52
+
53
+ </objective>
54
+
55
+ <context>
56
+ $ARGUMENTS
57
+
58
+ @FEATURE-MAP.md
59
+ </context>
60
+
61
+ <process>
62
+
63
+ ## Step 0: Parse flags
64
+
65
+ <!-- @cap-todo(ac:F-065/AC-1) Parse --serve (default), --share, --port N from $ARGUMENTS. -->
66
+ <!-- @cap-todo(ac:F-068/AC-1) Parse --editable flag. Only valid with --serve; --share ignores it. -->
67
+
68
+ Inspect `$ARGUMENTS`:
69
+ - `--share` — set `mode = "share"`
70
+ - `--serve` — set `mode = "serve"`
71
+ - `--port N` — capture `port` (integer)
72
+ - `--editable` — set `editable = true` (ignored with `--share`)
73
+ - If no mode flag, default to `mode = "serve"`
74
+
75
+ Log: `cap:ui | mode: {mode}`{ " | port: " + port if mode === 'serve' && port }{ " | editable" if editable }
76
+
77
+ ## Step 1: Dispatch by mode
78
+
79
+ ### Step 1a: --share (snapshot flow)
80
+
81
+ <!-- @cap-todo(ac:F-065/AC-4) --share writes .cap/ui/snapshot.html via createSnapshot(). -->
82
+
83
+ ```bash
84
+ node -e "
85
+ const ui = require('./cap/bin/lib/cap-ui.cjs');
86
+ const out = ui.createSnapshot({ projectRoot: process.cwd() });
87
+ console.log(JSON.stringify(out));
88
+ "
89
+ ```
90
+
91
+ Report:
92
+
93
+ ```
94
+ cap:ui --share complete.
95
+
96
+ Snapshot: .cap/ui/snapshot.html
97
+ Bytes: {bytes}
98
+
99
+ Next steps:
100
+ - Open .cap/ui/snapshot.html in any browser (no server required).
101
+ - Share via PR comment / Slack DM — inline CSS/JS, no external fetch.
102
+ - Re-run /cap:ui --share to refresh.
103
+ ```
104
+
105
+ Stop here. Do not run Step 1b.
106
+
107
+ ### Step 1b: --serve (live server flow)
108
+
109
+ <!-- @cap-todo(ac:F-065/AC-1) --serve starts the local HTTP server. -->
110
+ <!-- @cap-todo(ac:F-065/AC-3) File watcher attached, SSE broadcasts change events to browser clients. -->
111
+ <!-- @cap-todo(ac:F-065/AC-6) Every server event is logged to stdout via cap-ui.logEvent. -->
112
+
113
+ Start the server in the foreground and print the URL. The server blocks until the user hits Ctrl+C (SIGINT).
114
+
115
+ ```bash
116
+ node -e "
117
+ const ui = require('./cap/bin/lib/cap-ui.cjs');
118
+ const port = {PORT_OR_DEFAULT};
119
+ const editable = {EDITABLE};
120
+ (async function(){
121
+ const { url, port: actual, stop } = await ui.startServer({ projectRoot: process.cwd(), port, editable });
122
+ console.log('cap:ui listening on ' + url + ' (port ' + actual + ')' + (editable ? ' [EDITABLE — DESIGN.md writes enabled]' : ''));
123
+ console.log('Ctrl+C to stop.');
124
+ process.on('SIGINT', async function(){
125
+ console.log('\\ncap:ui stopping…');
126
+ await stop();
127
+ process.exit(0);
128
+ });
129
+ })().catch(function(err){ console.error('cap:ui server failed:', err.message); process.exit(1); });
130
+ "
131
+ ```
132
+
133
+ Final report appears only after the user stops the server (Ctrl+C):
134
+
135
+ ```
136
+ cap:ui --serve stopped.
137
+ Port: {actual_port}
138
+ Session saved: .cap/SESSION.json (lastCommand updated)
139
+ ```
140
+
141
+ ## Step 2: Update session state (both modes, fire-and-forget)
142
+
143
+ <!-- @cap-decision Session write happens after the main action so a failing --serve still reports the attempt. -->
144
+
145
+ ```bash
146
+ node -e "
147
+ const session = require('./cap/bin/lib/cap-session.cjs');
148
+ session.updateSession(process.cwd(), {
149
+ lastCommand: '/cap:ui',
150
+ lastCommandTimestamp: new Date().toISOString(),
151
+ step: 'ui-{mode}'
152
+ });
153
+ "
154
+ ```
155
+
156
+ </process>
157
+
158
+ ## Notes
159
+
160
+ - **No agent is spawned.** cap:ui is pure infrastructure — no LLM call is required.
161
+ - **Mind-Map (F-066), Thread Navigator (F-067), DESIGN.md editor (F-068)** are all shipped.
162
+ - **Port conflicts**: if 4747 is taken, the server auto-tries 4748, 4749, …, up to 4757; then fails with a clear error.
163
+ - **File watcher caveats**: `fs.watch` is platform-specific. Linux fires multiple events per write (inotify); macOS coalesces via FSEvents. A 100ms debounce smooths the difference.
164
+ - **Read-only guarantee (default)**: the HTML has no `<form>`, no POST targets, and the server rejects non-GET/HEAD methods with 405. Only `--editable` unlocks PUT/DELETE on `/api/design/*`.
165
+ - **Edit scope (F-068/AC-6)**: `--editable` is strictly DESIGN.md. FEATURE-MAP.md and Memory endpoints always respond 405 on writes — collaboration there stays Git-based.
166
+ - **Atomic writes (F-068/AC-5)**: each edit writes a temp file and renames it over DESIGN.md, so a crashed process never leaves a truncated file.
167
+ - **Path-traversal guard (F-068)**: `createSnapshot(outputPath)` now refuses paths that escape the project root; the same guard gates DESIGN.md edits.
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ // @cap-feature(feature:F-009) Hooks System — background update checker (SessionStart hook)
3
+ // cap-hook-version: {{CAP_VERSION}}
4
+ // Check for CAP updates in background, write result to cache
5
+ // Called by SessionStart hook - runs once per session
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const os = require('os');
10
+ const { spawn } = require('child_process');
11
+
12
+ const homeDir = os.homedir();
13
+ const cwd = process.cwd();
14
+
15
+ // Detect runtime config directory (supports Claude, OpenCode, Gemini)
16
+ // Respects CLAUDE_CONFIG_DIR for custom config directory setups
17
+ function detectConfigDir(baseDir) {
18
+ // Check env override first (supports multi-account setups)
19
+ const envDir = process.env.CLAUDE_CONFIG_DIR;
20
+ if (envDir && fs.existsSync(path.join(envDir, 'cap', 'VERSION'))) {
21
+ return envDir;
22
+ }
23
+ for (const dir of ['.config/opencode', '.opencode', '.gemini', '.claude']) {
24
+ if (fs.existsSync(path.join(baseDir, dir, 'cap', 'VERSION'))) {
25
+ return path.join(baseDir, dir);
26
+ }
27
+ }
28
+ return envDir || path.join(baseDir, '.claude');
29
+ }
30
+
31
+ const globalConfigDir = detectConfigDir(homeDir);
32
+ const projectConfigDir = detectConfigDir(cwd);
33
+ const cacheDir = path.join(globalConfigDir, 'cache');
34
+ const cacheFile = path.join(cacheDir, 'cap-update-check.json');
35
+
36
+ // VERSION file locations (check project first, then global)
37
+ const projectVersionFile = path.join(projectConfigDir, 'cap', 'VERSION');
38
+ const globalVersionFile = path.join(globalConfigDir, 'cap', 'VERSION');
39
+
40
+ // Ensure cache directory exists
41
+ if (!fs.existsSync(cacheDir)) {
42
+ fs.mkdirSync(cacheDir, { recursive: true });
43
+ }
44
+
45
+ // Run check in background (spawn background process, windowsHide prevents console flash)
46
+ const child = spawn(process.execPath, ['-e', `
47
+ const fs = require('fs');
48
+ const path = require('path');
49
+ const { execSync } = require('child_process');
50
+
51
+ const cacheFile = ${JSON.stringify(cacheFile)};
52
+ const projectVersionFile = ${JSON.stringify(projectVersionFile)};
53
+ const globalVersionFile = ${JSON.stringify(globalVersionFile)};
54
+
55
+ // Check project directory first (local install), then global
56
+ let installed = '0.0.0';
57
+ let configDir = '';
58
+ try {
59
+ if (fs.existsSync(projectVersionFile)) {
60
+ installed = fs.readFileSync(projectVersionFile, 'utf8').trim();
61
+ configDir = path.dirname(path.dirname(projectVersionFile));
62
+ } else if (fs.existsSync(globalVersionFile)) {
63
+ installed = fs.readFileSync(globalVersionFile, 'utf8').trim();
64
+ configDir = path.dirname(path.dirname(globalVersionFile));
65
+ }
66
+ } catch (e) {}
67
+
68
+ // Check for stale hooks — compare hook version headers against installed VERSION
69
+ // Hooks live inside cap/hooks/, not configDir/hooks/
70
+ let staleHooks = [];
71
+ if (configDir) {
72
+ const hooksDir = path.join(configDir, 'cap', 'hooks');
73
+ try {
74
+ if (fs.existsSync(hooksDir)) {
75
+ const hookFiles = fs.readdirSync(hooksDir).filter(f => (f.startsWith('gsd-') || f.startsWith('cap-')) && f.endsWith('.js'));
76
+ for (const hookFile of hookFiles) {
77
+ try {
78
+ const content = fs.readFileSync(path.join(hooksDir, hookFile), 'utf8');
79
+ const versionMatch = content.match(/\\/\\/ (?:gsd|cap)-hook-version:\\s*(.+)/);
80
+ if (versionMatch) {
81
+ const hookVersion = versionMatch[1].trim();
82
+ if (hookVersion !== installed && !hookVersion.includes('{{')) {
83
+ staleHooks.push({ file: hookFile, hookVersion, installedVersion: installed });
84
+ }
85
+ } else {
86
+ // No version header at all — definitely stale (pre-version-tracking)
87
+ staleHooks.push({ file: hookFile, hookVersion: 'unknown', installedVersion: installed });
88
+ }
89
+ } catch (e) {}
90
+ }
91
+ }
92
+ } catch (e) {}
93
+ }
94
+
95
+ let latest = null;
96
+ try {
97
+ latest = execSync('npm view code-as-plan version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
98
+ } catch (e) {}
99
+
100
+ const result = {
101
+ update_available: latest && installed !== latest,
102
+ installed,
103
+ latest: latest || 'unknown',
104
+ checked: Math.floor(Date.now() / 1000),
105
+ stale_hooks: staleHooks.length > 0 ? staleHooks : undefined
106
+ };
107
+
108
+ fs.writeFileSync(cacheFile, JSON.stringify(result));
109
+ `], {
110
+ stdio: 'ignore',
111
+ windowsHide: true,
112
+ detached: true // Required on Windows for proper process detachment
113
+ });
114
+
115
+ child.unref();
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ // @cap-feature(feature:F-009) Hooks System — context window monitor (PostToolUse hook)
3
+ // cap-hook-version: {{CAP_VERSION}}
4
+ /**
5
+ * Context Monitor - PostToolUse/AfterTool hook (Gemini uses AfterTool)
6
+ *
7
+ * Reads context metrics from the statusline bridge file and injects
8
+ * advisory hints when context usage is high. This makes the AGENT aware of
9
+ * context limits (the statusline only shows the user).
10
+ *
11
+ * How it works:
12
+ * 1. The statusline hook writes metrics to /tmp/claude-ctx-{session_id}.json
13
+ * 2. This hook reads those metrics after each tool use
14
+ * 3. When remaining context drops below thresholds, it injects an advisory
15
+ * hint as additionalContext, which the agent sees in its conversation
16
+ *
17
+ * Behavior changes (vs. earlier revisions):
18
+ * - Tonality is **advisory**, not imperative. Messages no longer say
19
+ * "Inform the user…" — they say "Hinweis (vom CAP-Framework, vom
20
+ * User-Prompt unabhängig): … Der Agent kann den User informieren falls
21
+ * relevant für die Aufgabe." This avoids overriding user preferences
22
+ * such as "terse responses, no summaries".
23
+ * - Warning threshold lowered from 35% → 30% to reduce early warnings;
24
+ * focus is on the truly critical 25% escalation.
25
+ * - New ENV `CAP_DISABLE_CONTEXT_MONITOR=1` silences the hook entirely
26
+ * (for power users who don't want any advisory injection).
27
+ *
28
+ * Thresholds:
29
+ * WARNING (remaining <= 30%): advisory hint, agent decides whether to surface
30
+ * CRITICAL (remaining <= 25%): stronger advisory, agent decides whether to surface
31
+ *
32
+ * Debounce: 5 tool uses between warnings to avoid spam.
33
+ * Severity escalation bypasses debounce (WARNING -> CRITICAL fires immediately).
34
+ */
35
+
36
+ const fs = require('fs');
37
+ const os = require('os');
38
+ const path = require('path');
39
+
40
+ const WARNING_THRESHOLD = 30; // remaining_percentage <= 30% (was 35%)
41
+ const CRITICAL_THRESHOLD = 25; // remaining_percentage <= 25%
42
+ const STALE_SECONDS = 60; // ignore metrics older than 60s
43
+ const DEBOUNCE_CALLS = 5; // min tool uses between warnings
44
+
45
+ // Power-user kill switch: if set, hook is fully silent regardless of context state.
46
+ if (process.env.CAP_DISABLE_CONTEXT_MONITOR === '1' ||
47
+ process.env.CAP_DISABLE_CONTEXT_MONITOR === 'true') {
48
+ process.exit(0);
49
+ }
50
+
51
+ let input = '';
52
+ // Timeout guard: if stdin doesn't close within 10s (e.g. pipe issues on
53
+ // Windows/Git Bash, or slow Claude Code piping during large outputs),
54
+ // exit silently instead of hanging until Claude Code kills the process
55
+ // and reports "hook error". See #775, #1162.
56
+ const stdinTimeout = setTimeout(() => process.exit(0), 10000);
57
+ process.stdin.setEncoding('utf8');
58
+ process.stdin.on('data', chunk => input += chunk);
59
+ process.stdin.on('end', () => {
60
+ clearTimeout(stdinTimeout);
61
+ try {
62
+ const data = JSON.parse(input);
63
+ const sessionId = data.session_id;
64
+
65
+ if (!sessionId) {
66
+ process.exit(0);
67
+ }
68
+
69
+ // Check if context warnings are disabled via config
70
+ const cwd = data.cwd || process.cwd();
71
+ const configPath = path.join(cwd, '.planning', 'config.json');
72
+ if (fs.existsSync(configPath)) {
73
+ try {
74
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
75
+ if (config.hooks?.context_warnings === false) {
76
+ process.exit(0);
77
+ }
78
+ } catch (e) {
79
+ // Ignore config parse errors
80
+ }
81
+ }
82
+
83
+ const tmpDir = os.tmpdir();
84
+ const metricsPath = path.join(tmpDir, `claude-ctx-${sessionId}.json`);
85
+
86
+ // If no metrics file, this is a subagent or fresh session -- exit silently
87
+ if (!fs.existsSync(metricsPath)) {
88
+ process.exit(0);
89
+ }
90
+
91
+ const metrics = JSON.parse(fs.readFileSync(metricsPath, 'utf8'));
92
+ const now = Math.floor(Date.now() / 1000);
93
+
94
+ // Ignore stale metrics
95
+ if (metrics.timestamp && (now - metrics.timestamp) > STALE_SECONDS) {
96
+ process.exit(0);
97
+ }
98
+
99
+ const remaining = metrics.remaining_percentage;
100
+ const usedPct = metrics.used_pct;
101
+
102
+ // No warning needed
103
+ if (remaining > WARNING_THRESHOLD) {
104
+ process.exit(0);
105
+ }
106
+
107
+ // Debounce: check if we warned recently
108
+ const warnPath = path.join(tmpDir, `claude-ctx-${sessionId}-warned.json`);
109
+ let warnData = { callsSinceWarn: 0, lastLevel: null };
110
+ let firstWarn = true;
111
+
112
+ if (fs.existsSync(warnPath)) {
113
+ try {
114
+ warnData = JSON.parse(fs.readFileSync(warnPath, 'utf8'));
115
+ firstWarn = false;
116
+ } catch (e) {
117
+ // Corrupted file, reset
118
+ }
119
+ }
120
+
121
+ warnData.callsSinceWarn = (warnData.callsSinceWarn || 0) + 1;
122
+
123
+ const isCritical = remaining <= CRITICAL_THRESHOLD;
124
+ const currentLevel = isCritical ? 'critical' : 'warning';
125
+
126
+ // Emit immediately on first warning, then debounce subsequent ones
127
+ // Severity escalation (WARNING -> CRITICAL) bypasses debounce
128
+ const severityEscalated = currentLevel === 'critical' && warnData.lastLevel === 'warning';
129
+ if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) {
130
+ // Update counter and exit without warning
131
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
132
+ process.exit(0);
133
+ }
134
+
135
+ // Reset debounce counter
136
+ warnData.callsSinceWarn = 0;
137
+ warnData.lastLevel = currentLevel;
138
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
139
+
140
+ // Detect if GSD is active (has .planning/STATE.md in working directory)
141
+ const isGsdActive = fs.existsSync(path.join(cwd, '.planning', 'STATE.md'));
142
+
143
+ // Build advisory message (no imperative commands — see #884).
144
+ // The framework-prefix makes it explicit that this is metadata
145
+ // independent of the user prompt, so user preferences like
146
+ // "terse responses" are not violated by the agent itself.
147
+ const PREFIX = 'Hinweis (vom CAP-Framework, vom User-Prompt unabhängig): ';
148
+ const SUFFIX = ' Der Agent kann den User informieren falls relevant für die Aufgabe.';
149
+
150
+ let message;
151
+ if (isCritical) {
152
+ message = isGsdActive
153
+ ? `${PREFIX}CONTEXT CRITICAL — Auslastung bei ${usedPct}%, verbleibend ${remaining}%. ` +
154
+ 'Context ist nahezu erschöpft. GSD-State ist bereits in STATE.md getrackt; ' +
155
+ 'es ist nicht nötig, autonom Handoff-Dateien zu schreiben oder neue komplexe Arbeit zu starten.' +
156
+ SUFFIX
157
+ : `${PREFIX}CONTEXT CRITICAL — Auslastung bei ${usedPct}%, verbleibend ${remaining}%. ` +
158
+ 'Context ist nahezu erschöpft. Autonomes Speichern von State oder Handoff-Dateien ' +
159
+ 'ist nicht erforderlich, sofern der User nicht ausdrücklich danach fragt.' +
160
+ SUFFIX;
161
+ } else {
162
+ message = isGsdActive
163
+ ? `${PREFIX}CONTEXT WARNING — Auslastung bei ${usedPct}%, verbleibend ${remaining}%. ` +
164
+ 'Context-Budget wird knapp. Größere neue Arbeit zwischen definierten Plan-Schritten ' +
165
+ 'ist günstig zu vermeiden.' +
166
+ SUFFIX
167
+ : `${PREFIX}CONTEXT WARNING — Auslastung bei ${usedPct}%, verbleibend ${remaining}%. ` +
168
+ 'Context-Budget wird knapp. Unnötige Exploration oder das Anstoßen neuer komplexer ' +
169
+ 'Arbeit ist günstig zu vermeiden.' +
170
+ SUFFIX;
171
+ }
172
+
173
+ const output = {
174
+ hookSpecificOutput: {
175
+ hookEventName: process.env.GEMINI_API_KEY ? "AfterTool" : "PostToolUse",
176
+ additionalContext: message
177
+ }
178
+ };
179
+
180
+ process.stdout.write(JSON.stringify(output));
181
+ } catch (e) {
182
+ // Silent fail -- never block tool execution
183
+ process.exit(0);
184
+ }
185
+ });