@sun-asterisk/sungen 3.2.35 → 3.3.0-alpha.10
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/discover.d.ts +4 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +16 -2
- package/dist/capabilities/discover.js.map +1 -1
- 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/case-triage-hint.d.ts +14 -0
- package/dist/cli/case-triage-hint.d.ts.map +1 -0
- package/dist/cli/case-triage-hint.js +23 -0
- package/dist/cli/case-triage-hint.js.map +1 -0
- package/dist/cli/commands/audit.js +1 -1
- 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 +12 -0
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
- package/dist/cli/commands/contract-derive-command.js +113 -0
- package/dist/cli/commands/contract-derive-command.js.map +1 -0
- package/dist/cli/commands/contract.d.ts +20 -0
- package/dist/cli/commands/contract.d.ts.map +1 -0
- package/dist/cli/commands/contract.js +195 -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 +109 -19
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/gate.d.ts.map +1 -1
- package/dist/cli/commands/gate.js +2 -1
- package/dist/cli/commands/gate.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +17 -3
- 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 +47 -17
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +13 -0
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +98 -9
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +2 -1
- package/dist/cli/commands/triage.d.ts.map +1 -1
- package/dist/cli/commands/triage.js +45 -3
- package/dist/cli/commands/triage.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 +37 -8
- 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/cli/json-error-on-exit.d.ts +34 -0
- package/dist/cli/json-error-on-exit.d.ts.map +1 -0
- package/dist/cli/json-error-on-exit.js +63 -0
- package/dist/cli/json-error-on-exit.js.map +1 -0
- package/dist/cli/project-sungen-invocation.d.ts +13 -0
- package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
- package/dist/cli/project-sungen-invocation.js +95 -0
- package/dist/cli/project-sungen-invocation.js.map +1 -0
- package/dist/cli/run-command-hints.d.ts +9 -0
- package/dist/cli/run-command-hints.d.ts.map +1 -0
- package/dist/cli/run-command-hints.js +84 -0
- package/dist/cli/run-command-hints.js.map +1 -0
- package/dist/cli/waiting-for-you-block.d.ts +18 -0
- package/dist/cli/waiting-for-you-block.d.ts.map +1 -0
- package/dist/cli/waiting-for-you-block.js +22 -0
- package/dist/cli/waiting-for-you-block.js.map +1 -0
- package/dist/contract/accept-opaque-steps.d.ts +3 -0
- package/dist/contract/accept-opaque-steps.d.ts.map +1 -0
- package/dist/contract/accept-opaque-steps.js +114 -0
- package/dist/contract/accept-opaque-steps.js.map +1 -0
- package/dist/contract/approve-contract.d.ts +38 -0
- package/dist/contract/approve-contract.d.ts.map +1 -0
- package/dist/contract/approve-contract.js +93 -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 +22 -0
- package/dist/contract/build-trace-conformance.d.ts.map +1 -0
- package/dist/contract/build-trace-conformance.js +151 -0
- package/dist/contract/build-trace-conformance.js.map +1 -0
- package/dist/contract/classify-contract-change.d.ts +24 -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 +47 -0
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
- package/dist/contract/classify-trace-conformance.js +164 -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 +92 -0
- package/dist/contract/contract-schema.d.ts.map +1 -0
- package/dist/contract/contract-schema.js +124 -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 +141 -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 +49 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -0
- package/dist/contract/derive-free-feature.js +183 -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 +75 -0
- package/dist/contract/project-contract-blockers.js.map +1 -0
- package/dist/contract/record-contract-approval.d.ts +36 -0
- package/dist/contract/record-contract-approval.d.ts.map +1 -0
- package/dist/contract/record-contract-approval.js +126 -0
- package/dist/contract/record-contract-approval.js.map +1 -0
- package/dist/contract/render-free-gherkin.d.ts +42 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -0
- package/dist/contract/render-free-gherkin.js +147 -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 +20 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
- package/dist/contract/resolve-unit-trace-identities.js +62 -0
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts +44 -0
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
- package/dist/contract/trace/collect-trace-evidence.js +219 -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/read-file-once.d.ts +20 -0
- package/dist/contract/trace/read-file-once.d.ts.map +1 -0
- package/dist/contract/trace/read-file-once.js +135 -0
- package/dist/contract/trace/read-file-once.js.map +1 -0
- package/dist/contract/trace/scenario-id-claims.d.ts +11 -0
- package/dist/contract/trace/scenario-id-claims.d.ts.map +1 -0
- package/dist/contract/trace/scenario-id-claims.js +89 -0
- package/dist/contract/trace/scenario-id-claims.js.map +1 -0
- package/dist/contract/trace/select-final-attempt.d.ts +29 -0
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
- package/dist/contract/trace/select-final-attempt.js +119 -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 +22 -0
- package/dist/contract/trace/trace-binding.d.ts.map +1 -0
- package/dist/contract/trace/trace-binding.js +91 -0
- package/dist/contract/trace/trace-binding.js.map +1 -0
- package/dist/contract/trace/trace-file-reader.d.ts +47 -0
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
- package/dist/contract/trace/trace-file-reader.js +137 -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-freshness.d.ts +27 -0
- package/dist/contract/trace/trace-freshness.d.ts.map +1 -0
- package/dist/contract/trace/trace-freshness.js +146 -0
- package/dist/contract/trace/trace-freshness.js.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts +28 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
- package/dist/contract/trace/trace-identity-resolution.js +87 -0
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
- package/dist/contract/trace/trace-run-record.d.ts +32 -0
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
- package/dist/contract/trace/trace-run-record.js +135 -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 +45 -0
- package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
- package/dist/contract/trace/trace-zip-limits.js +52 -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 +109 -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 +41 -0
- package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
- package/dist/decisions/confirmed-decision-commands.js +190 -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 +43 -0
- package/dist/decisions/decision-schema.d.ts.map +1 -0
- package/dist/decisions/decision-schema.js +76 -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 +19 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -0
- package/dist/decisions/git-head-trust.js +128 -0
- package/dist/decisions/git-head-trust.js.map +1 -0
- package/dist/decisions/human-confirmation.d.ts +35 -0
- package/dist/decisions/human-confirmation.d.ts.map +1 -0
- package/dist/decisions/human-confirmation.js +161 -0
- package/dist/decisions/human-confirmation.js.map +1 -0
- package/dist/decisions/legacy-waiver-migration.d.ts +38 -0
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
- package/dist/decisions/legacy-waiver-migration.js +179 -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 +11 -2
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +8 -4
- package/dist/exporters/csv-exporter.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 +10 -9
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +9 -1
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +13 -4
- 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/exporters/matrix/xlsx-cells.js +1 -1
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +2 -12
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/exporters/xlsx-exporter.d.ts +3 -2
- package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
- package/dist/exporters/xlsx-exporter.js +4 -4
- package/dist/exporters/xlsx-exporter.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +0 -1
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +18 -4
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +3 -9
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +3 -9
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +0 -8
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +8 -52
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +0 -16
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +0 -59
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +2 -10
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/graph/board-human-actions.d.ts +5 -0
- package/dist/graph/board-human-actions.d.ts.map +1 -0
- package/dist/graph/board-human-actions.js +83 -0
- package/dist/graph/board-human-actions.js.map +1 -0
- package/dist/graph/evaluate-graph.d.ts +41 -0
- package/dist/graph/evaluate-graph.d.ts.map +1 -0
- package/dist/graph/evaluate-graph.js +77 -0
- package/dist/graph/evaluate-graph.js.map +1 -0
- package/dist/graph/human-action.d.ts +21 -0
- package/dist/graph/human-action.d.ts.map +1 -0
- package/dist/graph/human-action.js +3 -0
- package/dist/graph/human-action.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/manual-triage-decisions.d.ts +19 -0
- package/dist/graph/manual-triage-decisions.d.ts.map +1 -0
- package/dist/graph/manual-triage-decisions.js +53 -0
- package/dist/graph/manual-triage-decisions.js.map +1 -0
- package/dist/graph/node-decl.d.ts +75 -0
- package/dist/graph/node-decl.d.ts.map +1 -0
- package/dist/graph/node-decl.js +11 -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 +21 -0
- package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-contract-nodes.js +72 -0
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
- package/dist/graph/nodes/test-case-nodes.d.ts +29 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
- package/dist/graph/nodes/test-case-nodes.js +95 -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 +96 -0
- package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
- package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
- package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
- package/dist/graph/nodes/unit-contract-node.js +96 -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 +91 -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 +12 -0
- package/dist/graph/test-case-results.d.ts.map +1 -0
- package/dist/graph/test-case-results.js +161 -0
- package/dist/graph/test-case-results.js.map +1 -0
- package/dist/graph/test-case-satisfied.d.ts +26 -0
- package/dist/graph/test-case-satisfied.d.ts.map +1 -0
- package/dist/graph/test-case-satisfied.js +55 -0
- package/dist/graph/test-case-satisfied.js.map +1 -0
- package/dist/graph/test-case-state-shape.d.ts +73 -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 +135 -0
- package/dist/graph/unit-artifact-probes.js.map +1 -0
- package/dist/graph/unit-results-freshness.d.ts +29 -0
- package/dist/graph/unit-results-freshness.d.ts.map +1 -0
- package/dist/graph/unit-results-freshness.js +213 -0
- package/dist/graph/unit-results-freshness.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 +14 -2
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +20 -21
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +647 -0
- package/dist/harness/defect-draft.d.ts.map +1 -1
- package/dist/harness/defect-draft.js +12 -2
- package/dist/harness/defect-draft.js.map +1 -1
- package/dist/harness/defects.d.ts +14 -0
- package/dist/harness/defects.d.ts.map +1 -1
- package/dist/harness/defects.js +14 -10
- package/dist/harness/defects.js.map +1 -1
- package/dist/harness/flow-check.d.ts +9 -0
- package/dist/harness/flow-check.d.ts.map +1 -1
- package/dist/harness/flow-check.js +11 -0
- package/dist/harness/flow-check.js.map +1 -1
- 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 +102 -0
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
- package/dist/harness/gates/audit-input-hash.d.ts +6 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
- package/dist/harness/gates/audit-input-hash.js +124 -0
- package/dist/harness/gates/audit-input-hash.js.map +1 -0
- package/dist/harness/gates/audit-report-verification.d.ts +43 -0
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
- package/dist/harness/gates/audit-report-verification.js +241 -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 +24 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
- package/dist/harness/gates/delivery-checklist.js +161 -0
- package/dist/harness/gates/delivery-checklist.js.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-gate.js +116 -0
- package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
- package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
- package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
- package/dist/harness/gates/delivery-decision-step.js +86 -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 +166 -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-import-bounds.d.ts +13 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.js +141 -0
- package/dist/harness/gates/migrated-waiver-import-bounds.js.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts +16 -0
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
- package/dist/harness/gates/migrated-waiver-review.js +114 -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 +64 -1
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +258 -34
- 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 +58 -4
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +55 -204
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +7 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +18 -2
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/provenance.d.ts +29 -0
- package/dist/harness/provenance.d.ts.map +1 -1
- package/dist/harness/provenance.js +109 -9
- package/dist/harness/provenance.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 +41 -38
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/triage-manual-classification.d.ts +32 -0
- package/dist/harness/triage-manual-classification.d.ts.map +1 -0
- package/dist/harness/triage-manual-classification.js +56 -0
- package/dist/harness/triage-manual-classification.js.map +1 -0
- package/dist/harness/unit-paths.d.ts +8 -0
- package/dist/harness/unit-paths.d.ts.map +1 -1
- package/dist/harness/unit-paths.js +23 -1
- package/dist/harness/unit-paths.js.map +1 -1
- package/dist/hooks/bash-read-only-segment.d.ts +9 -0
- package/dist/hooks/bash-read-only-segment.d.ts.map +1 -0
- package/dist/hooks/bash-read-only-segment.js +168 -0
- package/dist/hooks/bash-read-only-segment.js.map +1 -0
- package/dist/hooks/bash-write-targets.d.ts +25 -0
- package/dist/hooks/bash-write-targets.d.ts.map +1 -0
- package/dist/hooks/bash-write-targets.js +266 -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 +13 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
- package/dist/hooks/guard-protected-paths.js +116 -0
- package/dist/hooks/guard-protected-paths.js.map +1 -0
- package/dist/hooks/guard-rules.d.ts +20 -0
- package/dist/hooks/guard-rules.d.ts.map +1 -0
- package/dist/hooks/guard-rules.js +130 -0
- package/dist/hooks/guard-rules.js.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts +17 -0
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
- package/dist/hooks/guard-tty-spoof-rule.js +22 -0
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
- package/dist/hooks/hand-back-core.d.ts +42 -0
- package/dist/hooks/hand-back-core.d.ts.map +1 -0
- package/dist/hooks/hand-back-core.js +128 -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 +14 -0
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
- package/dist/hooks/session-start-unit-state-hook.js +60 -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 +43 -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/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- 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 +11 -3
- package/dist/orchestrator/ai-skills/commands.js.map +1 -1
- package/dist/orchestrator/assets-drift.d.ts +5 -0
- package/dist/orchestrator/assets-drift.d.ts.map +1 -1
- package/dist/orchestrator/assets-drift.js +12 -3
- package/dist/orchestrator/assets-drift.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 +24 -0
- package/dist/orchestrator/project-initializer.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 +6 -26
- 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 +17 -16
- package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -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 +4 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- 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/partials/waiting-for-you.claude.md +11 -0
- package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
- package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
- package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/dist/orchestrator/templates/specs-test-data.ts +4 -22
- 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/discover.ts +15 -2
- package/src/capabilities/registry.ts +16 -0
- package/src/cli/case-triage-hint.ts +31 -0
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/capability.ts +1 -1
- package/src/cli/commands/contract-derive-command.ts +72 -0
- package/src/cli/commands/contract.ts +164 -0
- package/src/cli/commands/delivery.ts +106 -19
- package/src/cli/commands/gate.ts +2 -1
- package/src/cli/commands/generate.ts +16 -3
- package/src/cli/commands/journey.ts +45 -18
- package/src/cli/commands/next.ts +92 -11
- package/src/cli/commands/triage.ts +41 -3
- package/src/cli/commands/update.ts +41 -10
- package/src/cli/index.ts +24 -30
- package/src/cli/json-error-on-exit.ts +72 -0
- package/src/cli/project-sungen-invocation.ts +59 -0
- package/src/cli/run-command-hints.ts +47 -0
- package/src/cli/waiting-for-you-block.ts +27 -0
- package/src/contract/accept-opaque-steps.ts +114 -0
- package/src/contract/approve-contract.ts +101 -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 +103 -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 +170 -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 +166 -0
- package/src/contract/contract-units.ts +52 -0
- package/src/contract/contracts-lock-file.ts +98 -0
- package/src/contract/data-normalize.ts +66 -0
- package/src/contract/derive-free-feature.ts +153 -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 +38 -0
- package/src/contract/record-contract-approval.ts +110 -0
- package/src/contract/render-free-gherkin.ts +118 -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 +58 -0
- package/src/contract/trace/collect-trace-evidence.ts +178 -0
- package/src/contract/trace/identity-cache.ts +61 -0
- package/src/contract/trace/read-file-once.ts +95 -0
- package/src/contract/trace/scenario-id-claims.ts +60 -0
- package/src/contract/trace/select-final-attempt.ts +77 -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 +104 -0
- package/src/contract/trace/trace-binding.ts +59 -0
- package/src/contract/trace/trace-file-reader.ts +144 -0
- package/src/contract/trace/trace-fingerprint.ts +68 -0
- package/src/contract/trace/trace-freshness.ts +110 -0
- package/src/contract/trace/trace-identity-resolution.ts +77 -0
- package/src/contract/trace/trace-run-record.ts +96 -0
- package/src/contract/trace/trace-steps.ts +88 -0
- package/src/contract/trace/trace-zip-limits.ts +77 -0
- package/src/contract/trace/trace-zip-reader.ts +127 -0
- package/src/contract/verify-approval-decisions.ts +64 -0
- package/src/decisions/append-decision.ts +35 -0
- package/src/decisions/confirmed-decision-commands.ts +149 -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 +77 -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 +76 -0
- package/src/decisions/human-confirmation.ts +119 -0
- package/src/decisions/legacy-waiver-migration.ts +146 -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 +12 -4
- package/src/exporters/matrix/build.ts +11 -9
- package/src/exporters/matrix/export.ts +16 -4
- 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/exporters/matrix/xlsx-cells.ts +1 -1
- package/src/exporters/test-data-resolver.ts +2 -10
- package/src/exporters/xlsx-exporter.ts +5 -4
- package/src/generators/gherkin-parser/index.ts +0 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
- package/src/generators/test-generator/code-generator.ts +17 -4
- package/src/generators/test-generator/diagnostics.ts +3 -9
- package/src/generators/test-generator/patterns/types.ts +0 -2
- package/src/generators/test-generator/step-mapper.ts +9 -56
- package/src/generators/test-generator/utils/data-resolver.ts +0 -53
- package/src/generators/test-generator/utils/selector-resolver.ts +2 -10
- package/src/graph/board-human-actions.ts +80 -0
- package/src/graph/evaluate-graph.ts +97 -0
- package/src/graph/human-action.ts +33 -0
- package/src/graph/locate-finding.ts +93 -0
- package/src/graph/manual-triage-decisions.ts +55 -0
- package/src/graph/node-decl.ts +83 -0
- package/src/graph/nodes/core-node-catalog.ts +15 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +90 -0
- package/src/graph/nodes/test-case-nodes.ts +100 -0
- package/src/graph/nodes/unit-audit-nodes.ts +96 -0
- package/src/graph/nodes/unit-contract-node.ts +100 -0
- package/src/graph/nodes/unit-design-nodes.ts +89 -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 +111 -0
- package/src/graph/test-case-satisfied.ts +58 -0
- package/src/graph/test-case-state-shape.ts +67 -0
- package/src/graph/test-case-states.ts +84 -0
- package/src/graph/unit-artifact-probes.ts +79 -0
- package/src/graph/unit-results-freshness.ts +165 -0
- package/src/graph/unit-state-facts.ts +112 -0
- package/src/harness/audit.ts +31 -18
- package/src/harness/catalog/gate-rules.yaml +647 -0
- package/src/harness/defect-draft.ts +13 -2
- package/src/harness/defects.ts +22 -9
- package/src/harness/flow-check.ts +11 -0
- package/src/harness/gates/audit-gate-terms.ts +80 -0
- package/src/harness/gates/audit-gate-verdict.ts +79 -0
- package/src/harness/gates/audit-input-hash.ts +79 -0
- package/src/harness/gates/audit-report-verification.ts +206 -0
- package/src/harness/gates/decisions-hash.ts +42 -0
- package/src/harness/gates/delivery-checklist.ts +152 -0
- package/src/harness/gates/delivery-decision-gate.ts +139 -0
- package/src/harness/gates/delivery-decision-step.ts +89 -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 +124 -0
- package/src/harness/gates/journey-gate-inputs.ts +89 -0
- package/src/harness/gates/migrated-waiver-import-bounds.ts +103 -0
- package/src/harness/gates/migrated-waiver-review.ts +121 -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 +287 -39
- package/src/harness/manifest.ts +67 -43
- package/src/harness/next-step.ts +91 -193
- package/src/harness/parse.ts +20 -2
- package/src/harness/provenance.ts +99 -11
- package/src/harness/script-check.ts +20 -5
- package/src/harness/sensors.ts +47 -40
- package/src/harness/triage-manual-classification.ts +76 -0
- package/src/harness/unit-paths.ts +19 -0
- package/src/hooks/bash-read-only-segment.ts +130 -0
- package/src/hooks/bash-write-targets.ts +195 -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 +80 -0
- package/src/hooks/guard-rules.ts +117 -0
- package/src/hooks/guard-tty-spoof-rule.ts +34 -0
- package/src/hooks/hand-back-core.ts +118 -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 +59 -0
- package/src/hooks/stop-next-step-hook.ts +38 -0
- package/src/hooks/sungen-project-root.ts +80 -0
- package/src/index.ts +1 -2
- package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
- package/src/orchestrator/ai-skills/commands.ts +17 -5
- package/src/orchestrator/assets-drift.ts +12 -5
- package/src/orchestrator/claude-hooks-install.ts +168 -0
- package/src/orchestrator/lockstep-version.ts +28 -15
- package/src/orchestrator/project-initializer.ts +22 -0
- package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +6 -26
- 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 +17 -16
- package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -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 +4 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +6 -8
- 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/partials/waiting-for-you.claude.md +11 -0
- package/src/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
- package/src/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
- package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
- package/src/orchestrator/templates/specs-test-data.ts +4 -22
- package/src/utils/safe-yaml-parse.ts +44 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code SessionStart hook — a new, resumed or compacted session starts knowing where the unit
|
|
3
|
+
* stands (P0.1, takumi T1).
|
|
4
|
+
*
|
|
5
|
+
* After `/clear` or a context compaction the agent has lost the thread: it re-derives the state
|
|
6
|
+
* from memory, or worse, re-runs work that is already done. This injects what `sungen next`
|
|
7
|
+
* derives for the session's unit (the one cwd sits in, else the most recently active): what the
|
|
8
|
+
* project already holds — stated as "do not redo" — the audit verdict, the next steps, and what waits
|
|
9
|
+
* for a human (#954).
|
|
10
|
+
*/
|
|
11
|
+
import { NO_OP, HookMeta, SungenHook } from './hook-result-contract';
|
|
12
|
+
import { formatSteps, locateUnitState } from './hand-back-core';
|
|
13
|
+
import { sungenInvocation } from '../cli/project-sungen-invocation';
|
|
14
|
+
import { waitingForYouLines } from '../cli/waiting-for-you-block';
|
|
15
|
+
import { listUnits } from './sungen-project-root';
|
|
16
|
+
import type { UnitState } from '../harness/next-step';
|
|
17
|
+
|
|
18
|
+
export const meta: HookMeta = {
|
|
19
|
+
events: ['SessionStart'],
|
|
20
|
+
matchers: { SessionStart: 'startup|resume|clear|compact' },
|
|
21
|
+
timeout: 10,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** What the unit already holds, in workflow order. */
|
|
25
|
+
function held(s: UnitState): string {
|
|
26
|
+
const items = [
|
|
27
|
+
s.hasSpec && 'spec', s.hasViewpoint && 'test-viewpoint',
|
|
28
|
+
s.kind === 'flow' && s.hasContract && (s.hasFlowInventory ? 'flow contract + inventory' : 'flow contract'),
|
|
29
|
+
s.scenarioCount > 0 && `${s.scenarioCount} scenario(s)`,
|
|
30
|
+
s.hasSelectors && !s.selectorsArePlaceholder && 'selectors',
|
|
31
|
+
s.compiled && 'compiled spec',
|
|
32
|
+
s.hasResults && `run results${s.failedCount ? ` (${s.failedCount} failed)` : ''}`,
|
|
33
|
+
s.hasDeliverable && 'deliverable',
|
|
34
|
+
].filter(Boolean);
|
|
35
|
+
return items.length ? items.join(' · ') : 'nothing yet';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const sessionStartUnitStateHook: SungenHook = {
|
|
39
|
+
name: 'session-start-unit-state',
|
|
40
|
+
meta,
|
|
41
|
+
run(input, ctx) {
|
|
42
|
+
const found = locateUnitState(ctx);
|
|
43
|
+
if (!found) return NO_OP;
|
|
44
|
+
const { root, unit, state } = found;
|
|
45
|
+
const others = listUnits(root).length - 1;
|
|
46
|
+
const sungen = sungenInvocation(root);
|
|
47
|
+
const lines = [
|
|
48
|
+
`[sungen] Unit in progress: ${unit.name} (${unit.kind})${others > 0 ? ` — the project holds ${others} other unit(s)` : ''}.`,
|
|
49
|
+
`Already done — do not redo: ${held(state)}.`,
|
|
50
|
+
state.audit ? `Audit: ${state.audit.overall}/10 [${state.audit.gateStatus}] · ${state.audit.findings.length} finding(s).` : '',
|
|
51
|
+
`Next (\`${sungen} next ${unit.name}\`, derived from the project state):`,
|
|
52
|
+
...formatSteps(state.steps, 4, root),
|
|
53
|
+
...waitingForYouLines(state.humanActions, root, state.humanActionsHeldBy, state.humanActionsHeldByCommand),
|
|
54
|
+
input.source === 'compact' ? 'Context was compacted: re-read the unit\'s files before acting on them.' : '',
|
|
55
|
+
others > 0 ? `Working on another unit? Ask \`${sungen} next <unit>\` (or \`${sungen} next\` for all).` : '',
|
|
56
|
+
];
|
|
57
|
+
return { status: 'context', output: lines.filter(Boolean).join('\n') };
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Stop hook — a turn that ran sungen work never ends without the next step (P0.1).
|
|
3
|
+
*
|
|
4
|
+
* A slash command has no CLI exit, so the CLI's `Next: sungen next …` footer cannot reach a session
|
|
5
|
+
* that ends inside `/sungen:create-test`; the hand-back rule in the command template is only an
|
|
6
|
+
* instruction. This makes it deterministic for Claude Code: when the turn that just ended ran
|
|
7
|
+
* sungen and did not hand back (no AskUserQuestion after the last sungen call), the hand-back core's
|
|
8
|
+
* answer is injected as context and Claude continues once to present it.
|
|
9
|
+
*
|
|
10
|
+
* Loop-safe: `stop_hook_active` (Claude Code is already continuing because of a stop hook) is a
|
|
11
|
+
* no-op, and so is anything the hook cannot read — a missing transcript, a non-sungen directory.
|
|
12
|
+
*/
|
|
13
|
+
import { NO_OP, HookMeta, SungenHook } from './hook-result-contract';
|
|
14
|
+
import { run as handBackCore } from './hand-back-core';
|
|
15
|
+
import { summarizeTurn } from './claude-transcript-turn';
|
|
16
|
+
|
|
17
|
+
export const meta: HookMeta = { events: ['Stop'], timeout: 10 };
|
|
18
|
+
|
|
19
|
+
export const stopNextStepHook: SungenHook = {
|
|
20
|
+
name: 'stop-next-step',
|
|
21
|
+
meta,
|
|
22
|
+
run(input, ctx) {
|
|
23
|
+
if (input.stop_hook_active === true) return NO_OP;
|
|
24
|
+
const turn = summarizeTurn(input.transcript_path);
|
|
25
|
+
if (!turn || !turn.sungenActivity || turn.askedAfter) return NO_OP;
|
|
26
|
+
const core = handBackCore({ unit: turn.lastUnit }, ctx);
|
|
27
|
+
if (core.status !== 'context') return NO_OP;
|
|
28
|
+
return {
|
|
29
|
+
status: 'context',
|
|
30
|
+
output: [
|
|
31
|
+
'[sungen] This turn ran sungen work but ended without the next-step hand-back.',
|
|
32
|
+
'Hand back now: present these steps to the user with AskUserQuestion and stop — do not run them yourself.',
|
|
33
|
+
...(/Waiting for you/.test(core.output) ? ['Quote the "Waiting for you" block verbatim: the user runs those commands in their own terminal (`! <command>`); never run them.'] : []),
|
|
34
|
+
core.output,
|
|
35
|
+
].join('\n'),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the sungen project is, and which unit a session is working on — read cheaply off disk.
|
|
3
|
+
*
|
|
4
|
+
* A hook runs from wherever Claude Code's shell happens to be, and in a monorepo the sungen project
|
|
5
|
+
* can sit below the repository root. So a project root is found by walking UP from a start path to
|
|
6
|
+
* the nearest directory holding `qa/` plus a sungen marker (`.sungen/` or `qa/capabilities.yaml`);
|
|
7
|
+
* the marker keeps an unrelated `~/qa/` folder higher up from being mistaken for a project.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import { reportSlug } from '../harness/unit-paths';
|
|
12
|
+
|
|
13
|
+
export type UnitKind = 'screen' | 'flow' | 'api';
|
|
14
|
+
export interface UnitRef { name: string; kind: UnitKind; dir: string }
|
|
15
|
+
|
|
16
|
+
const KIND_DIRS: Array<[string, UnitKind]> = [['screens', 'screen'], ['flows', 'flow'], ['api', 'api']];
|
|
17
|
+
const isDir = (p: string): boolean => { try { return fs.statSync(p).isDirectory(); } catch { return false; } };
|
|
18
|
+
const mtime = (p: string): number => { try { return fs.statSync(p).mtimeMs; } catch { return 0; } };
|
|
19
|
+
|
|
20
|
+
export function isSungenRoot(dir: string): boolean {
|
|
21
|
+
return isDir(path.join(dir, 'qa'))
|
|
22
|
+
&& (isDir(path.join(dir, '.sungen')) || fs.existsSync(path.join(dir, 'qa', 'capabilities.yaml')));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The nearest sungen project at or above `start`, or null outside one. */
|
|
26
|
+
export function findSungenRoot(start: string): string | null {
|
|
27
|
+
let dir = path.resolve(start);
|
|
28
|
+
for (let i = 0; i < 40; i++) {
|
|
29
|
+
if (isSungenRoot(dir)) return dir;
|
|
30
|
+
const parent = path.dirname(dir);
|
|
31
|
+
if (parent === dir) return null;
|
|
32
|
+
dir = parent;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Every unit directory the project holds (`qa/api/flows` is a container, not a unit). */
|
|
38
|
+
export function listUnits(root: string): UnitRef[] {
|
|
39
|
+
const out: UnitRef[] = [];
|
|
40
|
+
for (const [sub, kind] of KIND_DIRS) {
|
|
41
|
+
let entries: fs.Dirent[] = [];
|
|
42
|
+
try { entries = fs.readdirSync(path.join(root, 'qa', sub), { withFileTypes: true }); } catch { continue; }
|
|
43
|
+
for (const e of entries) {
|
|
44
|
+
if (!e.isDirectory() || (kind === 'api' && e.name === 'flows')) continue;
|
|
45
|
+
out.push({ name: e.name, kind, dir: path.join(root, 'qa', sub, e.name) });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The unit with this name, when exactly one directory holds it (an ambiguous name is no answer). */
|
|
52
|
+
export function findUnit(root: string, name: string): UnitRef | null {
|
|
53
|
+
const hits = listUnits(root).filter((u) => u.name === name);
|
|
54
|
+
return hits.length === 1 ? hits[0] : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The unit a session is most likely on: the one `cwd` sits inside, else the one with the most
|
|
59
|
+
* recent activity — its ledger, its audit report, or its directory, whichever moved last.
|
|
60
|
+
*/
|
|
61
|
+
export function nearestUnit(root: string, cwd: string): UnitRef | null {
|
|
62
|
+
const units = listUnits(root);
|
|
63
|
+
const rel = path.relative(root, path.resolve(cwd)).split(path.sep);
|
|
64
|
+
if (rel[0] === 'qa' && rel.length >= 3) {
|
|
65
|
+
const inside = units.find((u) => u.dir === path.join(root, 'qa', rel[1], rel[2]));
|
|
66
|
+
if (inside) return inside;
|
|
67
|
+
}
|
|
68
|
+
let best: UnitRef | null = null;
|
|
69
|
+
let bestAt = -1;
|
|
70
|
+
for (const u of units) {
|
|
71
|
+
const slug = reportSlug(u.name);
|
|
72
|
+
const at = Math.max(
|
|
73
|
+
mtime(path.join(root, '.sungen', 'ledger', `${slug}.jsonl`)),
|
|
74
|
+
mtime(path.join(root, '.sungen', 'reports', `${slug}-audit.json`)),
|
|
75
|
+
mtime(u.dir),
|
|
76
|
+
);
|
|
77
|
+
if (at > bestAt) { best = u; bestAt = at; }
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -20,8 +20,7 @@ export type { ResolvedAppProfile } from './generators/test-generator/app-profile
|
|
|
20
20
|
export type { MappedStep } from './generators/test-generator/step-mapper';
|
|
21
21
|
// The shared "nothing honest to compile" step body. Exported for the driver SPI: a pattern that
|
|
22
22
|
// must refuse (SG-W017 and siblings) emits THIS rather than shipping a one-sided refusal template,
|
|
23
|
-
// which would fail the adapter-parity gate and push playwright off its refusal-only floor
|
|
24
|
-
// `date-picker-unsupported` refusal both adapters ship for the resolver-based fill-input pattern, #907).
|
|
23
|
+
// which would fail the adapter-parity gate and push playwright off its refusal-only floor of 0.
|
|
25
24
|
export { unsupportedStepCode } from './generators/test-generator/patterns/unsupported-step-code';
|
|
26
25
|
export type { ParsedStep } from './generators/gherkin-parser';
|
|
27
26
|
export { getPathCode, inferPath, resolvePathVariables } from './generators/test-generator/utils/path-inference';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-assistant partials for command templates (P0.1, root cause c).
|
|
3
|
+
*
|
|
4
|
+
* A command pulls a shared block in with an explicit directive on its own line:
|
|
5
|
+
*
|
|
6
|
+
* <!-- include: hand-back-rule -->
|
|
7
|
+
*
|
|
8
|
+
* and each assistant gets its OWN twin file — `templates/ai-src/partials/<name>.<adapter>.md` —
|
|
9
|
+
* chosen here by file name, never by branching inside the content (Claude asks with
|
|
10
|
+
* AskUserQuestion; Copilot/Codex have no such tool and end with a numbered list instead).
|
|
11
|
+
*
|
|
12
|
+
* Fails loud, like cap-fences: an unknown partial, a twin missing for one assistant, or a command
|
|
13
|
+
* without a REQUIRED include throws — a typo can never ship a command that silently lacks the rule.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import type { AdapterKey } from './adapters';
|
|
18
|
+
|
|
19
|
+
const PARTIALS_DIR = path.resolve(__dirname, '..', 'templates', 'ai-src', 'partials');
|
|
20
|
+
|
|
21
|
+
/** Every command must include these. The hand-back rule is the reason this module exists. */
|
|
22
|
+
export const REQUIRED_INCLUDES = ['hand-back-rule'] as const;
|
|
23
|
+
|
|
24
|
+
const DIRECTIVE = /^[ \t]*<!--\s*include:\s*([a-z0-9-]+)\s*-->[ \t]*$/;
|
|
25
|
+
|
|
26
|
+
export class PartialError extends Error {}
|
|
27
|
+
|
|
28
|
+
/** Partial names a body includes, in order of appearance. */
|
|
29
|
+
export function includesOf(body: string): string[] {
|
|
30
|
+
const out: string[] = [];
|
|
31
|
+
for (const line of body.split('\n')) {
|
|
32
|
+
const m = line.match(DIRECTIVE);
|
|
33
|
+
if (m) out.push(m[1]);
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Throws when a command lacks a required include — the build-time gate. */
|
|
39
|
+
export function assertRequiredIncludes(body: string, commandId: string): void {
|
|
40
|
+
const have = new Set(includesOf(body));
|
|
41
|
+
const missing = REQUIRED_INCLUDES.filter((name) => !have.has(name));
|
|
42
|
+
if (missing.length > 0) {
|
|
43
|
+
throw new PartialError(
|
|
44
|
+
`commands/${commandId}.md: missing required <!-- include: ${missing.join(' -->, <!-- include: ')} --> `
|
|
45
|
+
+ '(every command carries the next-step hand-back rule; see ai-skills/command-partial-includes.ts)',
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function readPartial(name: string, adapter: AdapterKey, commandId: string): string {
|
|
51
|
+
const file = path.join(PARTIALS_DIR, `${name}.${adapter}.md`);
|
|
52
|
+
if (!fs.existsSync(file)) {
|
|
53
|
+
throw new PartialError(`commands/${commandId}.md: <!-- include: ${name} --> has no partials/${name}.${adapter}.md`);
|
|
54
|
+
}
|
|
55
|
+
// A trailing newline is the file's, not the block's: the directive line's own break follows it.
|
|
56
|
+
return fs.readFileSync(file, 'utf8').replace(/\n+$/, '');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Replace each directive line with the adapter's partial, substituting `{{var}}` placeholders from
|
|
61
|
+
* `vars`. A placeholder with no value is an authoring error and fails loud.
|
|
62
|
+
*/
|
|
63
|
+
export function expandIncludes(body: string, adapter: AdapterKey, commandId: string, vars: Record<string, string>): string {
|
|
64
|
+
return body.split('\n').map((line) => {
|
|
65
|
+
const m = line.match(DIRECTIVE);
|
|
66
|
+
if (!m) return line;
|
|
67
|
+
return readPartial(m[1], adapter, commandId).replace(/\{\{(\w+)\}\}/g, (_all, key: string) => {
|
|
68
|
+
if (!(key in vars)) throw new PartialError(`partials/${m[1]}.${adapter}.md: unknown placeholder {{${key}}}`);
|
|
69
|
+
return vars[key];
|
|
70
|
+
});
|
|
71
|
+
}).join('\n');
|
|
72
|
+
}
|
|
@@ -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,11 +64,15 @@ 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}`);
|
|
66
76
|
/** A YAML single-quoted scalar: an apostrophe is written twice, or it ends the value early (#899). */
|
|
67
77
|
const sq = (s: string) => `'${s.replace(/'/g, "''")}'`;
|
|
68
78
|
|
|
@@ -76,7 +86,7 @@ export function renderClaudeCommand(c: CommandSource): string {
|
|
|
76
86
|
`allowed-tools: ${c.claudeTools}`,
|
|
77
87
|
'---',
|
|
78
88
|
].join('\n');
|
|
79
|
-
return fm + '\n\n' +
|
|
89
|
+
return fm + '\n\n' + bodyFor(c, 'claude', ['parallel-subagents']);
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
/** Copilot prompt file — re-derived (lenient). */
|
|
@@ -90,7 +100,7 @@ export function renderCopilotCommand(c: CommandSource): string {
|
|
|
90
100
|
`tools: ${c.copilotTools}`,
|
|
91
101
|
'---',
|
|
92
102
|
].join('\n');
|
|
93
|
-
return fm + '\n\n' +
|
|
103
|
+
return fm + '\n\n' + bodyFor(c, 'copilot', []);
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
/** Codex command-skill — command folds into a skill with an explicit trigger (decision P2). */
|
|
@@ -104,10 +114,12 @@ export function renderCodexCommand(c: CommandSource): string {
|
|
|
104
114
|
...(c.order != null ? [`order: ${c.order}`] : []),
|
|
105
115
|
'---',
|
|
106
116
|
].join('\n');
|
|
107
|
-
return fm + '\n\n' +
|
|
117
|
+
return fm + '\n\n' + bodyFor(c, 'codex', []);
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
|
|
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);
|
|
111
123
|
if (adapter === 'claude') return { outputPath: `.claude/commands/sungen/${c.id}.md`, content: renderClaudeCommand(c) };
|
|
112
124
|
if (adapter === 'copilot') return { outputPath: `.github/prompts/sungen-${c.id}.prompt.md`, content: renderCopilotCommand(c) };
|
|
113
125
|
return { outputPath: `.agents/skills/sungen-${c.id}/SKILL.md`, content: renderCodexCommand(c) };
|
|
@@ -2,6 +2,7 @@ import * as fs from 'fs';
|
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { getPackageVersion } from '../exporters/package-info';
|
|
4
4
|
import { readJsonConfig, warnUnreadableConfig } from '../harness/config-file';
|
|
5
|
+
import { updateCommand } from '../cli/project-sungen-invocation';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Are this project's AI assets (commands + skills under `.claude/` etc.) the ones
|
|
@@ -54,6 +55,16 @@ export function checkAssetsDrift(cwd: string): AssetsDrift | null {
|
|
|
54
55
|
return { recordedVersion, runningVersion, changed, total };
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* The note's text. The update command is the one this project runs (`npx sungen` with a local install)
|
|
60
|
+
* on the channel it runs (`--alpha` / `--beta`): a plain `sungen update` would switch to stable (#939).
|
|
61
|
+
*/
|
|
62
|
+
export function assetsDriftNote(drift: AssetsDrift, cwd: string, paint: (cmd: string) => string = (c) => c): string {
|
|
63
|
+
return `note: this project's AI commands/skills were written by sungen ${drift.recordedVersion}, ` +
|
|
64
|
+
`you are running ${drift.runningVersion} — run ${paint(updateCommand(cwd, drift.runningVersion))} to refresh them ` +
|
|
65
|
+
'(upgrading the package alone does not).';
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
/** One line, on stderr so `--json` output stays machine-readable. */
|
|
58
69
|
export function warnAssetsDrift(cwd: string): void {
|
|
59
70
|
const drift = checkAssetsDrift(cwd);
|
|
@@ -61,9 +72,5 @@ export function warnAssetsDrift(cwd: string): void {
|
|
|
61
72
|
const gray = '\x1b[90m';
|
|
62
73
|
const cyan = '\x1b[36m';
|
|
63
74
|
const reset = '\x1b[0m';
|
|
64
|
-
process.stderr.write(
|
|
65
|
-
`${gray}note: this project's AI commands/skills were written by sungen ${drift.recordedVersion}, ` +
|
|
66
|
-
`you are running ${drift.runningVersion} — run ${cyan}sungen update${reset}${gray} to refresh them ` +
|
|
67
|
-
`(upgrading the package alone does not).${reset}\n`,
|
|
68
|
-
);
|
|
75
|
+
process.stderr.write(`${gray}${assetsDriftNote(drift, cwd, (c) => `${cyan}${c}${reset}${gray}`)}${reset}\n`);
|
|
69
76
|
}
|
|
@@ -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')) {
|
|
@@ -287,6 +294,7 @@ export class ProjectInitializer {
|
|
|
287
294
|
'specs/.auth-mobile/', // mobile auth contract = credentials (sensitive)
|
|
288
295
|
'.env.appium', // local mobile-test env = machine paths + device/team ids (.example IS committed)
|
|
289
296
|
'test-results/',
|
|
297
|
+
'test-results-free/', // free / @impl:code runs: their own outputDir, so a compiled run cannot clear their traces (#941)
|
|
290
298
|
'playwright-report/',
|
|
291
299
|
'.playwright-mcp/',
|
|
292
300
|
'.sungen/figma-cache/', // raw Figma node JSON (design IP)
|
|
@@ -397,6 +405,20 @@ export class ProjectInitializer {
|
|
|
397
405
|
);
|
|
398
406
|
}
|
|
399
407
|
|
|
408
|
+
/**
|
|
409
|
+
* Merge sungen's Claude Code hooks into `.claude/settings.json` (user hooks kept, backup before
|
|
410
|
+
* any change, unreadable file left alone — see claude-hooks-install.ts). A no-op for a project
|
|
411
|
+
* without Claude.
|
|
412
|
+
*/
|
|
413
|
+
private createClaudeHooks(): void {
|
|
414
|
+
if (!this.agents.includes('claude')) return;
|
|
415
|
+
const r = installClaudeHooks(this.cwd);
|
|
416
|
+
const line = describeHooksInstall(r);
|
|
417
|
+
if (r.settings === 'unreadable') this.notDoneItems.push(line);
|
|
418
|
+
else if (r.settings === 'unchanged') this.skippedItems.push(line);
|
|
419
|
+
else this.createdItems.push(line);
|
|
420
|
+
}
|
|
421
|
+
|
|
400
422
|
/**
|
|
401
423
|
* Create `.codex/config.toml` for Codex CLI — the Codex analog of `.mcp.json` (Claude) and
|
|
402
424
|
* `.vscode/mcp.json` (Copilot), so `sungen run-test` under Codex drives the same live Playwright
|