@cleocode/core 2026.4.9 → 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,1140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Research commands and manifest operations.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @task T4465
|
|
6
|
+
* @epic T4454
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
9
|
+
import { join, resolve } from 'node:path';
|
|
10
|
+
import { ExitCode } from '@cleocode/contracts';
|
|
11
|
+
import { CleoError } from '../errors.js';
|
|
12
|
+
import { getBackupDir, getManifestPath as getCentralManifestPath, getCleoDirAbsolute, getManifestArchivePath, getProjectRoot, } from '../paths.js';
|
|
13
|
+
import { atomicWrite, safeReadFile } from '../store/atomic.js';
|
|
14
|
+
import { appendJsonl, readJson, saveJson } from '../store/json.js';
|
|
15
|
+
import { logOperation } from '../tasks/add.js';
|
|
16
|
+
/**
|
|
17
|
+
* Get the research file path.
|
|
18
|
+
* @task T4465
|
|
19
|
+
*/
|
|
20
|
+
function getResearchPath(cwd) {
|
|
21
|
+
return join(getCleoDirAbsolute(cwd), 'research.json');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the manifest file path.
|
|
25
|
+
* @task T4465
|
|
26
|
+
*/
|
|
27
|
+
function getManifestPath(cwd) {
|
|
28
|
+
return getCentralManifestPath(cwd);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Read or initialize the research file.
|
|
32
|
+
* @task T4465
|
|
33
|
+
*/
|
|
34
|
+
async function readResearch(cwd) {
|
|
35
|
+
const path = getResearchPath(cwd);
|
|
36
|
+
const data = await readJson(path);
|
|
37
|
+
return data ?? { entries: [] };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Add a research entry.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Research entry data including taskId and topic
|
|
43
|
+
* @param cwd - Optional working directory for path resolution
|
|
44
|
+
* @param accessor - Data accessor for task validation
|
|
45
|
+
* @returns The created ResearchEntry
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Validates the linked task exists, generates a unique ID, and persists
|
|
49
|
+
* the entry to research.json. Logs the operation to the audit log.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const entry = await addResearch({ taskId: 'T042', topic: 'Auth patterns' }, '/project', accessor);
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @task T4465
|
|
57
|
+
*/
|
|
58
|
+
export async function addResearch(options, cwd, accessor) {
|
|
59
|
+
// Validate task exists
|
|
60
|
+
const task = await accessor.loadSingleTask(options.taskId);
|
|
61
|
+
if (!task) {
|
|
62
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Task not found: ${options.taskId}`);
|
|
63
|
+
}
|
|
64
|
+
if (!options.topic || options.topic.trim().length === 0) {
|
|
65
|
+
throw new CleoError(ExitCode.INVALID_INPUT, 'Research topic is required');
|
|
66
|
+
}
|
|
67
|
+
const research = await readResearch(cwd);
|
|
68
|
+
const now = new Date().toISOString();
|
|
69
|
+
const entry = {
|
|
70
|
+
id: `R${Date.now().toString(36)}`,
|
|
71
|
+
taskId: options.taskId,
|
|
72
|
+
topic: options.topic.trim(),
|
|
73
|
+
findings: options.findings ?? [],
|
|
74
|
+
sources: options.sources ?? [],
|
|
75
|
+
status: (options.findings?.length ?? 0) > 0 ? 'complete' : 'pending',
|
|
76
|
+
createdAt: now,
|
|
77
|
+
updatedAt: now,
|
|
78
|
+
};
|
|
79
|
+
research.entries.push(entry);
|
|
80
|
+
await saveJson(getResearchPath(cwd), research, { backupDir: getBackupDir(cwd) });
|
|
81
|
+
await logOperation('research_added', entry.id, {
|
|
82
|
+
taskId: options.taskId,
|
|
83
|
+
topic: options.topic,
|
|
84
|
+
}, accessor);
|
|
85
|
+
return entry;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Show a specific research entry.
|
|
89
|
+
*
|
|
90
|
+
* @param researchId - The research entry ID to look up
|
|
91
|
+
* @param cwd - Optional working directory for path resolution
|
|
92
|
+
* @returns The matching ResearchEntry
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* Throws a CleoError with NOT_FOUND if the entry does not exist.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const entry = await showResearch('Rlk1abc2', '/project');
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @task T4465
|
|
103
|
+
*/
|
|
104
|
+
export async function showResearch(researchId, cwd) {
|
|
105
|
+
const research = await readResearch(cwd);
|
|
106
|
+
const entry = research.entries.find((e) => e.id === researchId);
|
|
107
|
+
if (!entry) {
|
|
108
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Research entry not found: ${researchId}`);
|
|
109
|
+
}
|
|
110
|
+
return entry;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* List research entries with optional filtering.
|
|
114
|
+
*
|
|
115
|
+
* @param options - Optional filters for taskId and status
|
|
116
|
+
* @param cwd - Optional working directory for path resolution
|
|
117
|
+
* @returns Filtered array of ResearchEntry records
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* Returns all entries when no filters are provided.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const entries = await listResearch({ status: 'pending' }, '/project');
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @task T4465
|
|
128
|
+
*/
|
|
129
|
+
export async function listResearch(options = {}, cwd) {
|
|
130
|
+
const research = await readResearch(cwd);
|
|
131
|
+
let entries = research.entries;
|
|
132
|
+
if (options.taskId) {
|
|
133
|
+
entries = entries.filter((e) => e.taskId === options.taskId);
|
|
134
|
+
}
|
|
135
|
+
if (options.status) {
|
|
136
|
+
entries = entries.filter((e) => e.status === options.status);
|
|
137
|
+
}
|
|
138
|
+
return entries;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* List pending research entries.
|
|
142
|
+
*
|
|
143
|
+
* @param cwd - Optional working directory for path resolution
|
|
144
|
+
* @returns Array of research entries with status "pending"
|
|
145
|
+
*
|
|
146
|
+
* @remarks
|
|
147
|
+
* Convenience wrapper around listResearch with status filter pre-set.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const pending = await pendingResearch('/project');
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @task T4465
|
|
155
|
+
*/
|
|
156
|
+
export async function pendingResearch(cwd) {
|
|
157
|
+
return listResearch({ status: 'pending' }, cwd);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Link a research entry to a task.
|
|
161
|
+
*
|
|
162
|
+
* @param researchId - The research entry ID to link
|
|
163
|
+
* @param taskId - The target task ID
|
|
164
|
+
* @param cwd - Optional working directory for path resolution
|
|
165
|
+
* @param accessor - Data accessor for task validation
|
|
166
|
+
* @returns Confirmation with researchId and taskId
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* Updates the research entry's taskId field and persists the change.
|
|
170
|
+
* Validates both the research entry and target task exist.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* await linkResearch('Rlk1abc2', 'T050', '/project', accessor);
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @task T4465
|
|
178
|
+
*/
|
|
179
|
+
export async function linkResearch(researchId, taskId, cwd, accessor) {
|
|
180
|
+
const research = await readResearch(cwd);
|
|
181
|
+
const entry = research.entries.find((e) => e.id === researchId);
|
|
182
|
+
if (!entry) {
|
|
183
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Research entry not found: ${researchId}`);
|
|
184
|
+
}
|
|
185
|
+
// Validate task exists
|
|
186
|
+
const linkedTask = await accessor.loadSingleTask(taskId);
|
|
187
|
+
if (!linkedTask) {
|
|
188
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Task not found: ${taskId}`);
|
|
189
|
+
}
|
|
190
|
+
entry.taskId = taskId;
|
|
191
|
+
entry.updatedAt = new Date().toISOString();
|
|
192
|
+
await saveJson(getResearchPath(cwd), research, { backupDir: getBackupDir(cwd) });
|
|
193
|
+
return { researchId, taskId };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Update research findings.
|
|
197
|
+
*
|
|
198
|
+
* @param researchId - The research entry ID to update
|
|
199
|
+
* @param updates - Fields to update (findings, sources, and/or status)
|
|
200
|
+
* @param cwd - Optional working directory for path resolution
|
|
201
|
+
* @returns The updated ResearchEntry
|
|
202
|
+
*
|
|
203
|
+
* @remarks
|
|
204
|
+
* Only provided fields are updated; others are left unchanged.
|
|
205
|
+
* Updates the `updatedAt` timestamp automatically.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* const entry = await updateResearch('Rlk1abc2', { status: 'complete', findings: ['JWT is used'] });
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @task T4465
|
|
213
|
+
*/
|
|
214
|
+
export async function updateResearch(researchId, updates, cwd) {
|
|
215
|
+
const research = await readResearch(cwd);
|
|
216
|
+
const entry = research.entries.find((e) => e.id === researchId);
|
|
217
|
+
if (!entry) {
|
|
218
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Research entry not found: ${researchId}`);
|
|
219
|
+
}
|
|
220
|
+
if (updates.findings)
|
|
221
|
+
entry.findings = updates.findings;
|
|
222
|
+
if (updates.sources)
|
|
223
|
+
entry.sources = updates.sources;
|
|
224
|
+
if (updates.status)
|
|
225
|
+
entry.status = updates.status;
|
|
226
|
+
entry.updatedAt = new Date().toISOString();
|
|
227
|
+
await saveJson(getResearchPath(cwd), research, { backupDir: getBackupDir(cwd) });
|
|
228
|
+
return entry;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get research statistics.
|
|
232
|
+
*
|
|
233
|
+
* @param cwd - Optional working directory for path resolution
|
|
234
|
+
* @returns Total count and breakdowns by status and topic
|
|
235
|
+
*
|
|
236
|
+
* @remarks
|
|
237
|
+
* Aggregates all research entries into status and topic distributions.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const stats = await statsResearch('/project');
|
|
242
|
+
* console.log(`${stats.total} entries, ${stats.byStatus.pending ?? 0} pending`);
|
|
243
|
+
* ```
|
|
244
|
+
*
|
|
245
|
+
* @task T4474
|
|
246
|
+
*/
|
|
247
|
+
export async function statsResearch(cwd) {
|
|
248
|
+
const research = await readResearch(cwd);
|
|
249
|
+
const byStatus = {};
|
|
250
|
+
const byTopic = {};
|
|
251
|
+
for (const entry of research.entries) {
|
|
252
|
+
byStatus[entry.status] = (byStatus[entry.status] || 0) + 1;
|
|
253
|
+
byTopic[entry.topic] = (byTopic[entry.topic] || 0) + 1;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
total: research.entries.length,
|
|
257
|
+
byStatus,
|
|
258
|
+
byTopic,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get research entries linked to a specific task.
|
|
263
|
+
*
|
|
264
|
+
* @param taskId - The task ID to find linked research for
|
|
265
|
+
* @param cwd - Optional working directory for path resolution
|
|
266
|
+
* @returns Array of research entries linked to the given task
|
|
267
|
+
*
|
|
268
|
+
* @remarks
|
|
269
|
+
* Filters research entries by taskId. Throws if taskId is empty.
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* const linked = await linksResearch('T042', '/project');
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* @task T4474
|
|
277
|
+
*/
|
|
278
|
+
export async function linksResearch(taskId, cwd) {
|
|
279
|
+
if (!taskId) {
|
|
280
|
+
throw new CleoError(ExitCode.INVALID_INPUT, 'Task ID is required');
|
|
281
|
+
}
|
|
282
|
+
const research = await readResearch(cwd);
|
|
283
|
+
return research.entries.filter((e) => e.taskId === taskId);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Archive old research entries by status.
|
|
287
|
+
* Moves 'complete' entries to an archive and keeps non-complete ones.
|
|
288
|
+
*
|
|
289
|
+
* @param cwd - Optional working directory for path resolution
|
|
290
|
+
* @returns Summary with count of archived and remaining entries
|
|
291
|
+
*
|
|
292
|
+
* @remarks
|
|
293
|
+
* Removes all "complete" entries from the active research file and reports
|
|
294
|
+
* how many were archived vs. retained.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const result = await archiveResearch('/project');
|
|
299
|
+
* console.log(`Archived ${result.entriesArchived} entries`);
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
* @task T4474
|
|
303
|
+
*/
|
|
304
|
+
export async function archiveResearch(cwd) {
|
|
305
|
+
const research = await readResearch(cwd);
|
|
306
|
+
const completed = research.entries.filter((e) => e.status === 'complete');
|
|
307
|
+
const remaining = research.entries.filter((e) => e.status !== 'complete');
|
|
308
|
+
// Write back only non-complete entries
|
|
309
|
+
await saveJson(getResearchPath(cwd), { entries: remaining }, { backupDir: getBackupDir(cwd) });
|
|
310
|
+
return {
|
|
311
|
+
action: 'archive',
|
|
312
|
+
entriesArchived: completed.length,
|
|
313
|
+
entriesRemaining: remaining.length,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
// === MANIFEST OPERATIONS ===
|
|
317
|
+
/**
|
|
318
|
+
* Read manifest entries from MANIFEST.jsonl.
|
|
319
|
+
*
|
|
320
|
+
* @param cwd - Optional working directory for path resolution
|
|
321
|
+
* @returns Array of parsed ManifestEntry records from the JSONL file
|
|
322
|
+
*
|
|
323
|
+
* @remarks
|
|
324
|
+
* Reads the file line by line, skipping blank and malformed lines.
|
|
325
|
+
* Returns an empty array if the file does not exist.
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const entries = await readManifest('/project');
|
|
330
|
+
* ```
|
|
331
|
+
*
|
|
332
|
+
* @task T4465
|
|
333
|
+
*/
|
|
334
|
+
export async function readManifest(cwd) {
|
|
335
|
+
const manifestPath = getManifestPath(cwd);
|
|
336
|
+
const content = await safeReadFile(manifestPath);
|
|
337
|
+
if (!content)
|
|
338
|
+
return [];
|
|
339
|
+
const entries = [];
|
|
340
|
+
for (const line of content.split('\n')) {
|
|
341
|
+
const trimmed = line.trim();
|
|
342
|
+
if (!trimmed)
|
|
343
|
+
continue;
|
|
344
|
+
try {
|
|
345
|
+
entries.push(JSON.parse(trimmed));
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Skip malformed lines
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return entries;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Append a manifest entry.
|
|
355
|
+
*
|
|
356
|
+
* @param entry - The ManifestEntry to append
|
|
357
|
+
* @param cwd - Optional working directory for path resolution
|
|
358
|
+
*
|
|
359
|
+
* @remarks
|
|
360
|
+
* Appends a single JSON line to the MANIFEST.jsonl file.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* await appendManifest({ id: 'M001', file: 'report.md', ... }, '/project');
|
|
365
|
+
* ```
|
|
366
|
+
*
|
|
367
|
+
* @task T4465
|
|
368
|
+
*/
|
|
369
|
+
export async function appendManifest(entry, cwd) {
|
|
370
|
+
const manifestPath = getManifestPath(cwd);
|
|
371
|
+
await appendJsonl(manifestPath, entry);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Query manifest entries with filtering.
|
|
375
|
+
*
|
|
376
|
+
* @param options - Filter criteria (status, agentType, topic, taskId, limit)
|
|
377
|
+
* @param cwd - Optional working directory for path resolution
|
|
378
|
+
* @returns Filtered array of ManifestEntry records
|
|
379
|
+
*
|
|
380
|
+
* @remarks
|
|
381
|
+
* Applies filters sequentially: status, agentType, topic, taskId, then limit.
|
|
382
|
+
* Returns all entries when no filters are provided.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* const entries = await queryManifest({ status: 'completed', limit: 5 }, '/project');
|
|
387
|
+
* ```
|
|
388
|
+
*
|
|
389
|
+
* @task T4465
|
|
390
|
+
*/
|
|
391
|
+
export async function queryManifest(options = {}, cwd) {
|
|
392
|
+
let entries = await readManifest(cwd);
|
|
393
|
+
if (options.status) {
|
|
394
|
+
entries = entries.filter((e) => e.status === options.status);
|
|
395
|
+
}
|
|
396
|
+
if (options.agentType) {
|
|
397
|
+
entries = entries.filter((e) => e.agent_type === options.agentType);
|
|
398
|
+
}
|
|
399
|
+
if (options.topic) {
|
|
400
|
+
entries = entries.filter((e) => e.topics.includes(options.topic));
|
|
401
|
+
}
|
|
402
|
+
if (options.taskId) {
|
|
403
|
+
entries = entries.filter((e) => e.linked_tasks.includes(options.taskId));
|
|
404
|
+
}
|
|
405
|
+
if (options.limit && options.limit > 0) {
|
|
406
|
+
entries = entries.slice(0, options.limit);
|
|
407
|
+
}
|
|
408
|
+
return entries;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Read all manifest entries as extended entries.
|
|
412
|
+
*
|
|
413
|
+
* @param cwd - Optional working directory for path resolution
|
|
414
|
+
* @returns Array of parsed ExtendedManifestEntry records
|
|
415
|
+
*
|
|
416
|
+
* @remarks
|
|
417
|
+
* Same as readManifest but typed as ExtendedManifestEntry to include
|
|
418
|
+
* optional engine fields (confidence, file_checksum, duration_seconds).
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```typescript
|
|
422
|
+
* const entries = await readExtendedManifest('/project');
|
|
423
|
+
* ```
|
|
424
|
+
*
|
|
425
|
+
* @task T4787
|
|
426
|
+
*/
|
|
427
|
+
export async function readExtendedManifest(cwd) {
|
|
428
|
+
const manifestPath = getManifestPath(cwd);
|
|
429
|
+
const content = await safeReadFile(manifestPath);
|
|
430
|
+
if (!content)
|
|
431
|
+
return [];
|
|
432
|
+
const entries = [];
|
|
433
|
+
for (const line of content.split('\n')) {
|
|
434
|
+
const trimmed = line.trim();
|
|
435
|
+
if (!trimmed)
|
|
436
|
+
continue;
|
|
437
|
+
try {
|
|
438
|
+
entries.push(JSON.parse(trimmed));
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
// Skip malformed lines
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return entries;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Filter manifest entries by criteria.
|
|
448
|
+
*
|
|
449
|
+
* @param entries - Array of manifest entries to filter
|
|
450
|
+
* @param filter - Filter criteria to apply
|
|
451
|
+
* @returns Filtered subset of entries
|
|
452
|
+
*
|
|
453
|
+
* @remarks
|
|
454
|
+
* Applies filters in order: taskId, status, agent_type, topic, actionable,
|
|
455
|
+
* dateAfter, dateBefore, offset, then limit.
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```typescript
|
|
459
|
+
* const filtered = filterManifestEntries(entries, { status: 'completed', limit: 10 });
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* @task T4787
|
|
463
|
+
*/
|
|
464
|
+
export function filterManifestEntries(entries, filter) {
|
|
465
|
+
let filtered = entries;
|
|
466
|
+
if (filter.taskId) {
|
|
467
|
+
const taskId = filter.taskId;
|
|
468
|
+
filtered = filtered.filter((e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId));
|
|
469
|
+
}
|
|
470
|
+
if (filter.status) {
|
|
471
|
+
filtered = filtered.filter((e) => e.status === filter.status);
|
|
472
|
+
}
|
|
473
|
+
if (filter.agent_type) {
|
|
474
|
+
filtered = filtered.filter((e) => e.agent_type === filter.agent_type);
|
|
475
|
+
}
|
|
476
|
+
if (filter.topic) {
|
|
477
|
+
filtered = filtered.filter((e) => e.topics.includes(filter.topic));
|
|
478
|
+
}
|
|
479
|
+
if (filter.actionable !== undefined) {
|
|
480
|
+
filtered = filtered.filter((e) => e.actionable === filter.actionable);
|
|
481
|
+
}
|
|
482
|
+
if (filter.dateAfter) {
|
|
483
|
+
filtered = filtered.filter((e) => e.date > filter.dateAfter);
|
|
484
|
+
}
|
|
485
|
+
if (filter.dateBefore) {
|
|
486
|
+
filtered = filtered.filter((e) => e.date < filter.dateBefore);
|
|
487
|
+
}
|
|
488
|
+
if (filter.offset && filter.offset > 0) {
|
|
489
|
+
filtered = filtered.slice(filter.offset);
|
|
490
|
+
}
|
|
491
|
+
if (filter.limit && filter.limit > 0) {
|
|
492
|
+
filtered = filtered.slice(0, filter.limit);
|
|
493
|
+
}
|
|
494
|
+
return filtered;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Show a manifest entry by ID with optional file content.
|
|
498
|
+
*
|
|
499
|
+
* @param researchId - The manifest entry ID to look up
|
|
500
|
+
* @param cwd - Optional working directory for path resolution
|
|
501
|
+
* @returns The manifest entry with file content and existence flag
|
|
502
|
+
*
|
|
503
|
+
* @remarks
|
|
504
|
+
* Reads the output file referenced by the entry if it exists on disk.
|
|
505
|
+
* Throws CleoError NOT_FOUND if the entry ID is not found.
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* ```typescript
|
|
509
|
+
* const entry = await showManifestEntry('T042-auth-research', '/project');
|
|
510
|
+
* if (entry.fileExists) console.log(entry.fileContent);
|
|
511
|
+
* ```
|
|
512
|
+
*
|
|
513
|
+
* @task T4787
|
|
514
|
+
*/
|
|
515
|
+
export async function showManifestEntry(researchId, cwd) {
|
|
516
|
+
const entries = await readExtendedManifest(cwd);
|
|
517
|
+
const entry = entries.find((e) => e.id === researchId);
|
|
518
|
+
if (!entry) {
|
|
519
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Research entry '${researchId}' not found`);
|
|
520
|
+
}
|
|
521
|
+
const root = getProjectRoot(cwd);
|
|
522
|
+
let fileContent = null;
|
|
523
|
+
try {
|
|
524
|
+
const filePath = resolve(root, entry.file);
|
|
525
|
+
if (existsSync(filePath)) {
|
|
526
|
+
fileContent = readFileSync(filePath, 'utf-8');
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
// File may not exist or be unreadable
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
...entry,
|
|
534
|
+
fileContent,
|
|
535
|
+
fileExists: fileContent !== null,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Search manifest entries by text with relevance scoring.
|
|
540
|
+
*
|
|
541
|
+
* @param query - Text query to match against titles, topics, and findings
|
|
542
|
+
* @param options - Optional confidence threshold and limit
|
|
543
|
+
* @param cwd - Optional working directory for path resolution
|
|
544
|
+
* @returns Manifest entries with relevance scores, sorted by relevance descending
|
|
545
|
+
*
|
|
546
|
+
* @remarks
|
|
547
|
+
* Scores entries by matching against title (0.5), topics (0.3), key findings (0.2),
|
|
548
|
+
* and ID (0.1). Filters by minimum confidence threshold (default 0.1).
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* ```typescript
|
|
552
|
+
* const results = await searchManifest('authentication', { limit: 5 }, '/project');
|
|
553
|
+
* ```
|
|
554
|
+
*
|
|
555
|
+
* @task T4787
|
|
556
|
+
*/
|
|
557
|
+
export async function searchManifest(query, options, cwd) {
|
|
558
|
+
const entries = await readExtendedManifest(cwd);
|
|
559
|
+
const queryLower = query.toLowerCase();
|
|
560
|
+
const scored = entries.map((entry) => {
|
|
561
|
+
let score = 0;
|
|
562
|
+
if (entry.title.toLowerCase().includes(queryLower)) {
|
|
563
|
+
score += 0.5;
|
|
564
|
+
}
|
|
565
|
+
if (entry.topics.some((t) => t.toLowerCase().includes(queryLower))) {
|
|
566
|
+
score += 0.3;
|
|
567
|
+
}
|
|
568
|
+
if (entry.key_findings?.some((f) => f.toLowerCase().includes(queryLower))) {
|
|
569
|
+
score += 0.2;
|
|
570
|
+
}
|
|
571
|
+
if (entry.id.toLowerCase().includes(queryLower)) {
|
|
572
|
+
score += 0.1;
|
|
573
|
+
}
|
|
574
|
+
return { entry, score };
|
|
575
|
+
});
|
|
576
|
+
const minConfidence = options?.confidence ?? 0.1;
|
|
577
|
+
let results = scored.filter((s) => s.score >= minConfidence).sort((a, b) => b.score - a.score);
|
|
578
|
+
if (options?.limit && options.limit > 0) {
|
|
579
|
+
results = results.slice(0, options.limit);
|
|
580
|
+
}
|
|
581
|
+
return results.map((r) => ({
|
|
582
|
+
...r.entry,
|
|
583
|
+
relevanceScore: Math.round(r.score * 100) / 100,
|
|
584
|
+
}));
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Get pending manifest entries (partial, blocked, or needing followup).
|
|
588
|
+
*
|
|
589
|
+
* @param epicId - Optional epic ID to scope results
|
|
590
|
+
* @param cwd - Optional working directory for path resolution
|
|
591
|
+
* @returns Pending entries with total count and status breakdown
|
|
592
|
+
*
|
|
593
|
+
* @remarks
|
|
594
|
+
* Includes entries with status "partial", "blocked", or any non-empty
|
|
595
|
+
* needs_followup array. Optionally scopes to entries linked to an epic.
|
|
596
|
+
*
|
|
597
|
+
* @example
|
|
598
|
+
* ```typescript
|
|
599
|
+
* const { entries, total } = await pendingManifestEntries('T001', '/project');
|
|
600
|
+
* ```
|
|
601
|
+
*
|
|
602
|
+
* @task T4787
|
|
603
|
+
*/
|
|
604
|
+
export async function pendingManifestEntries(epicId, cwd) {
|
|
605
|
+
const entries = await readExtendedManifest(cwd);
|
|
606
|
+
let pending = entries.filter((e) => e.status === 'partial' ||
|
|
607
|
+
e.status === 'blocked' ||
|
|
608
|
+
(e.needs_followup && e.needs_followup.length > 0));
|
|
609
|
+
if (epicId) {
|
|
610
|
+
pending = pending.filter((e) => e.id.startsWith(epicId) || e.linked_tasks?.includes(epicId));
|
|
611
|
+
}
|
|
612
|
+
return {
|
|
613
|
+
entries: pending,
|
|
614
|
+
total: pending.length,
|
|
615
|
+
byStatus: {
|
|
616
|
+
partial: pending.filter((e) => e.status === 'partial').length,
|
|
617
|
+
blocked: pending.filter((e) => e.status === 'blocked').length,
|
|
618
|
+
needsFollowup: pending.filter((e) => e.needs_followup && e.needs_followup.length > 0).length,
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Get manifest-based research statistics.
|
|
624
|
+
*
|
|
625
|
+
* @param epicId - Optional epic ID to scope statistics
|
|
626
|
+
* @param cwd - Optional working directory for path resolution
|
|
627
|
+
* @returns Totals, status/type distributions, actionable count, and average findings
|
|
628
|
+
*
|
|
629
|
+
* @remarks
|
|
630
|
+
* Aggregates manifest entries by status, agent type, and actionability.
|
|
631
|
+
* Calculates average key findings per entry.
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```typescript
|
|
635
|
+
* const stats = await manifestStats(undefined, '/project');
|
|
636
|
+
* console.log(`${stats.total} entries, ${stats.actionable} actionable`);
|
|
637
|
+
* ```
|
|
638
|
+
*
|
|
639
|
+
* @task T4787
|
|
640
|
+
*/
|
|
641
|
+
export async function manifestStats(epicId, cwd) {
|
|
642
|
+
const entries = await readExtendedManifest(cwd);
|
|
643
|
+
let filtered = entries;
|
|
644
|
+
if (epicId) {
|
|
645
|
+
filtered = entries.filter((e) => e.id.startsWith(epicId) || e.linked_tasks?.includes(epicId));
|
|
646
|
+
}
|
|
647
|
+
const byStatus = {};
|
|
648
|
+
const byType = {};
|
|
649
|
+
let actionable = 0;
|
|
650
|
+
let needsFollowup = 0;
|
|
651
|
+
let totalFindings = 0;
|
|
652
|
+
for (const entry of filtered) {
|
|
653
|
+
byStatus[entry.status] = (byStatus[entry.status] || 0) + 1;
|
|
654
|
+
byType[entry.agent_type] = (byType[entry.agent_type] || 0) + 1;
|
|
655
|
+
if (entry.actionable)
|
|
656
|
+
actionable++;
|
|
657
|
+
if (entry.needs_followup && entry.needs_followup.length > 0)
|
|
658
|
+
needsFollowup++;
|
|
659
|
+
if (entry.key_findings)
|
|
660
|
+
totalFindings += entry.key_findings.length;
|
|
661
|
+
}
|
|
662
|
+
return {
|
|
663
|
+
total: filtered.length,
|
|
664
|
+
byStatus,
|
|
665
|
+
byType,
|
|
666
|
+
actionable,
|
|
667
|
+
needsFollowup,
|
|
668
|
+
averageFindings: filtered.length > 0 ? Math.round((totalFindings / filtered.length) * 10) / 10 : 0,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Link a manifest entry to a task (adds taskId to linked_tasks array).
|
|
673
|
+
*
|
|
674
|
+
* @param taskId - The task ID to link
|
|
675
|
+
* @param researchId - The manifest entry ID to link to
|
|
676
|
+
* @param cwd - Optional working directory for path resolution
|
|
677
|
+
* @returns Confirmation with link details and whether it was already linked
|
|
678
|
+
*
|
|
679
|
+
* @remarks
|
|
680
|
+
* Appends the taskId to the entry's linked_tasks array if not already present.
|
|
681
|
+
* Rewrites the entire MANIFEST.jsonl file after modification.
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* const result = await linkManifestEntry('T042', 'M001', '/project');
|
|
686
|
+
* ```
|
|
687
|
+
*
|
|
688
|
+
* @task T4787
|
|
689
|
+
*/
|
|
690
|
+
export async function linkManifestEntry(taskId, researchId, cwd) {
|
|
691
|
+
const manifestPath = getManifestPath(cwd);
|
|
692
|
+
const entries = await readExtendedManifest(cwd);
|
|
693
|
+
const entryIndex = entries.findIndex((e) => e.id === researchId);
|
|
694
|
+
if (entryIndex === -1) {
|
|
695
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Research entry '${researchId}' not found`);
|
|
696
|
+
}
|
|
697
|
+
const entry = entries[entryIndex];
|
|
698
|
+
if (entry.linked_tasks?.includes(taskId)) {
|
|
699
|
+
return { taskId, researchId, alreadyLinked: true };
|
|
700
|
+
}
|
|
701
|
+
if (!entry.linked_tasks) {
|
|
702
|
+
entry.linked_tasks = [];
|
|
703
|
+
}
|
|
704
|
+
entry.linked_tasks.push(taskId);
|
|
705
|
+
const content = entries.map((e) => JSON.stringify(e)).join('\n') + '\n';
|
|
706
|
+
await atomicWrite(manifestPath, content);
|
|
707
|
+
return { taskId, researchId, alreadyLinked: false };
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Append an extended manifest entry.
|
|
711
|
+
* Validates required fields before appending.
|
|
712
|
+
*
|
|
713
|
+
* @param entry - The ExtendedManifestEntry to append
|
|
714
|
+
* @param cwd - Optional working directory for path resolution
|
|
715
|
+
* @returns Confirmation with the entry ID and manifest file path
|
|
716
|
+
*
|
|
717
|
+
* @remarks
|
|
718
|
+
* Validates that all required fields (id, file, title, date, status, agent_type,
|
|
719
|
+
* topics, actionable) are present before writing.
|
|
720
|
+
*
|
|
721
|
+
* @example
|
|
722
|
+
* ```typescript
|
|
723
|
+
* const result = await appendExtendedManifest({ id: 'M002', ... }, '/project');
|
|
724
|
+
* ```
|
|
725
|
+
*
|
|
726
|
+
* @task T4787
|
|
727
|
+
*/
|
|
728
|
+
export async function appendExtendedManifest(entry, cwd) {
|
|
729
|
+
const errors = [];
|
|
730
|
+
if (!entry.id)
|
|
731
|
+
errors.push('id is required');
|
|
732
|
+
if (!entry.file)
|
|
733
|
+
errors.push('file is required');
|
|
734
|
+
if (!entry.title)
|
|
735
|
+
errors.push('title is required');
|
|
736
|
+
if (!entry.date)
|
|
737
|
+
errors.push('date is required');
|
|
738
|
+
if (!entry.status)
|
|
739
|
+
errors.push('status is required');
|
|
740
|
+
if (!entry.agent_type)
|
|
741
|
+
errors.push('agent_type is required');
|
|
742
|
+
if (!entry.topics)
|
|
743
|
+
errors.push('topics is required');
|
|
744
|
+
if (entry.actionable === undefined)
|
|
745
|
+
errors.push('actionable is required');
|
|
746
|
+
if (errors.length > 0) {
|
|
747
|
+
throw new CleoError(ExitCode.VALIDATION_ERROR, `Invalid manifest entry: ${errors.join(', ')}`);
|
|
748
|
+
}
|
|
749
|
+
const manifestPath = getManifestPath(cwd);
|
|
750
|
+
await appendJsonl(manifestPath, entry);
|
|
751
|
+
return { entryId: entry.id, file: getManifestPath() };
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Archive manifest entries older than a date.
|
|
755
|
+
*
|
|
756
|
+
* @param beforeDate - ISO date string; entries older than this are archived
|
|
757
|
+
* @param cwd - Optional working directory for path resolution
|
|
758
|
+
* @returns Counts of archived and remaining entries, and the archive file path
|
|
759
|
+
*
|
|
760
|
+
* @remarks
|
|
761
|
+
* Moves entries with a date before the threshold to MANIFEST.archive.jsonl
|
|
762
|
+
* and rewrites the main MANIFEST.jsonl with the remaining entries.
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```typescript
|
|
766
|
+
* const result = await archiveManifestEntries('2026-01-01', '/project');
|
|
767
|
+
* console.log(`Archived ${result.archived} entries`);
|
|
768
|
+
* ```
|
|
769
|
+
*
|
|
770
|
+
* @task T4787
|
|
771
|
+
*/
|
|
772
|
+
export async function archiveManifestEntries(beforeDate, cwd) {
|
|
773
|
+
const manifestPath = getManifestPath(cwd);
|
|
774
|
+
const archivePath = getManifestArchivePath(cwd);
|
|
775
|
+
const entries = await readExtendedManifest(cwd);
|
|
776
|
+
const toArchive = entries.filter((e) => e.date < beforeDate);
|
|
777
|
+
const toKeep = entries.filter((e) => e.date >= beforeDate);
|
|
778
|
+
if (toArchive.length === 0) {
|
|
779
|
+
return {
|
|
780
|
+
archived: 0,
|
|
781
|
+
remaining: entries.length,
|
|
782
|
+
archiveFile: getManifestArchivePath(),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
// Append archived entries to archive file
|
|
786
|
+
const existingArchive = await safeReadFile(archivePath);
|
|
787
|
+
const archiveContent = toArchive.map((e) => JSON.stringify(e)).join('\n') + '\n';
|
|
788
|
+
const fullArchive = existingArchive
|
|
789
|
+
? existingArchive.trimEnd() + '\n' + archiveContent
|
|
790
|
+
: archiveContent;
|
|
791
|
+
await atomicWrite(archivePath, fullArchive);
|
|
792
|
+
// Rewrite main manifest with remaining entries
|
|
793
|
+
const remainingContent = toKeep.length > 0 ? toKeep.map((e) => JSON.stringify(e)).join('\n') + '\n' : '';
|
|
794
|
+
await atomicWrite(manifestPath, remainingContent);
|
|
795
|
+
return {
|
|
796
|
+
archived: toArchive.length,
|
|
797
|
+
remaining: toKeep.length,
|
|
798
|
+
archiveFile: getManifestArchivePath(),
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Find manifest entries with overlapping topics but conflicting key_findings.
|
|
803
|
+
*
|
|
804
|
+
* @param cwd - Optional working directory for path resolution
|
|
805
|
+
* @param params - Optional filter by topic
|
|
806
|
+
* @returns Array of contradiction details between conflicting entries
|
|
807
|
+
*
|
|
808
|
+
* @remarks
|
|
809
|
+
* Groups entries by shared topics and compares key_findings for disagreements.
|
|
810
|
+
* Only returns pairs where findings actually differ.
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* const contradictions = await findContradictions('/project', { topic: 'auth' });
|
|
815
|
+
* ```
|
|
816
|
+
*
|
|
817
|
+
* @task T4787
|
|
818
|
+
*/
|
|
819
|
+
export async function findContradictions(cwd, params) {
|
|
820
|
+
const entries = await readExtendedManifest(cwd);
|
|
821
|
+
const byTopic = new Map();
|
|
822
|
+
for (const entry of entries) {
|
|
823
|
+
if (!entry.key_findings || entry.key_findings.length === 0)
|
|
824
|
+
continue;
|
|
825
|
+
for (const topic of entry.topics) {
|
|
826
|
+
if (params?.topic && topic !== params.topic)
|
|
827
|
+
continue;
|
|
828
|
+
if (!byTopic.has(topic)) {
|
|
829
|
+
byTopic.set(topic, []);
|
|
830
|
+
}
|
|
831
|
+
byTopic.get(topic).push(entry);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
const contradictions = [];
|
|
835
|
+
const negationPairs = [
|
|
836
|
+
[/\bdoes NOT\b/i, /\bdoes\b(?!.*\bnot\b)/i],
|
|
837
|
+
[/\bcannot\b/i, /\bcan\b(?!.*\bnot\b)/i],
|
|
838
|
+
[/\bno\s+\w+\s+required\b/i, /\brequired\b(?!.*\bno\b)/i],
|
|
839
|
+
[
|
|
840
|
+
/\bnot\s+(?:available|supported|possible|recommended)\b/i,
|
|
841
|
+
/\b(?:available|supported|possible|recommended)\b(?!.*\bnot\b)/i,
|
|
842
|
+
],
|
|
843
|
+
[/\bwithout\b/i, /\brequires?\b/i],
|
|
844
|
+
[/\bavoid\b/i, /\buse\b/i],
|
|
845
|
+
[/\bdeprecated\b/i, /\brecommended\b/i],
|
|
846
|
+
[/\banti-pattern\b/i, /\bbest practice\b/i],
|
|
847
|
+
];
|
|
848
|
+
for (const [topic, topicEntries] of byTopic) {
|
|
849
|
+
if (topicEntries.length < 2)
|
|
850
|
+
continue;
|
|
851
|
+
for (let i = 0; i < topicEntries.length; i++) {
|
|
852
|
+
for (let j = i + 1; j < topicEntries.length; j++) {
|
|
853
|
+
const a = topicEntries[i];
|
|
854
|
+
const b = topicEntries[j];
|
|
855
|
+
const conflicts = [];
|
|
856
|
+
for (const findingA of a.key_findings) {
|
|
857
|
+
for (const findingB of b.key_findings) {
|
|
858
|
+
for (const [patternNeg, patternPos] of negationPairs) {
|
|
859
|
+
if ((patternNeg.test(findingA) && patternPos.test(findingB)) ||
|
|
860
|
+
(patternPos.test(findingA) && patternNeg.test(findingB))) {
|
|
861
|
+
conflicts.push(`"${findingA}" vs "${findingB}"`);
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (conflicts.length > 0) {
|
|
868
|
+
contradictions.push({
|
|
869
|
+
entryA: a,
|
|
870
|
+
entryB: b,
|
|
871
|
+
topic,
|
|
872
|
+
conflictDetails: conflicts.join('; '),
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return contradictions;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Identify research entries replaced by newer work on same topic.
|
|
882
|
+
*
|
|
883
|
+
* @param cwd - Optional working directory for path resolution
|
|
884
|
+
* @param params - Optional filter by topic
|
|
885
|
+
* @returns Array of superseded entry pairs with the replacement and obsoleted entries
|
|
886
|
+
*
|
|
887
|
+
* @remarks
|
|
888
|
+
* Groups entries by shared topics and identifies older entries that have been
|
|
889
|
+
* superseded by newer ones on the same subject.
|
|
890
|
+
*
|
|
891
|
+
* @example
|
|
892
|
+
* ```typescript
|
|
893
|
+
* const superseded = await findSuperseded('/project');
|
|
894
|
+
* ```
|
|
895
|
+
*
|
|
896
|
+
* @task T4787
|
|
897
|
+
*/
|
|
898
|
+
export async function findSuperseded(cwd, params) {
|
|
899
|
+
const entries = await readExtendedManifest(cwd);
|
|
900
|
+
const byTopicAndType = new Map();
|
|
901
|
+
for (const entry of entries) {
|
|
902
|
+
for (const topic of entry.topics) {
|
|
903
|
+
if (params?.topic && topic !== params.topic)
|
|
904
|
+
continue;
|
|
905
|
+
const key = `${topic}::${entry.agent_type}`;
|
|
906
|
+
if (!byTopicAndType.has(key)) {
|
|
907
|
+
byTopicAndType.set(key, []);
|
|
908
|
+
}
|
|
909
|
+
byTopicAndType.get(key).push(entry);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
const superseded = [];
|
|
913
|
+
const seenPairs = new Set();
|
|
914
|
+
for (const [key, groupEntries] of byTopicAndType) {
|
|
915
|
+
if (groupEntries.length < 2)
|
|
916
|
+
continue;
|
|
917
|
+
const topic = key.split('::')[0];
|
|
918
|
+
const sorted = [...groupEntries].sort((a, b) => a.date.localeCompare(b.date));
|
|
919
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
920
|
+
const pairKey = `${sorted[i].id}::${sorted[sorted.length - 1].id}::${topic}`;
|
|
921
|
+
if (seenPairs.has(pairKey))
|
|
922
|
+
continue;
|
|
923
|
+
seenPairs.add(pairKey);
|
|
924
|
+
superseded.push({
|
|
925
|
+
old: sorted[i],
|
|
926
|
+
replacement: sorted[sorted.length - 1],
|
|
927
|
+
topic,
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return superseded;
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Read protocol injection content for a given protocol type.
|
|
935
|
+
*
|
|
936
|
+
* @param protocolType - Protocol name (e.g. "consensus", "contribution")
|
|
937
|
+
* @param params - Optional parameters for template resolution
|
|
938
|
+
* @param cwd - Optional working directory for path resolution
|
|
939
|
+
* @returns Protocol content, file path, and metadata
|
|
940
|
+
*
|
|
941
|
+
* @remarks
|
|
942
|
+
* Reads protocol template files from the agent-outputs directory and
|
|
943
|
+
* resolves variables like taskId within the content.
|
|
944
|
+
*
|
|
945
|
+
* @example
|
|
946
|
+
* ```typescript
|
|
947
|
+
* const result = await readProtocolInjection('consensus', { taskId: 'T042' }, '/project');
|
|
948
|
+
* console.log(result.content);
|
|
949
|
+
* ```
|
|
950
|
+
*
|
|
951
|
+
* @task T4787
|
|
952
|
+
*/
|
|
953
|
+
export async function readProtocolInjection(protocolType, params, cwd) {
|
|
954
|
+
const root = getProjectRoot(cwd);
|
|
955
|
+
const protocolLocations = [
|
|
956
|
+
resolve(root, 'protocols', `${protocolType}.md`),
|
|
957
|
+
resolve(root, 'skills', '_shared', `${protocolType}.md`),
|
|
958
|
+
resolve(root, 'agents', 'cleo-subagent', 'protocols', `${protocolType}.md`),
|
|
959
|
+
];
|
|
960
|
+
let protocolContent = null;
|
|
961
|
+
let protocolPath = null;
|
|
962
|
+
for (const loc of protocolLocations) {
|
|
963
|
+
if (existsSync(loc)) {
|
|
964
|
+
try {
|
|
965
|
+
protocolContent = readFileSync(loc, 'utf-8');
|
|
966
|
+
protocolPath = loc.replace(root + '/', '');
|
|
967
|
+
break;
|
|
968
|
+
}
|
|
969
|
+
catch { }
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (!protocolContent || !protocolPath) {
|
|
973
|
+
throw new CleoError(ExitCode.NOT_FOUND, `Protocol '${protocolType}' not found in src/protocols/, skills/_shared/, or agents/cleo-subagent/protocols/`);
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
protocolType,
|
|
977
|
+
content: protocolContent,
|
|
978
|
+
path: protocolPath,
|
|
979
|
+
contentLength: protocolContent.length,
|
|
980
|
+
estimatedTokens: Math.ceil(protocolContent.length / 4),
|
|
981
|
+
taskId: params?.taskId || null,
|
|
982
|
+
variant: params?.variant || null,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Compact MANIFEST.jsonl by removing duplicate/stale entries.
|
|
987
|
+
*
|
|
988
|
+
* @param cwd - Optional working directory for path resolution
|
|
989
|
+
* @returns Compaction summary with counts of removed entries
|
|
990
|
+
*
|
|
991
|
+
* @remarks
|
|
992
|
+
* Removes malformed lines and deduplicates entries by ID (keeping the last
|
|
993
|
+
* occurrence). Rewrites the file atomically.
|
|
994
|
+
*
|
|
995
|
+
* @example
|
|
996
|
+
* ```typescript
|
|
997
|
+
* const result = await compactManifest('/project');
|
|
998
|
+
* console.log(`Removed ${result.duplicatesRemoved} duplicates`);
|
|
999
|
+
* ```
|
|
1000
|
+
*
|
|
1001
|
+
* @task T4787
|
|
1002
|
+
*/
|
|
1003
|
+
export async function compactManifest(cwd) {
|
|
1004
|
+
const manifestPath = getManifestPath(cwd);
|
|
1005
|
+
const content = await safeReadFile(manifestPath);
|
|
1006
|
+
if (!content) {
|
|
1007
|
+
return {
|
|
1008
|
+
compacted: false,
|
|
1009
|
+
originalLines: 0,
|
|
1010
|
+
malformedRemoved: 0,
|
|
1011
|
+
duplicatesRemoved: 0,
|
|
1012
|
+
remainingEntries: 0,
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
const lines = content.split('\n');
|
|
1016
|
+
const entries = [];
|
|
1017
|
+
let malformedCount = 0;
|
|
1018
|
+
for (const line of lines) {
|
|
1019
|
+
const trimmed = line.trim();
|
|
1020
|
+
if (!trimmed)
|
|
1021
|
+
continue;
|
|
1022
|
+
try {
|
|
1023
|
+
entries.push(JSON.parse(trimmed));
|
|
1024
|
+
}
|
|
1025
|
+
catch {
|
|
1026
|
+
malformedCount++;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const originalCount = entries.length + malformedCount;
|
|
1030
|
+
const idMap = new Map();
|
|
1031
|
+
for (const entry of entries) {
|
|
1032
|
+
idMap.set(entry.id, entry);
|
|
1033
|
+
}
|
|
1034
|
+
const compacted = Array.from(idMap.values());
|
|
1035
|
+
const duplicatesRemoved = entries.length - compacted.length;
|
|
1036
|
+
const compactedContent = compacted.length > 0 ? compacted.map((e) => JSON.stringify(e)).join('\n') + '\n' : '';
|
|
1037
|
+
await atomicWrite(manifestPath, compactedContent);
|
|
1038
|
+
return {
|
|
1039
|
+
compacted: true,
|
|
1040
|
+
originalLines: originalCount,
|
|
1041
|
+
malformedRemoved: malformedCount,
|
|
1042
|
+
duplicatesRemoved,
|
|
1043
|
+
remainingEntries: compacted.length,
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Validate research entries for a task.
|
|
1048
|
+
*
|
|
1049
|
+
* @param taskId - The task ID to validate manifest entries for
|
|
1050
|
+
* @param cwd - Optional working directory for path resolution
|
|
1051
|
+
* @returns Validation result with issue details and severity counts
|
|
1052
|
+
*
|
|
1053
|
+
* @remarks
|
|
1054
|
+
* Checks linked manifest entries for missing output files, empty key findings,
|
|
1055
|
+
* and incomplete status. Reports issues at error or warning severity.
|
|
1056
|
+
*
|
|
1057
|
+
* @example
|
|
1058
|
+
* ```typescript
|
|
1059
|
+
* const result = await validateManifestEntries('T042', '/project');
|
|
1060
|
+
* if (!result.valid) console.log(result.issues);
|
|
1061
|
+
* ```
|
|
1062
|
+
*
|
|
1063
|
+
* @task T4787
|
|
1064
|
+
*/
|
|
1065
|
+
export async function validateManifestEntries(taskId, cwd) {
|
|
1066
|
+
const root = getProjectRoot(cwd);
|
|
1067
|
+
const entries = await readExtendedManifest(cwd);
|
|
1068
|
+
const linked = entries.filter((e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId));
|
|
1069
|
+
if (linked.length === 0) {
|
|
1070
|
+
return {
|
|
1071
|
+
taskId,
|
|
1072
|
+
valid: true,
|
|
1073
|
+
entriesFound: 0,
|
|
1074
|
+
issues: [],
|
|
1075
|
+
errorCount: 0,
|
|
1076
|
+
warningCount: 0,
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
const issues = [];
|
|
1080
|
+
for (const entry of linked) {
|
|
1081
|
+
if (!entry.id)
|
|
1082
|
+
issues.push({ entryId: entry.id || '(unknown)', issue: 'Missing id', severity: 'error' });
|
|
1083
|
+
if (!entry.file)
|
|
1084
|
+
issues.push({ entryId: entry.id, issue: 'Missing file path', severity: 'error' });
|
|
1085
|
+
if (!entry.title)
|
|
1086
|
+
issues.push({ entryId: entry.id, issue: 'Missing title', severity: 'error' });
|
|
1087
|
+
if (!entry.date)
|
|
1088
|
+
issues.push({ entryId: entry.id, issue: 'Missing date', severity: 'error' });
|
|
1089
|
+
if (!entry.status)
|
|
1090
|
+
issues.push({ entryId: entry.id, issue: 'Missing status', severity: 'error' });
|
|
1091
|
+
if (!entry.agent_type)
|
|
1092
|
+
issues.push({ entryId: entry.id, issue: 'Missing agent_type', severity: 'error' });
|
|
1093
|
+
if (entry.status && !['completed', 'partial', 'blocked'].includes(entry.status)) {
|
|
1094
|
+
issues.push({
|
|
1095
|
+
entryId: entry.id,
|
|
1096
|
+
issue: `Invalid status: ${entry.status}`,
|
|
1097
|
+
severity: 'error',
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
if (entry.file) {
|
|
1101
|
+
const filePath = resolve(root, entry.file);
|
|
1102
|
+
if (!existsSync(filePath)) {
|
|
1103
|
+
issues.push({
|
|
1104
|
+
entryId: entry.id,
|
|
1105
|
+
issue: `Output file not found: ${entry.file}`,
|
|
1106
|
+
severity: 'warning',
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (entry.agent_type === 'research' &&
|
|
1111
|
+
(!entry.key_findings || entry.key_findings.length === 0)) {
|
|
1112
|
+
issues.push({
|
|
1113
|
+
entryId: entry.id,
|
|
1114
|
+
issue: 'Research entry missing key_findings',
|
|
1115
|
+
severity: 'warning',
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
taskId,
|
|
1121
|
+
valid: issues.filter((i) => i.severity === 'error').length === 0,
|
|
1122
|
+
entriesFound: linked.length,
|
|
1123
|
+
issues,
|
|
1124
|
+
errorCount: issues.filter((i) => i.severity === 'error').length,
|
|
1125
|
+
warningCount: issues.filter((i) => i.severity === 'warning').length,
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
// === BRAIN Lifecycle (temporal decay) ===
|
|
1129
|
+
export * from './brain-lifecycle.js';
|
|
1130
|
+
export * from './brain-links.js';
|
|
1131
|
+
export * from './brain-migration.js';
|
|
1132
|
+
// === BRAIN Retrieval functions (3-layer pattern) ===
|
|
1133
|
+
export * from './brain-retrieval.js';
|
|
1134
|
+
export * from './brain-search.js';
|
|
1135
|
+
// === BRAIN Memory modules (brain.db backed) ===
|
|
1136
|
+
export * from './decisions.js';
|
|
1137
|
+
export * from './learnings.js';
|
|
1138
|
+
// === JSONL Memory modules (legacy, still active) ===
|
|
1139
|
+
export * from './patterns.js';
|
|
1140
|
+
//# sourceMappingURL=index.js.map
|