@cleocode/core 2026.10.27 → 2026.11.1-canary.3
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/README.md +2 -0
- package/binaries/README.md +30 -10
- package/dist/.source-stamp.json +4 -0
- package/dist/audit/reconstruct.d.ts.map +1 -1
- package/dist/audit/reconstruct.js +3 -13
- package/dist/audit/reconstruct.js.map +1 -1
- package/dist/build-provenance.json +2 -2
- package/dist/cloud/nexus-cloud.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud.js +3 -3
- package/dist/cloud/nexus-cloud.js.map +1 -1
- package/dist/cloud/nexus-device.d.ts +1 -1
- package/dist/cloud/nexus-link.d.ts +18 -2
- package/dist/cloud/nexus-link.d.ts.map +1 -1
- package/dist/cloud/nexus-link.js +26 -6
- package/dist/cloud/nexus-link.js.map +1 -1
- package/dist/cloud/nexus-vault.d.ts.map +1 -1
- package/dist/cloud/nexus-vault.js +3 -9
- package/dist/cloud/nexus-vault.js.map +1 -1
- package/dist/decide/sites/registry.d.ts +40 -0
- package/dist/decide/sites/registry.d.ts.map +1 -1
- package/dist/decide/sites/registry.js +38 -0
- package/dist/decide/sites/registry.js.map +1 -1
- package/dist/docs/adr-allocator.d.ts +3 -3
- package/dist/docs/adr-allocator.d.ts.map +1 -1
- package/dist/docs/adr-allocator.js +8 -5
- package/dist/docs/adr-allocator.js.map +1 -1
- package/dist/docs/blob-consolidation.d.ts.map +1 -1
- package/dist/docs/blob-consolidation.js +3 -2
- package/dist/docs/blob-consolidation.js.map +1 -1
- package/dist/docs/derive-links.d.ts +12 -0
- package/dist/docs/derive-links.d.ts.map +1 -1
- package/dist/docs/derive-links.js +19 -0
- package/dist/docs/derive-links.js.map +1 -1
- package/dist/docs/doc-name-rule.d.ts +105 -0
- package/dist/docs/doc-name-rule.d.ts.map +1 -0
- package/dist/docs/doc-name-rule.js +212 -0
- package/dist/docs/doc-name-rule.js.map +1 -0
- package/dist/docs/docs-inconsistency-detector.d.ts.map +1 -1
- package/dist/docs/docs-inconsistency-detector.js +4 -3
- package/dist/docs/docs-inconsistency-detector.js.map +1 -1
- package/dist/docs/docs-ops.d.ts +27 -5
- package/dist/docs/docs-ops.d.ts.map +1 -1
- package/dist/docs/docs-ops.js +149 -17
- package/dist/docs/docs-ops.js.map +1 -1
- package/dist/docs/docs-read-model.d.ts +45 -15
- package/dist/docs/docs-read-model.d.ts.map +1 -1
- package/dist/docs/docs-read-model.js +22 -102
- package/dist/docs/docs-read-model.js.map +1 -1
- package/dist/docs/docs-update.d.ts.map +1 -1
- package/dist/docs/docs-update.js +8 -2
- package/dist/docs/docs-update.js.map +1 -1
- package/dist/docs/doctor.d.ts +71 -4
- package/dist/docs/doctor.d.ts.map +1 -1
- package/dist/docs/doctor.js +324 -23
- package/dist/docs/doctor.js.map +1 -1
- package/dist/docs/duplicate-check.d.ts +138 -0
- package/dist/docs/duplicate-check.d.ts.map +1 -0
- package/dist/docs/duplicate-check.js +286 -0
- package/dist/docs/duplicate-check.js.map +1 -0
- package/dist/docs/fetch-result.d.ts.map +1 -1
- package/dist/docs/fetch-result.js +27 -0
- package/dist/docs/fetch-result.js.map +1 -1
- package/dist/docs/import/scanner.d.ts +2 -0
- package/dist/docs/import/scanner.d.ts.map +1 -1
- package/dist/docs/import/scanner.js +3 -1
- package/dist/docs/import/scanner.js.map +1 -1
- package/dist/docs/lineage.d.ts +66 -0
- package/dist/docs/lineage.d.ts.map +1 -0
- package/dist/docs/lineage.js +190 -0
- package/dist/docs/lineage.js.map +1 -0
- package/dist/docs/modernize/apply.d.ts +139 -0
- package/dist/docs/modernize/apply.d.ts.map +1 -0
- package/dist/docs/modernize/apply.js +760 -0
- package/dist/docs/modernize/apply.js.map +1 -0
- package/dist/docs/modernize/guard.d.ts +92 -0
- package/dist/docs/modernize/guard.d.ts.map +1 -0
- package/dist/docs/modernize/guard.js +214 -0
- package/dist/docs/modernize/guard.js.map +1 -0
- package/dist/docs/modernize/index.d.ts +68 -0
- package/dist/docs/modernize/index.d.ts.map +1 -0
- package/dist/docs/modernize/index.js +97 -0
- package/dist/docs/modernize/index.js.map +1 -0
- package/dist/docs/modernize/judge.d.ts +85 -0
- package/dist/docs/modernize/judge.d.ts.map +1 -0
- package/dist/docs/modernize/judge.js +186 -0
- package/dist/docs/modernize/judge.js.map +1 -0
- package/dist/docs/modernize/plan.d.ts +77 -0
- package/dist/docs/modernize/plan.d.ts.map +1 -0
- package/dist/docs/modernize/plan.js +510 -0
- package/dist/docs/modernize/plan.js.map +1 -0
- package/dist/docs/modernize/restore.d.ts +41 -0
- package/dist/docs/modernize/restore.d.ts.map +1 -0
- package/dist/docs/modernize/restore.js +103 -0
- package/dist/docs/modernize/restore.js.map +1 -0
- package/dist/docs/modernize/rules.d.ts +197 -0
- package/dist/docs/modernize/rules.d.ts.map +1 -0
- package/dist/docs/modernize/rules.js +510 -0
- package/dist/docs/modernize/rules.js.map +1 -0
- package/dist/docs/modernize/store.d.ts +64 -0
- package/dist/docs/modernize/store.d.ts.map +1 -0
- package/dist/docs/modernize/store.js +390 -0
- package/dist/docs/modernize/store.js.map +1 -0
- package/dist/docs/publications-store.d.ts +16 -2
- package/dist/docs/publications-store.d.ts.map +1 -1
- package/dist/docs/publications-store.js +23 -2
- package/dist/docs/publications-store.js.map +1 -1
- package/dist/docs/publish-pr.d.ts.map +1 -1
- package/dist/docs/publish-pr.js +12 -1
- package/dist/docs/publish-pr.js.map +1 -1
- package/dist/docs/rot.d.ts +94 -0
- package/dist/docs/rot.d.ts.map +1 -0
- package/dist/docs/rot.js +298 -0
- package/dist/docs/rot.js.map +1 -0
- package/dist/docs/similarity-check.d.ts +2 -0
- package/dist/docs/similarity-check.d.ts.map +1 -1
- package/dist/docs/similarity-check.js +6 -49
- package/dist/docs/similarity-check.js.map +1 -1
- package/dist/docs/slug-rename.d.ts +84 -0
- package/dist/docs/slug-rename.d.ts.map +1 -0
- package/dist/docs/slug-rename.js +166 -0
- package/dist/docs/slug-rename.js.map +1 -0
- package/dist/docs/slug-similarity.d.ts +24 -0
- package/dist/docs/slug-similarity.d.ts.map +1 -0
- package/dist/docs/slug-similarity.js +63 -0
- package/dist/docs/slug-similarity.js.map +1 -0
- package/dist/docs/wikilinks.d.ts +20 -4
- package/dist/docs/wikilinks.d.ts.map +1 -1
- package/dist/docs/wikilinks.js +52 -7
- package/dist/docs/wikilinks.js.map +1 -1
- package/dist/docs/writer-registry.d.ts.map +1 -1
- package/dist/docs/writer-registry.js +33 -0
- package/dist/docs/writer-registry.js.map +1 -1
- package/dist/doctor/type-matrix-repair.d.ts +194 -0
- package/dist/doctor/type-matrix-repair.d.ts.map +1 -0
- package/dist/doctor/type-matrix-repair.js +662 -0
- package/dist/doctor/type-matrix-repair.js.map +1 -0
- package/dist/gateway-client/generated/index.d.ts +2 -2
- package/dist/gateway-client/generated/index.d.ts.map +1 -1
- package/dist/gateway-client/generated/index.js +1 -1
- package/dist/gateway-client/generated/index.js.map +1 -1
- package/dist/gateway-client/generated/namespaces.gen.d.ts +5 -0
- package/dist/gateway-client/generated/namespaces.gen.d.ts.map +1 -1
- package/dist/gateway-client/generated/namespaces.gen.js +6 -1
- package/dist/gateway-client/generated/namespaces.gen.js.map +1 -1
- package/dist/gateway-client/generated/sdk.gen.d.ts +21 -1
- package/dist/gateway-client/generated/sdk.gen.d.ts.map +1 -1
- package/dist/gateway-client/generated/sdk.gen.js +55 -0
- package/dist/gateway-client/generated/sdk.gen.js.map +1 -1
- package/dist/gateway-client/generated/types.gen.d.ts +222 -0
- package/dist/gateway-client/generated/types.gen.d.ts.map +1 -1
- package/dist/gc/gc-subsystem.d.ts +4 -0
- package/dist/gc/gc-subsystem.d.ts.map +1 -1
- package/dist/gc/gc-subsystem.js +16 -0
- package/dist/gc/gc-subsystem.js.map +1 -1
- package/dist/git/work-tree.d.ts +48 -0
- package/dist/git/work-tree.d.ts.map +1 -1
- package/dist/git/work-tree.js +63 -1
- package/dist/git/work-tree.js.map +1 -1
- package/dist/hooks/handlers/session-hooks.d.ts +5 -4
- package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/session-hooks.js +5 -21
- package/dist/hooks/handlers/session-hooks.js.map +1 -1
- package/dist/internal.d.ts +5 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -1
- package/dist/internal.js.map +1 -1
- package/dist/memory/brain-doctor.d.ts.map +1 -1
- package/dist/memory/brain-doctor.js +6 -1
- package/dist/memory/brain-doctor.js.map +1 -1
- package/dist/memory/engine-compat.d.ts.map +1 -1
- package/dist/memory/engine-compat.js +6 -0
- package/dist/memory/engine-compat.js.map +1 -1
- package/dist/nexus/analyze-orchestrator.d.ts +24 -0
- package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
- package/dist/nexus/analyze-orchestrator.js +43 -5
- package/dist/nexus/analyze-orchestrator.js.map +1 -1
- package/dist/nexus/user-profile.d.ts +2 -1
- package/dist/nexus/user-profile.d.ts.map +1 -1
- package/dist/nexus/user-profile.js +13 -5
- package/dist/nexus/user-profile.js.map +1 -1
- package/dist/orchestrate/admission.d.ts +8 -0
- package/dist/orchestrate/admission.d.ts.map +1 -1
- package/dist/orchestrate/admission.js +3 -1
- package/dist/orchestrate/admission.js.map +1 -1
- package/dist/orchestrate/query-ops.d.ts.map +1 -1
- package/dist/orchestrate/query-ops.js +15 -4
- package/dist/orchestrate/query-ops.js.map +1 -1
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +43 -2
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestration/index.d.ts +6 -0
- package/dist/orchestration/index.d.ts.map +1 -1
- package/dist/orchestration/index.js +3 -0
- package/dist/orchestration/index.js.map +1 -1
- package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
- package/dist/orchestration/spawn-prompt.js +3 -1
- package/dist/orchestration/spawn-prompt.js.map +1 -1
- package/dist/paths.d.ts +43 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +51 -1
- package/dist/paths.js.map +1 -1
- package/dist/project-lifecycle.d.ts.map +1 -1
- package/dist/project-lifecycle.js +31 -0
- package/dist/project-lifecycle.js.map +1 -1
- package/dist/release/authorization.d.ts +156 -0
- package/dist/release/authorization.d.ts.map +1 -0
- package/dist/release/authorization.js +460 -0
- package/dist/release/authorization.js.map +1 -0
- package/dist/release/ci-evidence.d.ts +55 -4
- package/dist/release/ci-evidence.d.ts.map +1 -1
- package/dist/release/ci-evidence.js +251 -22
- package/dist/release/ci-evidence.js.map +1 -1
- package/dist/release/ci-run-evidence.d.ts +107 -0
- package/dist/release/ci-run-evidence.d.ts.map +1 -0
- package/dist/release/ci-run-evidence.js +234 -0
- package/dist/release/ci-run-evidence.js.map +1 -0
- package/dist/release/cut.d.ts +231 -0
- package/dist/release/cut.d.ts.map +1 -0
- package/dist/release/cut.js +775 -0
- package/dist/release/cut.js.map +1 -0
- package/dist/release/deploy-evidence.d.ts +173 -0
- package/dist/release/deploy-evidence.d.ts.map +1 -0
- package/dist/release/deploy-evidence.js +381 -0
- package/dist/release/deploy-evidence.js.map +1 -0
- package/dist/release/engine-ops.d.ts.map +1 -1
- package/dist/release/engine-ops.js +10 -4
- package/dist/release/engine-ops.js.map +1 -1
- package/dist/release/index.d.ts +3 -0
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +2 -0
- package/dist/release/index.js.map +1 -1
- package/dist/release/invariants/archive-reason-invariant.d.ts.map +1 -1
- package/dist/release/invariants/archive-reason-invariant.js +4 -1
- package/dist/release/invariants/archive-reason-invariant.js.map +1 -1
- package/dist/release/open.d.ts.map +1 -1
- package/dist/release/open.js +2 -6
- package/dist/release/open.js.map +1 -1
- package/dist/release/plan.d.ts +34 -2
- package/dist/release/plan.d.ts.map +1 -1
- package/dist/release/plan.js +30 -6
- package/dist/release/plan.js.map +1 -1
- package/dist/release/preflight-skip.d.ts +4 -19
- package/dist/release/preflight-skip.d.ts.map +1 -1
- package/dist/release/preflight-skip.js +5 -110
- package/dist/release/preflight-skip.js.map +1 -1
- package/dist/release/reconcile-latest.d.ts +29 -0
- package/dist/release/reconcile-latest.d.ts.map +1 -0
- package/dist/release/reconcile-latest.js +71 -0
- package/dist/release/reconcile-latest.js.map +1 -0
- package/dist/release/reconcile.d.ts +3 -1
- package/dist/release/reconcile.d.ts.map +1 -1
- package/dist/release/reconcile.js +18 -6
- package/dist/release/reconcile.js.map +1 -1
- package/dist/release/release-published.d.ts +27 -0
- package/dist/release/release-published.d.ts.map +1 -0
- package/dist/release/release-published.js +35 -0
- package/dist/release/release-published.js.map +1 -0
- package/dist/release/tty-confirm.d.ts +23 -0
- package/dist/release/tty-confirm.d.ts.map +1 -0
- package/dist/release/tty-confirm.js +50 -0
- package/dist/release/tty-confirm.js.map +1 -0
- package/dist/remote/index.js +1 -1
- package/dist/remote/index.js.map +1 -1
- package/dist/resources/admission-ledger.d.ts +103 -1
- package/dist/resources/admission-ledger.d.ts.map +1 -1
- package/dist/resources/admission-ledger.js +200 -17
- package/dist/resources/admission-ledger.js.map +1 -1
- package/dist/resources/agent-lease.d.ts +82 -0
- package/dist/resources/agent-lease.d.ts.map +1 -0
- package/dist/resources/agent-lease.js +167 -0
- package/dist/resources/agent-lease.js.map +1 -0
- package/dist/resources/governor.d.ts +27 -1
- package/dist/resources/governor.d.ts.map +1 -1
- package/dist/resources/governor.js +88 -4
- package/dist/resources/governor.js.map +1 -1
- package/dist/resources/hook-footprint.d.ts +13 -1
- package/dist/resources/hook-footprint.d.ts.map +1 -1
- package/dist/resources/hook-footprint.js +33 -7
- package/dist/resources/hook-footprint.js.map +1 -1
- package/dist/resources/run-governed.d.ts +25 -0
- package/dist/resources/run-governed.d.ts.map +1 -1
- package/dist/resources/run-governed.js +44 -3
- package/dist/resources/run-governed.js.map +1 -1
- package/dist/sagas/reconcile.d.ts.map +1 -1
- package/dist/sagas/reconcile.js +11 -0
- package/dist/sagas/reconcile.js.map +1 -1
- package/dist/scaffold/ensure-dirs.d.ts.map +1 -1
- package/dist/scaffold/ensure-dirs.js +8 -6
- package/dist/scaffold/ensure-dirs.js.map +1 -1
- package/dist/security/override-cap-setting.d.ts +132 -0
- package/dist/security/override-cap-setting.d.ts.map +1 -1
- package/dist/security/override-cap-setting.js +88 -10
- package/dist/security/override-cap-setting.js.map +1 -1
- package/dist/security/owner-override-authority.d.ts.map +1 -1
- package/dist/security/owner-override-authority.js +5 -1
- package/dist/security/owner-override-authority.js.map +1 -1
- package/dist/selfimprove/draft-pr.d.ts.map +1 -1
- package/dist/selfimprove/draft-pr.js +4 -1
- package/dist/selfimprove/draft-pr.js.map +1 -1
- package/dist/session/engine-ops.d.ts.map +1 -1
- package/dist/session/engine-ops.js +4 -16
- package/dist/session/engine-ops.js.map +1 -1
- package/dist/sessions/briefing.d.ts +6 -0
- package/dist/sessions/briefing.d.ts.map +1 -1
- package/dist/sessions/briefing.js +34 -0
- package/dist/sessions/briefing.js.map +1 -1
- package/dist/sessions/session-end-snapshot-entry.js +2 -2
- package/dist/sessions/session-end-snapshot-entry.js.map +1 -1
- package/dist/sessions/session-end-snapshot.js +4 -4
- package/dist/sessions/session-end-snapshot.js.map +1 -1
- package/dist/skills/injection/token.d.ts.map +1 -1
- package/dist/skills/injection/token.js +3 -6
- package/dist/skills/injection/token.js.map +1 -1
- package/dist/skills/orchestrator/spawn.d.ts.map +1 -1
- package/dist/skills/orchestrator/spawn.js +3 -4
- package/dist/skills/orchestrator/spawn.js.map +1 -1
- package/dist/skills/propose-patch.d.ts.map +1 -1
- package/dist/skills/propose-patch.js +4 -1
- package/dist/skills/propose-patch.js.map +1 -1
- package/dist/spawn/branch-integration.d.ts.map +1 -1
- package/dist/spawn/branch-integration.js +5 -2
- package/dist/spawn/branch-integration.js.map +1 -1
- package/dist/store/attachment-repair.d.ts.map +1 -1
- package/dist/store/attachment-repair.js +5 -4
- package/dist/store/attachment-repair.js.map +1 -1
- package/dist/store/attachment-store.d.ts +6 -0
- package/dist/store/attachment-store.d.ts.map +1 -1
- package/dist/store/attachment-store.js +19 -2
- package/dist/store/attachment-store.js.map +1 -1
- package/dist/store/blob-ops.d.ts +1 -1
- package/dist/store/blob-ops.d.ts.map +1 -1
- package/dist/store/blob-ops.js +7 -3
- package/dist/store/blob-ops.js.map +1 -1
- package/dist/store/conduit-doc-history.d.ts +15 -1
- package/dist/store/conduit-doc-history.d.ts.map +1 -1
- package/dist/store/conduit-doc-history.js +16 -10
- package/dist/store/conduit-doc-history.js.map +1 -1
- package/dist/store/db-helpers.d.ts +29 -0
- package/dist/store/db-helpers.d.ts.map +1 -1
- package/dist/store/db-helpers.js +89 -1
- package/dist/store/db-helpers.js.map +1 -1
- package/dist/store/decision-adr-links.d.ts.map +1 -1
- package/dist/store/decision-adr-links.js +5 -2
- package/dist/store/decision-adr-links.js.map +1 -1
- package/dist/store/git-checkpoint.d.ts +11 -1
- package/dist/store/git-checkpoint.d.ts.map +1 -1
- package/dist/store/git-checkpoint.js +14 -3
- package/dist/store/git-checkpoint.js.map +1 -1
- package/dist/store/llmtxt-blob-adapter.d.ts.map +1 -1
- package/dist/store/llmtxt-blob-adapter.js +4 -1
- package/dist/store/llmtxt-blob-adapter.js.map +1 -1
- package/dist/store/schema/attachments.d.ts +7 -5
- package/dist/store/schema/attachments.d.ts.map +1 -1
- package/dist/store/schema/attachments.js +5 -2
- package/dist/store/schema/attachments.js.map +1 -1
- package/dist/store/session-store.d.ts.map +1 -1
- package/dist/store/session-store.js +6 -0
- package/dist/store/session-store.js.map +1 -1
- package/dist/store/sqlite-backup.d.ts +6 -1
- package/dist/store/sqlite-backup.d.ts.map +1 -1
- package/dist/store/sqlite-backup.js +9 -5
- package/dist/store/sqlite-backup.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +63 -36
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/system/backup.d.ts +29 -0
- package/dist/system/backup.d.ts.map +1 -1
- package/dist/system/backup.js +240 -37
- package/dist/system/backup.js.map +1 -1
- package/dist/system/dependencies.d.ts +22 -0
- package/dist/system/dependencies.d.ts.map +1 -1
- package/dist/system/dependencies.js +49 -2
- package/dist/system/dependencies.js.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +23 -1
- package/dist/system/health.js.map +1 -1
- package/dist/task-work/claims.d.ts.map +1 -1
- package/dist/task-work/claims.js +14 -0
- package/dist/task-work/claims.js.map +1 -1
- package/dist/task-work/index.d.ts.map +1 -1
- package/dist/task-work/index.js +22 -0
- package/dist/task-work/index.js.map +1 -1
- package/dist/tasks/ac-coverage-gate.d.ts +27 -0
- package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
- package/dist/tasks/ac-coverage-gate.js +63 -28
- package/dist/tasks/ac-coverage-gate.js.map +1 -1
- package/dist/tasks/affected-packages.d.ts +26 -30
- package/dist/tasks/affected-packages.d.ts.map +1 -1
- package/dist/tasks/affected-packages.js +27 -50
- package/dist/tasks/affected-packages.js.map +1 -1
- package/dist/tasks/affected-scope.d.ts +13 -3
- package/dist/tasks/affected-scope.d.ts.map +1 -1
- package/dist/tasks/affected-scope.js +29 -11
- package/dist/tasks/affected-scope.js.map +1 -1
- package/dist/tasks/change-set.d.ts.map +1 -1
- package/dist/tasks/change-set.js +39 -20
- package/dist/tasks/change-set.js.map +1 -1
- package/dist/tasks/command-gate-cmd.d.ts +33 -0
- package/dist/tasks/command-gate-cmd.d.ts.map +1 -0
- package/dist/tasks/command-gate-cmd.js +45 -0
- package/dist/tasks/command-gate-cmd.js.map +1 -0
- package/dist/tasks/complete-ci.d.ts +9 -0
- package/dist/tasks/complete-ci.d.ts.map +1 -1
- package/dist/tasks/complete-ci.js +21 -4
- package/dist/tasks/complete-ci.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +14 -0
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/component-pr.d.ts +37 -0
- package/dist/tasks/component-pr.d.ts.map +1 -1
- package/dist/tasks/component-pr.js +106 -14
- package/dist/tasks/component-pr.js.map +1 -1
- package/dist/tasks/done-plan.d.ts +14 -1
- package/dist/tasks/done-plan.d.ts.map +1 -1
- package/dist/tasks/done-plan.js +125 -15
- package/dist/tasks/done-plan.js.map +1 -1
- package/dist/tasks/done-record.d.ts.map +1 -1
- package/dist/tasks/done-record.js +4 -0
- package/dist/tasks/done-record.js.map +1 -1
- package/dist/tasks/engine-converters.d.ts.map +1 -1
- package/dist/tasks/engine-converters.js +2 -0
- package/dist/tasks/engine-converters.js.map +1 -1
- package/dist/tasks/evidence-tree.d.ts +28 -1
- package/dist/tasks/evidence-tree.d.ts.map +1 -1
- package/dist/tasks/evidence-tree.js +66 -2
- package/dist/tasks/evidence-tree.js.map +1 -1
- package/dist/tasks/evidence.d.ts +39 -27
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +382 -188
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/gate-notes.d.ts +17 -0
- package/dist/tasks/gate-notes.d.ts.map +1 -1
- package/dist/tasks/gate-notes.js.map +1 -1
- package/dist/tasks/gate-preview.d.ts +7 -1
- package/dist/tasks/gate-preview.d.ts.map +1 -1
- package/dist/tasks/gate-preview.js +30 -4
- package/dist/tasks/gate-preview.js.map +1 -1
- package/dist/tasks/gate-runner.d.ts +42 -0
- package/dist/tasks/gate-runner.d.ts.map +1 -1
- package/dist/tasks/gate-runner.js +234 -94
- package/dist/tasks/gate-runner.js.map +1 -1
- package/dist/tasks/manifest-scope.d.ts +115 -0
- package/dist/tasks/manifest-scope.d.ts.map +1 -0
- package/dist/tasks/manifest-scope.js +352 -0
- package/dist/tasks/manifest-scope.js.map +1 -0
- package/dist/tasks/merge-close.d.ts +376 -0
- package/dist/tasks/merge-close.d.ts.map +1 -0
- package/dist/tasks/merge-close.js +1497 -0
- package/dist/tasks/merge-close.js.map +1 -0
- package/dist/tasks/qa-run-binding.d.ts +5 -0
- package/dist/tasks/qa-run-binding.d.ts.map +1 -1
- package/dist/tasks/qa-run-binding.js +6 -1
- package/dist/tasks/qa-run-binding.js.map +1 -1
- package/dist/tasks/req.d.ts.map +1 -1
- package/dist/tasks/req.js +29 -1
- package/dist/tasks/req.js.map +1 -1
- package/dist/tasks/review-verdict.d.ts +159 -0
- package/dist/tasks/review-verdict.d.ts.map +1 -0
- package/dist/tasks/review-verdict.js +442 -0
- package/dist/tasks/review-verdict.js.map +1 -0
- package/dist/tasks/task-reparent.d.ts.map +1 -1
- package/dist/tasks/task-reparent.js +22 -3
- package/dist/tasks/task-reparent.js.map +1 -1
- package/dist/tasks/test-report-counts.d.ts +274 -0
- package/dist/tasks/test-report-counts.d.ts.map +1 -0
- package/dist/tasks/test-report-counts.js +746 -0
- package/dist/tasks/test-report-counts.js.map +1 -0
- package/dist/tasks/test-run-binding.d.ts +20 -45
- package/dist/tasks/test-run-binding.d.ts.map +1 -1
- package/dist/tasks/test-run-binding.js +34 -119
- package/dist/tasks/test-run-binding.js.map +1 -1
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +42 -0
- package/dist/tasks/update.js.map +1 -1
- package/dist/tasks/verification-policy.d.ts +12 -0
- package/dist/tasks/verification-policy.d.ts.map +1 -1
- package/dist/tasks/verification-policy.js +13 -0
- package/dist/tasks/verification-policy.js.map +1 -1
- package/dist/tasks/workspace-resolution.d.ts +225 -0
- package/dist/tasks/workspace-resolution.d.ts.map +1 -0
- package/dist/tasks/workspace-resolution.js +497 -0
- package/dist/tasks/workspace-resolution.js.map +1 -0
- package/dist/validation/doctor/checks.d.ts +20 -0
- package/dist/validation/doctor/checks.d.ts.map +1 -1
- package/dist/validation/doctor/checks.js +112 -0
- package/dist/validation/doctor/checks.js.map +1 -1
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +37 -3
- package/dist/validation/engine-ops.js.map +1 -1
- package/dist/validation/validate-ops.d.ts +4 -0
- package/dist/validation/validate-ops.d.ts.map +1 -1
- package/dist/validation/validate-ops.js +79 -2
- package/dist/validation/validate-ops.js.map +1 -1
- package/dist/worktree/list.d.ts +4 -21
- package/dist/worktree/list.d.ts.map +1 -1
- package/dist/worktree/list.js +14 -44
- package/dist/worktree/list.js.map +1 -1
- package/dist/worktree/merged-cleanup.d.ts +63 -0
- package/dist/worktree/merged-cleanup.d.ts.map +1 -0
- package/dist/worktree/merged-cleanup.js +571 -0
- package/dist/worktree/merged-cleanup.js.map +1 -0
- package/dist/worktree/prune.d.ts +64 -2
- package/dist/worktree/prune.d.ts.map +1 -1
- package/dist/worktree/prune.js +151 -6
- package/dist/worktree/prune.js.map +1 -1
- package/dist/worktree/sentinel-index.d.ts +14 -0
- package/dist/worktree/sentinel-index.d.ts.map +1 -1
- package/dist/worktree/sentinel-index.js +17 -0
- package/dist/worktree/sentinel-index.js.map +1 -1
- package/dist/worktree/worktree-adopt.d.ts +1 -13
- package/dist/worktree/worktree-adopt.d.ts.map +1 -1
- package/dist/worktree/worktree-adopt.js +2 -17
- package/dist/worktree/worktree-adopt.js.map +1 -1
- package/package.json +12 -12
- package/schemas/project-context.schema.json +33 -0
- package/templates/CLEO-INJECTION.md +6 -16
- package/templates/CLEO-REFERENCE.md +27 -4
- package/templates/git-hooks/legacy-hashes.json +2 -1
- package/templates/git-hooks/pre-commit +43 -11
- package/templates/workflows/release-prepare.yml.tmpl +9 -88
|
@@ -30,7 +30,7 @@ import { constants, mkdirSync, readFileSync, realpathSync, renameSync, writeFile
|
|
|
30
30
|
import { lstat, open, readFile, realpath, stat } from 'node:fs/promises';
|
|
31
31
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
32
32
|
import { isDeepStrictEqual } from 'node:util';
|
|
33
|
-
import { acceptanceGateResultSchema, acceptanceGateSchema,
|
|
33
|
+
import { acceptanceGateResultSchema, acceptanceGateSchema, testCountSummarySchema, } from '@cleocode/contracts/acceptance-gate-schema.js';
|
|
34
34
|
import { findOnPath } from '@cleocode/paths';
|
|
35
35
|
import { resolveOriginDefault } from '../git/base-ref.js';
|
|
36
36
|
import { discoveryEnv } from '../git/work-tree.js';
|
|
@@ -42,11 +42,13 @@ import { captureWrapped } from '../resources/spawn-wrapper.js';
|
|
|
42
42
|
import { createAttachmentStore } from '../store/attachment-store.js';
|
|
43
43
|
import { registerTeardownAbort } from '../teardown-signal.js';
|
|
44
44
|
import { acItemToText, acTextHash } from './ac-table.js';
|
|
45
|
+
import { commandGateCmdProblem } from './command-gate-cmd.js';
|
|
45
46
|
import { splitCommandLine } from './command-line.js';
|
|
46
47
|
import { resolveCanonicalProjectRoot } from './evidence.js';
|
|
47
|
-
import { resolveEvidenceTree } from './evidence-tree.js';
|
|
48
|
-
import { buildGateCacheEntryBody, captureGateCacheState, describeGateCacheMiss, evidenceCacheKeyPath, gateCacheEntryPath, readGateCacheEntry, sealGateCacheEntry, } from './gate-result-cache.js';
|
|
48
|
+
import { resolveEvidenceRepository, resolveEvidenceTree } from './evidence-tree.js';
|
|
49
|
+
import { buildGateCacheEntryBody, captureGateCacheState, describeGateCacheMiss, evidenceCacheKeyPath, gateCacheEntryPath, isCacheableGate, readGateCacheEntry, sealGateCacheEntry, } from './gate-result-cache.js';
|
|
49
50
|
import { planHeavyToolEnv, vitestWorkerCeiling } from './heavy-tool-env.js';
|
|
51
|
+
import { readParsedTestReport, readTestReport, TEST_REPORT_FORMATS, } from './test-report-counts.js';
|
|
50
52
|
import { resolveSpawnTimeoutMs } from './tool-cache.js';
|
|
51
53
|
import { acquireGlobalSlot } from './tool-semaphore.js';
|
|
52
54
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
@@ -183,6 +185,85 @@ function loadEvidenceCacheKey() {
|
|
|
183
185
|
return null;
|
|
184
186
|
}
|
|
185
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Read (never create) the per-machine evidence cache key, for a read-only
|
|
190
|
+
* probe (T14138). `null` when it does not exist yet or cannot be read.
|
|
191
|
+
*/
|
|
192
|
+
function readEvidenceCacheKey() {
|
|
193
|
+
try {
|
|
194
|
+
const hex = readFileSync(evidenceCacheKeyPath(), 'utf-8').trim();
|
|
195
|
+
return /^[0-9a-f]{64}$/.test(hex) ? Buffer.from(hex, 'hex') : null;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Whether the evidence cache holds a sealed pass for one typed gate in the
|
|
203
|
+
* tree and environment the next evidence write would use (T14138), so
|
|
204
|
+
* `cleo done --plan` can report a pass `cleo verify --run` cached instead of
|
|
205
|
+
* calling it not-run. Read-only: it runs no gate, writes no entry and never
|
|
206
|
+
* creates the machine key. The inputs digest is computed as
|
|
207
|
+
* {@link runTaskGates} computes it, so a hit here is a hit for the write.
|
|
208
|
+
*
|
|
209
|
+
* @param task - Task that owns the gate.
|
|
210
|
+
* @param gate - The typed gate.
|
|
211
|
+
* @param execution - Admitted lifetime whose project root scopes the probe.
|
|
212
|
+
* @param env - Environment the gate would launch with.
|
|
213
|
+
* @returns A hit with its time, a miss naming the key part that moved (when a
|
|
214
|
+
* recent entry explains it), or why the cache cannot be consulted.
|
|
215
|
+
* @task T14138
|
|
216
|
+
*/
|
|
217
|
+
export async function probeTypedGateCache(task, gate, execution, env = process.env) {
|
|
218
|
+
if (!TOOL_GATE_KINDS.has(gate.kind) || !isCacheableGate(gate))
|
|
219
|
+
return { status: 'unavailable', reason: `a ${gate.kind} gate is never cached` };
|
|
220
|
+
const root = resolve(execution.identity.projectRoot);
|
|
221
|
+
let gateRoot;
|
|
222
|
+
try {
|
|
223
|
+
gateRoot = gateTreeFor(gate, resolveTypedGateRoot(root, undefined, undefined, task.id), root);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
return {
|
|
227
|
+
status: 'unavailable',
|
|
228
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const state = await captureGateCacheState(gateRoot);
|
|
232
|
+
if (state === null)
|
|
233
|
+
return { status: 'unavailable', reason: 'the gate tree is not a git checkout' };
|
|
234
|
+
const key = readEvidenceCacheKey();
|
|
235
|
+
if (key === null)
|
|
236
|
+
return {
|
|
237
|
+
status: 'unavailable',
|
|
238
|
+
reason: `no readable machine key at ${evidenceCacheKeyPath()}`,
|
|
239
|
+
};
|
|
240
|
+
const { invocation, refusal } = resolveInvocation(gate, gateRoot, { ...env });
|
|
241
|
+
if (refusal !== undefined)
|
|
242
|
+
return { status: 'unavailable', reason: refusal };
|
|
243
|
+
let artifacts;
|
|
244
|
+
try {
|
|
245
|
+
artifacts = await snapshotGateInputs(task, gate, invocation, execution, gateRoot);
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
return {
|
|
249
|
+
status: 'unavailable',
|
|
250
|
+
reason: `its inputs could not be captured: ${error instanceof Error ? error.message : String(error)}`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const inputsHash = gateInputsHash(invocation, artifacts);
|
|
254
|
+
const lookup = readGateCacheEntry(root, gate, state, inputsHash, key);
|
|
255
|
+
if (lookup.status === 'hit')
|
|
256
|
+
return { status: 'hit', cachedAt: lookup.createdAt };
|
|
257
|
+
if (lookup.status === 'invalid')
|
|
258
|
+
return { status: 'unavailable', reason: lookup.reason };
|
|
259
|
+
return {
|
|
260
|
+
status: 'miss',
|
|
261
|
+
why: describeGateCacheMiss(root, gate, state, inputsHash, {
|
|
262
|
+
environmentHash: invocation?.environmentHash ?? null,
|
|
263
|
+
artifacts,
|
|
264
|
+
}),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
186
267
|
/**
|
|
187
268
|
* Seal and store a pass this runner EXECUTED itself. Module-private for the same
|
|
188
269
|
* reason as {@link loadEvidenceCacheKey}: only an observed execution is cached.
|
|
@@ -240,7 +321,8 @@ export async function captureGateInputsHash(task, gate, execution, env = process
|
|
|
240
321
|
* @task T13693
|
|
241
322
|
*/
|
|
242
323
|
export async function captureGateInputs(task, gate, execution, env = process.env) {
|
|
243
|
-
const
|
|
324
|
+
const storeRoot = resolve(execution.identity.projectRoot);
|
|
325
|
+
const tree = gateTreeFor(gate, resolveTypedGateRoot(storeRoot, undefined, undefined, task.id), storeRoot);
|
|
244
326
|
const invocation = executableInvocation(gate, tree, { ...env });
|
|
245
327
|
const artifacts = await snapshotGateInputs(task, gate, invocation, execution, tree);
|
|
246
328
|
return {
|
|
@@ -305,6 +387,28 @@ env = process.env, taskId = null) {
|
|
|
305
387
|
const tree = real(resolveEvidenceTree(projectRoot, taskId, cwd, env, ofThisProject).root);
|
|
306
388
|
return tree === root ? projectRoot : tree;
|
|
307
389
|
}
|
|
390
|
+
/**
|
|
391
|
+
* The tree ONE typed gate runs in, captures its inputs in and is revalidated
|
|
392
|
+
* in: the declared evidence repository its `repo` names (T14078), else
|
|
393
|
+
* `tree` ({@link resolveTypedGateRoot}).
|
|
394
|
+
*
|
|
395
|
+
* @param gate - The typed gate.
|
|
396
|
+
* @param tree - The task's typed-gate tree.
|
|
397
|
+
* @param storeRoot - CLEO store root, whose project context declares repositories.
|
|
398
|
+
* @returns The checkout root the gate uses.
|
|
399
|
+
* @throws When `repo` names a repository the project does not declare, or
|
|
400
|
+
* one whose path is not a checkout's root.
|
|
401
|
+
* @task T14078
|
|
402
|
+
*/
|
|
403
|
+
export function gateTreeFor(gate, tree, storeRoot) {
|
|
404
|
+
if (gate.repo === undefined)
|
|
405
|
+
return tree;
|
|
406
|
+
const repo = resolveEvidenceRepository(storeRoot, gate.repo);
|
|
407
|
+
// @sync-invariant none:input-shape a typed gate naming an undeclared repository is refused before it runs; nothing is written
|
|
408
|
+
if (!repo.ok)
|
|
409
|
+
throw new Error(`Typed gate ${gate.req ?? gate.description}: ${repo.reason}`);
|
|
410
|
+
return repo.root;
|
|
411
|
+
}
|
|
308
412
|
/**
|
|
309
413
|
* Admission for a batch run without a caller-owned lifetime.
|
|
310
414
|
* An invalid deadline override is not swallowed: {@link runOneGate} resolves it
|
|
@@ -381,9 +485,19 @@ export async function runGates(gates, options = {}) {
|
|
|
381
485
|
if (cacheMode !== 'off' && (snapshot.length !== 1 || !cacheInputsHash))
|
|
382
486
|
throw new Error('Typed gate caching requires one gate per batch and its inputs digest');
|
|
383
487
|
// T12621: the repo state is captured only when the policy reads or writes.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
:
|
|
488
|
+
let cacheState = null;
|
|
489
|
+
if (cacheMode !== 'off' && TOOL_GATE_KINDS.has(snapshot[0].kind)) {
|
|
490
|
+
// T14078: keyed to the HEAD of the tree the gate runs in; a refused
|
|
491
|
+
// repository leaves the state unset and the loop reports the refusal.
|
|
492
|
+
let cacheTree = null;
|
|
493
|
+
try {
|
|
494
|
+
cacheTree = gateTreeFor(snapshot[0], treeRoot, projectRoot);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
cacheTree = null;
|
|
498
|
+
}
|
|
499
|
+
cacheState = cacheTree === null ? null : await captureGateCacheState(cacheTree);
|
|
500
|
+
}
|
|
387
501
|
const cacheKey = cacheState ? loadEvidenceCacheKey() : null;
|
|
388
502
|
const results = [];
|
|
389
503
|
try {
|
|
@@ -401,6 +515,7 @@ export async function runGates(gates, options = {}) {
|
|
|
401
515
|
const parsed = acceptanceGateSchema.parse(gate);
|
|
402
516
|
if (!isDeepStrictEqual(parsed, gate))
|
|
403
517
|
throw new Error('Gate includes unsupported or noncanonical fields');
|
|
518
|
+
const gateRoot = gateTreeFor(parsed, treeRoot, projectRoot);
|
|
404
519
|
if (cacheState && cacheKey && (cacheMode === 'use' || cacheMode === 'only')) {
|
|
405
520
|
const lookup = readGateCacheEntry(projectRoot, parsed, cacheState, cacheInputsHash, cacheKey);
|
|
406
521
|
if (lookup.status === 'hit') {
|
|
@@ -428,7 +543,7 @@ export async function runGates(gates, options = {}) {
|
|
|
428
543
|
throw new Error(`${gateNotCachedMessage(parsed, cacheState !== null, cacheKey !== null)}${why ? ` ${why}` : ''}`);
|
|
429
544
|
}
|
|
430
545
|
const observed = {
|
|
431
|
-
...(await runOneGate(parsed, i,
|
|
546
|
+
...(await runOneGate(parsed, i, gateRoot, options.skipManual ?? true, { ...batch, cwd: gateRoot }, projectRoot)),
|
|
432
547
|
source: 'executed',
|
|
433
548
|
};
|
|
434
549
|
if (cacheState && cacheKey && cacheMode !== 'only')
|
|
@@ -634,20 +749,30 @@ export async function runTaskGates(task, criteria, options) {
|
|
|
634
749
|
// quote) becomes ITS OWN `error` result. Throwing here rejected the whole
|
|
635
750
|
// batch, and the verify engine turned that into E_GENERAL, discarding
|
|
636
751
|
// every other gate's verdict.
|
|
637
|
-
|
|
752
|
+
// T14078: a gate naming a declared evidence repository runs there; an
|
|
753
|
+
// undeclared one is this gate's error, never a run in another tree.
|
|
754
|
+
let gateRoot = tree;
|
|
755
|
+
let repoRefusal;
|
|
756
|
+
try {
|
|
757
|
+
gateRoot = gateTreeFor(gate, tree, root);
|
|
758
|
+
}
|
|
759
|
+
catch (error) {
|
|
760
|
+
repoRefusal = error instanceof Error ? error.message : String(error);
|
|
761
|
+
}
|
|
762
|
+
const { invocation, refusal: invocationRefusal } = resolveInvocation(gate, gateRoot, env);
|
|
638
763
|
// T13527: an input that cannot be captured (an ambiguous symlink, an
|
|
639
764
|
// escape) is THIS gate's error, not a rejection of every gate in the
|
|
640
765
|
// batch. A cancellation still propagates.
|
|
641
766
|
let artifacts = [];
|
|
642
767
|
let snapshotRefusal;
|
|
643
768
|
try {
|
|
644
|
-
artifacts = await snapshotGateInputs(snapshot, gate, invocation, execution,
|
|
769
|
+
artifacts = await snapshotGateInputs(snapshot, gate, invocation, execution, gateRoot);
|
|
645
770
|
}
|
|
646
771
|
catch (error) {
|
|
647
772
|
execution.assertActive();
|
|
648
773
|
snapshotRefusal = `Typed gate inputs could not be captured: ${error instanceof Error ? error.message : String(error)}`;
|
|
649
774
|
}
|
|
650
|
-
const refusal = invocationRefusal ?? snapshotRefusal;
|
|
775
|
+
const refusal = repoRefusal ?? invocationRefusal ?? snapshotRefusal;
|
|
651
776
|
const binding = {
|
|
652
777
|
version: 1,
|
|
653
778
|
verificationId,
|
|
@@ -661,7 +786,7 @@ export async function runTaskGates(task, criteria, options) {
|
|
|
661
786
|
...(invocation ? { invocation } : {}),
|
|
662
787
|
artifacts,
|
|
663
788
|
};
|
|
664
|
-
const treeBinding = captureTreeBinding(
|
|
789
|
+
const treeBinding = captureTreeBinding(gateRoot, invocation, artifacts);
|
|
665
790
|
if (treeBinding)
|
|
666
791
|
binding.tree = treeBinding;
|
|
667
792
|
const observed = refusal
|
|
@@ -698,7 +823,7 @@ export async function runTaskGates(task, criteria, options) {
|
|
|
698
823
|
// A gate whose inputs were never captured has nothing to compare.
|
|
699
824
|
const after = snapshotRefusal
|
|
700
825
|
? artifacts
|
|
701
|
-
: await snapshotGateInputs(snapshot, gate, invocation, execution,
|
|
826
|
+
: await snapshotGateInputs(snapshot, gate, invocation, execution, gateRoot);
|
|
702
827
|
if (!isDeepStrictEqual(after, artifacts))
|
|
703
828
|
throw new Error('Verification inputs changed during execution');
|
|
704
829
|
}
|
|
@@ -924,7 +1049,7 @@ function rebindCommand(task, tree) {
|
|
|
924
1049
|
}
|
|
925
1050
|
/** Revalidate the stored result of the typed gate at `index`; throws when it does not stand. */
|
|
926
1051
|
async function revalidateTypedResult(scope, index, gate) {
|
|
927
|
-
const { task, rows, results, execution, root,
|
|
1052
|
+
const { task, rows, results, execution, root, env, requirePassing } = scope;
|
|
928
1053
|
execution.assertActive();
|
|
929
1054
|
const matches = results.filter((result) => result.index === index);
|
|
930
1055
|
if (matches.length !== 1)
|
|
@@ -934,6 +1059,8 @@ async function revalidateTypedResult(scope, index, gate) {
|
|
|
934
1059
|
if (stale)
|
|
935
1060
|
throw new Error(`Typed requirement ${gate.req ?? index} ${stale}`);
|
|
936
1061
|
const binding = result.binding;
|
|
1062
|
+
// T14078: revalidated in the tree it runs in, its declared repository when it names one.
|
|
1063
|
+
const tree = gateTreeFor(gate, scope.tree, root);
|
|
937
1064
|
// A refused command is bound without an invocation (T12718 review), so it
|
|
938
1065
|
// revalidates as the unmet `error` it was recorded as.
|
|
939
1066
|
const { invocation: resolved } = resolveInvocation(gate, tree, env);
|
|
@@ -1246,6 +1373,13 @@ export function executableInvocation(gate, root, env) {
|
|
|
1246
1373
|
const [testCommand, ...testArgs] = gate.kind === 'test' ? splitCommandLine(gate.command) : [];
|
|
1247
1374
|
if (gate.kind === 'test' && testCommand === undefined)
|
|
1248
1375
|
throw new Error('Test gate command is empty');
|
|
1376
|
+
// T14155: a stored command gate whose cmd carries its arguments would spawn
|
|
1377
|
+
// a program named the whole line and fail with a bare ENOENT. Every run path
|
|
1378
|
+
// (preview, verify --run, done) resolves its invocation here first.
|
|
1379
|
+
const cmdProblem = commandGateCmdProblem(gate, root);
|
|
1380
|
+
// @sync-invariant none:input-shape a stored gate's cmd shape is refused before it spawns; nothing is written
|
|
1381
|
+
if (cmdProblem !== null)
|
|
1382
|
+
throw new Error(cmdProblem);
|
|
1249
1383
|
const command = gate.kind === 'test'
|
|
1250
1384
|
? testCommand
|
|
1251
1385
|
: gate.kind === 'command'
|
|
@@ -1674,6 +1808,37 @@ function matchingBrace(text, start) {
|
|
|
1674
1808
|
}
|
|
1675
1809
|
return -1;
|
|
1676
1810
|
}
|
|
1811
|
+
/**
|
|
1812
|
+
* A report the shared reader (T14124) read, as gate counts; a refusal is
|
|
1813
|
+
* recorded in `refusals` (prefixed with where it was found) and yields null.
|
|
1814
|
+
*/
|
|
1815
|
+
function gateCounts(read, where, refusals) {
|
|
1816
|
+
if (read === null)
|
|
1817
|
+
return null;
|
|
1818
|
+
if (!read.ok) {
|
|
1819
|
+
refusals.push(`${where} is a ${read.format} report that was refused: ${read.reason}`);
|
|
1820
|
+
return null;
|
|
1821
|
+
}
|
|
1822
|
+
const { passed, failed, total, failure } = read.counts;
|
|
1823
|
+
return {
|
|
1824
|
+
numPassedTests: passed,
|
|
1825
|
+
numFailedTests: failed,
|
|
1826
|
+
numTotalTests: total,
|
|
1827
|
+
success: failed === 0 && failure === undefined,
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Whether a read report is a bare counter summary (runner summary or
|
|
1832
|
+
* node --test counters with no per-test results), which a gate accepts only as
|
|
1833
|
+
* its whole stdout or its report file (T14132).
|
|
1834
|
+
*/
|
|
1835
|
+
function isBareSummary(read) {
|
|
1836
|
+
if (read.format !== 'runner summary JSON' && read.format !== 'node --test summary JSON')
|
|
1837
|
+
return false;
|
|
1838
|
+
const files = read.report.testResults;
|
|
1839
|
+
return !(Array.isArray(files) &&
|
|
1840
|
+
files.some((f) => Array.isArray(f.assertionResults) && f.assertionResults.length > 0));
|
|
1841
|
+
}
|
|
1677
1842
|
/** Top-level keys that mark a JSON object as an attempted test-count report. */
|
|
1678
1843
|
const COUNT_REPORT_KEYS = ['numTotalTests', 'numPassedTests', 'numFailedTests', 'testResults'];
|
|
1679
1844
|
/**
|
|
@@ -1695,57 +1860,12 @@ function looksLikeCountReport(value) {
|
|
|
1695
1860
|
value !== null &&
|
|
1696
1861
|
COUNT_REPORT_KEYS.some((key) => Object.hasOwn(value, key)));
|
|
1697
1862
|
}
|
|
1698
|
-
/**
|
|
1699
|
-
* Counts from node:test TAP output (`node --test --test-reporter=tap`, also
|
|
1700
|
-
* via `tsx --test`), which ships no JSON reporter (T14051). The run's LAST
|
|
1701
|
-
* top-level plan (`1..N` at column 0) must be followed by its `# tests N`,
|
|
1702
|
-
* `# pass N` and `# fail N` summary; `# cancelled N` counts as failed. Test
|
|
1703
|
-
* console output is re-emitted as indented or `# ` comment lines before that
|
|
1704
|
-
* plan, so it cannot forge the summary.
|
|
1705
|
-
*
|
|
1706
|
-
* @param stdout - The run's captured stdout.
|
|
1707
|
-
* @returns Counts, a refusal reason, or null when the output is not TAP.
|
|
1708
|
-
* @task T14051
|
|
1709
|
-
*/
|
|
1710
|
-
function tapTestCounts(stdout) {
|
|
1711
|
-
const lines = stdout.split(/\r?\n/);
|
|
1712
|
-
if (!lines.some((line) => /^TAP version \d+$/.test(line.trim())))
|
|
1713
|
-
return null;
|
|
1714
|
-
if (lines.some((line) => /^\s*Bail out!/.test(line)))
|
|
1715
|
-
return { refusal: 'its TAP output contains "Bail out!"' };
|
|
1716
|
-
const plan = lines.findLastIndex((line) => /^1\.\.\d+(?:\s|$)/.test(line));
|
|
1717
|
-
if (plan === -1)
|
|
1718
|
-
return { refusal: 'its TAP output has no top-level 1..N plan' };
|
|
1719
|
-
const summary = new Map();
|
|
1720
|
-
for (const line of lines.slice(plan + 1)) {
|
|
1721
|
-
const match = line.match(/^# (tests|pass|fail|cancelled) (\d+)$/);
|
|
1722
|
-
if (match)
|
|
1723
|
-
summary.set(match[1], Number(match[2]));
|
|
1724
|
-
}
|
|
1725
|
-
const tests = summary.get('tests');
|
|
1726
|
-
const pass = summary.get('pass');
|
|
1727
|
-
const fail = summary.get('fail');
|
|
1728
|
-
if (tests === undefined || pass === undefined || fail === undefined)
|
|
1729
|
-
return {
|
|
1730
|
-
refusal: 'its TAP output has no "# tests", "# pass" and "# fail" summary after the plan',
|
|
1731
|
-
};
|
|
1732
|
-
if (tests === 0 || /^1\.\.0(?:\s|$)/.test(lines[plan]))
|
|
1733
|
-
return { refusal: 'its TAP output reports zero tests' };
|
|
1734
|
-
const failed = fail + (summary.get('cancelled') ?? 0);
|
|
1735
|
-
return {
|
|
1736
|
-
numPassedTests: pass,
|
|
1737
|
-
numFailedTests: failed,
|
|
1738
|
-
numTotalTests: tests,
|
|
1739
|
-
success: failed === 0,
|
|
1740
|
-
};
|
|
1741
|
-
}
|
|
1742
1863
|
/**
|
|
1743
1864
|
* Structured test counts emitted by THIS gate's own process, or `null`.
|
|
1744
1865
|
*
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
* details contradict.
|
|
1866
|
+
* Read by the shared count reader ({@link readParsedTestReport}, T14124),
|
|
1867
|
+
* which cross-checks the counters against the individual test results, so a
|
|
1868
|
+
* report cannot claim a total its own details contradict.
|
|
1749
1869
|
*
|
|
1750
1870
|
* The whole captured stream is searched rather than requiring `stdout` to BE
|
|
1751
1871
|
* the document, because a runner that writes a JSON report to stdout routinely
|
|
@@ -1758,7 +1878,8 @@ function tapTestCounts(stdout) {
|
|
|
1758
1878
|
*
|
|
1759
1879
|
* A non-runner command (a wrapper script) may instead print a bare count
|
|
1760
1880
|
* summary ({@link testCountSummarySchema}) as its last stdout line (T13753),
|
|
1761
|
-
* and node:test may print TAP (
|
|
1881
|
+
* and node:test may print TAP (T14051). TAP and every JSON candidate are read
|
|
1882
|
+
* by the reader `test-run:` uses ({@link readTestReport}, T14124).
|
|
1762
1883
|
*
|
|
1763
1884
|
* A candidate that parses as a count report but fails its schema is recorded
|
|
1764
1885
|
* in `refusals` with its first issue (T14060), so the error can say which
|
|
@@ -1768,13 +1889,15 @@ function tapTestCounts(stdout) {
|
|
|
1768
1889
|
* @param refusals - Receives why each report-like candidate was refused, in the order the
|
|
1769
1890
|
* candidates are tried (last stdout line, TAP, then the output newest-first); the
|
|
1770
1891
|
* first is the one reported.
|
|
1892
|
+
* @param cwd - The run's cwd, where TAP test file names resolve (T14161).
|
|
1771
1893
|
* @returns Validated counts, or `null` when the run emitted no usable report.
|
|
1772
1894
|
* @task T12308
|
|
1773
1895
|
* @task T13753
|
|
1774
1896
|
* @task T14051
|
|
1775
1897
|
* @task T14060
|
|
1898
|
+
* @task T14161
|
|
1776
1899
|
*/
|
|
1777
|
-
function structuredTestCounts(captured, refusals) {
|
|
1900
|
+
function structuredTestCounts(captured, refusals, cwd) {
|
|
1778
1901
|
const lastLine = captured.stdout.trimEnd().split('\n').at(-1)?.trim() ?? '';
|
|
1779
1902
|
if (lastLine.startsWith('{')) {
|
|
1780
1903
|
try {
|
|
@@ -1790,26 +1913,36 @@ function structuredTestCounts(captured, refusals) {
|
|
|
1790
1913
|
// Not JSON: fall through to the full-report search.
|
|
1791
1914
|
}
|
|
1792
1915
|
}
|
|
1793
|
-
|
|
1794
|
-
if (
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1916
|
+
// T14124: TAP through the reader `test-run:` uses.
|
|
1917
|
+
if (/^TAP version \d+$/m.test(captured.stdout))
|
|
1918
|
+
return gateCounts(readTestReport(captured.stdout, { cwd }), 'its TAP output', refusals);
|
|
1919
|
+
// T14124: a report that IS the whole stdout, in any format `test-run:` reads
|
|
1920
|
+
// (JUnit XML and libtest JSON lines included).
|
|
1921
|
+
const whole = readTestReport(captured.stdout.trim());
|
|
1922
|
+
if (whole !== null)
|
|
1923
|
+
return gateCounts(whole, 'its output', refusals);
|
|
1801
1924
|
const text = `${captured.stdout}\n${captured.stderr}`.trim();
|
|
1802
1925
|
if (text.length === 0)
|
|
1803
1926
|
return null;
|
|
1927
|
+
let embeddedSummary = false;
|
|
1804
1928
|
const tryParse = (candidate) => {
|
|
1805
1929
|
try {
|
|
1806
1930
|
const raw = JSON.parse(candidate);
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1931
|
+
// T14124: the reader `test-run:` uses, so every shape it reads counts here.
|
|
1932
|
+
const read = readParsedTestReport(raw);
|
|
1933
|
+
// T14132: a bare counter summary found INSIDE the output (any test can
|
|
1934
|
+
// print `{"total":5,"passed":5}`) proves nothing; only the whole stdout or
|
|
1935
|
+
// the gate's report file may be one. Full reports embedded in noise count.
|
|
1936
|
+
if (read?.ok && isBareSummary(read)) {
|
|
1937
|
+
if (!embeddedSummary)
|
|
1938
|
+
refusals.push(`a ${read.format} object inside its output is not counted; only the whole stdout ` +
|
|
1939
|
+
"or the gate's report file may be a summary-shaped report. Make the summary the " +
|
|
1940
|
+
"command's entire stdout (nothing else printed), or write it to a file the gate " +
|
|
1941
|
+
'names (--outputFile) or announces ("JSON report written to <path>")');
|
|
1942
|
+
embeddedSummary = true;
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
return gateCounts(read, 'a JSON report in its output', refusals);
|
|
1813
1946
|
}
|
|
1814
1947
|
catch {
|
|
1815
1948
|
return null;
|
|
@@ -1919,23 +2052,26 @@ async function fileStamp(path) {
|
|
|
1919
2052
|
* @param before - Each candidate's stamp just before the spawn.
|
|
1920
2053
|
* @param startedAt - Epoch ms just before the spawn.
|
|
1921
2054
|
* @param refusals - Receives why a fresh report that failed its schema was refused (T14060).
|
|
2055
|
+
* @param cwd - The run's cwd, where TAP test file names resolve (T14161).
|
|
1922
2056
|
* @returns Validated counts, or null.
|
|
1923
2057
|
* @task T13782
|
|
1924
2058
|
* @task T14060
|
|
1925
2059
|
*/
|
|
1926
|
-
async function freshReportCounts(before, startedAt, refusals) {
|
|
2060
|
+
async function freshReportCounts(before, startedAt, refusals, cwd) {
|
|
1927
2061
|
for (const [path, was] of before) {
|
|
1928
2062
|
const now = await fileStamp(path);
|
|
1929
2063
|
if (now === null || now.mtimeMs < startedAt || (was !== null && was.sha256 === now.sha256))
|
|
1930
2064
|
continue;
|
|
1931
2065
|
try {
|
|
1932
|
-
|
|
1933
|
-
|
|
2066
|
+
// T14124: any format `test-run:` reads (JUnit XML, libtest, JSON, TAP).
|
|
2067
|
+
const read = readTestReport(await readFile(path, 'utf-8'), { cwd });
|
|
2068
|
+
if (read?.ok &&
|
|
2069
|
+
typeof read.report.startTime === 'number' &&
|
|
2070
|
+
read.report.startTime < startedAt)
|
|
1934
2071
|
continue;
|
|
1935
|
-
const
|
|
1936
|
-
if (
|
|
1937
|
-
return
|
|
1938
|
-
refusals.push(`${path} fails the full report shape (${firstSchemaIssue(report.error)})`);
|
|
2072
|
+
const counts = gateCounts(read, path, refusals);
|
|
2073
|
+
if (counts !== null)
|
|
2074
|
+
return counts;
|
|
1939
2075
|
}
|
|
1940
2076
|
catch {
|
|
1941
2077
|
// Unreadable or not JSON: not a report of this run.
|
|
@@ -1973,13 +2109,13 @@ function describeMissingTestCount(gate, refusal) {
|
|
|
1973
2109
|
? `\`${invoked}\` emitted no machine-readable test report`
|
|
1974
2110
|
: `\`${invoked}\` emitted a test report that was refused: ${refusal}`;
|
|
1975
2111
|
return (`minCount ${gate.minCount} cannot be proved: ${found}, and an exit code alone carries no ` +
|
|
1976
|
-
`count.
|
|
1977
|
-
`
|
|
1978
|
-
`
|
|
1979
|
-
`
|
|
1980
|
-
`counters
|
|
1981
|
-
`{
|
|
1982
|
-
`
|
|
2112
|
+
`count. Formats tried: ${TEST_REPORT_FORMATS.join(', ')}, and a bare count summary as the ` +
|
|
2113
|
+
`LAST stdout line (at minimum {"numPassedTests":N}). These are the formats \`test-run:\` ` +
|
|
2114
|
+
`reads, among them a full Vitest/Jest JSON report (numTotalTests, numPassedTests, ` +
|
|
2115
|
+
`numFailedTests, numPendingTests, numTodoTests, testResults[].assertionResults); a report's ` +
|
|
2116
|
+
`counters must add up and agree with its own test results. Add a reporter ` +
|
|
2117
|
+
`to the gate command itself (e.g. \`${invoked} ${flag}\`) so the run that is being attested ` +
|
|
2118
|
+
`is the run that is counted. ` +
|
|
1983
2119
|
`A report file this run writes (its --outputFile, or ${REDIRECTED_JSON_REPORT}) is read too, ` +
|
|
1984
2120
|
`but one produced by a separate invocation is deliberately not accepted \u2014 it is not bound ` +
|
|
1985
2121
|
`to this execution; record that as \`test-run:<path>\` evidence instead, or drop minCount if ` +
|
|
@@ -2021,6 +2157,10 @@ export function outputReportsFailure(stdout) {
|
|
|
2021
2157
|
return /\bFAIL\b|failing|Error:|\b[1-9]\d*\s+fail(?:ed|ures?)\b/i.test(stdout.replace(PASSING_TEST_LINE, '').replace(ZERO_FAILURE_COUNT, ''));
|
|
2022
2158
|
}
|
|
2023
2159
|
async function runTestGate(gate, index, projectRoot, timeoutMs, context) {
|
|
2160
|
+
// Keep a direct call's refusal (T14155) an error verdict, not a rejection.
|
|
2161
|
+
const cmdProblem = commandGateCmdProblem(gate, projectRoot);
|
|
2162
|
+
if (cmdProblem !== null)
|
|
2163
|
+
return makeResult(index, gate, 'error', 0, undefined, cmdProblem);
|
|
2024
2164
|
const invocation = executableInvocation(gate, projectRoot, context.env ?? process.env);
|
|
2025
2165
|
// T13782: a JSON reporter redirected to a file still yields this run's counts.
|
|
2026
2166
|
const reportFiles = reportFileCandidates(invocation.args, invocation.cwd);
|
|
@@ -2035,8 +2175,8 @@ async function runTestGate(gate, index, projectRoot, timeoutMs, context) {
|
|
|
2035
2175
|
if (announced !== null && !before.has(announced))
|
|
2036
2176
|
before.set(announced, null);
|
|
2037
2177
|
const refusals = [];
|
|
2038
|
-
const counts = structuredTestCounts(captured, refusals) ??
|
|
2039
|
-
(await freshReportCounts(before, startedAt, refusals));
|
|
2178
|
+
const counts = structuredTestCounts(captured, refusals, invocation.cwd) ??
|
|
2179
|
+
(await freshReportCounts(before, startedAt, refusals, invocation.cwd));
|
|
2040
2180
|
// T12308: the counts come from this run's own validated report; only their
|
|
2041
2181
|
// ABSENCE is an error, because inferring a count from exit zero is the thing
|
|
2042
2182
|
// that must not happen. T13753: the error keeps the run's execution record.
|