@specship/specship-win32-arm64 0.24.0 → 0.28.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/bin/specship.cmd +31 -1
- package/lib/dist/activation/cheatsheet.d.ts +17 -1
- package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
- package/lib/dist/activation/cheatsheet.js +47 -3
- package/lib/dist/activation/cheatsheet.js.map +1 -1
- package/lib/dist/activation/hook-output.d.ts +80 -0
- package/lib/dist/activation/hook-output.d.ts.map +1 -0
- package/lib/dist/activation/hook-output.js +103 -0
- package/lib/dist/activation/hook-output.js.map +1 -0
- package/lib/dist/activation/search-intercept.d.ts +60 -29
- package/lib/dist/activation/search-intercept.d.ts.map +1 -1
- package/lib/dist/activation/search-intercept.js +159 -55
- package/lib/dist/activation/search-intercept.js.map +1 -1
- package/lib/dist/activation/steering.d.ts +11 -13
- package/lib/dist/activation/steering.d.ts.map +1 -1
- package/lib/dist/activation/steering.js +25 -10
- package/lib/dist/activation/steering.js.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
- package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.js +108 -2
- package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
- package/lib/dist/bin/node-version-check.d.ts +22 -7
- package/lib/dist/bin/node-version-check.d.ts.map +1 -1
- package/lib/dist/bin/node-version-check.js +39 -9
- package/lib/dist/bin/node-version-check.js.map +1 -1
- package/lib/dist/bin/specship.js +989 -116
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/commands/specship/learn.md +27 -3
- package/lib/dist/commands/specship/spec.md +85 -15
- package/lib/dist/db/spec-queries.d.ts +73 -3
- package/lib/dist/db/spec-queries.d.ts.map +1 -1
- package/lib/dist/db/spec-queries.js +139 -5
- package/lib/dist/db/spec-queries.js.map +1 -1
- package/lib/dist/db/sqlite-adapter.d.ts +7 -5
- package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/lib/dist/db/sqlite-adapter.js +11 -9
- package/lib/dist/db/sqlite-adapter.js.map +1 -1
- package/lib/dist/enforce/changed-files.d.ts +39 -0
- package/lib/dist/enforce/changed-files.d.ts.map +1 -0
- package/lib/dist/enforce/changed-files.js +114 -0
- package/lib/dist/enforce/changed-files.js.map +1 -0
- package/lib/dist/enforce/enforce.d.ts +53 -2
- package/lib/dist/enforce/enforce.d.ts.map +1 -1
- package/lib/dist/enforce/enforce.js +95 -8
- package/lib/dist/enforce/enforce.js.map +1 -1
- package/lib/dist/enforce/mutation.d.ts +46 -0
- package/lib/dist/enforce/mutation.d.ts.map +1 -0
- package/lib/dist/enforce/mutation.js +104 -0
- package/lib/dist/enforce/mutation.js.map +1 -0
- package/lib/dist/enforce/suppressions.d.ts +33 -0
- package/lib/dist/enforce/suppressions.d.ts.map +1 -0
- package/lib/dist/enforce/suppressions.js +159 -0
- package/lib/dist/enforce/suppressions.js.map +1 -0
- package/lib/dist/extraction/grammars.d.ts +10 -0
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +32 -3
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +7 -0
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts +7 -0
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js +97 -10
- package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm.gz +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-scala.wasm.gz +0 -0
- package/lib/dist/graph/spec-coverage.d.ts +142 -0
- package/lib/dist/graph/spec-coverage.d.ts.map +1 -0
- package/lib/dist/graph/spec-coverage.js +276 -0
- package/lib/dist/graph/spec-coverage.js.map +1 -0
- package/lib/dist/health/smoke-check.js +2 -2
- package/lib/dist/health/smoke-check.js.map +1 -1
- package/lib/dist/index.d.ts +75 -7
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +191 -23
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/gemini-commands.d.ts +107 -0
- package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
- package/lib/dist/installer/gemini-commands.js +264 -0
- package/lib/dist/installer/gemini-commands.js.map +1 -0
- package/lib/dist/installer/index.d.ts +55 -8
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +72 -53
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/init-offer.d.ts +14 -9
- package/lib/dist/installer/init-offer.d.ts.map +1 -1
- package/lib/dist/installer/init-offer.js +13 -9
- package/lib/dist/installer/init-offer.js.map +1 -1
- package/lib/dist/installer/install-defaults.d.ts +81 -0
- package/lib/dist/installer/install-defaults.d.ts.map +1 -0
- package/lib/dist/installer/install-defaults.js +95 -0
- package/lib/dist/installer/install-defaults.js.map +1 -0
- package/lib/dist/installer/instructions-template.d.ts +22 -0
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +37 -1
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts +18 -0
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +70 -23
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/gemini.d.ts +85 -12
- package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
- package/lib/dist/installer/targets/gemini.js +527 -30
- package/lib/dist/installer/targets/gemini.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +13 -0
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +22 -4
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +12 -0
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.d.ts +71 -4
- package/lib/dist/jira/auto-publish.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.js +186 -17
- package/lib/dist/jira/auto-publish.js.map +1 -1
- package/lib/dist/jira/reconcile.d.ts +24 -1
- package/lib/dist/jira/reconcile.d.ts.map +1 -1
- package/lib/dist/jira/reconcile.js +46 -2
- package/lib/dist/jira/reconcile.js.map +1 -1
- package/lib/dist/jira/repo-config.d.ts +9 -0
- package/lib/dist/jira/repo-config.d.ts.map +1 -1
- package/lib/dist/jira/repo-config.js +11 -0
- package/lib/dist/jira/repo-config.js.map +1 -1
- package/lib/dist/jira/types.d.ts +7 -0
- package/lib/dist/jira/types.d.ts.map +1 -1
- package/lib/dist/jira/types.js.map +1 -1
- package/lib/dist/knowledge/enforce.d.ts +75 -0
- package/lib/dist/knowledge/enforce.d.ts.map +1 -0
- package/lib/dist/knowledge/enforce.js +250 -0
- package/lib/dist/knowledge/enforce.js.map +1 -0
- package/lib/dist/knowledge/facts.d.ts +33 -0
- package/lib/dist/knowledge/facts.d.ts.map +1 -0
- package/lib/dist/knowledge/facts.js +117 -0
- package/lib/dist/knowledge/facts.js.map +1 -0
- package/lib/dist/knowledge/proposals.d.ts +88 -0
- package/lib/dist/knowledge/proposals.d.ts.map +1 -0
- package/lib/dist/knowledge/proposals.js +360 -0
- package/lib/dist/knowledge/proposals.js.map +1 -0
- package/lib/dist/knowledge/stale.d.ts +64 -0
- package/lib/dist/knowledge/stale.d.ts.map +1 -0
- package/lib/dist/knowledge/stale.js +174 -0
- package/lib/dist/knowledge/stale.js.map +1 -0
- package/lib/dist/mcp/fitness-tool.d.ts +5 -6
- package/lib/dist/mcp/fitness-tool.d.ts.map +1 -1
- package/lib/dist/mcp/fitness-tool.js +0 -16
- package/lib/dist/mcp/fitness-tool.js.map +1 -1
- package/lib/dist/mcp/gemini-session.d.ts +50 -0
- package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
- package/lib/dist/mcp/gemini-session.js +159 -0
- package/lib/dist/mcp/gemini-session.js.map +1 -0
- package/lib/dist/mcp/health-tool.d.ts +26 -0
- package/lib/dist/mcp/health-tool.d.ts.map +1 -0
- package/lib/dist/mcp/health-tool.js +50 -0
- package/lib/dist/mcp/health-tool.js.map +1 -0
- package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
- package/lib/dist/mcp/jira-tools.js +25 -0
- package/lib/dist/mcp/jira-tools.js.map +1 -1
- package/lib/dist/mcp/maintainability-tool.d.ts +5 -7
- package/lib/dist/mcp/maintainability-tool.d.ts.map +1 -1
- package/lib/dist/mcp/maintainability-tool.js +0 -16
- package/lib/dist/mcp/maintainability-tool.js.map +1 -1
- package/lib/dist/mcp/model-context.d.ts +31 -7
- package/lib/dist/mcp/model-context.d.ts.map +1 -1
- package/lib/dist/mcp/model-context.js +70 -21
- package/lib/dist/mcp/model-context.js.map +1 -1
- package/lib/dist/mcp/proxy.d.ts.map +1 -1
- package/lib/dist/mcp/proxy.js +5 -2
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +16 -15
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +72 -5
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.js +1 -1
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/spec-tools.d.ts +9 -1
- package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
- package/lib/dist/mcp/spec-tools.js +282 -49
- package/lib/dist/mcp/spec-tools.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +49 -9
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +210 -58
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/pulse/pulse.d.ts +93 -0
- package/lib/dist/pulse/pulse.d.ts.map +1 -0
- package/lib/dist/pulse/pulse.js +401 -0
- package/lib/dist/pulse/pulse.js.map +1 -0
- package/lib/dist/reflect/apply.d.ts.map +1 -1
- package/lib/dist/reflect/apply.js +38 -3
- package/lib/dist/reflect/apply.js.map +1 -1
- package/lib/dist/reflect/auto-sweep.d.ts +26 -0
- package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
- package/lib/dist/reflect/auto-sweep.js +90 -0
- package/lib/dist/reflect/auto-sweep.js.map +1 -0
- package/lib/dist/reflect/cli.d.ts +62 -0
- package/lib/dist/reflect/cli.d.ts.map +1 -0
- package/lib/dist/reflect/cli.js +163 -0
- package/lib/dist/reflect/cli.js.map +1 -0
- package/lib/dist/reflect/miner.d.ts.map +1 -1
- package/lib/dist/reflect/miner.js +119 -0
- package/lib/dist/reflect/miner.js.map +1 -1
- package/lib/dist/reflect/sweep.d.ts +1 -0
- package/lib/dist/reflect/sweep.d.ts.map +1 -1
- package/lib/dist/reflect/sweep.js +62 -13
- package/lib/dist/reflect/sweep.js.map +1 -1
- package/lib/dist/reflect/targets.d.ts +2 -0
- package/lib/dist/reflect/targets.d.ts.map +1 -1
- package/lib/dist/reflect/targets.js +33 -0
- package/lib/dist/reflect/targets.js.map +1 -1
- package/lib/dist/reflect/types.d.ts +19 -2
- package/lib/dist/reflect/types.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.d.ts +44 -2
- package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.js +132 -0
- package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
- package/lib/dist/resolution/test-title-links.d.ts +62 -0
- package/lib/dist/resolution/test-title-links.d.ts.map +1 -0
- package/lib/dist/resolution/test-title-links.js +97 -0
- package/lib/dist/resolution/test-title-links.js.map +1 -0
- package/lib/dist/search/query-parser.d.ts.map +1 -1
- package/lib/dist/search/query-parser.js +6 -1
- package/lib/dist/search/query-parser.js.map +1 -1
- package/lib/dist/server/project-registry.js +1 -1
- package/lib/dist/server/routes/claude.js +24 -43
- package/lib/dist/server/routes/graph.js +53 -7
- package/lib/dist/server/routes/knowledge.js +118 -0
- package/lib/dist/server/routes/mcp.js +4 -3
- package/lib/dist/server/routes/projects.js +4 -4
- package/lib/dist/server/routes/spec.js +49 -7
- package/lib/dist/server/server.js +31 -17
- package/lib/dist/skills/spec-author/SKILL.md +164 -0
- package/lib/dist/skills/spec-author/references/format.md +210 -0
- package/lib/dist/skills/spec-author/references/gap-questions.md +152 -0
- package/lib/dist/skills/spec-author/references/quality-rubric.md +125 -0
- package/lib/dist/skills/spec-author/references/review-checklist.md +175 -0
- package/lib/dist/spec-lint/lint.d.ts +82 -0
- package/lib/dist/spec-lint/lint.d.ts.map +1 -0
- package/lib/dist/spec-lint/lint.js +491 -0
- package/lib/dist/spec-lint/lint.js.map +1 -0
- package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
- package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
- package/lib/dist/spec-quality/criterion-ids.js +38 -0
- package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.js +183 -0
- package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
- package/lib/dist/spec-quality/link-persist.d.ts +65 -0
- package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
- package/lib/dist/spec-quality/link-persist.js +249 -0
- package/lib/dist/spec-quality/link-persist.js.map +1 -0
- package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
- package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
- package/lib/dist/spec-quality/plan-scope.js +129 -0
- package/lib/dist/spec-quality/plan-scope.js.map +1 -0
- package/lib/dist/spec-quality/postcheck.d.ts +85 -0
- package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
- package/lib/dist/spec-quality/postcheck.js +390 -0
- package/lib/dist/spec-quality/postcheck.js.map +1 -0
- package/lib/dist/spec-quality/readiness.d.ts +72 -0
- package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
- package/lib/dist/spec-quality/readiness.js +226 -0
- package/lib/dist/spec-quality/readiness.js.map +1 -0
- package/lib/dist/statusline/index.js.map +1 -1
- package/lib/dist/statusline/render.d.ts +1 -1
- package/lib/dist/statusline/render.d.ts.map +1 -1
- package/lib/dist/statusline/render.js +3 -1
- package/lib/dist/statusline/render.js.map +1 -1
- package/lib/dist/ui/assets/index-BzuUWUAE.js +50 -0
- package/lib/dist/ui/index.html +1 -1
- package/lib/dist/verify/report-ingest.d.ts +88 -0
- package/lib/dist/verify/report-ingest.d.ts.map +1 -0
- package/lib/dist/verify/report-ingest.js +269 -0
- package/lib/dist/verify/report-ingest.js.map +1 -0
- package/lib/dist/workflows/agents/claude.d.ts +16 -0
- package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
- package/lib/dist/workflows/agents/claude.js +82 -0
- package/lib/dist/workflows/agents/claude.js.map +1 -0
- package/lib/dist/workflows/agents/gemini.d.ts +21 -0
- package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
- package/lib/dist/workflows/agents/gemini.js +124 -0
- package/lib/dist/workflows/agents/gemini.js.map +1 -0
- package/lib/dist/workflows/agents/index.d.ts +28 -0
- package/lib/dist/workflows/agents/index.d.ts.map +1 -0
- package/lib/dist/workflows/agents/index.js +104 -0
- package/lib/dist/workflows/agents/index.js.map +1 -0
- package/lib/dist/workflows/agents/types.d.ts +55 -0
- package/lib/dist/workflows/agents/types.d.ts.map +1 -0
- package/lib/dist/workflows/agents/types.js +46 -0
- package/lib/dist/workflows/agents/types.js.map +1 -0
- package/lib/dist/workflows/batch.d.ts +63 -0
- package/lib/dist/workflows/batch.d.ts.map +1 -0
- package/lib/dist/workflows/batch.js +151 -0
- package/lib/dist/workflows/batch.js.map +1 -0
- package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -4
- package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
- package/lib/dist/workflows/defaults/spec-fix.yaml +103 -12
- package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -193
- package/lib/dist/workflows/defaults/spec-implement.yaml +701 -41
- package/lib/dist/workflows/defaults/spec-verify.yaml +60 -9
- package/lib/dist/workflows/discovery.d.ts +13 -0
- package/lib/dist/workflows/discovery.d.ts.map +1 -1
- package/lib/dist/workflows/discovery.js +79 -17
- package/lib/dist/workflows/discovery.js.map +1 -1
- package/lib/dist/workflows/executor.d.ts +18 -0
- package/lib/dist/workflows/executor.d.ts.map +1 -1
- package/lib/dist/workflows/executor.js +130 -33
- package/lib/dist/workflows/executor.js.map +1 -1
- package/lib/dist/workflows/gc.d.ts +50 -0
- package/lib/dist/workflows/gc.d.ts.map +1 -0
- package/lib/dist/workflows/gc.js +120 -0
- package/lib/dist/workflows/gc.js.map +1 -0
- package/lib/dist/workflows/merge-queue.d.ts +64 -0
- package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
- package/lib/dist/workflows/merge-queue.js +162 -0
- package/lib/dist/workflows/merge-queue.js.map +1 -0
- package/lib/dist/workflows/runners/approval.d.ts +1 -1
- package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
- package/lib/dist/workflows/runners/approval.js +11 -2
- package/lib/dist/workflows/runners/approval.js.map +1 -1
- package/lib/dist/workflows/runners/bash.d.ts +15 -0
- package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
- package/lib/dist/workflows/runners/bash.js +50 -1
- package/lib/dist/workflows/runners/bash.js.map +1 -1
- package/lib/dist/workflows/runners/prompt.d.ts +16 -41
- package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
- package/lib/dist/workflows/runners/prompt.js +55 -120
- package/lib/dist/workflows/runners/prompt.js.map +1 -1
- package/lib/dist/workflows/runners/types.d.ts +12 -0
- package/lib/dist/workflows/runners/types.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
- package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.js +27 -0
- package/lib/dist/workflows/schemas/workflow.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +8 -4
- package/package.json +5 -3
- package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/lib/dist/server/ingest/impact-query.js +0 -343
- package/lib/dist/server/routes/events.js +0 -152
- package/lib/dist/ui/assets/index-CjjaftDw.js +0 -50
- package/node.exe +0 -4
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic spec linter (AUTHG-DOC, REQ-AUTHG-001).
|
|
3
|
+
*
|
|
4
|
+
* Every structural check in the spec-author review checklist used to be an LLM
|
|
5
|
+
* eyeballing the draft. This module performs them mechanically: it reuses
|
|
6
|
+
* `MarkdownSpecExtractor`'s own errors (so the lint and the indexer agree about
|
|
7
|
+
* what a spec file means) and adds the checks the extractor has no reason to
|
|
8
|
+
* make — duplicate ids, orphaned `.A<N>` parents, requirements with no
|
|
9
|
+
* acceptance criteria, unresolved `[needs review]` markers, plus a set of
|
|
10
|
+
* advisory quality warnings.
|
|
11
|
+
*
|
|
12
|
+
* Pure over the file system at the edges only: `lintSpecSource` is a pure
|
|
13
|
+
* function of (path, source), which is what the tests drive. Nothing here
|
|
14
|
+
* writes, and nothing here needs a database — a lint must be runnable on a
|
|
15
|
+
* spec file that has never been indexed.
|
|
16
|
+
*/
|
|
17
|
+
export type LintSeverity = 'error' | 'warning';
|
|
18
|
+
/**
|
|
19
|
+
* Stable finding codes. Extractor-produced findings keep the extractor's own
|
|
20
|
+
* code (`spec_missing_id`, `spec_stranded_id`, `spec_bare_path_ref`,
|
|
21
|
+
* `spec_acceptance_parent_mismatch`) so one vocabulary spans both layers.
|
|
22
|
+
*/
|
|
23
|
+
export type LintCode = 'spec_duplicate_id' | 'spec_orphan_acceptance_parent' | 'spec_requirement_without_acceptance' | 'spec_needs_review_marker' | 'spec_unknown_evidence_kind' | 'spec_external_fact_missing_provenance' | 'spec_malformed_enforced_rule' | 'spec_no_negative_case' | 'spec_missing_non_goals' | 'spec_missing_test_plan' | 'spec_requirement_without_rfc2119' | string;
|
|
24
|
+
export interface LintFinding {
|
|
25
|
+
code: LintCode;
|
|
26
|
+
severity: LintSeverity;
|
|
27
|
+
/** Project-relative path of the spec file. */
|
|
28
|
+
filePath: string;
|
|
29
|
+
/** 1-indexed line, when the finding has one. */
|
|
30
|
+
line?: number;
|
|
31
|
+
/** The spec id the finding is about, when it has one. */
|
|
32
|
+
specId?: string;
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
export interface LintFileReport {
|
|
36
|
+
filePath: string;
|
|
37
|
+
findings: LintFinding[];
|
|
38
|
+
errorCount: number;
|
|
39
|
+
warningCount: number;
|
|
40
|
+
}
|
|
41
|
+
export interface LintReport {
|
|
42
|
+
/** One entry per linted file, sorted by path — the stable grouping (A4). */
|
|
43
|
+
files: LintFileReport[];
|
|
44
|
+
filesChecked: number;
|
|
45
|
+
errorCount: number;
|
|
46
|
+
warningCount: number;
|
|
47
|
+
/** The exit-code predicate (A3): errors fail, warnings alone do not. */
|
|
48
|
+
hasErrors: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Lint one spec file's source. `filePath` is used verbatim in findings, so
|
|
52
|
+
* callers should pass a project-relative path.
|
|
53
|
+
*/
|
|
54
|
+
export declare function lintSpecSource(filePath: string, source: string): LintFinding[];
|
|
55
|
+
export interface LintOptions {
|
|
56
|
+
/** Root that finding paths are made relative to. Defaults to `process.cwd()`. */
|
|
57
|
+
projectRoot?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Lint every `.md` under each path (a path may be a file or a directory).
|
|
61
|
+
* A path that does not exist contributes an error finding rather than throwing —
|
|
62
|
+
* a typo'd argument must not look like a clean run.
|
|
63
|
+
*/
|
|
64
|
+
export declare function lintSpecs(paths: string[], options?: LintOptions): LintReport;
|
|
65
|
+
/**
|
|
66
|
+
* Human-readable, file-grouped rendering (A4). Files with no findings are
|
|
67
|
+
* summarized in the tail count rather than listed, so a clean corpus prints
|
|
68
|
+
* one line.
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatLintReport(report: LintReport): string;
|
|
71
|
+
/**
|
|
72
|
+
* CLI entry point, kept here so registering the subcommand is three lines in
|
|
73
|
+
* `src/bin/specship.ts`. Returns the text to print and the process exit code
|
|
74
|
+
* (A3) instead of writing or exiting itself — that is what makes it testable.
|
|
75
|
+
*
|
|
76
|
+
* Usage: `specship lint [path...] [--json]`
|
|
77
|
+
*/
|
|
78
|
+
export declare function runLintCli(args?: string[], options?: LintOptions): {
|
|
79
|
+
output: string;
|
|
80
|
+
exitCode: number;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/spec-lint/lint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAEhB,mBAAmB,GACnB,+BAA+B,GAC/B,qCAAqC,GACrC,0BAA0B,GAC1B,4BAA4B,GAC5B,uCAAuC,GACvC,8BAA8B,GAE9B,uBAAuB,GACvB,wBAAwB,GACxB,wBAAwB,GACxB,kCAAkC,GAElC,MAAM,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,SAAS,EAAE,OAAO,CAAC;CACpB;AAkHD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CA2K9E;AA+DD,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,WAAgB,GAAG,UAAU,CAmEhF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAc3D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,GAAE,MAAM,EAAO,EACnB,OAAO,GAAE,WAAgB,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAQtC"}
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic spec linter (AUTHG-DOC, REQ-AUTHG-001).
|
|
4
|
+
*
|
|
5
|
+
* Every structural check in the spec-author review checklist used to be an LLM
|
|
6
|
+
* eyeballing the draft. This module performs them mechanically: it reuses
|
|
7
|
+
* `MarkdownSpecExtractor`'s own errors (so the lint and the indexer agree about
|
|
8
|
+
* what a spec file means) and adds the checks the extractor has no reason to
|
|
9
|
+
* make — duplicate ids, orphaned `.A<N>` parents, requirements with no
|
|
10
|
+
* acceptance criteria, unresolved `[needs review]` markers, plus a set of
|
|
11
|
+
* advisory quality warnings.
|
|
12
|
+
*
|
|
13
|
+
* Pure over the file system at the edges only: `lintSpecSource` is a pure
|
|
14
|
+
* function of (path, source), which is what the tests drive. Nothing here
|
|
15
|
+
* writes, and nothing here needs a database — a lint must be runnable on a
|
|
16
|
+
* spec file that has never been indexed.
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.lintSpecSource = lintSpecSource;
|
|
53
|
+
exports.lintSpecs = lintSpecs;
|
|
54
|
+
exports.formatLintReport = formatLintReport;
|
|
55
|
+
exports.runLintCli = runLintCli;
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const markdown_spec_extractor_1 = require("../extraction/specs/markdown-spec-extractor");
|
|
59
|
+
const evidence_kind_1 = require("../spec-quality/evidence-kind");
|
|
60
|
+
const enforce_1 = require("../knowledge/enforce");
|
|
61
|
+
/**
|
|
62
|
+
* Mirrors the extractor's private `ID_COMMENT`. Duplicated rather than
|
|
63
|
+
* imported because the extractor does not export it and its module is off
|
|
64
|
+
* limits to this one; the two MUST stay in sync — a marker the extractor
|
|
65
|
+
* recognizes and this does not would hide duplicate ids.
|
|
66
|
+
*/
|
|
67
|
+
const ID_COMMENT_LINE = /^\s*<!--\s*id\s*:\s*([^\s-][^\s]*)\s*-->\s*$/;
|
|
68
|
+
/** RFC 2119 requirement keywords (A2). Case-insensitive: authors write both. */
|
|
69
|
+
const RFC_2119 = /\b(MUST|MUST NOT|SHALL|SHALL NOT|SHOULD|SHOULD NOT|MAY|REQUIRED|RECOMMENDED|OPTIONAL)\b/i;
|
|
70
|
+
/**
|
|
71
|
+
* Negative-case vocabulary (A2). A requirement whose criteria never mention a
|
|
72
|
+
* refusal, a failure, or an absence is almost always specifying only the happy
|
|
73
|
+
* path. Heuristic by construction — hence a warning, never an error.
|
|
74
|
+
*/
|
|
75
|
+
const NEGATIVE_CASE = new RegExp([
|
|
76
|
+
'reject', 'refus', 'invalid', 'malformed', 'error', 'fail', 'failure',
|
|
77
|
+
'missing', 'absent', 'empty', 'never', 'without', 'unauthorized',
|
|
78
|
+
'forbidden', 'non-zero', 'not found', 'no match', 'unmatched', 'denied',
|
|
79
|
+
'conflict', 'timeout', 'exceed', 'cannot', "can't", 'must not',
|
|
80
|
+
'does not', "doesn't", 'is not', "isn't", 'no ',
|
|
81
|
+
].join('|'), 'i');
|
|
82
|
+
/** `## Non-goals` (or prose "non-goal") anywhere in the document. */
|
|
83
|
+
const NON_GOALS = /non[- ]goals?/i;
|
|
84
|
+
/**
|
|
85
|
+
* A test-plan signal: a `verifies:` link block, an `@verifies` marker, or prose
|
|
86
|
+
* naming a test plan. Any one of them means the author thought about evidence.
|
|
87
|
+
*/
|
|
88
|
+
const TEST_PLAN = /(^|\n)\s*verifies:|@verifies|test plan|test-plan/i;
|
|
89
|
+
/** An unresolved authoring marker that must not survive into a written spec. */
|
|
90
|
+
const NEEDS_REVIEW = /\[needs\s+review\]/i;
|
|
91
|
+
/**
|
|
92
|
+
* Drop inline code spans and fenced blocks before scanning prose. A spec that
|
|
93
|
+
* documents the marker syntax writes `` `[needs review]` `` in backticks and is
|
|
94
|
+
* not itself unresolved — without this, the lint flags the requirement that
|
|
95
|
+
* defines the lint.
|
|
96
|
+
*/
|
|
97
|
+
function stripCode(text) {
|
|
98
|
+
return text.replace(/```[\s\S]*?```/g, ' ').replace(/`[^`]*`/g, ' ');
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* True for a file that lives under `specs/` without being a spec: a brainstorm
|
|
102
|
+
* brief (`brief.md`) or a design handoff-bundle transcript (`source.md`, the
|
|
103
|
+
* designer convention). Neither carries id-marked headings by design, so every
|
|
104
|
+
* structural check below would fire on every heading.
|
|
105
|
+
*/
|
|
106
|
+
function isNonSpecArtifact(filePath) {
|
|
107
|
+
const base = (filePath.split(/[/\\]/).pop() ?? '').toLowerCase();
|
|
108
|
+
return base === 'brief.md' || base === 'source.md';
|
|
109
|
+
}
|
|
110
|
+
/** True for a domain fact — frontmatter-keyed, no requirement structure. */
|
|
111
|
+
function isDomainFile(filePath) {
|
|
112
|
+
return filePath.replace(/\\/g, '/').includes('specs/domain/');
|
|
113
|
+
}
|
|
114
|
+
/** The provenance an external fact must carry (REQ-KNOW-001). */
|
|
115
|
+
const EXTERNAL_PROVENANCE = ['dependency', 'version', 'source'];
|
|
116
|
+
/**
|
|
117
|
+
* Domain-fact checks (KNOWLEDGE-DOC):
|
|
118
|
+
* - an `external` fact missing `dependency` / `version` / `source` is an
|
|
119
|
+
* error naming the missing field(s) (REQ-KNOW-001.A2) — it still indexes;
|
|
120
|
+
* - an `## Enforced` bullet not of the form `` `<glob>` must not match
|
|
121
|
+
* `/<regex>/` `` is an error (REQ-KNOW-003.A3).
|
|
122
|
+
*/
|
|
123
|
+
function lintDomainFact(specs, source, add) {
|
|
124
|
+
const fact = specs.find((s) => s.kind === 'domain');
|
|
125
|
+
if (fact) {
|
|
126
|
+
const meta = (fact.metadata ?? {});
|
|
127
|
+
if (meta.type === 'external') {
|
|
128
|
+
const missing = EXTERNAL_PROVENANCE.filter((k) => {
|
|
129
|
+
const v = meta[k];
|
|
130
|
+
return !(typeof v === 'number' || (typeof v === 'string' && v.trim().length > 0));
|
|
131
|
+
});
|
|
132
|
+
if (missing.length > 0) {
|
|
133
|
+
add({
|
|
134
|
+
code: 'spec_external_fact_missing_provenance',
|
|
135
|
+
severity: 'error',
|
|
136
|
+
line: 1,
|
|
137
|
+
specId: fact.id,
|
|
138
|
+
message: `External fact ${fact.id} is missing ${missing.join(', ')} — an external fact must record the dependency, the version it was verified against, and its source.`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Parsed over the whole source so the line numbers are file lines; the
|
|
144
|
+
// frontmatter can't contain a `## Enforced` heading.
|
|
145
|
+
for (const m of (0, enforce_1.parseEnforcedRules)(source).malformed) {
|
|
146
|
+
add({
|
|
147
|
+
code: 'spec_malformed_enforced_rule',
|
|
148
|
+
severity: 'error',
|
|
149
|
+
line: m.line,
|
|
150
|
+
specId: fact?.id,
|
|
151
|
+
message: `Malformed enforced rule "${m.text}": ${m.reason}.`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Lint one spec file's source. `filePath` is used verbatim in findings, so
|
|
157
|
+
* callers should pass a project-relative path.
|
|
158
|
+
*/
|
|
159
|
+
function lintSpecSource(filePath, source) {
|
|
160
|
+
const findings = [];
|
|
161
|
+
const add = (f) => findings.push({ ...f, filePath });
|
|
162
|
+
// A brief or a design-handoff transcript is not a spec and is not held to a
|
|
163
|
+
// spec's shape — including the extractor's own `spec_missing_id`, which every
|
|
164
|
+
// heading in a transcript would trip. Nothing to report, at all.
|
|
165
|
+
if (isNonSpecArtifact(filePath))
|
|
166
|
+
return findings;
|
|
167
|
+
const lines = source.split(/\r?\n/);
|
|
168
|
+
const result = new markdown_spec_extractor_1.MarkdownSpecExtractor(filePath, source).extract();
|
|
169
|
+
// 1. The extractor's own verdict, carried through unchanged (A1). Its
|
|
170
|
+
// severities are already right: a missing id is an error, a bare-path link
|
|
171
|
+
// bullet is a warning (the no-edge pointer is legal, just invisible).
|
|
172
|
+
for (const e of result.errors) {
|
|
173
|
+
add({
|
|
174
|
+
code: e.code ?? 'spec_extraction_error',
|
|
175
|
+
severity: e.severity === 'error' ? 'error' : 'warning',
|
|
176
|
+
line: e.line,
|
|
177
|
+
message: e.message,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// 2. Duplicate ids within the file (A1). The persistence layer upserts by id,
|
|
181
|
+
// so the LAST occurrence wins and the earlier section silently vanishes.
|
|
182
|
+
const seen = new Map();
|
|
183
|
+
for (let i = 0; i < lines.length; i++) {
|
|
184
|
+
const m = (lines[i] ?? '').match(ID_COMMENT_LINE);
|
|
185
|
+
const id = m?.[1];
|
|
186
|
+
if (!id)
|
|
187
|
+
continue;
|
|
188
|
+
const first = seen.get(id);
|
|
189
|
+
if (first !== undefined) {
|
|
190
|
+
add({
|
|
191
|
+
code: 'spec_duplicate_id',
|
|
192
|
+
severity: 'error',
|
|
193
|
+
line: i + 1,
|
|
194
|
+
specId: id,
|
|
195
|
+
message: `Duplicate id ${id} (first declared on line ${first}). The last occurrence overwrites earlier ones, so the earlier section is lost.`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
seen.set(id, i + 1);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// A domain fact keeps the extractor's verdict (its frontmatter can genuinely
|
|
203
|
+
// be malformed) but has no requirement/acceptance structure to check. It has
|
|
204
|
+
// its own two checks instead (KNOWLEDGE-DOC).
|
|
205
|
+
if (isDomainFile(filePath)) {
|
|
206
|
+
lintDomainFact(result.specs, source, add);
|
|
207
|
+
return sortFindings(findings);
|
|
208
|
+
}
|
|
209
|
+
const declared = new Set([...seen.keys(), ...result.specs.map((s) => s.id)]);
|
|
210
|
+
const acceptance = result.specs.filter((s) => s.kind === 'acceptance');
|
|
211
|
+
const requirements = result.specs.filter((s) => s.kind === 'requirement');
|
|
212
|
+
// 3. An `.A<N>` id whose parent requirement is nowhere in the file (A1). The
|
|
213
|
+
// extractor parents it anyway (by id), so nothing complains at index time
|
|
214
|
+
// while the criterion hangs off a requirement that doesn't exist.
|
|
215
|
+
for (const spec of result.specs) {
|
|
216
|
+
const parent = (0, markdown_spec_extractor_1.parseAcceptanceParentId)(spec.id);
|
|
217
|
+
if (parent && !declared.has(parent)) {
|
|
218
|
+
add({
|
|
219
|
+
code: 'spec_orphan_acceptance_parent',
|
|
220
|
+
severity: 'error',
|
|
221
|
+
line: spec.startLine,
|
|
222
|
+
specId: spec.id,
|
|
223
|
+
message: `${spec.id} names ${parent} as its parent requirement, but ${parent} is not declared in this file.`,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// 4. A requirement with no acceptance criteria (A1) — unverifiable by
|
|
228
|
+
// construction, and invisible to the behaviour gate.
|
|
229
|
+
for (const req of requirements) {
|
|
230
|
+
const children = acceptance.filter((a) => a.parentId === req.id);
|
|
231
|
+
if (children.length === 0) {
|
|
232
|
+
add({
|
|
233
|
+
code: 'spec_requirement_without_acceptance',
|
|
234
|
+
severity: 'error',
|
|
235
|
+
line: req.startLine,
|
|
236
|
+
specId: req.id,
|
|
237
|
+
message: `${req.id} has no acceptance criteria — nothing can verify it.`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// 5. `[needs review]` left inside an acceptance bullet (A1).
|
|
242
|
+
for (const a of acceptance) {
|
|
243
|
+
if (NEEDS_REVIEW.test(stripCode(a.body))) {
|
|
244
|
+
add({
|
|
245
|
+
code: 'spec_needs_review_marker',
|
|
246
|
+
severity: 'error',
|
|
247
|
+
line: a.startLine,
|
|
248
|
+
specId: a.id,
|
|
249
|
+
message: `${a.id} still carries a [needs review] marker.`,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// 5b. An `(evidence: <kind>)` tag naming a kind outside the four
|
|
254
|
+
// (REQ-PIPETRUST-001.A3). Resolution would silently fall back to the
|
|
255
|
+
// derived kind, so the author's intent would be lost — an error.
|
|
256
|
+
for (const a of acceptance) {
|
|
257
|
+
const { invalid } = (0, evidence_kind_1.parseDeclaredEvidenceKind)(a.body);
|
|
258
|
+
if (invalid !== undefined) {
|
|
259
|
+
add({
|
|
260
|
+
code: 'spec_unknown_evidence_kind',
|
|
261
|
+
severity: 'error',
|
|
262
|
+
line: a.startLine,
|
|
263
|
+
specId: a.id,
|
|
264
|
+
message: `${a.id} declares unknown evidence kind "${invalid}" — use one of ${evidence_kind_1.EVIDENCE_KINDS.join(', ')}.`,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// 6. Happy-path-only requirements (A2, warning).
|
|
269
|
+
for (const req of requirements) {
|
|
270
|
+
const children = acceptance.filter((a) => a.parentId === req.id);
|
|
271
|
+
if (children.length === 0)
|
|
272
|
+
continue; // already an error above
|
|
273
|
+
if (!children.some((a) => NEGATIVE_CASE.test(a.body))) {
|
|
274
|
+
add({
|
|
275
|
+
code: 'spec_no_negative_case',
|
|
276
|
+
severity: 'warning',
|
|
277
|
+
line: req.startLine,
|
|
278
|
+
specId: req.id,
|
|
279
|
+
message: `${req.id} has no negative-case acceptance criterion (no refusal, failure, or absence is specified).`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// 7. A requirement stating no obligation (A2, warning). Scoped to the
|
|
284
|
+
// requirement's own title and body, NOT its bullets: house style writes
|
|
285
|
+
// acceptance criteria declaratively ("- The tile shows no delta…"), so a
|
|
286
|
+
// per-bullet check fires on essentially every criterion in the corpus and
|
|
287
|
+
// carries no signal. The obligation belongs on the requirement.
|
|
288
|
+
for (const req of requirements) {
|
|
289
|
+
const children = acceptance.filter((a) => a.parentId === req.id);
|
|
290
|
+
const prose = requirementProse(lines, req, children);
|
|
291
|
+
if (!RFC_2119.test(req.title) && !RFC_2119.test(prose)) {
|
|
292
|
+
add({
|
|
293
|
+
code: 'spec_requirement_without_rfc2119',
|
|
294
|
+
severity: 'warning',
|
|
295
|
+
line: req.startLine,
|
|
296
|
+
specId: req.id,
|
|
297
|
+
message: `${req.id} states no requirement keyword (MUST / SHOULD / MAY) in its title or body — its obligation is ambiguous.`,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// 8. Document-level signals the review checklist asks for (A2, warnings).
|
|
302
|
+
// Only meaningful for a file that actually declares requirements.
|
|
303
|
+
if (requirements.length > 0) {
|
|
304
|
+
if (!NON_GOALS.test(source)) {
|
|
305
|
+
add({
|
|
306
|
+
code: 'spec_missing_non_goals',
|
|
307
|
+
severity: 'warning',
|
|
308
|
+
message: 'No non-goals stated — scope has no stated boundary.',
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (!TEST_PLAN.test(source)) {
|
|
312
|
+
add({
|
|
313
|
+
code: 'spec_missing_test_plan',
|
|
314
|
+
severity: 'warning',
|
|
315
|
+
message: 'No test-evidence signal (`verifies:` block, `@verifies`, or a test plan) — nothing declares how this gets verified.',
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return sortFindings(findings);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* A requirement's own prose: its body minus the acceptance criteria that live
|
|
323
|
+
* inside it. `Spec.body` spans everything under the heading, criteria included,
|
|
324
|
+
* so scanning it for an obligation keyword would read the bullets' wording
|
|
325
|
+
* back — exactly what the requirement-level check exists to avoid.
|
|
326
|
+
*/
|
|
327
|
+
function requirementProse(lines, req, children) {
|
|
328
|
+
const from = (req.startLine ?? 1) + 1; // 1-indexed, excluding the heading
|
|
329
|
+
const to = req.endLine ?? lines.length;
|
|
330
|
+
const covered = (n) => children.some((c) => n >= (c.startLine ?? 0) && n <= (c.endLine ?? c.startLine ?? 0));
|
|
331
|
+
const out = [];
|
|
332
|
+
for (let n = from; n <= to && n <= lines.length; n++) {
|
|
333
|
+
const line = lines[n - 1] ?? '';
|
|
334
|
+
if (covered(n))
|
|
335
|
+
continue;
|
|
336
|
+
if (/^\s*#{1,6}\s*acceptance\s*$/i.test(line))
|
|
337
|
+
continue;
|
|
338
|
+
out.push(line);
|
|
339
|
+
}
|
|
340
|
+
return out.join('\n');
|
|
341
|
+
}
|
|
342
|
+
/** Stable order within a file: by line, then code, then message. */
|
|
343
|
+
function sortFindings(findings) {
|
|
344
|
+
return findings.sort((a, b) => (a.line ?? Number.MAX_SAFE_INTEGER) - (b.line ?? Number.MAX_SAFE_INTEGER) ||
|
|
345
|
+
a.code.localeCompare(b.code) ||
|
|
346
|
+
a.message.localeCompare(b.message));
|
|
347
|
+
}
|
|
348
|
+
/** Collect `.md` files under a path (file → itself). Hidden dirs skipped. */
|
|
349
|
+
function collectSpecFiles(target, out) {
|
|
350
|
+
let stat;
|
|
351
|
+
try {
|
|
352
|
+
stat = fs.statSync(target);
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (stat.isFile()) {
|
|
358
|
+
if (target.toLowerCase().endsWith('.md'))
|
|
359
|
+
out.push(target);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (!stat.isDirectory())
|
|
363
|
+
return;
|
|
364
|
+
let entries;
|
|
365
|
+
try {
|
|
366
|
+
entries = fs.readdirSync(target, { withFileTypes: true });
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
for (const entry of entries) {
|
|
372
|
+
const full = path.join(target, entry.name);
|
|
373
|
+
if (entry.isDirectory()) {
|
|
374
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
375
|
+
continue;
|
|
376
|
+
collectSpecFiles(full, out);
|
|
377
|
+
}
|
|
378
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
|
|
379
|
+
out.push(full);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Lint every `.md` under each path (a path may be a file or a directory).
|
|
385
|
+
* A path that does not exist contributes an error finding rather than throwing —
|
|
386
|
+
* a typo'd argument must not look like a clean run.
|
|
387
|
+
*/
|
|
388
|
+
function lintSpecs(paths, options = {}) {
|
|
389
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
390
|
+
const files = [];
|
|
391
|
+
const targets = paths.length > 0 ? paths : [path.join(projectRoot, 'specs')];
|
|
392
|
+
const absFiles = [];
|
|
393
|
+
for (const target of targets) {
|
|
394
|
+
const abs = path.isAbsolute(target) ? target : path.join(projectRoot, target);
|
|
395
|
+
if (!fs.existsSync(abs)) {
|
|
396
|
+
files.push({
|
|
397
|
+
filePath: path.relative(projectRoot, abs) || target,
|
|
398
|
+
findings: [
|
|
399
|
+
{
|
|
400
|
+
code: 'lint_path_not_found',
|
|
401
|
+
severity: 'error',
|
|
402
|
+
filePath: path.relative(projectRoot, abs) || target,
|
|
403
|
+
message: `No such file or directory: ${target}`,
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
errorCount: 1,
|
|
407
|
+
warningCount: 0,
|
|
408
|
+
});
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
collectSpecFiles(abs, absFiles);
|
|
412
|
+
}
|
|
413
|
+
for (const abs of [...new Set(absFiles)].sort()) {
|
|
414
|
+
const rel = path.relative(projectRoot, abs) || abs;
|
|
415
|
+
let source;
|
|
416
|
+
try {
|
|
417
|
+
source = fs.readFileSync(abs, 'utf-8');
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
files.push({
|
|
421
|
+
filePath: rel,
|
|
422
|
+
findings: [
|
|
423
|
+
{
|
|
424
|
+
code: 'lint_unreadable_file',
|
|
425
|
+
severity: 'error',
|
|
426
|
+
filePath: rel,
|
|
427
|
+
message: `Could not read: ${err instanceof Error ? err.message : String(err)}`,
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
errorCount: 1,
|
|
431
|
+
warningCount: 0,
|
|
432
|
+
});
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const findings = lintSpecSource(rel, source);
|
|
436
|
+
files.push({
|
|
437
|
+
filePath: rel,
|
|
438
|
+
findings,
|
|
439
|
+
errorCount: findings.filter((f) => f.severity === 'error').length,
|
|
440
|
+
warningCount: findings.filter((f) => f.severity === 'warning').length,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
files.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
444
|
+
const errorCount = files.reduce((n, f) => n + f.errorCount, 0);
|
|
445
|
+
const warningCount = files.reduce((n, f) => n + f.warningCount, 0);
|
|
446
|
+
return {
|
|
447
|
+
files,
|
|
448
|
+
filesChecked: files.length,
|
|
449
|
+
errorCount,
|
|
450
|
+
warningCount,
|
|
451
|
+
hasErrors: errorCount > 0,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Human-readable, file-grouped rendering (A4). Files with no findings are
|
|
456
|
+
* summarized in the tail count rather than listed, so a clean corpus prints
|
|
457
|
+
* one line.
|
|
458
|
+
*/
|
|
459
|
+
function formatLintReport(report) {
|
|
460
|
+
const out = [];
|
|
461
|
+
for (const file of report.files) {
|
|
462
|
+
if (file.findings.length === 0)
|
|
463
|
+
continue;
|
|
464
|
+
out.push(file.filePath);
|
|
465
|
+
for (const f of file.findings) {
|
|
466
|
+
const where = f.line !== undefined ? `:${f.line}` : '';
|
|
467
|
+
out.push(` ${f.severity === 'error' ? 'error' : 'warn '} ${f.code}${where} — ${f.message}`);
|
|
468
|
+
}
|
|
469
|
+
out.push('');
|
|
470
|
+
}
|
|
471
|
+
const counts = `${report.errorCount} error(s), ${report.warningCount} warning(s) in ${report.filesChecked} file(s)`;
|
|
472
|
+
out.push(report.errorCount === 0 && report.warningCount === 0 ? `Clean — ${counts}` : counts);
|
|
473
|
+
return out.join('\n');
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* CLI entry point, kept here so registering the subcommand is three lines in
|
|
477
|
+
* `src/bin/specship.ts`. Returns the text to print and the process exit code
|
|
478
|
+
* (A3) instead of writing or exiting itself — that is what makes it testable.
|
|
479
|
+
*
|
|
480
|
+
* Usage: `specship lint [path...] [--json]`
|
|
481
|
+
*/
|
|
482
|
+
function runLintCli(args = [], options = {}) {
|
|
483
|
+
const json = args.includes('--json');
|
|
484
|
+
const paths = args.filter((a) => !a.startsWith('--'));
|
|
485
|
+
const report = lintSpecs(paths, options);
|
|
486
|
+
return {
|
|
487
|
+
output: json ? JSON.stringify(report, null, 2) : formatLintReport(report),
|
|
488
|
+
exitCode: report.hasErrors ? 1 : 0,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/spec-lint/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec ids named in free text, with criterion shorthand expanded
|
|
3
|
+
* (PIPETRUST-DOC, REQ-PIPETRUST-008).
|
|
4
|
+
*
|
|
5
|
+
* Test titles cite several criteria of one requirement in shorthand —
|
|
6
|
+
* `REQ-X-004.A1/A3`, `REQ-X-028.A2/.A3`, `REQ-X-001.A1 / A3`. Reading only the
|
|
7
|
+
* first id left the rest silently unlinked, so the title scanner and postcheck
|
|
8
|
+
* share this one parser. A bare `A2` with no preceding full id names nothing,
|
|
9
|
+
* and ids match whole: `REQ-X.A10` never yields `REQ-X.A1`.
|
|
10
|
+
*/
|
|
11
|
+
/** Every spec id `text` names, shorthand expanded, in order of appearance (duplicates kept). */
|
|
12
|
+
export declare function criterionIdsInText(text: string): string[];
|
|
13
|
+
//# sourceMappingURL=criterion-ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criterion-ids.d.ts","sourceRoot":"","sources":["../../src/spec-quality/criterion-ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,gGAAgG;AAChG,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBzD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Spec ids named in free text, with criterion shorthand expanded
|
|
4
|
+
* (PIPETRUST-DOC, REQ-PIPETRUST-008).
|
|
5
|
+
*
|
|
6
|
+
* Test titles cite several criteria of one requirement in shorthand —
|
|
7
|
+
* `REQ-X-004.A1/A3`, `REQ-X-028.A2/.A3`, `REQ-X-001.A1 / A3`. Reading only the
|
|
8
|
+
* first id left the rest silently unlinked, so the title scanner and postcheck
|
|
9
|
+
* share this one parser. A bare `A2` with no preceding full id names nothing,
|
|
10
|
+
* and ids match whole: `REQ-X.A10` never yields `REQ-X.A1`.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.criterionIdsInText = criterionIdsInText;
|
|
14
|
+
/** A full spec id, an optional `.A<N>` suffix, then any `/A<N>`, `, .A<N>`, `& A<N>` continuations. */
|
|
15
|
+
const SPEC_ID_CHAIN = /\b([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+)(\.A\d+)?((?:\s*[/,&]\s*\.?A\d+\b)*)(?![\w-])/g;
|
|
16
|
+
const CONTINUATION = /\.?A(\d+)/g;
|
|
17
|
+
/** Every spec id `text` names, shorthand expanded, in order of appearance (duplicates kept). */
|
|
18
|
+
function criterionIdsInText(text) {
|
|
19
|
+
const out = [];
|
|
20
|
+
SPEC_ID_CHAIN.lastIndex = 0;
|
|
21
|
+
let m;
|
|
22
|
+
while ((m = SPEC_ID_CHAIN.exec(text)) !== null) {
|
|
23
|
+
const base = m[1];
|
|
24
|
+
const first = m[2];
|
|
25
|
+
if (!first) {
|
|
26
|
+
out.push(base);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
out.push(base + first);
|
|
30
|
+
const chain = m[3] ?? '';
|
|
31
|
+
CONTINUATION.lastIndex = 0;
|
|
32
|
+
let c;
|
|
33
|
+
while ((c = CONTINUATION.exec(chain)) !== null)
|
|
34
|
+
out.push(`${base}.A${c[1]}`);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=criterion-ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criterion-ids.js","sourceRoot":"","sources":["../../src/spec-quality/criterion-ids.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAQH,gDAkBC;AAxBD,uGAAuG;AACvG,MAAM,aAAa,GACjB,iFAAiF,CAAC;AACpF,MAAM,YAAY,GAAG,YAAY,CAAC;AAElC,gGAAgG;AAChG,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,aAAa,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACnB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzB,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAyB,CAAC;QAC9B,OAAO,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|