rcf-lite 0.19.0 → 0.21.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 (263) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/bin/rcf.js +5 -0
  3. package/blueprints/application-admin-console/CHANGELOG.md +11 -0
  4. package/blueprints/application-admin-console/README.md +98 -0
  5. package/blueprints/application-admin-console/blueprint.json +226 -0
  6. package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +25 -0
  7. package/blueprints/application-admin-console/contributions/adrs/adr-2202-application-admin-console-baseline-roles.json +25 -0
  8. package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +20 -0
  9. package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +20 -0
  10. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +18 -0
  11. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +18 -0
  12. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +18 -0
  13. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +18 -0
  14. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +18 -0
  15. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +18 -0
  16. package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +40 -0
  17. package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +44 -0
  18. package/blueprints/application-admin-console/contributions/tacs/tac-2203-application-admin-console-permission-matrix.json +34 -0
  19. package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +40 -0
  20. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +34 -0
  21. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +34 -0
  22. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +34 -0
  23. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +28 -0
  24. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +34 -0
  25. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +27 -0
  26. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +27 -0
  27. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +27 -0
  28. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +33 -0
  29. package/blueprints/application-admin-console/docs/topics.md +35 -0
  30. package/blueprints/application-admin-console/guide/application-admin-console.md +29 -0
  31. package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +182 -0
  32. package/blueprints/application-api-rest/docs/topics.md +5 -0
  33. package/blueprints/application-charts/CHANGELOG.md +12 -0
  34. package/blueprints/application-charts/README.md +73 -0
  35. package/blueprints/application-charts/blueprint.json +26 -0
  36. package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +25 -0
  37. package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +25 -0
  38. package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.json +25 -0
  39. package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +15 -0
  40. package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +15 -0
  41. package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +15 -0
  42. package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +15 -0
  43. package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +42 -0
  44. package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +40 -0
  45. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +35 -0
  46. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +35 -0
  47. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +35 -0
  48. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +35 -0
  49. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +35 -0
  50. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +35 -0
  51. package/blueprints/application-charts/docs/topics.md +37 -0
  52. package/blueprints/application-charts/guide/application-charts.md +44 -0
  53. package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +191 -0
  54. package/blueprints/application-dashboard/CHANGELOG.md +10 -0
  55. package/blueprints/application-dashboard/README.md +102 -0
  56. package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +124 -0
  57. package/blueprints/application-dashboard/blueprint.json +29 -0
  58. package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +25 -0
  59. package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +25 -0
  60. package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.json +25 -0
  61. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-001.json +15 -0
  62. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +15 -0
  63. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +15 -0
  64. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +15 -0
  65. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +15 -0
  66. package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +47 -0
  67. package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +41 -0
  68. package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +35 -0
  69. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +35 -0
  70. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +35 -0
  71. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +35 -0
  72. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +35 -0
  73. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +35 -0
  74. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +35 -0
  75. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +35 -0
  76. package/blueprints/application-dashboard/docs/topics.md +43 -0
  77. package/blueprints/application-dashboard/guide/application-dashboard.md +48 -0
  78. package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +231 -0
  79. package/blueprints/application-datatable/CHANGELOG.md +8 -0
  80. package/blueprints/application-datatable/README.md +43 -0
  81. package/blueprints/application-datatable/blueprint.json +33 -0
  82. package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +25 -0
  83. package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +20 -0
  84. package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +20 -0
  85. package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +20 -0
  86. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-001.json +15 -0
  87. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +15 -0
  88. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +15 -0
  89. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +15 -0
  90. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +15 -0
  91. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +15 -0
  92. package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +50 -0
  93. package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +39 -0
  94. package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +28 -0
  95. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +44 -0
  96. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +44 -0
  97. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +44 -0
  98. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +44 -0
  99. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +44 -0
  100. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +44 -0
  101. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +44 -0
  102. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +44 -0
  103. package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +44 -0
  104. package/blueprints/application-datatable/docs/topics.md +35 -0
  105. package/blueprints/application-datatable/guide/application-datatable.md +38 -0
  106. package/blueprints/application-datatable/probe-packs/application-datatable.pack.mjs +240 -0
  107. package/blueprints/application-error-handling/docs/topics.md +5 -0
  108. package/blueprints/application-notifications-in-app/CHANGELOG.md +9 -0
  109. package/blueprints/application-notifications-in-app/README.md +80 -0
  110. package/blueprints/application-notifications-in-app/blueprint.json +30 -0
  111. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +25 -0
  112. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2102-application-notifications-in-app-toast-timeout-floor.json +25 -0
  113. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2103-application-notifications-in-app-retention-window.json +25 -0
  114. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +15 -0
  115. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +15 -0
  116. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +15 -0
  117. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +15 -0
  118. package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +15 -0
  119. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +46 -0
  120. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +52 -0
  121. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +40 -0
  122. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +35 -0
  123. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +35 -0
  124. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +35 -0
  125. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +35 -0
  126. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +35 -0
  127. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +26 -0
  128. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +26 -0
  129. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +26 -0
  130. package/blueprints/application-notifications-in-app/docs/topics.md +39 -0
  131. package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +47 -0
  132. package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +328 -0
  133. package/blueprints/application-spa/docs/topics.md +5 -0
  134. package/blueprints/delivery-ci-workflows/docs/topics.md +5 -0
  135. package/blueprints/deploy-cloudflare-workers/docs/topics.md +5 -0
  136. package/blueprints/email-smtp-resend/docs/topics.md +5 -0
  137. package/blueprints/observability-essentials/docs/topics.md +5 -0
  138. package/blueprints/observability-logging/CHANGELOG.md +5 -0
  139. package/blueprints/observability-logging/README.md +1 -1
  140. package/blueprints/observability-logging/blueprint.json +113 -21
  141. package/blueprints/observability-logging/docs/topics.md +5 -0
  142. package/blueprints/observability-probe-endpoints/docs/topics.md +5 -0
  143. package/blueprints/persistence-data-d1/docs/topics.md +5 -0
  144. package/blueprints/persistence-data-sqlite/docs/topics.md +5 -0
  145. package/blueprints/security-auth-clerk/CHANGELOG.md +5 -0
  146. package/blueprints/security-auth-clerk/blueprint.json +2 -1
  147. package/blueprints/security-auth-clerk/docs/topics.md +5 -0
  148. package/blueprints/security-auth-keycloak/CHANGELOG.md +5 -0
  149. package/blueprints/security-auth-keycloak/blueprint.json +2 -1
  150. package/blueprints/security-auth-keycloak/docs/topics.md +5 -0
  151. package/blueprints/security-auth-magic-link/CHANGELOG.md +5 -0
  152. package/blueprints/security-auth-magic-link/blueprint.json +2 -1
  153. package/blueprints/security-auth-magic-link/docs/topics.md +5 -0
  154. package/blueprints/security-auth-oauth2/CHANGELOG.md +5 -0
  155. package/blueprints/security-auth-oauth2/blueprint.json +2 -1
  156. package/blueprints/security-auth-oauth2/docs/topics.md +5 -0
  157. package/blueprints/security-secrets-management/docs/topics.md +5 -0
  158. package/fixtures/canary-manifest.json +9 -9
  159. package/package.json +2 -2
  160. package/rcf/code-nodes/cn-098.json +13 -0
  161. package/rcf/code-nodes/cn-099.json +13 -0
  162. package/rcf/code-nodes/cn-100.json +13 -0
  163. package/rcf/code-nodes/cn-101.json +13 -0
  164. package/rcf/code-nodes/cn-102.json +13 -0
  165. package/rcf/code-nodes/cn-103.json +13 -0
  166. package/rcf/code-nodes/cn-104.json +13 -0
  167. package/rcf/code-nodes/cn-105.json +13 -0
  168. package/rcf/code-nodes/cn-106.json +13 -0
  169. package/rcf/code-nodes/cn-107.json +14 -0
  170. package/rcf/code-nodes/cn-108.json +13 -0
  171. package/rcf/code-nodes/cn-109.json +12 -0
  172. package/rcf/code-nodes/cn-110.json +12 -0
  173. package/rcf/code-nodes/cn-111.json +14 -0
  174. package/rcf/code-nodes/cn-112.json +14 -0
  175. package/rcf/code-nodes/cn-113.json +12 -0
  176. package/rcf/code-nodes/cn-114.json +13 -0
  177. package/rcf/code-nodes/cn-115.json +13 -0
  178. package/rcf/code-nodes/cn-116.json +12 -0
  179. package/rcf/code-nodes/cn-117.json +13 -0
  180. package/rcf/code-nodes/cn-118.json +13 -0
  181. package/rcf/code-nodes/cn-119.json +13 -0
  182. package/rcf/code-nodes/cn-120.json +13 -0
  183. package/rcf/code-nodes/cn-121.json +12 -0
  184. package/rcf/code-nodes/cn-122.json +12 -0
  185. package/rcf/code-nodes/cn-123.json +13 -0
  186. package/rcf/code-nodes/cn-124.json +13 -0
  187. package/rcf/code-nodes/cn-125.json +13 -0
  188. package/rcf/code-nodes/cn-126.json +13 -0
  189. package/rcf/code-nodes/cn-127.json +12 -0
  190. package/rcf/code-nodes/cn-128.json +14 -0
  191. package/rcf/code-nodes/cn-129.json +14 -0
  192. package/rcf/code-nodes/cn-130.json +14 -0
  193. package/rcf/code-nodes/cn-131.json +15 -0
  194. package/rcf/code-nodes/cn-132.json +12 -0
  195. package/rcf/code-nodes/cn-133.json +13 -0
  196. package/rcf/evals/eval-001.json +55 -0
  197. package/rcf/fbs/fbs-035.json +18 -0
  198. package/rcf/fbs/fbs-036.json +22 -0
  199. package/rcf/fbs/fbs-037.json +19 -0
  200. package/rcf/fbs/fbs-038.json +19 -0
  201. package/rcf/fbs/fbs-039.json +21 -0
  202. package/rcf/fbs/fbs-040.json +20 -0
  203. package/rcf/fbs/fbs-041.json +13 -0
  204. package/rcf/fbs/fbs-042.json +13 -0
  205. package/rcf/requirements/req-016.json +37 -0
  206. package/rcf/requirements/req-017.json +18 -0
  207. package/rcf/requirements/req-018.json +18 -0
  208. package/rcf/requirements/req-019.json +38 -0
  209. package/rcf/requirements/req-020.json +13 -0
  210. package/rcf/requirements/req-021.json +13 -0
  211. package/rcf/requirements/req-022.json +13 -0
  212. package/rcf/requirements/req-023.json +14 -0
  213. package/rcf/test-suites/ts-045.json +46 -0
  214. package/rcf/test-suites/ts-046.json +78 -0
  215. package/rcf/test-suites/ts-047.json +54 -0
  216. package/rcf/test-suites/ts-048.json +54 -0
  217. package/rcf/test-suites/ts-049.json +70 -0
  218. package/rcf/test-suites/ts-050.json +69 -0
  219. package/rcf/test-suites/ts-051.json +22 -0
  220. package/rcf/test-suites/ts-052.json +20 -0
  221. package/rcf/user-stories/us-1601.json +37 -0
  222. package/rcf/user-stories/us-1701.json +56 -0
  223. package/rcf/user-stories/us-1801.json +40 -0
  224. package/rcf/user-stories/us-1901.json +40 -0
  225. package/rcf/user-stories/us-2001.json +50 -0
  226. package/rcf/user-stories/us-2101.json +45 -0
  227. package/rcf/user-stories/us-2201.json +60 -0
  228. package/rcf/user-stories/us-2301.json +51 -0
  229. package/releases/releases.yaml +20 -1
  230. package/src/blueprint/apply.js +98 -1
  231. package/src/blueprint/capabilities.js +318 -0
  232. package/src/blueprint/loader.js +247 -0
  233. package/src/browser-verify/boot.js +180 -0
  234. package/src/browser-verify/index.js +13 -0
  235. package/src/browser-verify/manifest-writer.js +31 -6
  236. package/src/browser-verify/pack-browser.js +294 -0
  237. package/src/browser-verify/pack-loader.js +176 -0
  238. package/src/browser-verify/pack-runner.js +193 -0
  239. package/src/browser-verify/pack-schema.js +155 -0
  240. package/src/browser-verify/runner.js +24 -1
  241. package/src/cli/blueprint.js +92 -0
  242. package/src/cli/browser-verify.js +147 -7
  243. package/src/cli/create.js +14 -0
  244. package/src/cli/eval-coverage.js +221 -0
  245. package/src/cli/eval.js +43 -0
  246. package/src/cli/finalise.js +64 -0
  247. package/src/cli/help.js +4 -0
  248. package/src/core/errors/index.js +7 -0
  249. package/src/core/store/ids.js +5 -1
  250. package/src/core/store/init.js +4 -0
  251. package/src/core/store/loader.js +4 -0
  252. package/src/core/store/validator.js +8 -1
  253. package/src/core/store/walker.js +71 -2
  254. package/src/core/store/writer.js +4 -0
  255. package/src/eval/judge.js +338 -0
  256. package/src/finalise/index.js +8 -0
  257. package/src/finalise/ingest.js +27 -0
  258. package/src/finalise/ship-without-eval.js +123 -0
  259. package/src/query/eval-coverage.js +162 -0
  260. package/src/verify/chain/index.js +67 -0
  261. package/src/verify/cli/run.js +15 -0
  262. package/src/verify/engine/index.js +10 -0
  263. package/src/verify/verdict/index.js +46 -0
@@ -184,6 +184,14 @@ const OPTION_SPEC = {
184
184
  // Companion-suggestion mechanism (core-companions spec section 2).
185
185
  companion: { type: 'string', multiple: true },
186
186
  'no-companion-suggestions': { type: 'boolean' },
187
+ // Capability-declaration mechanism (visual round T-5 spec 5.5.1,
188
+ // 5.5.2). --allow-no-auth-yet is the override for the
189
+ // requiresAppliedCapabilities gate. --answer <id>=<value> is
190
+ // repeatable; --answers <file> reads a JSON object mapping elicit
191
+ // ids to values. Both feed the elicitation phase in applyBlueprint.
192
+ 'allow-no-auth-yet': { type: 'boolean' },
193
+ answer: { type: 'string', multiple: true },
194
+ answers: { type: 'string' },
187
195
  };
188
196
 
189
197
  /**
@@ -286,9 +294,54 @@ export async function main(argv, deps = {}) {
286
294
  }
287
295
  }
288
296
  }
297
+ // Capability-declaration mechanism (visual round T-5). Compose
298
+ // the operator-supplied elicit answers bag from --answers <file>
299
+ // (JSON object) and --answer <id>=<value> (repeatable). Later
300
+ // --answer entries override --answers file entries so a shell
301
+ // one-liner beats a stored default without editing the file.
302
+ let elicitAnswers = {};
303
+ if (typeof parsed.values.answers === 'string' && parsed.values.answers.length > 0) {
304
+ try {
305
+ const raw = await (await import('node:fs/promises')).readFile(parsed.values.answers, 'utf8');
306
+ const parsedBag = JSON.parse(raw);
307
+ if (typeof parsedBag !== 'object' || parsedBag === null || Array.isArray(parsedBag)) {
308
+ stderr.write(`[error] blueprint add: --answers file must contain a JSON object of id -> value.\n`);
309
+ return 2;
310
+ }
311
+ elicitAnswers = { ...parsedBag };
312
+ } catch (err) {
313
+ stderr.write(`[error] blueprint add: --answers file read failed: ${err.message}\n`);
314
+ return 2;
315
+ }
316
+ }
317
+ if (Array.isArray(parsed.values.answer)) {
318
+ for (const entry of parsed.values.answer) {
319
+ const eq = entry.indexOf('=');
320
+ if (eq < 1) {
321
+ stderr.write(`[error] blueprint add: --answer expects <id>=<value>; got '${entry}'.\n`);
322
+ return 2;
323
+ }
324
+ elicitAnswers[entry.slice(0, eq)] = entry.slice(eq + 1);
325
+ }
326
+ }
327
+ // Custom-auth capability elicits (visual round T-5 spec 5.5
328
+ // "Risks"): providesCapability elicits fire pre-refusal. On a
329
+ // TTY, prompt the operator for any unanswered custom-auth elicits
330
+ // through readline so a fresh project with no shelf auth can pass
331
+ // the requiresAppliedCapabilities gate by declaring what its own
332
+ // auth provides. Non-interactive runs skip the prompt and read
333
+ // answers from the bag only.
334
+ const stdin = deps.stdin ?? process.stdin;
335
+ const isTty = Boolean(stdin && stdin.isTTY);
336
+ const customAuthReadLine = isTty
337
+ ? await createCustomAuthReadLine({ stdin, stdout })
338
+ : null;
289
339
  const result = await applyBlueprint({
290
340
  projectRoot, tree, source,
291
341
  namespaceOverride: parsed.values.namespace,
342
+ allowNoAuthYet: parsed.values['allow-no-auth-yet'] === true,
343
+ elicitAnswers,
344
+ customAuthReadLine,
292
345
  // Library-qualified resolves rewire the applied identity under
293
346
  // the library prefix and forward the library's declared bands
294
347
  // for the apply-time gate (spec §5.3, §8.3). The qualified typed
@@ -321,6 +374,19 @@ export async function main(argv, deps = {}) {
321
374
  }
322
375
  }
323
376
  if (isRcfError(result)) {
377
+ // Capability-declaration refusal (visual round T-5 spec 5.5.1)
378
+ // is exit 3, and the message is spec-verbatim (built by
379
+ // buildRefusalMessage in blueprint/capabilities.js): print it
380
+ // as-is on stderr, no [error] prefix. Every other rcfError
381
+ // stays exit 2 with the [error] prefix.
382
+ if (result.kind === 'requiresAppliedCapabilities') {
383
+ if (parsed.values.json) {
384
+ stderr.write(`${JSON.stringify({ refused: true, error: { kind: result.kind, message: result.message } })}\n`);
385
+ } else {
386
+ stderr.write(`${result.message}\n`);
387
+ }
388
+ return 3;
389
+ }
324
390
  if (parsed.values.json) {
325
391
  stderr.write(`${JSON.stringify({ refused: true, error: { kind: result.kind, message: result.message } })}\n`);
326
392
  } else {
@@ -759,3 +825,29 @@ function parseResolveOptions(rawList, reason) {
759
825
  }
760
826
  return { value: out };
761
827
  }
828
+
829
+ /**
830
+ * Build a readline-backed prompt function for custom-auth capability
831
+ * elicits (visual round T-5 spec 5.5 "Risks"). Wraps node:readline in
832
+ * a promise so `runCustomAuthCapabilityElicits` can `await` each line.
833
+ * Only used when stdin is a TTY; the callback closes the interface on
834
+ * first shutdown to avoid leaking file descriptors.
835
+ *
836
+ * @param {{ stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream }} deps
837
+ * @returns {Promise<(prompt: string) => Promise<string>>}
838
+ */
839
+ async function createCustomAuthReadLine({ stdin, stdout }) {
840
+ const { createInterface } = await import('node:readline');
841
+ const rl = createInterface({ input: stdin, output: stdout, terminal: true });
842
+ let closed = false;
843
+ return (prompt) => new Promise((resolve) => {
844
+ if (closed) return resolve('');
845
+ rl.question(prompt, (answer) => {
846
+ if (!closed) {
847
+ try { rl.close(); } catch { /* fine */ }
848
+ closed = true;
849
+ }
850
+ resolve(answer);
851
+ });
852
+ });
853
+ }
@@ -18,13 +18,18 @@
18
18
 
19
19
  import { parseArgs } from 'node:util';
20
20
  import process from 'node:process';
21
+ import { isAbsolute, resolve } from 'node:path';
21
22
 
22
23
  import { walkTree } from '#core/store';
23
24
  import { writeUnexpectedFailure, rcfError } from '#core/errors';
24
25
 
25
26
  import { findProjectRoot } from '../view/index.js';
26
27
  import {
28
+ bootIfNeeded,
27
29
  composeOperatorSessionRecord,
30
+ createPackBrowser,
31
+ loadProbePacks,
32
+ pickBootFromPacks,
28
33
  runAgentScreenshotCritique,
29
34
  stubBrowserDriver,
30
35
  writeBrowserVerificationAck,
@@ -40,6 +45,9 @@ const OPTION_SPEC = {
40
45
  quiet: { type: 'boolean' },
41
46
  ack: { type: 'boolean' },
42
47
  notes: { type: 'string' },
48
+ 'probe-pack': { type: 'string' },
49
+ 'no-boot': { type: 'boolean' },
50
+ 'no-browser': { type: 'boolean' },
43
51
  help: { type: 'boolean' },
44
52
  };
45
53
 
@@ -61,6 +69,22 @@ Options:
61
69
  --quiet Suppress non-error confirmations.
62
70
  --ack Mark operatorAckAt on the latest record for
63
71
  this FBS (used to clear a warn verdict).
72
+ --probe-pack <name> Restrict this run to one blueprint-shipped
73
+ probe pack by packName. When omitted, every
74
+ discovered pack whose appliesTo() matches
75
+ this FBS runs. Refuses (exit 2) when the
76
+ name resolves to no discovered pack.
77
+ --no-browser Skip the real headless browser (probe packs
78
+ that call browser.* will see browser=null).
79
+ Default: provision a headless browser via
80
+ the pinned Playwright MCP so packs can drive
81
+ real DOM interactions.
82
+ --no-boot Do not run a pack's declared bootCommand
83
+ when the runtime URL is unreachable. Default:
84
+ when any pack declares a boot block and the
85
+ runtime is not answering, spawn bootCommand
86
+ from the project root, wait for waitForUrl
87
+ then waitForSelector, then run packs.
64
88
  --help Print this help.
65
89
 
66
90
  Exit codes:
@@ -163,13 +187,77 @@ export async function main(argv, deps = {}) {
163
187
  stderr.write('[error] usage browser-verify: no fetch available in the runtime; supply deps.fetch\n');
164
188
  return 2;
165
189
  }
166
- record = await runAgentScreenshotCritique({
167
- tree, fbs, runtimeUrl, runtimeProfile: profile,
168
- browserDriver, fetch: fetchFn,
169
- artefactDir: `.rcf/artefacts/${fbsId.toLowerCase()}`,
170
- critiqueNotes: flags.notes,
171
- now,
172
- });
190
+ // Probe-pack discovery: gather packs from every applied blueprint
191
+ // on the manifest, then apply --probe-pack filter if any.
192
+ const appliedBlueprints = readAppliedBlueprints({ manifest: tree.manifest, projectRoot });
193
+ const { packs, errors: packErrors } = await loadProbePacks({ appliedBlueprints, projectRoot });
194
+ if (packErrors.length > 0) {
195
+ for (const e of packErrors) stderr.write(`[error] usage browser-verify: probe-pack loader refused ${e.packAbsPath}: ${e.message}\n`);
196
+ return 2;
197
+ }
198
+ const packNameFilter = typeof flags['probe-pack'] === 'string' && flags['probe-pack'].length > 0
199
+ ? flags['probe-pack']
200
+ : undefined;
201
+ if (packNameFilter && !packs.some((p) => p.packName === packNameFilter)) {
202
+ const discovered = packs.map((p) => p.packName).sort();
203
+ stderr.write(`[error] usage browser-verify: --probe-pack '${packNameFilter}' resolves to no discovered pack. Discovered packs: ${discovered.length === 0 ? '(none)' : discovered.join(', ')}.\n`);
204
+ return 2;
205
+ }
206
+
207
+ const filteredPacks = packNameFilter
208
+ ? packs.filter((p) => p.packName === packNameFilter)
209
+ : packs;
210
+ const provisionBrowser = deps.createPackBrowser ?? createPackBrowser;
211
+ const bootProbe = deps.bootIfNeeded ?? bootIfNeeded;
212
+
213
+ let packBrowser = deps.packBrowser ?? null;
214
+ const cleanups = [];
215
+ try {
216
+ if (packBrowser === null && filteredPacks.length > 0 && !flags['no-browser']) {
217
+ packBrowser = await provisionBrowser({
218
+ projectRoot,
219
+ logger: (line) => { if (!flags.quiet) stderr.write(`${line}\n`); },
220
+ });
221
+ cleanups.push(async () => { try { await packBrowser.close(); } catch { /* fine */ } });
222
+ }
223
+
224
+ if (!flags['no-boot'] && filteredPacks.length > 0) {
225
+ const boot = pickBootFromPacks(filteredPacks);
226
+ if (boot) {
227
+ const bootOutcome = await bootProbe({
228
+ boot,
229
+ runtimeUrl,
230
+ projectRoot,
231
+ fetch: fetchFn,
232
+ browser: packBrowser,
233
+ logger: (line) => { if (!flags.quiet) stderr.write(`${line}\n`); },
234
+ });
235
+ for (const n of bootOutcome.notes) if (!flags.quiet) stderr.write(`[boot] ${n}\n`);
236
+ if (bootOutcome.started) {
237
+ cleanups.push(async () => { try { await bootOutcome.stop(); } catch { /* fine */ } });
238
+ }
239
+ }
240
+ }
241
+
242
+ record = await runAgentScreenshotCritique({
243
+ tree, fbs, runtimeUrl, runtimeProfile: profile,
244
+ browserDriver, fetch: fetchFn,
245
+ artefactDir: `.rcf/artefacts/${fbsId.toLowerCase()}`,
246
+ critiqueNotes: flags.notes,
247
+ probePacks: packs,
248
+ packBrowser,
249
+ packNameFilter,
250
+ projectRoot,
251
+ now,
252
+ });
253
+ } finally {
254
+ // LIFO cleanup: close browser before stopping the server so a
255
+ // page.close talking to a killed server never hangs the CLI.
256
+ while (cleanups.length > 0) {
257
+ const step = cleanups.pop();
258
+ try { await step(); } catch { /* fine */ }
259
+ }
260
+ }
173
261
  }
174
262
  } catch (err) {
175
263
  writeUnexpectedFailure(
@@ -203,6 +291,41 @@ export async function main(argv, deps = {}) {
203
291
  return record.verdict === 'pass' ? 0 : 4;
204
292
  }
205
293
 
294
+ /**
295
+ * Read applied blueprints off the manifest as an array of
296
+ * `{ slug, absPath }` suitable for `loadProbePacks`.
297
+ *
298
+ * The applied-blueprint record carries a `source` field (see
299
+ * `src/blueprint/apply.js`). For a shelf apply the source is the
300
+ * shelf-relative slug; for a local-path apply it is an absolute
301
+ * path; for a library apply it is `<library>:<slug>`. We resolve
302
+ * to the shelf path shipped alongside the CLI package or, in the
303
+ * monorepo, the repo-root shelf. Missing directories are skipped
304
+ * without error (the CLI later checks discovered vs. requested).
305
+ */
306
+ function readAppliedBlueprints({ manifest, projectRoot }) {
307
+ const list = Array.isArray(manifest?.blueprints) ? manifest.blueprints : [];
308
+ const out = [];
309
+ for (const entry of list) {
310
+ if (!entry || typeof entry.slug !== 'string' || entry.slug.length === 0) continue;
311
+ const absPath = resolveBlueprintAbsPath({ entry, projectRoot });
312
+ if (absPath) out.push({ slug: entry.slug, absPath });
313
+ }
314
+ return out;
315
+ }
316
+
317
+ function resolveBlueprintAbsPath({ entry, projectRoot }) {
318
+ const { slug, source } = entry;
319
+ if (typeof source === 'string' && source.length > 0) {
320
+ if (isAbsolute(source)) return source;
321
+ if (source.startsWith('./') || source.startsWith('../')) {
322
+ return resolve(projectRoot, source);
323
+ }
324
+ }
325
+ const cwd = resolve(projectRoot, 'blueprints', slug);
326
+ return cwd;
327
+ }
328
+
206
329
  function defaultUrlForProfile(profile) {
207
330
  if (profile === 'ci') return 'http://127.0.0.1:3000';
208
331
  if (profile === 'deployed') return '';
@@ -227,5 +350,22 @@ function renderSummary({ stdout, record }) {
227
350
  stdout.write(` [${c.verdict}] ${c.check} (status=${c.status ?? 'n/a'})${detail}\n`);
228
351
  }
229
352
  }
353
+ if (Array.isArray(record.probePacks) && record.probePacks.length > 0) {
354
+ stdout.write(' probe packs:\n');
355
+ for (const p of record.probePacks) {
356
+ if (p.applicable === false) {
357
+ stdout.write(` [skip] ${p.packName} (${p.blueprintSlug}): ${p.detail ?? 'not applicable to this FBS'}\n`);
358
+ continue;
359
+ }
360
+ for (const pc of p.preChecks ?? []) {
361
+ const detail = pc.detail ? ` - ${pc.detail}` : '';
362
+ stdout.write(` [${pc.verdict}] ${p.packName} pre-check ${pc.id}${detail}\n`);
363
+ }
364
+ for (const c of p.checks ?? []) {
365
+ const detail = c.detail ? ` - ${c.detail}` : '';
366
+ stdout.write(` [${c.verdict}] ${p.packName} ${c.id}${detail}\n`);
367
+ }
368
+ }
369
+ }
230
370
  stdout.write(` verdict: ${record.verdict}\n\n`);
231
371
  }
package/src/cli/create.js CHANGED
@@ -37,6 +37,12 @@ const OPTION_SPEC = {
37
37
  path: { type: 'string' },
38
38
  deps: { type: 'string' },
39
39
  'derive-deps': { type: 'boolean' },
40
+ // rcf-eval-node spec section 2.2: `rcf define create ac
41
+ // --determinism deterministic|nonDeterministic`. Optional at CLI
42
+ // (default deterministic; absence is treated as `deterministic` by
43
+ // every consumer). A value outside the enum exits 2 with the spec-
44
+ // named message (spec section 8).
45
+ determinism: { type: 'string' },
40
46
  };
41
47
 
42
48
  export const HELP = `Usage: rcf define create <kind> [options]
@@ -202,6 +208,14 @@ export async function main(argv, deps = {}) {
202
208
  stderr.write(`[error] usage create ${kind}: --description is required\n`);
203
209
  return 2;
204
210
  }
211
+ // rcf-eval-node spec section 2.2 + 8: --determinism enum guard.
212
+ if (kind === 'ac' && flags.determinism !== undefined) {
213
+ if (flags.determinism !== 'deterministic' && flags.determinism !== 'nonDeterministic') {
214
+ stderr.write(`--determinism expects 'deterministic' or 'nonDeterministic', got '${flags.determinism}'\n`);
215
+ return 2;
216
+ }
217
+ body.determinism = flags.determinism;
218
+ }
205
219
  } else if (kind === 'cn') {
206
220
  if (!body.path) {
207
221
  stderr.write('[error] usage create cn: --path is required\n');
@@ -0,0 +1,221 @@
1
+ // `rcf audit eval coverage` subcommand handler. Sibling of `rcf audit
2
+ // coverage`; grades non-deterministic AC coverage by EVAL docs rather
3
+ // than TS/TC coverage. See spec section 4 of
4
+ // projects/rcf-lite-wsd/specs/rcf-eval-node-spec-2026-09-04.md.
5
+ //
6
+ // Coverage rule (spec 2.3): an AC counts as covered by EVAL only when
7
+ // at least one EVAL document lists its id in acIds[], is not
8
+ // superseded, and has a non-pending runRecord[] entry (a "resolving"
9
+ // EVAL, mirroring the resolving-TC rule on `rcf audit coverage`).
10
+ //
11
+ // Exit codes: 0 clean, 2 usage refusal, 3 tree drift, 4 strict-gate
12
+ // refusal (any nonDeterministic AC without a resolving EVAL).
13
+ //
14
+ // Deterministic ACs never trigger the strict gate. A subtree with zero
15
+ // nonDeterministic ACs passes trivially. Presence of a resolving EVAL
16
+ // on a deterministic AC is reported as `covered-optional`, never as a
17
+ // defect.
18
+
19
+ import { parseArgs } from 'node:util';
20
+
21
+ import { formatErrors } from '#core/errors';
22
+ import { walkTree } from '#core/store';
23
+ import { findProjectRoot } from '../view/index.js';
24
+ import {
25
+ classifyCoverageScope,
26
+ } from '../query/index.js';
27
+ import { computeEvalCoverage } from '../query/eval-coverage.js';
28
+
29
+ const OPTION_SPEC = {
30
+ strict: { type: 'boolean' },
31
+ format: { type: 'string' },
32
+ help: { type: 'boolean' },
33
+ // 0.7.0 verification-integrity precedent: opt-in extra gate on
34
+ // --strict that refuses any EVAL still at authoringStatus `draft`.
35
+ // Named --require-approved to match `rcf audit coverage`'s flag,
36
+ // spec section 12 Q1 recommendation.
37
+ 'require-approved': { type: 'boolean' },
38
+ };
39
+
40
+ export const HELP = `Usage: rcf audit eval coverage [scope-id] [options]
41
+
42
+ Report EVAL coverage of the non-deterministic ACs on the scoped
43
+ subtree. An AC counts as covered by EVAL only when at least one EVAL
44
+ document lists its id in acIds[], is not superseded, and has a
45
+ non-pending runRecord[] entry (a "resolving" EVAL, mirroring the
46
+ resolving-TC rule on \`rcf audit coverage\`).
47
+
48
+ Deterministic ACs never trigger the strict gate. Presence of a
49
+ resolving EVAL on a deterministic AC is reported as covered-optional,
50
+ never as a defect.
51
+
52
+ Positional:
53
+ scope-id Optional PRD / REQ / US id to scope the
54
+ audit to a subtree. Below-AC ids exit 2.
55
+
56
+ Options:
57
+ --strict Per-AC-strict mode; exits 4 on any
58
+ nonDeterministic AC without a resolving
59
+ EVAL. Deterministic ACs are never gated.
60
+ --require-approved Extra --strict gate: refuse any EVAL still
61
+ at authoringStatus 'draft'.
62
+ --format <format> table (default) | json | mermaid
63
+ --help Print this help
64
+ `;
65
+
66
+ const VALID_FORMATS = new Set(['table', 'json', 'mermaid']);
67
+
68
+ /**
69
+ * @param {string[]} argv - argv slice after `eval coverage`
70
+ * @param {object} [deps]
71
+ * @returns {Promise<number>}
72
+ */
73
+ export async function main(argv, deps = {}) {
74
+ const stdout = deps.stdout ?? process.stdout;
75
+ const stderr = deps.stderr ?? process.stderr;
76
+ const cwd = deps.cwd ?? process.cwd();
77
+
78
+ let parsed;
79
+ try {
80
+ parsed = parseArgs({ args: argv, options: OPTION_SPEC, allowPositionals: true, strict: true });
81
+ } catch (err) {
82
+ stderr.write(`[error] usage ${err.message}\n`);
83
+ stderr.write(HELP);
84
+ return 2;
85
+ }
86
+ const flags = parsed.values;
87
+ const positionals = parsed.positionals;
88
+ if (flags.help) { stdout.write(HELP); return 0; }
89
+
90
+ const format = flags.format ?? 'table';
91
+ if (!VALID_FORMATS.has(format)) {
92
+ stderr.write(`[error] usage eval coverage: unknown --format ${format} (expected table | json | mermaid)\n`);
93
+ return 2;
94
+ }
95
+ if (positionals.length > 1) {
96
+ stderr.write('[error] usage eval coverage: multiple positional ids are not supported\n');
97
+ return 2;
98
+ }
99
+
100
+ const projectRoot = await findProjectRoot(cwd);
101
+ if (!projectRoot) {
102
+ 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');
103
+ return 2;
104
+ }
105
+ const { tree, errors } = await walkTree({ projectRoot });
106
+ if (errors.length > 0) {
107
+ stderr.write(`${formatErrors(errors, { verbose: false, strict: false })}\n`);
108
+ return 3;
109
+ }
110
+
111
+ let scopeId = null;
112
+ if (positionals.length === 1) {
113
+ scopeId = positionals[0];
114
+ if (scopeId.includes('*') || scopeId.includes('?')) {
115
+ stderr.write('[error] usage eval coverage: wildcard / glob positional not supported\n');
116
+ return 2;
117
+ }
118
+ const classification = classifyCoverageScope(tree, scopeId);
119
+ if (classification === 'below-ac') {
120
+ stderr.write(
121
+ `[error] usage eval coverage: scope-id ${scopeId} is below the AC layer or off the REQ chain; ` +
122
+ 'eval coverage scope must be a PRD / REQ / US id\n',
123
+ );
124
+ return 2;
125
+ }
126
+ if (classification === 'not-found' || classification === 'unknown-kind') {
127
+ stderr.write(`[error] usage eval coverage: id ${scopeId} not found\n`);
128
+ return 2;
129
+ }
130
+ }
131
+
132
+ const report = computeEvalCoverage(tree, { scopeId });
133
+
134
+ if (format === 'json') stdout.write(`${JSON.stringify(report, null, 2)}\n`);
135
+ else if (format === 'mermaid') stdout.write(formatMermaid(report));
136
+ else stdout.write(formatTable(report));
137
+
138
+ // --strict on any missing = exit 4 (CI-gate friendly). Otherwise 0.
139
+ if (flags.strict && !report.ok) return 4;
140
+
141
+ if (flags.strict && flags['require-approved']) {
142
+ const draftEvalIds = (tree.evals ?? []).filter((e) => e.status !== 'approved').map((e) => e.id);
143
+ if (draftEvalIds.length > 0) {
144
+ stderr.write(`[error] eval coverage --strict --require-approved: refused - ${draftEvalIds.length} EVAL(s) still not approved: ${draftEvalIds.join(', ')}\n`);
145
+ return 4;
146
+ }
147
+ }
148
+ return 0;
149
+ }
150
+
151
+ /**
152
+ * Render the EVAL coverage report as a plain-text table.
153
+ *
154
+ * @param {import('../query/eval-coverage.js').EvalCoverageReport} report
155
+ * @returns {string}
156
+ */
157
+ export function formatTable(report) {
158
+ const lines = [];
159
+ lines.push('EVAL coverage report');
160
+ if (report.scopeId) lines.push(`scope: ${report.scopeId}`);
161
+ lines.push('');
162
+ if (report.nonDeterministicCount === 0) {
163
+ lines.push('no nonDeterministic ACs on this chain; audit passes trivially');
164
+ lines.push('');
165
+ lines.push(`ok=${report.ok}`);
166
+ return `${lines.join('\n')}\n`;
167
+ }
168
+ lines.push(' AC US determinism evalStatus outcome evalId');
169
+ for (const ac of report.acs) {
170
+ const cols = [
171
+ pad(ac.acId, 15),
172
+ pad(ac.usId, 9),
173
+ pad(ac.determinism, 16),
174
+ pad(ac.evalStatus, 11),
175
+ pad(ac.outcome, 18),
176
+ ac.evalId ?? '',
177
+ ];
178
+ lines.push(` ${cols.join(' ')}`);
179
+ }
180
+ lines.push('');
181
+ lines.push(
182
+ `nonDeterministic=${report.nonDeterministicCount}, `
183
+ + `covered=${report.coveredCount}, `
184
+ + `missing=${report.missingCount}, ok=${report.ok}`,
185
+ );
186
+ return `${lines.join('\n')}\n`;
187
+ }
188
+
189
+ /**
190
+ * Colour-coded mermaid summary. Spec section 4: green deterministic
191
+ * (out of scope), amber nonDeterministic with a resolving EVAL, red
192
+ * nonDeterministic without one.
193
+ *
194
+ * @param {import('../query/eval-coverage.js').EvalCoverageReport} report
195
+ * @returns {string}
196
+ */
197
+ export function formatMermaid(report) {
198
+ const lines = ['graph TD'];
199
+ lines.push(' classDef deterministic fill:#d1f2c4,stroke:#2f7a1e;');
200
+ lines.push(' classDef covered fill:#ffe6a1,stroke:#a56a00;');
201
+ lines.push(' classDef missing fill:#f4b4b4,stroke:#a00000;');
202
+ for (const ac of report.acs) {
203
+ const cls = ac.outcome === 'missing'
204
+ ? 'missing'
205
+ : ac.outcome === 'covered'
206
+ ? 'covered'
207
+ : 'deterministic';
208
+ const label = ac.evalId ? `${ac.acId}\\n[${ac.evalId}]` : ac.acId;
209
+ lines.push(` ${idOf(ac.acId)}["${label}"]:::${cls}`);
210
+ }
211
+ return `${lines.join('\n')}\n`;
212
+ }
213
+
214
+ function pad(s, w) {
215
+ const str = String(s ?? '');
216
+ return str.length >= w ? str : str + ' '.repeat(w - str.length);
217
+ }
218
+
219
+ function idOf(s) {
220
+ return String(s).replace(/[^A-Za-z0-9]+/g, '_');
221
+ }
@@ -0,0 +1,43 @@
1
+ // `rcf audit eval <sub-verb>` dispatcher. v1 exposes one sub-verb:
2
+ // `coverage`. The compound invocation `rcf audit eval coverage`
3
+ // matches the spec text exactly (section 4). Future sibling sub-verbs
4
+ // (`rcf audit eval trace`, `rcf build eval run`, ...) plug in here.
5
+
6
+ import { main as evalCoverageMain, HELP as COVERAGE_HELP } from './eval-coverage.js';
7
+
8
+ export const HELP = `Usage: rcf audit eval <sub-verb> [options]
9
+
10
+ Sub-verbs:
11
+ coverage Report EVAL coverage over the chain.
12
+
13
+ Options:
14
+ --help Print this help
15
+ `;
16
+
17
+ const SUB_VERBS = {
18
+ coverage: evalCoverageMain,
19
+ };
20
+
21
+ /**
22
+ * @param {string[]} argv - argv slice after `eval`
23
+ * @param {object} [deps]
24
+ * @returns {Promise<number>}
25
+ */
26
+ export async function main(argv, deps = {}) {
27
+ const stdout = deps.stdout ?? process.stdout;
28
+ const stderr = deps.stderr ?? process.stderr;
29
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
30
+ stdout.write(HELP);
31
+ return 0;
32
+ }
33
+ const subVerb = argv[0];
34
+ const handler = SUB_VERBS[subVerb];
35
+ if (!handler) {
36
+ stderr.write(`[error] usage unknown sub-verb '${subVerb}' under 'audit eval'.\n`);
37
+ stderr.write(HELP);
38
+ return 2;
39
+ }
40
+ return await handler(argv.slice(1), deps);
41
+ }
42
+
43
+ export { COVERAGE_HELP };