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