@cleocode/core 2026.4.7 → 2026.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/adapter-registry.js +64 -0
- package/dist/adapters/adapter-registry.js.map +1 -0
- package/dist/adapters/discovery.js +83 -0
- package/dist/adapters/discovery.js.map +1 -0
- package/dist/adapters/index.js +9 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/manager.js +260 -0
- package/dist/adapters/manager.js.map +1 -0
- package/dist/admin/export-tasks.js +171 -0
- package/dist/admin/export-tasks.js.map +1 -0
- package/dist/admin/export.js +103 -0
- package/dist/admin/export.js.map +1 -0
- package/dist/admin/help.js +106 -0
- package/dist/admin/help.js.map +1 -0
- package/dist/admin/import-tasks.js +182 -0
- package/dist/admin/import-tasks.js.map +1 -0
- package/dist/admin/import.js +129 -0
- package/dist/admin/import.js.map +1 -0
- package/dist/admin/index.js +13 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/adrs/find.js +134 -0
- package/dist/adrs/find.js.map +1 -0
- package/dist/adrs/index.js +15 -0
- package/dist/adrs/index.js.map +1 -0
- package/dist/adrs/link-pipeline.js +160 -0
- package/dist/adrs/link-pipeline.js.map +1 -0
- package/dist/adrs/list.js +43 -0
- package/dist/adrs/list.js.map +1 -0
- package/dist/adrs/parse.js +51 -0
- package/dist/adrs/parse.js.map +1 -0
- package/dist/adrs/show.js +22 -0
- package/dist/adrs/show.js.map +1 -0
- package/dist/adrs/sync.js +188 -0
- package/dist/adrs/sync.js.map +1 -0
- package/dist/adrs/types.js +9 -0
- package/dist/adrs/types.js.map +1 -0
- package/dist/adrs/validate.js +57 -0
- package/dist/adrs/validate.js.map +1 -0
- package/dist/agents/agent-registry.js +288 -0
- package/dist/agents/agent-registry.js.map +1 -0
- package/dist/agents/agent-schema.d.ts +2 -2
- package/dist/agents/agent-schema.js +82 -0
- package/dist/agents/agent-schema.js.map +1 -0
- package/dist/agents/capacity.js +116 -0
- package/dist/agents/capacity.js.map +1 -0
- package/dist/agents/execution-learning.js +474 -0
- package/dist/agents/execution-learning.js.map +1 -0
- package/dist/agents/health-monitor.js +217 -0
- package/dist/agents/health-monitor.js.map +1 -0
- package/dist/agents/index.js +29 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/registry.js +314 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/retry.js +215 -0
- package/dist/agents/retry.js.map +1 -0
- package/dist/audit-prune.js +94 -0
- package/dist/audit-prune.js.map +1 -0
- package/dist/audit.js +68 -0
- package/dist/audit.js.map +1 -0
- package/dist/backfill/index.js +229 -0
- package/dist/backfill/index.js.map +1 -0
- package/dist/bootstrap.js +344 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/caamp/adapter.js +259 -0
- package/dist/caamp/adapter.js.map +1 -0
- package/dist/caamp/capability-check.js +38 -0
- package/dist/caamp/capability-check.js.map +1 -0
- package/dist/caamp/index.js +21 -0
- package/dist/caamp/index.js.map +1 -0
- package/dist/caamp-init.js +16 -0
- package/dist/caamp-init.js.map +1 -0
- package/dist/cleo.js +322 -0
- package/dist/cleo.js.map +1 -0
- package/dist/code/index.js +10 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code/outline.js +165 -0
- package/dist/code/outline.js.map +1 -0
- package/dist/code/parser.js +295 -0
- package/dist/code/parser.js.map +1 -0
- package/dist/code/search.js +135 -0
- package/dist/code/search.js.map +1 -0
- package/dist/code/unfold.js +155 -0
- package/dist/code/unfold.js.map +1 -0
- package/dist/codebase-map/analyzers/architecture.js +130 -0
- package/dist/codebase-map/analyzers/architecture.js.map +1 -0
- package/dist/codebase-map/analyzers/concerns.js +122 -0
- package/dist/codebase-map/analyzers/concerns.js.map +1 -0
- package/dist/codebase-map/analyzers/conventions.js +149 -0
- package/dist/codebase-map/analyzers/conventions.js.map +1 -0
- package/dist/codebase-map/analyzers/integrations.js +108 -0
- package/dist/codebase-map/analyzers/integrations.js.map +1 -0
- package/dist/codebase-map/analyzers/stack.js +117 -0
- package/dist/codebase-map/analyzers/stack.js.map +1 -0
- package/dist/codebase-map/analyzers/structure.js +137 -0
- package/dist/codebase-map/analyzers/structure.js.map +1 -0
- package/dist/codebase-map/analyzers/testing.js +118 -0
- package/dist/codebase-map/analyzers/testing.js.map +1 -0
- package/dist/codebase-map/index.js +57 -0
- package/dist/codebase-map/index.js.map +1 -0
- package/dist/codebase-map/store.js +122 -0
- package/dist/codebase-map/store.js.map +1 -0
- package/dist/codebase-map/summary.js +152 -0
- package/dist/codebase-map/summary.js.map +1 -0
- package/dist/compliance/index.js +288 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/compliance/protocol-enforcement.js +332 -0
- package/dist/compliance/protocol-enforcement.js.map +1 -0
- package/dist/compliance/protocol-rules.js +786 -0
- package/dist/compliance/protocol-rules.js.map +1 -0
- package/dist/compliance/protocol-types.js +79 -0
- package/dist/compliance/protocol-types.js.map +1 -0
- package/dist/compliance/store.js +53 -0
- package/dist/compliance/store.js.map +1 -0
- package/dist/conduit/conduit-client.js +107 -0
- package/dist/conduit/conduit-client.js.map +1 -0
- package/dist/conduit/factory.js +52 -0
- package/dist/conduit/factory.js.map +1 -0
- package/dist/conduit/http-transport.js +155 -0
- package/dist/conduit/http-transport.js.map +1 -0
- package/dist/conduit/index.js +15 -0
- package/dist/conduit/index.js.map +1 -0
- package/dist/conduit/local-transport.js +245 -0
- package/dist/conduit/local-transport.js.map +1 -0
- package/dist/conduit/sse-transport.js +299 -0
- package/dist/conduit/sse-transport.js.map +1 -0
- package/dist/config/build-config.js +29 -0
- package/dist/config/build-config.js.map +1 -0
- package/dist/config.js +401 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.js +18 -0
- package/dist/constants.js.map +1 -0
- package/dist/context/index.js +137 -0
- package/dist/context/index.js.map +1 -0
- package/dist/crypto/credentials.js +191 -0
- package/dist/crypto/credentials.js.map +1 -0
- package/dist/discovery.js +182 -0
- package/dist/discovery.js.map +1 -0
- package/dist/engine-result.js +12 -0
- package/dist/engine-result.js.map +1 -0
- package/dist/error-catalog.js +404 -0
- package/dist/error-catalog.js.map +1 -0
- package/dist/error-registry.js +393 -0
- package/dist/error-registry.js.map +1 -0
- package/dist/errors.js +167 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks/handlers/agent-hooks.js +106 -0
- package/dist/hooks/handlers/agent-hooks.js.map +1 -0
- package/dist/hooks/handlers/context-hooks.js +111 -0
- package/dist/hooks/handlers/context-hooks.js.map +1 -0
- package/dist/hooks/handlers/error-hooks.js +52 -0
- package/dist/hooks/handlers/error-hooks.js.map +1 -0
- package/dist/hooks/handlers/file-hooks.js +104 -0
- package/dist/hooks/handlers/file-hooks.js.map +1 -0
- package/dist/hooks/handlers/handler-helpers.js +61 -0
- package/dist/hooks/handlers/handler-helpers.js.map +1 -0
- package/dist/hooks/handlers/index.js +28 -0
- package/dist/hooks/handlers/index.js.map +1 -0
- package/dist/hooks/handlers/memory-bridge-refresh.js +42 -0
- package/dist/hooks/handlers/memory-bridge-refresh.js.map +1 -0
- package/dist/hooks/handlers/notification-hooks.js +62 -0
- package/dist/hooks/handlers/notification-hooks.js.map +1 -0
- package/dist/hooks/handlers/session-hooks.d.ts +21 -0
- package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/session-hooks.js +142 -0
- package/dist/hooks/handlers/session-hooks.js.map +1 -0
- package/dist/hooks/handlers/task-hooks.js +65 -0
- package/dist/hooks/handlers/task-hooks.js.map +1 -0
- package/dist/hooks/handlers/work-capture-hooks.js +165 -0
- package/dist/hooks/handlers/work-capture-hooks.js.map +1 -0
- package/dist/hooks/index.js +13 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/payload-schemas.d.ts +2 -2
- package/dist/hooks/payload-schemas.js +220 -0
- package/dist/hooks/payload-schemas.js.map +1 -0
- package/dist/hooks/provider-hooks.js +66 -0
- package/dist/hooks/provider-hooks.js.map +1 -0
- package/dist/hooks/registry.js +229 -0
- package/dist/hooks/registry.js.map +1 -0
- package/dist/hooks/types.js +66 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/hooks.js +136 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.js +3361 -3095
- package/dist/index.js.map +4 -4
- package/dist/init.js +852 -0
- package/dist/init.js.map +1 -0
- package/dist/inject/index.js +82 -0
- package/dist/inject/index.js.map +1 -0
- package/dist/injection.js +343 -0
- package/dist/injection.js.map +1 -0
- package/dist/intelligence/adaptive-validation.js +497 -0
- package/dist/intelligence/adaptive-validation.js.map +1 -0
- package/dist/intelligence/impact.js +675 -0
- package/dist/intelligence/impact.js.map +1 -0
- package/dist/intelligence/index.js +22 -0
- package/dist/intelligence/index.js.map +1 -0
- package/dist/intelligence/patterns.js +492 -0
- package/dist/intelligence/patterns.js.map +1 -0
- package/dist/intelligence/prediction.js +499 -0
- package/dist/intelligence/prediction.js.map +1 -0
- package/dist/intelligence/types.js +13 -0
- package/dist/intelligence/types.js.map +1 -0
- package/dist/internal.d.ts +7 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +299 -0
- package/dist/internal.js.map +1 -0
- package/dist/issue/create.js +121 -0
- package/dist/issue/create.js.map +1 -0
- package/dist/issue/diagnostics.js +59 -0
- package/dist/issue/diagnostics.js.map +1 -0
- package/dist/issue/index.js +10 -0
- package/dist/issue/index.js.map +1 -0
- package/dist/issue/template-parser.js +267 -0
- package/dist/issue/template-parser.js.map +1 -0
- package/dist/json-schema-validator.js +76 -0
- package/dist/json-schema-validator.js.map +1 -0
- package/dist/lib/index.js +11 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/retry.js +152 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/tree-sitter-languages.js +71 -0
- package/dist/lib/tree-sitter-languages.js.map +1 -0
- package/dist/lifecycle/chain-composition.js +152 -0
- package/dist/lifecycle/chain-composition.js.map +1 -0
- package/dist/lifecycle/chain-store.js +246 -0
- package/dist/lifecycle/chain-store.js.map +1 -0
- package/dist/lifecycle/consolidate-rcasd.js +352 -0
- package/dist/lifecycle/consolidate-rcasd.js.map +1 -0
- package/dist/lifecycle/default-chain.js +176 -0
- package/dist/lifecycle/default-chain.js.map +1 -0
- package/dist/lifecycle/evidence.js +180 -0
- package/dist/lifecycle/evidence.js.map +1 -0
- package/dist/lifecycle/frontmatter.js +363 -0
- package/dist/lifecycle/frontmatter.js.map +1 -0
- package/dist/lifecycle/index.js +756 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/pipeline.js +656 -0
- package/dist/lifecycle/pipeline.js.map +1 -0
- package/dist/lifecycle/rcasd-index.js +326 -0
- package/dist/lifecycle/rcasd-index.js.map +1 -0
- package/dist/lifecycle/rcasd-paths.js +220 -0
- package/dist/lifecycle/rcasd-paths.js.map +1 -0
- package/dist/lifecycle/resume.js +864 -0
- package/dist/lifecycle/resume.js.map +1 -0
- package/dist/lifecycle/stage-artifacts.js +94 -0
- package/dist/lifecycle/stage-artifacts.js.map +1 -0
- package/dist/lifecycle/stage-guidance.js +234 -0
- package/dist/lifecycle/stage-guidance.js.map +1 -0
- package/dist/lifecycle/stages.js +534 -0
- package/dist/lifecycle/stages.js.map +1 -0
- package/dist/lifecycle/state-machine.js +516 -0
- package/dist/lifecycle/state-machine.js.map +1 -0
- package/dist/lifecycle/tessera-engine.js +249 -0
- package/dist/lifecycle/tessera-engine.js.map +1 -0
- package/dist/logger.js +140 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/auto-extract.js +177 -0
- package/dist/memory/auto-extract.js.map +1 -0
- package/dist/memory/brain-embedding.js +66 -0
- package/dist/memory/brain-embedding.js.map +1 -0
- package/dist/memory/brain-lifecycle.js +298 -0
- package/dist/memory/brain-lifecycle.js.map +1 -0
- package/dist/memory/brain-links.js +161 -0
- package/dist/memory/brain-links.js.map +1 -0
- package/dist/memory/brain-maintenance.js +114 -0
- package/dist/memory/brain-maintenance.js.map +1 -0
- package/dist/memory/brain-migration.js +149 -0
- package/dist/memory/brain-migration.js.map +1 -0
- package/dist/memory/brain-reasoning.js +215 -0
- package/dist/memory/brain-reasoning.js.map +1 -0
- package/dist/memory/brain-retrieval.js +542 -0
- package/dist/memory/brain-retrieval.js.map +1 -0
- package/dist/memory/brain-row-types.js +10 -0
- package/dist/memory/brain-row-types.js.map +1 -0
- package/dist/memory/brain-search.js +519 -0
- package/dist/memory/brain-search.js.map +1 -0
- package/dist/memory/brain-similarity.js +145 -0
- package/dist/memory/brain-similarity.js.map +1 -0
- package/dist/memory/claude-mem-migration.js +277 -0
- package/dist/memory/claude-mem-migration.js.map +1 -0
- package/dist/memory/decisions.js +162 -0
- package/dist/memory/decisions.js.map +1 -0
- package/dist/memory/embedding-local.js +97 -0
- package/dist/memory/embedding-local.js.map +1 -0
- package/dist/memory/embedding-queue.js +271 -0
- package/dist/memory/embedding-queue.js.map +1 -0
- package/dist/memory/embedding-worker.js +58 -0
- package/dist/memory/embedding-worker.js.map +1 -0
- package/dist/memory/engine-compat.js +1397 -0
- package/dist/memory/engine-compat.js.map +1 -0
- package/dist/memory/index.js +1140 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/learnings.d.ts +4 -4
- package/dist/memory/learnings.js +121 -0
- package/dist/memory/learnings.js.map +1 -0
- package/dist/memory/memory-bridge.js +370 -0
- package/dist/memory/memory-bridge.js.map +1 -0
- package/dist/memory/patterns.d.ts +6 -6
- package/dist/memory/patterns.js +122 -0
- package/dist/memory/patterns.js.map +1 -0
- package/dist/memory/pipeline-manifest-sqlite.js +975 -0
- package/dist/memory/pipeline-manifest-sqlite.js.map +1 -0
- package/dist/memory/session-memory.js +331 -0
- package/dist/memory/session-memory.js.map +1 -0
- package/dist/metrics/ab-test.js +260 -0
- package/dist/metrics/ab-test.js.map +1 -0
- package/dist/metrics/aggregation.js +363 -0
- package/dist/metrics/aggregation.js.map +1 -0
- package/dist/metrics/common.js +64 -0
- package/dist/metrics/common.js.map +1 -0
- package/dist/metrics/enums.js +78 -0
- package/dist/metrics/enums.js.map +1 -0
- package/dist/metrics/index.js +19 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/model-provider-registry.js +88 -0
- package/dist/metrics/model-provider-registry.js.map +1 -0
- package/dist/metrics/otel-integration.js +263 -0
- package/dist/metrics/otel-integration.js.map +1 -0
- package/dist/metrics/provider-detection.js +103 -0
- package/dist/metrics/provider-detection.js.map +1 -0
- package/dist/metrics/token-estimation.js +253 -0
- package/dist/metrics/token-estimation.js.map +1 -0
- package/dist/metrics/token-service.js +450 -0
- package/dist/metrics/token-service.js.map +1 -0
- package/dist/migration/agent-outputs.js +316 -0
- package/dist/migration/agent-outputs.js.map +1 -0
- package/dist/migration/checksum.js +92 -0
- package/dist/migration/checksum.js.map +1 -0
- package/dist/migration/index.js +282 -0
- package/dist/migration/index.js.map +1 -0
- package/dist/migration/logger.js +360 -0
- package/dist/migration/logger.js.map +1 -0
- package/dist/migration/preflight.js +9 -0
- package/dist/migration/preflight.js.map +1 -0
- package/dist/migration/state.js +421 -0
- package/dist/migration/state.js.map +1 -0
- package/dist/migration/validate.js +241 -0
- package/dist/migration/validate.js.map +1 -0
- package/dist/mvi-helpers.js +74 -0
- package/dist/mvi-helpers.js.map +1 -0
- package/dist/nexus/deps.js +375 -0
- package/dist/nexus/deps.js.map +1 -0
- package/dist/nexus/discover.js +288 -0
- package/dist/nexus/discover.js.map +1 -0
- package/dist/nexus/hash.js +10 -0
- package/dist/nexus/hash.js.map +1 -0
- package/dist/nexus/index.js +40 -0
- package/dist/nexus/index.js.map +1 -0
- package/dist/nexus/migrate-json-to-sqlite.js +115 -0
- package/dist/nexus/migrate-json-to-sqlite.js.map +1 -0
- package/dist/nexus/permissions.js +105 -0
- package/dist/nexus/permissions.js.map +1 -0
- package/dist/nexus/query.js +175 -0
- package/dist/nexus/query.js.map +1 -0
- package/dist/nexus/registry.js +584 -0
- package/dist/nexus/registry.js.map +1 -0
- package/dist/nexus/sharing/index.js +288 -0
- package/dist/nexus/sharing/index.js.map +1 -0
- package/dist/nexus/transfer-types.js +8 -0
- package/dist/nexus/transfer-types.js.map +1 -0
- package/dist/nexus/transfer.js +263 -0
- package/dist/nexus/transfer.js.map +1 -0
- package/dist/nexus/workspace.js +355 -0
- package/dist/nexus/workspace.js.map +1 -0
- package/dist/observability/index.js +103 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/log-filter.js +63 -0
- package/dist/observability/log-filter.js.map +1 -0
- package/dist/observability/log-parser.js +99 -0
- package/dist/observability/log-parser.js.map +1 -0
- package/dist/observability/log-reader.js +139 -0
- package/dist/observability/log-reader.js.map +1 -0
- package/dist/observability/types.js +19 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/orchestration/analyze.js +107 -0
- package/dist/orchestration/analyze.js.map +1 -0
- package/dist/orchestration/bootstrap.js +132 -0
- package/dist/orchestration/bootstrap.js.map +1 -0
- package/dist/orchestration/context.js +56 -0
- package/dist/orchestration/context.js.map +1 -0
- package/dist/orchestration/critical-path.js +100 -0
- package/dist/orchestration/critical-path.js.map +1 -0
- package/dist/orchestration/hierarchy.js +183 -0
- package/dist/orchestration/hierarchy.js.map +1 -0
- package/dist/orchestration/index.js +287 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/parallel.js +89 -0
- package/dist/orchestration/parallel.js.map +1 -0
- package/dist/orchestration/protocol-validators.js +815 -0
- package/dist/orchestration/protocol-validators.js.map +1 -0
- package/dist/orchestration/skill-ops.js +98 -0
- package/dist/orchestration/skill-ops.js.map +1 -0
- package/dist/orchestration/status.js +107 -0
- package/dist/orchestration/status.js.map +1 -0
- package/dist/orchestration/unblock.js +103 -0
- package/dist/orchestration/unblock.js.map +1 -0
- package/dist/orchestration/validate-spawn.js +67 -0
- package/dist/orchestration/validate-spawn.js.map +1 -0
- package/dist/orchestration/waves.js +86 -0
- package/dist/orchestration/waves.js.map +1 -0
- package/dist/otel/index.js +163 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/output.js +164 -0
- package/dist/output.js.map +1 -0
- package/dist/pagination.js +64 -0
- package/dist/pagination.js.map +1 -0
- package/dist/paths.d.ts +39 -9
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +776 -0
- package/dist/paths.js.map +1 -0
- package/dist/phases/deps.js +372 -0
- package/dist/phases/deps.js.map +1 -0
- package/dist/phases/index.js +349 -0
- package/dist/phases/index.js.map +1 -0
- package/dist/pipeline/index.js +10 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/phase.js +45 -0
- package/dist/pipeline/phase.js.map +1 -0
- package/dist/platform.js +211 -0
- package/dist/platform.js.map +1 -0
- package/dist/project-info.js +84 -0
- package/dist/project-info.js.map +1 -0
- package/dist/reconciliation/index.js +10 -0
- package/dist/reconciliation/index.js.map +1 -0
- package/dist/reconciliation/link-store.js +129 -0
- package/dist/reconciliation/link-store.js.map +1 -0
- package/dist/reconciliation/reconciliation-engine.js +298 -0
- package/dist/reconciliation/reconciliation-engine.js.map +1 -0
- package/dist/release/artifacts.js +427 -0
- package/dist/release/artifacts.js.map +1 -0
- package/dist/release/changelog-writer.js +151 -0
- package/dist/release/changelog-writer.js.map +1 -0
- package/dist/release/channel.js +144 -0
- package/dist/release/channel.js.map +1 -0
- package/dist/release/ci.js +166 -0
- package/dist/release/ci.js.map +1 -0
- package/dist/release/github-pr.js +225 -0
- package/dist/release/github-pr.js.map +1 -0
- package/dist/release/guards.js +116 -0
- package/dist/release/guards.js.map +1 -0
- package/dist/release/index.js +22 -0
- package/dist/release/index.js.map +1 -0
- package/dist/release/release-config.js +158 -0
- package/dist/release/release-config.js.map +1 -0
- package/dist/release/release-manifest.js +1019 -0
- package/dist/release/release-manifest.js.map +1 -0
- package/dist/release/version-bump.js +255 -0
- package/dist/release/version-bump.js.map +1 -0
- package/dist/remote/index.js +257 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/repair.js +130 -0
- package/dist/repair.js.map +1 -0
- package/dist/research/index.js +2 -0
- package/dist/research/index.js.map +1 -0
- package/dist/roadmap/index.js +59 -0
- package/dist/roadmap/index.js.map +1 -0
- package/dist/routing/capability-matrix.js +1556 -0
- package/dist/routing/capability-matrix.js.map +1 -0
- package/dist/routing/index.js +9 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/scaffold.d.ts +15 -2
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +1759 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/schema-management.js +295 -0
- package/dist/schema-management.js.map +1 -0
- package/dist/security/index.js +9 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/input-sanitization.js +321 -0
- package/dist/security/input-sanitization.js.map +1 -0
- package/dist/sequence/index.js +295 -0
- package/dist/sequence/index.js.map +1 -0
- package/dist/sessions/assumptions.js +54 -0
- package/dist/sessions/assumptions.js.map +1 -0
- package/dist/sessions/briefing.js +377 -0
- package/dist/sessions/briefing.js.map +1 -0
- package/dist/sessions/context-alert.js +222 -0
- package/dist/sessions/context-alert.js.map +1 -0
- package/dist/sessions/context-inject.js +61 -0
- package/dist/sessions/context-inject.js.map +1 -0
- package/dist/sessions/context-monitor.js +98 -0
- package/dist/sessions/context-monitor.js.map +1 -0
- package/dist/sessions/decisions.js +65 -0
- package/dist/sessions/decisions.js.map +1 -0
- package/dist/sessions/find.js +65 -0
- package/dist/sessions/find.js.map +1 -0
- package/dist/sessions/handoff.js +328 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/hitl-warnings.js +254 -0
- package/dist/sessions/hitl-warnings.js.map +1 -0
- package/dist/sessions/index.js +327 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/session-archive.js +40 -0
- package/dist/sessions/session-archive.js.map +1 -0
- package/dist/sessions/session-cleanup.js +59 -0
- package/dist/sessions/session-cleanup.js.map +1 -0
- package/dist/sessions/session-drift.js +134 -0
- package/dist/sessions/session-drift.js.map +1 -0
- package/dist/sessions/session-enforcement.js +144 -0
- package/dist/sessions/session-enforcement.js.map +1 -0
- package/dist/sessions/session-grade.js +253 -0
- package/dist/sessions/session-grade.js.map +1 -0
- package/dist/sessions/session-history.js +42 -0
- package/dist/sessions/session-history.js.map +1 -0
- package/dist/sessions/session-id.js +81 -0
- package/dist/sessions/session-id.js.map +1 -0
- package/dist/sessions/session-memory-bridge.js +52 -0
- package/dist/sessions/session-memory-bridge.js.map +1 -0
- package/dist/sessions/session-show.js +24 -0
- package/dist/sessions/session-show.js.map +1 -0
- package/dist/sessions/session-stats.js +69 -0
- package/dist/sessions/session-stats.js.map +1 -0
- package/dist/sessions/session-suspend.js +39 -0
- package/dist/sessions/session-suspend.js.map +1 -0
- package/dist/sessions/session-switch.js +51 -0
- package/dist/sessions/session-switch.js.map +1 -0
- package/dist/sessions/session-view.js +76 -0
- package/dist/sessions/session-view.js.map +1 -0
- package/dist/sessions/snapshot.js +213 -0
- package/dist/sessions/snapshot.js.map +1 -0
- package/dist/sessions/statusline-setup.js +85 -0
- package/dist/sessions/statusline-setup.js.map +1 -0
- package/dist/sessions/types.js +8 -0
- package/dist/sessions/types.js.map +1 -0
- package/dist/skills/agents/config.js +94 -0
- package/dist/skills/agents/config.js.map +1 -0
- package/dist/skills/agents/install.js +116 -0
- package/dist/skills/agents/install.js.map +1 -0
- package/dist/skills/agents/registry.js +161 -0
- package/dist/skills/agents/registry.js.map +1 -0
- package/dist/skills/discovery.js +333 -0
- package/dist/skills/discovery.js.map +1 -0
- package/dist/skills/dispatch.js +347 -0
- package/dist/skills/dispatch.js.map +1 -0
- package/dist/skills/dynamic-skill-generator.js +87 -0
- package/dist/skills/dynamic-skill-generator.js.map +1 -0
- package/dist/skills/index.js +44 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/injection/subagent.js +195 -0
- package/dist/skills/injection/subagent.js.map +1 -0
- package/dist/skills/injection/token.js +260 -0
- package/dist/skills/injection/token.js.map +1 -0
- package/dist/skills/install.js +40 -0
- package/dist/skills/install.js.map +1 -0
- package/dist/skills/manifests/contribution.js +175 -0
- package/dist/skills/manifests/contribution.js.map +1 -0
- package/dist/skills/manifests/research.js +281 -0
- package/dist/skills/manifests/research.js.map +1 -0
- package/dist/skills/manifests/resolver.js +146 -0
- package/dist/skills/manifests/resolver.js.map +1 -0
- package/dist/skills/marketplace.js +90 -0
- package/dist/skills/marketplace.js.map +1 -0
- package/dist/skills/orchestrator/spawn.js +178 -0
- package/dist/skills/orchestrator/spawn.js.map +1 -0
- package/dist/skills/orchestrator/startup.js +451 -0
- package/dist/skills/orchestrator/startup.js.map +1 -0
- package/dist/skills/orchestrator/validator.js +301 -0
- package/dist/skills/orchestrator/validator.js.map +1 -0
- package/dist/skills/precedence-integration.js +73 -0
- package/dist/skills/precedence-integration.js.map +1 -0
- package/dist/skills/precedence-types.js +16 -0
- package/dist/skills/precedence-types.js.map +1 -0
- package/dist/skills/routing-table.js +63 -0
- package/dist/skills/routing-table.js.map +1 -0
- package/dist/skills/skill-paths.js +217 -0
- package/dist/skills/skill-paths.js.map +1 -0
- package/dist/skills/test-utility.js +55 -0
- package/dist/skills/test-utility.js.map +1 -0
- package/dist/skills/types.js +118 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/skills/validation.js +183 -0
- package/dist/skills/validation.js.map +1 -0
- package/dist/skills/version.js +57 -0
- package/dist/skills/version.js.map +1 -0
- package/dist/snapshot/index.js +188 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/spawn/adapter-registry.js +246 -0
- package/dist/spawn/adapter-registry.js.map +1 -0
- package/dist/spawn/index.js +10 -0
- package/dist/spawn/index.js.map +1 -0
- package/dist/stats/index.js +343 -0
- package/dist/stats/index.js.map +1 -0
- package/dist/stats/workflow-telemetry.js +400 -0
- package/dist/stats/workflow-telemetry.js.map +1 -0
- package/dist/sticky/archive.js +47 -0
- package/dist/sticky/archive.js.map +1 -0
- package/dist/sticky/convert.js +235 -0
- package/dist/sticky/convert.js.map +1 -0
- package/dist/sticky/create.js +48 -0
- package/dist/sticky/create.js.map +1 -0
- package/dist/sticky/id.js +35 -0
- package/dist/sticky/id.js.map +1 -0
- package/dist/sticky/index.js +16 -0
- package/dist/sticky/index.js.map +1 -0
- package/dist/sticky/list.js +44 -0
- package/dist/sticky/list.js.map +1 -0
- package/dist/sticky/purge.js +45 -0
- package/dist/sticky/purge.js.map +1 -0
- package/dist/sticky/show.js +42 -0
- package/dist/sticky/show.js.map +1 -0
- package/dist/sticky/types.js +10 -0
- package/dist/sticky/types.js.map +1 -0
- package/dist/store/agent-registry-accessor.js +265 -0
- package/dist/store/agent-registry-accessor.js.map +1 -0
- package/dist/store/atomic.js +167 -0
- package/dist/store/atomic.js.map +1 -0
- package/dist/store/backup.js +94 -0
- package/dist/store/backup.js.map +1 -0
- package/dist/store/brain-accessor.js +397 -0
- package/dist/store/brain-accessor.js.map +1 -0
- package/dist/store/brain-schema.d.ts +8 -8
- package/dist/store/brain-schema.js +215 -0
- package/dist/store/brain-schema.js.map +1 -0
- package/dist/store/brain-sqlite.js +222 -0
- package/dist/store/brain-sqlite.js.map +1 -0
- package/dist/store/cache.js +168 -0
- package/dist/store/cache.js.map +1 -0
- package/dist/store/chain-schema.js +51 -0
- package/dist/store/chain-schema.js.map +1 -0
- package/dist/store/cleanup-legacy.d.ts +128 -0
- package/dist/store/cleanup-legacy.d.ts.map +1 -0
- package/dist/store/converters.js +124 -0
- package/dist/store/converters.js.map +1 -0
- package/dist/store/cross-db-cleanup.js +319 -0
- package/dist/store/cross-db-cleanup.js.map +1 -0
- package/dist/store/data-accessor.js +26 -0
- package/dist/store/data-accessor.js.map +1 -0
- package/dist/store/data-safety-central.js +269 -0
- package/dist/store/data-safety-central.js.map +1 -0
- package/dist/store/data-safety.js +274 -0
- package/dist/store/data-safety.js.map +1 -0
- package/dist/store/db-helpers.js +224 -0
- package/dist/store/db-helpers.js.map +1 -0
- package/dist/store/export.js +155 -0
- package/dist/store/export.js.map +1 -0
- package/dist/store/file-utils.js +270 -0
- package/dist/store/file-utils.js.map +1 -0
- package/dist/store/git-checkpoint.js +365 -0
- package/dist/store/git-checkpoint.js.map +1 -0
- package/dist/store/import-logging.js +139 -0
- package/dist/store/import-logging.js.map +1 -0
- package/dist/store/import-remap.js +145 -0
- package/dist/store/import-remap.js.map +1 -0
- package/dist/store/import-sort.js +121 -0
- package/dist/store/import-sort.js.map +1 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +29 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/json.js +208 -0
- package/dist/store/json.js.map +1 -0
- package/dist/store/lifecycle-store.js +249 -0
- package/dist/store/lifecycle-store.js.map +1 -0
- package/dist/store/lock.js +70 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/migration-manager.js +151 -0
- package/dist/store/migration-manager.js.map +1 -0
- package/dist/store/migration-sqlite.js +676 -0
- package/dist/store/migration-sqlite.js.map +1 -0
- package/dist/store/nexus-schema.js +62 -0
- package/dist/store/nexus-schema.js.map +1 -0
- package/dist/store/nexus-sqlite.d.ts +14 -2
- package/dist/store/nexus-sqlite.d.ts.map +1 -1
- package/dist/store/nexus-sqlite.js +217 -0
- package/dist/store/nexus-sqlite.js.map +1 -0
- package/dist/store/nexus-validation-schemas.js +40 -0
- package/dist/store/nexus-validation-schemas.js.map +1 -0
- package/dist/store/parsers.js +37 -0
- package/dist/store/parsers.js.map +1 -0
- package/dist/store/project-detect.js +457 -0
- package/dist/store/project-detect.js.map +1 -0
- package/dist/store/provider.js +101 -0
- package/dist/store/provider.js.map +1 -0
- package/dist/store/safety-data-accessor.js +257 -0
- package/dist/store/safety-data-accessor.js.map +1 -0
- package/dist/store/schema.js +7 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store/session-store.js +219 -0
- package/dist/store/session-store.js.map +1 -0
- package/dist/store/signaldock-sqlite.js +400 -0
- package/dist/store/signaldock-sqlite.js.map +1 -0
- package/dist/store/sqlite-backup.d.ts +121 -10
- package/dist/store/sqlite-backup.d.ts.map +1 -1
- package/dist/store/sqlite-backup.js +241 -0
- package/dist/store/sqlite-backup.js.map +1 -0
- package/dist/store/sqlite-data-accessor.js +787 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +481 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/status-registry.js +8 -0
- package/dist/store/status-registry.js.map +1 -0
- package/dist/store/task-store.js +358 -0
- package/dist/store/task-store.js.map +1 -0
- package/dist/store/tasks-schema.d.ts +8 -8
- package/dist/store/tasks-schema.js +610 -0
- package/dist/store/tasks-schema.js.map +1 -0
- package/dist/store/typed-query.js +15 -0
- package/dist/store/typed-query.js.map +1 -0
- package/dist/store/validation-schemas.d.ts +37 -37
- package/dist/store/validation-schemas.js +278 -0
- package/dist/store/validation-schemas.js.map +1 -0
- package/dist/system/archive-analytics.js +277 -0
- package/dist/system/archive-analytics.js.map +1 -0
- package/dist/system/archive-stats.js +64 -0
- package/dist/system/archive-stats.js.map +1 -0
- package/dist/system/audit.js +145 -0
- package/dist/system/audit.js.map +1 -0
- package/dist/system/backup.d.ts +91 -3
- package/dist/system/backup.d.ts.map +1 -1
- package/dist/system/backup.js +280 -0
- package/dist/system/backup.js.map +1 -0
- package/dist/system/cleanup.js +134 -0
- package/dist/system/cleanup.js.map +1 -0
- package/dist/system/health.js +1100 -0
- package/dist/system/health.js.map +1 -0
- package/dist/system/index.js +18 -0
- package/dist/system/index.js.map +1 -0
- package/dist/system/inject-generate.js +122 -0
- package/dist/system/inject-generate.js.map +1 -0
- package/dist/system/labels.js +38 -0
- package/dist/system/labels.js.map +1 -0
- package/dist/system/metrics.js +61 -0
- package/dist/system/metrics.js.map +1 -0
- package/dist/system/migrate.js +43 -0
- package/dist/system/migrate.js.map +1 -0
- package/dist/system/platform-paths.js +80 -0
- package/dist/system/platform-paths.js.map +1 -0
- package/dist/system/runtime.js +161 -0
- package/dist/system/runtime.js.map +1 -0
- package/dist/system/safestop.js +99 -0
- package/dist/system/safestop.js.map +1 -0
- package/dist/system/storage-preflight.js +123 -0
- package/dist/system/storage-preflight.js.map +1 -0
- package/dist/task-work/index.js +159 -0
- package/dist/task-work/index.js.map +1 -0
- package/dist/tasks/add.js +661 -0
- package/dist/tasks/add.js.map +1 -0
- package/dist/tasks/analyze.js +85 -0
- package/dist/tasks/analyze.js.map +1 -0
- package/dist/tasks/archive.js +90 -0
- package/dist/tasks/archive.js.map +1 -0
- package/dist/tasks/atomicity.js +83 -0
- package/dist/tasks/atomicity.js.map +1 -0
- package/dist/tasks/cancel-ops.js +83 -0
- package/dist/tasks/cancel-ops.js.map +1 -0
- package/dist/tasks/complete.js +211 -0
- package/dist/tasks/complete.js.map +1 -0
- package/dist/tasks/crossref-extract.js +73 -0
- package/dist/tasks/crossref-extract.js.map +1 -0
- package/dist/tasks/delete-preview.js +192 -0
- package/dist/tasks/delete-preview.js.map +1 -0
- package/dist/tasks/delete.js +120 -0
- package/dist/tasks/delete.js.map +1 -0
- package/dist/tasks/deletion-strategy.js +200 -0
- package/dist/tasks/deletion-strategy.js.map +1 -0
- package/dist/tasks/dependency-check.js +278 -0
- package/dist/tasks/dependency-check.js.map +1 -0
- package/dist/tasks/deps-ready.js +32 -0
- package/dist/tasks/deps-ready.js.map +1 -0
- package/dist/tasks/enforcement.js +86 -0
- package/dist/tasks/enforcement.js.map +1 -0
- package/dist/tasks/epic-enforcement.js +294 -0
- package/dist/tasks/epic-enforcement.js.map +1 -0
- package/dist/tasks/find.js +154 -0
- package/dist/tasks/find.js.map +1 -0
- package/dist/tasks/graph-cache.js +127 -0
- package/dist/tasks/graph-cache.js.map +1 -0
- package/dist/tasks/graph-ops.js +171 -0
- package/dist/tasks/graph-ops.js.map +1 -0
- package/dist/tasks/graph-rag.js +328 -0
- package/dist/tasks/graph-rag.js.map +1 -0
- package/dist/tasks/hierarchy-policy.js +149 -0
- package/dist/tasks/hierarchy-policy.js.map +1 -0
- package/dist/tasks/hierarchy.js +185 -0
- package/dist/tasks/hierarchy.js.map +1 -0
- package/dist/tasks/id-generator.js +65 -0
- package/dist/tasks/id-generator.js.map +1 -0
- package/dist/tasks/index.js +14 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/labels.js +52 -0
- package/dist/tasks/labels.js.map +1 -0
- package/dist/tasks/list.js +75 -0
- package/dist/tasks/list.js.map +1 -0
- package/dist/tasks/phase-tracking.js +133 -0
- package/dist/tasks/phase-tracking.js.map +1 -0
- package/dist/tasks/pipeline-stage.js +248 -0
- package/dist/tasks/pipeline-stage.js.map +1 -0
- package/dist/tasks/plan.js +268 -0
- package/dist/tasks/plan.js.map +1 -0
- package/dist/tasks/relates.js +89 -0
- package/dist/tasks/relates.js.map +1 -0
- package/dist/tasks/show.js +80 -0
- package/dist/tasks/show.js.map +1 -0
- package/dist/tasks/size-weighting.js +86 -0
- package/dist/tasks/size-weighting.js.map +1 -0
- package/dist/tasks/staleness.js +86 -0
- package/dist/tasks/staleness.js.map +1 -0
- package/dist/tasks/task-ops.js +1741 -0
- package/dist/tasks/task-ops.js.map +1 -0
- package/dist/tasks/update.js +277 -0
- package/dist/tasks/update.js.map +1 -0
- package/dist/templates/index.js +10 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/parser.js +254 -0
- package/dist/templates/parser.js.map +1 -0
- package/dist/ui/aliases.js +153 -0
- package/dist/ui/aliases.js.map +1 -0
- package/dist/ui/changelog.js +184 -0
- package/dist/ui/changelog.js.map +1 -0
- package/dist/ui/command-registry.js +168 -0
- package/dist/ui/command-registry.js.map +1 -0
- package/dist/ui/flags.js +94 -0
- package/dist/ui/flags.js.map +1 -0
- package/dist/ui/index.js +24 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/upgrade.js +1148 -0
- package/dist/upgrade.js.map +1 -0
- package/dist/validation/chain-validation.js +146 -0
- package/dist/validation/chain-validation.js.map +1 -0
- package/dist/validation/compliance.js +155 -0
- package/dist/validation/compliance.js.map +1 -0
- package/dist/validation/docs-sync.js +212 -0
- package/dist/validation/docs-sync.js.map +1 -0
- package/dist/validation/doctor/checks.js +1069 -0
- package/dist/validation/doctor/checks.js.map +1 -0
- package/dist/validation/doctor/index.js +9 -0
- package/dist/validation/doctor/index.js.map +1 -0
- package/dist/validation/doctor/project-cache.js +160 -0
- package/dist/validation/doctor/project-cache.js.map +1 -0
- package/dist/validation/doctor/utils.js +155 -0
- package/dist/validation/doctor/utils.js.map +1 -0
- package/dist/validation/engine.js +902 -0
- package/dist/validation/engine.js.map +1 -0
- package/dist/validation/gap-check.js +175 -0
- package/dist/validation/gap-check.js.map +1 -0
- package/dist/validation/index.js +40 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/manifest.js +237 -0
- package/dist/validation/manifest.js.map +1 -0
- package/dist/validation/operation-gate-validators.js +724 -0
- package/dist/validation/operation-gate-validators.js.map +1 -0
- package/dist/validation/operation-verification-gates.js +532 -0
- package/dist/validation/operation-verification-gates.js.map +1 -0
- package/dist/validation/param-utils.js +139 -0
- package/dist/validation/param-utils.js.map +1 -0
- package/dist/validation/protocol-common.js +300 -0
- package/dist/validation/protocol-common.js.map +1 -0
- package/dist/validation/protocols/_shared.js +75 -0
- package/dist/validation/protocols/_shared.js.map +1 -0
- package/dist/validation/protocols/architecture-decision.js +31 -0
- package/dist/validation/protocols/architecture-decision.js.map +1 -0
- package/dist/validation/protocols/artifact-publish.js +28 -0
- package/dist/validation/protocols/artifact-publish.js.map +1 -0
- package/dist/validation/protocols/consensus.js +41 -0
- package/dist/validation/protocols/consensus.js.map +1 -0
- package/dist/validation/protocols/contribution.js +27 -0
- package/dist/validation/protocols/contribution.js.map +1 -0
- package/dist/validation/protocols/decomposition.js +28 -0
- package/dist/validation/protocols/decomposition.js.map +1 -0
- package/dist/validation/protocols/implementation.js +24 -0
- package/dist/validation/protocols/implementation.js.map +1 -0
- package/dist/validation/protocols/provenance.js +29 -0
- package/dist/validation/protocols/provenance.js.map +1 -0
- package/dist/validation/protocols/release.js +29 -0
- package/dist/validation/protocols/release.js.map +1 -0
- package/dist/validation/protocols/research.js +24 -0
- package/dist/validation/protocols/research.js.map +1 -0
- package/dist/validation/protocols/specification.js +27 -0
- package/dist/validation/protocols/specification.js.map +1 -0
- package/dist/validation/protocols/testing.js +30 -0
- package/dist/validation/protocols/testing.js.map +1 -0
- package/dist/validation/protocols/validation.js +30 -0
- package/dist/validation/protocols/validation.js.map +1 -0
- package/dist/validation/schema-integrity.js +170 -0
- package/dist/validation/schema-integrity.js.map +1 -0
- package/dist/validation/schema-validator.js +176 -0
- package/dist/validation/schema-validator.js.map +1 -0
- package/dist/validation/validate-ops.js +937 -0
- package/dist/validation/validate-ops.js.map +1 -0
- package/dist/validation/validation-rules.js +226 -0
- package/dist/validation/validation-rules.js.map +1 -0
- package/dist/validation/verification.js +321 -0
- package/dist/validation/verification.js.map +1 -0
- package/package.json +10 -8
- package/src/__tests__/paths-walkup.test.ts +305 -0
- package/src/__tests__/paths.test.ts +61 -17
- package/src/hooks/handlers/session-hooks.ts +42 -0
- package/src/internal.ts +19 -2
- package/src/paths.ts +91 -14
- package/src/scaffold.ts +22 -3
- package/src/store/__tests__/cleanup-legacy.test.ts +268 -0
- package/src/store/__tests__/database-topology-integration.test.ts +504 -0
- package/src/store/__tests__/sqlite-backup-global.test.ts +281 -0
- package/src/store/__tests__/sqlite-backup.test.ts +118 -10
- package/src/store/cleanup-legacy.ts +208 -0
- package/src/store/index.ts +7 -0
- package/src/store/nexus-sqlite.ts +32 -3
- package/src/store/sqlite-backup.ts +368 -37
- package/src/store/sqlite.ts +19 -3
- package/src/system/__tests__/backup.test.ts +237 -0
- package/src/system/backup.ts +248 -28
- package/templates/cleo-gitignore +19 -3
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the system backup module.
|
|
3
|
+
*
|
|
4
|
+
* Focus areas (T5158):
|
|
5
|
+
* - createBackup uses VACUUM INTO via the live SQLite handle and falls back
|
|
6
|
+
* gracefully when the handle is unavailable (non-fatal).
|
|
7
|
+
* - createBackup uses atomic tmp-then-rename for JSON files.
|
|
8
|
+
* - createBackup writes a .meta.json sidecar enumerating captured files.
|
|
9
|
+
* - listSystemBackups reads back the sidecars.
|
|
10
|
+
* - restoreBackup materializes files back into .cleo/.
|
|
11
|
+
*
|
|
12
|
+
* These tests rely on filesystem-level state in a temporary directory —
|
|
13
|
+
* they do NOT open a real CLEO database. SQLite handles are provided via
|
|
14
|
+
* vi.doMock to exercise the VACUUM INTO code path.
|
|
15
|
+
*
|
|
16
|
+
* @task T5158
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
20
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
21
|
+
import { tmpdir } from 'node:os';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
24
|
+
|
|
25
|
+
describe('system/backup', () => {
|
|
26
|
+
let testDir: string;
|
|
27
|
+
|
|
28
|
+
beforeEach(async () => {
|
|
29
|
+
vi.resetModules();
|
|
30
|
+
testDir = await mkdtemp(join(tmpdir(), 'cleo-system-backup-'));
|
|
31
|
+
mkdirSync(join(testDir, '.cleo'), { recursive: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(async () => {
|
|
35
|
+
await rm(testDir, { recursive: true, force: true });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('createBackup snapshots SQLite files via VACUUM INTO and JSON via atomic write', async () => {
|
|
39
|
+
const tasksExec = vi.fn((sql: string) => {
|
|
40
|
+
// Simulate VACUUM INTO by creating the destination file.
|
|
41
|
+
const match = sql.match(/VACUUM INTO '(.+)'/);
|
|
42
|
+
if (match) writeFileSync(match[1]!, 'vacuumed-tasks');
|
|
43
|
+
});
|
|
44
|
+
const brainExec = vi.fn((sql: string) => {
|
|
45
|
+
const match = sql.match(/VACUUM INTO '(.+)'/);
|
|
46
|
+
if (match) writeFileSync(match[1]!, 'vacuumed-brain');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// createBackup dynamically imports sqlite.js / brain-sqlite.js to
|
|
50
|
+
// ensure the DBs are open before snapshotting; mocks must cover both
|
|
51
|
+
// the `getDb`/`getBrainDb` open entry points AND the
|
|
52
|
+
// `getNativeDb`/`getBrainNativeDb` handle accessors.
|
|
53
|
+
vi.doMock('../../store/sqlite.js', () => ({
|
|
54
|
+
getDb: vi.fn().mockResolvedValue({}),
|
|
55
|
+
getNativeDb: () => ({ exec: tasksExec }),
|
|
56
|
+
}));
|
|
57
|
+
vi.doMock('../../store/brain-sqlite.js', () => ({
|
|
58
|
+
getBrainDb: vi.fn().mockResolvedValue({}),
|
|
59
|
+
getBrainNativeDb: () => ({ exec: brainExec }),
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
// Seed source files so existsSync checks pass in createBackup.
|
|
63
|
+
writeFileSync(join(testDir, '.cleo', 'tasks.db'), 'live-tasks');
|
|
64
|
+
writeFileSync(join(testDir, '.cleo', 'brain.db'), 'live-brain');
|
|
65
|
+
writeFileSync(join(testDir, '.cleo', 'config.json'), '{"version":"test"}');
|
|
66
|
+
writeFileSync(join(testDir, '.cleo', 'project-info.json'), '{"projectId":"test"}');
|
|
67
|
+
|
|
68
|
+
const { createBackup } = await import('../backup.js');
|
|
69
|
+
const result = await createBackup(testDir, { type: 'snapshot', note: 't5158-test' });
|
|
70
|
+
|
|
71
|
+
expect(result.files).toEqual(
|
|
72
|
+
expect.arrayContaining(['tasks.db', 'brain.db', 'config.json', 'project-info.json']),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// VACUUM INTO was invoked with wal_checkpoint preceding it.
|
|
76
|
+
const tasksCalls = tasksExec.mock.calls.map((c) => c[0]);
|
|
77
|
+
const brainCalls = brainExec.mock.calls.map((c) => c[0]);
|
|
78
|
+
const tasksWal = tasksCalls.findIndex((c) => c.includes('wal_checkpoint'));
|
|
79
|
+
const tasksVacuum = tasksCalls.findIndex((c) => c.includes('VACUUM INTO'));
|
|
80
|
+
expect(tasksWal).toBeGreaterThanOrEqual(0);
|
|
81
|
+
expect(tasksVacuum).toBeGreaterThan(tasksWal);
|
|
82
|
+
const brainWal = brainCalls.findIndex((c) => c.includes('wal_checkpoint'));
|
|
83
|
+
const brainVacuum = brainCalls.findIndex((c) => c.includes('VACUUM INTO'));
|
|
84
|
+
expect(brainWal).toBeGreaterThanOrEqual(0);
|
|
85
|
+
expect(brainVacuum).toBeGreaterThan(brainWal);
|
|
86
|
+
|
|
87
|
+
// Snapshot files materialized in the backup dir.
|
|
88
|
+
const snapshotDir = join(testDir, '.cleo', 'backups', 'snapshot');
|
|
89
|
+
const files = readdirSync(snapshotDir);
|
|
90
|
+
expect(files.some((f) => f.startsWith('tasks.db.'))).toBe(true);
|
|
91
|
+
expect(files.some((f) => f.startsWith('brain.db.'))).toBe(true);
|
|
92
|
+
expect(files.some((f) => f.startsWith('config.json.'))).toBe(true);
|
|
93
|
+
expect(files.some((f) => f.startsWith('project-info.json.'))).toBe(true);
|
|
94
|
+
|
|
95
|
+
// Metadata sidecar.
|
|
96
|
+
const metaFile = files.find((f) => f.endsWith('.meta.json'));
|
|
97
|
+
expect(metaFile).toBeDefined();
|
|
98
|
+
const meta = JSON.parse(readFileSync(join(snapshotDir, metaFile!), 'utf-8'));
|
|
99
|
+
expect(meta.note).toBe('t5158-test');
|
|
100
|
+
expect(meta.files).toEqual(
|
|
101
|
+
expect.arrayContaining(['tasks.db', 'brain.db', 'config.json', 'project-info.json']),
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('createBackup skips SQLite files when the native handle is null (non-fatal)', async () => {
|
|
106
|
+
vi.doMock('../../store/sqlite.js', () => ({
|
|
107
|
+
getDb: vi.fn().mockResolvedValue({}),
|
|
108
|
+
getNativeDb: () => null,
|
|
109
|
+
}));
|
|
110
|
+
vi.doMock('../../store/brain-sqlite.js', () => ({
|
|
111
|
+
getBrainDb: vi.fn().mockResolvedValue({}),
|
|
112
|
+
getBrainNativeDb: () => null,
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
writeFileSync(join(testDir, '.cleo', 'tasks.db'), 'live-tasks');
|
|
116
|
+
writeFileSync(join(testDir, '.cleo', 'brain.db'), 'live-brain');
|
|
117
|
+
writeFileSync(join(testDir, '.cleo', 'config.json'), '{"v":1}');
|
|
118
|
+
|
|
119
|
+
const { createBackup } = await import('../backup.js');
|
|
120
|
+
const result = await createBackup(testDir);
|
|
121
|
+
|
|
122
|
+
// JSON file captured, SQLite files skipped because no handle available.
|
|
123
|
+
expect(result.files).toContain('config.json');
|
|
124
|
+
expect(result.files).not.toContain('tasks.db');
|
|
125
|
+
expect(result.files).not.toContain('brain.db');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('listSystemBackups reads sidecars from all known backup type dirs', async () => {
|
|
129
|
+
const snapshotDir = join(testDir, '.cleo', 'backups', 'snapshot');
|
|
130
|
+
const safetyDir = join(testDir, '.cleo', 'backups', 'safety');
|
|
131
|
+
mkdirSync(snapshotDir, { recursive: true });
|
|
132
|
+
mkdirSync(safetyDir, { recursive: true });
|
|
133
|
+
|
|
134
|
+
writeFileSync(
|
|
135
|
+
join(snapshotDir, 'snapshot-A.meta.json'),
|
|
136
|
+
JSON.stringify({
|
|
137
|
+
backupId: 'snapshot-A',
|
|
138
|
+
type: 'snapshot',
|
|
139
|
+
timestamp: '2026-04-07T12:00:00.000Z',
|
|
140
|
+
files: ['config.json'],
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
writeFileSync(
|
|
144
|
+
join(safetyDir, 'safety-B.meta.json'),
|
|
145
|
+
JSON.stringify({
|
|
146
|
+
backupId: 'safety-B',
|
|
147
|
+
type: 'safety',
|
|
148
|
+
timestamp: '2026-04-07T13:00:00.000Z',
|
|
149
|
+
files: ['tasks.db'],
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const { listSystemBackups } = await import('../backup.js');
|
|
154
|
+
const entries = listSystemBackups(testDir);
|
|
155
|
+
|
|
156
|
+
expect(entries.length).toBe(2);
|
|
157
|
+
// Newest first.
|
|
158
|
+
expect(entries[0]?.backupId).toBe('safety-B');
|
|
159
|
+
expect(entries[1]?.backupId).toBe('snapshot-A');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('restoreBackup materializes captured files back into .cleo/', async () => {
|
|
163
|
+
const snapshotDir = join(testDir, '.cleo', 'backups', 'snapshot');
|
|
164
|
+
mkdirSync(snapshotDir, { recursive: true });
|
|
165
|
+
const backupId = 'snapshot-restore-test';
|
|
166
|
+
|
|
167
|
+
writeFileSync(join(snapshotDir, `tasks.db.${backupId}`), 'restored-tasks');
|
|
168
|
+
writeFileSync(join(snapshotDir, `config.json.${backupId}`), '{"restored":true}');
|
|
169
|
+
writeFileSync(
|
|
170
|
+
join(snapshotDir, `${backupId}.meta.json`),
|
|
171
|
+
JSON.stringify({
|
|
172
|
+
backupId,
|
|
173
|
+
type: 'snapshot',
|
|
174
|
+
timestamp: '2026-04-07T14:00:00.000Z',
|
|
175
|
+
files: ['tasks.db', 'config.json'],
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Pre-existing live copies the restore will overwrite.
|
|
180
|
+
writeFileSync(join(testDir, '.cleo', 'tasks.db'), 'stale-tasks');
|
|
181
|
+
writeFileSync(join(testDir, '.cleo', 'config.json'), '{"stale":true}');
|
|
182
|
+
|
|
183
|
+
const { restoreBackup } = await import('../backup.js');
|
|
184
|
+
const result = restoreBackup(testDir, { backupId });
|
|
185
|
+
|
|
186
|
+
expect(result.restored).toBe(true);
|
|
187
|
+
expect(result.filesRestored).toEqual(expect.arrayContaining(['tasks.db', 'config.json']));
|
|
188
|
+
expect(readFileSync(join(testDir, '.cleo', 'tasks.db'), 'utf-8')).toBe('restored-tasks');
|
|
189
|
+
expect(readFileSync(join(testDir, '.cleo', 'config.json'), 'utf-8')).toBe('{"restored":true}');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('restoreBackup throws NOT_FOUND for a missing backupId', async () => {
|
|
193
|
+
const { restoreBackup } = await import('../backup.js');
|
|
194
|
+
expect(() => restoreBackup(testDir, { backupId: 'nonexistent' })).toThrowError(
|
|
195
|
+
/Backup not found/,
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Sanity: ensure the safety snapshot produced by the vacuumed blob is readable
|
|
201
|
+
// as a normal file (we treat .db files as opaque blobs during restore).
|
|
202
|
+
describe('system/backup — restored .db files are byte-identical', () => {
|
|
203
|
+
let testDir: string;
|
|
204
|
+
beforeEach(async () => {
|
|
205
|
+
vi.resetModules();
|
|
206
|
+
testDir = await mkdtemp(join(tmpdir(), 'cleo-system-backup-restore-'));
|
|
207
|
+
mkdirSync(join(testDir, '.cleo'), { recursive: true });
|
|
208
|
+
});
|
|
209
|
+
afterEach(async () => {
|
|
210
|
+
await rm(testDir, { recursive: true, force: true });
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('restoreBackup copies .db files without re-vacuuming', async () => {
|
|
214
|
+
const snapshotDir = join(testDir, '.cleo', 'backups', 'snapshot');
|
|
215
|
+
mkdirSync(snapshotDir, { recursive: true });
|
|
216
|
+
const backupId = 'snapshot-byte-identity';
|
|
217
|
+
const payload = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
218
|
+
writeFileSync(join(snapshotDir, `tasks.db.${backupId}`), payload);
|
|
219
|
+
writeFileSync(
|
|
220
|
+
join(snapshotDir, `${backupId}.meta.json`),
|
|
221
|
+
JSON.stringify({
|
|
222
|
+
backupId,
|
|
223
|
+
type: 'snapshot',
|
|
224
|
+
timestamp: '2026-04-07T15:00:00.000Z',
|
|
225
|
+
files: ['tasks.db'],
|
|
226
|
+
}),
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const { restoreBackup } = await import('../backup.js');
|
|
230
|
+
const result = restoreBackup(testDir, { backupId });
|
|
231
|
+
expect(result.restored).toBe(true);
|
|
232
|
+
|
|
233
|
+
const liveBytes = readFileSync(join(testDir, '.cleo', 'tasks.db'));
|
|
234
|
+
expect(Buffer.compare(liveBytes, payload)).toBe(0);
|
|
235
|
+
expect(existsSync(join(testDir, '.cleo', 'tasks.db'))).toBe(true);
|
|
236
|
+
});
|
|
237
|
+
});
|
package/src/system/backup.ts
CHANGED
|
@@ -1,33 +1,153 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Backup and restore core module.
|
|
3
|
+
*
|
|
4
|
+
* Produces full-`.cleo/` snapshots containing tasks.db, brain.db, config.json
|
|
5
|
+
* and project-info.json using the safest available method for each file type:
|
|
6
|
+
*
|
|
7
|
+
* - SQLite databases: `VACUUM INTO` via the live native handle (see
|
|
8
|
+
* {@link ../store/sqlite-backup.ts}). This is the ONLY safe way to
|
|
9
|
+
* snapshot a WAL-mode SQLite database while it is open — raw filesystem
|
|
10
|
+
* copies can capture torn writes or stale WAL frames.
|
|
11
|
+
*
|
|
12
|
+
* - JSON files: atomic tmp-then-rename via {@link atomicWrite} so a partial
|
|
13
|
+
* write can never corrupt the backup target.
|
|
14
|
+
*
|
|
15
|
+
* Snapshots are recorded under `.cleo/backups/{type}/` with a JSON sidecar
|
|
16
|
+
* (`{backupId}.meta.json`) enumerating which files were captured and how.
|
|
17
|
+
* Restores read the same sidecars and materialize each file back into the
|
|
18
|
+
* live `.cleo/` directory.
|
|
19
|
+
*
|
|
20
|
+
* This is the backing store for the `cleo backup` and `cleo restore backup`
|
|
21
|
+
* CLI verbs (see packages/cleo/src/cli/commands/backup.ts and restore.ts).
|
|
22
|
+
*
|
|
3
23
|
* @task T4783
|
|
24
|
+
* @task T5158 — extended to use VACUUM INTO for .db files and atomicWrite for JSON
|
|
25
|
+
* @task T306 — extended to support global-tier scope (nexus.db; epic T299)
|
|
4
26
|
*/
|
|
5
27
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
28
|
+
import {
|
|
29
|
+
copyFileSync,
|
|
30
|
+
existsSync,
|
|
31
|
+
mkdirSync,
|
|
32
|
+
readdirSync,
|
|
33
|
+
readFileSync,
|
|
34
|
+
renameSync,
|
|
35
|
+
unlinkSync,
|
|
36
|
+
writeFileSync,
|
|
37
|
+
} from 'node:fs';
|
|
38
|
+
import { dirname, join } from 'node:path';
|
|
8
39
|
import { ExitCode } from '@cleocode/contracts';
|
|
9
40
|
import { CleoError } from '../errors.js';
|
|
41
|
+
import { getBrainNativeDb } from '../store/brain-sqlite.js';
|
|
42
|
+
import { getNativeDb } from '../store/sqlite.js';
|
|
10
43
|
|
|
44
|
+
/** Safe wrapper around VACUUM INTO: flushes WAL then clones the DB. */
|
|
45
|
+
function safeSqliteSnapshot(db: { exec: (sql: string) => void } | null, destPath: string): boolean {
|
|
46
|
+
if (!db) return false;
|
|
47
|
+
db.exec('PRAGMA wal_checkpoint(TRUNCATE)');
|
|
48
|
+
const safeDest = destPath.replace(/'/g, "''");
|
|
49
|
+
db.exec(`VACUUM INTO '${safeDest}'`);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Synchronous atomic write: writes to a sibling `.tmp` file and renames on
|
|
55
|
+
* success. Mirrors the behavior of `write-file-atomic` but in a sync flavor
|
|
56
|
+
* suitable for `createBackup()` which has a sync contract throughout its
|
|
57
|
+
* call chain.
|
|
58
|
+
*
|
|
59
|
+
* On rename failure the tmp file is best-effort cleaned up. Throws on the
|
|
60
|
+
* originating error so callers can decide how to handle the backup partial.
|
|
61
|
+
*/
|
|
62
|
+
function atomicWriteSync(destPath: string, data: Buffer | string): void {
|
|
63
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
64
|
+
const tmp = `${destPath}.${process.pid}.${Date.now()}.tmp`;
|
|
65
|
+
try {
|
|
66
|
+
writeFileSync(tmp, data);
|
|
67
|
+
renameSync(tmp, destPath);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
try {
|
|
70
|
+
unlinkSync(tmp);
|
|
71
|
+
} catch {
|
|
72
|
+
/* ignore cleanup failure */
|
|
73
|
+
}
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Result shape returned by {@link createBackup}. */
|
|
11
79
|
export interface BackupResult {
|
|
80
|
+
/** Unique backup identifier (timestamped). */
|
|
12
81
|
backupId: string;
|
|
82
|
+
/** Absolute path to the directory containing the snapshot files. */
|
|
13
83
|
path: string;
|
|
84
|
+
/** ISO-8601 timestamp when the backup was created. */
|
|
14
85
|
timestamp: string;
|
|
86
|
+
/** Backup category (`snapshot`, `safety`, `migration`). */
|
|
15
87
|
type: string;
|
|
88
|
+
/** Files that were successfully captured into this backup. */
|
|
16
89
|
files: string[];
|
|
90
|
+
/**
|
|
91
|
+
* Global-tier snapshot results, populated when `opts.includeGlobal` is true.
|
|
92
|
+
* Key is the DB name (e.g. `'nexus'`), value is the snapshot path or an
|
|
93
|
+
* empty string when the DB was not initialized.
|
|
94
|
+
*
|
|
95
|
+
* @task T306
|
|
96
|
+
* @epic T299
|
|
97
|
+
*/
|
|
98
|
+
global?: Record<string, string>;
|
|
17
99
|
}
|
|
18
100
|
|
|
101
|
+
/** Result shape returned by {@link restoreBackup}. */
|
|
19
102
|
export interface RestoreResult {
|
|
103
|
+
/** Whether any files were actually restored (false if none matched). */
|
|
20
104
|
restored: boolean;
|
|
105
|
+
/** The backup identifier that was restored. */
|
|
21
106
|
backupId: string;
|
|
107
|
+
/** ISO-8601 timestamp of the original backup. */
|
|
22
108
|
timestamp: string;
|
|
109
|
+
/** File names that were successfully restored back into `.cleo/`. */
|
|
23
110
|
filesRestored: string[];
|
|
24
111
|
}
|
|
25
112
|
|
|
26
|
-
/**
|
|
27
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Create a backup of the canonical CLEO data files.
|
|
115
|
+
*
|
|
116
|
+
* Produces safe copies via VACUUM INTO (for SQLite) and atomicWrite
|
|
117
|
+
* (for JSON) into `.cleo/backups/{type}/`. Writes a `{backupId}.meta.json`
|
|
118
|
+
* sidecar describing the snapshot.
|
|
119
|
+
*
|
|
120
|
+
* Opens both `tasks.db` and `brain.db` through their canonical drizzle
|
|
121
|
+
* accessors before snapshotting so that the native DB handles are live
|
|
122
|
+
* when `safeSqliteSnapshot` asks for them. This makes the function
|
|
123
|
+
* self-contained — callers do not need to pre-open the DBs.
|
|
124
|
+
*
|
|
125
|
+
* When `opts.includeGlobal` is true, also snapshots global-tier databases
|
|
126
|
+
* (currently `nexus.db`) via {@link vacuumIntoGlobalBackup}. Global snapshots
|
|
127
|
+
* are written to `$XDG_DATA_HOME/cleo/backups/sqlite/` and returned in
|
|
128
|
+
* `result.global`.
|
|
129
|
+
*
|
|
130
|
+
* Async because opening the database engines requires async migration
|
|
131
|
+
* reconciliation (ADR-012). The CLI dispatch layer awaits this result.
|
|
132
|
+
*
|
|
133
|
+
* @task T306
|
|
134
|
+
* @epic T299
|
|
135
|
+
*/
|
|
136
|
+
export async function createBackup(
|
|
28
137
|
projectRoot: string,
|
|
29
|
-
opts?: {
|
|
30
|
-
|
|
138
|
+
opts?: {
|
|
139
|
+
type?: string;
|
|
140
|
+
note?: string;
|
|
141
|
+
/**
|
|
142
|
+
* When true, also snapshot global-tier databases (nexus.db).
|
|
143
|
+
* Defaults to false for backwards compatibility.
|
|
144
|
+
*
|
|
145
|
+
* @task T306
|
|
146
|
+
* @epic T299
|
|
147
|
+
*/
|
|
148
|
+
includeGlobal?: boolean;
|
|
149
|
+
},
|
|
150
|
+
): Promise<BackupResult> {
|
|
31
151
|
const cleoDir = join(projectRoot, '.cleo');
|
|
32
152
|
const btype = opts?.type || 'snapshot';
|
|
33
153
|
const timestamp = new Date().toISOString();
|
|
@@ -38,27 +158,72 @@ export function createBackup(
|
|
|
38
158
|
mkdirSync(backupDir, { recursive: true });
|
|
39
159
|
}
|
|
40
160
|
|
|
41
|
-
|
|
161
|
+
// Ensure both SQLite engines are initialized so getNativeDb/
|
|
162
|
+
// getBrainNativeDb return live handles when we call them below. Both
|
|
163
|
+
// opens are best-effort — if one fails we still snapshot whatever we
|
|
164
|
+
// can reach (plus the JSON files). Dynamic imports avoid pulling
|
|
165
|
+
// drizzle into test suites that mock the store layer.
|
|
166
|
+
try {
|
|
167
|
+
const { getDb } = await import('../store/sqlite.js');
|
|
168
|
+
await getDb(projectRoot);
|
|
169
|
+
} catch {
|
|
170
|
+
// tasks.db open failed — will be skipped by the sqlite target below
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const { getBrainDb } = await import('../store/brain-sqlite.js');
|
|
174
|
+
await getBrainDb(projectRoot);
|
|
175
|
+
} catch {
|
|
176
|
+
// brain.db open failed — will be skipped by the sqlite target below
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Per-file backup strategy. SQLite files go through `safeSqliteSnapshot`
|
|
181
|
+
* (VACUUM INTO), JSON files through `atomicWrite`. Anything not in this
|
|
182
|
+
* table is skipped.
|
|
183
|
+
*/
|
|
184
|
+
const sqliteTargets: Array<{
|
|
185
|
+
file: string;
|
|
186
|
+
getDb: () => { exec: (sql: string) => void } | null;
|
|
187
|
+
}> = [
|
|
188
|
+
{ file: 'tasks.db', getDb: getNativeDb },
|
|
189
|
+
{ file: 'brain.db', getDb: getBrainNativeDb },
|
|
190
|
+
];
|
|
191
|
+
const jsonTargets: string[] = ['config.json', 'project-info.json'];
|
|
42
192
|
const backedUp: string[] = [];
|
|
43
193
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// skip files that fail to copy
|
|
194
|
+
// SQLite via VACUUM INTO.
|
|
195
|
+
for (const target of sqliteTargets) {
|
|
196
|
+
const src = join(cleoDir, target.file);
|
|
197
|
+
if (!existsSync(src)) continue;
|
|
198
|
+
const dest = join(backupDir, `${target.file}.${backupId}`);
|
|
199
|
+
try {
|
|
200
|
+
const ok = safeSqliteSnapshot(target.getDb(), dest);
|
|
201
|
+
if (ok) {
|
|
202
|
+
backedUp.push(target.file);
|
|
54
203
|
}
|
|
204
|
+
} catch {
|
|
205
|
+
// skip files that fail to snapshot — backup remains partial but usable
|
|
55
206
|
}
|
|
56
207
|
}
|
|
57
208
|
|
|
58
|
-
//
|
|
209
|
+
// JSON via atomic write.
|
|
210
|
+
for (const file of jsonTargets) {
|
|
211
|
+
const src = join(cleoDir, file);
|
|
212
|
+
if (!existsSync(src)) continue;
|
|
213
|
+
const dest = join(backupDir, `${file}.${backupId}`);
|
|
214
|
+
try {
|
|
215
|
+
const content = readFileSync(src);
|
|
216
|
+
atomicWriteSync(dest, content);
|
|
217
|
+
backedUp.push(file);
|
|
218
|
+
} catch {
|
|
219
|
+
// skip files that fail to copy
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Write metadata sidecar.
|
|
59
224
|
const metaPath = join(backupDir, `${backupId}.meta.json`);
|
|
60
225
|
try {
|
|
61
|
-
|
|
226
|
+
atomicWriteSync(
|
|
62
227
|
metaPath,
|
|
63
228
|
JSON.stringify(
|
|
64
229
|
{
|
|
@@ -71,21 +236,56 @@ export function createBackup(
|
|
|
71
236
|
null,
|
|
72
237
|
2,
|
|
73
238
|
),
|
|
74
|
-
'utf-8',
|
|
75
239
|
);
|
|
76
240
|
} catch {
|
|
77
241
|
// non-fatal
|
|
78
242
|
}
|
|
79
243
|
|
|
80
|
-
|
|
244
|
+
// Global-tier backup (nexus.db) — only when explicitly requested.
|
|
245
|
+
// @task T306 @epic T299
|
|
246
|
+
const globalResults: Record<string, string> = {};
|
|
247
|
+
if (opts?.includeGlobal) {
|
|
248
|
+
// Ensure nexus.db is initialized so its native handle is available.
|
|
249
|
+
try {
|
|
250
|
+
const { getNexusDb } = await import('../store/nexus-sqlite.js');
|
|
251
|
+
await getNexusDb();
|
|
252
|
+
} catch {
|
|
253
|
+
// nexus.db open failed — vacuumIntoGlobalBackup will return empty path
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const { vacuumIntoGlobalBackup } = await import('../store/sqlite-backup.js');
|
|
257
|
+
const nexusResult = await vacuumIntoGlobalBackup('nexus');
|
|
258
|
+
globalResults['nexus'] = nexusResult.snapshotPath;
|
|
259
|
+
} catch {
|
|
260
|
+
// non-fatal — global backup failure must not block project backup
|
|
261
|
+
globalResults['nexus'] = '';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const result: BackupResult = {
|
|
266
|
+
backupId,
|
|
267
|
+
path: backupDir,
|
|
268
|
+
timestamp,
|
|
269
|
+
type: btype,
|
|
270
|
+
files: backedUp,
|
|
271
|
+
};
|
|
272
|
+
if (opts?.includeGlobal) {
|
|
273
|
+
result.global = globalResults;
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
81
276
|
}
|
|
82
277
|
|
|
83
278
|
/** A single backup entry returned by listSystemBackups. */
|
|
84
279
|
export interface BackupEntry {
|
|
280
|
+
/** Unique backup identifier (timestamped). */
|
|
85
281
|
backupId: string;
|
|
282
|
+
/** Backup category (`snapshot`, `safety`, `migration`). */
|
|
86
283
|
type: string;
|
|
284
|
+
/** ISO-8601 timestamp when the backup was created. */
|
|
87
285
|
timestamp: string;
|
|
286
|
+
/** Optional human-readable note attached at creation time. */
|
|
88
287
|
note?: string;
|
|
288
|
+
/** File names captured in this backup. */
|
|
89
289
|
files: string[];
|
|
90
290
|
}
|
|
91
291
|
|
|
@@ -131,7 +331,18 @@ export function listSystemBackups(projectRoot: string): BackupEntry[] {
|
|
|
131
331
|
return entries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
132
332
|
}
|
|
133
333
|
|
|
134
|
-
/**
|
|
334
|
+
/**
|
|
335
|
+
* Restore a backup into the live `.cleo/` directory.
|
|
336
|
+
*
|
|
337
|
+
* This operation overwrites the in-place copies of the files recorded in
|
|
338
|
+
* the backup's sidecar. SQLite files are restored via a plain `copyFileSync`
|
|
339
|
+
* because restore runs BEFORE the next CLEO process opens the database — no
|
|
340
|
+
* WAL is active at that point — so a filesystem copy is safe. Callers must
|
|
341
|
+
* ensure no CLEO process is concurrently writing to the target database.
|
|
342
|
+
*
|
|
343
|
+
* JSON files are restored via `atomicWrite` (tmp-then-rename) so a crash
|
|
344
|
+
* mid-restore cannot produce a truncated config.
|
|
345
|
+
*/
|
|
135
346
|
export function restoreBackup(
|
|
136
347
|
projectRoot: string,
|
|
137
348
|
params: { backupId: string; force?: boolean },
|
|
@@ -168,14 +379,23 @@ export function restoreBackup(
|
|
|
168
379
|
const restored: string[] = [];
|
|
169
380
|
for (const file of meta.files ?? []) {
|
|
170
381
|
const backupFile = join(backupDir, `${file}.${params.backupId}`);
|
|
171
|
-
if (existsSync(backupFile))
|
|
172
|
-
|
|
382
|
+
if (!existsSync(backupFile)) continue;
|
|
383
|
+
const destPath = join(cleoDir, file);
|
|
384
|
+
try {
|
|
385
|
+
if (file.endsWith('.db')) {
|
|
386
|
+
// Atomic filesystem copy — target DB must not be in use (caller's
|
|
387
|
+
// responsibility). Raw copy is safe here because no VACUUM INTO is
|
|
388
|
+
// applicable (we are writing to the final location, not into a
|
|
389
|
+
// snapshot).
|
|
390
|
+
copyFileSync(backupFile, destPath);
|
|
391
|
+
} else {
|
|
392
|
+
// JSON via atomic tmp-then-rename.
|
|
173
393
|
const content = readFileSync(backupFile);
|
|
174
|
-
|
|
175
|
-
restored.push(file);
|
|
176
|
-
} catch {
|
|
177
|
-
// skip files that fail to restore
|
|
394
|
+
atomicWriteSync(destPath, content);
|
|
178
395
|
}
|
|
396
|
+
restored.push(file);
|
|
397
|
+
} catch {
|
|
398
|
+
// skip files that fail to restore
|
|
179
399
|
}
|
|
180
400
|
}
|
|
181
401
|
|
package/templates/cleo-gitignore
CHANGED
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
#
|
|
8
8
|
# Canonical audit: .cleo/agent-outputs/T5159-cleo-file-audit.md
|
|
9
9
|
# ADR: ADR-013-data-integrity-checkpoint-architecture.md
|
|
10
|
+
#
|
|
11
|
+
# ADR-013 §9 (2026-04-07, T5158) — IMPORTANT:
|
|
12
|
+
# tasks.db / brain.db / config.json / project-info.json are NOT tracked
|
|
13
|
+
# in EITHER the project git repo OR the isolated .cleo/.git checkpoint
|
|
14
|
+
# repo. They are regenerated deterministically by `cleo init` and are
|
|
15
|
+
# backed up via VACUUM INTO snapshots (SQLite) + atomic copies (JSON)
|
|
16
|
+
# stored under .cleo/backups/. See the ADR for the full recovery story.
|
|
17
|
+
#
|
|
18
|
+
# Because git treats nested .gitignore allow rules (`!foo`) as overriding
|
|
19
|
+
# parent-repo ignore rules, this file must NOT re-include those four
|
|
20
|
+
# files — doing so would unignore them at the project repository level
|
|
21
|
+
# and re-open the T5158 data-loss vector.
|
|
10
22
|
# =============================================================================
|
|
11
23
|
|
|
12
24
|
# Step 1: Ignore everything in .cleo/
|
|
@@ -19,10 +31,9 @@
|
|
|
19
31
|
# Step 2: Allow this .gitignore itself
|
|
20
32
|
!.gitignore
|
|
21
33
|
|
|
22
|
-
# Step 3: Allow project configuration files
|
|
23
|
-
|
|
34
|
+
# Step 3: Allow project configuration files that are SAFE to track
|
|
35
|
+
# (detected project facts and bootstrap scripts — not runtime state).
|
|
24
36
|
!project-context.json
|
|
25
|
-
!project-info.json
|
|
26
37
|
!setup-otel.sh
|
|
27
38
|
!DATA-SAFETY-IMPLEMENTATION-SUMMARY.md
|
|
28
39
|
|
|
@@ -49,6 +60,11 @@
|
|
|
49
60
|
*.db-wal
|
|
50
61
|
*.db-journal
|
|
51
62
|
|
|
63
|
+
# Runtime config snapshots — regenerated by `cleo init`, backed up via
|
|
64
|
+
# `cleo backup add`. NEVER track (ADR-013 §9).
|
|
65
|
+
config.json
|
|
66
|
+
project-info.json
|
|
67
|
+
|
|
52
68
|
# Logs — NEVER track (append-only runtime data)
|
|
53
69
|
log.json
|
|
54
70
|
tasks-log.jsonl
|