@sun-asterisk/sungen 3.2.34 → 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 +9 -4
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +6 -2
- 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/defect.d.ts +7 -0
- package/dist/cli/commands/defect.d.ts.map +1 -0
- package/dist/cli/commands/defect.js +68 -0
- package/dist/cli/commands/defect.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +87 -10
- 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/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +98 -0
- package/dist/cli/commands/triage.js.map +1 -0
- 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 +24 -33
- 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/csv-exporter.d.ts +4 -0
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +1 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/feature-parser.d.ts +8 -0
- package/dist/exporters/feature-parser.d.ts.map +1 -1
- package/dist/exporters/feature-parser.js +12 -0
- package/dist/exporters/feature-parser.js.map +1 -1
- 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 +59 -19
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
- package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
- package/dist/exporters/matrix/carry-manual-results.js +76 -6
- package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +8 -2
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +16 -3
- 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 +4 -1
- 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 +6 -0
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +9 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +1 -0
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +2 -0
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/types.d.ts +5 -0
- package/dist/exporters/types.d.ts.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 +34 -9
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/counted-assertions.d.ts +2 -0
- package/dist/harness/counted-assertions.d.ts.map +1 -0
- package/dist/harness/counted-assertions.js +38 -0
- package/dist/harness/counted-assertions.js.map +1 -0
- package/dist/harness/defect-draft.d.ts +14 -0
- package/dist/harness/defect-draft.d.ts.map +1 -0
- package/dist/harness/defect-draft.js +143 -0
- package/dist/harness/defect-draft.js.map +1 -0
- package/dist/harness/defects.d.ts +24 -0
- package/dist/harness/defects.d.ts.map +1 -0
- package/dist/harness/defects.js +118 -0
- package/dist/harness/defects.js.map +1 -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 +73 -45
- package/dist/harness/manifest.js.map +1 -1
- package/dist/harness/next-step.d.ts +37 -6
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +34 -174
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +25 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +38 -13
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +29 -6
- 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 +64 -44
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/triage-signals.d.ts +20 -0
- package/dist/harness/triage-signals.d.ts.map +1 -0
- package/dist/harness/triage-signals.js +30 -0
- package/dist/harness/triage-signals.js.map +1 -0
- package/dist/harness/triage-unit.d.ts +23 -0
- package/dist/harness/triage-unit.d.ts.map +1 -0
- package/dist/harness/triage-unit.js +142 -0
- package/dist/harness/triage-unit.js.map +1 -0
- package/dist/harness/triage.d.ts +28 -0
- package/dist/harness/triage.d.ts.map +1 -0
- package/dist/harness/triage.js +99 -0
- package/dist/harness/triage.js.map +1 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +2 -1
- 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/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 +4 -2
- 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 +14 -16
- 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 +14 -10
- 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-error-mapping/SKILL.md +2 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- 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 +9 -4
- package/src/cli/commands/capability.ts +4 -2
- package/src/cli/commands/contract-derive-command.ts +60 -0
- package/src/cli/commands/contract.ts +130 -0
- package/src/cli/commands/defect.ts +49 -0
- package/src/cli/commands/delivery.ts +85 -13
- 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/triage.ts +57 -0
- package/src/cli/commands/update.ts +35 -8
- package/src/cli/index.ts +24 -30
- 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/csv-exporter.ts +5 -1
- package/src/exporters/feature-parser.ts +12 -0
- package/src/exporters/matrix/build.ts +62 -18
- package/src/exporters/matrix/carry-manual-results.ts +70 -7
- package/src/exporters/matrix/export.ts +17 -2
- package/src/exporters/matrix/gates.ts +62 -129
- package/src/exporters/matrix/render-csv.ts +4 -1
- package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
- package/src/exporters/matrix/render-xlsx.ts +6 -0
- package/src/exporters/matrix/types.ts +9 -1
- package/src/exporters/playwright-report-parser.ts +1 -0
- package/src/exporters/scenario-merger.ts +2 -1
- package/src/exporters/types.ts +5 -0
- 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 +46 -11
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/counted-assertions.ts +33 -0
- package/src/harness/defect-draft.ts +115 -0
- package/src/harness/defects.ts +94 -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 +69 -45
- package/src/harness/next-step.ts +60 -170
- package/src/harness/parse.ts +40 -13
- package/src/harness/script-check.ts +27 -6
- package/src/harness/sensors.ts +73 -47
- package/src/harness/triage-signals.ts +46 -0
- package/src/harness/triage-unit.ts +113 -0
- package/src/harness/triage.ts +127 -0
- package/src/harness/viewpoint-ledger.ts +2 -2
- 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/lockstep-version.ts +28 -15
- package/src/orchestrator/project-initializer.ts +21 -0
- package/src/orchestrator/screen-manager.ts +3 -1
- 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 +14 -16
- 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 +14 -10
- 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-error-mapping/SKILL.md +2 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/utils/safe-yaml-parse.ts +44 -0
|
@@ -12,11 +12,15 @@
|
|
|
12
12
|
* claude-tools: "Read, Grep, ..." # verbatim allowed-tools line for Claude
|
|
13
13
|
* codex-trigger: "Run when the user asks to ..." # explicit trigger for Codex (P2 mitigation)
|
|
14
14
|
* copilot-tools: "[vscode, execute, ...]" # optional; default used if absent
|
|
15
|
+
* unit-arg: "<screen-name>" # optional; fills {{unitArg}} in partials (default <unit>)
|
|
15
16
|
* ---
|
|
17
|
+
* <!-- include: hand-back-rule --> # REQUIRED — see command-partial-includes.ts
|
|
16
18
|
* <body with cap-fences>
|
|
17
19
|
*/
|
|
18
20
|
import { stripCaps } from './cap-stripper';
|
|
19
21
|
import { GenFile } from './generator';
|
|
22
|
+
import type { AdapterKey } from './adapters';
|
|
23
|
+
import { assertRequiredIncludes, expandIncludes } from './command-partial-includes';
|
|
20
24
|
|
|
21
25
|
export interface CommandSource {
|
|
22
26
|
id: string; // command identity (from source filename) — drives output paths
|
|
@@ -27,7 +31,9 @@ export interface CommandSource {
|
|
|
27
31
|
claudeTools: string;
|
|
28
32
|
copilotTools: string;
|
|
29
33
|
codexTrigger: string;
|
|
30
|
-
|
|
34
|
+
/** What `{{unitArg}}` renders as inside a partial — the unit placeholder the command takes. */
|
|
35
|
+
unitArg: string;
|
|
36
|
+
body: string; // with cap-fences and include directives
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
const DEFAULT_COPILOT_TOOLS = '[vscode, execute, read, edit, search, todo]';
|
|
@@ -58,23 +64,29 @@ export function parseCommandSource(text: string, id: string): CommandSource {
|
|
|
58
64
|
claudeTools: dec('claude-tools'),
|
|
59
65
|
copilotTools: raw['copilot-tools'] ? dec('copilot-tools') : DEFAULT_COPILOT_TOOLS,
|
|
60
66
|
codexTrigger: dec('codex-trigger'),
|
|
67
|
+
unitArg: dec('unit-arg') || '<unit>',
|
|
61
68
|
body,
|
|
62
69
|
};
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
const unquote = (s: string) => s.replace(/^['"]|['"]$/g, '');
|
|
73
|
+
/** The body as one assistant sees it: its own partials pulled in, then its cap-fences resolved. */
|
|
74
|
+
const bodyFor = (c: CommandSource, adapter: AdapterKey, caps: string[]): string =>
|
|
75
|
+
stripCaps(expandIncludes(c.body, adapter, c.id, { unitArg: c.unitArg }), caps, `cmd:${c.id}`);
|
|
76
|
+
/** A YAML single-quoted scalar: an apostrophe is written twice, or it ends the value early (#899). */
|
|
77
|
+
const sq = (s: string) => `'${s.replace(/'/g, "''")}'`;
|
|
66
78
|
|
|
67
79
|
/** Claude command file — MUST reproduce the exact existing format (byte-identical gate). */
|
|
68
80
|
export function renderClaudeCommand(c: CommandSource): string {
|
|
69
81
|
const fm = [
|
|
70
82
|
'---',
|
|
71
83
|
...(c.name ? [`name: ${c.name}`] : []), // some commands (locale) omit name
|
|
72
|
-
`description:
|
|
84
|
+
`description: ${sq(c.description)}`,
|
|
73
85
|
`argument-hint: ${c.argumentHint}`,
|
|
74
86
|
`allowed-tools: ${c.claudeTools}`,
|
|
75
87
|
'---',
|
|
76
88
|
].join('\n');
|
|
77
|
-
return fm + '\n\n' +
|
|
89
|
+
return fm + '\n\n' + bodyFor(c, 'claude', ['parallel-subagents']);
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
/** Copilot prompt file — re-derived (lenient). */
|
|
@@ -82,13 +94,13 @@ export function renderCopilotCommand(c: CommandSource): string {
|
|
|
82
94
|
const fm = [
|
|
83
95
|
'---',
|
|
84
96
|
`name: sungen-${c.id}`,
|
|
85
|
-
`description:
|
|
86
|
-
`argument-hint:
|
|
97
|
+
`description: ${sq(c.description)}`,
|
|
98
|
+
`argument-hint: ${sq(unquote(c.argumentHint))}`,
|
|
87
99
|
`agent: 'agent'`,
|
|
88
100
|
`tools: ${c.copilotTools}`,
|
|
89
101
|
'---',
|
|
90
102
|
].join('\n');
|
|
91
|
-
return fm + '\n\n' +
|
|
103
|
+
return fm + '\n\n' + bodyFor(c, 'copilot', []);
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
/** Codex command-skill — command folds into a skill with an explicit trigger (decision P2). */
|
|
@@ -102,10 +114,12 @@ export function renderCodexCommand(c: CommandSource): string {
|
|
|
102
114
|
...(c.order != null ? [`order: ${c.order}`] : []),
|
|
103
115
|
'---',
|
|
104
116
|
].join('\n');
|
|
105
|
-
return fm + '\n\n' +
|
|
117
|
+
return fm + '\n\n' + bodyFor(c, 'codex', []);
|
|
106
118
|
}
|
|
107
119
|
|
|
108
|
-
|
|
120
|
+
/** The build path: a command that lacks a required include never renders (fails loud). */
|
|
121
|
+
export function generateCommand(c: CommandSource, adapter: AdapterKey): GenFile {
|
|
122
|
+
assertRequiredIncludes(c.body, c.id);
|
|
109
123
|
if (adapter === 'claude') return { outputPath: `.claude/commands/sungen/${c.id}.md`, content: renderClaudeCommand(c) };
|
|
110
124
|
if (adapter === 'copilot') return { outputPath: `.github/prompts/sungen-${c.id}.prompt.md`, content: renderCopilotCommand(c) };
|
|
111
125
|
return { outputPath: `.agents/skills/sungen-${c.id}/SKILL.md`, content: renderCodexCommand(c) };
|
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import * as fs from 'fs';
|
|
18
18
|
import * as path from 'path';
|
|
19
|
+
import { parseDocument } from 'yaml';
|
|
19
20
|
import { buildOutputs } from './build';
|
|
20
21
|
import { parseCommandSource } from './commands';
|
|
21
22
|
|
|
22
23
|
const FIX = path.resolve(__dirname, '..', '..', '..', 'tests', 'golden', 'ai-skills', 'fixtures');
|
|
23
24
|
const SRC = path.resolve(__dirname, '..', 'templates', 'ai-src', 'skills');
|
|
24
25
|
const SRC_CMD = path.resolve(__dirname, '..', 'templates', 'ai-src', 'commands');
|
|
26
|
+
const SRC_CFG = path.resolve(__dirname, '..', 'templates', 'ai-src', 'config');
|
|
25
27
|
const UPDATE = process.argv.includes('--update');
|
|
26
28
|
|
|
27
29
|
function lint(): string[] {
|
|
@@ -47,6 +49,18 @@ function lint(): string[] {
|
|
|
47
49
|
if (!c.description) errs.push(`commands/${f}: missing description`);
|
|
48
50
|
if (c.order != null) { const k = String(c.order); if (seen.has(k)) { /* allowed: parallel entrypoints */ } else seen.set(k, f); }
|
|
49
51
|
}
|
|
52
|
+
// The CLAUDE.md / copilot-instructions tables are the always-loaded index of what ships, so
|
|
53
|
+
// they must list every skill and command, with the right count (#899).
|
|
54
|
+
const skills = fs.readdirSync(SRC).filter((d) => fs.existsSync(path.join(SRC, d, 'SKILL.md')));
|
|
55
|
+
const cmds = fs.readdirSync(SRC_CMD).filter((f) => f.endsWith('.md')).map((f) => f.replace(/\.md$/, ''));
|
|
56
|
+
for (const [cfg, prefix] of [['claude.md', '/sungen:'], ['copilot.md', '/sungen-']] as const) {
|
|
57
|
+
const t = fs.readFileSync(path.join(SRC_CFG, cfg), 'utf8');
|
|
58
|
+
for (const s of skills) if (!t.includes(`| \`${s}\` |`)) errs.push(`config/${cfg}: skills table misses ${s}`);
|
|
59
|
+
const listed = (c: string) => [' ', '`'].some((end) => t.includes(`| \`${prefix}${c}${end}`));
|
|
60
|
+
for (const c of cmds) if (!listed(c)) errs.push(`config/${cfg}: workflow table misses ${prefix}${c}`);
|
|
61
|
+
const n = t.match(/## Workflow \((\d+) AI commands\)/)?.[1];
|
|
62
|
+
if (Number(n) !== cmds.length) errs.push(`config/${cfg}: says ${n} AI commands, ${cmds.length} ship`);
|
|
63
|
+
}
|
|
50
64
|
return errs;
|
|
51
65
|
}
|
|
52
66
|
|
|
@@ -77,6 +91,15 @@ function run() {
|
|
|
77
91
|
else codexNames.set(m[1], f.outputPath);
|
|
78
92
|
}
|
|
79
93
|
|
|
94
|
+
// The key regex in lint() accepts frontmatter a real YAML parser rejects (an unquoted ": ", an
|
|
95
|
+
// unescaped apostrophe inside '...'), and assistants then drop every field silently (#899).
|
|
96
|
+
// Parse what ships — renderers re-quote command fields, so a valid source is not enough.
|
|
97
|
+
for (const f of outputs) {
|
|
98
|
+
if (!f.content.startsWith('---')) continue;
|
|
99
|
+
const doc = parseDocument(f.content.slice(3, f.content.indexOf('\n---', 3)));
|
|
100
|
+
for (const e of doc.errors) lintErrs.push(`${f.outputPath}: frontmatter is not valid YAML — ${e.message.split('\n')[0]}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
80
103
|
if (UPDATE) {
|
|
81
104
|
fs.rmSync(FIX, { recursive: true, force: true });
|
|
82
105
|
for (const f of outputs) {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install sungen's Claude Code hooks into `.claude/settings.json` — by MERGING (P0.1, takumi T1).
|
|
3
|
+
*
|
|
4
|
+
* A team commits that file, so it holds the user's own hooks, permissions and env. The installer
|
|
5
|
+
* owns exactly one thing in it: hook entries that run the sungen launcher
|
|
6
|
+
* (`.claude/hooks/sungen-hook.cjs`, matched exactly — a user's `my-sungen-hook.cjs` is not ours).
|
|
7
|
+
* Each run removes every such entry and appends the wanted ones, so a hook turned off in
|
|
8
|
+
* `qa/sungen.config.yaml`, or dropped by a later version, leaves — and nothing else does. That is
|
|
9
|
+
* also the rollback path: `sungen update` takes out sungen's entries without touching anyone's.
|
|
10
|
+
*
|
|
11
|
+
* The first change backs the file up byte for byte, and that pristine backup is never overwritten;
|
|
12
|
+
* the file keeps its own indentation; an unreadable file is never rewritten; a run that changes
|
|
13
|
+
* nothing writes nothing.
|
|
14
|
+
*
|
|
15
|
+
* Entries use EXEC FORM — `{ command: 'node', args: ['${CLAUDE_PROJECT_DIR}/…/sungen-hook.cjs', hook] }`
|
|
16
|
+
* (Claude Code ≥ 2.1.139). No shell is involved and Claude Code substitutes the placeholder itself.
|
|
17
|
+
* A shell-form `node "$CLAUDE_PROJECT_DIR/…"` runs in PowerShell on Windows without Git Bash, where
|
|
18
|
+
* that variable is empty, and since 2.1.299 a FAILING shell-form PreToolUse hook there blocks every
|
|
19
|
+
* tool call. `onFailure` is left unset: its default (continue) is the fail-open one, and versions
|
|
20
|
+
* before 2.1.295 do not know the field.
|
|
21
|
+
*/
|
|
22
|
+
import * as fs from 'fs';
|
|
23
|
+
import * as path from 'path';
|
|
24
|
+
import { allHooks } from '../hooks/hook-registry';
|
|
25
|
+
import { configDisabledHooks } from '../hooks/hook-toggles';
|
|
26
|
+
import type { SungenHook } from '../hooks/hook-result-contract';
|
|
27
|
+
import { readTextFile } from '../harness/read-text';
|
|
28
|
+
import { writeFileAtomic } from '../harness/write-atomic';
|
|
29
|
+
|
|
30
|
+
export const LAUNCHER_REL = path.join('.claude', 'hooks', 'sungen-hook.cjs');
|
|
31
|
+
/** The launcher as the hook entry names it: Claude Code substitutes the placeholder, no shell does. */
|
|
32
|
+
export const LAUNCHER_ARG = '${CLAUDE_PROJECT_DIR}/.claude/hooks/sungen-hook.cjs';
|
|
33
|
+
const SETTINGS_REL = path.join('.claude', 'settings.json');
|
|
34
|
+
const BACKUP_SUFFIX = '.sungen-backup';
|
|
35
|
+
const LAUNCHER_SRC = path.join(__dirname, 'templates', 'claude-hooks', 'sungen-hook.cjs');
|
|
36
|
+
/** What marks an entry as sungen's: it runs exactly this launcher (exec form `args[0]` or a shell command). */
|
|
37
|
+
const OWNED = /\.claude\/hooks\/sungen-hook\.cjs(?:["'\s]|$)/;
|
|
38
|
+
|
|
39
|
+
type Settings = Record<string, unknown> & { hooks?: Record<string, unknown> };
|
|
40
|
+
type Entry = { command?: unknown; args?: unknown };
|
|
41
|
+
const entriesOf = (g: unknown): Entry[] | null =>
|
|
42
|
+
g && typeof g === 'object' && Array.isArray((g as { hooks?: unknown }).hooks) ? (g as { hooks: Entry[] }).hooks : null;
|
|
43
|
+
const argsOf = (e: Entry): string[] => (Array.isArray(e?.args) ? e.args.filter((a): a is string => typeof a === 'string') : []);
|
|
44
|
+
const isOwned = (e: Entry): boolean =>
|
|
45
|
+
(typeof e?.command === 'string' && OWNED.test(e.command)) || OWNED.test(argsOf(e)[0] ?? '');
|
|
46
|
+
const keyOf = (e: Entry): string => [String(e?.command ?? ''), ...argsOf(e)].join(' ');
|
|
47
|
+
|
|
48
|
+
export interface HooksInstallReport {
|
|
49
|
+
settings: 'created' | 'updated' | 'unchanged' | 'unreadable';
|
|
50
|
+
launcher: 'written' | 'unchanged' | 'removed' | 'absent';
|
|
51
|
+
/** Hooks registered after this run. */
|
|
52
|
+
installed: string[];
|
|
53
|
+
/** sungen entries no longer registered (stale, or turned off). */
|
|
54
|
+
removed: number;
|
|
55
|
+
/** The backup written THIS run (only the first change writes one). */
|
|
56
|
+
backup?: string;
|
|
57
|
+
error?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function hookEntry(hook: SungenHook): Record<string, unknown> {
|
|
61
|
+
return { type: 'command', command: 'node', args: [LAUNCHER_ARG, hook.name], ...(hook.meta.timeout ? { timeout: hook.meta.timeout } : {}) };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Pure: every sungen-owned entry removed, the wanted hooks appended, everything else as it was. */
|
|
65
|
+
export function mergeSungenHooks(settings: Settings, wanted: SungenHook[]): Settings {
|
|
66
|
+
const hooks: Record<string, unknown> = { ...(settings.hooks ?? {}) };
|
|
67
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
68
|
+
if (!Array.isArray(groups)) continue; // readSettings refuses this shape; never rewrite it here
|
|
69
|
+
const kept = groups.flatMap((g) => {
|
|
70
|
+
const entries = entriesOf(g);
|
|
71
|
+
if (!entries || !entries.some(isOwned)) return [g];
|
|
72
|
+
const rest = entries.filter((e) => !isOwned(e));
|
|
73
|
+
return rest.length ? [{ ...(g as object), hooks: rest }] : [];
|
|
74
|
+
});
|
|
75
|
+
if (kept.length || !groups.length) hooks[event] = kept; else delete hooks[event];
|
|
76
|
+
}
|
|
77
|
+
for (const hook of wanted) {
|
|
78
|
+
for (const event of hook.meta.events) {
|
|
79
|
+
const matcher = hook.meta.matchers?.[event];
|
|
80
|
+
hooks[event] = [...(Array.isArray(hooks[event]) ? hooks[event] as unknown[] : []), { ...(matcher ? { matcher } : {}), hooks: [hookEntry(hook)] }];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const out: Settings = { ...settings };
|
|
84
|
+
if (Object.keys(hooks).length || settings.hooks !== undefined) out.hooks = hooks;
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const ownedKeys = (s: Settings): string[] => Object.values(s.hooks ?? {})
|
|
89
|
+
.flatMap((groups) => (Array.isArray(groups) ? groups : []).flatMap((g) => entriesOf(g) ?? []))
|
|
90
|
+
.filter(isOwned).map(keyOf);
|
|
91
|
+
|
|
92
|
+
/** The file's own indentation (a tab, or N spaces); 2 for a file that has none yet. */
|
|
93
|
+
function indentOf(raw: string): string | number {
|
|
94
|
+
const m = raw.match(/^[{[][^\S\n]*\r?\n([ \t]+)\S/);
|
|
95
|
+
if (!m) return 2;
|
|
96
|
+
return m[1].startsWith('\t') ? '\t' : m[1].length;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function readSettings(file: string): { settings: Settings; indent: string | number } {
|
|
100
|
+
const raw = readTextFile(file);
|
|
101
|
+
const parsed: unknown = JSON.parse(raw);
|
|
102
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('not a JSON object');
|
|
103
|
+
const hooks = (parsed as Settings).hooks;
|
|
104
|
+
if (hooks !== undefined && (!hooks || typeof hooks !== 'object' || Array.isArray(hooks))) throw new Error('"hooks" is not an object');
|
|
105
|
+
// An event that is not a list is a shape we cannot merge into without replacing it.
|
|
106
|
+
const odd = Object.entries(hooks ?? {}).find(([, groups]) => !Array.isArray(groups));
|
|
107
|
+
if (odd) throw new Error(`"hooks.${odd[0]}" is not a list`);
|
|
108
|
+
return { settings: parsed as Settings, indent: indentOf(raw) };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function installClaudeHooks(cwd: string, opts: { dryRun?: boolean } = {}): HooksInstallReport {
|
|
112
|
+
const settingsPath = path.join(cwd, SETTINGS_REL);
|
|
113
|
+
const existed = fs.existsSync(settingsPath);
|
|
114
|
+
let current: Settings = {};
|
|
115
|
+
let indent: string | number = 2;
|
|
116
|
+
if (existed) {
|
|
117
|
+
try { ({ settings: current, indent } = readSettings(settingsPath)); } catch (e) {
|
|
118
|
+
return { settings: 'unreadable', launcher: 'absent', installed: [], removed: 0, error: `${SETTINGS_REL}: ${(e as Error).message.split('\n')[0]}` };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const off = configDisabledHooks(cwd);
|
|
122
|
+
const wanted = off === 'all' ? [] : allHooks().filter((h) => !off.has(h.name));
|
|
123
|
+
const merged = mergeSungenHooks(current, wanted);
|
|
124
|
+
const after = ownedKeys(merged);
|
|
125
|
+
const changed = existed ? JSON.stringify(merged) !== JSON.stringify(current) : wanted.length > 0;
|
|
126
|
+
const report: HooksInstallReport = {
|
|
127
|
+
settings: !changed ? 'unchanged' : existed ? 'updated' : 'created',
|
|
128
|
+
launcher: 'absent',
|
|
129
|
+
installed: wanted.map((h) => h.name),
|
|
130
|
+
removed: ownedKeys(current).filter((k) => !after.includes(k)).length,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const launcherPath = path.join(cwd, LAUNCHER_REL);
|
|
134
|
+
const onDisk = fs.existsSync(launcherPath) ? fs.readFileSync(launcherPath, 'utf8') : null;
|
|
135
|
+
const src = wanted.length ? fs.readFileSync(LAUNCHER_SRC, 'utf8') : null;
|
|
136
|
+
if (src !== null) report.launcher = onDisk === src ? 'unchanged' : 'written';
|
|
137
|
+
else if (onDisk !== null) report.launcher = 'removed';
|
|
138
|
+
if (opts.dryRun) return report;
|
|
139
|
+
|
|
140
|
+
const writeSettings = (): void => {
|
|
141
|
+
if (!changed) return;
|
|
142
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
143
|
+
const backup = settingsPath + BACKUP_SUFFIX;
|
|
144
|
+
if (existed && !fs.existsSync(backup)) { // keep the pristine original: never overwrite it
|
|
145
|
+
fs.copyFileSync(settingsPath, backup);
|
|
146
|
+
report.backup = SETTINGS_REL + BACKUP_SUFFIX;
|
|
147
|
+
}
|
|
148
|
+
writeFileAtomic(settingsPath, `${JSON.stringify(merged, null, indent)}\n`);
|
|
149
|
+
};
|
|
150
|
+
// settings.json must never point at a launcher that is not there: install the launcher BEFORE the
|
|
151
|
+
// entries that run it, and remove it only AFTER the entries are gone.
|
|
152
|
+
if (src !== null) {
|
|
153
|
+
if (onDisk !== src) { fs.mkdirSync(path.dirname(launcherPath), { recursive: true }); writeFileAtomic(launcherPath, src); }
|
|
154
|
+
writeSettings();
|
|
155
|
+
} else {
|
|
156
|
+
writeSettings();
|
|
157
|
+
if (onDisk !== null) fs.rmSync(launcherPath, { force: true });
|
|
158
|
+
}
|
|
159
|
+
return report;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** One summary line for init/update output. */
|
|
163
|
+
export function describeHooksInstall(r: HooksInstallReport): string {
|
|
164
|
+
if (r.settings === 'unreadable') return `${r.error} — Claude Code hooks not installed; fix the JSON and re-run`;
|
|
165
|
+
const what = r.installed.length ? `Claude Code hooks: ${r.installed.join(', ')}` : 'Claude Code hooks: none (turned off in qa/sungen.config.yaml)';
|
|
166
|
+
const extra = [r.removed ? `${r.removed} stale removed` : '', r.backup ? `backup ${r.backup}` : ''].filter(Boolean).join(', ');
|
|
167
|
+
return `${SETTINGS_REL} (${what}${extra ? `; ${extra}` : ''})`;
|
|
168
|
+
}
|
|
@@ -18,29 +18,42 @@ export function coreVersion(): string {
|
|
|
18
18
|
/**
|
|
19
19
|
* Resolve the version to install for a family package, given the running `core` version.
|
|
20
20
|
*
|
|
21
|
-
* Lockstep wants the EXACT `core` version. But the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* Lockstep wants the EXACT `core` version. But the prerelease channels publish `<core>-beta.N`
|
|
22
|
+
* (beta branch) and `<core>-alpha.N` (alpha branch) before a stable `<core>` ever exists — so a
|
|
23
|
+
* released core (e.g. 3.2.10) asking for `@3.2.10` hits ETARGET out-of-the-box when npm only has
|
|
24
|
+
* `3.2.10-beta.2` (`sungen capability add` then fails for a fresh user). Fall back on the SAME
|
|
25
|
+
* version line — see `pickDriverVersion`. Keeps the driver's pinned core-dep on the same line.
|
|
26
26
|
*/
|
|
27
27
|
export function resolveDriverVersion(pkg: string, core: string): string {
|
|
28
28
|
if (core === 'latest') return 'beta';
|
|
29
29
|
try {
|
|
30
30
|
const out = spawnSync('npm', ['view', pkg, 'versions', '--json'], { encoding: 'utf-8', shell: true });
|
|
31
31
|
if (out.status !== 0 || !out.stdout) return core; // can't query → let the exact install try/fail
|
|
32
|
-
let versions: string[] = [];
|
|
33
32
|
const parsed = JSON.parse(out.stdout);
|
|
34
|
-
|
|
35
|
-
if (versions.includes(core)) return core; // exact exists → lockstep
|
|
36
|
-
const prefix = `${core}-beta.`;
|
|
37
|
-
const betas = versions
|
|
38
|
-
.filter((v) => typeof v === 'string' && v.startsWith(prefix))
|
|
39
|
-
.map((v) => parseInt(v.slice(prefix.length), 10))
|
|
40
|
-
.filter((n) => Number.isInteger(n));
|
|
41
|
-
if (betas.length) return `${core}-beta.${Math.max(...betas)}`; // highest same-line prerelease
|
|
42
|
-
return 'beta'; // nothing on this line → newest beta dist-tag
|
|
33
|
+
return pickDriverVersion(Array.isArray(parsed) ? parsed : [parsed], core);
|
|
43
34
|
} catch {
|
|
44
35
|
return core;
|
|
45
36
|
}
|
|
46
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Pick from a package's published `versions`: the exact `core`, else the highest same-line
|
|
41
|
+
* prerelease of core's OWN channel, else that channel's dist-tag. The channel is `alpha` for an
|
|
42
|
+
* alpha core and `beta` for any other (stable or beta): a stable or beta core never takes an alpha
|
|
43
|
+
* driver — alpha builds are the next big update, and an alpha driver pins an alpha core.
|
|
44
|
+
*
|
|
45
|
+
* The line is core without its prerelease suffix (as `sameVersionLine` in capabilities/discover.ts
|
|
46
|
+
* reads it), so `3.3.0-alpha.4` with no exact driver still finds `3.3.0-alpha.3`.
|
|
47
|
+
*/
|
|
48
|
+
export function pickDriverVersion(versions: readonly string[], core: string): string {
|
|
49
|
+
if (versions.includes(core)) return core; // exact exists → lockstep
|
|
50
|
+
const channel = /-alpha(\.|$)/.test(core) ? 'alpha' : 'beta';
|
|
51
|
+
const line = core.split('-')[0];
|
|
52
|
+
const prefix = `${line}-${channel}.`;
|
|
53
|
+
const indexes = versions
|
|
54
|
+
.filter((v) => typeof v === 'string' && v.startsWith(prefix))
|
|
55
|
+
.map((v) => parseInt(v.slice(prefix.length), 10))
|
|
56
|
+
.filter((n) => Number.isInteger(n));
|
|
57
|
+
if (indexes.length) return `${line}-${channel}.${Math.max(...indexes)}`; // highest same-line prerelease
|
|
58
|
+
return channel; // nothing on this line → newest build of core's channel
|
|
59
|
+
}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from './mobile-runtime-scaffolder';
|
|
19
19
|
import { emitAppiumEnvironment, runAppiumEnvironmentSetup, appiumEnvironmentRerunCommand } from './appium-environment-setup';
|
|
20
20
|
import { ensureSecurityOverrides, reportSecurityOverrides } from './security-overrides';
|
|
21
|
+
import { installClaudeHooks, describeHooksInstall } from './claude-hooks-install';
|
|
21
22
|
import { readTextFile } from '../harness/read-text';
|
|
22
23
|
|
|
23
24
|
export { MobileInitOptions };
|
|
@@ -198,6 +199,12 @@ export class ProjectInitializer {
|
|
|
198
199
|
// Create root .mcp.json for Claude Code
|
|
199
200
|
this.createClaudeMCPConfig();
|
|
200
201
|
|
|
202
|
+
// Claude Code hooks (hand-back on Stop, unit state on SessionStart, approval-path guard),
|
|
203
|
+
// merged into .claude/settings.json — only when Claude is a selected assistant.
|
|
204
|
+
if (this.agents.includes('claude')) {
|
|
205
|
+
this.createClaudeHooks();
|
|
206
|
+
}
|
|
207
|
+
|
|
201
208
|
// Create .codex/config.toml for Codex CLI — only when Codex is a selected assistant
|
|
202
209
|
// (`sungen init --assistant codex`), since it is Codex-specific config.
|
|
203
210
|
if (this.agents.includes('codex')) {
|
|
@@ -397,6 +404,20 @@ export class ProjectInitializer {
|
|
|
397
404
|
);
|
|
398
405
|
}
|
|
399
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Merge sungen's Claude Code hooks into `.claude/settings.json` (user hooks kept, backup before
|
|
409
|
+
* any change, unreadable file left alone — see claude-hooks-install.ts). A no-op for a project
|
|
410
|
+
* without Claude.
|
|
411
|
+
*/
|
|
412
|
+
private createClaudeHooks(): void {
|
|
413
|
+
if (!this.agents.includes('claude')) return;
|
|
414
|
+
const r = installClaudeHooks(this.cwd);
|
|
415
|
+
const line = describeHooksInstall(r);
|
|
416
|
+
if (r.settings === 'unreadable') this.notDoneItems.push(line);
|
|
417
|
+
else if (r.settings === 'unchanged') this.skippedItems.push(line);
|
|
418
|
+
else this.createdItems.push(line);
|
|
419
|
+
}
|
|
420
|
+
|
|
400
421
|
/**
|
|
401
422
|
* Create `.codex/config.toml` for Codex CLI — the Codex analog of `.mcp.json` (Claude) and
|
|
402
423
|
* `.vscode/mcp.json` (Copilot), so `sungen run-test` under Codex drives the same live Playwright
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
-
import { chromium } from '@playwright/test';
|
|
9
8
|
import { readCapabilities } from '../harness/capability';
|
|
10
9
|
import { testDataHeader, ensureTestDataGuideFiles } from './test-data-guide';
|
|
11
10
|
import { resolveWebBaseUrl } from '../exporters/env-qa';
|
|
@@ -264,6 +263,9 @@ export class ScreenManager {
|
|
|
264
263
|
|
|
265
264
|
let browser;
|
|
266
265
|
try {
|
|
266
|
+
// Loaded here, not at module top: @playwright/test is a peerDependency a mobile project never
|
|
267
|
+
// installs, and `sungen add` loads this module on every platform (#865).
|
|
268
|
+
const { chromium } = await import('@playwright/test');
|
|
267
269
|
browser = await chromium.launch();
|
|
268
270
|
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
|
269
271
|
await page.goto(url, { waitUntil: 'networkidle', timeout: 15000 });
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Bash, Glob, Edit, Write, AskUserQuestion"
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, todo]"
|
|
8
8
|
codex-trigger: "Run when the user asks to add or scaffold a NEW API area/resource or an API flow to test (REST/HTTP endpoints, not a UI screen). Step 1 of the API workflow. Do NOT use for UI screens, flows across screens, creating test cases, or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
{{^cap parallel-subagents}}
|
|
11
13
|
**Input**: an API area name (a resource/tag, e.g. `orders`, `users`) and the base URL:
|
|
12
14
|
`/sungen-add-api orders --base-url https://api.example.com`.
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Bash, Glob, Edit, Write, AskUserQuestion, mcp__playwr
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, todo]"
|
|
8
8
|
codex-trigger: "Run when the user asks to add a NEW cross-screen end-to-end flow. Step 1 (flow variant). Do NOT use for a single screen, creating test cases, or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
{{^cap parallel-subagents}}
|
|
11
13
|
**Input**: Flow name and optional starting URL (e.g., `/sungen-add-flow award-submission --path /login`).
|
|
12
14
|
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Bash, Glob, Edit, Write, AskUserQuestion, mcp__playwr
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, web, browser, todo, 'playwright/*']"
|
|
8
8
|
codex-trigger: "Run when the user asks to add or scaffold a NEW screen/page to test. Step 1 of the sungen workflow. Do NOT use for flows, creating test cases, or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
{{^cap parallel-subagents}}
|
|
11
13
|
**Input**: Screen name and URL path (e.g., `/sungen-add-screen login /login`).
|
|
12
14
|
Optionally include a Figma URL: `/sungen-add-screen login /login --figma https://www.figma.com/design/...`.
|
|
@@ -7,6 +7,7 @@ claude-tools: "Read, Grep, Bash, Glob, Write, Edit, AskUserQuestion, Skill"
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, todo]"
|
|
8
8
|
codex-trigger: "Run when the user asks to CREATE, generate, or standardize TEST DATA / test values for a screen or flow (valid/boundary/invalid, boundary values, negative data). Uses the Data Factory driver. Not for generating the .feature scenarios themselves (that is create-test)."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
10
11
|
|
|
11
12
|
**Input**: A screen or flow name (e.g., `/sungen:create-data-test login`), OR **no name** to do every unit (with a confirmation — see ALL mode). Load the `sungen-data-factory` skill for the full method.
|
|
12
13
|
|
|
@@ -7,22 +7,7 @@ claude-tools: "Read, Grep, Bash, Glob, Write, AskUserQuestion, Skill, mcp__playw
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, web, browser, todo, 'playwright/*']"
|
|
8
8
|
codex-trigger: "Run when the user asks to CREATE, generate, write, or author test cases / a .feature file for a screen or flow. Step 2 (after add-screen/add-flow, before run-test). Do NOT use for executing, running, or compiling existing tests."
|
|
9
9
|
---
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
A run is NOT finished when its files are written or its output prints. The final action of EVERY
|
|
13
|
-
run — success, partial, or aborted — is the next-step hand-back.
|
|
14
|
-
|
|
15
|
-
**Ask `sungen next <unit>` rather than deciding from memory.** It derives the answer from what the
|
|
16
|
-
project actually holds (artifacts on disk, the audit report, the accepted viewpoint baseline, the
|
|
17
|
-
compiled spec, the run results), so the hand-back stays correct even when the run ended somewhere
|
|
18
|
-
unexpected — a failed install, a driver that turned out not to support this unit kind, an aborted
|
|
19
|
-
repair loop. Every `sungen` command also prints `Next: sungen next …` as its own last line.
|
|
20
|
-
|
|
21
|
-
This matters most exactly where it used to break. A run that ended on a command with no footer of
|
|
22
|
-
its own — `sungen capability add`, a dead-end install — left the session with nothing to follow and
|
|
23
|
-
it stopped mid-workflow. If a step turns out to be impossible, that is still a hand-back: say what
|
|
24
|
-
blocked it, run `sungen next <unit>`, and offer what remains. Ending with a prose summary and no
|
|
25
|
-
choices is a broken run.
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
26
11
|
|
|
27
12
|
---
|
|
28
13
|
{{#cap parallel-subagents}}
|
|
@@ -115,6 +100,19 @@ declaration instead of leaving both on record.
|
|
|
115
100
|
|
|
116
101
|
---
|
|
117
102
|
|
|
103
|
+
## ⛔ HARD RULE — approvals and waivers are a human's, on a terminal
|
|
104
|
+
|
|
105
|
+
`sungen contract approve`, `sungen journey --waive` and `sungen journey --decide` record a QA
|
|
106
|
+
decision and ask for a typed confirmation on a real terminal (TTY). Never run them, never fake the
|
|
107
|
+
terminal (`script`, `expect`, a pty wrapper), and never edit `contracts.lock.yaml` or
|
|
108
|
+
`qa/**/decisions/` by hand. When one is due, show the exact command and stop for the human.
|
|
109
|
+
|
|
110
|
+
**Hand-written free tests (`@free` / `@impl:code`).** When the unit has free tests with recorded
|
|
111
|
+
traces, write their Gherkin with `sungen contract derive --screen <name>` — deterministic, it writes
|
|
112
|
+
`features/<name>.free.feature` with every scenario tagged `@free @proposed`. Do not author those
|
|
113
|
+
steps yourself; you may name the scenarios and suggest VP-ids. A `@proposed` scenario is not
|
|
114
|
+
counted by the audit until a QA approves it (`sungen contract approve --screen <name>`).
|
|
115
|
+
|
|
118
116
|
## Platform detection (do this FIRST)
|
|
119
117
|
|
|
120
118
|
Read `qa/capabilities.yaml` and check the `platform` field — **and the verification scope** (`verification:` if set, else derived from `enabled`: `ui` always; `api`/`db` only if that driver is on). This is the project's recorded **test type**: an **E2E/UI-only** project (no `api`/`db`) must NOT get `@api`/`@query`/`@requires:api|db` verification unless the test-viewpoint explicitly asks for it — keep oracles UI-observable, and cap any in-scope API/DB-in-E2E verification at the **≤20% band** (see `sungen-tc-generation` → "Respect the project's verification scope"). `sungen audit` flags `VERIFICATION-OUT-OF-SCOPE`.
|
|
@@ -7,6 +7,8 @@ claude-tools: "Bash, Read, AskUserQuestion"
|
|
|
7
7
|
copilot-tools: "[read, execute, edit, vscode/askQuestions]"
|
|
8
8
|
codex-trigger: "Run when the user asks to OPEN or view the sungen results dashboard."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
## Role
|
|
11
13
|
|
|
12
14
|
You are a **QA Reporting Engineer**. Your job is to invoke the deterministic `sungen dashboard` CLI which builds a self-contained HTML report. The HTML is shareable as-is (open via `file://`, no server required).
|
|
@@ -7,6 +7,8 @@ claude-tools: "Bash, Read, Write, AskUserQuestion"
|
|
|
7
7
|
copilot-tools: "[read, execute, edit, vscode/askQuestions]"
|
|
8
8
|
codex-trigger: "Run when the user asks to EXPORT or deliver test cases for QA hand-off. Final step. Do NOT use for creating or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
## Role
|
|
11
13
|
|
|
12
14
|
You are a **QA Test Delivery Engineer**. The deterministic `sungen delivery` CLI does all parsing,
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Bash, Glob, Write, AskUserQuestion, Skill, mcp__playw
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, agent, edit, search, web, browser, todo, 'playwright/*']"
|
|
8
8
|
codex-trigger: "Run when the user asks to capture DESIGN/visual context (Figma, live page scan, mockups) for a screen. Used before create-test. Do NOT use for writing or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
{{#cap parallel-subagents}}
|
|
11
13
|
## `/sungen:design` is an alias of `/sungen:create-test`
|
|
12
14
|
{{/cap}}
|
|
@@ -6,6 +6,8 @@ claude-tools: "Read, Grep, Bash, Glob, Edit, Write, AskUserQuestion, mcp__playwr
|
|
|
6
6
|
copilot-tools: "[read, execute, edit, vscode/askQuestions, playwright/*]"
|
|
7
7
|
codex-trigger: "Run when the user asks to bootstrap i18n/localization for a screen. Runs before run-test --env <locale>."
|
|
8
8
|
---
|
|
9
|
+
<!-- include: hand-back-rule -->
|
|
10
|
+
|
|
9
11
|
## Role
|
|
10
12
|
|
|
11
13
|
You are a **Senior QA Localization Engineer**. Use the `sungen-locale` skill — it contains the full phased strategy. Your job in this command is parameter parsing, context detection, and final hand-off.
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Glob, Bash, Edit, Write, AskUserQuestion"
|
|
|
7
7
|
copilot-tools: "[vscode, execute, read, edit, search, todo]"
|
|
8
8
|
codex-trigger: "Run when the user asks to REVIEW or score the quality of already-generated test cases. Step 3 (between create-test and run-test). Do NOT use for creating or running tests."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
{{^cap parallel-subagents}}
|
|
11
13
|
**Input**: Screen or flow name (e.g., `/sungen-review admin-users`).
|
|
12
14
|
|
|
@@ -7,6 +7,8 @@ claude-tools: "Read, Grep, Bash, Glob, Edit, Write, AskUserQuestion, mcp__playwr
|
|
|
7
7
|
copilot-tools: "[read, execute, edit, vscode/askQuestions, playwright/*, appium/*]"
|
|
8
8
|
codex-trigger: "Run when the user asks to RUN, execute, or compile tests, generate selectors.yaml, or run tests. Step 4. Do NOT use for authoring/creating new test cases."
|
|
9
9
|
---
|
|
10
|
+
<!-- include: hand-back-rule -->
|
|
11
|
+
|
|
10
12
|
## ⛔ HARD RULE — the transition INTO this run is a tool call, never prose
|
|
11
13
|
|
|
12
14
|
A QA field report: the user picked "Run test" from create-test's hand-back, and the session
|
|
@@ -25,14 +27,6 @@ inside the run, not reasons to stop and hand the work back.
|
|
|
25
27
|
`export PATH="$HOME/.nvm/versions/node/$(ls $HOME/.nvm/versions/node | grep '^v22' | tail -1)/bin:$PATH"`
|
|
26
28
|
— and say so in one line. Only if NO compatible Node exists do you stop, with the exact
|
|
27
29
|
install command as the hand-back.
|
|
28
|
-
- Ending this run follows the same law as create-test: the LAST action is the next-step
|
|
29
|
-
hand-back (the AskUserQuestion in "After showing results"), no matter how the run went.
|
|
30
|
-
**Ask `sungen next <unit>` rather than deciding from memory** — it derives the answer from what
|
|
31
|
-
the project now holds, so the hand-back stays correct even when the run ended somewhere
|
|
32
|
-
unexpected (a failed install, a driver that does not support this unit kind, an aborted repair
|
|
33
|
-
loop). Every `sungen` command also prints `Next: sungen next …` as its own last line. A step
|
|
34
|
-
that turns out to be impossible is still a hand-back: say what blocked it, run
|
|
35
|
-
`sungen next <unit>`, and offer what remains.
|
|
36
30
|
|
|
37
31
|
---
|
|
38
32
|
|
|
@@ -79,7 +73,9 @@ Stop here for mobile — do not continue to the web path.
|
|
|
79
73
|
> ⛔ **The `.feature` Gherkin is QA-approved and FROZEN.** During auto-fix you may write
|
|
80
74
|
> **only** `selectors.yaml`, `test-data.yaml` (and other `*.yaml` data), plus the **one narrow
|
|
81
75
|
> `.feature` edit** allowed: the **element-type token** on a `[Reference]` (e.g. `field`→`textbox`,
|
|
82
|
-
> `button`→`link` — selector resolution, not test logic).
|
|
76
|
+
> `button`→`link` — selector resolution, not test logic). A second, equally narrow exception:
|
|
77
|
+
> adding **`@known-defect:DEF-NNN`** to a scenario's tag line once its defect record exists (step 8)
|
|
78
|
+
> — that tag only, the tag line only. You must **NOT** change the Gherkin's
|
|
83
79
|
> content or logic: no rewriting/adding/removing steps, no `wait for` steps, no changed expected
|
|
84
80
|
> values, no weakened assertions. A failure that would need any of those is a **CANDIDATE BUG /
|
|
85
81
|
> QA finding → report it, let it FAIL** (it may be a real bug). The live page is NOT the oracle;
|
|
@@ -270,7 +266,11 @@ question already.
|
|
|
270
266
|
5. **Phase 1 — Smoke Check**: Run first 5 `@high` scenarios only. If failures → diagnose, fix fundamentals (page selector, auth, base @steps), re-run. Max 2 attempts. If still broken → ask user.
|
|
271
267
|
6. **Phase 2 — Priority Wave**: Run all `@high` scenarios. Fix only failures from this wave. Max 2 attempts. Shared selectors fixed here cascade to later phases.
|
|
272
268
|
7. **Phase 3 — Full Run**: Run all tests. Fix only **new** failures (elements unique to `@normal`/`@low`). Max 1 attempt. Don't loop on low-priority failures.
|
|
273
|
-
8. **Phase 4 — Regression**: One final full run.
|
|
269
|
+
8. **Phase 4 — Regression**: One final full run. No more fix loops. Then run `sungen triage --screen <name>` and render its table as the results summary: every red or flaky scenario already sits in one class (`product-candidate`, `unclassified`, `test-defect`, `environment`, `blocked-capability`, `known-defect`, `flaky`) with the rule and one evidence line. You may move an `unclassified` row into a class only with a written evidence line of your own. You may never turn a `product-candidate` into a `test-defect` by editing the `.feature` or the expected value — the Gherkin is frozen; report it as a candidate bug. For each `product-candidate` you judge to be a product bug, run `sungen defect draft --screen <name> --scenario "<title>"`, fill the record's Summary, check its Expected against `spec.md`, then add `@known-defect:DEF-NNN` to that scenario's tag line (the tag-only exception above). The severity in the draft is `proposed` — confirm it with QA (`AskUserQuestion`) before the hand-back and set `severity_source: qa`. A row you judge is not a product bug stays in the summary with your reason, and gets no record. A `bare-timeout` row (`unclassified`) is never re-run inside this command — Phase 4 was the final run; offer the re-run in Next steps.
|
|
270
|
+
8a. **Test Contract — every unit with a lock.** When `qa/<screens|flows|api>/<name>/contracts.lock.yaml` exists, check the suite still does what QA approved:
|
|
271
|
+
- **`@free` / `@impl:code` scenarios** (hand-written specs, not compiled): in the Phase 4 final run, run their specs with `--trace on` (`npx playwright test <their spec> --trace on`) — their trace is the only proof. The project's config needs the sungen run-record reporter; if it is missing, no trace is admissible: tell the QA, do not edit the config yourself. Then `sungen contract check --screen <name> --trace`.
|
|
272
|
+
- **No free tests**: `sungen contract check --screen <name>`.
|
|
273
|
+
- **Exit 2 (hard)** — `oracle-weakened`, `target-changed`, `assertion-lost`, `lock-uncommitted`, `unproven` → report each finding to the QA in the results summary, with its rule. **Never** edit the `.feature`, an expected value, the lock or a decision to turn it green, and **never** run `sungen contract approve` — approving is a QA's decision, on a terminal. **Exit 0 with `review`** → list it for the QA: review blocks `sungen delivery` until QA re-approves. **Exit 1** → report the error. No lock → skip: every scenario is `proposed`, which never blocks.
|
|
274
274
|
9. **Phase 8 — Serial-cascade risk check** (#414): If any scenario has many steps, a skipped test may cause downstream steps to be incorrectly skipped due to the serial-cascade sensor detecting false "not reached" conditions. When you see "test skipped" messages during Phase 3–4 runs, check if the skipped scenario is a **blockers-exist** dependency in the test ledger (`sungen ledger query --screen <name>`). If the scenario had high step count and cascade fired, offer: *"Scenarios with deep steps can trigger serial-cascade skipping. Consider parallelizing this spec with `@concurrent` tags or breaking into smaller scenarios."* Let the user decide whether to refactor (do not auto-apply parallelization).
|
|
275
275
|
{{#cap parallel-subagents}}
|
|
276
276
|
9. **Integrity check & trace (always run after the final run).**
|
|
@@ -478,3 +478,7 @@ If tests **failed** (after retries):
|
|
|
478
478
|
- **`/sungen-create-test <name>`** — Revise test cases
|
|
479
479
|
{{/cap}}
|
|
480
480
|
- **Done for now** — I'll fix manually later
|
|
481
|
+
|
|
482
|
+
If the triage table has `bare-timeout` rows, put this option FIRST and mark it Recommended: **Re-run the N timed-out scenario(s) once** — it tells a slow environment from a hanging page (name them). Ask; never re-run them on your own: a scenario may create data or spend an OTP/rate limit on a shared environment. On a yes, re-run only those scenarios with the subset-merge flow (§ Playwright command guidelines — never overwrite the result file), then `sungen triage` again:
|
|
483
|
+
- green now → move the row to `flaky` (or `environment`) with that as the evidence line;
|
|
484
|
+
- the same timeout again → read the trace's last action: stuck after a submit or a navigation → candidate bug, handled as in Phase 4 step 8 (`sungen defect draft`, QA confirms the severity); stuck in a wait the test itself defines → `test-defect`.
|