@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
package/dist/docs/doctor.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* `cleo docs doctor` — store health diagnostics + safe repairs — T13447.
|
|
3
3
|
*
|
|
4
4
|
* Audits the CleoDocs store (`cleo.db` `attachments`/`docs_wikilinks` tables
|
|
5
|
-
* plus the on-disk legacy surfaces
|
|
5
|
+
* plus the on-disk legacy surfaces and the `docs_publications` ledger) for nine
|
|
6
|
+
* known drift classes and, when
|
|
6
7
|
* invoked with `apply: true`, performs the repairs that are safe to run
|
|
7
8
|
* in-place:
|
|
8
9
|
*
|
|
@@ -63,6 +64,25 @@
|
|
|
63
64
|
* doc whose remaining positions are
|
|
64
65
|
* unrecoverable stays listed at `info` level —
|
|
65
66
|
* visibility only, no invented repair (T13843).
|
|
67
|
+
* - `publication-ledger-drift` — `docs_publications` rows whose mirror is not
|
|
68
|
+
* in sync (T14117): the file is gone (`deleted`;
|
|
69
|
+
* outside the project root this is a dead
|
|
70
|
+
* worktree) or differs from the store head
|
|
71
|
+
* (`modified`). Repair (`prune-publication`) deletes
|
|
72
|
+
* a `deleted` row only when the mirror is provably
|
|
73
|
+
* gone and its blob is still held by an attachments
|
|
74
|
+
* row or by a live ledger row. The ledger syncs
|
|
75
|
+
* across devices, so an absolute path or one outside
|
|
76
|
+
* both this root and this device's worktrees root is
|
|
77
|
+
* `report-only`, and a relative path still tracked by
|
|
78
|
+
* HEAD or the default branch (another branch checked
|
|
79
|
+
* out) is kept. A path in a removed worktree of this
|
|
80
|
+
* device is gone. Each pruned row is appended in
|
|
81
|
+
* full to {@link DOCS_DOCTOR_LEDGER_PRUNE_AUDIT_FILE}
|
|
82
|
+
* first, so it can be re-inserted. `modified` rows
|
|
83
|
+
* and unprotected `deleted` rows get a plan-only
|
|
84
|
+
* entry (republish, or ingest the edit) — the
|
|
85
|
+
* doctor never picks which side of a drift wins.
|
|
66
86
|
*
|
|
67
87
|
* SAFETY: `apply: true` (or `repair: true`) REFUSES to run without a backup receipt
|
|
68
88
|
* ({@link DocsDoctorOptions.backupReceiptPath}) whose mtime is at most
|
|
@@ -79,12 +99,13 @@
|
|
|
79
99
|
* @see wikilinks.ts — derived edge table + rebuild (T11826)
|
|
80
100
|
*/
|
|
81
101
|
import { createHash } from 'node:crypto';
|
|
82
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
102
|
+
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, statSync, } from 'node:fs';
|
|
83
103
|
import { readFile } from 'node:fs/promises';
|
|
84
104
|
import { tmpdir } from 'node:os';
|
|
85
|
-
import { isAbsolute, join, resolve, sep } from 'node:path';
|
|
105
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
86
106
|
import { getCleoWorktreesRoot } from '@cleocode/paths';
|
|
87
107
|
import { eq } from 'drizzle-orm';
|
|
108
|
+
import { gitDefaultBranchRefs, gitRefHasPath, gitToplevel } from '../git/work-tree.js';
|
|
88
109
|
import { resolveCleoDir } from '../paths.js';
|
|
89
110
|
import { createAttachmentStore } from '../store/attachment-store.js';
|
|
90
111
|
import { backfillBlobStoreBytes, blobContentExists, resolveLegacyByteSource, } from '../store/blob-keep.js';
|
|
@@ -94,6 +115,8 @@ import { docsAttachments } from '../store/tasks-schema.js';
|
|
|
94
115
|
import { applyConduitHistoryBackfill, planConduitHistoryBackfill, } from './conduit-history-backfill.js';
|
|
95
116
|
import { deriveDocLinks, isScannableTextMime, linksJsonOrNull, } from './derive-links.js';
|
|
96
117
|
import { DOCS_VERSIONING_AUDIT_FILE } from './docs-update.js';
|
|
118
|
+
import { assertCheckoutOfProject } from './modernize/guard.js';
|
|
119
|
+
import { deleteDocsPublication, readDocsPublications } from './publications-store.js';
|
|
97
120
|
import { deriveWikilinkEdges, rebuildDocsWikilinks } from './wikilinks.js';
|
|
98
121
|
/**
|
|
99
122
|
* Maximum age of the backup receipt accepted before an `apply` run.
|
|
@@ -117,6 +140,33 @@ export const DOCS_DOCTOR_DEFAULT_OLDER_THAN_DAYS = 30;
|
|
|
117
140
|
* @task T13447
|
|
118
141
|
*/
|
|
119
142
|
export const DOCS_DOCTOR_MAX_DETAIL_ITEMS = 50;
|
|
143
|
+
/**
|
|
144
|
+
* Project-relative audit log the ledger prune appends each deleted
|
|
145
|
+
* `docs_publications` row to (one JSON line per row, written before the
|
|
146
|
+
* delete), so a pruned row can be restored with `upsertDocsPublication`.
|
|
147
|
+
*
|
|
148
|
+
* @task T14117
|
|
149
|
+
*/
|
|
150
|
+
export const DOCS_DOCTOR_LEDGER_PRUNE_AUDIT_FILE = '.cleo/audit/docs-publications-prune.jsonl';
|
|
151
|
+
/**
|
|
152
|
+
* The diagnostic classes that carry a repair, accepted by
|
|
153
|
+
* {@link DocsDoctorOptions.only} to scope a run to some of them (T14174).
|
|
154
|
+
*
|
|
155
|
+
* @task T14174
|
|
156
|
+
*/
|
|
157
|
+
export const DOCS_DOCTOR_REPAIR_CLASSES = [
|
|
158
|
+
'dangling-pointers',
|
|
159
|
+
'doc-version-skew',
|
|
160
|
+
'empty-provenance',
|
|
161
|
+
'wikilinks-drift',
|
|
162
|
+
'legacy-blob-coverage',
|
|
163
|
+
'conduit-history-gaps',
|
|
164
|
+
'publication-ledger-drift',
|
|
165
|
+
];
|
|
166
|
+
/** Whether a diagnostic kind carries a repair (T14174). @internal */
|
|
167
|
+
function isRepairClass(kind) {
|
|
168
|
+
return DOCS_DOCTOR_REPAIR_CLASSES.includes(kind);
|
|
169
|
+
}
|
|
120
170
|
/**
|
|
121
171
|
* Parse a row's `attachment_json` defensively. Malformed JSON yields null —
|
|
122
172
|
* such rows are skipped by kind-scoped checks rather than failing the run.
|
|
@@ -326,6 +376,157 @@ async function fetchRowContent(row, payload, projectRoot) {
|
|
|
326
376
|
return null;
|
|
327
377
|
}
|
|
328
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Decide whether a missing mirror is provably gone, not merely absent from
|
|
381
|
+
* this device or this checkout (T14117 review). `docs_publications` syncs
|
|
382
|
+
* across devices, so a prune here deletes the row everywhere:
|
|
383
|
+
*
|
|
384
|
+
* - an absolute path, or one outside both this project root and this
|
|
385
|
+
* device's CLEO worktrees root, belongs to another device or checkout and
|
|
386
|
+
* is never proven gone;
|
|
387
|
+
* - a path inside this device's worktrees root whose worktree directory no
|
|
388
|
+
* longer exists is gone;
|
|
389
|
+
* - otherwise the path must be absent from `HEAD` and from the default
|
|
390
|
+
* branch (local and `origin/`) of the checkout that holds it, so a file
|
|
391
|
+
* missing only because another branch is checked out is kept. When git
|
|
392
|
+
* cannot answer, the row is not proven gone.
|
|
393
|
+
*
|
|
394
|
+
* @internal
|
|
395
|
+
*/
|
|
396
|
+
function provePublicationGone(projectRoot, publishedPath, absPath) {
|
|
397
|
+
if (isAbsolute(publishedPath)) {
|
|
398
|
+
return {
|
|
399
|
+
gone: false,
|
|
400
|
+
reason: 'its path is absolute (published from another device or checkout)',
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
const relToRoot = relative(projectRoot, absPath);
|
|
404
|
+
const insideRoot = !relToRoot.startsWith('..') && !isAbsolute(relToRoot);
|
|
405
|
+
// `base` is the existing directory the path sits under; git paths are taken
|
|
406
|
+
// relative to it through its realpath, since gitToplevel() canonicalises
|
|
407
|
+
// (macOS /var → /private/var would otherwise yield a bogus `../..` path).
|
|
408
|
+
let base = projectRoot;
|
|
409
|
+
if (!insideRoot) {
|
|
410
|
+
const worktreesRoot = getCleoWorktreesRoot();
|
|
411
|
+
const relToWorktrees = relative(worktreesRoot, absPath);
|
|
412
|
+
if (relToWorktrees.startsWith('..') || isAbsolute(relToWorktrees)) {
|
|
413
|
+
return {
|
|
414
|
+
gone: false,
|
|
415
|
+
reason: "it is outside this project root and this device's worktrees root (another device's path)",
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
const [projectHash, worktreeName] = relToWorktrees.split(sep);
|
|
419
|
+
if (projectHash === undefined || worktreeName === undefined) {
|
|
420
|
+
return { gone: false, reason: 'it does not name a worktree' };
|
|
421
|
+
}
|
|
422
|
+
const worktreeDir = join(worktreesRoot, projectHash, worktreeName);
|
|
423
|
+
if (!existsSync(worktreeDir)) {
|
|
424
|
+
return { gone: true, reason: `its worktree ${worktreeDir} no longer exists` };
|
|
425
|
+
}
|
|
426
|
+
base = worktreeDir;
|
|
427
|
+
}
|
|
428
|
+
const toplevel = gitToplevel(base);
|
|
429
|
+
if (toplevel === null)
|
|
430
|
+
return { gone: false, reason: 'git cannot read the checkout that holds it' };
|
|
431
|
+
const relPath = join(relative(toplevel, realpathSync(base)), relative(base, absPath))
|
|
432
|
+
.split(sep)
|
|
433
|
+
.join('/');
|
|
434
|
+
const defaults = gitDefaultBranchRefs(toplevel);
|
|
435
|
+
for (const ref of ['HEAD', ...defaults]) {
|
|
436
|
+
const has = gitRefHasPath(toplevel, ref, relPath);
|
|
437
|
+
if (has === true)
|
|
438
|
+
return { gone: false, reason: `${ref} still tracks it` };
|
|
439
|
+
if (has === null && ref === 'HEAD')
|
|
440
|
+
return { gone: false, reason: 'git cannot read HEAD' };
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
gone: true,
|
|
444
|
+
reason: `absent from ${['HEAD', ...defaults].join(', ')}`,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Classify every non-in-sync `docs_publications` row and plan its repair
|
|
449
|
+
* (T14117). Reuses {@link statusDocs} for the drift classification so the
|
|
450
|
+
* doctor and `cleo docs status` can never disagree.
|
|
451
|
+
*
|
|
452
|
+
* A `deleted` row is prunable only when its blob stays protected without it:
|
|
453
|
+
* some attachments row holds the sha, or another ledger row naming the same
|
|
454
|
+
* sha is not itself `deleted`.
|
|
455
|
+
*
|
|
456
|
+
* @internal
|
|
457
|
+
*/
|
|
458
|
+
async function scanPublicationLedger(projectRoot, rows, checkoutRoot) {
|
|
459
|
+
const ledger = await readDocsPublications(projectRoot);
|
|
460
|
+
if (ledger.length === 0)
|
|
461
|
+
return [];
|
|
462
|
+
const { statusDocs } = await import('./docs-ops.js');
|
|
463
|
+
const status = await statusDocs({ projectRoot, checkoutRoot });
|
|
464
|
+
const key = (r) => `${r.ownerId}\u0000${r.blobName}\u0000${r.publishedPath}`;
|
|
465
|
+
const recordByKey = new Map(ledger.map((r) => [key(r), r]));
|
|
466
|
+
const attachmentShas = new Set(rows.map((r) => r.sha256));
|
|
467
|
+
const liveLedgerShas = new Map();
|
|
468
|
+
for (const item of status.items) {
|
|
469
|
+
if (item.drift === 'deleted')
|
|
470
|
+
continue;
|
|
471
|
+
const record = recordByKey.get(key(item));
|
|
472
|
+
if (record)
|
|
473
|
+
liveLedgerShas.set(record.lastBlobSha, (liveLedgerShas.get(record.lastBlobSha) ?? 0) + 1);
|
|
474
|
+
}
|
|
475
|
+
const findings = [];
|
|
476
|
+
for (const item of status.items) {
|
|
477
|
+
if (item.drift !== 'deleted' && item.drift !== 'modified')
|
|
478
|
+
continue;
|
|
479
|
+
const record = recordByKey.get(key(item));
|
|
480
|
+
if (!record)
|
|
481
|
+
continue;
|
|
482
|
+
const absPath = isAbsolute(record.publishedPath)
|
|
483
|
+
? record.publishedPath
|
|
484
|
+
: resolve(checkoutRoot, record.publishedPath);
|
|
485
|
+
const rel = relative(checkoutRoot, absPath);
|
|
486
|
+
const outsideRoot = rel.startsWith('..') || isAbsolute(rel);
|
|
487
|
+
if (item.drift === 'modified') {
|
|
488
|
+
const storeMoved = item.fileSha === record.lastBlobSha;
|
|
489
|
+
findings.push({
|
|
490
|
+
record,
|
|
491
|
+
drift: 'modified',
|
|
492
|
+
outsideRoot,
|
|
493
|
+
action: storeMoved ? 'republish' : 'reconcile-edit',
|
|
494
|
+
prunable: false,
|
|
495
|
+
detail: storeMoved
|
|
496
|
+
? `mirror ${record.publishedPath} holds the last published blob; the store head moved on — run \`cleo docs publish\``
|
|
497
|
+
: `mirror ${record.publishedPath} was edited outside the store — ingest it with \`cleo docs update\` or republish to overwrite`,
|
|
498
|
+
});
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
const shas = new Set([record.lastBlobSha, item.blobSha]);
|
|
502
|
+
const protectedElsewhere = [...shas].every((sha) => attachmentShas.has(sha) || (liveLedgerShas.get(sha) ?? 0) > 0);
|
|
503
|
+
const proof = provePublicationGone(checkoutRoot, record.publishedPath, absPath);
|
|
504
|
+
const blob = record.lastBlobSha.slice(0, 12);
|
|
505
|
+
let action;
|
|
506
|
+
let detail;
|
|
507
|
+
if (proof.gone === false) {
|
|
508
|
+
action = 'report-only';
|
|
509
|
+
detail = `mirror ${record.publishedPath} is missing here but ${proof.reason} — not pruned (the ledger syncs across devices)`;
|
|
510
|
+
}
|
|
511
|
+
else if (!protectedElsewhere) {
|
|
512
|
+
action = 'republish-or-prune';
|
|
513
|
+
detail = `mirror ${record.publishedPath} is gone (${proof.reason}) and this row is the only reference to blob ${blob}… — republish it, or archive the doc before pruning`;
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
action = 'prune-publication';
|
|
517
|
+
detail = `mirror ${record.publishedPath} is gone (${proof.reason}); blob ${blob}… stays referenced elsewhere → delete the ledger row`;
|
|
518
|
+
}
|
|
519
|
+
findings.push({
|
|
520
|
+
record,
|
|
521
|
+
drift: 'deleted',
|
|
522
|
+
outsideRoot,
|
|
523
|
+
action,
|
|
524
|
+
prunable: action === 'prune-publication',
|
|
525
|
+
detail,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
return findings;
|
|
529
|
+
}
|
|
329
530
|
/**
|
|
330
531
|
* Scan the store and compute diagnostics + repair inputs in one pass.
|
|
331
532
|
*
|
|
@@ -335,7 +536,7 @@ async function fetchRowContent(row, payload, projectRoot) {
|
|
|
335
536
|
*
|
|
336
537
|
* @internal
|
|
337
538
|
*/
|
|
338
|
-
async function scanStore(projectRoot, db, olderThanDays) {
|
|
539
|
+
async function scanStore(projectRoot, db, olderThanDays, checkoutRoot) {
|
|
339
540
|
const rows = await db.select().from(docsAttachments).all();
|
|
340
541
|
const payloadById = new Map();
|
|
341
542
|
for (const row of rows)
|
|
@@ -540,6 +741,15 @@ async function scanStore(projectRoot, db, olderThanDays) {
|
|
|
540
741
|
// planner reads the audit file, the registry and (hash-verified) bytes,
|
|
541
742
|
// and writes nothing.
|
|
542
743
|
const conduitBackfill = await planConduitHistoryBackfill(projectRoot);
|
|
744
|
+
const ledger = await scanPublicationLedger(projectRoot, rows, checkoutRoot);
|
|
745
|
+
const ledgerItems = ledger.slice(0, DOCS_DOCTOR_MAX_DETAIL_ITEMS).map((f) => ({
|
|
746
|
+
ownerId: f.record.ownerId,
|
|
747
|
+
blobName: f.record.blobName,
|
|
748
|
+
publishedPath: f.record.publishedPath,
|
|
749
|
+
drift: f.drift,
|
|
750
|
+
outsideRoot: f.outsideRoot,
|
|
751
|
+
proposed: f.action,
|
|
752
|
+
}));
|
|
543
753
|
// Actionable = anything a doctor run should surface: rows to backfill,
|
|
544
754
|
// unrecoverable gaps (real, unhealed drift — reported even when the doc
|
|
545
755
|
// is otherwise complete), or a refused conflict (review-2253). Severity:
|
|
@@ -616,6 +826,13 @@ async function scanStore(projectRoot, db, olderThanDays) {
|
|
|
616
826
|
items: conduitItems,
|
|
617
827
|
truncated: conduitActionable.length > conduitItems.length,
|
|
618
828
|
},
|
|
829
|
+
{
|
|
830
|
+
kind: 'publication-ledger-drift',
|
|
831
|
+
severity: ledger.length > 0 ? 'warn' : 'info',
|
|
832
|
+
count: ledger.length,
|
|
833
|
+
items: ledgerItems,
|
|
834
|
+
truncated: ledger.length > ledgerItems.length,
|
|
835
|
+
},
|
|
619
836
|
];
|
|
620
837
|
return {
|
|
621
838
|
diagnostics,
|
|
@@ -626,6 +843,7 @@ async function scanStore(projectRoot, db, olderThanDays) {
|
|
|
626
843
|
missingEdges,
|
|
627
844
|
needsWikilinksRebuild: missingEdges.length > 0 || backfillChangesLinks,
|
|
628
845
|
conduitBackfill,
|
|
846
|
+
ledger,
|
|
629
847
|
};
|
|
630
848
|
}
|
|
631
849
|
/**
|
|
@@ -668,18 +886,63 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
668
886
|
},
|
|
669
887
|
};
|
|
670
888
|
}
|
|
889
|
+
// T14174 — scope to some repair classes.
|
|
890
|
+
let only = null;
|
|
891
|
+
if (opts.only !== undefined) {
|
|
892
|
+
const valid = new Set(DOCS_DOCTOR_REPAIR_CLASSES);
|
|
893
|
+
const unknown = opts.only.filter((c) => !valid.has(c));
|
|
894
|
+
if (unknown.length > 0 || opts.only.length === 0) {
|
|
895
|
+
return {
|
|
896
|
+
ok: false,
|
|
897
|
+
error: {
|
|
898
|
+
// @sync-invariant none:input-shape an argument refusal before any repair write; nothing was written
|
|
899
|
+
code: 'E_DOCS_DOCTOR_UNKNOWN_CLASS',
|
|
900
|
+
message: `docs doctor: --only ${unknown.length > 0 ? `names unknown class(es) ${unknown.join(', ')}` : 'names no class'}; ` +
|
|
901
|
+
`valid classes: ${DOCS_DOCTOR_REPAIR_CLASSES.join(', ')}`,
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
if (repair) {
|
|
906
|
+
return {
|
|
907
|
+
ok: false,
|
|
908
|
+
error: {
|
|
909
|
+
// @sync-invariant none:input-shape a flag-combination refusal before any repair write; nothing was written
|
|
910
|
+
code: 'E_DOCS_DOCTOR_FLAG_CONFLICT',
|
|
911
|
+
message: 'docs doctor: --only and --repair cannot be combined — --repair is already scoped to ' +
|
|
912
|
+
'the legacy-blob backfill; use `--apply --only legacy-blob-coverage` instead.',
|
|
913
|
+
},
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
only = [...new Set(opts.only)].filter((c) => valid.has(c));
|
|
917
|
+
}
|
|
918
|
+
const inScope = (kind) => only === null || only.includes(kind);
|
|
919
|
+
const rebuildWikilinks = inScope('wikilinks-drift') || inScope('empty-provenance');
|
|
671
920
|
if (mutate) {
|
|
672
921
|
const refusal = checkBackupReceipt(opts.backupReceiptPath);
|
|
673
922
|
if (refusal)
|
|
674
923
|
return { ok: false, error: refusal };
|
|
675
924
|
}
|
|
676
925
|
const db = await getDb(projectRoot);
|
|
677
|
-
const
|
|
926
|
+
const checkoutRoot = opts.checkoutRoot ?? projectRoot;
|
|
927
|
+
try {
|
|
928
|
+
assertCheckoutOfProject(projectRoot, checkoutRoot);
|
|
929
|
+
}
|
|
930
|
+
catch (err) {
|
|
931
|
+
return {
|
|
932
|
+
ok: false,
|
|
933
|
+
error: {
|
|
934
|
+
// @sync-invariant none:input-shape a checkout of another repository is refused before any read or repair write
|
|
935
|
+
code: 'E_DOCS_DOCTOR_FOREIGN_CHECKOUT',
|
|
936
|
+
message: err instanceof Error ? err.message : String(err),
|
|
937
|
+
},
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
const pre = await scanStore(projectRoot, db, olderThanDays, checkoutRoot);
|
|
678
941
|
const repairs = [];
|
|
679
942
|
// T13653: in repair mode ONLY the blob backfill runs — apply mode plans it
|
|
680
943
|
// alongside the other repairs.
|
|
681
944
|
if (!repair) {
|
|
682
|
-
for (const { row, path } of pre.dangling.archivable) {
|
|
945
|
+
for (const { row, path } of inScope('dangling-pointers') ? pre.dangling.archivable : []) {
|
|
683
946
|
repairs.push({
|
|
684
947
|
kind: 'dangling-pointers',
|
|
685
948
|
action: 'archive-dangling',
|
|
@@ -689,7 +952,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
689
952
|
detail: `marked-dangling: local-file target missing (${path}) → lifecycle_status = 'archived'`,
|
|
690
953
|
});
|
|
691
954
|
}
|
|
692
|
-
for (const { row, path } of pre.dangling.clearable) {
|
|
955
|
+
for (const { row, path } of inScope('dangling-pointers') ? pre.dangling.clearable : []) {
|
|
693
956
|
repairs.push({
|
|
694
957
|
kind: 'dangling-pointers',
|
|
695
958
|
action: 'clear-stale-path',
|
|
@@ -700,7 +963,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
700
963
|
`(sha256 ${row.sha256.slice(0, 12)}…)`,
|
|
701
964
|
});
|
|
702
965
|
}
|
|
703
|
-
for (const { row, expected } of pre.skewed) {
|
|
966
|
+
for (const { row, expected } of inScope('doc-version-skew') ? pre.skewed : []) {
|
|
704
967
|
repairs.push({
|
|
705
968
|
kind: 'doc-version-skew',
|
|
706
969
|
action: 'set-doc-version',
|
|
@@ -710,7 +973,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
710
973
|
detail: `audit-note: docVersion ${row.docVersion} → ${expected} (audit log revisions + 1)`,
|
|
711
974
|
});
|
|
712
975
|
}
|
|
713
|
-
for (const { row, derived } of pre.backfillable) {
|
|
976
|
+
for (const { row, derived } of inScope('empty-provenance') ? pre.backfillable : []) {
|
|
714
977
|
const derivedCount = derived.topics.length + derived.relatedTasks.length;
|
|
715
978
|
repairs.push({
|
|
716
979
|
kind: 'empty-provenance',
|
|
@@ -723,7 +986,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
723
986
|
: 'no derivable topics or task mentions — columns stay NULL',
|
|
724
987
|
});
|
|
725
988
|
}
|
|
726
|
-
if (pre.needsWikilinksRebuild) {
|
|
989
|
+
if (pre.needsWikilinksRebuild && rebuildWikilinks) {
|
|
727
990
|
repairs.push({
|
|
728
991
|
kind: 'wikilinks-drift',
|
|
729
992
|
action: 'rebuild-wikilinks',
|
|
@@ -737,7 +1000,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
737
1000
|
// dry-run/apply mode; executed only under --apply (the --repair mode
|
|
738
1001
|
// stays the T13653 blob-backfill-only fast path). A complete doc with
|
|
739
1002
|
// unrecoverable gaps still gets an entry so the gap stays explained.
|
|
740
|
-
for (const plan of pre.conduitBackfill) {
|
|
1003
|
+
for (const plan of inScope('conduit-history-gaps') ? pre.conduitBackfill : []) {
|
|
741
1004
|
if (plan.complete && plan.gaps.length === 0)
|
|
742
1005
|
continue;
|
|
743
1006
|
if (plan.conflict) {
|
|
@@ -775,8 +1038,19 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
775
1038
|
`(chain ${plan.expectedVersions}, present ${plan.presentVersions}${gapNote}${auditNote})`,
|
|
776
1039
|
});
|
|
777
1040
|
}
|
|
1041
|
+
// T14117 — publication-ledger drift: prune protected deleted rows; every
|
|
1042
|
+
// other finding is a plan-only proposal.
|
|
1043
|
+
for (const finding of inScope('publication-ledger-drift') ? pre.ledger : []) {
|
|
1044
|
+
repairs.push({
|
|
1045
|
+
kind: 'publication-ledger-drift',
|
|
1046
|
+
action: finding.action,
|
|
1047
|
+
applied: apply && finding.prunable,
|
|
1048
|
+
detail: finding.detail,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
778
1051
|
}
|
|
779
|
-
|
|
1052
|
+
const blobBackfillable = inScope('legacy-blob-coverage') ? pre.blobBackfillable : [];
|
|
1053
|
+
for (const candidate of blobBackfillable) {
|
|
780
1054
|
repairs.push({
|
|
781
1055
|
kind: 'legacy-blob-coverage',
|
|
782
1056
|
action: 'backfill-blob-bytes',
|
|
@@ -798,7 +1072,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
798
1072
|
.map((r, i) => ({ r, i }))
|
|
799
1073
|
.filter(({ r }) => r.kind === 'legacy-blob-coverage' && r.action === 'backfill-blob-bytes')
|
|
800
1074
|
.map(({ i }) => i);
|
|
801
|
-
for (const [n, candidate] of
|
|
1075
|
+
for (const [n, candidate] of blobBackfillable.entries()) {
|
|
802
1076
|
if (candidate.sourcePath === null)
|
|
803
1077
|
continue;
|
|
804
1078
|
const outcome = await backfillBlobStoreBytes(cleoDir, candidate.sha256, candidate.sourcePath);
|
|
@@ -822,7 +1096,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
822
1096
|
// backfill above so the bytes the new rows address are mirrored first;
|
|
823
1097
|
// annotate each repair entry with its executed outcome (zip by slug).
|
|
824
1098
|
const conduitBySlug = new Map();
|
|
825
|
-
for (const plan of pre.conduitBackfill) {
|
|
1099
|
+
for (const plan of inScope('conduit-history-gaps') ? pre.conduitBackfill : []) {
|
|
826
1100
|
if (plan.toBackfill.length === 0 || plan.conflict)
|
|
827
1101
|
continue;
|
|
828
1102
|
const result = await applyConduitHistoryBackfill(projectRoot, plan);
|
|
@@ -839,14 +1113,14 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
839
1113
|
detail: `${repair.detail} → executed: ${outcome.inserted} row(s) inserted, ${outcome.gaps} gap(s)`,
|
|
840
1114
|
};
|
|
841
1115
|
}
|
|
842
|
-
for (const { row, expected } of pre.skewed) {
|
|
1116
|
+
for (const { row, expected } of inScope('doc-version-skew') ? pre.skewed : []) {
|
|
843
1117
|
await db
|
|
844
1118
|
.update(docsAttachments)
|
|
845
1119
|
.set({ docVersion: expected })
|
|
846
1120
|
.where(eq(docsAttachments.id, row.id))
|
|
847
1121
|
.run();
|
|
848
1122
|
}
|
|
849
|
-
for (const { row, derived } of pre.backfillable) {
|
|
1123
|
+
for (const { row, derived } of inScope('empty-provenance') ? pre.backfillable : []) {
|
|
850
1124
|
if (derived.topics.length + derived.relatedTasks.length === 0)
|
|
851
1125
|
continue;
|
|
852
1126
|
await db
|
|
@@ -858,14 +1132,14 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
858
1132
|
.where(eq(docsAttachments.id, row.id))
|
|
859
1133
|
.run();
|
|
860
1134
|
}
|
|
861
|
-
for (const { row } of pre.dangling.archivable) {
|
|
1135
|
+
for (const { row } of inScope('dangling-pointers') ? pre.dangling.archivable : []) {
|
|
862
1136
|
await db
|
|
863
1137
|
.update(docsAttachments)
|
|
864
1138
|
.set({ lifecycleStatus: 'archived' })
|
|
865
1139
|
.where(eq(docsAttachments.id, row.id))
|
|
866
1140
|
.run();
|
|
867
1141
|
}
|
|
868
|
-
for (const { row, payload } of pre.dangling.clearable) {
|
|
1142
|
+
for (const { row, payload } of inScope('dangling-pointers') ? pre.dangling.clearable : []) {
|
|
869
1143
|
const cleaned = { ...payload };
|
|
870
1144
|
delete cleaned['path'];
|
|
871
1145
|
await db
|
|
@@ -874,32 +1148,57 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
874
1148
|
.where(eq(docsAttachments.id, row.id))
|
|
875
1149
|
.run();
|
|
876
1150
|
}
|
|
877
|
-
if (pre.needsWikilinksRebuild) {
|
|
1151
|
+
if (pre.needsWikilinksRebuild && rebuildWikilinks) {
|
|
878
1152
|
await rebuildDocsWikilinks({ projectRoot });
|
|
879
1153
|
}
|
|
1154
|
+
const prunable = inScope('publication-ledger-drift')
|
|
1155
|
+
? pre.ledger.filter((f) => f.prunable)
|
|
1156
|
+
: [];
|
|
1157
|
+
if (prunable.length > 0) {
|
|
1158
|
+
const auditPath = join(projectRoot, DOCS_DOCTOR_LEDGER_PRUNE_AUDIT_FILE);
|
|
1159
|
+
mkdirSync(dirname(auditPath), { recursive: true });
|
|
1160
|
+
const prunedAt = new Date().toISOString();
|
|
1161
|
+
for (const finding of prunable) {
|
|
1162
|
+
// Audit first: the full row is recoverable even if the delete is interrupted.
|
|
1163
|
+
appendFileSync(auditPath, `${JSON.stringify({ op: 'docs.doctor.prune-publication', prunedAt, drift: finding.drift, outsideRoot: finding.outsideRoot, backupReceiptPath: opts.backupReceiptPath ?? null, record: finding.record })}\n`, 'utf-8');
|
|
1164
|
+
await deleteDocsPublication(projectRoot, finding.record);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
880
1167
|
}
|
|
881
1168
|
}
|
|
882
1169
|
// T13560: on a mutating run, re-scan so the envelope's diagnostics (and the
|
|
883
1170
|
// summary computed from them) describe POST-repair state, consistent with
|
|
884
1171
|
// a follow-up dry run. Dry runs keep the pre-repair scan.
|
|
885
|
-
const post = mutate ? await scanStore(projectRoot, db, olderThanDays) : pre;
|
|
1172
|
+
const post = mutate ? await scanStore(projectRoot, db, olderThanDays, checkoutRoot) : pre;
|
|
886
1173
|
const findings = post.diagnostics.reduce((sum, d) => sum + d.count, 0);
|
|
887
1174
|
// T13727 — surface the conduit backfill counts in the one-line summary so
|
|
888
1175
|
// operators see backfilled/skipped/gap per run without reading the report.
|
|
889
1176
|
const conduitActionable = pre.conduitBackfill.filter((p) => !p.complete || p.gaps.length > 0 || p.conflict);
|
|
890
1177
|
const conduitGapTotal = conduitActionable.reduce((s, p) => s + p.gaps.length, 0);
|
|
891
1178
|
const conduitConflictTotal = conduitActionable.filter((p) => p.conflict).length;
|
|
892
|
-
const conduitBackfillNote = repair || conduitActionable.length === 0
|
|
1179
|
+
const conduitBackfillNote = repair || !inScope('conduit-history-gaps') || conduitActionable.length === 0
|
|
893
1180
|
? ''
|
|
894
1181
|
: apply
|
|
895
1182
|
? `; conduit history: ${conduitActionable.reduce((s, p) => s + p.toBackfill.length, 0)} version(s) backfilled across ${conduitActionable.length} doc(s) (${conduitGapTotal} gap(s) unrecoverable, ${conduitConflictTotal} conflict(s))`
|
|
896
1183
|
: `; conduit history: ${conduitActionable.length} doc(s) need attention (${conduitActionable.reduce((s, p) => s + p.toBackfill.length, 0)} version(s) to backfill, ${conduitGapTotal} gap(s) unrecoverable, ${conduitConflictTotal} conflict(s))`;
|
|
1184
|
+
const repairCounts = {};
|
|
1185
|
+
for (const r of repairs) {
|
|
1186
|
+
const kind = r.kind;
|
|
1187
|
+
if (!isRepairClass(kind))
|
|
1188
|
+
continue;
|
|
1189
|
+
const entry = repairCounts[kind] ?? { planned: 0, applied: 0 };
|
|
1190
|
+
entry.planned += 1;
|
|
1191
|
+
if (r.applied)
|
|
1192
|
+
entry.applied += 1;
|
|
1193
|
+
repairCounts[kind] = entry;
|
|
1194
|
+
}
|
|
1195
|
+
const scopeNote = only === null ? '' : ` (only: ${only.join(', ')})`;
|
|
897
1196
|
const summary = repair
|
|
898
1197
|
? `docs doctor repaired ${repairs.filter((r) => r.applied).length} blob backfill(s); ` +
|
|
899
1198
|
`${post.diagnostics.find((d) => d.kind === 'legacy-blob-coverage')?.count ?? 0} sha(s) still missing post-repair`
|
|
900
1199
|
: apply
|
|
901
|
-
? `docs doctor applied ${repairs.filter((r) => r.applied).length} repair(s); ${findings} finding(s) remain post-repair${conduitBackfillNote}`
|
|
902
|
-
: `docs doctor found ${findings} finding(s); ${repairs.length} repair(s) planned (dry-run — pass --apply to execute)${conduitBackfillNote}`;
|
|
1200
|
+
? `docs doctor applied ${repairs.filter((r) => r.applied).length} repair(s)${scopeNote}; ${findings} finding(s) remain post-repair${conduitBackfillNote}`
|
|
1201
|
+
: `docs doctor found ${findings} finding(s); ${repairs.length} repair(s) planned${scopeNote} (dry-run — pass --apply to execute)${conduitBackfillNote}`;
|
|
903
1202
|
return {
|
|
904
1203
|
ok: true,
|
|
905
1204
|
report: {
|
|
@@ -908,6 +1207,8 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
|
|
|
908
1207
|
backupReceiptPath: mutate ? (opts.backupReceiptPath ?? null) : null,
|
|
909
1208
|
diagnostics: post.diagnostics,
|
|
910
1209
|
repairs,
|
|
1210
|
+
repairCounts,
|
|
1211
|
+
only,
|
|
911
1212
|
summary,
|
|
912
1213
|
},
|
|
913
1214
|
};
|