rcf-lite 0.0.1 → 0.7.1

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 (342) hide show
  1. package/CHANGELOG.md +288 -0
  2. package/LICENSE +202 -0
  3. package/README.md +92 -4
  4. package/bin/rcf-verify.js +122 -0
  5. package/bin/rcf.js +174 -0
  6. package/bin/view-supervisor-child.mjs +14 -0
  7. package/fixtures/canary-manifest.json +103 -0
  8. package/guidance/README.md +25 -0
  9. package/guidance/build-cycle-playbook.md +492 -0
  10. package/guidance/build-cycle.md +40 -0
  11. package/guidance/document-model.md +45 -0
  12. package/guidance/elicitation-playbook.md +442 -0
  13. package/guidance/harness-template.md +246 -0
  14. package/guidance/managed/README.md +63 -0
  15. package/guidance/managed/agent-instructions-block.hash +1 -0
  16. package/guidance/managed/agent-instructions-block.md +220 -0
  17. package/guidance/managed/legacy-fragment-hashes.json +22 -0
  18. package/guidance/manifest.json +21 -0
  19. package/guidance/overview.md +48 -0
  20. package/guidance/persona-programme.md +44 -0
  21. package/package.json +69 -8
  22. package/rcf/adrs/adr-001.json +25 -0
  23. package/rcf/adrs/adr-002.json +25 -0
  24. package/rcf/adrs/adr-003.json +25 -0
  25. package/rcf/adrs/adr-004.json +20 -0
  26. package/rcf/adrs/adr-005.json +20 -0
  27. package/rcf/adrs/adr-006.json +25 -0
  28. package/rcf/adrs/adr-007.json +25 -0
  29. package/rcf/adrs/adr-008.json +25 -0
  30. package/rcf/adrs/adr-009.json +25 -0
  31. package/rcf/build-sequence.json +11 -0
  32. package/rcf/code-nodes/cn-001.json +14 -0
  33. package/rcf/code-nodes/cn-002.json +14 -0
  34. package/rcf/code-nodes/cn-003.json +15 -0
  35. package/rcf/code-nodes/cn-004.json +17 -0
  36. package/rcf/code-nodes/cn-005.json +19 -0
  37. package/rcf/code-nodes/cn-006.json +17 -0
  38. package/rcf/code-nodes/cn-007.json +16 -0
  39. package/rcf/code-nodes/cn-008.json +19 -0
  40. package/rcf/code-nodes/cn-009.json +16 -0
  41. package/rcf/code-nodes/cn-010.json +18 -0
  42. package/rcf/code-nodes/cn-011.json +18 -0
  43. package/rcf/code-nodes/cn-012.json +18 -0
  44. package/rcf/code-nodes/cn-013.json +19 -0
  45. package/rcf/code-nodes/cn-014.json +16 -0
  46. package/rcf/code-nodes/cn-015.json +16 -0
  47. package/rcf/code-nodes/cn-016.json +16 -0
  48. package/rcf/code-nodes/cn-017.json +16 -0
  49. package/rcf/code-nodes/cn-018.json +15 -0
  50. package/rcf/code-nodes/cn-019.json +16 -0
  51. package/rcf/code-nodes/cn-020.json +16 -0
  52. package/rcf/code-nodes/cn-021.json +16 -0
  53. package/rcf/code-nodes/cn-022.json +16 -0
  54. package/rcf/code-nodes/cn-023.json +16 -0
  55. package/rcf/code-nodes/cn-024.json +16 -0
  56. package/rcf/code-nodes/cn-025.json +16 -0
  57. package/rcf/code-nodes/cn-026.json +16 -0
  58. package/rcf/code-nodes/cn-027.json +16 -0
  59. package/rcf/code-nodes/cn-028.json +16 -0
  60. package/rcf/code-nodes/cn-029.json +19 -0
  61. package/rcf/code-nodes/cn-030.json +14 -0
  62. package/rcf/code-nodes/cn-031.json +14 -0
  63. package/rcf/code-nodes/cn-032.json +14 -0
  64. package/rcf/code-nodes/cn-033.json +14 -0
  65. package/rcf/code-nodes/cn-034.json +14 -0
  66. package/rcf/code-nodes/cn-035.json +14 -0
  67. package/rcf/code-nodes/cn-036.json +14 -0
  68. package/rcf/code-nodes/cn-037.json +14 -0
  69. package/rcf/code-nodes/cn-038.json +14 -0
  70. package/rcf/code-nodes/cn-039.json +14 -0
  71. package/rcf/code-nodes/cn-040.json +14 -0
  72. package/rcf/code-nodes/cn-041.json +14 -0
  73. package/rcf/code-nodes/cn-042.json +14 -0
  74. package/rcf/code-nodes/cn-043.json +14 -0
  75. package/rcf/code-nodes/cn-044.json +14 -0
  76. package/rcf/code-nodes/cn-045.json +14 -0
  77. package/rcf/code-nodes/cn-046.json +14 -0
  78. package/rcf/code-nodes/cn-047.json +14 -0
  79. package/rcf/code-nodes/cn-048.json +14 -0
  80. package/rcf/code-nodes/cn-049.json +14 -0
  81. package/rcf/code-nodes/cn-050.json +14 -0
  82. package/rcf/code-nodes/cn-051.json +14 -0
  83. package/rcf/code-nodes/cn-052.json +14 -0
  84. package/rcf/code-nodes/cn-053.json +14 -0
  85. package/rcf/code-nodes/cn-054.json +14 -0
  86. package/rcf/code-nodes/cn-055.json +14 -0
  87. package/rcf/code-nodes/cn-056.json +14 -0
  88. package/rcf/code-nodes/cn-057.json +14 -0
  89. package/rcf/fbs/fbs-001.json +49 -0
  90. package/rcf/fbs/fbs-002.json +42 -0
  91. package/rcf/fbs/fbs-003.json +37 -0
  92. package/rcf/fbs/fbs-004.json +39 -0
  93. package/rcf/fbs/fbs-005.json +38 -0
  94. package/rcf/fbs/fbs-006.json +48 -0
  95. package/rcf/fbs/fbs-007.json +39 -0
  96. package/rcf/fbs/fbs-008.json +40 -0
  97. package/rcf/fbs/fbs-009.json +36 -0
  98. package/rcf/fbs/fbs-010.json +41 -0
  99. package/rcf/fbs/fbs-011.json +36 -0
  100. package/rcf/fbs/fbs-012.json +46 -0
  101. package/rcf/fbs/fbs-013.json +42 -0
  102. package/rcf/fbs/fbs-014.json +49 -0
  103. package/rcf/fbs/fbs-015.json +32 -0
  104. package/rcf/manifest.json +17 -0
  105. package/rcf/prd.json +47 -0
  106. package/rcf/requirements/req-001.json +19 -0
  107. package/rcf/requirements/req-002.json +19 -0
  108. package/rcf/requirements/req-003.json +19 -0
  109. package/rcf/requirements/req-004.json +19 -0
  110. package/rcf/requirements/req-005.json +19 -0
  111. package/rcf/requirements/req-006.json +19 -0
  112. package/rcf/requirements/req-007.json +19 -0
  113. package/rcf/requirements/req-008.json +19 -0
  114. package/rcf/requirements/req-009.json +19 -0
  115. package/rcf/tacs/tac-001.json +45 -0
  116. package/rcf/tacs/tac-002.json +109 -0
  117. package/rcf/tacs/tac-003.json +40 -0
  118. package/rcf/tacs/tac-004.json +51 -0
  119. package/rcf/tacs/tac-005.json +52 -0
  120. package/rcf/tacs/tac-006.json +104 -0
  121. package/rcf/tacs/tac-007.json +38 -0
  122. package/rcf/tacs/tac-008.json +51 -0
  123. package/rcf/tad.json +51 -0
  124. package/rcf/test-suites/PENDING.md +23 -0
  125. package/rcf/test-suites/ts-001.json +38 -0
  126. package/rcf/test-suites/ts-002.json +38 -0
  127. package/rcf/test-suites/ts-003.json +43 -0
  128. package/rcf/test-suites/ts-004.json +44 -0
  129. package/rcf/test-suites/ts-005.json +30 -0
  130. package/rcf/test-suites/ts-006.json +36 -0
  131. package/rcf/test-suites/ts-007.json +43 -0
  132. package/rcf/test-suites/ts-008.json +37 -0
  133. package/rcf/test-suites/ts-009.json +38 -0
  134. package/rcf/test-suites/ts-010.json +38 -0
  135. package/rcf/test-suites/ts-011.json +44 -0
  136. package/rcf/test-suites/ts-012.json +36 -0
  137. package/rcf/test-suites/ts-013.json +38 -0
  138. package/rcf/test-suites/ts-014.json +38 -0
  139. package/rcf/test-suites/ts-015.json +38 -0
  140. package/rcf/test-suites/ts-016.json +37 -0
  141. package/rcf/test-suites/ts-017.json +38 -0
  142. package/rcf/test-suites/ts-018.json +38 -0
  143. package/rcf/test-suites/ts-019.json +37 -0
  144. package/rcf/test-suites/ts-020.json +46 -0
  145. package/rcf/test-suites/ts-021.json +46 -0
  146. package/rcf/test-suites/ts-022.json +46 -0
  147. package/rcf/test-suites/ts-023.json +46 -0
  148. package/rcf/test-suites/ts-024.json +46 -0
  149. package/rcf/test-suites/ts-025.json +52 -0
  150. package/rcf/user-stories/us-101.json +40 -0
  151. package/rcf/user-stories/us-102.json +40 -0
  152. package/rcf/user-stories/us-201.json +40 -0
  153. package/rcf/user-stories/us-202.json +40 -0
  154. package/rcf/user-stories/us-203.json +32 -0
  155. package/rcf/user-stories/us-301.json +40 -0
  156. package/rcf/user-stories/us-302.json +40 -0
  157. package/rcf/user-stories/us-303.json +40 -0
  158. package/rcf/user-stories/us-304.json +40 -0
  159. package/rcf/user-stories/us-401.json +40 -0
  160. package/rcf/user-stories/us-402.json +40 -0
  161. package/rcf/user-stories/us-403.json +40 -0
  162. package/rcf/user-stories/us-501.json +40 -0
  163. package/rcf/user-stories/us-502.json +40 -0
  164. package/rcf/user-stories/us-503.json +40 -0
  165. package/rcf/user-stories/us-601.json +40 -0
  166. package/rcf/user-stories/us-602.json +40 -0
  167. package/rcf/user-stories/us-701.json +40 -0
  168. package/rcf/user-stories/us-702.json +40 -0
  169. package/rcf/user-stories/us-801.json +49 -0
  170. package/rcf/user-stories/us-802.json +49 -0
  171. package/rcf/user-stories/us-803.json +49 -0
  172. package/rcf/user-stories/us-804.json +49 -0
  173. package/rcf/user-stories/us-805.json +49 -0
  174. package/rcf/user-stories/us-901.json +40 -0
  175. package/src/.gitkeep +0 -0
  176. package/src/browser-verify/auth-smoke.js +109 -0
  177. package/src/browser-verify/index.js +29 -0
  178. package/src/browser-verify/invariants.js +336 -0
  179. package/src/browser-verify/manifest-writer.js +189 -0
  180. package/src/browser-verify/runner.js +171 -0
  181. package/src/build/bundle.js +198 -0
  182. package/src/build/formatters/json.js +18 -0
  183. package/src/build/formatters/markdown.js +406 -0
  184. package/src/build/index.js +14 -0
  185. package/src/build/mark.js +177 -0
  186. package/src/build/queue.js +285 -0
  187. package/src/cli/browser-verify.js +231 -0
  188. package/src/cli/build.js +584 -0
  189. package/src/cli/coverage.js +219 -0
  190. package/src/cli/create.js +355 -0
  191. package/src/cli/delete.js +127 -0
  192. package/src/cli/design.js +353 -0
  193. package/src/cli/doctor.js +548 -0
  194. package/src/cli/fbs.js +171 -0
  195. package/src/cli/finalise.js +377 -0
  196. package/src/cli/guidance.js +206 -0
  197. package/src/cli/help.js +156 -0
  198. package/src/cli/impact.js +119 -0
  199. package/src/cli/init.js +282 -0
  200. package/src/cli/intake.js +153 -0
  201. package/src/cli/link.js +128 -0
  202. package/src/cli/mcp.js +160 -0
  203. package/src/cli/preflight.js +220 -0
  204. package/src/cli/read.js +162 -0
  205. package/src/cli/req-baseline.js +269 -0
  206. package/src/cli/req-classify.js +135 -0
  207. package/src/cli/review.js +295 -0
  208. package/src/cli/test-suite.js +216 -0
  209. package/src/cli/trace.js +172 -0
  210. package/src/cli/ui-baseline.js +292 -0
  211. package/src/cli/ui-classify.js +108 -0
  212. package/src/cli/update.js +197 -0
  213. package/src/cli/validate.js +168 -0
  214. package/src/cli/view.js +452 -0
  215. package/src/core/baseline-catalog/data/auth.json +42 -0
  216. package/src/core/baseline-catalog/data/http-api.json +42 -0
  217. package/src/core/baseline-catalog/data/notifications.json +33 -0
  218. package/src/core/baseline-catalog/data/persistence.json +33 -0
  219. package/src/core/baseline-catalog/data/web-ui.json +60 -0
  220. package/src/core/baseline-catalog/index.js +121 -0
  221. package/src/core/errors/index.js +167 -0
  222. package/src/core/fixtures/register-canary/canary-prompt-01.json +18 -0
  223. package/src/core/fixtures/register-canary/canary-prompt-02.json +21 -0
  224. package/src/core/fixtures/register-canary/canary-prompt-03.json +17 -0
  225. package/src/core/isolation/index.js +60 -0
  226. package/src/core/mcp/framing.js +103 -0
  227. package/src/core/mcp/index.js +8 -0
  228. package/src/core/mcp/server.js +228 -0
  229. package/src/core/patterns/register-canary.js +209 -0
  230. package/src/core/patterns/req-shapes.js +158 -0
  231. package/src/core/patterns/services.js +358 -0
  232. package/src/core/patterns/ui-shapes.js +166 -0
  233. package/src/core/store/cn-resolve.js +134 -0
  234. package/src/core/store/derive-deps.js +93 -0
  235. package/src/core/store/ids.js +78 -0
  236. package/src/core/store/index.js +20 -0
  237. package/src/core/store/init.js +255 -0
  238. package/src/core/store/loader.js +211 -0
  239. package/src/core/store/tp-resolve.js +176 -0
  240. package/src/core/store/validator.js +191 -0
  241. package/src/core/store/walker.js +898 -0
  242. package/src/core/store/writer.js +1849 -0
  243. package/src/design/index.js +11 -0
  244. package/src/design/writer.js +271 -0
  245. package/src/finalise/detect.js +129 -0
  246. package/src/finalise/index.js +17 -0
  247. package/src/finalise/ingest.js +119 -0
  248. package/src/finalise/install.js +119 -0
  249. package/src/finalise/ship-without-verified.js +131 -0
  250. package/src/finalise/spawn.js +84 -0
  251. package/src/intake/fidelity.js +105 -0
  252. package/src/intake/index.js +6 -0
  253. package/src/intake/manifest-writer.js +100 -0
  254. package/src/intake/orchestrator.js +138 -0
  255. package/src/intake/validate.js +80 -0
  256. package/src/mcp/map-errors.js +131 -0
  257. package/src/mcp/prompts.js +49 -0
  258. package/src/mcp/resources.js +244 -0
  259. package/src/mcp/tools.js +1204 -0
  260. package/src/preflight/design-shapes.js +185 -0
  261. package/src/preflight/index.js +90 -0
  262. package/src/preflight/manifest-writer.js +264 -0
  263. package/src/preflight/scanner.js +206 -0
  264. package/src/preflight/secrets.js +134 -0
  265. package/src/preflight/session.js +246 -0
  266. package/src/query/attestation.js +285 -0
  267. package/src/query/coverage.js +308 -0
  268. package/src/query/formatters/json.js +21 -0
  269. package/src/query/formatters/mermaid.js +209 -0
  270. package/src/query/formatters/table.js +203 -0
  271. package/src/query/impact.js +173 -0
  272. package/src/query/index.js +9 -0
  273. package/src/query/trace.js +345 -0
  274. package/src/register-canary/fixture-loader.js +87 -0
  275. package/src/register-canary/index.js +10 -0
  276. package/src/register-canary/record-writer.js +132 -0
  277. package/src/register-canary/runner.js +156 -0
  278. package/src/req-baseline/gate.js +86 -0
  279. package/src/req-baseline/index.js +27 -0
  280. package/src/req-baseline/open-candidates.js +143 -0
  281. package/src/req-baseline/opt-out.js +195 -0
  282. package/src/req-baseline/sweep.js +230 -0
  283. package/src/req-detection/classifier.js +181 -0
  284. package/src/req-detection/index.js +9 -0
  285. package/src/req-detection/persist.js +55 -0
  286. package/src/review/index.js +325 -0
  287. package/src/review/mutation.js +117 -0
  288. package/src/review/ui-baseline-drift.js +138 -0
  289. package/src/server/index.js +178 -0
  290. package/src/server/routes.js +110 -0
  291. package/src/server/sse.js +118 -0
  292. package/src/setup/agent-setup.js +362 -0
  293. package/src/setup/identity-seed.js +104 -0
  294. package/src/setup/knowledge-seed.js +123 -0
  295. package/src/setup/managed-block.js +193 -0
  296. package/src/setup/managed-gitignore.js +166 -0
  297. package/src/setup/managed-markers.js +49 -0
  298. package/src/ui-baseline/defaults.js +119 -0
  299. package/src/ui-baseline/index.js +25 -0
  300. package/src/ui-baseline/manifest-writer.js +282 -0
  301. package/src/ui-baseline/session.js +178 -0
  302. package/src/ui-detection/classifier.js +192 -0
  303. package/src/verify/chain/index.js +190 -0
  304. package/src/verify/cli/cleanup.js +61 -0
  305. package/src/verify/cli/help.js +56 -0
  306. package/src/verify/cli/mcp.js +98 -0
  307. package/src/verify/cli/provision.js +71 -0
  308. package/src/verify/cli/report.js +71 -0
  309. package/src/verify/cli/run.js +155 -0
  310. package/src/verify/engine/brief.js +87 -0
  311. package/src/verify/engine/index.js +177 -0
  312. package/src/verify/engine/launcher.js +307 -0
  313. package/src/verify/mcp/tools.js +107 -0
  314. package/src/verify/profile/index.js +146 -0
  315. package/src/verify/provision/index.js +256 -0
  316. package/src/verify/report/index.js +139 -0
  317. package/src/verify/report/renderer.js +118 -0
  318. package/src/verify/verdict/index.js +246 -0
  319. package/src/view/doc-renderers/adr.js +44 -0
  320. package/src/view/doc-renderers/build-sequence.js +40 -0
  321. package/src/view/doc-renderers/fbs.js +128 -0
  322. package/src/view/doc-renderers/helpers.js +159 -0
  323. package/src/view/doc-renderers/index.js +12 -0
  324. package/src/view/doc-renderers/prd.js +45 -0
  325. package/src/view/doc-renderers/req.js +43 -0
  326. package/src/view/doc-renderers/tac.js +38 -0
  327. package/src/view/doc-renderers/tad.js +74 -0
  328. package/src/view/doc-renderers/test-suite.js +45 -0
  329. package/src/view/doc-renderers/user-story.js +63 -0
  330. package/src/view/html-page.js +462 -0
  331. package/src/view/index.js +63 -0
  332. package/src/view/live-client.js +338 -0
  333. package/src/view/mermaid-diagram.js +178 -0
  334. package/src/view/style.css +735 -0
  335. package/src/view/tree-model.js +152 -0
  336. package/src/view/vendored/mermaid.min.js +2607 -0
  337. package/src/view-supervisor/index.js +26 -0
  338. package/src/view-supervisor/logs.js +32 -0
  339. package/src/view-supervisor/manifest-writer.js +178 -0
  340. package/src/view-supervisor/persist-until.js +85 -0
  341. package/src/view-supervisor/supervisor.js +276 -0
  342. package/src/watch/index.js +152 -0
@@ -0,0 +1,206 @@
1
+ // `rcf guidance [topic]` subcommand handler. Prints a guidance-pack
2
+ // document from the INSTALLED package to stdout, so the method is
3
+ // reachable from a consumer project on the CLI alone.
4
+ //
5
+ // Why this verb exists: the pack ships inside the package (package.json
6
+ // `files` includes `guidance`), but it is never copied into a consumer
7
+ // project. Guidance that pointed at a bare `guidance/<file>.md` path was
8
+ // therefore only reachable by someone sitting in the rcf-build-lite repo.
9
+ // MCP-wired harnesses reach the same content through `rcf://docs/<slug>`
10
+ // resources and the `rcf_*` prompts; this is the CLI-only route to it.
11
+ //
12
+ // Topics come from guidance/manifest.json - the same map the MCP layer
13
+ // reads - so there is one inventory and no duplication. Doc topics keep
14
+ // their manifest slug; prompt topics are addressed by filename minus
15
+ // extension (`build-cycle-playbook`, `elicitation-playbook`), which is
16
+ // the same slug convention.
17
+ //
18
+ // No project root is required: this reads the package, not the tree.
19
+
20
+ import { readFile } from 'node:fs/promises';
21
+ import { dirname, join, resolve } from 'node:path';
22
+ import { parseArgs } from 'node:util';
23
+ import { fileURLToPath } from 'node:url';
24
+
25
+ const here = dirname(fileURLToPath(import.meta.url));
26
+ const PACKAGE_ROOT = resolve(here, '..', '..');
27
+ const GUIDANCE_DIR = join(PACKAGE_ROOT, 'guidance');
28
+
29
+ const OPTION_SPEC = {
30
+ list: { type: 'boolean' },
31
+ path: { type: 'boolean' },
32
+ help: { type: 'boolean' },
33
+ };
34
+
35
+ export const HELP = `Usage: rcf guidance [topic] [options]
36
+
37
+ Print a guidance-pack document from the installed rcf-build-lite
38
+ package to stdout. The pack ships with the package and is never copied
39
+ into your project, so this verb is how a CLI-only agent reads the
40
+ method. MCP-wired harnesses can use the rcf://docs/<slug> resources and
41
+ the rcf_* prompts instead; the content is the same.
42
+
43
+ Topics (run 'rcf guidance' with no arguments to list them):
44
+ overview What RCF is and the document hierarchy
45
+ document-model Document kinds, fields and relationships
46
+ build-cycle The 5-stage build cycle contract
47
+ harness-template The agent-instructions fragment rcf init writes
48
+ build-cycle-playbook Deep method: running the build cycle well
49
+ elicitation-playbook Deep method: drawing a valid tree out of a
50
+ conversation
51
+ persona-programme Persona programme: the tail-interview template
52
+
53
+ Platform-invariant printer (Track C+D):
54
+ rcf guidance invariants Print the platform invariants block from the
55
+ manifest (currently: never-skip-RCF).
56
+
57
+ Options:
58
+ --list List the topics, one per line, and exit
59
+ --path Print the file's absolute path instead of
60
+ its contents
61
+ --help Print this help
62
+
63
+ Exit codes:
64
+ 0 success
65
+ 1 the pack could not be read from the installed package
66
+ 2 usage error (unknown topic, too many arguments)
67
+ `;
68
+
69
+ /**
70
+ * Read the guidance manifest and flatten it into an ordered topic list.
71
+ * Docs keep their manifest slug; prompts are addressed by filename
72
+ * minus extension. Both resolve to a file inside guidance/.
73
+ *
74
+ * @param {string} [guidanceDir]
75
+ * @returns {Promise<Array<{ slug: string, file: string, title: string }>>}
76
+ */
77
+ export async function listTopics(guidanceDir = GUIDANCE_DIR) {
78
+ const manifest = JSON.parse(await readFile(join(guidanceDir, 'manifest.json'), 'utf8'));
79
+ const topics = [];
80
+ for (const d of manifest.docs ?? []) {
81
+ topics.push({ slug: d.slug, file: d.file, title: d.title });
82
+ }
83
+ // Note: Track C+D §8's `rcf guidance invariants` is deliberately NOT
84
+ // registered as a listTopics entry. It is a virtual verb (no backing
85
+ // file; it formats the platformInvariants[] array from the manifest),
86
+ // handled by the `positionals[0] === 'invariants'` branch in main().
87
+ // Listing it here would break the byte-faithful topic-serving contract
88
+ // (topic → file bytes verbatim) that the pack-inventory tests lock.
89
+ for (const p of manifest.prompts ?? []) {
90
+ topics.push({
91
+ slug: p.file.replace(/\.md$/, ''),
92
+ file: p.file,
93
+ title: p.description ?? p.name,
94
+ });
95
+ }
96
+ return topics;
97
+ }
98
+
99
+ /**
100
+ * @param {string[]} argv - argv slice after `guidance`
101
+ * @param {object} [deps]
102
+ * @returns {Promise<number>}
103
+ */
104
+ export async function main(argv, deps = {}) {
105
+ const stdout = deps.stdout ?? process.stdout;
106
+ const stderr = deps.stderr ?? process.stderr;
107
+ const guidanceDir = deps.guidanceDir ?? GUIDANCE_DIR;
108
+
109
+ let parsed;
110
+ try {
111
+ parsed = parseArgs({ args: argv, options: OPTION_SPEC, allowPositionals: true, strict: true });
112
+ } catch (err) {
113
+ stderr.write(`[error] usage ${err.message}\n`);
114
+ stderr.write(HELP);
115
+ return 2;
116
+ }
117
+ const flags = parsed.values;
118
+ const positionals = parsed.positionals;
119
+ if (flags.help) { stdout.write(HELP); return 0; }
120
+ if (positionals.length > 1) {
121
+ stderr.write('[error] usage guidance: expected at most one <topic>\n');
122
+ stderr.write(HELP);
123
+ return 2;
124
+ }
125
+
126
+ let topics;
127
+ try {
128
+ topics = await listTopics(guidanceDir);
129
+ } catch (err) {
130
+ stderr.write(`[error] io guidance pack not readable at ${guidanceDir} (${err.message})\n`);
131
+ return 1;
132
+ }
133
+
134
+ // No topic named: list what is available. Terse when --list, so the
135
+ // output pipes cleanly; annotated otherwise, so a human sees titles.
136
+ if (positionals.length === 0) {
137
+ if (flags.list) {
138
+ stdout.write(`${topics.map((t) => t.slug).join('\n')}\n`);
139
+ return 0;
140
+ }
141
+ const width = Math.max(...topics.map((t) => t.slug.length));
142
+ const lines = topics.map((t) => ` ${t.slug.padEnd(width)} ${firstSentence(t.title)}`);
143
+ stdout.write(`Guidance topics (rcf guidance <topic> prints one):\n${lines.join('\n')}\n`);
144
+ return 0;
145
+ }
146
+
147
+ // Special virtual topic: `invariants` prints the platform-invariant
148
+ // list from the manifest, not a guidance file. `--path` on this topic
149
+ // resolves to the manifest itself.
150
+ if (positionals[0] === 'invariants') {
151
+ const manifestPath = join(guidanceDir, 'manifest.json');
152
+ if (flags.path) {
153
+ stdout.write(`${manifestPath}\n`);
154
+ return 0;
155
+ }
156
+ let invariants;
157
+ try {
158
+ const manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
159
+ invariants = Array.isArray(manifest?.platformInvariants) ? manifest.platformInvariants : [];
160
+ } catch (err) {
161
+ stderr.write(`[error] io guidance invariants: ${err.message}\n`);
162
+ return 1;
163
+ }
164
+ if (invariants.length === 0) {
165
+ stdout.write('no platform invariants declared in this build\n');
166
+ return 0;
167
+ }
168
+ const lines = [];
169
+ lines.push('# Platform invariants');
170
+ lines.push('');
171
+ for (const [i, inv] of invariants.entries()) {
172
+ lines.push(`## ${i + 1}. ${inv.title} (id: ${inv.id})`);
173
+ lines.push('');
174
+ lines.push(inv.text);
175
+ lines.push('');
176
+ }
177
+ stdout.write(lines.join('\n'));
178
+ return 0;
179
+ }
180
+
181
+ const topic = topics.find((t) => t.slug === positionals[0]);
182
+ if (!topic) {
183
+ stderr.write(`[error] usage guidance: no topic named '${positionals[0]}'. Known topics: ${topics.map((t) => t.slug).join(', ')}\n`);
184
+ return 2;
185
+ }
186
+ const filePath = join(guidanceDir, topic.file);
187
+ if (flags.path) {
188
+ stdout.write(`${filePath}\n`);
189
+ return 0;
190
+ }
191
+ let text;
192
+ try {
193
+ text = await readFile(filePath, 'utf8');
194
+ } catch (err) {
195
+ stderr.write(`[error] io guidance: ${topic.file} is mapped by the manifest but not readable (${err.message})\n`);
196
+ return 1;
197
+ }
198
+ stdout.write(text.endsWith('\n') ? text : `${text}\n`);
199
+ return 0;
200
+ }
201
+
202
+ /** First sentence of a title/description, for the one-line topic list. */
203
+ function firstSentence(text) {
204
+ const cut = String(text).split('. ')[0];
205
+ return cut.length > 88 ? `${cut.slice(0, 85)}...` : cut;
206
+ }
@@ -0,0 +1,156 @@
1
+ // Top-level and per-subcommand help. British English, ASCII hyphens
2
+ // only (Phase 4 §D17).
3
+ //
4
+ // Single-source rule: this module owns the TOP_LEVEL block and NOTHING
5
+ // else. Every per-subcommand block is imported from the module that
6
+ // implements the subcommand, so `rcf help <cmd>` and `rcf <cmd> --help`
7
+ // are the same string by construction. Do not reintroduce a local copy
8
+ // of a subcommand's help - `test/cli/help-parity.test.js` fails the
9
+ // moment the two paths differ. (This file previously kept private
10
+ // duplicates of nine blocks; every one of them had drifted stale, and
11
+ // `rcf help create` was hiding the `cn` kind outright.)
12
+
13
+ import { HELP as BUILD_HELP } from './build.js';
14
+ import { HELP as COVERAGE_HELP } from './coverage.js';
15
+ import { HELP as CREATE_HELP } from './create.js';
16
+ import { HELP as DELETE_HELP } from './delete.js';
17
+ import { HELP as DOCTOR_HELP } from './doctor.js';
18
+ import { HELP as FINALISE_HELP } from './finalise.js';
19
+ import { HELP as GUIDANCE_HELP } from './guidance.js';
20
+ import { HELP as IMPACT_HELP } from './impact.js';
21
+ import { HELP as INIT_HELP } from './init.js';
22
+ import { HELP as LINK_HELP, UNLINK_HELP } from './link.js';
23
+ import { HELP as MCP_HELP } from './mcp.js';
24
+ import { HELP as PREFLIGHT_HELP } from './preflight.js';
25
+ import { HELP as READ_HELP } from './read.js';
26
+ import { HELP as REVIEW_HELP } from './review.js';
27
+ import { HELP as FBS_HELP } from './fbs.js';
28
+ import { HELP as TEST_SUITE_HELP } from './test-suite.js';
29
+ import { HELP as TRACE_HELP } from './trace.js';
30
+ import { HELP as UI_CLASSIFY_HELP } from './ui-classify.js';
31
+ import { HELP as UI_BASELINE_HELP } from './ui-baseline.js';
32
+ import { HELP as DESIGN_HELP } from './design.js';
33
+ import { HELP as BROWSER_VERIFY_HELP } from './browser-verify.js';
34
+ import { HELP as UPDATE_HELP } from './update.js';
35
+ import { HELP as VALIDATE_HELP } from './validate.js';
36
+ import { HELP as VIEW_HELP } from './view.js';
37
+ // Track C+D (elicitation-and-playbook-hardening-0.7.0) verbs.
38
+ import { HELP as REQ_CLASSIFY_HELP } from './req-classify.js';
39
+ import { HELP as REQ_BASELINE_HELP } from './req-baseline.js';
40
+ import { HELP as INTAKE_HELP } from './intake.js';
41
+ // 0.7.1 packaging consolidation: `rcf verify <verb>` routes to the same
42
+ // help block the transition-grace `rcf-verify` alias bin uses.
43
+ import { TOP_LEVEL_HELP as VERIFY_HELP } from '../verify/cli/help.js';
44
+
45
+ const TOP_LEVEL = `Usage: rcf <command> [options]
46
+
47
+ Commands:
48
+ init Scaffold a new RCF project
49
+ view Render the tree as HTML (live server)
50
+ validate Walk the tree and report schema and reference issues
51
+ create <kind> Create a new document
52
+ read <id> Print a document's body to stdout
53
+ update <id> Patch fields on an existing document
54
+ delete <id> Delete a document (refuses on dependents by default)
55
+ link <us-id> Link a US to a TAC (appends to tacIds; idempotent)
56
+ unlink <us-id> Unlink a US from a TAC
57
+ coverage Structural coverage report (PRD -> REQ -> US -> AC -> TS -> TC)
58
+ trace <id> Walk the graph forward / back / both from an id
59
+ impact <id> Impact fan-out with per-node action label
60
+ build [fbs-id] Assemble FBS spec bundles and drive the build queue
61
+ finalise <fbs-id> Ship gate: verify the deployed app, then mark verified
62
+ doctor Diagnose init-hygiene drift (0.6.0 spec); --fix repairs
63
+ guidance [topic] Print a method document from the installed pack
64
+ mcp Serve the project over MCP (local stdio)
65
+ preflight Elicit pre-flight service-attestation + design-shape record
66
+ fbs <fbs-id> FBS-level verbs (depends-on)
67
+ test-suite <ts-id> Test-suite verbs (provenance, approve)
68
+ review <fbs-id> REVIEW-stage audit (test-theatre + mutation-sampling)
69
+ ui-classify <id> Run the UI-bearing classifier on one FBS
70
+ ui-baseline <verb> UI baseline: init | show | opt-out
71
+ design <fbs-id> Design substage: dispatch worker or hand-author artefacts
72
+ browser-verify <id> Stage 5 browser-verification gate for a UI-bearing FBS
73
+ req-classify <id> Rerun the REQ-shape classifier and write the block
74
+ req-baseline <verb> Baseline-AC sweep and opt-out ledger for classified REQs
75
+ intake Variable-fidelity intake stage (classify supplied artefacts)
76
+ verify <verb> Adversarial ship gate (run|report|provision|cleanup|mcp); the legacy rcf-verify bin is a transition alias
77
+ help [command] Print help for a command
78
+
79
+ Options:
80
+ --version Print the package version and exit
81
+ --help Print this help and exit
82
+
83
+ Exit codes:
84
+ 0 success
85
+ 1 IO / unexpected runtime failure
86
+ 2 usage error (bad flags, unknown id)
87
+ 3 schema validation or broken references
88
+ 4 refused (delete with dependents; other blocked mutations)
89
+
90
+ Run 'rcf help <command>' for command-specific help.
91
+ `;
92
+
93
+ // Every value here is an import. See the single-source rule at the top
94
+ // of this file before adding an entry.
95
+ const HELP_MAP = {
96
+ init: INIT_HELP,
97
+ validate: VALIDATE_HELP,
98
+ create: CREATE_HELP,
99
+ read: READ_HELP,
100
+ update: UPDATE_HELP,
101
+ delete: DELETE_HELP,
102
+ link: LINK_HELP,
103
+ unlink: UNLINK_HELP,
104
+ coverage: COVERAGE_HELP,
105
+ trace: TRACE_HELP,
106
+ impact: IMPACT_HELP,
107
+ build: BUILD_HELP,
108
+ finalise: FINALISE_HELP,
109
+ doctor: DOCTOR_HELP,
110
+ guidance: GUIDANCE_HELP,
111
+ mcp: MCP_HELP,
112
+ view: VIEW_HELP,
113
+ preflight: PREFLIGHT_HELP,
114
+ review: REVIEW_HELP,
115
+ fbs: FBS_HELP,
116
+ 'test-suite': TEST_SUITE_HELP,
117
+ 'ui-classify': UI_CLASSIFY_HELP,
118
+ 'ui-baseline': UI_BASELINE_HELP,
119
+ design: DESIGN_HELP,
120
+ 'browser-verify': BROWSER_VERIFY_HELP,
121
+ // Track C+D (elicitation-and-playbook-hardening-0.7.0) verbs.
122
+ 'req-classify': REQ_CLASSIFY_HELP,
123
+ 'req-baseline': REQ_BASELINE_HELP,
124
+ intake: INTAKE_HELP,
125
+ // 0.7.1 packaging consolidation: verify subcommand tree.
126
+ verify: VERIFY_HELP,
127
+ };
128
+
129
+ /**
130
+ * `rcf help [command]` handler. Positional after `help` names the
131
+ * subcommand; absent → top-level help.
132
+ *
133
+ * @param {string[]} argv - argv slice after `help`
134
+ * @param {object} [deps]
135
+ * @returns {Promise<number>}
136
+ */
137
+ export async function main(argv, deps = {}) {
138
+ const stdout = deps.stdout ?? process.stdout;
139
+ const stderr = deps.stderr ?? process.stderr;
140
+ if (argv.length === 0) {
141
+ stdout.write(TOP_LEVEL);
142
+ return 0;
143
+ }
144
+ const cmd = argv[0];
145
+ const body = HELP_MAP[cmd];
146
+ if (!body) {
147
+ stderr.write(`[error] usage no help topic named '${cmd}'\n`);
148
+ stdout.write(TOP_LEVEL);
149
+ return 2;
150
+ }
151
+ stdout.write(body);
152
+ return 0;
153
+ }
154
+
155
+ export const TOP_LEVEL_HELP = TOP_LEVEL;
156
+ export { HELP_MAP };
@@ -0,0 +1,119 @@
1
+ // `rcf impact <id>` subcommand handler. Reports "if this id changes,
2
+ // what should we re-verify / re-approve". Phase 5 §D7.
3
+ //
4
+ // Impact = trace-forward (down to test-leaves) + trace-back (up to
5
+ // root PRD / TAD / BS) + a labelled `actionNeeded` column per node,
6
+ // driven by static (kind, role) rules per D7.
7
+
8
+ import { parseArgs } from 'node:util';
9
+
10
+ import { formatErrors } from '#core/errors';
11
+ import { walkTree } from '#core/store';
12
+ import { findProjectRoot } from '../view/index.js';
13
+ import {
14
+ computeImpact,
15
+ formatJson,
16
+ formatMermaid,
17
+ formatTable,
18
+ kindOf,
19
+ } from '../query/index.js';
20
+
21
+ const OPTION_SPEC = {
22
+ format: { type: 'string' },
23
+ help: { type: 'boolean' },
24
+ // Phase 10 (X2 CodeNode bridge): extend the forward fan-out into the code
25
+ // layer (AC -> implementing Code Nodes -> transitively dependent CNs).
26
+ 'to-code': { type: 'boolean' },
27
+ };
28
+
29
+ export const HELP = `Usage: rcf impact <id> [options]
30
+
31
+ Report the fan-out for 'if <id> changes'. Emits ancestors (up to the
32
+ root PRD / TAD / BS) plus descendants (down to test-leaves) with a
33
+ per-node action label:
34
+ re-run test needs to be re-executed
35
+ re-verify suite ownership; check whether the change invalidates
36
+ re-approve the AC or PRD approval scope needs re-signing
37
+ review-scope US / REQ scope needs re-checking
38
+ review-arch TAD architectural context needs revisiting
39
+ review-plan BS build queue may need re-ordering
40
+ re-execute FBS delivery re-runs against updated AC
41
+ review-context TAC / ADR referenced by an affected FBS
42
+ re-verify-code code node reached from a spec change (--to-code)
43
+
44
+ Options:
45
+ --format <format> table (default) | json | mermaid
46
+ --to-code Extend the forward fan-out into Code Nodes
47
+ --help Print this help
48
+ `;
49
+
50
+ const VALID_FORMATS = new Set(['table', 'json', 'mermaid']);
51
+
52
+ /**
53
+ * @param {string[]} argv - argv slice after `impact`
54
+ * @param {object} [deps]
55
+ * @returns {Promise<number>}
56
+ */
57
+ export async function main(argv, deps = {}) {
58
+ const stdout = deps.stdout ?? process.stdout;
59
+ const stderr = deps.stderr ?? process.stderr;
60
+ const cwd = deps.cwd ?? process.cwd();
61
+
62
+ let parsed;
63
+ try {
64
+ parsed = parseArgs({ args: argv, options: OPTION_SPEC, allowPositionals: true, strict: true });
65
+ } catch (err) {
66
+ stderr.write(`[error] usage ${err.message}\n`);
67
+ stderr.write(HELP);
68
+ return 2;
69
+ }
70
+ const flags = parsed.values;
71
+ const positionals = parsed.positionals;
72
+ if (flags.help) { stdout.write(HELP); return 0; }
73
+
74
+ const format = flags.format ?? 'table';
75
+ if (!VALID_FORMATS.has(format)) {
76
+ stderr.write(`[error] usage impact: unknown --format ${format} (expected table | json | mermaid)\n`);
77
+ return 2;
78
+ }
79
+
80
+ if (positionals.length === 0) {
81
+ stderr.write('[error] usage impact: expected exactly one <id>\n');
82
+ stderr.write(HELP);
83
+ return 2;
84
+ }
85
+ if (positionals.length > 1) {
86
+ stderr.write('[error] usage impact: multiple positional ids are not supported\n');
87
+ return 2;
88
+ }
89
+ const id = positionals[0];
90
+ if (id.includes('*') || id.includes('?')) {
91
+ stderr.write('[error] usage impact: wildcard / glob positional not supported\n');
92
+ return 2;
93
+ }
94
+
95
+ const projectRoot = await findProjectRoot(cwd);
96
+ if (!projectRoot) {
97
+ stderr.write('[error] usage no project root found (no rcf/manifest.json in this directory or any ancestor). Run `npx rcf init` to create and wire a project.\n');
98
+ return 2;
99
+ }
100
+ const { tree, errors } = await walkTree({ projectRoot });
101
+ if (errors.length > 0) {
102
+ stderr.write(`${formatErrors(errors, { verbose: false, strict: false })}\n`);
103
+ return 3;
104
+ }
105
+
106
+ if (!kindOf(tree, id)) {
107
+ stderr.write(`[error] usage impact: id ${id} not found\n`);
108
+ return 2;
109
+ }
110
+
111
+ const result = computeImpact(tree, { id, includeCode: Boolean(flags['to-code']) });
112
+
113
+ let output;
114
+ if (format === 'json') output = formatJson(result, 'impact');
115
+ else if (format === 'mermaid') output = formatMermaid(result, 'impact');
116
+ else output = formatTable(result, 'impact');
117
+ stdout.write(output);
118
+ return 0;
119
+ }