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.
- package/CHANGELOG.md +38 -0
- package/bin/rcf.js +5 -0
- package/blueprints/application-admin-console/CHANGELOG.md +11 -0
- package/blueprints/application-admin-console/README.md +98 -0
- package/blueprints/application-admin-console/blueprint.json +226 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +25 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2202-application-admin-console-baseline-roles.json +25 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +20 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +20 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +18 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +40 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +44 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2203-application-admin-console-permission-matrix.json +34 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +40 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +28 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +33 -0
- package/blueprints/application-admin-console/docs/topics.md +35 -0
- package/blueprints/application-admin-console/guide/application-admin-console.md +29 -0
- package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +182 -0
- package/blueprints/application-api-rest/docs/topics.md +5 -0
- package/blueprints/application-charts/CHANGELOG.md +12 -0
- package/blueprints/application-charts/README.md +73 -0
- package/blueprints/application-charts/blueprint.json +26 -0
- package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +25 -0
- package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +25 -0
- package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.json +25 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +15 -0
- package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +42 -0
- package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +40 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +35 -0
- package/blueprints/application-charts/docs/topics.md +37 -0
- package/blueprints/application-charts/guide/application-charts.md +44 -0
- package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +191 -0
- package/blueprints/application-dashboard/CHANGELOG.md +10 -0
- package/blueprints/application-dashboard/README.md +102 -0
- package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +124 -0
- package/blueprints/application-dashboard/blueprint.json +29 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +25 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +25 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.json +25 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-001.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +15 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +47 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +41 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +35 -0
- package/blueprints/application-dashboard/docs/topics.md +43 -0
- package/blueprints/application-dashboard/guide/application-dashboard.md +48 -0
- package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +231 -0
- package/blueprints/application-datatable/CHANGELOG.md +8 -0
- package/blueprints/application-datatable/README.md +43 -0
- package/blueprints/application-datatable/blueprint.json +33 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +25 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +20 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +20 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +20 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-001.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +15 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +50 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +39 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +28 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +44 -0
- package/blueprints/application-datatable/docs/topics.md +35 -0
- package/blueprints/application-datatable/guide/application-datatable.md +38 -0
- package/blueprints/application-datatable/probe-packs/application-datatable.pack.mjs +240 -0
- package/blueprints/application-error-handling/docs/topics.md +5 -0
- package/blueprints/application-notifications-in-app/CHANGELOG.md +9 -0
- package/blueprints/application-notifications-in-app/README.md +80 -0
- package/blueprints/application-notifications-in-app/blueprint.json +30 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2102-application-notifications-in-app-toast-timeout-floor.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2103-application-notifications-in-app-retention-window.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +46 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +52 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +40 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +26 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +26 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +26 -0
- package/blueprints/application-notifications-in-app/docs/topics.md +39 -0
- package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +47 -0
- package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +328 -0
- package/blueprints/application-spa/docs/topics.md +5 -0
- package/blueprints/delivery-ci-workflows/docs/topics.md +5 -0
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +5 -0
- package/blueprints/email-smtp-resend/docs/topics.md +5 -0
- package/blueprints/observability-essentials/docs/topics.md +5 -0
- package/blueprints/observability-logging/CHANGELOG.md +5 -0
- package/blueprints/observability-logging/README.md +1 -1
- package/blueprints/observability-logging/blueprint.json +113 -21
- package/blueprints/observability-logging/docs/topics.md +5 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +5 -0
- package/blueprints/persistence-data-d1/docs/topics.md +5 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +5 -0
- package/blueprints/security-auth-clerk/CHANGELOG.md +5 -0
- package/blueprints/security-auth-clerk/blueprint.json +2 -1
- package/blueprints/security-auth-clerk/docs/topics.md +5 -0
- package/blueprints/security-auth-keycloak/CHANGELOG.md +5 -0
- package/blueprints/security-auth-keycloak/blueprint.json +2 -1
- package/blueprints/security-auth-keycloak/docs/topics.md +5 -0
- package/blueprints/security-auth-magic-link/CHANGELOG.md +5 -0
- package/blueprints/security-auth-magic-link/blueprint.json +2 -1
- package/blueprints/security-auth-magic-link/docs/topics.md +5 -0
- package/blueprints/security-auth-oauth2/CHANGELOG.md +5 -0
- package/blueprints/security-auth-oauth2/blueprint.json +2 -1
- package/blueprints/security-auth-oauth2/docs/topics.md +5 -0
- package/blueprints/security-secrets-management/docs/topics.md +5 -0
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +2 -2
- package/rcf/code-nodes/cn-098.json +13 -0
- package/rcf/code-nodes/cn-099.json +13 -0
- package/rcf/code-nodes/cn-100.json +13 -0
- package/rcf/code-nodes/cn-101.json +13 -0
- package/rcf/code-nodes/cn-102.json +13 -0
- package/rcf/code-nodes/cn-103.json +13 -0
- package/rcf/code-nodes/cn-104.json +13 -0
- package/rcf/code-nodes/cn-105.json +13 -0
- package/rcf/code-nodes/cn-106.json +13 -0
- package/rcf/code-nodes/cn-107.json +14 -0
- package/rcf/code-nodes/cn-108.json +13 -0
- package/rcf/code-nodes/cn-109.json +12 -0
- package/rcf/code-nodes/cn-110.json +12 -0
- package/rcf/code-nodes/cn-111.json +14 -0
- package/rcf/code-nodes/cn-112.json +14 -0
- package/rcf/code-nodes/cn-113.json +12 -0
- package/rcf/code-nodes/cn-114.json +13 -0
- package/rcf/code-nodes/cn-115.json +13 -0
- package/rcf/code-nodes/cn-116.json +12 -0
- package/rcf/code-nodes/cn-117.json +13 -0
- package/rcf/code-nodes/cn-118.json +13 -0
- package/rcf/code-nodes/cn-119.json +13 -0
- package/rcf/code-nodes/cn-120.json +13 -0
- package/rcf/code-nodes/cn-121.json +12 -0
- package/rcf/code-nodes/cn-122.json +12 -0
- package/rcf/code-nodes/cn-123.json +13 -0
- package/rcf/code-nodes/cn-124.json +13 -0
- package/rcf/code-nodes/cn-125.json +13 -0
- package/rcf/code-nodes/cn-126.json +13 -0
- package/rcf/code-nodes/cn-127.json +12 -0
- package/rcf/code-nodes/cn-128.json +14 -0
- package/rcf/code-nodes/cn-129.json +14 -0
- package/rcf/code-nodes/cn-130.json +14 -0
- package/rcf/code-nodes/cn-131.json +15 -0
- package/rcf/code-nodes/cn-132.json +12 -0
- package/rcf/code-nodes/cn-133.json +13 -0
- package/rcf/evals/eval-001.json +55 -0
- package/rcf/fbs/fbs-035.json +18 -0
- package/rcf/fbs/fbs-036.json +22 -0
- package/rcf/fbs/fbs-037.json +19 -0
- package/rcf/fbs/fbs-038.json +19 -0
- package/rcf/fbs/fbs-039.json +21 -0
- package/rcf/fbs/fbs-040.json +20 -0
- package/rcf/fbs/fbs-041.json +13 -0
- package/rcf/fbs/fbs-042.json +13 -0
- package/rcf/requirements/req-016.json +37 -0
- package/rcf/requirements/req-017.json +18 -0
- package/rcf/requirements/req-018.json +18 -0
- package/rcf/requirements/req-019.json +38 -0
- package/rcf/requirements/req-020.json +13 -0
- package/rcf/requirements/req-021.json +13 -0
- package/rcf/requirements/req-022.json +13 -0
- package/rcf/requirements/req-023.json +14 -0
- package/rcf/test-suites/ts-045.json +46 -0
- package/rcf/test-suites/ts-046.json +78 -0
- package/rcf/test-suites/ts-047.json +54 -0
- package/rcf/test-suites/ts-048.json +54 -0
- package/rcf/test-suites/ts-049.json +70 -0
- package/rcf/test-suites/ts-050.json +69 -0
- package/rcf/test-suites/ts-051.json +22 -0
- package/rcf/test-suites/ts-052.json +20 -0
- package/rcf/user-stories/us-1601.json +37 -0
- package/rcf/user-stories/us-1701.json +56 -0
- package/rcf/user-stories/us-1801.json +40 -0
- package/rcf/user-stories/us-1901.json +40 -0
- package/rcf/user-stories/us-2001.json +50 -0
- package/rcf/user-stories/us-2101.json +45 -0
- package/rcf/user-stories/us-2201.json +60 -0
- package/rcf/user-stories/us-2301.json +51 -0
- package/releases/releases.yaml +20 -1
- package/src/blueprint/apply.js +98 -1
- package/src/blueprint/capabilities.js +318 -0
- package/src/blueprint/loader.js +247 -0
- package/src/browser-verify/boot.js +180 -0
- package/src/browser-verify/index.js +13 -0
- package/src/browser-verify/manifest-writer.js +31 -6
- package/src/browser-verify/pack-browser.js +294 -0
- package/src/browser-verify/pack-loader.js +176 -0
- package/src/browser-verify/pack-runner.js +193 -0
- package/src/browser-verify/pack-schema.js +155 -0
- package/src/browser-verify/runner.js +24 -1
- package/src/cli/blueprint.js +92 -0
- package/src/cli/browser-verify.js +147 -7
- package/src/cli/create.js +14 -0
- package/src/cli/eval-coverage.js +221 -0
- package/src/cli/eval.js +43 -0
- package/src/cli/finalise.js +64 -0
- package/src/cli/help.js +4 -0
- package/src/core/errors/index.js +7 -0
- package/src/core/store/ids.js +5 -1
- package/src/core/store/init.js +4 -0
- package/src/core/store/loader.js +4 -0
- package/src/core/store/validator.js +8 -1
- package/src/core/store/walker.js +71 -2
- package/src/core/store/writer.js +4 -0
- package/src/eval/judge.js +338 -0
- package/src/finalise/index.js +8 -0
- package/src/finalise/ingest.js +27 -0
- package/src/finalise/ship-without-eval.js +123 -0
- package/src/query/eval-coverage.js +162 -0
- package/src/verify/chain/index.js +67 -0
- package/src/verify/cli/run.js +15 -0
- package/src/verify/engine/index.js +10 -0
- package/src/verify/verdict/index.js +46 -0
package/src/cli/blueprint.js
CHANGED
|
@@ -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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
+
}
|
package/src/cli/eval.js
ADDED
|
@@ -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 };
|