@sun-asterisk/sungen 3.3.0-alpha.1 → 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/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/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/contract-derive-command.d.ts +4 -2
- package/dist/cli/commands/contract-derive-command.d.ts.map +1 -1
- package/dist/cli/commands/contract-derive-command.js +19 -5
- package/dist/cli/commands/contract-derive-command.js.map +1 -1
- package/dist/cli/commands/contract.d.ts +3 -0
- package/dist/cli/commands/contract.d.ts.map +1 -1
- package/dist/cli/commands/contract.js +40 -7
- package/dist/cli/commands/contract.js.map +1 -1
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +59 -18
- 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 +14 -2
- 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 +6 -4
- package/dist/cli/commands/journey.js.map +1 -1
- package/dist/cli/commands/next.d.ts +7 -2
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +41 -10
- 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.map +1 -1
- package/dist/cli/commands/update.js +6 -2
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +5 -1
- 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 +8 -1
- package/dist/contract/approve-contract.d.ts.map +1 -1
- package/dist/contract/approve-contract.js +6 -0
- package/dist/contract/approve-contract.js.map +1 -1
- package/dist/contract/build-contract-verdict.js +2 -2
- package/dist/contract/build-contract-verdict.js.map +1 -1
- package/dist/contract/build-trace-conformance.d.ts +5 -1
- package/dist/contract/build-trace-conformance.d.ts.map +1 -1
- package/dist/contract/build-trace-conformance.js +12 -14
- package/dist/contract/build-trace-conformance.js.map +1 -1
- package/dist/contract/classify-contract-change.d.ts +3 -2
- package/dist/contract/classify-contract-change.d.ts.map +1 -1
- package/dist/contract/classify-contract-change.js.map +1 -1
- package/dist/contract/classify-trace-conformance.d.ts +18 -3
- package/dist/contract/classify-trace-conformance.d.ts.map +1 -1
- package/dist/contract/classify-trace-conformance.js +64 -17
- package/dist/contract/classify-trace-conformance.js.map +1 -1
- package/dist/contract/contract-schema.d.ts +21 -0
- package/dist/contract/contract-schema.d.ts.map +1 -1
- package/dist/contract/contract-schema.js +25 -3
- package/dist/contract/contract-schema.js.map +1 -1
- package/dist/contract/contracts-lock-file.d.ts.map +1 -1
- package/dist/contract/contracts-lock-file.js +1 -0
- package/dist/contract/contracts-lock-file.js.map +1 -1
- package/dist/contract/derive-free-feature.d.ts +19 -0
- package/dist/contract/derive-free-feature.d.ts.map +1 -1
- package/dist/contract/derive-free-feature.js +40 -2
- package/dist/contract/derive-free-feature.js.map +1 -1
- package/dist/contract/project-contract-blockers.d.ts.map +1 -1
- package/dist/contract/project-contract-blockers.js +4 -2
- package/dist/contract/project-contract-blockers.js.map +1 -1
- package/dist/contract/record-contract-approval.d.ts +16 -1
- package/dist/contract/record-contract-approval.d.ts.map +1 -1
- package/dist/contract/record-contract-approval.js +29 -1
- package/dist/contract/record-contract-approval.js.map +1 -1
- package/dist/contract/render-free-gherkin.d.ts +2 -0
- package/dist/contract/render-free-gherkin.d.ts.map +1 -1
- package/dist/contract/render-free-gherkin.js +6 -0
- package/dist/contract/render-free-gherkin.js.map +1 -1
- package/dist/contract/resolve-unit-trace-identities.d.ts +12 -0
- package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -1
- package/dist/contract/resolve-unit-trace-identities.js +33 -49
- package/dist/contract/resolve-unit-trace-identities.js.map +1 -1
- package/dist/contract/trace/collect-trace-evidence.d.ts +16 -5
- package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -1
- package/dist/contract/trace/collect-trace-evidence.js +101 -43
- package/dist/contract/trace/collect-trace-evidence.js.map +1 -1
- 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 +4 -2
- package/dist/contract/trace/select-final-attempt.d.ts.map +1 -1
- package/dist/contract/trace/select-final-attempt.js +7 -4
- package/dist/contract/trace/select-final-attempt.js.map +1 -1
- package/dist/contract/trace/test-step-join.d.ts +3 -3
- package/dist/contract/trace/test-step-join.d.ts.map +1 -1
- package/dist/contract/trace/test-step-join.js +2 -2
- package/dist/contract/trace/test-step-join.js.map +1 -1
- package/dist/contract/trace/trace-binding.d.ts +3 -2
- package/dist/contract/trace/trace-binding.d.ts.map +1 -1
- package/dist/contract/trace/trace-binding.js +6 -3
- package/dist/contract/trace/trace-binding.js.map +1 -1
- package/dist/contract/trace/trace-file-reader.d.ts +14 -2
- package/dist/contract/trace/trace-file-reader.d.ts.map +1 -1
- package/dist/contract/trace/trace-file-reader.js +27 -45
- package/dist/contract/trace/trace-file-reader.js.map +1 -1
- 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 +2 -0
- package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -1
- package/dist/contract/trace/trace-identity-resolution.js +6 -3
- package/dist/contract/trace/trace-identity-resolution.js.map +1 -1
- package/dist/contract/trace/trace-run-record.d.ts +8 -3
- package/dist/contract/trace/trace-run-record.d.ts.map +1 -1
- package/dist/contract/trace/trace-run-record.js +42 -22
- package/dist/contract/trace/trace-run-record.js.map +1 -1
- package/dist/contract/trace/trace-steps.js +1 -1
- package/dist/contract/trace/trace-steps.js.map +1 -1
- package/dist/contract/trace/trace-zip-limits.d.ts +5 -1
- package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -1
- package/dist/contract/trace/trace-zip-limits.js +6 -2
- package/dist/contract/trace/trace-zip-limits.js.map +1 -1
- package/dist/contract/verify-approval-decisions.d.ts.map +1 -1
- package/dist/contract/verify-approval-decisions.js +9 -4
- package/dist/contract/verify-approval-decisions.js.map +1 -1
- package/dist/decisions/confirmed-decision-commands.d.ts +11 -0
- package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -1
- package/dist/decisions/confirmed-decision-commands.js +21 -3
- package/dist/decisions/confirmed-decision-commands.js.map +1 -1
- package/dist/decisions/decision-schema.d.ts +2 -1
- package/dist/decisions/decision-schema.d.ts.map +1 -1
- package/dist/decisions/decision-schema.js +2 -1
- package/dist/decisions/decision-schema.js.map +1 -1
- package/dist/decisions/git-head-trust.d.ts +12 -0
- package/dist/decisions/git-head-trust.d.ts.map +1 -1
- package/dist/decisions/git-head-trust.js +52 -0
- package/dist/decisions/git-head-trust.js.map +1 -1
- package/dist/decisions/human-confirmation.d.ts +2 -0
- package/dist/decisions/human-confirmation.d.ts.map +1 -1
- package/dist/decisions/human-confirmation.js +6 -0
- package/dist/decisions/human-confirmation.js.map +1 -1
- package/dist/decisions/legacy-waiver-migration.d.ts +8 -1
- package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -1
- package/dist/decisions/legacy-waiver-migration.js +13 -4
- package/dist/decisions/legacy-waiver-migration.js.map +1 -1
- 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/export.d.ts +6 -1
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +11 -4
- package/dist/exporters/matrix/export.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/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/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 +21 -1
- package/dist/graph/evaluate-graph.d.ts.map +1 -1
- package/dist/graph/evaluate-graph.js +37 -9
- package/dist/graph/evaluate-graph.js.map +1 -1
- 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/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 +16 -0
- package/dist/graph/node-decl.d.ts.map +1 -1
- package/dist/graph/node-decl.js +4 -1
- package/dist/graph/node-decl.js.map +1 -1
- package/dist/graph/nodes/test-case-contract-nodes.d.ts +3 -1
- package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -1
- package/dist/graph/nodes/test-case-contract-nodes.js +22 -6
- package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -1
- package/dist/graph/nodes/test-case-nodes.d.ts +3 -0
- package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -1
- package/dist/graph/nodes/test-case-nodes.js +33 -4
- package/dist/graph/nodes/test-case-nodes.js.map +1 -1
- package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -1
- package/dist/graph/nodes/unit-audit-nodes.js +1 -0
- package/dist/graph/nodes/unit-audit-nodes.js.map +1 -1
- package/dist/graph/nodes/unit-contract-node.d.ts +2 -1
- package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -1
- package/dist/graph/nodes/unit-contract-node.js +16 -1
- package/dist/graph/nodes/unit-contract-node.js.map +1 -1
- package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -1
- package/dist/graph/nodes/unit-design-nodes.js +2 -1
- package/dist/graph/nodes/unit-design-nodes.js.map +1 -1
- package/dist/graph/test-case-results.d.ts +1 -0
- package/dist/graph/test-case-results.d.ts.map +1 -1
- package/dist/graph/test-case-results.js +27 -3
- package/dist/graph/test-case-results.js.map +1 -1
- package/dist/graph/test-case-satisfied.d.ts +5 -4
- package/dist/graph/test-case-satisfied.d.ts.map +1 -1
- package/dist/graph/test-case-satisfied.js +4 -0
- package/dist/graph/test-case-satisfied.js.map +1 -1
- package/dist/graph/test-case-state-shape.d.ts +7 -1
- package/dist/graph/test-case-state-shape.d.ts.map +1 -1
- package/dist/graph/unit-artifact-probes.d.ts.map +1 -1
- package/dist/graph/unit-artifact-probes.js +3 -1
- package/dist/graph/unit-artifact-probes.js.map +1 -1
- 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/harness/audit.d.ts +3 -2
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +4 -17
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/catalog/gate-rules.yaml +3 -3
- 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-verdict.d.ts.map +1 -1
- package/dist/harness/gates/audit-gate-verdict.js +2 -1
- package/dist/harness/gates/audit-gate-verdict.js.map +1 -1
- package/dist/harness/gates/audit-input-hash.d.ts +2 -0
- package/dist/harness/gates/audit-input-hash.d.ts.map +1 -1
- package/dist/harness/gates/audit-input-hash.js +30 -2
- package/dist/harness/gates/audit-input-hash.js.map +1 -1
- package/dist/harness/gates/audit-report-verification.d.ts +17 -6
- package/dist/harness/gates/audit-report-verification.d.ts.map +1 -1
- package/dist/harness/gates/audit-report-verification.js +55 -21
- package/dist/harness/gates/audit-report-verification.js.map +1 -1
- package/dist/harness/gates/delivery-checklist.d.ts +3 -0
- package/dist/harness/gates/delivery-checklist.d.ts.map +1 -1
- package/dist/harness/gates/delivery-checklist.js +39 -6
- package/dist/harness/gates/delivery-checklist.js.map +1 -1
- package/dist/harness/gates/delivery-decision-gate.d.ts +4 -0
- package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -1
- package/dist/harness/gates/delivery-decision-gate.js +26 -1
- package/dist/harness/gates/delivery-decision-gate.js.map +1 -1
- package/dist/harness/gates/delivery-decision-step.d.ts +4 -1
- package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -1
- package/dist/harness/gates/delivery-decision-step.js +17 -2
- package/dist/harness/gates/delivery-decision-step.js.map +1 -1
- package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -1
- package/dist/harness/gates/in-run-decision-check.js +40 -12
- package/dist/harness/gates/in-run-decision-check.js.map +1 -1
- 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 +14 -4
- package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -1
- package/dist/harness/gates/migrated-waiver-review.js +78 -80
- package/dist/harness/gates/migrated-waiver-review.js.map +1 -1
- package/dist/harness/journey.d.ts +40 -0
- package/dist/harness/journey.d.ts.map +1 -1
- package/dist/harness/journey.js +155 -22
- package/dist/harness/journey.js.map +1 -1
- package/dist/harness/next-step.d.ts +19 -0
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +21 -0
- package/dist/harness/next-step.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/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 +12 -2
- package/dist/hooks/bash-write-targets.d.ts.map +1 -1
- package/dist/hooks/bash-write-targets.js +122 -29
- package/dist/hooks/bash-write-targets.js.map +1 -1
- package/dist/hooks/guard-protected-paths.d.ts +4 -0
- package/dist/hooks/guard-protected-paths.d.ts.map +1 -1
- package/dist/hooks/guard-protected-paths.js +13 -3
- package/dist/hooks/guard-protected-paths.js.map +1 -1
- package/dist/hooks/guard-rules.d.ts +0 -17
- package/dist/hooks/guard-rules.d.ts.map +1 -1
- package/dist/hooks/guard-rules.js +79 -10
- package/dist/hooks/guard-rules.js.map +1 -1
- package/dist/hooks/guard-tty-spoof-rule.d.ts +3 -1
- package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -1
- package/dist/hooks/guard-tty-spoof-rule.js +3 -2
- package/dist/hooks/guard-tty-spoof-rule.js.map +1 -1
- package/dist/hooks/hand-back-core.d.ts +9 -4
- package/dist/hooks/hand-back-core.d.ts.map +1 -1
- package/dist/hooks/hand-back-core.js +24 -11
- package/dist/hooks/hand-back-core.js.map +1 -1
- package/dist/hooks/session-start-unit-state-hook.d.ts +2 -1
- package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -1
- package/dist/hooks/session-start-unit-state-hook.js +9 -4
- package/dist/hooks/session-start-unit-state-hook.js.map +1 -1
- package/dist/hooks/stop-next-step-hook.d.ts.map +1 -1
- package/dist/hooks/stop-next-step-hook.js +1 -0
- package/dist/hooks/stop-next-step-hook.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/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +1 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +6 -3
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +1 -1
- 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/package.json +3 -3
- package/src/capabilities/discover.ts +15 -2
- package/src/cli/case-triage-hint.ts +31 -0
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/contract-derive-command.ts +20 -8
- package/src/cli/commands/contract.ts +41 -7
- package/src/cli/commands/delivery.ts +56 -18
- package/src/cli/commands/gate.ts +2 -1
- package/src/cli/commands/generate.ts +13 -2
- package/src/cli/commands/journey.ts +8 -6
- package/src/cli/commands/next.ts +41 -12
- package/src/cli/commands/triage.ts +41 -3
- package/src/cli/commands/update.ts +6 -2
- package/src/cli/index.ts +5 -1
- 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 +10 -3
- package/src/contract/build-contract-verdict.ts +2 -2
- package/src/contract/build-trace-conformance.ts +11 -8
- package/src/contract/classify-contract-change.ts +3 -3
- package/src/contract/classify-trace-conformance.ts +76 -22
- package/src/contract/contract-schema.ts +31 -2
- package/src/contract/contracts-lock-file.ts +1 -0
- package/src/contract/derive-free-feature.ts +46 -3
- package/src/contract/project-contract-blockers.ts +4 -2
- package/src/contract/record-contract-approval.ts +41 -1
- package/src/contract/render-free-gherkin.ts +5 -0
- package/src/contract/resolve-unit-trace-identities.ts +35 -12
- package/src/contract/trace/collect-trace-evidence.ts +105 -36
- 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 +12 -5
- package/src/contract/trace/test-step-join.ts +6 -5
- package/src/contract/trace/trace-binding.ts +7 -4
- package/src/contract/trace/trace-file-reader.ts +34 -13
- package/src/contract/trace/trace-freshness.ts +110 -0
- package/src/contract/trace/trace-identity-resolution.ts +7 -4
- package/src/contract/trace/trace-run-record.ts +37 -15
- package/src/contract/trace/trace-steps.ts +1 -1
- package/src/contract/trace/trace-zip-limits.ts +6 -2
- package/src/contract/verify-approval-decisions.ts +9 -5
- package/src/decisions/confirmed-decision-commands.ts +25 -4
- package/src/decisions/decision-schema.ts +2 -1
- package/src/decisions/git-head-trust.ts +44 -0
- package/src/decisions/human-confirmation.ts +5 -0
- package/src/decisions/legacy-waiver-migration.ts +14 -3
- package/src/exporters/csv-exporter.ts +12 -4
- package/src/exporters/matrix/export.ts +11 -4
- package/src/exporters/matrix/xlsx-cells.ts +1 -1
- package/src/exporters/xlsx-exporter.ts +5 -4
- package/src/graph/board-human-actions.ts +80 -0
- package/src/graph/evaluate-graph.ts +45 -10
- package/src/graph/human-action.ts +33 -0
- package/src/graph/manual-triage-decisions.ts +55 -0
- package/src/graph/node-decl.ts +18 -0
- package/src/graph/nodes/test-case-contract-nodes.ts +28 -7
- package/src/graph/nodes/test-case-nodes.ts +37 -5
- package/src/graph/nodes/unit-audit-nodes.ts +2 -1
- package/src/graph/nodes/unit-contract-node.ts +20 -2
- package/src/graph/nodes/unit-design-nodes.ts +2 -1
- package/src/graph/test-case-results.ts +25 -4
- package/src/graph/test-case-satisfied.ts +7 -4
- package/src/graph/test-case-state-shape.ts +7 -2
- package/src/graph/unit-artifact-probes.ts +3 -1
- package/src/graph/unit-results-freshness.ts +165 -0
- package/src/harness/audit.ts +4 -13
- package/src/harness/catalog/gate-rules.yaml +3 -3
- 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-verdict.ts +2 -1
- package/src/harness/gates/audit-input-hash.ts +27 -3
- package/src/harness/gates/audit-report-verification.ts +57 -24
- package/src/harness/gates/delivery-checklist.ts +39 -7
- package/src/harness/gates/delivery-decision-gate.ts +29 -1
- package/src/harness/gates/delivery-decision-step.ts +19 -3
- package/src/harness/gates/in-run-decision-check.ts +38 -13
- package/src/harness/gates/migrated-waiver-import-bounds.ts +103 -0
- package/src/harness/gates/migrated-waiver-review.ts +90 -37
- package/src/harness/journey.ts +174 -21
- package/src/harness/next-step.ts +34 -1
- package/src/harness/provenance.ts +99 -11
- 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 +109 -23
- package/src/hooks/guard-protected-paths.ts +13 -3
- package/src/hooks/guard-rules.ts +37 -18
- package/src/hooks/guard-tty-spoof-rule.ts +6 -3
- package/src/hooks/hand-back-core.ts +24 -12
- package/src/hooks/session-start-unit-state-hook.ts +9 -4
- package/src/hooks/stop-next-step-hook.ts +1 -0
- package/src/orchestrator/assets-drift.ts +12 -5
- package/src/orchestrator/project-initializer.ts +1 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +6 -3
- package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +1 -1
- 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/hooks/guard-rules.ts
CHANGED
|
@@ -4,20 +4,29 @@
|
|
|
4
4
|
*
|
|
5
5
|
* protected-approval-paths DENY a precise write (Edit/Write/MultiEdit, or Bash `>`, `tee`,
|
|
6
6
|
* `sed -i`) to a contract lock, a decision record, approval state or
|
|
7
|
-
* trace evidence (.sungen/trace-identity, test-results/sungen-run-record*)
|
|
7
|
+
* trace evidence (.sungen/trace-identity, test-results[-free]/sungen-run-record*)
|
|
8
8
|
* protected-hook-control ASK the same writes to the files that control the hooks, so the
|
|
9
9
|
* agent cannot switch its own guard off unasked
|
|
10
|
-
* bash-protected-mention ASK any other Bash segment that names a protected path and
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* bash-protected-mention ASK any other Bash segment that names a protected path and is not
|
|
11
|
+
* read-only (cp, mv, ln, install, rm, bash -c, python -c, perl -i…);
|
|
12
|
+
* a read-only one too when its output is piped into a non-read-only
|
|
13
|
+
* command, or the line has command substitution or sets shell state
|
|
14
|
+
* (`X=…`, export, alias, a function…); a heredoc / here-string
|
|
15
|
+
* that names one; and a write target with a glob or brace (#968 — bash-read-only-segment.ts lists what counts
|
|
16
|
+
* as read-only, and the accepted floor)
|
|
13
17
|
*
|
|
14
18
|
* A floor, not a sandbox: a path built at runtime, a symlink, or a script file that writes without
|
|
15
|
-
* naming the path on the command line is out of reach by design
|
|
19
|
+
* naming the path on the command line is out of reach by design (the full list of what the floor
|
|
20
|
+
* does not catch is in bash-read-only-segment.ts; release-time decision integrity is the backstop). Each rule only matches strings,
|
|
16
21
|
* so each fails open (`onError: 'no-op'`); a rule that READS project state must declare `'ask'`.
|
|
17
22
|
*/
|
|
23
|
+
import * as path from 'path';
|
|
18
24
|
import type { HookContext, HookResult } from './hook-result-contract';
|
|
19
|
-
import { bashSegments } from './bash-write-targets';
|
|
20
|
-
import {
|
|
25
|
+
import { BashSegment, bashSegments } from './bash-write-targets';
|
|
26
|
+
import { isReadOnlySegment, lineKeepsReadOnlyExemption, pipelineStaysReadOnly } from './bash-read-only-segment';
|
|
27
|
+
import {
|
|
28
|
+
approvalRecordPath, hookControlPath, mentionsProtectedPath, mentionsProtectedText, opaqueNearProtected, traceEvidencePath,
|
|
29
|
+
} from './guard-protected-paths';
|
|
21
30
|
|
|
22
31
|
/** One tool call, normalized from the untrusted payload. */
|
|
23
32
|
export interface GuardedCall {
|
|
@@ -76,23 +85,33 @@ export const protectedHookControl: GuardRule = {
|
|
|
76
85
|
},
|
|
77
86
|
};
|
|
78
87
|
|
|
79
|
-
/**
|
|
80
|
-
const
|
|
81
|
-
const GIT_READ_ONLY = new Set(['diff', 'log', 'show', 'status']);
|
|
82
|
-
const isReadOnly = (cmd: string, words: string[]): boolean =>
|
|
83
|
-
READ_ONLY.has(cmd) || (cmd === 'git' && GIT_READ_ONLY.has(words.find((w) => !w.startsWith('-')) ?? ''));
|
|
88
|
+
/** A heredoc or here-string: its body is another program's input, which the segments do not see. */
|
|
89
|
+
const HEREDOC = /<</;
|
|
84
90
|
|
|
85
91
|
export const bashProtectedMention: GuardRule = {
|
|
86
92
|
id: 'bash-protected-mention',
|
|
87
93
|
onError: 'no-op',
|
|
88
94
|
check(call) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
const command = call.tool === 'Bash' ? call.bashCommand : undefined;
|
|
96
|
+
if (!command) return null;
|
|
97
|
+
const segs = bashSegments(command, call.cwd);
|
|
98
|
+
const lineExempt = lineKeepsReadOnlyExemption(command, segs);
|
|
99
|
+
// the command word too: zsh `for f (qa/decisions/*) …` puts the list where a command name goes
|
|
100
|
+
const names = (s: BashSegment): boolean => [s.cmdPath, ...s.words, ...s.assigns.map((a) => a.slice(a.indexOf('=') + 1))]
|
|
101
|
+
.some((w) => w !== '' && (mentionsProtectedPath(w, s.dir) || opaqueNearProtected(w)));
|
|
102
|
+
const seg = segs.find((s, i) => names(s) && !(lineExempt && isReadOnlySegment(s) && pipelineStaysReadOnly(segs, i)));
|
|
103
|
+
// a write target the shell expands (`> q*/decisions/x`, `--output=qa/{a,b}`, `> $Q/decisions/x`, a literal `\`),
|
|
104
|
+
// or a relative one after a `cd` the guard could not follow, cannot be judged by its text
|
|
105
|
+
const opaqueWrite = segs.some((s) => s.writesInUnknownDir || s.writes.some((w) => {
|
|
106
|
+
const rel = path.relative(s.dir, w);
|
|
107
|
+
return /[*?[{\\]/.test(rel) || opaqueNearProtected(rel);
|
|
108
|
+
}));
|
|
109
|
+
if (!seg && !opaqueWrite && !(HEREDOC.test(command) && mentionsProtectedText(command))) return null;
|
|
110
|
+
const what = seg ? (seg.cmd ? `\`${seg.cmd}\` command` : 'variable') : opaqueWrite ? 'write target the guard cannot resolve' : 'heredoc';
|
|
111
|
+
return {
|
|
93
112
|
status: 'ask',
|
|
94
|
-
askReason: `sungen: this
|
|
113
|
+
askReason: `sungen: this ${what} names a contract lock, a decision record, approval state or a hook-control file, `
|
|
95
114
|
+ 'and the guard cannot tell whether it writes it. Allow only if you asked for exactly this.',
|
|
96
|
-
}
|
|
115
|
+
};
|
|
97
116
|
},
|
|
98
117
|
};
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Guard rule `tty-spoof` (phase 06, M5): ASK before an agent runs a human-confirmed sungen command
|
|
3
3
|
* through a terminal emulator.
|
|
4
4
|
*
|
|
5
|
-
* `contract approve`, `journey --waive
|
|
5
|
+
* `contract approve`, `journey --waive`, `journey --decide`, `journey --signoff`, `triage --as test-defect|environment`
|
|
6
|
+
* (#928: a red classified away from the product-defect path) and `delivery --accept-in-run` (delivering past
|
|
7
|
+
* decisions recorded during the run) refuse without a TTY (DOS-13.4), and
|
|
6
8
|
* an agent's Bash has none — unless it borrows one: `script`, `expect`, `unbuffer`, or a pty from
|
|
7
9
|
* Python/Perl/zsh. Then the prompt sees a "terminal" and a piped phrase reads as a human typing it.
|
|
8
10
|
* This rule spots the pair in the raw command (quotes included, so `bash -c "…"` and `expect -c '…'`
|
|
@@ -13,7 +15,7 @@
|
|
|
13
15
|
import type { GuardRule } from './guard-rules';
|
|
14
16
|
|
|
15
17
|
const TTY_EMULATOR = /\b(?:script|unbuffer|expect|pty|zpty|openpty|forkpty|ptyprocess)\b/i;
|
|
16
|
-
const HUMAN_GATED = /\bsungen\b[\s\S]*?\b(?:contract['",\s]+approve\b|journey\b[\s\S]*?--(?:waive|decide)\b)/i;
|
|
18
|
+
const HUMAN_GATED = /\bsungen\b[\s\S]*?\b(?:contract['",\s]+approve\b|journey\b[\s\S]*?--(?:waive|decide|signoff)\b|triage\b[\s\S]*?--as[\s='",]+(?:test-defect|environment)\b|delivery\b[\s\S]*?--accept-in-run\b)/i;
|
|
17
19
|
|
|
18
20
|
export const ttySpoof: GuardRule = {
|
|
19
21
|
id: 'tty-spoof',
|
|
@@ -23,7 +25,8 @@ export const ttySpoof: GuardRule = {
|
|
|
23
25
|
if (!cmd || !TTY_EMULATOR.test(cmd) || !HUMAN_GATED.test(cmd)) return null;
|
|
24
26
|
return {
|
|
25
27
|
status: 'ask',
|
|
26
|
-
askReason: 'sungen: this runs a human-confirmed sungen action (`contract approve` / `journey --waive|--decide`
|
|
28
|
+
askReason: 'sungen: this runs a human-confirmed sungen action (`contract approve` / `journey --waive|--decide|--signoff` / '
|
|
29
|
+
+ '`triage --as test-defect|environment` / `delivery --accept-in-run`) through a terminal '
|
|
27
30
|
+ 'emulator (script / expect / unbuffer / pty). Those confirmations exist so a PERSON at a terminal decides — allow only if you '
|
|
28
31
|
+ 'are that person and asked for exactly this; otherwise run the command yourself in your own terminal.',
|
|
29
32
|
};
|
|
@@ -10,23 +10,28 @@
|
|
|
10
10
|
* commander's preAction, so a usage error — which never reaches an action — and `main().catch`
|
|
11
11
|
* ended in silence. The state now starts the moment parsing does; the action only refines it.
|
|
12
12
|
*/
|
|
13
|
+
import { sungenInvocation, withProjectInvocationInText } from '../cli/project-sungen-invocation';
|
|
14
|
+
import { waitingForYouLines } from '../cli/waiting-for-you-block';
|
|
13
15
|
import { resolveUnitCandidates } from '../cli/resolve-unit';
|
|
14
16
|
import { readUnitState, NextStep, UnitState } from '../harness/next-step';
|
|
15
17
|
import { NO_OP, HookContext, HookInput, HookResult } from './hook-result-contract';
|
|
16
18
|
import { findSungenRoot, findUnit, nearestUnit, UnitRef } from './sungen-project-root';
|
|
17
19
|
|
|
18
|
-
/** `
|
|
19
|
-
const SILENT_COMMANDS = new Set(['
|
|
20
|
+
/** `hook` speaks JSON to Claude Code on stdout: it never prints a hand-back. */
|
|
21
|
+
const SILENT_COMMANDS = new Set(['hook']);
|
|
22
|
+
/** `next` IS the answer when it succeeds; a failed `next` answered nothing and hands back like any failure (#937). */
|
|
23
|
+
const ANSWER_COMMANDS = new Set(['next']);
|
|
20
24
|
const UNIT_FLAG = /^(?:--screen|-s|--flow|--area|--api)$/;
|
|
21
25
|
const UNIT_FLAG_EQ = /^--(?:screen|flow|area|api)=(.+)$/;
|
|
22
26
|
/** A unit id is a name or `flows/<name>` — anything else is not offered back to the operator. */
|
|
23
27
|
const SAFE_UNIT = /^[\w.-]+(?:\/[\w.-]+)?$/;
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
/** `invocation`: how the project runs sungen (`npx sungen` with a local install, #939). */
|
|
30
|
+
export function handBackLine(unit?: string, invocation = 'sungen'): string {
|
|
31
|
+
return `Next: ${invocation} next${unit ? ` ${unit}` : ''}`;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
export interface CliHandBackState { unit?: string; machine: boolean; silent: boolean; actionRan: boolean }
|
|
34
|
+
export interface CliHandBackState { unit?: string; machine: boolean; silent: boolean; answer: boolean; actionRan: boolean }
|
|
30
35
|
|
|
31
36
|
/** The default, set before commander parses — what a usage error or a fatal error hands back. */
|
|
32
37
|
export function initialHandBackState(argv: string[]): CliHandBackState {
|
|
@@ -38,13 +43,14 @@ export function initialHandBackState(argv: string[]): CliHandBackState {
|
|
|
38
43
|
else if (UNIT_FLAG.test(args[i]) && args[i + 1] && !args[i + 1].startsWith('-')) unit ??= args[++i];
|
|
39
44
|
}
|
|
40
45
|
const command = args.find((a) => !a.startsWith('-')) ?? '';
|
|
41
|
-
return { unit, machine: args.includes('--json') || args.includes('--grep'), silent: SILENT_COMMANDS.has(command), actionRan: false };
|
|
46
|
+
return { unit, machine: args.includes('--json') || args.includes('--grep'), silent: SILENT_COMMANDS.has(command), answer: ANSWER_COMMANDS.has(command), actionRan: false };
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
/** commander's preAction: the action now KNOWS its unit and output mode. */
|
|
45
50
|
export function onCliAction(state: CliHandBackState, name: string, opts: Record<string, unknown>, args: unknown[]): void {
|
|
46
51
|
state.actionRan = true;
|
|
47
52
|
if (SILENT_COMMANDS.has(name)) { state.silent = true; return; }
|
|
53
|
+
state.answer = ANSWER_COMMANDS.has(name);
|
|
48
54
|
const flagged = [opts.screen, opts.flow, opts.area, opts.api].find((v) => typeof v === 'string' && v) as string | undefined;
|
|
49
55
|
state.unit = flagged ?? (typeof args?.[0] === 'string' ? args[0] : undefined);
|
|
50
56
|
// `--grep` is machine output too: callers capture it with `$(…)` (#836).
|
|
@@ -57,10 +63,11 @@ export function onCliAction(state: CliHandBackState, name: string, opts: Record<
|
|
|
57
63
|
*/
|
|
58
64
|
export function exitHandBack(state: CliHandBackState, code: number, cwd: string): { stream: 'stdout' | 'stderr'; text: string } | null {
|
|
59
65
|
if (state.silent) return null;
|
|
66
|
+
if (state.answer && code === 0) return null; // a successful `next` is the hand-back itself
|
|
60
67
|
if (!state.actionRan && code === 0) return null; // --help / --version printed what was asked
|
|
61
68
|
const unit = state.unit && SAFE_UNIT.test(state.unit) && !state.unit.split('/').includes('..')
|
|
62
69
|
&& resolveUnitCandidates(state.unit, cwd).length > 0 ? state.unit : undefined;
|
|
63
|
-
const line = handBackLine(unit);
|
|
70
|
+
const line = handBackLine(unit, sungenInvocation(findSungenRoot(cwd) ?? cwd));
|
|
64
71
|
if (code === 1) return { stream: 'stderr', text: `${line}\n` }; // after the error, one line
|
|
65
72
|
return { stream: state.machine ? 'stderr' : 'stdout', text: `\n${line}\n` };
|
|
66
73
|
}
|
|
@@ -81,10 +88,14 @@ export function attachCliHandBack(argv: string[], cwd: string): { onAction: (nam
|
|
|
81
88
|
|
|
82
89
|
const MARK: Record<NextStep['kind'], string> = { do: '→', blocked: '⛔', optional: '○', decide: '⚖' };
|
|
83
90
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
91
|
+
/**
|
|
92
|
+
* `sungen next` rendered compactly for an agent's context; commands — the step's own and those quoted in
|
|
93
|
+
* its reason (#966) — as `root` runs sungen, the way `sungen next` prints them.
|
|
94
|
+
*/
|
|
95
|
+
export function formatSteps(steps: NextStep[], max = 4, root?: string): string[] {
|
|
96
|
+
const asRun = (text: string): string => (root ? withProjectInvocationInText(text, root) : text);
|
|
86
97
|
return steps.slice(0, max).map((st) =>
|
|
87
|
-
` ${MARK[st.kind]} ${st.command}${st.kind === 'decide' ? ' (a QA decision — ask, do not run)' : ''}\n ${st.because}`);
|
|
98
|
+
` ${MARK[st.kind]} ${asRun(st.command)}${st.kind === 'decide' ? ' (a QA decision — ask, do not run)' : ''}\n ${asRun(st.because)}`);
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
/** The unit a session is on (a named one when it exists, else the nearest) and its derived state. */
|
|
@@ -95,12 +106,13 @@ export function locateUnitState(ctx: HookContext, preferred?: string): { root: s
|
|
|
95
106
|
return unit ? { root, unit, state: readUnitState(root, unit.dir, unit.name, unit.kind) } : null;
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
/** Hook core: the next steps for the session's unit (input.unit, else the nearest) as context. */
|
|
109
|
+
/** Hook core: the next steps for the session's unit (input.unit, else the nearest) as context, then what waits for a human (#954). */
|
|
99
110
|
export function run(input: HookInput, ctx: HookContext): HookResult {
|
|
100
111
|
const found = locateUnitState(ctx, typeof input.unit === 'string' ? input.unit : undefined);
|
|
101
112
|
if (!found || found.state.steps.length === 0) return NO_OP;
|
|
102
113
|
return {
|
|
103
114
|
status: 'context',
|
|
104
|
-
output: [`${handBackLine(found.unit.name)} — derived from what the project holds now:`, ...formatSteps(found.state.steps
|
|
115
|
+
output: [`${handBackLine(found.unit.name, sungenInvocation(found.root))} — derived from what the project holds now:`, ...formatSteps(found.state.steps, 4, found.root),
|
|
116
|
+
...waitingForYouLines(found.state.humanActions, found.root, found.state.humanActionsHeldBy, found.state.humanActionsHeldByCommand)].join('\n'),
|
|
105
117
|
};
|
|
106
118
|
}
|
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
* After `/clear` or a context compaction the agent has lost the thread: it re-derives the state
|
|
6
6
|
* from memory, or worse, re-runs work that is already done. This injects what `sungen next`
|
|
7
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,
|
|
8
|
+
* project already holds — stated as "do not redo" — the audit verdict, the next steps, and what waits
|
|
9
|
+
* for a human (#954).
|
|
9
10
|
*/
|
|
10
11
|
import { NO_OP, HookMeta, SungenHook } from './hook-result-contract';
|
|
11
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';
|
|
12
15
|
import { listUnits } from './sungen-project-root';
|
|
13
16
|
import type { UnitState } from '../harness/next-step';
|
|
14
17
|
|
|
@@ -40,14 +43,16 @@ export const sessionStartUnitStateHook: SungenHook = {
|
|
|
40
43
|
if (!found) return NO_OP;
|
|
41
44
|
const { root, unit, state } = found;
|
|
42
45
|
const others = listUnits(root).length - 1;
|
|
46
|
+
const sungen = sungenInvocation(root);
|
|
43
47
|
const lines = [
|
|
44
48
|
`[sungen] Unit in progress: ${unit.name} (${unit.kind})${others > 0 ? ` — the project holds ${others} other unit(s)` : ''}.`,
|
|
45
49
|
`Already done — do not redo: ${held(state)}.`,
|
|
46
50
|
state.audit ? `Audit: ${state.audit.overall}/10 [${state.audit.gateStatus}] · ${state.audit.findings.length} finding(s).` : '',
|
|
47
|
-
`Next (
|
|
48
|
-
...formatSteps(state.steps),
|
|
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),
|
|
49
54
|
input.source === 'compact' ? 'Context was compacted: re-read the unit\'s files before acting on them.' : '',
|
|
50
|
-
others > 0 ?
|
|
55
|
+
others > 0 ? `Working on another unit? Ask \`${sungen} next <unit>\` (or \`${sungen} next\` for all).` : '',
|
|
51
56
|
];
|
|
52
57
|
return { status: 'context', output: lines.filter(Boolean).join('\n') };
|
|
53
58
|
},
|
|
@@ -30,6 +30,7 @@ export const stopNextStepHook: SungenHook = {
|
|
|
30
30
|
output: [
|
|
31
31
|
'[sungen] This turn ran sungen work but ended without the next-step hand-back.',
|
|
32
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.'] : []),
|
|
33
34
|
core.output,
|
|
34
35
|
].join('\n'),
|
|
35
36
|
};
|
|
@@ -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
|
}
|
|
@@ -294,6 +294,7 @@ export class ProjectInitializer {
|
|
|
294
294
|
'specs/.auth-mobile/', // mobile auth contract = credentials (sensitive)
|
|
295
295
|
'.env.appium', // local mobile-test env = machine paths + device/team ids (.example IS committed)
|
|
296
296
|
'test-results/',
|
|
297
|
+
'test-results-free/', // free / @impl:code runs: their own outputDir, so a compiled run cannot clear their traces (#941)
|
|
297
298
|
'playwright-report/',
|
|
298
299
|
'.playwright-mcp/',
|
|
299
300
|
'.sungen/figma-cache/', // raw Figma node JSON (design IP)
|
|
@@ -102,8 +102,8 @@ declaration instead of leaving both on record.
|
|
|
102
102
|
|
|
103
103
|
## ⛔ HARD RULE — approvals and waivers are a human's, on a terminal
|
|
104
104
|
|
|
105
|
-
`sungen contract approve`, `sungen journey --waive` and `sungen journey --
|
|
106
|
-
decision and ask for a typed confirmation on a real terminal (TTY). Never run them, never fake the
|
|
105
|
+
`sungen contract approve`, `sungen journey --waive`, `sungen journey --decide` and `sungen journey --signoff` record a QA
|
|
106
|
+
decision (the sign-off is the single human gate before delivery) and ask for a typed confirmation on a real terminal (TTY). Never run them, never fake the
|
|
107
107
|
terminal (`script`, `expect`, a pty wrapper), and never edit `contracts.lock.yaml` or
|
|
108
108
|
`qa/**/decisions/` by hand. When one is due, show the exact command and stop for the human.
|
|
109
109
|
|
|
@@ -111,7 +111,10 @@ terminal (`script`, `expect`, a pty wrapper), and never edit `contracts.lock.yam
|
|
|
111
111
|
traces, write their Gherkin with `sungen contract derive --screen <name>` — deterministic, it writes
|
|
112
112
|
`features/<name>.free.feature` with every scenario tagged `@free @proposed`. Do not author those
|
|
113
113
|
steps yourself; you may name the scenarios and suggest VP-ids. A `@proposed` scenario is not
|
|
114
|
-
counted by the audit until a QA approves it (`sungen contract approve --screen <name>`).
|
|
114
|
+
counted by the audit until a QA approves it (`sungen contract approve --screen <name>`). When
|
|
115
|
+
two recorded tests claim one ID, `sungen contract derive` exits `1`, names both tests and writes
|
|
116
|
+
nothing: stop and ask the QA to give each test its own ID (its title's leading ID, or its `@tag`).
|
|
117
|
+
Never rename a test's ID — or a scenario's — yourself to get past it.
|
|
115
118
|
|
|
116
119
|
## Platform detection (do this FIRST)
|
|
117
120
|
|
|
@@ -237,3 +237,5 @@ sungen delivery [names...] # matrix (default; needs the map) → XLSX onl
|
|
|
237
237
|
Outputs: `qa/deliverables/<unit>-testcases.xlsx` (Overview + Auto + Manual + Coverage sheets) by default;
|
|
238
238
|
`--format csv` writes `<unit>-testcases.csv` instead (flat, `Level` column `item|variant`),
|
|
239
239
|
`--format both` writes both. Legacy mode writes the classic files instead.
|
|
240
|
+
|
|
241
|
+
<!-- include: waiting-for-you -->
|
|
@@ -97,3 +97,5 @@ You are an **independent QA Reviewer** — you did not author these tests. You d
|
|
|
97
97
|
5. **Trace + next** — `sungen trace --screen ${input:name}` (human-loop focus), then offer:
|
|
98
98
|
- **`/sungen-run-test ${input:name}`** (Recommended) · **`/sungen-delivery ${input:name}`** · **`/sungen-create-test ${input:name}`** · Done.
|
|
99
99
|
{{/cap}}
|
|
100
|
+
|
|
101
|
+
<!-- include: waiting-for-you -->
|
|
@@ -268,7 +268,7 @@ question already.
|
|
|
268
268
|
7. **Phase 3 — Full Run**: Run all tests. Fix only **new** failures (elements unique to `@normal`/`@low`). Max 1 attempt. Don't loop on low-priority failures.
|
|
269
269
|
8. **Phase 4 — Regression**: One final full run. No more fix loops. Then run `sungen triage --screen <name>` and render its table as the results summary: every red or flaky scenario already sits in one class (`product-candidate`, `unclassified`, `test-defect`, `environment`, `blocked-capability`, `known-defect`, `flaky`) with the rule and one evidence line. You may move an `unclassified` row into a class only with a written evidence line of your own. You may never turn a `product-candidate` into a `test-defect` by editing the `.feature` or the expected value — the Gherkin is frozen; report it as a candidate bug. For each `product-candidate` you judge to be a product bug, run `sungen defect draft --screen <name> --scenario "<title>"`, fill the record's Summary, check its Expected against `spec.md`, then add `@known-defect:DEF-NNN` to that scenario's tag line (the tag-only exception above). The severity in the draft is `proposed` — confirm it with QA (`AskUserQuestion`) before the hand-back and set `severity_source: qa`. A row you judge is not a product bug stays in the summary with your reason, and gets no record. A `bare-timeout` row (`unclassified`) is never re-run inside this command — Phase 4 was the final run; offer the re-run in Next steps.
|
|
270
270
|
8a. **Test Contract — every unit with a lock.** When `qa/<screens|flows|api>/<name>/contracts.lock.yaml` exists, check the suite still does what QA approved:
|
|
271
|
-
- **`@free` / `@impl:code` scenarios** (hand-written specs, not compiled):
|
|
271
|
+
- **`@free` / `@impl:code` scenarios** (hand-written specs, not compiled): after the Phase 4 final run, run their specs with the project's free-test config and `--trace on` (`npx playwright test -c <free-test config> --trace on`) — their trace is the only proof. That config writes to its own `outputDir: 'test-results-free'` with `trace: 'on'` and the sungen run-record reporter; never run them into `test-results/`, which the next compiled run clears (the trace is then gone and the scenario is `unproven`). If the project has no such config, no trace is admissible: tell the QA, do not write or edit the config yourself. Then `sungen contract check --screen <name> --trace`.
|
|
272
272
|
- **No free tests**: `sungen contract check --screen <name>`.
|
|
273
273
|
- **Exit 2 (hard)** — `oracle-weakened`, `target-changed`, `assertion-lost`, `lock-uncommitted`, `unproven` → report each finding to the QA in the results summary, with its rule. **Never** edit the `.feature`, an expected value, the lock or a decision to turn it green, and **never** run `sungen contract approve` — approving is a QA's decision, on a terminal. **Exit 0 with `review`** → list it for the QA: review blocks `sungen delivery` until QA re-approves. **Exit 1** → report the error. No lock → skip: every scenario is `proposed`, which never blocks.
|
|
274
274
|
9. **Phase 8 — Serial-cascade risk check** (#414): If any scenario has many steps, a skipped test may cause downstream steps to be incorrectly skipped due to the serial-cascade sensor detecting false "not reached" conditions. When you see "test skipped" messages during Phase 3–4 runs, check if the skipped scenario is a **blockers-exist** dependency in the test ledger (`sungen ledger query --screen <name>`). If the scenario had high step count and cascade fired, offer: *"Scenarios with deep steps can trigger serial-cascade skipping. Consider parallelizing this spec with `@concurrent` tags or breaking into smaller scenarios."* Let the user decide whether to refactor (do not auto-apply parallelization).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- sungen:waiting-for-you v1 -->
|
|
2
|
+
## Waiting for you — the commands only the QA runs
|
|
3
|
+
|
|
4
|
+
Right before the hand-back question, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
|
|
5
|
+
block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
|
|
6
|
+
sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
|
|
7
|
+
the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one in
|
|
8
|
+
their own terminal — in Claude Code, type `! <command>` in the prompt (a `/sungen:…` command is typed
|
|
9
|
+
as is). **Never run them yourself**, and never pipe or type a confirmation into them. When `sungen next`
|
|
10
|
+
prints no such block, say that nothing is waiting for the QA.
|
|
11
|
+
<!-- /sungen:waiting-for-you -->
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- sungen:waiting-for-you v1 -->
|
|
2
|
+
## Waiting for you — the commands only the QA runs
|
|
3
|
+
|
|
4
|
+
Right before the hand-back list, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
|
|
5
|
+
block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
|
|
6
|
+
sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
|
|
7
|
+
the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one
|
|
8
|
+
themselves, in their own terminal (a slash command is typed as is). **Never run them yourself**, and
|
|
9
|
+
never pipe or type a confirmation into them. When `sungen next` prints no such block, say that nothing
|
|
10
|
+
is waiting for the QA.
|
|
11
|
+
<!-- /sungen:waiting-for-you -->
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!-- sungen:waiting-for-you v1 -->
|
|
2
|
+
## Waiting for you — the commands only the QA runs
|
|
3
|
+
|
|
4
|
+
Right before the hand-back list, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
|
|
5
|
+
block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
|
|
6
|
+
sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
|
|
7
|
+
the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one
|
|
8
|
+
themselves, in their own terminal (a slash command is typed as is). **Never run them yourself**, and
|
|
9
|
+
never pipe or type a confirmation into them. When `sungen next` prints no such block, say that nothing
|
|
10
|
+
is waiting for the QA.
|
|
11
|
+
<!-- /sungen:waiting-for-you -->
|