@sun-asterisk/sungen 3.2.34-beta.1 → 3.3.0-alpha.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/dist/basis/anchor-grammar.d.ts +32 -0
- package/dist/basis/anchor-grammar.d.ts.map +1 -0
- package/dist/basis/anchor-grammar.js +82 -0
- package/dist/basis/anchor-grammar.js.map +1 -0
- package/dist/basis/anchor-hash.d.ts +6 -0
- package/dist/basis/anchor-hash.d.ts.map +1 -0
- package/dist/basis/anchor-hash.js +28 -0
- package/dist/basis/anchor-hash.js.map +1 -0
- package/dist/basis/bm51-tables.d.ts +20 -0
- package/dist/basis/bm51-tables.d.ts.map +1 -0
- package/dist/basis/bm51-tables.js +71 -0
- package/dist/basis/bm51-tables.js.map +1 -0
- package/dist/basis/extract-spec-anchors.d.ts +39 -0
- package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
- package/dist/basis/extract-spec-anchors.js +81 -0
- package/dist/basis/extract-spec-anchors.js.map +1 -0
- package/dist/basis/migration-sentinel.d.ts +47 -0
- package/dist/basis/migration-sentinel.d.ts.map +1 -0
- package/dist/basis/migration-sentinel.js +219 -0
- package/dist/basis/migration-sentinel.js.map +1 -0
- package/dist/basis/spec-frontmatter.d.ts +18 -0
- package/dist/basis/spec-frontmatter.d.ts.map +1 -0
- package/dist/basis/spec-frontmatter.js +55 -0
- package/dist/basis/spec-frontmatter.js.map +1 -0
- package/dist/basis/spec-sections.d.ts +18 -0
- package/dist/basis/spec-sections.d.ts.map +1 -0
- package/dist/basis/spec-sections.js +27 -0
- package/dist/basis/spec-sections.js.map +1 -0
- package/dist/basis/test-basis-schema.d.ts +28 -0
- package/dist/basis/test-basis-schema.d.ts.map +1 -0
- package/dist/basis/test-basis-schema.js +141 -0
- package/dist/basis/test-basis-schema.js.map +1 -0
- package/dist/capabilities/registry.d.ts +15 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +3 -29
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.js +1 -1
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/contract-derive-command.d.ts +10 -0
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
- package/dist/cli/commands/contract-derive-command.js +99 -0
- package/dist/cli/commands/contract-derive-command.js.map +1 -0
- package/dist/cli/commands/contract.d.ts +17 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +162 -0
- package/dist/cli/commands/contract.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +52 -3
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +3 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/journey.d.ts.map +1 -1
- package/dist/cli/commands/journey.js +41 -13
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +8 -0
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +64 -6
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/update.d.ts +11 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +31 -6
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +20 -35
- package/dist/cli/index.js.map +1 -1
- package/dist/contract/approve-contract.d.ts +31 -0
- package/dist/contract/approve-contract.d.ts.map +1 -0
- package/dist/contract/approve-contract.js +87 -0
- package/dist/contract/approve-contract.js.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
- package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
- package/dist/contract/assertion-matcher-vocabulary.js +100 -0
- package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
- package/dist/contract/build-contract-verdict.d.ts +32 -0
- package/dist/contract/build-contract-verdict.d.ts.map +1 -0
- package/dist/contract/build-contract-verdict.js +123 -0
- package/dist/contract/build-contract-verdict.js.map +1 -0
- package/dist/contract/build-trace-conformance.d.ts +18 -0
- package/dist/contract/build-trace-conformance.d.ts.map +1 -0
- package/dist/contract/build-trace-conformance.js +153 -0
- package/dist/contract/build-trace-conformance.js.map +1 -0
- package/dist/contract/classify-contract-change.d.ts +23 -0
- package/dist/contract/classify-contract-change.d.ts.map +1 -0
- package/dist/contract/classify-contract-change.js +98 -0
- package/dist/contract/classify-contract-change.js.map +1 -0
- package/dist/contract/classify-contract-unit.d.ts +18 -0
- package/dist/contract/classify-contract-unit.d.ts.map +1 -0
- package/dist/contract/classify-contract-unit.js +49 -0
- package/dist/contract/classify-contract-unit.js.map +1 -0
- package/dist/contract/classify-trace-conformance.d.ts +32 -0
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
- package/dist/contract/classify-trace-conformance.js +117 -0
- package/dist/contract/classify-trace-conformance.js.map +1 -0
- package/dist/contract/contract-git.d.ts +24 -0
- package/dist/contract/contract-git.d.ts.map +1 -0
- package/dist/contract/contract-git.js +144 -0
- package/dist/contract/contract-git.js.map +1 -0
- package/dist/contract/contract-hash.d.ts +7 -0
- package/dist/contract/contract-hash.d.ts.map +1 -0
- package/dist/contract/contract-hash.js +38 -0
- package/dist/contract/contract-hash.js.map +1 -0
- package/dist/contract/contract-report-file.d.ts +4 -0
- package/dist/contract/contract-report-file.d.ts.map +1 -0
- package/dist/contract/contract-report-file.js +60 -0
- package/dist/contract/contract-report-file.js.map +1 -0
- package/dist/contract/contract-schema.d.ts +71 -0
- package/dist/contract/contract-schema.d.ts.map +1 -0
- package/dist/contract/contract-schema.js +102 -0
- package/dist/contract/contract-schema.js.map +1 -0
- package/dist/contract/contract-units.d.ts +12 -0
- package/dist/contract/contract-units.d.ts.map +1 -0
- package/dist/contract/contract-units.js +96 -0
- package/dist/contract/contract-units.js.map +1 -0
- package/dist/contract/contracts-lock-file.d.ts +24 -0
- package/dist/contract/contracts-lock-file.d.ts.map +1 -0
- package/dist/contract/contracts-lock-file.js +140 -0
- package/dist/contract/contracts-lock-file.js.map +1 -0
- package/dist/contract/data-normalize.d.ts +10 -0
- package/dist/contract/data-normalize.d.ts.map +1 -0
- package/dist/contract/data-normalize.js +110 -0
- package/dist/contract/data-normalize.js.map +1 -0
- package/dist/contract/derive-free-feature.d.ts +30 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -0
- package/dist/contract/derive-free-feature.js +145 -0
- package/dist/contract/derive-free-feature.js.map +1 -0
- package/dist/contract/field-semantic-redaction.d.ts +21 -0
- package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
- package/dist/contract/field-semantic-redaction.js +118 -0
- package/dist/contract/field-semantic-redaction.js.map +1 -0
- package/dist/contract/free-feature-blocks.d.ts +10 -0
- package/dist/contract/free-feature-blocks.d.ts.map +1 -0
- package/dist/contract/free-feature-blocks.js +94 -0
- package/dist/contract/free-feature-blocks.js.map +1 -0
- package/dist/contract/lock-secret-guard.d.ts +22 -0
- package/dist/contract/lock-secret-guard.d.ts.map +1 -0
- package/dist/contract/lock-secret-guard.js +134 -0
- package/dist/contract/lock-secret-guard.js.map +1 -0
- package/dist/contract/lock-vs-git-head.d.ts +26 -0
- package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
- package/dist/contract/lock-vs-git-head.js +28 -0
- package/dist/contract/lock-vs-git-head.js.map +1 -0
- package/dist/contract/normalize-contract-step.d.ts +21 -0
- package/dist/contract/normalize-contract-step.d.ts.map +1 -0
- package/dist/contract/normalize-contract-step.js +70 -0
- package/dist/contract/normalize-contract-step.js.map +1 -0
- package/dist/contract/normalize-feature-steps.d.ts +7 -0
- package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
- package/dist/contract/normalize-feature-steps.js +127 -0
- package/dist/contract/normalize-feature-steps.js.map +1 -0
- package/dist/contract/oracle-strength.d.ts +12 -0
- package/dist/contract/oracle-strength.d.ts.map +1 -0
- package/dist/contract/oracle-strength.js +88 -0
- package/dist/contract/oracle-strength.js.map +1 -0
- package/dist/contract/project-contract-blockers.d.ts +10 -0
- package/dist/contract/project-contract-blockers.d.ts.map +1 -0
- package/dist/contract/project-contract-blockers.js +73 -0
- package/dist/contract/project-contract-blockers.js.map +1 -0
- package/dist/contract/record-contract-approval.d.ts +21 -0
- package/dist/contract/record-contract-approval.d.ts.map +1 -0
- package/dist/contract/record-contract-approval.js +98 -0
- package/dist/contract/record-contract-approval.js.map +1 -0
- package/dist/contract/render-free-gherkin.d.ts +40 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -0
- package/dist/contract/render-free-gherkin.js +141 -0
- package/dist/contract/render-free-gherkin.js.map +1 -0
- package/dist/contract/render-trace-sentence.d.ts +20 -0
- package/dist/contract/render-trace-sentence.d.ts.map +1 -0
- package/dist/contract/render-trace-sentence.js +109 -0
- package/dist/contract/render-trace-sentence.js.map +1 -0
- package/dist/contract/render-trace-target.d.ts +14 -0
- package/dist/contract/render-trace-target.d.ts.map +1 -0
- package/dist/contract/render-trace-target.js +70 -0
- package/dist/contract/render-trace-target.js.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.js +78 -0
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.js +161 -0
- package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
- package/dist/contract/trace/identity-cache.d.ts +19 -0
- package/dist/contract/trace/identity-cache.d.ts.map +1 -0
- package/dist/contract/trace/identity-cache.js +104 -0
- package/dist/contract/trace/identity-cache.js.map +1 -0
- package/dist/contract/trace/select-final-attempt.d.ts +27 -0
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
- package/dist/contract/trace/select-final-attempt.js +116 -0
- package/dist/contract/trace/select-final-attempt.js.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
- package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-html-renderer.js +172 -0
- package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
- package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
- package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-resolver.js +65 -0
- package/dist/contract/trace/snapshot-resolver.js.map +1 -0
- package/dist/contract/trace/snapshot-store.d.ts +66 -0
- package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
- package/dist/contract/trace/snapshot-store.js +173 -0
- package/dist/contract/trace/snapshot-store.js.map +1 -0
- package/dist/contract/trace/target-identity.d.ts +74 -0
- package/dist/contract/trace/target-identity.d.ts.map +1 -0
- package/dist/contract/trace/target-identity.js +68 -0
- package/dist/contract/trace/target-identity.js.map +1 -0
- package/dist/contract/trace/test-step-join.d.ts +65 -0
- package/dist/contract/trace/test-step-join.d.ts.map +1 -0
- package/dist/contract/trace/test-step-join.js +80 -0
- package/dist/contract/trace/test-step-join.js.map +1 -0
- package/dist/contract/trace/trace-binding.d.ts +21 -0
- package/dist/contract/trace/trace-binding.d.ts.map +1 -0
- package/dist/contract/trace/trace-binding.js +88 -0
- package/dist/contract/trace/trace-binding.js.map +1 -0
- package/dist/contract/trace/trace-file-reader.d.ts +35 -0
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-file-reader.js +155 -0
- package/dist/contract/trace/trace-file-reader.js.map +1 -0
- package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
- package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
- package/dist/contract/trace/trace-fingerprint.js +96 -0
- package/dist/contract/trace/trace-fingerprint.js.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.js +84 -0
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
- package/dist/contract/trace/trace-run-record.d.ts +27 -0
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
- package/dist/contract/trace/trace-run-record.js +115 -0
- package/dist/contract/trace/trace-run-record.js.map +1 -0
- package/dist/contract/trace/trace-steps.d.ts +19 -0
- package/dist/contract/trace/trace-steps.d.ts.map +1 -0
- package/dist/contract/trace/trace-steps.js +79 -0
- package/dist/contract/trace/trace-steps.js.map +1 -0
- package/dist/contract/trace/trace-zip-limits.d.ts +41 -0
- package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-limits.js +48 -0
- package/dist/contract/trace/trace-zip-limits.js.map +1 -0
- package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
- package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-reader.js +186 -0
- package/dist/contract/trace/trace-zip-reader.js.map +1 -0
- package/dist/contract/verify-approval-decisions.d.ts +5 -0
- package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
- package/dist/contract/verify-approval-decisions.js +104 -0
- package/dist/contract/verify-approval-decisions.js.map +1 -0
- package/dist/decisions/append-decision.d.ts +12 -0
- package/dist/decisions/append-decision.d.ts.map +1 -0
- package/dist/decisions/append-decision.js +73 -0
- package/dist/decisions/append-decision.js.map +1 -0
- package/dist/decisions/confirmed-decision-commands.d.ts +30 -0
- package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
- package/dist/decisions/confirmed-decision-commands.js +172 -0
- package/dist/decisions/confirmed-decision-commands.js.map +1 -0
- package/dist/decisions/decision-file.d.ts +31 -0
- package/dist/decisions/decision-file.d.ts.map +1 -0
- package/dist/decisions/decision-file.js +139 -0
- package/dist/decisions/decision-file.js.map +1 -0
- package/dist/decisions/decision-identity.d.ts +12 -0
- package/dist/decisions/decision-identity.d.ts.map +1 -0
- package/dist/decisions/decision-identity.js +78 -0
- package/dist/decisions/decision-identity.js.map +1 -0
- package/dist/decisions/decision-integrity-check.d.ts +12 -0
- package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
- package/dist/decisions/decision-integrity-check.js +102 -0
- package/dist/decisions/decision-integrity-check.js.map +1 -0
- package/dist/decisions/decision-schema.d.ts +42 -0
- package/dist/decisions/decision-schema.d.ts.map +1 -0
- package/dist/decisions/decision-schema.js +75 -0
- package/dist/decisions/decision-schema.js.map +1 -0
- package/dist/decisions/decision-source.d.ts +2 -0
- package/dist/decisions/decision-source.d.ts.map +1 -0
- package/dist/decisions/decision-source.js +18 -0
- package/dist/decisions/decision-source.js.map +1 -0
- package/dist/decisions/exclusive-file-create.d.ts +3 -0
- package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
- package/dist/decisions/exclusive-file-create.js +84 -0
- package/dist/decisions/exclusive-file-create.js.map +1 -0
- package/dist/decisions/git-head-trust.d.ts +7 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -0
- package/dist/decisions/git-head-trust.js +76 -0
- package/dist/decisions/git-head-trust.js.map +1 -0
- package/dist/decisions/human-confirmation.d.ts +33 -0
- package/dist/decisions/human-confirmation.d.ts.map +1 -0
- package/dist/decisions/human-confirmation.js +155 -0
- package/dist/decisions/human-confirmation.js.map +1 -0
- package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
- package/dist/decisions/legacy-waiver-migration.js +170 -0
- package/dist/decisions/legacy-waiver-migration.js.map +1 -0
- package/dist/decisions/read-decisions.d.ts +19 -0
- package/dist/decisions/read-decisions.d.ts.map +1 -0
- package/dist/decisions/read-decisions.js +90 -0
- package/dist/decisions/read-decisions.js.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
- package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
- package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
- package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
- package/dist/decisions/waiver-decisions.d.ts +24 -0
- package/dist/decisions/waiver-decisions.d.ts.map +1 -0
- package/dist/decisions/waiver-decisions.js +46 -0
- package/dist/decisions/waiver-decisions.js.map +1 -0
- package/dist/exporters/matrix/build.d.ts +3 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +10 -9
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +3 -0
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +2 -0
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.d.ts +6 -1
- package/dist/exporters/matrix/gates.d.ts.map +1 -1
- package/dist/exporters/matrix/gates.js +57 -128
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +3 -0
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
- package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +3 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +4 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +13 -0
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/graph/evaluate-graph.d.ts +21 -0
- package/dist/graph/evaluate-graph.d.ts.map +1 -0
- package/dist/graph/evaluate-graph.js +49 -0
- package/dist/graph/evaluate-graph.js.map +1 -0
- package/dist/graph/locate-finding.d.ts +20 -0
- package/dist/graph/locate-finding.d.ts.map +1 -0
- package/dist/graph/locate-finding.js +137 -0
- package/dist/graph/locate-finding.js.map +1 -0
- package/dist/graph/node-decl.d.ts +59 -0
- package/dist/graph/node-decl.d.ts.map +1 -0
- package/dist/graph/node-decl.js +8 -0
- package/dist/graph/node-decl.js.map +1 -0
- package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
- package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
- package/dist/graph/nodes/core-node-catalog.js +13 -0
- package/dist/graph/nodes/core-node-catalog.js.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts +19 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.js +56 -0
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
- package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-nodes.js +66 -0
- package/dist/graph/nodes/test-case-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
- package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-audit-nodes.js +95 -0
- package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-contract-node.d.ts +20 -0
- package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
- package/dist/graph/nodes/unit-contract-node.js +81 -0
- package/dist/graph/nodes/unit-contract-node.js.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
- package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-design-nodes.js +90 -0
- package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
- package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/unit-execution-nodes.js +79 -0
- package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
- package/dist/graph/test-case-identity.d.ts +13 -0
- package/dist/graph/test-case-identity.d.ts.map +1 -0
- package/dist/graph/test-case-identity.js +106 -0
- package/dist/graph/test-case-identity.js.map +1 -0
- package/dist/graph/test-case-results.d.ts +11 -0
- package/dist/graph/test-case-results.d.ts.map +1 -0
- package/dist/graph/test-case-results.js +137 -0
- package/dist/graph/test-case-results.js.map +1 -0
- package/dist/graph/test-case-satisfied.d.ts +25 -0
- package/dist/graph/test-case-satisfied.d.ts.map +1 -0
- package/dist/graph/test-case-satisfied.js +51 -0
- package/dist/graph/test-case-satisfied.js.map +1 -0
- package/dist/graph/test-case-state-shape.d.ts +67 -0
- package/dist/graph/test-case-state-shape.d.ts.map +1 -0
- package/dist/graph/test-case-state-shape.js +3 -0
- package/dist/graph/test-case-state-shape.js.map +1 -0
- package/dist/graph/test-case-states.d.ts +9 -0
- package/dist/graph/test-case-states.d.ts.map +1 -0
- package/dist/graph/test-case-states.js +116 -0
- package/dist/graph/test-case-states.js.map +1 -0
- package/dist/graph/unit-artifact-probes.d.ts +19 -0
- package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
- package/dist/graph/unit-artifact-probes.js +133 -0
- package/dist/graph/unit-artifact-probes.js.map +1 -0
- package/dist/graph/unit-state-facts.d.ts +43 -0
- package/dist/graph/unit-state-facts.d.ts.map +1 -0
- package/dist/graph/unit-state-facts.js +87 -0
- package/dist/graph/unit-state-facts.js.map +1 -0
- package/dist/harness/audit.d.ts +11 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +18 -17
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
- package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-terms.js +72 -0
- package/dist/harness/gates/audit-gate-terms.js.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
- package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
- package/dist/harness/gates/audit-gate-verdict.js +101 -0
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
- package/dist/harness/gates/audit-input-hash.d.ts +4 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
- package/dist/harness/gates/audit-input-hash.js +96 -0
- package/dist/harness/gates/audit-input-hash.js.map +1 -0
- package/dist/harness/gates/audit-report-verification.d.ts +32 -0
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
- package/dist/harness/gates/audit-report-verification.js +207 -0
- package/dist/harness/gates/audit-report-verification.js.map +1 -0
- package/dist/harness/gates/decisions-hash.d.ts +13 -0
- package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
- package/dist/harness/gates/decisions-hash.js +72 -0
- package/dist/harness/gates/decisions-hash.js.map +1 -0
- package/dist/harness/gates/delivery-checklist.d.ts +21 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
- package/dist/harness/gates/delivery-checklist.js +128 -0
- package/dist/harness/gates/delivery-checklist.js.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts +29 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.js +91 -0
- package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
- package/dist/harness/gates/delivery-decision-step.d.ts +16 -0
- package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-step.js +71 -0
- package/dist/harness/gates/delivery-decision-step.js.map +1 -0
- package/dist/harness/gates/gate-override-report.d.ts +59 -0
- package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-report.js +86 -0
- package/dist/harness/gates/gate-override-report.js.map +1 -0
- package/dist/harness/gates/gate-override-scope.d.ts +18 -0
- package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-scope.js +98 -0
- package/dist/harness/gates/gate-override-scope.js.map +1 -0
- package/dist/harness/gates/gate-override-validation.d.ts +25 -0
- package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
- package/dist/harness/gates/gate-override-validation.js +81 -0
- package/dist/harness/gates/gate-override-validation.js.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
- package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
- package/dist/harness/gates/gate-rule-catalog.js +112 -0
- package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
- package/dist/harness/gates/gate-terms.d.ts +33 -0
- package/dist/harness/gates/gate-terms.d.ts.map +1 -0
- package/dist/harness/gates/gate-terms.js +41 -0
- package/dist/harness/gates/gate-terms.js.map +1 -0
- package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
- package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
- package/dist/harness/gates/in-run-decision-check.js +138 -0
- package/dist/harness/gates/in-run-decision-check.js.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
- package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
- package/dist/harness/gates/journey-gate-inputs.js +81 -0
- package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.js +116 -0
- package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
- package/dist/harness/gates/resolve-rule.d.ts +59 -0
- package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
- package/dist/harness/gates/resolve-rule.js +41 -0
- package/dist/harness/gates/resolve-rule.js.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
- package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
- package/dist/harness/gates/unit-gate-overrides.js +122 -0
- package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
- package/dist/harness/journey.d.ts +24 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +114 -23
- package/dist/harness/journey.js.map +1 -1
- package/dist/harness/manifest.d.ts +12 -0
- package/dist/harness/manifest.d.ts.map +1 -1
- package/dist/harness/manifest.js +71 -43
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +39 -6
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +34 -218
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +10 -6
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +22 -11
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +22 -5
- package/dist/harness/script-check.js.map +1 -1
- package/dist/harness/sensors.d.ts +14 -3
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +50 -49
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
- package/dist/harness/viewpoint-baseline.js +1 -7
- package/dist/harness/viewpoint-baseline.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts +3 -13
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +8 -38
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/hooks/bash-write-targets.d.ts +15 -0
- package/dist/hooks/bash-write-targets.d.ts.map +1 -0
- package/dist/hooks/bash-write-targets.js +173 -0
- package/dist/hooks/bash-write-targets.js.map +1 -0
- package/dist/hooks/claude-hook-entry.d.ts +11 -0
- package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
- package/dist/hooks/claude-hook-entry.js +137 -0
- package/dist/hooks/claude-hook-entry.js.map +1 -0
- package/dist/hooks/claude-transcript-turn.d.ts +11 -0
- package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
- package/dist/hooks/claude-transcript-turn.js +143 -0
- package/dist/hooks/claude-transcript-turn.js.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
- package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
- package/dist/hooks/guard-delivery-contract-rule.js +152 -0
- package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
- package/dist/hooks/guard-protected-paths.d.ts +9 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
- package/dist/hooks/guard-protected-paths.js +106 -0
- package/dist/hooks/guard-protected-paths.js.map +1 -0
- package/dist/hooks/guard-rules.d.ts +37 -0
- package/dist/hooks/guard-rules.d.ts.map +1 -0
- package/dist/hooks/guard-rules.js +61 -0
- package/dist/hooks/guard-rules.js.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.js +21 -0
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
- package/dist/hooks/hand-back-core.d.ts +37 -0
- package/dist/hooks/hand-back-core.d.ts.map +1 -0
- package/dist/hooks/hand-back-core.js +115 -0
- package/dist/hooks/hand-back-core.js.map +1 -0
- package/dist/hooks/hook-cli-command.d.ts +9 -0
- package/dist/hooks/hook-cli-command.d.ts.map +1 -0
- package/dist/hooks/hook-cli-command.js +46 -0
- package/dist/hooks/hook-cli-command.js.map +1 -0
- package/dist/hooks/hook-registry.d.ts +10 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hooks/hook-registry.js +24 -0
- package/dist/hooks/hook-registry.js.map +1 -0
- package/dist/hooks/hook-result-contract.d.ts +50 -0
- package/dist/hooks/hook-result-contract.d.ts.map +1 -0
- package/dist/hooks/hook-result-contract.js +80 -0
- package/dist/hooks/hook-result-contract.js.map +1 -0
- package/dist/hooks/hook-toggles.d.ts +10 -0
- package/dist/hooks/hook-toggles.d.ts.map +1 -0
- package/dist/hooks/hook-toggles.js +107 -0
- package/dist/hooks/hook-toggles.js.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
- package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
- package/dist/hooks/pre-tool-guard-hook.js +105 -0
- package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.js +55 -0
- package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
- package/dist/hooks/stop-next-step-hook.d.ts +16 -0
- package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
- package/dist/hooks/stop-next-step-hook.js +42 -0
- package/dist/hooks/stop-next-step-hook.js.map +1 -0
- package/dist/hooks/sungen-project-root.d.ts +19 -0
- package/dist/hooks/sungen-project-root.d.ts.map +1 -0
- package/dist/hooks/sungen-project-root.js +130 -0
- package/dist/hooks/sungen-project-root.js.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
- package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
- package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
- package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
- package/dist/orchestrator/ai-skills/commands.js +16 -6
- package/dist/orchestrator/ai-skills/commands.js.map +1 -1
- package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
- package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
- package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
- package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
- package/dist/orchestrator/claude-hooks-install.js +203 -0
- package/dist/orchestrator/claude-hooks-install.js.map +1 -0
- package/dist/orchestrator/flow-manager.d.ts +1 -0
- package/dist/orchestrator/flow-manager.d.ts.map +1 -1
- package/dist/orchestrator/flow-manager.js +52 -3
- package/dist/orchestrator/flow-manager.js.map +1 -1
- package/dist/orchestrator/lockstep-version.d.ts +15 -5
- package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
- package/dist/orchestrator/lockstep-version.js +30 -17
- package/dist/orchestrator/lockstep-version.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +6 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +23 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +52 -4
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +36 -46
- package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +1 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +0 -18
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts +1 -4
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts.map +1 -1
- package/dist/orchestrator/viewpoint-pattern-catalog.js +2 -5
- package/dist/orchestrator/viewpoint-pattern-catalog.js.map +1 -1
- package/dist/utils/safe-yaml-parse.d.ts +8 -0
- package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
- package/dist/utils/safe-yaml-parse.js +51 -0
- package/dist/utils/safe-yaml-parse.js.map +1 -0
- package/package.json +3 -3
- package/src/basis/anchor-grammar.ts +83 -0
- package/src/basis/anchor-hash.ts +27 -0
- package/src/basis/bm51-tables.ts +65 -0
- package/src/basis/extract-spec-anchors.ts +95 -0
- package/src/basis/migration-sentinel.ts +175 -0
- package/src/basis/spec-frontmatter.ts +68 -0
- package/src/basis/spec-sections.ts +35 -0
- package/src/basis/test-basis-schema.ts +81 -0
- package/src/capabilities/registry.ts +16 -0
- package/src/cli/commands/audit.ts +3 -26
- package/src/cli/commands/capability.ts +1 -1
- package/src/cli/commands/contract-derive-command.ts +60 -0
- package/src/cli/commands/contract.ts +130 -0
- package/src/cli/commands/delivery.ts +52 -3
- package/src/cli/commands/generate.ts +3 -1
- package/src/cli/commands/journey.ts +39 -14
- package/src/cli/commands/next.ts +60 -8
- package/src/cli/commands/update.ts +35 -8
- package/src/cli/index.ts +20 -32
- package/src/contract/approve-contract.ts +94 -0
- package/src/contract/assertion-matcher-vocabulary.ts +93 -0
- package/src/contract/build-contract-verdict.ts +108 -0
- package/src/contract/build-trace-conformance.ts +100 -0
- package/src/contract/classify-contract-change.ts +92 -0
- package/src/contract/classify-contract-unit.ts +47 -0
- package/src/contract/classify-trace-conformance.ts +116 -0
- package/src/contract/contract-git.ts +106 -0
- package/src/contract/contract-hash.ts +34 -0
- package/src/contract/contract-report-file.ts +25 -0
- package/src/contract/contract-schema.ts +137 -0
- package/src/contract/contract-units.ts +52 -0
- package/src/contract/contracts-lock-file.ts +97 -0
- package/src/contract/data-normalize.ts +66 -0
- package/src/contract/derive-free-feature.ts +110 -0
- package/src/contract/field-semantic-redaction.ts +80 -0
- package/src/contract/free-feature-blocks.ts +56 -0
- package/src/contract/lock-secret-guard.ts +95 -0
- package/src/contract/lock-vs-git-head.ts +38 -0
- package/src/contract/normalize-contract-step.ts +74 -0
- package/src/contract/normalize-feature-steps.ts +93 -0
- package/src/contract/oracle-strength.ts +80 -0
- package/src/contract/project-contract-blockers.ts +36 -0
- package/src/contract/record-contract-approval.ts +70 -0
- package/src/contract/render-free-gherkin.ts +113 -0
- package/src/contract/render-trace-sentence.ts +98 -0
- package/src/contract/render-trace-target.ts +68 -0
- package/src/contract/resolve-unit-trace-identities.ts +35 -0
- package/src/contract/trace/collect-trace-evidence.ts +109 -0
- package/src/contract/trace/identity-cache.ts +61 -0
- package/src/contract/trace/select-final-attempt.ts +70 -0
- package/src/contract/trace/snapshot-html-renderer.ts +136 -0
- package/src/contract/trace/snapshot-resolver.ts +66 -0
- package/src/contract/trace/snapshot-store.ts +151 -0
- package/src/contract/trace/target-identity.ts +104 -0
- package/src/contract/trace/test-step-join.ts +103 -0
- package/src/contract/trace/trace-binding.ts +56 -0
- package/src/contract/trace/trace-file-reader.ts +123 -0
- package/src/contract/trace/trace-fingerprint.ts +68 -0
- package/src/contract/trace/trace-identity-resolution.ts +74 -0
- package/src/contract/trace/trace-run-record.ts +74 -0
- package/src/contract/trace/trace-steps.ts +88 -0
- package/src/contract/trace/trace-zip-limits.ts +73 -0
- package/src/contract/trace/trace-zip-reader.ts +127 -0
- package/src/contract/verify-approval-decisions.ts +60 -0
- package/src/decisions/append-decision.ts +35 -0
- package/src/decisions/confirmed-decision-commands.ts +128 -0
- package/src/decisions/decision-file.ts +93 -0
- package/src/decisions/decision-identity.ts +73 -0
- package/src/decisions/decision-integrity-check.ts +61 -0
- package/src/decisions/decision-schema.ts +76 -0
- package/src/decisions/decision-source.ts +14 -0
- package/src/decisions/exclusive-file-create.ts +42 -0
- package/src/decisions/git-head-trust.ts +32 -0
- package/src/decisions/human-confirmation.ts +114 -0
- package/src/decisions/legacy-waiver-migration.ts +135 -0
- package/src/decisions/read-decisions.ts +61 -0
- package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
- package/src/decisions/waiver-decisions.ts +56 -0
- package/src/exporters/matrix/build.ts +11 -9
- package/src/exporters/matrix/export.ts +5 -0
- package/src/exporters/matrix/gates.ts +62 -129
- package/src/exporters/matrix/render-csv.ts +3 -0
- package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
- package/src/exporters/matrix/render-xlsx.ts +3 -0
- package/src/exporters/matrix/types.ts +4 -1
- package/src/generators/test-generator/code-generator.ts +13 -0
- package/src/graph/evaluate-graph.ts +62 -0
- package/src/graph/locate-finding.ts +93 -0
- package/src/graph/node-decl.ts +65 -0
- package/src/graph/nodes/core-node-catalog.ts +15 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +69 -0
- package/src/graph/nodes/test-case-nodes.ts +68 -0
- package/src/graph/nodes/unit-audit-nodes.ts +95 -0
- package/src/graph/nodes/unit-contract-node.ts +82 -0
- package/src/graph/nodes/unit-design-nodes.ts +88 -0
- package/src/graph/nodes/unit-execution-nodes.ts +77 -0
- package/src/graph/test-case-identity.ts +75 -0
- package/src/graph/test-case-results.ts +90 -0
- package/src/graph/test-case-satisfied.ts +55 -0
- package/src/graph/test-case-state-shape.ts +62 -0
- package/src/graph/test-case-states.ts +84 -0
- package/src/graph/unit-artifact-probes.ts +77 -0
- package/src/graph/unit-state-facts.ts +112 -0
- package/src/harness/audit.ts +29 -18
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/gates/audit-gate-terms.ts +80 -0
- package/src/harness/gates/audit-gate-verdict.ts +78 -0
- package/src/harness/gates/audit-input-hash.ts +55 -0
- package/src/harness/gates/audit-report-verification.ts +173 -0
- package/src/harness/gates/decisions-hash.ts +42 -0
- package/src/harness/gates/delivery-checklist.ts +120 -0
- package/src/harness/gates/delivery-decision-gate.ts +111 -0
- package/src/harness/gates/delivery-decision-step.ts +73 -0
- package/src/harness/gates/gate-override-report.ts +114 -0
- package/src/harness/gates/gate-override-scope.ts +66 -0
- package/src/harness/gates/gate-override-validation.ts +75 -0
- package/src/harness/gates/gate-rule-catalog.ts +82 -0
- package/src/harness/gates/gate-terms.ts +59 -0
- package/src/harness/gates/in-run-decision-check.ts +99 -0
- package/src/harness/gates/journey-gate-inputs.ts +89 -0
- package/src/harness/gates/migrated-waiver-review.ts +68 -0
- package/src/harness/gates/resolve-rule.ts +94 -0
- package/src/harness/gates/unit-gate-overrides.ts +99 -0
- package/src/harness/journey.ts +122 -27
- package/src/harness/manifest.ts +67 -43
- package/src/harness/next-step.ts +59 -210
- package/src/harness/parse.ts +25 -15
- package/src/harness/script-check.ts +20 -5
- package/src/harness/sensors.ts +55 -49
- package/src/harness/viewpoint-baseline.ts +1 -7
- package/src/harness/viewpoint-ledger.ts +11 -52
- package/src/hooks/bash-write-targets.ts +109 -0
- package/src/hooks/claude-hook-entry.ts +85 -0
- package/src/hooks/claude-transcript-turn.ts +96 -0
- package/src/hooks/guard-delivery-contract-rule.ts +110 -0
- package/src/hooks/guard-protected-paths.ts +70 -0
- package/src/hooks/guard-rules.ts +98 -0
- package/src/hooks/guard-tty-spoof-rule.ts +31 -0
- package/src/hooks/hand-back-core.ts +106 -0
- package/src/hooks/hook-cli-command.ts +17 -0
- package/src/hooks/hook-registry.ts +24 -0
- package/src/hooks/hook-result-contract.ts +114 -0
- package/src/hooks/hook-toggles.ts +66 -0
- package/src/hooks/pre-tool-guard-hook.ts +67 -0
- package/src/hooks/session-start-unit-state-hook.ts +54 -0
- package/src/hooks/stop-next-step-hook.ts +37 -0
- package/src/hooks/sungen-project-root.ts +80 -0
- package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
- package/src/orchestrator/ai-skills/commands.ts +22 -8
- package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
- package/src/orchestrator/claude-hooks-install.ts +168 -0
- package/src/orchestrator/flow-manager.ts +53 -3
- package/src/orchestrator/lockstep-version.ts +28 -15
- package/src/orchestrator/project-initializer.ts +21 -0
- package/src/orchestrator/screen-manager.ts +52 -4
- package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +36 -46
- package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
- package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
- package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +1 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +0 -18
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/orchestrator/viewpoint-pattern-catalog.ts +2 -5
- package/src/utils/safe-yaml-parse.ts +44 -0
- package/dist/cli/commands/viewpoint.d.ts +0 -7
- package/dist/cli/commands/viewpoint.d.ts.map +0 -1
- package/dist/cli/commands/viewpoint.js +0 -70
- package/dist/cli/commands/viewpoint.js.map +0 -1
- package/dist/harness/viewpoint-draft-header.d.ts +0 -7
- package/dist/harness/viewpoint-draft-header.d.ts.map +0 -1
- package/dist/harness/viewpoint-draft-header.js +0 -100
- package/dist/harness/viewpoint-draft-header.js.map +0 -1
- package/dist/harness/viewpoint-mode.d.ts +0 -9
- package/dist/harness/viewpoint-mode.d.ts.map +0 -1
- package/dist/harness/viewpoint-mode.js +0 -52
- package/dist/harness/viewpoint-mode.js.map +0 -1
- package/dist/harness/viewpoint-priority.d.ts +0 -19
- package/dist/harness/viewpoint-priority.d.ts.map +0 -1
- package/dist/harness/viewpoint-priority.js +0 -36
- package/dist/harness/viewpoint-priority.js.map +0 -1
- package/dist/harness/viewpoint-review-open.d.ts +0 -6
- package/dist/harness/viewpoint-review-open.d.ts.map +0 -1
- package/dist/harness/viewpoint-review-open.js +0 -90
- package/dist/harness/viewpoint-review-open.js.map +0 -1
- package/dist/harness/viewpoint-scan-refs.d.ts +0 -50
- package/dist/harness/viewpoint-scan-refs.d.ts.map +0 -1
- package/dist/harness/viewpoint-scan-refs.js +0 -200
- package/dist/harness/viewpoint-scan-refs.js.map +0 -1
- package/dist/harness/viewpoint-scan.d.ts +0 -41
- package/dist/harness/viewpoint-scan.d.ts.map +0 -1
- package/dist/harness/viewpoint-scan.js +0 -118
- package/dist/harness/viewpoint-scan.js.map +0 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +0 -63
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +0 -158
- package/dist/orchestrator/viewpoint-scaffold.d.ts +0 -3
- package/dist/orchestrator/viewpoint-scaffold.d.ts.map +0 -1
- package/dist/orchestrator/viewpoint-scaffold.js +0 -70
- package/dist/orchestrator/viewpoint-scaffold.js.map +0 -1
- package/src/cli/commands/viewpoint.ts +0 -58
- package/src/harness/viewpoint-draft-header.ts +0 -55
- package/src/harness/viewpoint-mode.ts +0 -49
- package/src/harness/viewpoint-priority.ts +0 -38
- package/src/harness/viewpoint-review-open.ts +0 -51
- package/src/harness/viewpoint-scan-refs.ts +0 -154
- package/src/harness/viewpoint-scan.ts +0 -111
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +0 -63
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +0 -158
- package/src/orchestrator/viewpoint-scaffold.ts +0 -36
package/src/harness/sensors.ts
CHANGED
|
@@ -12,8 +12,9 @@ import { parse as parseYaml } from 'yaml';
|
|
|
12
12
|
import { ScenarioInfo, ViewpointEntry, idPrefix } from './parse';
|
|
13
13
|
import { readTextFile } from './read-text';
|
|
14
14
|
import { keywordHit, hasKeyword } from './keyword-match';
|
|
15
|
-
import { parsePriority } from './viewpoint-priority';
|
|
16
15
|
import { countedAssertions } from './counted-assertions';
|
|
16
|
+
import { CATALOG_GATE_RULES, GateRules } from './gates/resolve-rule';
|
|
17
|
+
import { ruleVerdict, sensorSeverityOf } from './gates/gate-terms';
|
|
17
18
|
|
|
18
19
|
// Business-critical category keywords (matched by CONTAINMENT against the VP category, so a
|
|
19
20
|
// compound category like LIST-DISPLAY / ADD-TO-CART / PRODUCT-DISCOVERY classifies correctly).
|
|
@@ -277,6 +278,8 @@ export function assertionDepth(
|
|
|
277
278
|
scenarios: ScenarioInfo[],
|
|
278
279
|
dataThemes: CatalogTheme[] = [],
|
|
279
280
|
focus = 'functional',
|
|
281
|
+
/** The unit's gate rules; the catalog alone (today's levels) by default. */
|
|
282
|
+
rules: GateRules = CATALOG_GATE_RULES,
|
|
280
283
|
): DepthResult {
|
|
281
284
|
const nonManual = scenarios.filter((s) => !s.manual);
|
|
282
285
|
const shallow = nonManual.filter((s) => s.shallow);
|
|
@@ -300,8 +303,7 @@ export function assertionDepth(
|
|
|
300
303
|
const ratio = required.length ? 1 - reqShallow.length / required.length : 1;
|
|
301
304
|
|
|
302
305
|
const threshold = DEPTH_THRESHOLDS[focus] ?? DEPTH_THRESHOLDS.functional;
|
|
303
|
-
|
|
304
|
-
if (ratio < threshold) verdict = WARN_ONLY_FOCUS.has(focus) ? 'warn' : 'fail';
|
|
306
|
+
const verdict = ruleVerdict(rules, 'audit.assertion-depth', ratio < threshold, WARN_ONLY_FOCUS.has(focus));
|
|
305
307
|
|
|
306
308
|
return {
|
|
307
309
|
total: nonManual.length,
|
|
@@ -712,7 +714,10 @@ export interface ClaimUnproven {
|
|
|
712
714
|
claim: string; // the claim keyword matched in the title
|
|
713
715
|
need: string; // the assertion shape the steps must contain
|
|
714
716
|
hint: string; // how to fix
|
|
715
|
-
|
|
717
|
+
/** Resolved from the row's catalog rule (fail = blocks when under the ratio; info only via an override). */
|
|
718
|
+
severity: 'fail' | 'warn' | 'info';
|
|
719
|
+
/** The gate rule that decided `severity` (`claim.*`, or `claim.partial-proof`). */
|
|
720
|
+
rule: string;
|
|
716
721
|
}
|
|
717
722
|
|
|
718
723
|
export interface ClaimProofResult {
|
|
@@ -727,16 +732,17 @@ export interface ClaimProofResult {
|
|
|
727
732
|
}
|
|
728
733
|
|
|
729
734
|
interface ClaimRule {
|
|
735
|
+
/** The catalog rule (`claim.*`) whose resolved severity a missing proof gets (OES-11.2). */
|
|
736
|
+
rule: string;
|
|
730
737
|
claim: string;
|
|
731
738
|
title: RegExp; // claim keyword(s) in the title
|
|
732
739
|
proof: RegExp; // required assertion shape in the steps
|
|
733
740
|
need: string;
|
|
734
741
|
hint: string;
|
|
735
|
-
severity: 'fail' | 'warn';
|
|
736
742
|
// Optional: even when `proof` matches, if `underproof` also matches the proof is
|
|
737
|
-
// PARTIAL (the right shape exists but on the wrong/another element) → a
|
|
738
|
-
//
|
|
739
|
-
// but asserts the actions with singular presence.
|
|
743
|
+
// PARTIAL (the right shape exists but on the wrong/another element) → a finding at the
|
|
744
|
+
// `claim.partial-proof` rule's level. e.g. an "each card exposes <action>" claim that has
|
|
745
|
+
// a see-all on price but asserts the actions with singular presence.
|
|
740
746
|
underproof?: RegExp;
|
|
741
747
|
underNeed?: string;
|
|
742
748
|
underHint?: string;
|
|
@@ -750,29 +756,30 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
750
756
|
// catch, so proving it with a substring proves the opposite of what the title says. Found on
|
|
751
757
|
// a real basic flow whose seven confirmation rows all used `contains` while claiming the six
|
|
752
758
|
// values "survive unchanged" (#599).
|
|
759
|
+
rule: 'claim.unchanged-preserved',
|
|
753
760
|
claim: 'unchanged/preserved',
|
|
754
761
|
title: /\b(unchanged|unmodified|un-?edited|identical|preserved|intact|verbatim|as entered|without (?:any )?(?:change|modification))\b/,
|
|
755
762
|
proof: /^(?![\s\S]*\bcontains \{\{)/,
|
|
756
763
|
need: 'exact-value assertions (`see [X] text with {{v}}` / `field with {{v}}`) for the values the title says are unchanged',
|
|
757
764
|
hint: 'swap `contains {{v}}` for `with {{v}}` on the continuity rows. A substring match cannot distinguish "unchanged" from "changed by adding a prefix" — and if the screen genuinely renders extra text around the value, say so in the title instead of claiming exactness.',
|
|
758
|
-
severity: 'warn',
|
|
759
765
|
},
|
|
760
766
|
{
|
|
761
767
|
// An ORDER claim ("sorted by date descending", "ties broken by last-updated") is invisible to
|
|
762
768
|
// a presence check: `see [List] table` passes whatever order the rows are in. It sits ahead of
|
|
763
769
|
// the generic rules so "all results sorted …" is judged as an ordering claim, not an all-claim.
|
|
764
770
|
// A tiebreaker is a Tier-1 guard in the tc-generation skill, yet no rule recognised it (#810).
|
|
771
|
+
rule: 'claim.ordering-sort',
|
|
765
772
|
claim: 'ordering/sort',
|
|
766
773
|
title: /\b(ascending|descending|sorted|sorts|sort order|ordered by|order by|in (?:chronological|alphabetical|reverse|numeric) order|(?:newest|oldest|latest|earliest|highest|lowest) first|tie-?break(?:s|er|ers)?|ties?)\b|降順|昇順|並び順|giảm dần|tăng dần|sắp xếp/,
|
|
767
774
|
proof: /match data|is sorted|sorted (?:ascending|descending)|\brow \d+\b|\.first\.|\.last\.|\[\d+\]\.|order by/,
|
|
768
775
|
need: 'an order-sensitive assertion (`table match data:` rows in the expected order, `is sorted ascending|descending`, or positional `row N` checks)',
|
|
769
776
|
hint: 'a presence check passes in any order — assert the rows in their expected sequence (`User see [T] table match data:`), or the column sort state; a tiebreak needs two rows sharing the primary key.',
|
|
770
|
-
severity: 'fail',
|
|
771
777
|
},
|
|
772
778
|
{
|
|
773
779
|
// A LIMIT claim ("never exceeds 10", "at most 5 files") is a count claim in disguise.
|
|
774
780
|
// Ahead of 'no-side-effect', whose negation+effect pattern would otherwise swallow
|
|
775
781
|
// "never exceeds 10 records" and ask for a duplicate-count proof.
|
|
782
|
+
rule: 'claim.limit-cap',
|
|
776
783
|
claim: 'limit/cap',
|
|
777
784
|
// The quantity must be ≥2 ("at most ONE order" is a no-duplicate claim — left to the rules
|
|
778
785
|
// below) and not a duration ("up to 30 seconds" is a timing claim, not a cap).
|
|
@@ -780,51 +787,50 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
780
787
|
proof: /\bcount\b|tohavecount|table with|row with \{\{|match data|is at most|\bexactly\b|field with \{\{|\berror\b|invalid|is disabled/,
|
|
781
788
|
need: 'a count/boundary assertion (count is N, `is at most`, the N+1th input rejected or truncated)',
|
|
782
789
|
hint: 'assert the boundary itself — the count at the cap, or the value/error when one more is attempted — not just that the list or field is present.',
|
|
783
|
-
severity: 'fail',
|
|
784
790
|
},
|
|
785
791
|
{
|
|
792
|
+
rule: 'claim.all-every-each',
|
|
786
793
|
claim: 'all/every/each',
|
|
787
794
|
title: /\b(all|every|each)\b/,
|
|
788
795
|
proof: /\bsee all\b/,
|
|
789
796
|
need: 'a `User see all …` assertion (every element, not one)',
|
|
790
797
|
hint: 'assert across all matched elements — for per-card structure use the all-card DSL (roadmap Q2).',
|
|
791
|
-
severity: 'fail',
|
|
792
798
|
// singular action presence under an "each/every" claim = partial proof
|
|
793
799
|
underproof: /\bsee \[[^\]]+\] (link|button)\b/,
|
|
794
800
|
underNeed: 'an all-card assertion for the claimed action (not single presence)',
|
|
795
801
|
underHint: 'the actions are asserted once, not per-card — wrap them with the all-card DSL `User see all [Card] contain [Action]` (roadmap Q2).',
|
|
796
802
|
},
|
|
797
803
|
{
|
|
804
|
+
rule: 'claim.only-belong-to',
|
|
798
805
|
claim: 'only/belong-to',
|
|
799
806
|
title: /\b(only|belongs? to|exclusively)\b/,
|
|
800
807
|
proof: /\bsee all\b[^.]*\bcontain/,
|
|
801
808
|
need: 'all-match (`User see all … contains …`)',
|
|
802
809
|
hint: 'all displayed items must match the facet; "no items OUTSIDE" is UI-limited → verify via hybrid API/DB or mark @manual with reason.',
|
|
803
|
-
severity: 'warn',
|
|
804
810
|
},
|
|
805
811
|
{
|
|
812
|
+
rule: 'claim.single-exactly-one',
|
|
806
813
|
claim: 'single/exactly-one',
|
|
807
814
|
title: /\b(a single|single|exactly one|just one|only one)\b/,
|
|
808
815
|
proof: /\bcount\b|\btable with\b|\bexactly\b|tohavecount/,
|
|
809
816
|
need: 'a count assertion (e.g. count is 1)',
|
|
810
817
|
hint: 'assert the quantity, not just presence.',
|
|
811
|
-
severity: 'fail',
|
|
812
818
|
},
|
|
813
819
|
{
|
|
820
|
+
rule: 'claim.correct-matching-identity',
|
|
814
821
|
claim: 'correct/matching/identity',
|
|
815
822
|
title: /\b(correct|matching|the same|same (product|name|price|value|item)|consistency|identity|lands? in|is the (product|item))\b/,
|
|
816
823
|
proof: /\bremember\b/,
|
|
817
824
|
need: 'capture + compare (`User remember … as {{v}}` then assert {{v}})',
|
|
818
825
|
hint: 'remember the value on the source, then assert it on the target (cross-screen → defer to a flow as @manual).',
|
|
819
|
-
severity: 'fail',
|
|
820
826
|
},
|
|
821
827
|
{
|
|
828
|
+
rule: 'claim.changes-toggles',
|
|
822
829
|
claim: 'changes/toggles',
|
|
823
830
|
title: /\b(changes?|toggles?|updates?|reflects?|reopens?)\b/,
|
|
824
831
|
proof: /\bremember\b|\bis hidden\b/,
|
|
825
832
|
need: 'a state delta (before ≠ after, or a visible→hidden contrast)',
|
|
826
833
|
hint: 'capture the before-state and assert the after-state differs, or assert the visible/hidden transition.',
|
|
827
|
-
severity: 'warn',
|
|
828
834
|
},
|
|
829
835
|
{
|
|
830
836
|
// GENERAL — mutation-absence. A title asserts that a STATE-CHANGING action does NOT
|
|
@@ -835,6 +841,7 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
835
841
|
// count/contrast (record count unchanged) or defer to @manual. This is the general
|
|
836
842
|
// category behind "browser back does not re-submit", "does not re-charge the card",
|
|
837
843
|
// "double-click does not create two orders" — not a per-feature keyword.
|
|
844
|
+
rule: 'claim.no-side-effect',
|
|
838
845
|
claim: 'no-side-effect/no-duplicate',
|
|
839
846
|
// The negation must attach to an EFFECT — something created, sent, stored, charged, fired
|
|
840
847
|
// twice — not to the INPUT being refused. "duplicate address is rejected" is an observable
|
|
@@ -852,33 +859,33 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
852
859
|
proof: /\bcount\b|ok_count|status_counts|row with \{\{|table with|tohavecount|is hidden|are hidden|is disabled|are disabled|not complete|no longer/,
|
|
853
860
|
need: 'a record/request-count proof (count stays at one, e.g. `User see [Table] row with {{count}}`, an API `{{name.ok_count}}` invariant, or a `@query` DB count) or @manual with a request-count oracle',
|
|
854
861
|
hint: 'a "does-not-happen / does-not-repeat" claim about a state-changing action is NOT proven by a terminal `see [...] page` — that page is identical whether or not the action (re-)fired. Prove the side-effect count is unchanged, or mark @manual with a setup→action→assert-no-duplicate oracle.',
|
|
855
|
-
severity: 'fail',
|
|
856
862
|
},
|
|
857
863
|
{
|
|
864
|
+
rule: 'claim.hidden-rejected',
|
|
858
865
|
claim: 'hidden/rejected/not-complete',
|
|
859
866
|
title: /\b(hidden|closed|dismiss(es|ed)?|not complete|rejected|inert)\b/,
|
|
860
867
|
proof: /\bis hidden\b|\bare hidden\b|message is hidden|not complete|\bhidden\b/,
|
|
861
868
|
need: 'a negative / hidden assertion (`… is hidden`)',
|
|
862
869
|
hint: 'assert the absence/hidden state that the title claims, not just an unrelated visible element.',
|
|
863
|
-
severity: 'fail',
|
|
864
870
|
},
|
|
865
871
|
{
|
|
872
|
+
rule: 'claim.cleared-emptied',
|
|
866
873
|
claim: 'cleared/emptied',
|
|
867
874
|
title: /\b(cleared|clears|emptied|empties|reset to empty|wiped)\b/,
|
|
868
875
|
proof: /\bis empty\b|with \{\{empty|with ['"]?['"]?\s*$|\bempty\b/,
|
|
869
876
|
need: 'an empty/cleared assertion after the action (e.g. `field with {{empty_value}}` / `is empty`)',
|
|
870
877
|
hint: 'prove the value is actually gone — return to the screen and assert the field is empty, not just that the action ran.',
|
|
871
|
-
severity: 'fail',
|
|
872
878
|
},
|
|
873
879
|
{
|
|
880
|
+
rule: 'claim.restored-preserved',
|
|
874
881
|
claim: 'restored/preserved',
|
|
875
882
|
title: /\b(restored|preserved|persists?|retained|remembered|kept)\b/,
|
|
876
883
|
proof: /\bremember\b|with \{\{|field with/,
|
|
877
884
|
need: 'the value re-asserted after the transition (capture or `field with {{v}}` after returning)',
|
|
878
885
|
hint: 'prove the value survives — assert the field still holds the typed value after the reload/return, not just that it was typed.',
|
|
879
|
-
severity: 'warn',
|
|
880
886
|
},
|
|
881
887
|
{
|
|
888
|
+
rule: 'claim.independent-separate',
|
|
882
889
|
claim: 'independent/separate',
|
|
883
890
|
title: /\b(independent|separate|isolat(ed|es)|per[- ]tab|two tabs|each tab)\b/,
|
|
884
891
|
// A storage `does not exist` check on the OTHER tenant's key proves isolation
|
|
@@ -887,23 +894,22 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
887
894
|
proof: /\bcontext\b|tab a|tab b|second (tab|context)|does not exist/,
|
|
888
895
|
need: 'a multi-context proof (tab A vs tab B)',
|
|
889
896
|
hint: 'independence across tabs/contexts is rarely DSL-expressible — mark @manual with a clear setup/action/oracle.',
|
|
890
|
-
severity: 'warn',
|
|
891
897
|
},
|
|
892
898
|
{
|
|
899
|
+
rule: 'claim.sanitized-inert',
|
|
893
900
|
claim: 'sanitized/inert',
|
|
894
901
|
title: /\b(sanitized|sanitised|escaped|inert|not executed|not rendered|stripped)\b/,
|
|
895
902
|
proof: /field with \{\{|payload|inert|toContainText|is hidden/,
|
|
896
903
|
need: 'the payload echoed as inert text (`field with {{payload}}`) + no execution',
|
|
897
904
|
hint: 'prove the payload round-trips as literal text and triggers nothing — assert the field value and the absence of any effect.',
|
|
898
|
-
severity: 'warn',
|
|
899
905
|
},
|
|
900
906
|
{
|
|
907
|
+
rule: 'claim.announces-aria',
|
|
901
908
|
claim: 'announces/aria',
|
|
902
909
|
title: /\b(announce[sd]?|aria|screen[- ]reader|programmatically associated)\b/,
|
|
903
910
|
proof: /aria|role|@manual|describedby|is focused|tab order/,
|
|
904
911
|
need: 'an aria/role assertion (or @manual with a screen-reader oracle)',
|
|
905
912
|
hint: 'ARIA announcement is usually not DSL-expressible — assert aria attributes if possible, else @manual with an NVDA/VoiceOver oracle.',
|
|
906
|
-
severity: 'warn',
|
|
907
913
|
},
|
|
908
914
|
{
|
|
909
915
|
// GENERAL CATCH-ALL (last) — any negative/absence title not handled by a specific
|
|
@@ -913,6 +919,7 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
913
919
|
// only a positive presence. WARN, because a positive proxy is sometimes a valid
|
|
914
920
|
// negative proof (e.g. "stayed on the login page"); the semantic reviewer is the
|
|
915
921
|
// authoritative recall layer for the residue this can't judge structurally.
|
|
922
|
+
rule: 'claim.negative-absence',
|
|
916
923
|
claim: 'negative-claim/absence',
|
|
917
924
|
title: /(\bno\b|\bnot\b|n['’]t\b|\bnever\b|\bwithout\b|\bcannot\b|prevent|block|avoid|reject|disabl|\bdeny\b|denies|\bkhông\b|\bchưa\b)/i,
|
|
918
925
|
// `does not exist` covers the storage-absence shape — the broad "any storage
|
|
@@ -922,7 +929,6 @@ const CLAIM_RULES: ClaimRule[] = [
|
|
|
922
929
|
proof: /is hidden|are hidden|is empty|no longer|not complete|disabl|invalid|rejected|\berror\b|\bcount\b|row with \{\{|table with|\bremember\b|\bexactly\b|tohavecount|does not exist|tab order/i,
|
|
923
930
|
need: 'a proof of the ABSENCE — a contrast/empty/hidden/error/count assertion, or @manual with an oracle',
|
|
924
931
|
hint: 'a negative claim ("no / not / không …") is not proven by a positive `see [X]` that looks the same whether or not the claim holds. Assert the contrast (state hidden/empty, error shown, count unchanged), or mark @manual.',
|
|
925
|
-
severity: 'warn',
|
|
926
932
|
},
|
|
927
933
|
];
|
|
928
934
|
|
|
@@ -1015,7 +1021,12 @@ export function taxonomyLint(scenarios: ScenarioInfo[]): TaxonomyResult {
|
|
|
1015
1021
|
return { total: scenarios.length, checked, mislabeled };
|
|
1016
1022
|
}
|
|
1017
1023
|
|
|
1018
|
-
|
|
1024
|
+
/**
|
|
1025
|
+
* `rules` resolves each row's catalog rule for the unit being audited (the catalog alone by default —
|
|
1026
|
+
* today's levels). A rule switched `off` by a gate-override is not measured: its unproven claim is
|
|
1027
|
+
* neither counted nor reported (a partial-proof switched off leaves the claim proven).
|
|
1028
|
+
*/
|
|
1029
|
+
export function claimProof(scenarios: ScenarioInfo[], focus = 'functional', rules: GateRules = CATALOG_GATE_RULES): ClaimProofResult {
|
|
1019
1030
|
const measured = scenarios.filter((s) => !s.manual);
|
|
1020
1031
|
const unproven: ClaimUnproven[] = [];
|
|
1021
1032
|
let withClaims = 0;
|
|
@@ -1024,19 +1035,17 @@ export function claimProof(scenarios: ScenarioInfo[], focus = 'functional'): Cla
|
|
|
1024
1035
|
const title = s.name.toLowerCase();
|
|
1025
1036
|
const rule = CLAIM_RULES.find((r) => r.title.test(title));
|
|
1026
1037
|
if (!rule) continue; // no claim → not measured
|
|
1038
|
+
const miss = !rule.proof.test(s.stepsText)
|
|
1039
|
+
// proof shape entirely absent → the claim's own rule decides the level
|
|
1040
|
+
? { rule: rule.rule, need: rule.need, hint: rule.hint }
|
|
1041
|
+
: rule.underproof && rule.underproof.test(s.stepsText)
|
|
1042
|
+
// right shape exists but only as a partial proof
|
|
1043
|
+
? { rule: 'claim.partial-proof', need: rule.underNeed ?? rule.need, hint: rule.underHint ?? rule.hint }
|
|
1044
|
+
: null;
|
|
1045
|
+
const severity = miss ? sensorSeverityOf(rules.resolve(miss.rule)) : undefined;
|
|
1046
|
+
if (miss && severity === null && miss.rule === rule.rule) continue; // the claim's rule is off for this unit
|
|
1027
1047
|
withClaims++;
|
|
1028
|
-
if (
|
|
1029
|
-
// proof shape entirely absent → fail at the rule's severity
|
|
1030
|
-
unproven.push({ name: s.name, claim: rule.claim, need: rule.need, hint: rule.hint, severity: rule.severity });
|
|
1031
|
-
} else if (rule.underproof && rule.underproof.test(s.stepsText)) {
|
|
1032
|
-
// right shape exists but only as a partial proof → warn
|
|
1033
|
-
unproven.push({
|
|
1034
|
-
name: s.name, claim: rule.claim,
|
|
1035
|
-
need: rule.underNeed ?? rule.need,
|
|
1036
|
-
hint: rule.underHint ?? rule.hint,
|
|
1037
|
-
severity: 'warn',
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1048
|
+
if (miss && severity) unproven.push({ name: s.name, claim: rule.claim, need: miss.need, hint: miss.hint, severity, rule: miss.rule });
|
|
1040
1049
|
}
|
|
1041
1050
|
|
|
1042
1051
|
const proven = withClaims - unproven.length;
|
|
@@ -1044,10 +1053,7 @@ export function claimProof(scenarios: ScenarioInfo[], focus = 'functional'): Cla
|
|
|
1044
1053
|
const threshold = DEPTH_THRESHOLDS[focus] ?? DEPTH_THRESHOLDS.functional;
|
|
1045
1054
|
|
|
1046
1055
|
const hasFail = unproven.some((u) => u.severity === 'fail');
|
|
1047
|
-
|
|
1048
|
-
if (ratio < threshold) {
|
|
1049
|
-
verdict = WARN_ONLY_FOCUS.has(focus) || !hasFail ? 'warn' : 'fail';
|
|
1050
|
-
}
|
|
1056
|
+
const verdict = ruleVerdict(rules, 'audit.claim-proof', ratio < threshold, WARN_ONLY_FOCUS.has(focus) || !hasFail);
|
|
1051
1057
|
|
|
1052
1058
|
return { total: measured.length, withClaims, proven, unproven, ratio, focus, threshold, verdict };
|
|
1053
1059
|
}
|
|
@@ -1103,6 +1109,8 @@ export function priorityMismatches(
|
|
|
1103
1109
|
const declared = new Map<string, string>();
|
|
1104
1110
|
for (const v of viewpoints) if (v.priorityWord) declared.set(v.id.toUpperCase(), v.priorityWord);
|
|
1105
1111
|
if (declared.size === 0) return [];
|
|
1112
|
+
// `medium` and `normal` are the same rank under different names in real documents.
|
|
1113
|
+
const rank = (p: string): string => (p === 'medium' ? 'normal' : p);
|
|
1106
1114
|
const out: Array<{ id: string; declared: string; tagged: string; scenario: string }> = [];
|
|
1107
1115
|
for (const s of scenarios) {
|
|
1108
1116
|
const id = (s.vpId ?? '').toUpperCase();
|
|
@@ -1110,14 +1118,12 @@ export function priorityMismatches(
|
|
|
1110
1118
|
// The most specific declared row that prefixes this id.
|
|
1111
1119
|
const key = [...declared.keys()].filter((k) => id.startsWith(k)).sort((a, b) => b.length - a.length)[0];
|
|
1112
1120
|
if (!key) continue;
|
|
1113
|
-
|
|
1114
|
-
const
|
|
1115
|
-
// `deferred` and `skip` (declared not applicable, #853) have no tag equivalent —
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
if (!tagged) continue;
|
|
1120
|
-
if (want !== parsePriority(tagged)) out.push({ id: key, declared: declared.get(key)!, tagged, scenario: s.name });
|
|
1121
|
+
const want = rank(declared.get(key)!);
|
|
1122
|
+
const got = rank(String(s.priority).toLowerCase());
|
|
1123
|
+
// `critical`, `deferred` and `skip` (declared not applicable, #853) have no tag equivalent —
|
|
1124
|
+
// nothing to contradict.
|
|
1125
|
+
if (want === 'critical' || want === 'deferred' || want === 'skip') continue;
|
|
1126
|
+
if (want !== got) out.push({ id: key, declared: declared.get(key)!, tagged: got, scenario: s.name });
|
|
1121
1127
|
}
|
|
1122
1128
|
return out;
|
|
1123
1129
|
}
|
|
@@ -2,7 +2,6 @@ import * as crypto from 'crypto';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { parseViewpointOverview } from './parse';
|
|
5
|
-
import { isAiDraft, removeDraftLine } from './viewpoint-draft-header';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Keep the yardstick from moving with the thing it measures.
|
|
@@ -90,12 +89,7 @@ function fingerprint(ids: string[]): string {
|
|
|
90
89
|
*/
|
|
91
90
|
function fileFingerprint(viewpointPath: string): string {
|
|
92
91
|
try {
|
|
93
|
-
|
|
94
|
-
// `drafted-by: ai` is provenance that accept REMOVES, so it is not part of what was reviewed:
|
|
95
|
-
// counted, accepting a draft would read as the declaration changing. Every other byte stays raw.
|
|
96
|
-
const text = bytes.toString('utf-8');
|
|
97
|
-
const hashed = isAiDraft(text) ? Buffer.from(removeDraftLine(text), 'utf-8') : bytes;
|
|
98
|
-
return crypto.createHash('sha1').update(hashed).digest('hex').slice(0, 12);
|
|
92
|
+
return crypto.createHash('sha1').update(fs.readFileSync(viewpointPath)).digest('hex').slice(0, 12);
|
|
99
93
|
} catch { return ''; }
|
|
100
94
|
}
|
|
101
95
|
|
|
@@ -58,13 +58,6 @@ function claimedCount(text: string): number | null {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const ID_RE = /\b([A-Z]{1,5}\d{0,2}(?:[.\-][A-Za-z0-9]+)*-?\d{0,3})\b/; // VP0.Title, VP7-002, MS-HP-001, TV-01
|
|
61
|
-
/**
|
|
62
|
-
* A bullet declares only the id it STARTS with (after a `[ ]` checkbox); one further along is a
|
|
63
|
-
* citation (`… (SG-01, …)`). `- **High** VP-…` or `- Email shown — VP-…` therefore carry no id.
|
|
64
|
-
*/
|
|
65
|
-
const BULLET_ID = new RegExp(`^[\\s(#]*(?:\\[[ xX]\\]\\s*)?\\[?${ID_RE.source}`);
|
|
66
|
-
/** A table cell that is an id and nothing else. */
|
|
67
|
-
const WHOLE_ID = new RegExp(`^${ID_RE.source}$`);
|
|
68
61
|
|
|
69
62
|
/**
|
|
70
63
|
* Lines that DECLARE something about the checklist rather than being a checklist item —
|
|
@@ -109,31 +102,17 @@ const PROCEDURE_LEAD = /^(?:how to (?:run|test|reproduce|verify)|(?:manual )?pro
|
|
|
109
102
|
const LIST_ITEM = /^(?:[-*+]|\d+[.)])\s+/;
|
|
110
103
|
const GENERIC = new Set(['display', 'shown', 'value', 'field', 'input', 'page', 'screen', 'button', 'link', 'text', 'check', 'verify', 'should', 'with', 'when', 'then', 'user', 'this', 'that', 'each', 'item', 'items']);
|
|
111
104
|
|
|
112
|
-
/**
|
|
113
|
-
* `decision`: a `- D4: …` line under Design Decisions. It names the spec's intent so rows can cite
|
|
114
|
-
* it; its testable part is carried by a VP row (review check 8). No scenario ever carries `D4`, so
|
|
115
|
-
* as a ledger item it stayed MISSING for good — "not tested" decisions included (phase-7 D5). The
|
|
116
|
-
* ledger skips it; the continuity, source and integrity checks still read it. Only that section
|
|
117
|
-
* declares: a QA claim labelled `D8` elsewhere stays a claim, and an id-less decision bullet stays
|
|
118
|
-
* the prose claim it always was.
|
|
119
|
-
*/
|
|
120
|
-
export interface ViewpointItem { id?: string; text: string; decision?: true }
|
|
121
|
-
const DECISION_ID = /^D\d+$/;
|
|
122
|
-
const DECISIONS_SECTION = /^(?:design decisions?|quyết định(?: thiết kế)?)\b/i;
|
|
123
|
-
|
|
124
105
|
/** Extract atomic checklist items from a viewpoint file (format-tolerant). */
|
|
125
|
-
export function parseViewpointItems(viewpointPath: string):
|
|
106
|
+
export function parseViewpointItems(viewpointPath: string): { id?: string; text: string }[] {
|
|
126
107
|
if (!fs.existsSync(viewpointPath)) return [];
|
|
127
108
|
const lines = readViewpointText(viewpointPath).split('\n');
|
|
128
|
-
const items:
|
|
109
|
+
const items: { id?: string; text: string }[] = [];
|
|
129
110
|
let inFence = false;
|
|
130
111
|
let inDeclarationSection = false;
|
|
131
112
|
// The level an excluded section was opened at. A SUBSECTION inherits it: `### Optional`
|
|
132
113
|
// nested under `## 8. Traceability Index` used to re-open the section and hand its rows
|
|
133
114
|
// back as claims, because exclusion was recomputed from scratch at every heading.
|
|
134
115
|
let excludedAt: number | null = null;
|
|
135
|
-
// The level the Design Decisions section was opened at, while inside it (see `decision`).
|
|
136
|
-
let decisionsAt: number | null = null;
|
|
137
116
|
// Inside the list a PROCEDURE_LEAD introduced: the indent of the lead (-1 for a paragraph lead),
|
|
138
117
|
// whose list items — and their wrapped continuation lines — are steps. A heading, a table, a
|
|
139
118
|
// new lead, or (after a paragraph lead) a blank line once a step was read ends it: when in
|
|
@@ -168,28 +147,21 @@ export function parseViewpointItems(viewpointPath: string): ViewpointItem[] {
|
|
|
168
147
|
if (heading) {
|
|
169
148
|
const level = heading[1].length;
|
|
170
149
|
if (excludedAt !== null && level > excludedAt) continue; // still inside the excluded section
|
|
171
|
-
if (decisionsAt !== null && level > decisionsAt) continue; // a subsection of Design Decisions
|
|
172
150
|
// A heading both ends the previous section and decides whether this one declares or claims.
|
|
173
151
|
// Strip an ordinal prefix ("## 5. Known Issues", "## 8. Viewpoint Grouping") before
|
|
174
152
|
// testing. The regex anchors at the start, so a NUMBERED heading matched nothing and
|
|
175
153
|
// every excluded section leaked its rows back in as claims — a real viewpoint numbers
|
|
176
154
|
// its sections, so in practice the exclusion list was doing nothing at all (#657).
|
|
177
|
-
|
|
178
|
-
const headText = heading[2].replace(/[*`]/g, '').replace(/^\s*(?:(?:[Pp]hần|[Pp]art|[Mm]ục|[Ss]ection)\s+)?(?:\d+|[A-Z])\s*[.):]\s*/, '').trim();
|
|
155
|
+
const headText = heading[2].replace(/[*`]/g, '').replace(/^\s*(?:\d+|[A-Z])\s*[.):]\s*/, '').trim();
|
|
179
156
|
inDeclarationSection = DECLARATION_SECTION.test(headText);
|
|
180
157
|
excludedAt = inDeclarationSection ? level : null;
|
|
181
|
-
decisionsAt = DECISIONS_SECTION.test(headText) ? level : null;
|
|
182
158
|
continue;
|
|
183
159
|
}
|
|
184
160
|
if (inDeclarationSection) continue;
|
|
185
161
|
let text = '';
|
|
186
162
|
let lead = '';
|
|
187
|
-
let declared: RegExpMatchArray | null = null;
|
|
188
163
|
const bullet = line.match(/^(?:[-*+]|\d+[.)])\s+(.*)$/);
|
|
189
|
-
if (bullet) {
|
|
190
|
-
text = bullet[1]; lead = bullet[1];
|
|
191
|
-
declared = lead.replace(/[*`]/g, '').match(BULLET_ID);
|
|
192
|
-
}
|
|
164
|
+
if (bullet) { text = bullet[1]; lead = bullet[1]; }
|
|
193
165
|
else if (line.startsWith('|')) { // table data row
|
|
194
166
|
if (/^\|[\s|:-]+\|?$/.test(line)) continue; // separator
|
|
195
167
|
// The row right above a `|---|` separator IS the header, whatever its words (`Skill #`,
|
|
@@ -200,14 +172,7 @@ export function parseViewpointItems(viewpointPath: string): ViewpointItem[] {
|
|
|
200
172
|
const cells = line.split('|').map((c) => c.trim()).filter(Boolean);
|
|
201
173
|
if (/^(vp|id|viewpoint|priority|reason|no\.?|category|item|trigger|#|pattern|applicable|notes|field|constraint|code|description|status|step|flow|ref|level|question|screen|actor|branches from|own steps|component|thành phần|trường|bước)$/i.test(cells[0] || '')) continue; // header
|
|
202
174
|
text = cells.join(' — ');
|
|
203
|
-
|
|
204
|
-
// declares nothing. A later cell holding an id and nothing else still declares (`| x | VP-UI-001 |`),
|
|
205
|
-
// and so does a row number followed by a cell that starts with one (`| 1 | VP-UI-001 — … |`).
|
|
206
|
-
const raw = line.replace(/^\|/, '').replace(/\|$/, '').split('|').map((c) => c.replace(/[*`]/g, '').trim());
|
|
207
|
-
lead = raw[0] ?? '';
|
|
208
|
-
declared = lead.match(ID_RE)
|
|
209
|
-
?? (/^\d+\.?$/.test(lead) ? (raw[1] ?? '').match(BULLET_ID) : null)
|
|
210
|
-
?? raw.slice(1).map((c) => c.match(WHOLE_ID)).find(Boolean) ?? null;
|
|
175
|
+
lead = cells[0] ?? '';
|
|
211
176
|
} else continue;
|
|
212
177
|
text = text.replace(/[*`]/g, '').trim();
|
|
213
178
|
if (!text) continue;
|
|
@@ -222,16 +187,15 @@ export function parseViewpointItems(viewpointPath: string): ViewpointItem[] {
|
|
|
222
187
|
// under a grouping section. It declares nothing; it points at things declared elsewhere.
|
|
223
188
|
const leadIds = new Set((leadClean.match(new RegExp(ID_RE.source, 'g')) || []).filter((x) => /\d/.test(x)));
|
|
224
189
|
if (leadIds.size > 1) continue;
|
|
225
|
-
const
|
|
190
|
+
const idM = leadClean.match(ID_RE) ?? text.match(ID_RE);
|
|
191
|
+
const id = idM && /\d/.test(idM[1]) ? idM[1] : undefined; // require a digit so prose words aren't IDs
|
|
226
192
|
// A row keyed by a bare GROUP prefix ("VP-LOGIC — transitions — High — why the flow exists")
|
|
227
193
|
// declares a family and its priority, not a checklist item: nothing can "cover" it, and
|
|
228
194
|
// demanding coverage sends the author looking for a test that was never meant to exist.
|
|
229
195
|
if (/^VP-[A-Z]+\s*(?:—|-|\||$)/.test(leadClean) && !/\d/.test(leadClean)) continue;
|
|
230
196
|
const words = (text.toLowerCase().match(/[a-z][a-z-]{3,}/g) || []).filter((w) => !GENERIC.has(w));
|
|
231
197
|
if (!id && words.length < 2) continue; // not substantive enough to track
|
|
232
|
-
items.push(
|
|
233
|
-
? { id, text: text.slice(0, 100), decision: true }
|
|
234
|
-
: { id, text: text.slice(0, 100) });
|
|
198
|
+
items.push({ id, text: text.slice(0, 100) });
|
|
235
199
|
}
|
|
236
200
|
return items;
|
|
237
201
|
}
|
|
@@ -242,7 +206,6 @@ export function viewpointLedger(viewpointPath: string, scenarios: ScenarioInfo[]
|
|
|
242
206
|
// (#622) — silently collapsing those would remove its input.
|
|
243
207
|
const seen = new Set<string>();
|
|
244
208
|
const items = parseViewpointItems(viewpointPath)
|
|
245
|
-
.filter((i) => !i.decision)
|
|
246
209
|
.filter((i) => { const k = `${i.id ?? ''}|${i.text}`; if (seen.has(k)) return false; seen.add(k); return true; });
|
|
247
210
|
if (!fs.existsSync(viewpointPath) || items.length === 0) {
|
|
248
211
|
return { hasViewpoint: fs.existsSync(viewpointPath), total: 0, covered: 0, ratio: 1, missing: [], manualOnly: [], partial: [] };
|
|
@@ -434,15 +397,11 @@ export function viewpointIntegrity(
|
|
|
434
397
|
|
|
435
398
|
// The Priority-Viewpoints table: `| <id> | <priority> | <reason> |`.
|
|
436
399
|
const vpText = readViewpointText(viewpointPath);
|
|
437
|
-
const
|
|
400
|
+
const rows = [...vpText
|
|
438
401
|
.matchAll(new RegExp(`^\\|\\s*((?:VP|FL)[A-Z0-9._-]*)\\s*\\|\\s*(${PRIORITY_WORDS})\\s*\\|`, 'gim'))]
|
|
439
402
|
.map((m) => m[2].toLowerCase());
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const level = (w: string): string => (/^(?:medium|med|normal)$/.test(w) ? 'normal' : w);
|
|
443
|
-
const uniformPriority = words.length >= 3 && new Set(words.map(level)).size === 1
|
|
444
|
-
? { levels: [words[0]], rows: words.length } // the word QA wrote, not the folded key
|
|
445
|
-
: null;
|
|
403
|
+
const levels = [...new Set(rows)];
|
|
404
|
+
const uniformPriority = rows.length >= 3 && levels.length === 1 ? { levels, rows: rows.length } : null;
|
|
446
405
|
|
|
447
406
|
return { duplicateIds, danglingRefs, uniformPriority };
|
|
448
407
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a Bash command line WRITES through the three forms the pre-tool guard covers (P0.1):
|
|
3
|
+
* output redirection (`>`, `>>`, `>|`, `&>`, `2>`…), `tee`, and in-place `sed -i`.
|
|
4
|
+
*
|
|
5
|
+
* A floor, not a shell interpreter: quotes, escapes, `;`/`&&`/`||`/`|` and a leading `cd` are
|
|
6
|
+
* understood; anything else that can write a file (`cp`, a script, `python -c`) is out of scope by
|
|
7
|
+
* design. The command string is untrusted — it is only tokenized here, never executed.
|
|
8
|
+
*/
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
|
|
11
|
+
type Tok = { kind: 'word'; value: string } | { kind: 'sep' } | { kind: 'redir'; writes: boolean };
|
|
12
|
+
|
|
13
|
+
/** Commands that run another command: the real one is the next word. */
|
|
14
|
+
const WRAPPERS = new Set(['sudo', 'env', 'command', 'nohup', 'time', 'exec', 'nice']);
|
|
15
|
+
const ASSIGNMENT = /^[A-Za-z_]\w*=/;
|
|
16
|
+
|
|
17
|
+
function tokenize(cmd: string): Tok[] {
|
|
18
|
+
const toks: Tok[] = [];
|
|
19
|
+
let word = '';
|
|
20
|
+
let inWord = false;
|
|
21
|
+
const flush = (): void => { if (inWord) toks.push({ kind: 'word', value: word }); word = ''; inWord = false; };
|
|
22
|
+
for (let i = 0; i < cmd.length;) {
|
|
23
|
+
const ch = cmd[i];
|
|
24
|
+
if (ch === "'") {
|
|
25
|
+
const end = cmd.indexOf("'", i + 1);
|
|
26
|
+
word += cmd.slice(i + 1, end < 0 ? cmd.length : end); inWord = true; i = end < 0 ? cmd.length : end + 1;
|
|
27
|
+
} else if (ch === '"') {
|
|
28
|
+
let j = i + 1;
|
|
29
|
+
for (; j < cmd.length && cmd[j] !== '"'; j++) { if (cmd[j] === '\\' && j + 1 < cmd.length) j++; word += cmd[j]; }
|
|
30
|
+
inWord = true; i = j + 1;
|
|
31
|
+
} else if (ch === '\\' && i + 1 < cmd.length) {
|
|
32
|
+
word += cmd[i + 1]; inWord = true; i += 2;
|
|
33
|
+
} else if (ch === ' ' || ch === '\t') {
|
|
34
|
+
flush(); i++;
|
|
35
|
+
} else if ('\n;|()'.includes(ch) || (ch === '&' && cmd[i + 1] !== '>')) {
|
|
36
|
+
flush(); toks.push({ kind: 'sep' }); i += (ch === '|' || ch === '&') && cmd[i + 1] === ch ? 2 : 1;
|
|
37
|
+
} else if (ch === '>' || (ch === '&' && cmd[i + 1] === '>')) {
|
|
38
|
+
if (ch === '>' && inWord && /^\d+$/.test(word)) { word = ''; inWord = false; } else flush(); // `2>`: an fd, not a word
|
|
39
|
+
i += ch === '&' ? 2 : 1;
|
|
40
|
+
if (cmd[i] === '>' || cmd[i] === '|') i++;
|
|
41
|
+
if (cmd[i] === '&') { i++; toks.push({ kind: 'redir', writes: false }); } // `>&2`: an fd dup
|
|
42
|
+
else toks.push({ kind: 'redir', writes: true });
|
|
43
|
+
} else if (ch === '<') {
|
|
44
|
+
flush(); i++;
|
|
45
|
+
while (cmd[i] === '<') i++;
|
|
46
|
+
toks.push({ kind: 'redir', writes: false });
|
|
47
|
+
} else {
|
|
48
|
+
word += ch; inWord = true; i++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
flush();
|
|
52
|
+
return toks;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isInPlaceFlag = (a: string): boolean => a === '--in-place' || a.startsWith('--in-place=') || /^-[a-zA-Z]*i/.test(a);
|
|
56
|
+
|
|
57
|
+
/** One simple command of a Bash line (`a | b && c` is three). */
|
|
58
|
+
export interface BashSegment {
|
|
59
|
+
/** The command name (basename, after env assignments and wrappers like `sudo`), or ''. */
|
|
60
|
+
cmd: string;
|
|
61
|
+
/** Its arguments, and every redirection target, as written. */
|
|
62
|
+
words: string[];
|
|
63
|
+
/** The directory it runs in — a preceding `cd` in the same line is followed. */
|
|
64
|
+
dir: string;
|
|
65
|
+
/** Absolute paths it writes via redirection, `tee` or `sed -i`. */
|
|
66
|
+
writes: string[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function bashSegments(command: string, cwd: string): BashSegment[] {
|
|
70
|
+
const out: BashSegment[] = [];
|
|
71
|
+
const toks = tokenize(command);
|
|
72
|
+
let dir = cwd;
|
|
73
|
+
let seg: string[] = [];
|
|
74
|
+
let redirected: string[] = [];
|
|
75
|
+
let writes: string[] = [];
|
|
76
|
+
const endSegment = (): void => {
|
|
77
|
+
let k = 0;
|
|
78
|
+
while (k < seg.length && (ASSIGNMENT.test(seg[k]) || WRAPPERS.has(seg[k]))) k++;
|
|
79
|
+
const cmd = path.basename(seg[k] ?? '');
|
|
80
|
+
const args = seg.slice(k + 1).filter((a) => a !== '');
|
|
81
|
+
if (cmd === 'tee') writes.push(...args.filter((a) => !a.startsWith('-')).map((a) => path.resolve(dir, a)));
|
|
82
|
+
else if ((cmd === 'sed' || cmd === 'gsed') && args.some(isInPlaceFlag)) {
|
|
83
|
+
writes.push(...args.filter((a) => !a.startsWith('-')).map((a) => path.resolve(dir, a)));
|
|
84
|
+
}
|
|
85
|
+
if (cmd || redirected.length) out.push({ cmd, words: [...args, ...redirected], dir, writes });
|
|
86
|
+
if (cmd === 'cd' && args.length === 1 && !/^[-~]/.test(args[0])) dir = path.resolve(dir, args[0]);
|
|
87
|
+
seg = []; redirected = []; writes = [];
|
|
88
|
+
};
|
|
89
|
+
for (let t = 0; t < toks.length; t++) {
|
|
90
|
+
const tok = toks[t];
|
|
91
|
+
if (tok.kind === 'sep') { endSegment(); continue; }
|
|
92
|
+
if (tok.kind === 'redir') {
|
|
93
|
+
const target = toks[t + 1];
|
|
94
|
+
if (target?.kind !== 'word') continue;
|
|
95
|
+
t++;
|
|
96
|
+
redirected.push(target.value);
|
|
97
|
+
if (tok.writes && target.value && target.value !== '/dev/null' && target.value !== '-') writes.push(path.resolve(dir, target.value));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
seg.push(tok.value);
|
|
101
|
+
}
|
|
102
|
+
endSegment();
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Absolute paths the command writes via redirection, `tee` or `sed -i`, resolved against `cwd`. */
|
|
107
|
+
export function bashWriteTargets(command: string, cwd: string): string[] {
|
|
108
|
+
return bashSegments(command, cwd).flatMap((s) => s.writes);
|
|
109
|
+
}
|