akm-cli 0.9.16 → 0.9.17-alpha.10
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 +2101 -0
- package/STABILITY.md +11 -10
- package/dist/akm +124 -193
- package/dist/akm-migrate +38 -19
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/prompts/consolidate-system.md +4 -11
- package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/shared.js +6 -2
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +68 -10
- package/dist/commands/agent/agent-dispatch.js +1 -1
- package/dist/commands/command/command-execution.js +24 -62
- package/dist/commands/feedback-cli.js +0 -1
- package/dist/commands/health/accept-rate.js +6 -0
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/checks.js +83 -74
- package/dist/commands/health/config-skew.js +38 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/egress.js +54 -0
- package/dist/commands/health/html-report.js +1 -42
- package/dist/commands/health/improve-metrics.js +136 -591
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/plugin-staleness.js +53 -3
- package/dist/commands/health/renderers.js +12 -4
- package/dist/commands/health/report-view-model.js +14 -120
- package/dist/commands/health/types-improve.js +4 -19
- package/dist/commands/health/windows.js +64 -74
- package/dist/commands/health.js +145 -143
- package/dist/commands/improve/consolidate/chunking.js +26 -117
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate/sanitize.js +54 -149
- package/dist/commands/improve/consolidate.js +589 -1127
- package/dist/commands/improve/content-hash.js +16 -24
- package/dist/commands/improve/distill/content-repair.js +18 -100
- package/dist/commands/improve/distill-guards.js +20 -81
- package/dist/commands/improve/distill-promotion-policy.js +23 -243
- package/dist/commands/improve/distill.js +608 -1041
- package/dist/commands/improve/eligibility.js +126 -390
- package/dist/commands/improve/execution.js +8 -10
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/extract.js +487 -1046
- package/dist/commands/improve/feedback-valence.js +0 -25
- package/dist/commands/improve/improve-cli.js +75 -169
- package/dist/commands/improve/improve-result-file.js +10 -66
- package/dist/commands/improve/improve-strategies.js +52 -4
- package/dist/commands/improve/improve-usage-report.js +18 -64
- package/dist/commands/improve/improve.js +480 -1074
- package/dist/commands/improve/ledger.js +119 -0
- package/dist/commands/improve/locks.js +2 -8
- package/dist/commands/improve/loop-stages.js +415 -1073
- package/dist/commands/improve/memory/derived-ref.js +12 -77
- package/dist/commands/improve/memory/memory-belief.js +16 -118
- package/dist/commands/improve/memory/memory-improve.js +266 -14
- package/dist/commands/improve/outcome-loop.js +28 -156
- package/dist/commands/improve/planner.js +5 -15
- package/dist/commands/improve/preparation.js +779 -2319
- package/dist/commands/improve/proactive-maintenance.js +34 -101
- package/dist/commands/improve/reflect-noise.js +104 -280
- package/dist/commands/improve/reflect.js +642 -1353
- package/dist/commands/improve/retrieval-gate.js +127 -0
- package/dist/commands/improve/retrieval-scope.js +92 -0
- package/dist/commands/improve/salience.js +41 -240
- package/dist/commands/improve/session-asset.js +19 -100
- package/dist/commands/improve/stage.js +322 -0
- package/dist/commands/lint/base-linter.js +37 -15
- package/dist/commands/proposal/drain.js +261 -578
- package/dist/commands/proposal/proposal-cli.js +19 -20
- package/dist/commands/proposal/proposal-types.js +31 -24
- package/dist/commands/proposal/proposal.js +38 -8
- package/dist/commands/proposal/propose.js +134 -160
- package/dist/commands/proposal/repository.js +1097 -1394
- package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
- package/dist/commands/proposal/validators/proposal-validators.js +1 -1
- package/dist/commands/proposal/validators/proposals.js +22 -89
- package/dist/commands/read/curate.js +105 -462
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/search-cli.js +16 -33
- package/dist/commands/read/search.js +17 -23
- package/dist/commands/read/show.js +57 -108
- package/dist/commands/sources/bundle-cli.js +25 -2
- package/dist/commands/sources/bundle-config-ops.js +4 -0
- package/dist/commands/sources/dangerous-env-audit.js +1 -2
- package/dist/commands/sources/info.js +127 -29
- package/dist/commands/sources/installed-stashes.js +197 -746
- package/dist/commands/sources/schema-repair.js +98 -129
- package/dist/commands/sources/source-add.js +62 -12
- package/dist/commands/sources/source-manage.js +9 -2
- package/dist/commands/sources/stash-cli.js +24 -4
- package/dist/commands/tasks/explain.js +10 -13
- package/dist/commands/tasks/tasks-cli.js +12 -13
- package/dist/commands/tasks/tasks.js +350 -936
- package/dist/commands/tasks/validate.js +26 -24
- package/dist/commands/workflow/plan.js +22 -29
- package/dist/commands/workflow-cli.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +2 -1
- package/dist/core/adapter/adapters/akm-lint.js +2 -3
- package/dist/core/adapter/adapters/akm-metadata.js +42 -12
- package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +17 -29
- package/dist/core/asset/asset-placement.js +4 -13
- package/dist/core/asset/frontmatter.js +106 -1
- package/dist/core/asset/resolve-ref.js +1 -1
- package/dist/core/bundle-id.js +42 -5
- package/dist/core/bundle-rename.js +285 -0
- package/dist/core/config/config-io.js +1 -2
- package/dist/core/config/config-schema.js +9 -34
- package/dist/core/config/config-walker.js +1 -1
- package/dist/core/config/config.js +184 -111
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/legacy-source-shape-shim.js +38 -9
- package/dist/core/config/schema/embedding.js +20 -5
- package/dist/core/config/schema/engines.js +5 -0
- package/dist/core/config/schema/execution.js +1 -1
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/improve-processes.js +54 -125
- package/dist/core/config/schema/improve.js +4 -42
- package/dist/core/config/schema/index-config.js +9 -48
- package/dist/core/config/schema/scheduler.js +12 -12
- package/dist/core/config/schema/search.js +6 -22
- package/dist/core/env-secret-ref.js +0 -1
- package/dist/core/errors.js +8 -9
- package/dist/core/file-change.js +13 -5
- package/dist/core/file-lock.js +76 -173
- package/dist/core/improve-result.js +35 -7
- package/dist/core/improve-types.js +0 -1
- package/dist/core/logs-db.js +2 -2
- package/dist/core/loopback.js +7 -12
- package/dist/core/non-task-input.js +20 -0
- package/dist/core/parse.js +13 -16
- package/dist/core/paths.js +0 -24
- package/dist/core/redaction.js +109 -2
- package/dist/core/run-lock.js +2 -5
- package/dist/core/spawn-env.js +1 -1
- package/dist/core/state/migrations.js +123 -61
- package/dist/core/state-db-scope.js +2 -4
- package/dist/core/state-db.js +126 -692
- package/dist/core/time.js +0 -20
- package/dist/core/type-presentation.js +1 -9
- package/dist/core/write-source.js +294 -1005
- package/dist/execution/input-contract.js +1 -1
- package/dist/execution/resolved-request.js +135 -689
- package/dist/execution/source.js +63 -257
- package/dist/execution/target-ref.js +1 -1
- package/dist/indexer/bundle-identity-guard.js +2 -2
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +77 -73
- package/dist/indexer/index-rebuild-lock.js +3 -11
- package/dist/indexer/index-writer-lock.js +8 -17
- package/dist/indexer/index-written-assets.js +141 -154
- package/dist/indexer/indexer.js +400 -1124
- package/dist/indexer/links/declared-links.js +90 -0
- package/dist/indexer/materialize-embeddings.js +60 -397
- package/dist/indexer/passes/memory-inference.js +96 -90
- package/dist/indexer/passes/metadata.js +132 -219
- package/dist/indexer/read-preflight.js +0 -7
- package/dist/indexer/scan/doc-to-entry.js +2 -3
- package/dist/indexer/scan/drain-dir.js +1 -1
- package/dist/indexer/search/db-search.js +190 -590
- package/dist/indexer/search/fts-query.js +30 -41
- package/dist/indexer/search/ranking.js +28 -154
- package/dist/indexer/search/search-attribution.js +12 -32
- package/dist/indexer/search/search-fields.js +11 -15
- package/dist/indexer/search/search-hit-enrichers.js +54 -85
- package/dist/indexer/search/search-source.js +1 -4
- package/dist/indexer/usage/usage-events.js +36 -7
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/integrations/agent/engine-fallback.js +23 -40
- package/dist/integrations/agent/engine-resolution.js +93 -183
- package/dist/integrations/agent/execution.js +507 -0
- package/dist/integrations/agent/model-map.js +28 -156
- package/dist/integrations/agent/request-lowering.js +66 -141
- package/dist/integrations/agent/runner-dispatch.js +143 -321
- package/dist/integrations/agent/runner.js +54 -14
- package/dist/integrations/lockfile.js +53 -101
- package/dist/llm/client.js +18 -6
- package/dist/llm/embedders/deterministic.js +2 -3
- package/dist/llm/embedders/profile.js +71 -0
- package/dist/llm/embedders/remote.js +11 -17
- package/dist/llm/feature-gate.js +0 -8
- package/dist/llm/index-passes.js +3 -5
- package/dist/llm/memory-infer.js +1 -2
- package/dist/llm/structured-call.js +5 -24
- package/dist/output/generic-render.js +23 -11
- package/dist/output/html-render.js +13 -10
- package/dist/output/render-registry.js +3 -32
- package/dist/output/shapes/helpers.js +25 -38
- package/dist/output/shapes/passthrough.js +1 -9
- package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
- package/dist/output/text/command-format.js +69 -31
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +5 -14
- package/dist/output/text/proposal-format.js +48 -3
- package/dist/output/text/show-format.js +13 -17
- package/dist/output/text/workflow-format.js +0 -32
- package/dist/output/text.js +2 -0
- package/dist/registry/factory.js +4 -19
- package/dist/registry/network.js +66 -220
- package/dist/registry/providers/index.js +0 -2
- package/dist/registry/providers/skills-sh.js +3 -14
- package/dist/registry/providers/static-index.js +24 -26
- package/dist/registry/resolve.js +55 -131
- package/dist/scripts/akm-migrate-node.js +42948 -92369
- package/dist/scripts/akm-migrate.js +42935 -92354
- package/dist/setup/registry-stash-loader.js +4 -13
- package/dist/setup/semantic-assets.js +3 -44
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/setup/steps/tasks.js +25 -15
- package/dist/sources/provider-factory.js +17 -18
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +7 -1
- package/dist/sources/providers/git-provider.js +0 -3
- package/dist/sources/providers/git-stash.js +83 -21
- package/dist/sources/providers/npm.js +2 -4
- package/dist/sources/providers/provider-utils.js +5 -10
- package/dist/sources/providers/website.js +0 -2
- package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
- package/dist/sources/website-url.js +2 -2
- package/dist/storage/database.js +9 -35
- package/dist/storage/repositories/improve-ledger-repository.js +209 -0
- package/dist/storage/repositories/index-connection.js +39 -72
- package/dist/storage/repositories/index-entries-repository.js +131 -129
- package/dist/storage/repositories/index-entry-mapper.js +1 -2
- package/dist/storage/repositories/index-entry-schema.js +101 -268
- package/dist/storage/repositories/index-fts-repository.js +86 -256
- package/dist/storage/repositories/index-links-repository.js +143 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
- package/dist/storage/repositories/index-meta-repository.js +6 -4
- package/dist/storage/repositories/index-schema.js +257 -325
- package/dist/storage/repositories/index-utility-repository.js +8 -29
- package/dist/storage/repositories/index-vec-repository.js +133 -414
- package/dist/storage/repositories/outcome-repository.js +2 -1
- package/dist/storage/repositories/proposals-repository.js +104 -1
- package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/dist/storage/repositories/task-history-repository.js +26 -4
- package/dist/storage/repositories/workflow-runs-repository.js +53 -244
- package/dist/storage/sqlite-migrations.js +136 -0
- package/dist/storage/sqlite-pragmas.js +11 -9
- package/dist/storage/sqlite-transaction.js +170 -0
- package/dist/storage/state-db-integrity.js +130 -0
- package/dist/tasks/activation-config.js +134 -62
- package/dist/tasks/backends/cron.js +191 -302
- package/dist/tasks/backends/exec-utils.js +2 -5
- package/dist/tasks/backends/launchd.js +141 -748
- package/dist/tasks/backends/schtasks.js +119 -623
- package/dist/tasks/prepare/prepare-support.js +5 -15
- package/dist/tasks/prepare/prepare.js +0 -2
- package/dist/tasks/resolve-akm-bin.js +20 -79
- package/dist/tasks/run/attempt-lifecycle.js +0 -1
- package/dist/tasks/run/load-task.js +1 -1
- package/dist/tasks/scheduler-binding.js +20 -238
- package/dist/tasks/scheduler-invocation.js +136 -244
- package/dist/tasks/scheduler-lock.js +53 -0
- package/dist/tasks/scheduler-sync.js +368 -679
- package/dist/tasks/source/parse-task-source.js +55 -9
- package/dist/tasks/source/task-source-v3-frozen.js +3 -4
- package/dist/tasks/source/task-to-v4.js +464 -88
- package/dist/workflows/authoring/authoring.js +3 -12
- package/dist/workflows/compile.js +211 -0
- package/dist/workflows/concurrency-policy.js +13 -74
- package/dist/workflows/exec/child-invocation.js +3 -17
- package/dist/workflows/exec/child-workflow.js +32 -141
- package/dist/workflows/exec/dispatch-redaction.js +13 -53
- package/dist/workflows/exec/environment.js +98 -0
- package/dist/workflows/exec/exec-unit.js +33 -140
- package/dist/workflows/exec/frozen-judge.js +7 -59
- package/dist/workflows/exec/native-executor.js +82 -341
- package/dist/workflows/exec/param-secrets.js +29 -47
- package/dist/workflows/exec/run-workflow.js +154 -387
- package/dist/workflows/exec/scheduler.js +9 -36
- package/dist/workflows/exec/step-work.js +127 -430
- package/dist/workflows/exec/unit-dispatch.js +11 -63
- package/dist/workflows/exec/unit-writer.js +8 -52
- package/dist/workflows/exec/worktree.js +39 -273
- package/dist/workflows/freeze/child-output-references.js +4 -15
- package/dist/workflows/freeze/environment.js +99 -92
- package/dist/workflows/freeze/freeze.js +172 -0
- package/dist/workflows/freeze/step-values.js +19 -21
- package/dist/workflows/freeze/targets/child-workflow.js +23 -92
- package/dist/workflows/freeze/targets/command.js +10 -33
- package/dist/workflows/freeze/targets/script.js +5 -12
- package/dist/workflows/freeze/targets/shell.js +3 -6
- package/dist/workflows/freeze/targets/task.js +25 -80
- package/dist/workflows/freeze/task-bindings.js +20 -67
- package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
- package/dist/workflows/ir/params.js +6 -51
- package/dist/workflows/ir/plan-hash.js +2 -34
- package/dist/workflows/parser.js +140 -43
- package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
- package/dist/workflows/renderer.js +36 -69
- package/dist/workflows/resource-limits.js +12 -120
- package/dist/workflows/runtime/agent-identity.js +8 -40
- package/dist/workflows/runtime/run-outputs.js +3 -6
- package/dist/workflows/runtime/run-plan.js +316 -0
- package/dist/workflows/runtime/runs.js +48 -200
- package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
- package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/integration/bundling-akm.md +49 -42
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.17.md +43 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
- package/docs/reference/cli.md +232 -135
- package/docs/reference/configuration.md +71 -57
- package/docs/reference/data-and-telemetry.md +20 -21
- package/docs/reference/tasks.md +105 -39
- package/docs/reference/workflow-schema.md +14 -18
- package/docs/reference/workflows.md +6 -9
- package/package.json +1 -1
- package/schemas/akm-config.json +115 -738
- package/schemas/akm-workflow.json +1 -0
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/commands/health/advisories.js +0 -150
- package/dist/commands/health/metrics.js +0 -329
- package/dist/commands/health/surfaces.js +0 -102
- package/dist/commands/improve/anti-collapse.js +0 -83
- package/dist/commands/improve/collapse-detector.js +0 -432
- package/dist/commands/improve/consolidate/eligibility.js +0 -48
- package/dist/commands/improve/consolidate/merge.js +0 -149
- package/dist/commands/improve/distill/promote-memory.js +0 -291
- package/dist/commands/improve/distill/quality-gate.js +0 -337
- package/dist/commands/improve/eval-cases.js +0 -52
- package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
- package/dist/commands/improve/proposal-envelope.js +0 -31
- package/dist/commands/improve/run-context.js +0 -123
- package/dist/commands/improve/shared.js +0 -31
- package/dist/commands/improve/source-identity.js +0 -28
- package/dist/commands/improve/triage.js +0 -96
- package/dist/commands/proposal/drain-policies.js +0 -151
- package/dist/commands/sources/update-transaction.js +0 -220
- package/dist/core/action-contributors.js +0 -28
- package/dist/core/config/config-version-shim.js +0 -101
- package/dist/core/fs-txn.js +0 -405
- package/dist/core/lexical-score.js +0 -25
- package/dist/core/maintenance-barrier.js +0 -167
- package/dist/execution/executable-identity.js +0 -105
- package/dist/execution/guarded-source.js +0 -427
- package/dist/indexer/db/graph-db.js +0 -444
- package/dist/indexer/graph/graph-boost.js +0 -427
- package/dist/indexer/graph/graph-dedup.js +0 -95
- package/dist/indexer/graph/graph-extraction.js +0 -1108
- package/dist/indexer/search/name-match.js +0 -35
- package/dist/indexer/search/ranking-contributors.js +0 -515
- package/dist/indexer/search/ranking-types.js +0 -4
- package/dist/indexer/walk/project-context.js +0 -192
- package/dist/integrations/agent/execution-cascade.js +0 -566
- package/dist/integrations/agent/execution-definitions.js +0 -202
- package/dist/integrations/agent/execution-lowering.js +0 -841
- package/dist/integrations/agent/execution-preparation.js +0 -98
- package/dist/integrations/agent/inline-execution.js +0 -74
- package/dist/llm/graph-extract.js +0 -728
- package/dist/llm/metadata-enhance.js +0 -96
- package/dist/registry/create-provider-registry.js +0 -29
- package/dist/registry/pinned-request-helper.js +0 -247
- package/dist/registry/pinned-transport.js +0 -717
- package/dist/sources/providers/index.js +0 -14
- package/dist/storage/engines/sqlite-migrations.js +0 -271
- package/dist/storage/repositories/canaries-repository.js +0 -107
- package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
- package/dist/storage/repositories/registry-cache.js +0 -113
- package/dist/tasks/scheduler-sync-preview.js +0 -52
- package/dist/tasks/source/task-to-v3.js +0 -507
- package/dist/workflows/freeze/resolve-steps.js +0 -86
- package/dist/workflows/freeze/source-freeze.js +0 -64
- package/dist/workflows/ir/compile.js +0 -321
- package/dist/workflows/ir/environment-v4.js +0 -330
- package/dist/workflows/ir/freeze-v4.js +0 -153
- package/dist/workflows/ir/schema-v4.js +0 -745
- package/dist/workflows/ir/schema.js +0 -354
- package/dist/workflows/program/schema.js +0 -77
- package/dist/workflows/runtime/checkin.js +0 -57
- package/dist/workflows/runtime/plan-classifier.js +0 -196
- package/dist/workflows/runtime/unit-checkin.js +0 -45
- package/dist/workflows/runtime/unit-phases.js +0 -20
- package/dist/workflows/schema.js +0 -4
- package/dist/workflows/source-ir/compile.js +0 -200
- package/dist/workflows/source-ir/program.js +0 -50
- package/dist/workflows/source-ir/result.js +0 -26
- package/dist/workflows/source-ir/schema.js +0 -786
- package/dist/workflows/source-ir/triggers.js +0 -79
- package/dist/workflows/source-ir/uses.js +0 -40
- package/dist/workflows/validator.js +0 -60
|
@@ -169,10 +169,9 @@ function isInsideGitRepo(dir) {
|
|
|
169
169
|
/**
|
|
170
170
|
* Recursively collect every `.md` file under `root`.
|
|
171
171
|
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* instead of silently looking like a clean, empty scan.
|
|
172
|
+
* Used by memory-inference. Mirrors the `complete` tracking of the other
|
|
173
|
+
* walkers in this file: a directory that cannot be read makes the result
|
|
174
|
+
* incomplete instead of silently looking like a clean, empty scan.
|
|
176
175
|
*/
|
|
177
176
|
export function walkMarkdownFiles(root) {
|
|
178
177
|
const files = [];
|
|
@@ -3,72 +3,55 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { defaultWhich } from "./detect.js";
|
|
5
5
|
import { OPENCODE_SDK_SERVER_BIN } from "./profiles.js";
|
|
6
|
-
/**
|
|
7
|
-
* Engine name used for the synthesized entry. Matches the platform id so it
|
|
8
|
-
* reads correctly in `akm workflow status`, frozen plans, and error messages.
|
|
9
|
-
* A user-configured engine of the same name is preferred over synthesizing.
|
|
10
|
-
*/
|
|
6
|
+
/** Engine name used for the synthesized entry; matches the platform id. */
|
|
11
7
|
export const FALLBACK_ENGINE_NAME = "opencode-sdk";
|
|
12
8
|
/** Announcement text, surfaced once per run/dispatch. */
|
|
13
9
|
export const FALLBACK_ANNOUNCEMENT = `No engine is configured; falling back to \`${FALLBACK_ENGINE_NAME}\` via the ` +
|
|
14
10
|
`\`${OPENCODE_SDK_SERVER_BIN}\` binary on PATH — provider, model, and auth come ` +
|
|
15
11
|
"from opencode's own configuration. " +
|
|
16
12
|
"Run `akm setup`, or set `defaults.engine`, to choose explicitly.";
|
|
17
|
-
/**
|
|
18
|
-
* Failure suffix for every surface that needs an engine and found none.
|
|
19
|
-
* Owned HERE, beside the probe whose outcome it describes: the probe follows a
|
|
20
|
-
* configured `bin` when one is pinned, so a consumer restating "not on PATH"
|
|
21
|
-
* would misdescribe a missing absolute path.
|
|
22
|
-
*/
|
|
13
|
+
/** Failure suffix for every surface that needs an engine and found none. */
|
|
23
14
|
export const NO_ENGINE_MESSAGE_SUFFIX = `has no selected engine, and no usable \`${OPENCODE_SDK_SERVER_BIN}\` binary was found to fall back to.`;
|
|
24
|
-
/**
|
|
25
|
-
* Guidance used when the fallback itself is unavailable.
|
|
26
|
-
*
|
|
27
|
-
* The opencode route names a BINARY install, not `npm i @opencode-ai/sdk`:
|
|
28
|
-
* that package is an HTTP client with no dependencies and cannot serve
|
|
29
|
-
* anything on its own (see the module doc).
|
|
30
|
-
*/
|
|
15
|
+
/** Guidance used when the fallback itself is unavailable. */
|
|
31
16
|
export const NO_ENGINE_REMEDY = "Run `akm setup` to detect an installed agent, or set one explicitly: " +
|
|
32
17
|
'`akm config set engines.claude \'{"kind":"agent","platform":"claude"}\'` ' +
|
|
33
18
|
"then `akm config set defaults.engine claude`. " +
|
|
34
19
|
`Installing the \`${OPENCODE_SDK_SERVER_BIN}\` binary also works ` +
|
|
35
20
|
"(`npm i -g opencode-ai`) — akm falls back to it automatically.";
|
|
36
21
|
/**
|
|
37
|
-
*
|
|
38
|
-
* `opencode-sdk`
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
* The fallback engine when its `opencode` binary is present: an
|
|
23
|
+
* operator-configured `opencode-sdk` entry (whose pinned `bin`, possibly
|
|
24
|
+
* outside PATH, is what gets probed), else a bare opencode-sdk agent engine.
|
|
25
|
+
*/
|
|
26
|
+
export function fallbackEngineConfig(config, whichFn = defaultWhich) {
|
|
27
|
+
const existing = config.engines?.[FALLBACK_ENGINE_NAME];
|
|
28
|
+
const bin = existing?.kind === "agent" ? existing.bin : undefined;
|
|
29
|
+
if (!whichFn(bin ?? OPENCODE_SDK_SERVER_BIN))
|
|
30
|
+
return undefined;
|
|
31
|
+
return existing ?? { kind: "agent", platform: "opencode-sdk" };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* For diagnostics that report the effective engine: a config whose
|
|
35
|
+
* `defaults.engine` resolves, with the implicit `opencode-sdk` fallback when it
|
|
36
|
+
* does not and an opencode binary is present. Never mutates `config`; returns
|
|
37
|
+
* the same object when no fallback is needed.
|
|
43
38
|
*/
|
|
44
39
|
export function withEngineFallback(config, whichFn = defaultWhich) {
|
|
45
40
|
if (config.defaults?.engine)
|
|
46
41
|
return { config };
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// THAT bin rather than the bare command: a configured absolute path outside
|
|
50
|
-
// PATH is still a usable engine, and reporting it as missing would contradict
|
|
51
|
-
// the operator-configured-wins rule.
|
|
52
|
-
const existing = config.engines?.[FALLBACK_ENGINE_NAME];
|
|
53
|
-
if (!whichFn(existing?.bin ?? OPENCODE_SDK_SERVER_BIN))
|
|
42
|
+
const engine = fallbackEngineConfig(config, whichFn);
|
|
43
|
+
if (!engine)
|
|
54
44
|
return { config };
|
|
55
|
-
const engines = existing
|
|
56
|
-
? config.engines
|
|
57
|
-
: { ...(config.engines ?? {}), [FALLBACK_ENGINE_NAME]: { kind: "agent", platform: "opencode-sdk" } };
|
|
58
45
|
return {
|
|
59
46
|
config: {
|
|
60
47
|
...config,
|
|
61
|
-
engines,
|
|
48
|
+
engines: { ...(config.engines ?? {}), [FALLBACK_ENGINE_NAME]: engine },
|
|
62
49
|
defaults: { ...(config.defaults ?? {}), engine: FALLBACK_ENGINE_NAME },
|
|
63
50
|
},
|
|
64
51
|
fallbackEngineName: FALLBACK_ENGINE_NAME,
|
|
65
52
|
};
|
|
66
53
|
}
|
|
67
|
-
/**
|
|
68
|
-
* The announcement, but only when the fallback candidate is the engine that
|
|
69
|
-
* actually won selection. Returns `undefined` otherwise, so an explicitly
|
|
70
|
-
* selected engine never triggers a claim that opencode supplied the model.
|
|
71
|
-
*/
|
|
54
|
+
/** The announcement, but only when the fallback candidate is the engine that actually won selection. */
|
|
72
55
|
export function fallbackAnnouncement(fallbackEngineName, selectedEngineName) {
|
|
73
56
|
if (!fallbackEngineName || selectedEngineName !== fallbackEngineName)
|
|
74
57
|
return undefined;
|
|
@@ -14,21 +14,23 @@ import { warn } from "../../core/warn.js";
|
|
|
14
14
|
import { resolveSecretFromStore } from "../../sources/snapshot-fetchers/secret-seam.js";
|
|
15
15
|
import { getHarness } from "../harnesses/index.js";
|
|
16
16
|
import { DEFAULT_AGENT_TIMEOUT_MS, DEFAULT_LLM_TIMEOUT_MS } from "./config.js";
|
|
17
|
-
import { getBuiltinAgentProfile } from "./profiles.js";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
import { getBuiltinAgentProfile, OPENCODE_SDK_SERVER_BIN } from "./profiles.js";
|
|
18
|
+
const LLM_CONNECTION_FIELDS = [
|
|
19
|
+
"provider",
|
|
20
|
+
"endpoint",
|
|
21
|
+
"model",
|
|
22
|
+
"temperature",
|
|
23
|
+
"maxTokens",
|
|
24
|
+
"supportsJsonSchema",
|
|
25
|
+
"extraParams",
|
|
26
|
+
"contextLength",
|
|
27
|
+
"enableThinking",
|
|
28
|
+
"reasoningEffort",
|
|
29
|
+
];
|
|
27
30
|
function envName(reference) {
|
|
28
31
|
const match = /^\$(?:\{)?([A-Za-z_][A-Za-z0-9_]*)(?:\})?$/.exec(reference);
|
|
29
32
|
return match?.[1];
|
|
30
33
|
}
|
|
31
|
-
/** Expand a leading `~` the same way `loadSetupConfigFromFile` does for `--from <file>`. */
|
|
32
34
|
function expandHomePath(filePath) {
|
|
33
35
|
return filePath.startsWith("~") ? path.join(os.homedir(), filePath.slice(1)) : filePath;
|
|
34
36
|
}
|
|
@@ -36,12 +38,7 @@ function expandHomePath(filePath) {
|
|
|
36
38
|
function trimTrailingNewline(raw) {
|
|
37
39
|
return raw.replace(/\r?\n$/, "");
|
|
38
40
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Read a file-backed credential (#905) at the dispatch boundary. Never
|
|
41
|
-
* includes the file's content in a thrown message — only the engine name and
|
|
42
|
-
* path, so a misconfigured `apiKeyFile` cannot leak its (partial) contents
|
|
43
|
-
* into a log or error report.
|
|
44
|
-
*/
|
|
41
|
+
/** Read a file-backed credential; errors name the engine and path, never the contents. */
|
|
45
42
|
function readApiKeyFile(engineName, filePath) {
|
|
46
43
|
let raw;
|
|
47
44
|
try {
|
|
@@ -58,12 +55,7 @@ function readApiKeyFile(engineName, filePath) {
|
|
|
58
55
|
}
|
|
59
56
|
return value;
|
|
60
57
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Best-effort, non-throwing read of a file-backed credential's current value
|
|
63
|
-
* (#905), for redaction inventories and health probes that must never fail
|
|
64
|
-
* just because a value collector ran ahead of the real dispatch — a missing
|
|
65
|
-
* or empty file is reported by {@link readApiKeyFile} at the actual call.
|
|
66
|
-
*/
|
|
58
|
+
/** Best-effort, non-throwing read of a file-backed credential for redaction and health. */
|
|
67
59
|
export function lookupApiKeyFileValue(filePath) {
|
|
68
60
|
try {
|
|
69
61
|
const value = trimTrailingNewline(fs.readFileSync(filePath, "utf8"));
|
|
@@ -73,13 +65,7 @@ export function lookupApiKeyFileValue(filePath) {
|
|
|
73
65
|
return undefined;
|
|
74
66
|
}
|
|
75
67
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Best-effort, non-throwing read of a secret-store-backed credential's
|
|
78
|
-
* current value (#953), for redaction inventories and health probes that
|
|
79
|
-
* must never fail just because a value collector ran ahead of the real
|
|
80
|
-
* dispatch — an unresolvable reference is reported by
|
|
81
|
-
* {@link resolveLlmCredentialValue} at the actual call.
|
|
82
|
-
*/
|
|
68
|
+
/** Best-effort, non-throwing read of a secret-store credential for redaction and health. */
|
|
83
69
|
export function lookupApiKeySecretRefValue(ref) {
|
|
84
70
|
try {
|
|
85
71
|
return resolveSecret(ref, resolveSecretFromStore);
|
|
@@ -90,52 +76,39 @@ export function lookupApiKeySecretRefValue(ref) {
|
|
|
90
76
|
}
|
|
91
77
|
function selectedEngineName(config, layers, llmOnly) {
|
|
92
78
|
for (let index = layers.length - 1; index >= 0; index--) {
|
|
93
|
-
const
|
|
94
|
-
if (!layer)
|
|
95
|
-
continue;
|
|
96
|
-
const engine = ownValue(layer, "engine");
|
|
79
|
+
const engine = layers[index]?.engine;
|
|
97
80
|
if (engine !== undefined)
|
|
98
81
|
return engine;
|
|
99
82
|
}
|
|
100
|
-
|
|
101
|
-
return defaults ? ownValue(defaults, llmOnly ? "llmEngine" : "engine") : undefined;
|
|
83
|
+
return llmOnly ? config.defaults?.llmEngine : config.defaults?.engine;
|
|
102
84
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const engine = engines && hasOwn(engines, name) ? engines[name] : undefined;
|
|
106
|
-
if (!engine)
|
|
85
|
+
/** The configured engine of this name; an unconfigured name is an error. */
|
|
86
|
+
export function configuredEngine(name, config) {
|
|
87
|
+
const engine = config.engines && Object.hasOwn(config.engines, name) ? config.engines[name] : undefined;
|
|
88
|
+
if (!engine)
|
|
107
89
|
throw new ConfigError(`Engine "${name}" is not configured.`, "INVALID_CONFIG_FILE");
|
|
108
|
-
}
|
|
109
90
|
return engine;
|
|
110
91
|
}
|
|
111
92
|
function resolveCredential(name, engine, config) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const explicit = envName(apiKey);
|
|
93
|
+
if (engine.apiKey !== undefined) {
|
|
94
|
+
const explicit = envName(engine.apiKey);
|
|
115
95
|
if (explicit)
|
|
116
96
|
return { names: [explicit], required: true };
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
// apiKeyFile above is its own credential source.
|
|
120
|
-
if (SECRET_STORE_REFERENCE_PATTERN.test(apiKey))
|
|
97
|
+
// A secret-store reference is carried as `apiKeySecretRef` instead.
|
|
98
|
+
if (SECRET_STORE_REFERENCE_PATTERN.test(engine.apiKey))
|
|
121
99
|
return undefined;
|
|
122
100
|
throw new ConfigError(`Engine "${name}" has an invalid symbolic apiKey reference.`, "INVALID_CONFIG_FILE");
|
|
123
101
|
}
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
if (ownValue(engine, "apiKeyFile") !== undefined)
|
|
102
|
+
// An explicit apiKeyFile is its own credential source; it does not also
|
|
103
|
+
// fall through to the implicit AKM_ENGINE_<NAME>_API_KEY convention.
|
|
104
|
+
if (engine.apiKeyFile !== undefined)
|
|
128
105
|
return undefined;
|
|
129
106
|
const specific = `AKM_ENGINE_${name.toUpperCase().replaceAll("-", "_")}_API_KEY`;
|
|
130
|
-
|
|
131
|
-
return (defaults ? ownValue(defaults, "llmEngine") : undefined) === name
|
|
107
|
+
return config.defaults?.llmEngine === name
|
|
132
108
|
? { names: [specific, "AKM_LLM_API_KEY"], required: false }
|
|
133
109
|
: { names: [specific], required: false };
|
|
134
110
|
}
|
|
135
|
-
/**
|
|
136
|
-
* Lookup-only credential projection used by redaction inventories. Returns the
|
|
137
|
-
* first non-empty trimmed value without enforcing a required descriptor.
|
|
138
|
-
*/
|
|
111
|
+
/** Lookup-only credential projection used by redaction inventories. */
|
|
139
112
|
export function lookupCredentialFromEnv(credential, envSource = process.env) {
|
|
140
113
|
for (const name of credential?.names ?? []) {
|
|
141
114
|
const candidate = envSource[name]?.trim();
|
|
@@ -144,10 +117,7 @@ export function lookupCredentialFromEnv(credential, envSource = process.env) {
|
|
|
144
117
|
}
|
|
145
118
|
return undefined;
|
|
146
119
|
}
|
|
147
|
-
/**
|
|
148
|
-
* The enforcing env-credential seam. Live and frozen dispatch use the same
|
|
149
|
-
* ordered lookup; a missing required descriptor names its primary variable.
|
|
150
|
-
*/
|
|
120
|
+
/** The enforcing env-credential lookup; a missing required descriptor names its primary variable. */
|
|
151
121
|
export function resolveCredentialFromEnv(credential, envSource = process.env) {
|
|
152
122
|
const value = lookupCredentialFromEnv(credential, envSource);
|
|
153
123
|
if (value)
|
|
@@ -158,12 +128,9 @@ export function resolveCredentialFromEnv(credential, envSource = process.env) {
|
|
|
158
128
|
return undefined;
|
|
159
129
|
}
|
|
160
130
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* Call this once per operation — lease acquisition, or direct materialize —
|
|
165
|
-
* so a whole operation observes one stable credential value instead of
|
|
166
|
-
* re-reading the file on every dispatch within it.
|
|
131
|
+
* Resolve one LLM credential value at the dispatch boundary: the env
|
|
132
|
+
* descriptor first, then the file-backed value, then the secret-store
|
|
133
|
+
* reference. Nothing before dispatch reads any of them.
|
|
167
134
|
*/
|
|
168
135
|
export function resolveLlmCredentialValue(engine, credential, apiKeyFile, apiKeySecretRef, envSource = process.env) {
|
|
169
136
|
const envValue = resolveCredentialFromEnv(credential, envSource);
|
|
@@ -171,25 +138,12 @@ export function resolveLlmCredentialValue(engine, credential, apiKeyFile, apiKey
|
|
|
171
138
|
return envValue;
|
|
172
139
|
if (apiKeyFile !== undefined)
|
|
173
140
|
return readApiKeyFile(engine, apiKeyFile);
|
|
174
|
-
// #953: a secret-store reference is the last fallback tier, reusing the
|
|
175
|
-
// same resolveSecret() helper llm/client.ts and embedders/remote.ts call
|
|
176
|
-
// directly — throws SECRET_REFERENCE_UNRESOLVED naming only the reference.
|
|
177
141
|
return apiKeySecretRef !== undefined ? resolveSecret(apiKeySecretRef, resolveSecretFromStore) : undefined;
|
|
178
142
|
}
|
|
179
143
|
/**
|
|
180
|
-
* Non-throwing credential-presence check for `akm health
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* a secret-store reference resolves. Never reads env/disk/store speculatively
|
|
184
|
-
* beyond what's needed to answer "is something here", and never throws on a
|
|
185
|
-
* broken/missing source — that is reported by {@link resolveLlmCredentialValue}
|
|
186
|
-
* at the real dispatch.
|
|
187
|
-
*
|
|
188
|
-
* On failure, `reference` and `reason` name WHICH env var / file / secret
|
|
189
|
-
* reference is missing (never its value) — the operator's own shell often
|
|
190
|
-
* passes the same check a scheduler's stripped-down environment fails, so the
|
|
191
|
-
* caller needs to say which reference is the problem. Callers that must never
|
|
192
|
-
* name the reference (`akm health`'s evidence/message) use only `.available`.
|
|
144
|
+
* Non-throwing credential-presence check for `akm health` and improve's
|
|
145
|
+
* strategy probe. Names WHICH env var / file / secret reference is missing,
|
|
146
|
+
* never its value; a broken source is reported by the real dispatch.
|
|
193
147
|
*/
|
|
194
148
|
export function describeLlmCredentialAvailability(resolved, env = process.env) {
|
|
195
149
|
if (resolved.credential?.required) {
|
|
@@ -218,18 +172,13 @@ export function describeLlmCredentialAvailability(resolved, env = process.env) {
|
|
|
218
172
|
}
|
|
219
173
|
return { available: true };
|
|
220
174
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Thin boolean wrapper over {@link describeLlmCredentialAvailability} for
|
|
223
|
-
* callers (`akm health`'s engine-reachability probes) that only need a
|
|
224
|
-
* yes/no answer and never surface the reference.
|
|
225
|
-
*/
|
|
226
175
|
export function isLlmCredentialAvailable(resolved, env = process.env) {
|
|
227
176
|
return describeLlmCredentialAvailability(resolved, env).available;
|
|
228
177
|
}
|
|
229
|
-
/** Collect
|
|
178
|
+
/** Collect every configured engine's current credential value for output and persistence redaction. */
|
|
230
179
|
export function collectEngineCredentialValues(config, envSource = process.env) {
|
|
231
180
|
const values = new Set();
|
|
232
|
-
for (const [name, engine] of Object.entries(
|
|
181
|
+
for (const [name, engine] of Object.entries(config.engines ?? {})) {
|
|
233
182
|
if (engine.kind !== "llm")
|
|
234
183
|
continue;
|
|
235
184
|
for (const envVar of resolveCredential(name, engine, config)?.names ?? []) {
|
|
@@ -237,19 +186,15 @@ export function collectEngineCredentialValues(config, envSource = process.env) {
|
|
|
237
186
|
if (value)
|
|
238
187
|
values.add(value);
|
|
239
188
|
}
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (apiKeyFile !== undefined) {
|
|
245
|
-
const value = lookupApiKeyFileValue(expandHomePath(apiKeyFile));
|
|
189
|
+
// File and secret-store lookups are best-effort so one broken engine never
|
|
190
|
+
// stops redaction from collecting every other engine's value.
|
|
191
|
+
if (engine.apiKeyFile !== undefined) {
|
|
192
|
+
const value = lookupApiKeyFileValue(expandHomePath(engine.apiKeyFile));
|
|
246
193
|
if (value)
|
|
247
194
|
values.add(value);
|
|
248
195
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (apiKey !== undefined && SECRET_STORE_REFERENCE_PATTERN.test(apiKey)) {
|
|
252
|
-
const value = lookupApiKeySecretRefValue(apiKey);
|
|
196
|
+
if (engine.apiKey !== undefined && SECRET_STORE_REFERENCE_PATTERN.test(engine.apiKey)) {
|
|
197
|
+
const value = lookupApiKeySecretRefValue(engine.apiKey);
|
|
253
198
|
if (value)
|
|
254
199
|
values.add(value);
|
|
255
200
|
}
|
|
@@ -258,27 +203,17 @@ export function collectEngineCredentialValues(config, envSource = process.env) {
|
|
|
258
203
|
}
|
|
259
204
|
function effectiveTimeout(engine, layers, fallback) {
|
|
260
205
|
for (let index = layers.length - 1; index >= 0; index--) {
|
|
261
|
-
|
|
262
|
-
|
|
206
|
+
const layer = layers[index];
|
|
207
|
+
if (layer && Object.hasOwn(layer, "timeoutMs"))
|
|
208
|
+
return layer.timeoutMs ?? null;
|
|
263
209
|
}
|
|
264
|
-
return hasOwn(engine, "timeoutMs") ? (engine.timeoutMs ?? null) : fallback;
|
|
210
|
+
return Object.hasOwn(engine, "timeoutMs") ? (engine.timeoutMs ?? null) : fallback;
|
|
265
211
|
}
|
|
266
212
|
function rawLlmConnection(engine) {
|
|
267
|
-
const connection = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
temperature: ownValue(engine, "temperature"),
|
|
272
|
-
maxTokens: ownValue(engine, "maxTokens"),
|
|
273
|
-
supportsJsonSchema: ownValue(engine, "supportsJsonSchema"),
|
|
274
|
-
extraParams: ownValue(engine, "extraParams"),
|
|
275
|
-
contextLength: ownValue(engine, "contextLength"),
|
|
276
|
-
enableThinking: ownValue(engine, "enableThinking"),
|
|
277
|
-
reasoningEffort: ownValue(engine, "reasoningEffort"),
|
|
278
|
-
};
|
|
279
|
-
for (const key of Object.keys(connection)) {
|
|
280
|
-
if (connection[key] === undefined)
|
|
281
|
-
delete connection[key];
|
|
213
|
+
const connection = {};
|
|
214
|
+
for (const key of LLM_CONNECTION_FIELDS) {
|
|
215
|
+
if (engine[key] !== undefined)
|
|
216
|
+
connection[key] = engine[key];
|
|
282
217
|
}
|
|
283
218
|
return connection;
|
|
284
219
|
}
|
|
@@ -289,11 +224,10 @@ export function resolveLlmEngineUse(config, layers, options = {}) {
|
|
|
289
224
|
return undefined;
|
|
290
225
|
throw new ConfigError("No LLM engine is selected. Set defaults.llmEngine or specify engine.", "LLM_NOT_CONFIGURED");
|
|
291
226
|
}
|
|
292
|
-
const engine =
|
|
227
|
+
const engine = configuredEngine(name, config);
|
|
293
228
|
if (engine.kind !== "llm") {
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
const fallbackEngine = fallbackName ? resolveEngineConfig(fallbackName, config) : undefined;
|
|
229
|
+
const fallbackName = engine.llmEngine ?? config.defaults?.llmEngine;
|
|
230
|
+
const fallbackEngine = fallbackName ? configuredEngine(fallbackName, config) : undefined;
|
|
297
231
|
if (!fallbackEngine || fallbackEngine.kind !== "llm") {
|
|
298
232
|
if (options.optional)
|
|
299
233
|
return undefined;
|
|
@@ -308,55 +242,41 @@ export function resolveLlmEngineUse(config, layers, options = {}) {
|
|
|
308
242
|
}
|
|
309
243
|
let connection = rawLlmConnection(engine);
|
|
310
244
|
for (const layer of layers) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (
|
|
314
|
-
connection =
|
|
315
|
-
if (model !== undefined)
|
|
316
|
-
connection.model = model;
|
|
245
|
+
if (layer.llm)
|
|
246
|
+
connection = deepMergeConfig(connection, layer.llm);
|
|
247
|
+
if (layer.model !== undefined)
|
|
248
|
+
connection.model = layer.model;
|
|
317
249
|
}
|
|
318
250
|
for (const key of Object.keys(connection)) {
|
|
319
251
|
if (connection[key] === undefined)
|
|
320
252
|
delete connection[key];
|
|
321
253
|
}
|
|
322
|
-
const
|
|
323
|
-
const apiKeyRaw = ownValue(engine, "apiKey");
|
|
324
|
-
const apiKeySecretRef = apiKeyRaw !== undefined && SECRET_STORE_REFERENCE_PATTERN.test(apiKeyRaw) ? apiKeyRaw : undefined;
|
|
254
|
+
const apiKeySecretRef = engine.apiKey !== undefined && SECRET_STORE_REFERENCE_PATTERN.test(engine.apiKey) ? engine.apiKey : undefined;
|
|
325
255
|
return {
|
|
326
256
|
engine: name,
|
|
327
|
-
connection:
|
|
257
|
+
connection: connection,
|
|
328
258
|
credential: resolveCredential(name, engine, config),
|
|
329
|
-
...(apiKeyFile !== undefined ? { apiKeyFile: expandHomePath(apiKeyFile) } : {}),
|
|
259
|
+
...(engine.apiKeyFile !== undefined ? { apiKeyFile: expandHomePath(engine.apiKeyFile) } : {}),
|
|
330
260
|
...(apiKeySecretRef !== undefined ? { apiKeySecretRef } : {}),
|
|
331
261
|
timeoutMs: effectiveTimeout(engine, layers, DEFAULT_LLM_TIMEOUT_MS),
|
|
332
262
|
};
|
|
333
263
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Inject an already-resolved credential value into a connection. Callers
|
|
336
|
-
* resolve the value themselves via {@link resolveLlmCredentialValue} (or its
|
|
337
|
-
* lease-cached equivalent) — this function never reads env or disk itself, so
|
|
338
|
-
* a frozen `ResolvedLlmUse`/`RunnerSpec` plan object can be materialized
|
|
339
|
-
* repeatedly without re-triggering I/O per call.
|
|
340
|
-
*/
|
|
264
|
+
/** Inject an already-resolved credential value into a connection; reads nothing itself. */
|
|
341
265
|
export function materializeLlmConnectionWithCredential(resolved, credentialValue) {
|
|
342
|
-
const extraParams =
|
|
266
|
+
const extraParams = resolved.connection.extraParams;
|
|
343
267
|
if (extraParams !== undefined) {
|
|
344
268
|
const issue = validateExtraParams(extraParams)[0];
|
|
345
269
|
if (issue) {
|
|
346
270
|
throw new ConfigError(formatExtraParamsIssue(`Engine "${resolved.engine}" extraParams`, issue), "INVALID_CONFIG_FILE");
|
|
347
271
|
}
|
|
348
272
|
}
|
|
349
|
-
return
|
|
273
|
+
return {
|
|
350
274
|
...resolved.connection,
|
|
351
275
|
...(credentialValue ? { apiKey: credentialValue } : {}),
|
|
352
276
|
timeoutMs: resolved.timeoutMs,
|
|
353
|
-
}
|
|
277
|
+
};
|
|
354
278
|
}
|
|
355
|
-
/**
|
|
356
|
-
* Read and inject one resolved credential at the runtime boundary: the
|
|
357
|
-
* symbolic `$VAR` reference, or the file-backed alternative (#905) when the
|
|
358
|
-
* engine has no env descriptor.
|
|
359
|
-
*/
|
|
279
|
+
/** Read and inject one resolved credential at the runtime boundary. */
|
|
360
280
|
export function materializeLlmConnection(resolved, envSource = process.env) {
|
|
361
281
|
return materializeLlmConnectionWithCredential(resolved, resolveLlmCredentialValue(resolved.engine, resolved.credential, resolved.apiKeyFile, resolved.apiKeySecretRef, envSource));
|
|
362
282
|
}
|
|
@@ -368,33 +288,29 @@ function lowerAgentEngine(name, engine, config) {
|
|
|
368
288
|
const platform = harness.id;
|
|
369
289
|
const sdk = platform === "opencode-sdk";
|
|
370
290
|
const builtin = getBuiltinAgentProfile(platform);
|
|
371
|
-
const
|
|
372
|
-
const args = ownValue(engine, "args");
|
|
373
|
-
const workspace = ownValue(engine, "workspace");
|
|
374
|
-
const model = ownValue(engine, "model");
|
|
375
|
-
const profile = sterileRecord({
|
|
291
|
+
const profile = {
|
|
376
292
|
name,
|
|
377
293
|
platform,
|
|
378
294
|
personaChannel: sdk ? "native" : (harness.agentBuilder?.personaChannel ?? "prompt"),
|
|
379
|
-
bin: bin ?? builtin?.bin ?? (sdk ?
|
|
380
|
-
args: args ?? builtin?.args ?? [],
|
|
295
|
+
bin: engine.bin ?? builtin?.bin ?? (sdk ? OPENCODE_SDK_SERVER_BIN : platform),
|
|
296
|
+
args: engine.args ?? builtin?.args ?? [],
|
|
381
297
|
stdio: "captured",
|
|
382
298
|
...(builtin?.env ? { env: builtin.env } : {}),
|
|
383
299
|
envPassthrough: builtin?.envPassthrough ?? [],
|
|
384
300
|
parseOutput: "text",
|
|
385
|
-
...(workspace ? { workspace: path.resolve(workspace) } : {}),
|
|
386
|
-
...(model ? { model } : {}),
|
|
387
|
-
}
|
|
301
|
+
...(engine.workspace ? { workspace: path.resolve(engine.workspace) } : {}),
|
|
302
|
+
...(engine.model ? { model: engine.model } : {}),
|
|
303
|
+
};
|
|
304
|
+
const ownTimeout = Object.hasOwn(engine, "timeoutMs") ? (engine.timeoutMs ?? null) : undefined;
|
|
388
305
|
if (!sdk) {
|
|
389
306
|
return {
|
|
390
307
|
kind: "agent",
|
|
391
308
|
engine: name,
|
|
392
309
|
profile,
|
|
393
|
-
timeoutMs:
|
|
310
|
+
timeoutMs: ownTimeout !== undefined ? ownTimeout : DEFAULT_AGENT_TIMEOUT_MS,
|
|
394
311
|
};
|
|
395
312
|
}
|
|
396
|
-
const
|
|
397
|
-
const fallbackName = ownValue(engine, "llmEngine") ?? (defaults ? ownValue(defaults, "llmEngine") : undefined);
|
|
313
|
+
const fallbackName = engine.llmEngine ?? config.defaults?.llmEngine;
|
|
398
314
|
const fallback = fallbackName
|
|
399
315
|
? resolveLlmEngineUse(config, [{ engine: fallbackName }], { optional: true })
|
|
400
316
|
: undefined;
|
|
@@ -411,27 +327,21 @@ function lowerAgentEngine(name, engine, config) {
|
|
|
411
327
|
fallbackTimeoutMs: fallback.timeoutMs,
|
|
412
328
|
}
|
|
413
329
|
: {}),
|
|
414
|
-
timeoutMs:
|
|
415
|
-
? (engine.timeoutMs ?? null)
|
|
416
|
-
: (fallback?.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS),
|
|
330
|
+
timeoutMs: ownTimeout !== undefined ? ownTimeout : (fallback?.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS),
|
|
417
331
|
};
|
|
418
332
|
}
|
|
419
|
-
/**
|
|
420
|
-
export function resolveEngine(name, config) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
timeoutMs: resolved.timeoutMs,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
return lowerAgentEngine(name, engine, config);
|
|
333
|
+
/** Resolve a configured engine name to its runner: an LLM connection, a spawned agent, or the SDK. */
|
|
334
|
+
export function resolveEngine(name, config, engine = configuredEngine(name, config)) {
|
|
335
|
+
if (engine.kind !== "llm")
|
|
336
|
+
return lowerAgentEngine(name, engine, config);
|
|
337
|
+
const resolved = resolveLlmEngineUse(config, [{ engine: name }]);
|
|
338
|
+
return {
|
|
339
|
+
kind: "llm",
|
|
340
|
+
engine: name,
|
|
341
|
+
connection: resolved.connection,
|
|
342
|
+
...(resolved.credential ? { credential: resolved.credential } : {}),
|
|
343
|
+
...(resolved.apiKeyFile ? { apiKeyFile: resolved.apiKeyFile } : {}),
|
|
344
|
+
...(resolved.apiKeySecretRef ? { apiKeySecretRef: resolved.apiKeySecretRef } : {}),
|
|
345
|
+
timeoutMs: resolved.timeoutMs,
|
|
346
|
+
};
|
|
437
347
|
}
|