akm-cli 0.9.30 → 0.10.261001-beta
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/CHANGELOG.md +438 -0
- package/README.md +10 -10
- package/ROADMAP.md +112 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +125 -118
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +12 -7
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +74 -14
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15769 -16731
- package/dist/scripts/akm-migrate.js +16339 -17297
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +94 -13
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +43 -42
- package/docs/agents/README.md +15 -0
- package/docs/agents/agent-install.md +14 -0
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/README.md +67 -0
- package/docs/architecture/adapters.md +258 -0
- package/docs/architecture/akm-architecture-decision-history.md +2055 -0
- package/docs/architecture/akm-core-principles.md +126 -0
- package/docs/architecture/architecture.md +578 -0
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +550 -0
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +72 -0
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +142 -0
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +189 -0
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +97 -0
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +108 -0
- package/docs/architecture/decisions/0006-task-source-version-routing.md +124 -0
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +83 -0
- package/docs/architecture/decisions/0008-task-binding-normalization.md +88 -0
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +80 -0
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +36 -0
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +125 -0
- package/docs/architecture/decisions/README.md +62 -0
- package/docs/architecture/improvement.md +479 -0
- package/docs/architecture/internals/classification.md +154 -0
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +40 -0
- package/docs/architecture/internals/functional-contract-patterns.md +340 -0
- package/docs/architecture/internals/health-advisories.md +110 -0
- package/docs/architecture/internals/improve-workflow.md +719 -0
- package/docs/architecture/internals/indexing.md +498 -0
- package/docs/architecture/internals/registry-network-boundary.md +57 -0
- package/docs/architecture/internals/search.md +248 -0
- package/docs/architecture/internals/storage-locations.md +943 -0
- package/docs/architecture/persisted-data-compat.md +68 -0
- package/docs/architecture/reviews/env-secret-access.md +319 -0
- package/docs/architecture/runtime-boundary-design.md +153 -0
- package/docs/architecture/specs/0.9.0-close-out-plan.md +361 -0
- package/docs/architecture/specs/0.9.0-decisions.md +532 -0
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +745 -0
- package/docs/architecture/specs/0.9.0-open-items-register.md +135 -0
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +740 -0
- package/docs/architecture/specs/0.9.0-release-surface-review.md +636 -0
- package/docs/architecture/specs/agent-command-engine-model-design.md +513 -0
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +501 -0
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +291 -0
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +2059 -0
- package/docs/architecture/specs/di-seams-plan.md +539 -0
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +275 -0
- package/docs/architecture/specs/fact-asset-type.md +142 -0
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +634 -0
- package/docs/architecture/specs/okf-support.md +148 -0
- package/docs/architecture/specs/ref.md +329 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +72 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +152 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +352 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +300 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +402 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +758 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +645 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +602 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +74 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +15 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +132 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +147 -0
- package/docs/architecture/specs/stash-conventions-code-spec.md +275 -0
- package/docs/architecture/specs/stash-organization-conventions.md +377 -0
- package/docs/architecture/specs/task-workflow-format-unification.md +721 -0
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +231 -0
- package/docs/architecture/specs/workflow-format-unification.md +432 -0
- package/docs/architecture/testing/manual-testing-checklist.md +3411 -0
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +924 -0
- package/docs/architecture/testing/task-workflow-manual-tests.md +1720 -0
- package/docs/architecture/testing/testing-workflow.md +446 -0
- package/docs/architecture/workflow-engine.md +223 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/author-bundles.md +310 -0
- package/docs/guides/author-workflows.md +490 -0
- package/docs/guides/bundles.md +323 -0
- package/docs/guides/capture-knowledge.md +136 -0
- package/docs/guides/claude-code-vs-akm-workflows.md +29 -0
- package/docs/guides/concepts.md +93 -0
- package/docs/guides/discover-and-load.md +158 -0
- package/docs/guides/getting-started.md +240 -0
- package/docs/guides/improve-the-library.md +247 -0
- package/docs/guides/knowledge-management.md +18 -0
- package/docs/guides/recipes/headless-install.md +97 -0
- package/docs/guides/recipes/website-source.md +28 -0
- package/docs/guides/run-workflows.md +279 -0
- package/docs/guides/scheduling.md +131 -0
- package/docs/guides/use-with-any-agent.md +174 -0
- package/docs/guides/wikis.md +81 -0
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/README.md +19 -0
- package/docs/maintainers/curate-workmap.md +335 -0
- package/docs/maintainers/eval.md +3 -0
- package/docs/maintainers/local-development.md +108 -0
- package/docs/maintainers/release-checklist.md +135 -0
- package/docs/migration/README.md +4 -2
- package/docs/migration/release-notes/0.0.13.md +1 -1
- package/docs/migration/release-notes/0.1.0.md +1 -1
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/0.2.0.md +1 -1
- package/docs/migration/release-notes/0.3.0.md +1 -1
- package/docs/migration/release-notes/0.5.0.md +1 -1
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.3.md +2 -2
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +1 -1
- package/docs/migration/release-notes/0.8.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/0.9.14.md +1 -1
- package/docs/migration/release-notes/0.9.15.md +1 -1
- package/docs/migration/release-notes/0.9.16.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +1 -1
- package/docs/migration/release-notes/0.9.19.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +1 -1
- package/docs/migration/release-notes/README.md +28 -31
- package/docs/migration/v0.5-to-v0.6.md +759 -0
- package/docs/migration/v0.8-to-v0.9.md +1 -1
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +423 -0
- package/docs/posts/README.md +30 -0
- package/docs/posts/akm-command-tour.md +495 -0
- package/docs/posts/akm-logo-sized.webp +0 -0
- package/docs/posts/belief-aware-memory-12.md +139 -0
- package/docs/posts/config-v2-lessons-16.md +191 -0
- package/docs/posts/improve-loop-autonomous-10.md +225 -0
- package/docs/posts/improve-pipeline-debugging-0803.md +179 -0
- package/docs/posts/intro-part-01.md +76 -0
- package/docs/posts/intro-part-02.md +221 -0
- package/docs/posts/intro-part-03.md +190 -0
- package/docs/posts/intro-part-04.md +221 -0
- package/docs/posts/llm-mode-reflect-13.md +166 -0
- package/docs/posts/openpalm-built-on-akm.md +86 -0
- package/docs/posts/progressive-disclosure-06.md +129 -0
- package/docs/posts/proposal-safety-net-15.md +112 -0
- package/docs/posts/release-0.5.0.md +247 -0
- package/docs/posts/release-0.6.0.md +117 -0
- package/docs/posts/release-0.7.0.md +159 -0
- package/docs/posts/release-0.8.0.md +332 -0
- package/docs/posts/scattered-skills-05.md +100 -0
- package/docs/posts/task-assets-persistent-workflows-11.md +222 -0
- package/docs/posts/team-skills-07.md +198 -0
- package/docs/posts/wiki-agent-knowledge-08.md +223 -0
- package/docs/posts/workflows-vaults-09.md +321 -0
- package/docs/product-surface.md +54 -0
- package/docs/reference/README.md +2 -2
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +166 -0
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +163 -192
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +126 -0
- package/docs/reference/memory.md +124 -0
- package/docs/reference/refs.md +156 -0
- package/docs/reference/registry.md +489 -0
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +141 -0
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +23 -16
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# DI seams plan — replace `mock.module` with swap-and-restore module seams
|
|
2
|
+
|
|
3
|
+
Branch: `refactor/di-seams`
|
|
4
|
+
|
|
5
|
+
> **Implementation note (added later):** this plan has landed — the seam
|
|
6
|
+
> pattern (`_set…ForTests` delegators, `tests/_helpers/seams.ts`,
|
|
7
|
+
> `overrideSeam`/`withSeam`) is in production use (e.g.
|
|
8
|
+
> `_setChatCompletionForTests` in `src/llm/client.ts`, consumed by multiple
|
|
9
|
+
> test files), `mock.module(` no longer appears as live code anywhere under
|
|
10
|
+
> `tests/` (only two historical comments reference the retired pattern), and
|
|
11
|
+
> `src/indexer/db/db.ts` — flagged below as needing its stale mock deleted —
|
|
12
|
+
> no longer exists at all; its functionality (`openIndexDatabase`) now lives
|
|
13
|
+
> in `src/storage/repositories/index-connection.ts`. Several of the specific
|
|
14
|
+
> test file paths named per-module below were renamed or consolidated by a
|
|
15
|
+
> later, unrelated test reorganization; those are annotated in place rather
|
|
16
|
+
> than silently repointed, since this document's per-module breakdown is
|
|
17
|
+
> itself the historical record of how the migration was planned.
|
|
18
|
+
|
|
19
|
+
## Guardrails (binding, non-negotiable)
|
|
20
|
+
|
|
21
|
+
This workstream was previously done wrong (~900 dependency-injection parameter
|
|
22
|
+
threads, reverted). The rules for THIS attempt:
|
|
23
|
+
|
|
24
|
+
- **Swap-and-restore, not parameter threading.** Model: `withMockedFetch` in
|
|
25
|
+
`tests/_helpers/sandbox.ts` (swap `globalThis.fetch` → run → finally-restore)
|
|
26
|
+
and `src/storage/database.ts`'s "plain module, not an adapter layer" stance.
|
|
27
|
+
- Each seamed module keeps its normal exports. Internally the exported function
|
|
28
|
+
delegates through one module-level binding. The module gains exactly ONE small
|
|
29
|
+
test-only override function (`_set…ForTests(fake | undefined)`); passing
|
|
30
|
+
`undefined` restores the real implementation.
|
|
31
|
+
- **Zero changes to production call sites.** No context objects, no new
|
|
32
|
+
parameters on existing functions, no interfaces/ports/adapters, no factories,
|
|
33
|
+
no new wrapper modules. If a module seems to need call-site changes, STOP.
|
|
34
|
+
- Net diff per module: tens of lines in `src`, offset by deleted `mock.module`
|
|
35
|
+
boilerplate in tests.
|
|
36
|
+
- The override function is inert unless a test calls it. Production behavior is
|
|
37
|
+
byte-identical.
|
|
38
|
+
|
|
39
|
+
## The seam pattern (canonical shape)
|
|
40
|
+
|
|
41
|
+
For a module exporting `foo(a, b)`:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// ── Test seam ────────────────────────────────────────────────────────────────
|
|
45
|
+
// Swap-and-restore override. Inert in production; only tests call the setter.
|
|
46
|
+
let fooOverride: typeof fooReal | undefined;
|
|
47
|
+
|
|
48
|
+
/** TEST-ONLY. Swap the implementation of `foo`; pass undefined to restore. */
|
|
49
|
+
export function _setFooForTests(fake?: typeof fooReal): void {
|
|
50
|
+
fooOverride = fake;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function foo(a: A, b: B): R {
|
|
54
|
+
if (fooOverride) return fooOverride(a, b);
|
|
55
|
+
return fooReal(a, b);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function fooReal(a: A, b: B): R {
|
|
59
|
+
// …existing body, renamed, NOT exported…
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Notes on the shape:
|
|
64
|
+
|
|
65
|
+
- The existing exported function body is renamed to a private `…Real` function;
|
|
66
|
+
the export becomes a 2-line delegator. Importers see the identical signature.
|
|
67
|
+
- Intra-module calls to the exported name (e.g. `client.ts` calls its own
|
|
68
|
+
`chatCompletion` from `probeCapabilities`) go through the delegator too.
|
|
69
|
+
This is a *superset* of what `mock.module` guarantees for internal callers
|
|
70
|
+
and matches the tests' intent (no network, ever).
|
|
71
|
+
- One setter per module. When a module has several overridable exports, the
|
|
72
|
+
setter takes a partial overrides object (see per-module specs) — still ONE
|
|
73
|
+
test-only export, one internal binding.
|
|
74
|
+
- Naming convention: `_set<Thing>ForTests`, prefixed `_` so the
|
|
75
|
+
it's self-evidently not public API. Never call it from `src`.
|
|
76
|
+
|
|
77
|
+
## Shared test helper — `tests/_helpers/seams.ts` (new file, ~40 lines)
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// tests/_helpers/seams.ts
|
|
81
|
+
type SeamSetter<T> = (fake: T | undefined) => void;
|
|
82
|
+
|
|
83
|
+
/** Setters that currently hold a fake; drained by resetAllSeams(). */
|
|
84
|
+
const active = new Set<SeamSetter<unknown>>();
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Install a fake for the current test. Restoration is automatic: the
|
|
88
|
+
* tests/_preload.ts afterEach calls resetAllSeams(). Use this for
|
|
89
|
+
* file-scoped or beforeEach-scoped fakes (the common case, mirroring
|
|
90
|
+
* today's top-of-file mock.module blocks).
|
|
91
|
+
*/
|
|
92
|
+
export function overrideSeam<T>(set: SeamSetter<T>, fake: T): void {
|
|
93
|
+
set(fake);
|
|
94
|
+
active.add(set as SeamSetter<unknown>);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Scoped swap → run → finally-restore, for fakes needed in one test only. */
|
|
98
|
+
export async function withSeam<T, R>(
|
|
99
|
+
set: SeamSetter<T>,
|
|
100
|
+
fake: T,
|
|
101
|
+
run: () => R | Promise<R>,
|
|
102
|
+
): Promise<R> {
|
|
103
|
+
set(fake);
|
|
104
|
+
active.add(set as SeamSetter<unknown>);
|
|
105
|
+
try {
|
|
106
|
+
return await run();
|
|
107
|
+
} finally {
|
|
108
|
+
set(undefined);
|
|
109
|
+
active.delete(set as SeamSetter<unknown>);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Safety net: restore every active seam. Called by tests/_preload.ts. */
|
|
114
|
+
export function resetAllSeams(): void {
|
|
115
|
+
for (const set of active) set(undefined);
|
|
116
|
+
active.clear();
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Wiring into `tests/_preload.ts`
|
|
121
|
+
|
|
122
|
+
Two one-line additions to the existing harness (no new lifecycle machinery):
|
|
123
|
+
|
|
124
|
+
1. `resetSingletons()` (tests/_preload.ts:294) gains `resetAllSeams();` — a
|
|
125
|
+
leaked seam from a previous file is cleared before every test, exactly like
|
|
126
|
+
`resetConfigCache()` / `resetLocalEmbedder()` today.
|
|
127
|
+
2. The existing `afterEach` (tests/_preload.ts:329) gains `resetAllSeams();`
|
|
128
|
+
so a fake never survives past the test that installed it.
|
|
129
|
+
|
|
130
|
+
Because tests always install fakes via `overrideSeam`/`withSeam`, the preload
|
|
131
|
+
needs no knowledge of individual `_set…ForTests` functions — the registry is
|
|
132
|
+
the reset list. A test that calls a `_set…ForTests` setter directly (bypassing
|
|
133
|
+
the helper) is a review-reject; grep-able (`_set.*ForTests` outside
|
|
134
|
+
`tests/_helpers/seams.ts` usage must go through the helper).
|
|
135
|
+
|
|
136
|
+
Typical file migration shape (replaces a top-of-file `mock.module` block):
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { overrideSeam } from "../_helpers/seams";
|
|
140
|
+
import { _setChatCompletionForTests } from "../../src/llm/client";
|
|
141
|
+
|
|
142
|
+
let chatResponder: (userContent: string) => string | Promise<string> = () => "";
|
|
143
|
+
|
|
144
|
+
beforeEach(() => {
|
|
145
|
+
overrideSeam(_setChatCompletionForTests, async (_conn, messages) => {
|
|
146
|
+
const user = messages.find((m) => m.role === "user");
|
|
147
|
+
return chatResponder(user?.content ?? "");
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Static imports of the module under test become safe again (no more
|
|
153
|
+
"`mock.module` must run before the module under test is imported" ordering
|
|
154
|
+
comments, no more dynamic-import contortions).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Per-module seam designs
|
|
159
|
+
|
|
160
|
+
Ordered for sequential implementation, most-used-by-tests first. Implement one
|
|
161
|
+
module per commit: add seam → migrate its test files → delete the
|
|
162
|
+
`mock.module` blocks → gate green → commit.
|
|
163
|
+
|
|
164
|
+
### 0. Helper first: `tests/_helpers/seams.ts` + `tests/_preload.ts` wiring
|
|
165
|
+
|
|
166
|
+
As specified above. Land with module 1 (the helper is exercised immediately).
|
|
167
|
+
|
|
168
|
+
### 1. `src/llm/client` — 5 test files (easiest, highest fan-out)
|
|
169
|
+
|
|
170
|
+
- **Binding**: `let chatCompletionOverride: ChatCompletionFn | undefined;` next
|
|
171
|
+
to `chatCompletion` (client.ts:263). Real body → private `chatCompletionReal`.
|
|
172
|
+
- **Hook**:
|
|
173
|
+
```ts
|
|
174
|
+
export function _setChatCompletionForTests(fake?: typeof chatCompletion): void;
|
|
175
|
+
```
|
|
176
|
+
- Internal callers at client.ts:445 (`isLlmAvailable`) and :463
|
|
177
|
+
(`probeCapabilities`-adjacent) route through the delegator — intended.
|
|
178
|
+
- **Test migration** (all five spread the real module and override only
|
|
179
|
+
`chatCompletion`; the spread + `mock.module` block deletes, the responder
|
|
180
|
+
var + `overrideSeam` call replaces it):
|
|
181
|
+
- `tests/indexer/staleness-detect.test.ts` — deterministic validator fake →
|
|
182
|
+
`overrideSeam(_setChatCompletionForTests, fake)` in `beforeEach`. *(This
|
|
183
|
+
path no longer exists; no equivalently-named test was found by a later
|
|
184
|
+
search of `tests/indexer/` and `tests/integration/indexer/`.)*
|
|
185
|
+
- `tests/llm/memory-infer.test.ts` — `chatResponder` + `chatCalls` counter
|
|
186
|
+
pattern translates directly (see canonical migration above).
|
|
187
|
+
- `tests/llm/metadata-enhance.test.ts` — same shape.
|
|
188
|
+
- `tests/integration/commands/reflect-response-schema.test.ts` — same shape.
|
|
189
|
+
(Landed under `tests/integration/commands/`, not `tests/commands/`.)
|
|
190
|
+
- `tests/commands/consolidate/consolidate-judged-cache.test.ts` — same shape
|
|
191
|
+
(`chatCalls` recording preserved by the fake closure). *(This path no
|
|
192
|
+
longer exists; `tests/commands/consolidate/goldens-consolidate-journal.test.ts`
|
|
193
|
+
and `tests/commands/consolidate/goldens-consolidate-ops.test.ts` both use
|
|
194
|
+
`_setChatCompletionForTests` today and are the closest surviving
|
|
195
|
+
candidates, but neither is confirmed as this file's direct successor.)*
|
|
196
|
+
- No module state, no extra reset needed beyond the registry.
|
|
197
|
+
|
|
198
|
+
### 2. `src/core/warn` — 3 test files
|
|
199
|
+
|
|
200
|
+
The module already has real hooks for all its *state*
|
|
201
|
+
(`setQuiet/resetQuiet/setVerbose/resetVerbose/setLogFile/clearLogFile`). Tests
|
|
202
|
+
mock it only to **capture output**. So the seam is a single sink intercept,
|
|
203
|
+
not 13 overridable functions:
|
|
204
|
+
|
|
205
|
+
- **Binding** (warn.ts, next to `quiet`/`verbose`/`logFilePath` at :20-22):
|
|
206
|
+
```ts
|
|
207
|
+
export type WarnSinkForTests = (
|
|
208
|
+
level: "info" | "warn" | "error" | "warnVerbose",
|
|
209
|
+
args: unknown[],
|
|
210
|
+
) => void;
|
|
211
|
+
let sinkOverride: WarnSinkForTests | undefined;
|
|
212
|
+
```
|
|
213
|
+
- **Hook**:
|
|
214
|
+
```ts
|
|
215
|
+
export function _setWarnSinkForTests(fake?: WarnSinkForTests): void;
|
|
216
|
+
```
|
|
217
|
+
- Each of `info`/`warn`/`error`/`warnVerbose` gets a first line:
|
|
218
|
+
`if (sinkOverride) { sinkOverride("<level>", args); return; }`
|
|
219
|
+
Interception happens **before** the quiet/verbose gates — deliberately
|
|
220
|
+
matching today's `mock.module` full-replacement semantics (the existing
|
|
221
|
+
fakes capture every call regardless of flags). All other exports
|
|
222
|
+
(`setQuiet`, `isVerbose`, `getLogFile`, …) stay untouched — the real hooks
|
|
223
|
+
already serve tests.
|
|
224
|
+
- **Test migration**:
|
|
225
|
+
- `tests/llm/memory-infer.test.ts` — spread + override of `warn` →
|
|
226
|
+
`overrideSeam(_setWarnSinkForTests, (level, args) => { if (level === "warn") warnCalls.push(join(args)); })`.
|
|
227
|
+
- `tests/llm/metadata-enhance.test.ts` — same, also captures `warnVerbose`
|
|
228
|
+
level.
|
|
229
|
+
- `tests/agent/agent-builders.test.ts` — currently reimplements ALL 13
|
|
230
|
+
exports with parallel `mockedQuiet`/`mockedVerbose`/`mockedLogFile` state.
|
|
231
|
+
Migration = delete the whole reimplementation; use the REAL module's
|
|
232
|
+
`setQuiet`/`setVerbose` hooks for flag control plus the sink to capture
|
|
233
|
+
`warnings`. Assertions about gating move from "did console.warn fire" to
|
|
234
|
+
"what the sink captured + real `isQuiet()`/`isVerbose()`". Largest test
|
|
235
|
+
rewrite in this group but pure subtraction (~60 lines of fake module
|
|
236
|
+
deleted).
|
|
237
|
+
|
|
238
|
+
### 3. `src/llm/embedder` — 3 test files
|
|
239
|
+
|
|
240
|
+
Facade module; several mocked names are re-exports of pure constants/math
|
|
241
|
+
that need **no seam** (`DEFAULT_LOCAL_MODEL` constant, `cosineSimilarity`
|
|
242
|
+
math — the real ones satisfy every test).
|
|
243
|
+
|
|
244
|
+
- **Binding** (embedder.ts, after the `_localEmbedder` singleton at :50):
|
|
245
|
+
```ts
|
|
246
|
+
interface EmbedderOverridesForTests {
|
|
247
|
+
embed?: typeof embed;
|
|
248
|
+
embedBatch?: typeof embedBatch;
|
|
249
|
+
resolveEmbeddingModelId?: typeof resolveEmbeddingModelId;
|
|
250
|
+
checkEmbeddingAvailability?: typeof checkEmbeddingAvailability;
|
|
251
|
+
isTransformersAvailable?: () => boolean;
|
|
252
|
+
}
|
|
253
|
+
let embedderOverrides: EmbedderOverridesForTests | undefined;
|
|
254
|
+
```
|
|
255
|
+
- **Hook**:
|
|
256
|
+
```ts
|
|
257
|
+
export function _setEmbedderForTests(fakes?: EmbedderOverridesForTests): void;
|
|
258
|
+
```
|
|
259
|
+
- Delegation: each listed export gains
|
|
260
|
+
`if (embedderOverrides?.embedBatch) return embedderOverrides.embedBatch(...)`
|
|
261
|
+
as its first line (bodies are already thin dispatchers; no `…Real` rename
|
|
262
|
+
needed except `isTransformersAvailable`, which is currently a re-export from
|
|
263
|
+
`./embedders/local` (embedder.ts:39) and must become a 3-line delegating
|
|
264
|
+
wrapper in the facade — importers unchanged).
|
|
265
|
+
- **Implementation-time check**: grep that consumers under these tests import
|
|
266
|
+
from the facade (`src/llm/embedder`), not `./embedders/local` directly; a
|
|
267
|
+
direct submodule import bypasses the facade seam. (indexer and setup do use
|
|
268
|
+
the facade per the facade's own doc comment.)
|
|
269
|
+
- **Test migration**:
|
|
270
|
+
- `tests/integration/indexer.test.ts` — spreads real via specifier
|
|
271
|
+
`'../../src/llm/embedder.js'` with a mutable `embedBatch` impl var →
|
|
272
|
+
`overrideSeam(_setEmbedderForTests, { embedBatch: (...) => impl(...) })`.
|
|
273
|
+
Kills the `.js`-specifier fragility entirely. *(This flat path no longer
|
|
274
|
+
exists; indexer tests now live under `tests/indexer/` and
|
|
275
|
+
`tests/integration/indexer/` as multiple smaller files.)*
|
|
276
|
+
- `tests/commands/improve/dedup-cache-wiring.test.ts` — mocks
|
|
277
|
+
`{embedBatch, resolveEmbeddingModelId, cosineSimilarity}` WITHOUT
|
|
278
|
+
spreading → seam `{embedBatch, resolveEmbeddingModelId}`; real
|
|
279
|
+
`cosineSimilarity` is used as-is. Deletes the "mock.module must run before
|
|
280
|
+
import" dance; `dedup` can be statically imported. *(This path no longer
|
|
281
|
+
exists; `tests/integration/commands/consolidate/consolidate-promote-dedup.test.ts`
|
|
282
|
+
is the closest surviving dedup-focused test but is not confirmed as this
|
|
283
|
+
file's direct successor.)*
|
|
284
|
+
- `tests/integration/setup-run.test.ts` — replaces with only
|
|
285
|
+
`{DEFAULT_LOCAL_MODEL, isTransformersAvailable, checkEmbeddingAvailability}`
|
|
286
|
+
→ seam `{isTransformersAvailable, checkEmbeddingAvailability}`; real
|
|
287
|
+
`DEFAULT_LOCAL_MODEL`.
|
|
288
|
+
- Existing state hooks (`resetLocalEmbedder`, `clearEmbeddingCache`) already
|
|
289
|
+
run in `_preload.ts:resetSingletons` — unchanged.
|
|
290
|
+
|
|
291
|
+
### 4. `@huggingface/transformers` — 2 test files (seam lives in src, NOT the package)
|
|
292
|
+
|
|
293
|
+
Third-party, but the ONLY consumer is the dynamic
|
|
294
|
+
`await import("@huggingface/transformers")` inside
|
|
295
|
+
`LocalEmbedder.getPipeline` (src/llm/embedders/local.ts:220). That import is a
|
|
296
|
+
perfect internal binding:
|
|
297
|
+
|
|
298
|
+
- **Binding** (embedders/local.ts, module level):
|
|
299
|
+
```ts
|
|
300
|
+
type TransformersLoader = () => Promise<{ pipeline: unknown }>;
|
|
301
|
+
const realTransformersLoader: TransformersLoader = () =>
|
|
302
|
+
import("@huggingface/transformers") as Promise<{ pipeline: unknown }>;
|
|
303
|
+
let transformersLoader: TransformersLoader = realTransformersLoader;
|
|
304
|
+
```
|
|
305
|
+
- **Hook**:
|
|
306
|
+
```ts
|
|
307
|
+
export function _setTransformersLoaderForTests(fake?: TransformersLoader): void {
|
|
308
|
+
transformersLoader = fake ?? realTransformersLoader;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
Re-export from the facade `src/llm/embedder.ts` so tests import one module.
|
|
312
|
+
- `getPipeline` replaces the inline `await import(...)` with
|
|
313
|
+
`await transformersLoader()`. The MODULE_NOT_FOUND error-shaping branch
|
|
314
|
+
(local.ts:222-241) is untouched — a fake loader that throws a
|
|
315
|
+
`Cannot find module` error still exercises the binary-hint path.
|
|
316
|
+
- **Test migration**: `tests/integration/embedder.test.ts` and
|
|
317
|
+
`tests/integration/embedding-model-config.test.ts` both mock
|
|
318
|
+
`{pipeline}` today and already call `resetLocalEmbedder()` in `beforeEach`
|
|
319
|
+
(required — the cached `pipelinePromise` must not carry a previous loader's
|
|
320
|
+
result; the preload also resets it). Their fake `pipeline` factory moves
|
|
321
|
+
verbatim into `overrideSeam(_setTransformersLoaderForTests, async () => ({ pipeline: fakePipeline }))`.
|
|
322
|
+
- `isTransformersAvailable` (local.ts:289, `resolveModule` probe) is NOT
|
|
323
|
+
seamed here; the facade seam from module 3 covers the one test that fakes it.
|
|
324
|
+
|
|
325
|
+
### 5. `src/setup/registry-stash-loader` — 1 test file
|
|
326
|
+
|
|
327
|
+
- **Binding**: real body of `loadSetupStashes` (registry-stash-loader.ts:82)
|
|
328
|
+
→ private `loadSetupStashesReal`; exported delegator.
|
|
329
|
+
- **Hook**:
|
|
330
|
+
```ts
|
|
331
|
+
export function _setLoadSetupStashesForTests(fake?: typeof loadSetupStashes): void;
|
|
332
|
+
```
|
|
333
|
+
- `DEFAULT_SELECTED_STASH_IDS` is a plain exported const — no seam; the test's
|
|
334
|
+
mocked copy is deleted and the real constant used.
|
|
335
|
+
- **Test migration**: `tests/setup-wizard.test.ts:64` block →
|
|
336
|
+
`overrideSeam(_setLoadSetupStashesForTests, async () => fakeStashEntries)`.
|
|
337
|
+
(Alternative considered: `withMockedFetch` against the real fetch path —
|
|
338
|
+
rejected: couples the test to the registry JSON wire shape for no gain.)
|
|
339
|
+
NOTE: setup-wizard.test.ts also fakes `@clack/prompts` — originally deferred
|
|
340
|
+
as a kept `mock.module`, now migrated onto the `src/cli/clack` seam (see the
|
|
341
|
+
resolved deferred section at the bottom).
|
|
342
|
+
|
|
343
|
+
### 6. `src/tasks/backends` — 1 test file
|
|
344
|
+
|
|
345
|
+
`selectBackend(options)` already accepts injected backends
|
|
346
|
+
(src/tasks/backends/index.ts:59-69) but production callers invoke it with no
|
|
347
|
+
args — threading a fake backend through `akmTasksAdd` would be a call-site
|
|
348
|
+
change (forbidden). Module seam instead:
|
|
349
|
+
|
|
350
|
+
- **Binding** (index.ts):
|
|
351
|
+
```ts
|
|
352
|
+
interface BackendsOverridesForTests {
|
|
353
|
+
selectBackend?: typeof selectBackend;
|
|
354
|
+
backendNameForPlatform?: typeof backendNameForPlatform;
|
|
355
|
+
}
|
|
356
|
+
let backendsOverrides: BackendsOverridesForTests | undefined;
|
|
357
|
+
```
|
|
358
|
+
- **Hook**:
|
|
359
|
+
```ts
|
|
360
|
+
export function _setBackendsForTests(fakes?: BackendsOverridesForTests): void;
|
|
361
|
+
```
|
|
362
|
+
Both exports gain a first-line delegation check (bodies are small switches;
|
|
363
|
+
no rename needed).
|
|
364
|
+
- **Test migration**: `tests/integration/commands/tasks-write-target.test.ts` →
|
|
365
|
+
`overrideSeam(_setBackendsForTests, { selectBackend: () => fakeBackend, backendNameForPlatform: () => "cron" })`.
|
|
366
|
+
(Landed under `tests/integration/commands/`, not `tests/commands/`.)
|
|
367
|
+
|
|
368
|
+
### 7-14. The `tests/integration/setup-run.test.ts` cluster (one file, 74 `mock.module` calls across 9 near-identical blocks)
|
|
369
|
+
|
|
370
|
+
This file repeats the same ~10 mocks in every test block. Migrate it LAST, in
|
|
371
|
+
one pass, after all seams below exist. Each block's mock stanza collapses to a
|
|
372
|
+
single `installSetupSeams(overrides)` local helper (test-file-local function
|
|
373
|
+
calling `overrideSeam` per seam) — deleting ~600 lines of repeated mock
|
|
374
|
+
boilerplate. Per module:
|
|
375
|
+
|
|
376
|
+
#### 7. `src/core/config/config` — NO SEAM (subtract the mock)
|
|
377
|
+
|
|
378
|
+
`resetConfigCache()` exists (config.ts:124) and already runs in the preload.
|
|
379
|
+
The module is XDG-env-driven and the sandbox helpers
|
|
380
|
+
(`withIsolatedAkmStorage` / `sandboxXdgConfigHome` in tests/_helpers/sandbox.ts)
|
|
381
|
+
already isolate it. Migration: delete the mock; let the wizard read/write the
|
|
382
|
+
REAL config in the sandboxed XDG home. Assertions on "what was saved" read the
|
|
383
|
+
config file (or `loadUserConfig()`) from the sandbox instead of spying on
|
|
384
|
+
`saveConfig`. Fallback ONLY if an assertion truly needs call interception: a
|
|
385
|
+
minimal `_setSaveConfigForTests` — decide during implementation, default is
|
|
386
|
+
no seam.
|
|
387
|
+
|
|
388
|
+
#### 8. `src/core/paths` — NO SEAM (subtract the mock)
|
|
389
|
+
|
|
390
|
+
Pure functions of `process.env`; `getConfigDir`/`getDataDir` already take
|
|
391
|
+
`(env, platform)`. With sandboxed XDG env vars the mock is dead weight.
|
|
392
|
+
Migration: delete the mock block; assert against the sandbox paths.
|
|
393
|
+
|
|
394
|
+
#### 9. `src/setup/detect` — seam for the two network/host probes
|
|
395
|
+
|
|
396
|
+
- **Binding** (detect.ts):
|
|
397
|
+
```ts
|
|
398
|
+
interface DetectOverridesForTests {
|
|
399
|
+
detectOllama?: typeof detectOllama;
|
|
400
|
+
detectAgentPlatforms?: typeof detectAgentPlatforms;
|
|
401
|
+
}
|
|
402
|
+
let detectOverrides: DetectOverridesForTests | undefined;
|
|
403
|
+
```
|
|
404
|
+
- **Hook**: `export function _setDetectForTests(fakes?: DetectOverridesForTests): void;`
|
|
405
|
+
- `detectOllama` (detect.ts:44, network probe) and `detectAgentPlatforms`
|
|
406
|
+
(detect.ts:157, host scan) get first-line delegation. `detectLMStudio`,
|
|
407
|
+
`scanProviderEnvVars` (already env-injected), `pickDefaultModel` untouched.
|
|
408
|
+
|
|
409
|
+
#### 10. `src/commands/sources/init` — seam for `akmInit`
|
|
410
|
+
|
|
411
|
+
Single export, no state. Real body → `akmInitReal`; delegator +
|
|
412
|
+
`export function _setAkmInitForTests(fake?: typeof akmInit): void;`.
|
|
413
|
+
|
|
414
|
+
#### 11. `src/indexer/indexer` — seam for `akmIndex`
|
|
415
|
+
|
|
416
|
+
Today's full-module replacement leaves every OTHER export (e.g.
|
|
417
|
+
`buildFileBasenameMap`) `undefined` for the module under test — a latent bug
|
|
418
|
+
the seam fixes for free. Real body → `akmIndexReal`; delegator +
|
|
419
|
+
`export function _setAkmIndexForTests(fake?: typeof akmIndex): void;`. All
|
|
420
|
+
other exports stay real.
|
|
421
|
+
|
|
422
|
+
#### 12. `src/indexer/db/db` — DELETE THE STALE MOCK (no seam, decide fallback in-flight)
|
|
423
|
+
|
|
424
|
+
The current mock is **broken**: it exports `openDatabase`, but the real module
|
|
425
|
+
and setup.ts:41 use `openIndexDatabase` — under the mock, `openIndexDatabase`
|
|
426
|
+
is `undefined` and the vec-probe try/catch (setup.ts:582-600) silently
|
|
427
|
+
swallows the TypeError. The test has never exercised this path. Migration:
|
|
428
|
+
delete the mock and let the vec probe open a REAL index DB inside the
|
|
429
|
+
sandboxed tmp dirs (this is an integration test; that is the honest behavior
|
|
430
|
+
and un-swallows the probe). Fallback only if a real open proves too slow or
|
|
431
|
+
vec-extension-dependent in CI: minimal
|
|
432
|
+
`_setIndexDbForTests({ openIndexDatabase?, isVecAvailable? })` delegators.
|
|
433
|
+
Default is deletion. *(Landed as deletion, confirmed: `tests/integration/setup-run.test.ts`
|
|
434
|
+
has zero `mock.module` calls today. `src/indexer/db/db.ts` no longer exists —
|
|
435
|
+
`openIndexDatabase` now lives in `src/storage/repositories/index-connection.ts`
|
|
436
|
+
— though `setup-run.test.ts` still has a stale comment naming the old path.)*
|
|
437
|
+
|
|
438
|
+
#### 13. `src/integrations/agent` — seam in the DEFINING module
|
|
439
|
+
|
|
440
|
+
The test spreads the real barrel and overrides `detectAgentCliProfiles` +
|
|
441
|
+
`pickDefaultAgentProfile`. Both are defined in
|
|
442
|
+
`src/integrations/agent/detect.ts` (:81, :106) and re-exported by the barrel
|
|
443
|
+
(index.ts:33). **The seam must live in `detect.ts`** (a barrel re-export of a
|
|
444
|
+
delegator carries the seam automatically; seaming the barrel itself would not
|
|
445
|
+
affect direct `./detect` importers).
|
|
446
|
+
|
|
447
|
+
- **Binding** (integrations/agent/detect.ts):
|
|
448
|
+
```ts
|
|
449
|
+
interface AgentDetectOverridesForTests {
|
|
450
|
+
detectAgentCliProfiles?: typeof detectAgentCliProfiles;
|
|
451
|
+
pickDefaultAgentProfile?: typeof pickDefaultAgentProfile;
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
- **Hook**: `export function _setAgentDetectForTests(fakes?: AgentDetectOverridesForTests): void;`
|
|
455
|
+
(re-exported from the barrel so tests import one module).
|
|
456
|
+
|
|
457
|
+
#### 14. `src/commands/tasks/default-tasks` — seam for the three mocked exports
|
|
458
|
+
|
|
459
|
+
`registerDefaultTasks(deps)` and `isCiEnvironment(env = process.env)` already
|
|
460
|
+
have DI params, but setup.ts:19 imports and calls them bare — using the DI
|
|
461
|
+
params would be a call-site change (forbidden). Module seam:
|
|
462
|
+
|
|
463
|
+
- **Binding** (default-tasks.ts):
|
|
464
|
+
```ts
|
|
465
|
+
interface DefaultTasksOverridesForTests {
|
|
466
|
+
detectServerDefault?: typeof detectServerDefault;
|
|
467
|
+
isCiEnvironment?: typeof isCiEnvironment;
|
|
468
|
+
registerDefaultTasks?: typeof registerDefaultTasks;
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
- **Hook**: `export function _setDefaultTasksForTests(fakes?: DefaultTasksOverridesForTests): void;`
|
|
472
|
+
- First-line delegation on all three (note default-tasks.ts:179/:184 call
|
|
473
|
+
`isCiEnvironment()`/`detectServerDefault()` internally — through the
|
|
474
|
+
delegators, so overriding `detectServerDefault` alone still steers a real
|
|
475
|
+
`registerDefaultTasks`, which today's all-or-nothing mock cannot do).
|
|
476
|
+
- The existing `installDefaultTasksMock` beforeEach helper in setup-run
|
|
477
|
+
becomes an `overrideSeam` call.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Deferred — RESOLVED (deferral is over)
|
|
482
|
+
|
|
483
|
+
### `@clack/prompts` — src seam SHIPPED (`src/cli/clack.ts`); `mock.module` is at ZERO
|
|
484
|
+
|
|
485
|
+
Originally deferred because seaming a third-party package needs a src-side
|
|
486
|
+
wrapper module and the guardrails forbid new wrappers. The deferral was
|
|
487
|
+
overturned by an adversarial review that BLOCKED landing the branch on proof:
|
|
488
|
+
|
|
489
|
+
- **The leak proof made zero-mock mandatory.** A two-file probe showed Bun
|
|
490
|
+
`mock.module` registrations ARE visible in later test files in the same
|
|
491
|
+
process, and the preload's `mock.restore()` does NOT clear them. `--isolate`
|
|
492
|
+
was deleted on this branch (63a58d4a), and that deletion is only sound at
|
|
493
|
+
ZERO `mock.module` — three clack mocks was three too many.
|
|
494
|
+
- **A latent restore bug existed by construction:** setup-scheduled-tasks
|
|
495
|
+
captured `REAL_CLACK` via `await import("@clack/prompts")` AFTER its fake
|
|
496
|
+
was installed, so the `afterAll` "restore" re-registered the fake. The
|
|
497
|
+
mock/restore dance cannot be made safe; only a seam deletes the bug class.
|
|
498
|
+
|
|
499
|
+
Resolution (same pattern as the `@huggingface/transformers` loader seam in
|
|
500
|
+
`src/llm/embedders/local.ts` — a third-party module gets its seam in src):
|
|
501
|
+
|
|
502
|
+
- `src/cli/clack.ts` re-exports the clack surface the codebase uses (`intro`,
|
|
503
|
+
`outro`, `cancel`, `confirm`, `select`, `multiselect`, `text`, `spinner`,
|
|
504
|
+
`note`, `isCancel`, `log`) through call-time delegators over ONE binding,
|
|
505
|
+
with the canonical single `_setClackForTests(fake | undefined)` hook.
|
|
506
|
+
- The four src importers (setup.ts, cli/confirm.ts, sources/add-cli.ts,
|
|
507
|
+
sources/stash-cli.ts) switched their import specifier to the seam —
|
|
508
|
+
import-specifier changes only, zero signature/behavior changes.
|
|
509
|
+
- The three test files migrated onto `overrideSeam(_setClackForTests, …)`;
|
|
510
|
+
the REAL_CLACK capture/restore blocks and cache-busting dynamic module
|
|
511
|
+
reloads were deleted (static imports are safe again).
|
|
512
|
+
|
|
513
|
+
Standing rule: `mock.module(` must never reappear in `tests/` (grep-enforced
|
|
514
|
+
at review; the preload comment documents why). New third-party dependencies
|
|
515
|
+
that tests need to fake get a src-side seam module like this one.
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Implementation order (one commit per numbered step, gate green each time)
|
|
520
|
+
|
|
521
|
+
1. `tests/_helpers/seams.ts` + `tests/_preload.ts` wiring **+** `src/llm/client`
|
|
522
|
+
seam, migrating its 5 test files (proves the whole pattern end-to-end on the
|
|
523
|
+
easiest group).
|
|
524
|
+
2. `src/core/warn` sink seam — 3 files (includes the agent-builders rewrite).
|
|
525
|
+
3. `src/llm/embedder` facade seam — indexer.test.ts + dedup-cache-wiring
|
|
526
|
+
migrations (setup-run's embedder block waits for step 7).
|
|
527
|
+
4. `@huggingface/transformers` loader seam in `embedders/local.ts` — 2 files.
|
|
528
|
+
5. `src/setup/registry-stash-loader` — setup-wizard partial migration
|
|
529
|
+
(clack mock stays).
|
|
530
|
+
6. `src/tasks/backends` — tasks-write-target.
|
|
531
|
+
7. setup-run cluster, one seam-module at a time inside the single file:
|
|
532
|
+
add seams for detect / init / indexer / agent-detect / default-tasks;
|
|
533
|
+
delete the config + paths + indexer-db mocks (sandbox/real replacements);
|
|
534
|
+
dedupe the clack mock; collapse the 9 stanzas into `installSetupSeams()`.
|
|
535
|
+
|
|
536
|
+
Per-commit gate: `bun run check` (types + lint + unit/integration per repo
|
|
537
|
+
release-gate rule) — 0 errors, 0 warnings, 0 failures. Expected net effect:
|
|
538
|
+
~15-20 added lines per seamed src module vs hundreds of deleted mock lines in
|
|
539
|
+
tests (setup-run alone should shrink by roughly half).
|