akm-cli 0.9.0-beta.6 → 0.9.0-rc.0
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 +663 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/help/help-improve.md +9 -6
- package/dist/assets/hints/cli-hints-full.md +6 -5
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/proactive-maintenance.json +25 -0
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/recombine-only.json +21 -0
- package/dist/assets/profiles/reflect-distill.json +30 -0
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +11 -3
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +45 -16
- package/dist/assets/wiki/schema-template.md +4 -4
- package/dist/cli/clack.js +56 -0
- package/dist/cli/config-migrate.js +7 -1
- package/dist/cli/confirm.js +1 -1
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +25 -14
- package/dist/commands/agent/agent-dispatch.js +3 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +26 -7
- package/dist/commands/config-cli.js +26 -13
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-cli.js +220 -227
- package/dist/commands/env/env.js +14 -67
- package/dist/commands/env/secret-cli.js +140 -138
- package/dist/commands/feedback-cli.js +153 -147
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +76 -72
- package/dist/commands/health/advisories.js +151 -0
- package/dist/commands/health/checks.js +103 -16
- package/dist/commands/health/html-report.js +447 -81
- package/dist/commands/health/improve-metrics.js +771 -0
- package/dist/commands/health/llm-usage.js +65 -0
- package/dist/commands/health/md-report.js +103 -0
- package/dist/commands/health/metrics.js +278 -0
- package/dist/commands/health/stash-exposure.js +46 -0
- package/dist/commands/health/surfaces.js +216 -0
- package/dist/commands/health/task-runs.js +135 -0
- package/dist/commands/health/types.js +26 -0
- package/dist/commands/health/windows.js +195 -0
- package/dist/commands/health.js +91 -1083
- package/dist/commands/improve/anti-collapse.js +170 -0
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/collapse-detector.js +421 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +64 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +1313 -1278
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill/content-repair.js +202 -0
- package/dist/commands/improve/distill/promote-memory.js +229 -0
- package/dist/commands/improve/distill/quality-gate.js +236 -0
- package/dist/commands/improve/distill-guards.js +127 -0
- package/dist/commands/improve/distill-promotion-policy.js +826 -167
- package/dist/commands/improve/distill.js +243 -599
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +179 -59
- package/dist/commands/improve/extract-prompt.js +55 -4
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +409 -43
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/hot-probation.js +45 -0
- package/dist/commands/improve/improve-auto-accept.js +160 -7
- package/dist/commands/improve/improve-cli.js +115 -73
- package/dist/commands/improve/improve-profiles.js +32 -8
- package/dist/commands/improve/improve-result-file.js +15 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +510 -2537
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1100 -0
- package/dist/commands/improve/memory/memory-belief.js +14 -15
- package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
- package/dist/commands/improve/memory/memory-improve.js +27 -27
- package/dist/commands/improve/outcome-loop.js +270 -0
- package/dist/commands/improve/preparation.js +2002 -0
- package/dist/commands/improve/proactive-maintenance.js +115 -0
- package/dist/commands/improve/procedural.js +398 -0
- package/dist/commands/improve/recombine.js +818 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +212 -45
- package/dist/commands/improve/salience.js +455 -0
- package/dist/commands/improve/schema-similarity-gate.js +168 -0
- package/dist/commands/improve/shared.js +51 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/observability-cli.js +4 -4
- package/dist/commands/proposal/drain-policies.js +13 -4
- package/dist/commands/proposal/drain.js +45 -51
- package/dist/commands/proposal/legacy-import.js +115 -0
- package/dist/commands/proposal/proposal-cli.js +24 -34
- package/dist/commands/proposal/proposal.js +7 -1
- package/dist/commands/proposal/propose.js +8 -3
- package/dist/commands/proposal/repository.js +829 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +93 -882
- package/dist/commands/read/curate.js +419 -103
- package/dist/commands/read/knowledge.js +10 -3
- package/dist/commands/read/remember-cli.js +133 -138
- package/dist/commands/read/search-cli.js +15 -8
- package/dist/commands/read/search.js +22 -11
- package/dist/commands/read/show.js +106 -14
- package/dist/commands/registry-cli.js +76 -87
- package/dist/commands/remember.js +11 -12
- package/dist/commands/sources/add-cli.js +91 -95
- package/dist/commands/sources/history.js +1 -1
- package/dist/commands/sources/init.js +66 -18
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/schema-repair.js +44 -46
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/sources-cli.js +3 -3
- package/dist/commands/sources/stash-cli.js +29 -41
- package/dist/commands/sources/stash-skeleton.js +57 -8
- package/dist/commands/tasks/default-tasks.js +15 -2
- package/dist/commands/tasks/tasks-cli.js +20 -29
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +23 -38
- package/dist/commands/workflow-cli.js +15 -1
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +21 -4
- package/dist/core/asset/frontmatter.js +188 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +4 -23
- package/dist/core/concurrent.js +10 -1
- package/dist/core/config/config-io.js +10 -1
- package/dist/core/config/config-migration.js +18 -40
- package/dist/core/config/config-schema.js +389 -58
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +67 -22
- package/dist/core/deep-merge.js +38 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/eval/rank-metrics.js +113 -0
- package/dist/core/events.js +4 -7
- package/dist/core/improve-types.js +47 -8
- package/dist/core/logs-db.js +14 -75
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +21 -18
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +770 -0
- package/dist/core/state-db.js +142 -1091
- package/dist/core/structured.js +69 -0
- package/dist/core/time.js +53 -0
- package/dist/core/warn.js +21 -0
- package/dist/core/write-source.js +37 -0
- package/dist/indexer/db/db.js +356 -780
- package/dist/indexer/db/entry-mapper.js +41 -0
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/db/schema.js +516 -0
- package/dist/indexer/ensure-index.js +103 -24
- package/dist/indexer/feedback/utility-policy.js +75 -0
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +207 -4
- package/dist/indexer/index-writer-lock.js +106 -0
- package/dist/indexer/index-written-assets.js +105 -0
- package/dist/indexer/indexer.js +291 -310
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/metadata.js +20 -0
- package/dist/indexer/read-preflight.js +23 -0
- package/dist/indexer/search/db-search.js +89 -13
- package/dist/indexer/search/fts-query.js +51 -0
- package/dist/indexer/search/ranking-contributors.js +95 -9
- package/dist/indexer/search/ranking.js +79 -3
- package/dist/indexer/search/search-fields.js +6 -0
- package/dist/indexer/search/search-source.js +32 -21
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +9 -0
- package/dist/indexer/walk/walker.js +21 -13
- package/dist/integrations/agent/builders.js +39 -13
- package/dist/integrations/agent/config.js +20 -59
- package/dist/integrations/agent/detect.js +9 -0
- package/dist/integrations/agent/index.js +3 -19
- package/dist/integrations/agent/model-aliases.js +7 -2
- package/dist/integrations/agent/profiles.js +7 -1
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +59 -0
- package/dist/integrations/agent/runner.js +13 -9
- package/dist/integrations/agent/spawn.js +69 -67
- package/dist/integrations/harnesses/claude/agent-builder.js +1 -1
- package/dist/integrations/harnesses/claude/index.js +2 -0
- package/dist/integrations/harnesses/claude/session-log.js +11 -1
- package/dist/integrations/harnesses/index.js +2 -3
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
- package/dist/integrations/harnesses/opencode/index.js +2 -0
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +98 -17
- package/dist/integrations/harnesses/types.js +1 -0
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/call-ai.js +2 -2
- package/dist/llm/client.js +57 -15
- package/dist/llm/embedder.js +67 -4
- package/dist/llm/embedders/cache.js +3 -1
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +73 -3
- package/dist/llm/feature-gate.js +16 -15
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +85 -14
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/helpers.js +0 -3
- package/dist/output/shapes/passthrough.js +2 -1
- package/dist/output/text/helpers.js +29 -1
- package/dist/output/text/workflow.js +1 -0
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +27 -9
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +2718 -2354
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +891 -597
- package/dist/setup/detect.js +9 -0
- package/dist/setup/legacy-config.js +106 -0
- package/dist/setup/prompt.js +57 -0
- package/dist/setup/providers.js +14 -0
- package/dist/setup/registry-stash-loader.js +12 -0
- package/dist/setup/semantic-assets.js +124 -0
- package/dist/setup/setup.js +52 -1614
- package/dist/setup/steps/connection.js +734 -0
- package/dist/setup/steps/output.js +31 -0
- package/dist/setup/steps/platforms.js +124 -0
- package/dist/setup/steps/semantic.js +27 -0
- package/dist/setup/steps/sources.js +222 -0
- package/dist/setup/steps/stashdir.js +42 -0
- package/dist/setup/steps/tasks.js +152 -0
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/canaries-repository.js +107 -0
- package/dist/storage/repositories/consolidation-repository.js +38 -0
- package/dist/storage/repositories/embeddings-repository.js +72 -0
- package/dist/storage/repositories/events-repository.js +187 -0
- package/dist/storage/repositories/extract-sessions-repository.js +96 -0
- package/dist/storage/repositories/improve-runs-repository.js +146 -0
- package/dist/storage/repositories/index-db.js +14 -8
- package/dist/storage/repositories/proposals-repository.js +220 -0
- package/dist/storage/repositories/recombine-repository.js +213 -0
- package/dist/storage/repositories/registry-cache.js +93 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
- package/dist/storage/repositories/task-history-repository.js +93 -0
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/index.js +9 -0
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +15 -13
- package/dist/text-import-hook.mjs +0 -0
- package/dist/wiki/wiki.js +52 -11
- package/dist/workflows/cli.js +1 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/runtime/runs.js +43 -118
- package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/README.md +69 -18
- package/docs/data-and-telemetry.md +5 -4
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +10 -10
- package/dist/assets/tasks/core/update-stashes.yml +0 -4
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
- package/dist/indexer/passes/staleness-detect.js +0 -488
|
@@ -1,8 +1,68 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { makeAssetRef } from "../../core/asset/asset-ref.js";
|
|
6
|
+
import { getStateDbPath } from "../../core/state-db.js";
|
|
7
|
+
import { openDatabase } from "../../storage/database.js";
|
|
4
8
|
import { getUtilityScoresByIds } from "../db/db.js";
|
|
5
|
-
import { applyScoreContributors, applyUtilityContributors } from "./ranking-contributors.js";
|
|
9
|
+
import { applyContributorAblation, applyScoreContributors, applyUtilityContributors, defaultRankingContributors, defaultUtilityRankingContributors, } from "./ranking-contributors.js";
|
|
10
|
+
/**
|
|
11
|
+
* R2 — best-effort load of `asset_salience.rank_score` from state.db for the
|
|
12
|
+
* ranked items. Fail-open: any error (state.db locked by a concurrent improve
|
|
13
|
+
* run, missing table, unreadable path) returns an empty map, which makes the
|
|
14
|
+
* salience contributor a no-op — byte-identical to pre-R2 ranking.
|
|
15
|
+
*
|
|
16
|
+
* Deliberately NOT `openStateDatabase()`: that helper runs migrations and sets
|
|
17
|
+
* a 30 s busy timeout — too heavy for a search hot path. This opens read-only,
|
|
18
|
+
* never creates or migrates state.db (missing file / missing table = empty
|
|
19
|
+
* map), and caps lock waits at 250 ms so a concurrent improve run can only
|
|
20
|
+
* ever cost the search a quarter second, not a stall.
|
|
21
|
+
*/
|
|
22
|
+
export function loadSalienceRankScores(items) {
|
|
23
|
+
const result = new Map();
|
|
24
|
+
if (items.length === 0)
|
|
25
|
+
return result;
|
|
26
|
+
try {
|
|
27
|
+
const dbPath = getStateDbPath();
|
|
28
|
+
if (!fs.existsSync(dbPath))
|
|
29
|
+
return result; // improve loop has never run here
|
|
30
|
+
const idByRef = new Map();
|
|
31
|
+
for (const item of items) {
|
|
32
|
+
idByRef.set(makeAssetRef(item.entry.type, item.entry.name), item.id);
|
|
33
|
+
}
|
|
34
|
+
const stateDb = openDatabase(dbPath, { readonly: true });
|
|
35
|
+
try {
|
|
36
|
+
try {
|
|
37
|
+
stateDb.exec("PRAGMA busy_timeout = 250");
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// pragma failure on a readonly handle is fine — default timeout applies
|
|
41
|
+
}
|
|
42
|
+
const refs = [...idByRef.keys()];
|
|
43
|
+
const CHUNK = 500;
|
|
44
|
+
for (let i = 0; i < refs.length; i += CHUNK) {
|
|
45
|
+
const chunk = refs.slice(i, i + CHUNK);
|
|
46
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
47
|
+
const rows = stateDb
|
|
48
|
+
.prepare(`SELECT asset_ref, rank_score FROM asset_salience WHERE asset_ref IN (${placeholders})`)
|
|
49
|
+
.all(...chunk);
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
const id = idByRef.get(row.asset_ref);
|
|
52
|
+
if (id !== undefined)
|
|
53
|
+
result.set(id, row.rank_score);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
stateDb.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Fail open — search must never break because state.db is unavailable.
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
6
66
|
export function normalizeFtsScores(results) {
|
|
7
67
|
const ftsScoreMap = new Map();
|
|
8
68
|
if (results.length === 0)
|
|
@@ -20,6 +80,7 @@ export function normalizeFtsScores(results) {
|
|
|
20
80
|
export function combineSearchScores(options) {
|
|
21
81
|
const FTS_WEIGHT = 0.7;
|
|
22
82
|
const VEC_WEIGHT = 0.3;
|
|
83
|
+
const excludeTypeSet = options.excludeTypes && options.excludeTypes.length > 0 ? new Set(options.excludeTypes) : null;
|
|
23
84
|
const scored = [];
|
|
24
85
|
const seenIds = new Set();
|
|
25
86
|
for (const [id, { score: ftsScore, result }] of options.ftsScoreMap) {
|
|
@@ -42,6 +103,9 @@ export function combineSearchScores(options) {
|
|
|
42
103
|
continue;
|
|
43
104
|
if (options.typeFilter && found.entry.type !== options.typeFilter)
|
|
44
105
|
continue;
|
|
106
|
+
// #627 — drop vector-only neighbors whose type is excluded on the default path.
|
|
107
|
+
if (excludeTypeSet?.has(found.entry.type))
|
|
108
|
+
continue;
|
|
45
109
|
scored.push({
|
|
46
110
|
id,
|
|
47
111
|
entry: found.entry,
|
|
@@ -63,19 +127,31 @@ export function applyRankingRules(options) {
|
|
|
63
127
|
graphContext: options.graphContext,
|
|
64
128
|
projectContext: options.projectContext,
|
|
65
129
|
};
|
|
130
|
+
// Eval/debug only: AKM_ABLATE_CONTRIBUTORS lets the ablation harness drop
|
|
131
|
+
// named contributors to measure their effect. Resolved once per query;
|
|
132
|
+
// a no-op (full lists) when the env var is unset — see applyContributorAblation.
|
|
133
|
+
const ablateEnv = process.env.AKM_ABLATE_CONTRIBUTORS;
|
|
134
|
+
const activeScoreContributors = applyContributorAblation(defaultRankingContributors, ablateEnv);
|
|
135
|
+
const activeUtilityContributors = applyContributorAblation(defaultUtilityRankingContributors, ablateEnv);
|
|
66
136
|
for (const item of options.items) {
|
|
67
|
-
applyScoreContributors(item, rankingContext);
|
|
137
|
+
applyScoreContributors(item, rankingContext, activeScoreContributors);
|
|
68
138
|
}
|
|
69
139
|
const { global: utilScoresMap, scoped: scopedUtilScoresMap } = getUtilityScoresByIds(options.db, options.items.map((item) => item.id), options.scopeKey);
|
|
140
|
+
// R2 — compose the improve loop's salience into user-facing ranking.
|
|
141
|
+
// undefined = load from state.db (default); null = explicitly disabled.
|
|
142
|
+
const salienceRankScores = options.salienceRankScores === null
|
|
143
|
+
? new Map()
|
|
144
|
+
: (options.salienceRankScores ?? loadSalienceRankScores(options.items));
|
|
70
145
|
const utilityContext = {
|
|
71
146
|
...rankingContext,
|
|
72
147
|
utilityScores: utilScoresMap,
|
|
73
148
|
scopedUtilityScores: scopedUtilScoresMap,
|
|
74
149
|
utilityDecayConfig: options.utilityDecayConfig,
|
|
75
150
|
positiveFeedbackCounts: options.positiveFeedbackCounts,
|
|
151
|
+
salienceRankScores,
|
|
76
152
|
};
|
|
77
153
|
for (const item of options.items) {
|
|
78
|
-
applyUtilityContributors(item, utilityContext);
|
|
154
|
+
applyUtilityContributors(item, utilityContext, activeUtilityContributors);
|
|
79
155
|
}
|
|
80
156
|
return options.items;
|
|
81
157
|
}
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* - hints: searchHints + examples + usage + intent fields
|
|
12
12
|
* - content: TOC headings (lowest-weight catch-all)
|
|
13
13
|
*/
|
|
14
|
+
// NOTE (R5): the collapse detector's frozen canary queries are built from the
|
|
15
|
+
// same surface this function indexes (name tokens / tags / description) and
|
|
16
|
+
// scored via FTS against it. Changing what buildSearchFields includes shifts
|
|
17
|
+
// the detector's recall baseline for ALL existing canary sets — coordinate
|
|
18
|
+
// with src/commands/improve/collapse-detector.ts (buildCanaryQuery) and expect
|
|
19
|
+
// operators to re-mint via `akm improve canary --refresh` after such a change.
|
|
14
20
|
export function buildSearchFields(entry) {
|
|
15
21
|
const name = entry.name.replace(/[-_]/g, " ").toLowerCase();
|
|
16
22
|
const description = (entry.description ?? "").toLowerCase();
|
|
@@ -10,8 +10,6 @@ import { resolveSourceProviderFactory } from "../../sources/provider-factory.js"
|
|
|
10
10
|
// before resolveEntryContentDir() runs.
|
|
11
11
|
import "../../sources/providers/index.js";
|
|
12
12
|
import { warn } from "../../core/warn.js";
|
|
13
|
-
import { ensureGitMirror, getCachePaths, parseGitRepoUrl } from "../../sources/providers/git.js";
|
|
14
|
-
import { ensureWebsiteMirror } from "../../sources/website-ingest.js";
|
|
15
13
|
// Legacy "context-hub" / "github" type aliases are normalized to "git" at
|
|
16
14
|
// config-load time (see src/config.ts), so this set only contains the canonical
|
|
17
15
|
// type.
|
|
@@ -169,14 +167,26 @@ export function getWritableStashDirs(overrideStashDir, existingConfig) {
|
|
|
169
167
|
}
|
|
170
168
|
/**
|
|
171
169
|
* Find which source a file path belongs to.
|
|
170
|
+
*
|
|
171
|
+
* Longest-matching-prefix wins: a source nested inside another (e.g. `akm add
|
|
172
|
+
* ./sub` where `./sub` lives under the primary stash — which is always
|
|
173
|
+
* `sources[0]`) is the more specific owner and must win over the enclosing
|
|
174
|
+
* source regardless of array order. A first-match-in-order scan would
|
|
175
|
+
* misattribute every asset under the nested source to the primary stash,
|
|
176
|
+
* corrupting origin / editability / provenance decisions for the affected files.
|
|
172
177
|
*/
|
|
173
178
|
export function findSourceForPath(filePath, sources) {
|
|
174
179
|
const resolved = path.resolve(filePath);
|
|
180
|
+
let best;
|
|
181
|
+
let bestLen = -1;
|
|
175
182
|
for (const source of sources) {
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
const base = path.resolve(source.path);
|
|
184
|
+
if (resolved.startsWith(base + path.sep) && base.length > bestLen) {
|
|
185
|
+
best = source;
|
|
186
|
+
bestLen = base.length;
|
|
187
|
+
}
|
|
178
188
|
}
|
|
179
|
-
return
|
|
189
|
+
return best;
|
|
180
190
|
}
|
|
181
191
|
/**
|
|
182
192
|
* Return the primary stash source (first entry in the list).
|
|
@@ -261,31 +271,32 @@ function isValidDirectory(dir) {
|
|
|
261
271
|
export async function ensureSourceCaches(config, options) {
|
|
262
272
|
const cfg = config ?? loadConfig();
|
|
263
273
|
const force = options?.force === true;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
// Polymorphic refresh: walk every enabled source through its registered
|
|
275
|
+
// provider and call `sync()`. Every cache-backed kind (git, website, npm)
|
|
276
|
+
// refreshes the same way — a bad source warns and is skipped without
|
|
277
|
+
// aborting the others. The git content/-subdir layout convention stays in
|
|
278
|
+
// resolveEntryContentDir.
|
|
279
|
+
for (const entry of getSources(cfg)) {
|
|
280
|
+
if (entry.enabled === false)
|
|
281
|
+
continue;
|
|
282
|
+
const factory = resolveSourceProviderFactory(entry.type);
|
|
283
|
+
if (!factory)
|
|
267
284
|
continue;
|
|
285
|
+
let provider;
|
|
268
286
|
try {
|
|
269
|
-
|
|
270
|
-
const cachePaths = getCachePaths(repo.canonicalUrl);
|
|
271
|
-
await ensureGitMirror(repo, cachePaths, {
|
|
272
|
-
requireRepoDir: true,
|
|
273
|
-
writable: entry.writable === true,
|
|
274
|
-
force,
|
|
275
|
-
});
|
|
287
|
+
provider = factory(entry);
|
|
276
288
|
}
|
|
277
289
|
catch (err) {
|
|
278
|
-
warn(`Warning: failed to
|
|
290
|
+
warn(`Warning: failed to construct ${entry.type} source provider for "${entry.name ?? entry.url ?? entry.path}": ${err instanceof Error ? err.message : String(err)}`);
|
|
291
|
+
continue;
|
|
279
292
|
}
|
|
280
|
-
|
|
281
|
-
for (const entry of entries) {
|
|
282
|
-
if (entry.type !== "website" || !entry.url || entry.enabled === false)
|
|
293
|
+
if (!provider.sync)
|
|
283
294
|
continue;
|
|
284
295
|
try {
|
|
285
|
-
await
|
|
296
|
+
await provider.sync({ force });
|
|
286
297
|
}
|
|
287
298
|
catch (err) {
|
|
288
|
-
warn(`Warning: failed to refresh
|
|
299
|
+
warn(`Warning: failed to refresh ${provider.kind} source "${provider.name}": ${err instanceof Error ? err.message : String(err)}`);
|
|
289
300
|
}
|
|
290
301
|
}
|
|
291
302
|
}
|
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { writeFileAtomic } from "../../core/common.js";
|
|
6
6
|
import { getCacheDir, getSemanticStatusPath } from "../../core/paths.js";
|
|
7
|
+
import { DETERMINISTIC_EMBED_MODEL_ID, isDeterministicEmbedEnabled } from "../../llm/embedders/deterministic.js";
|
|
7
8
|
import { DEFAULT_LOCAL_MODEL } from "../../llm/embedders/local.js";
|
|
8
9
|
export function deriveSemanticProviderFingerprint(embedding) {
|
|
10
|
+
if (isDeterministicEmbedEnabled()) {
|
|
11
|
+
return `deterministic:${DETERMINISTIC_EMBED_MODEL_ID}`;
|
|
12
|
+
}
|
|
9
13
|
if (embedding?.endpoint) {
|
|
10
14
|
return `remote:${embedding.endpoint}|${embedding.model}|${embedding.dimension ?? "default"}`;
|
|
11
15
|
}
|
|
@@ -78,6 +78,15 @@ const DIR_TYPE_MAP = [
|
|
|
78
78
|
type: "session",
|
|
79
79
|
test: (ext) => ext === ".md",
|
|
80
80
|
},
|
|
81
|
+
{
|
|
82
|
+
// Durable stash-level facts live under `facts/<category>/<name>.md`.
|
|
83
|
+
// classifyByDirectory walks every ancestor dir, so nested category
|
|
84
|
+
// subdirs still match. Without this entry a fact file would fall through
|
|
85
|
+
// to classifyBySmartMd and be mistyped as `knowledge`.
|
|
86
|
+
dir: "facts",
|
|
87
|
+
type: "fact",
|
|
88
|
+
test: (ext) => ext === ".md",
|
|
89
|
+
},
|
|
81
90
|
];
|
|
82
91
|
const COMMAND_PLACEHOLDER_RE = /\$ARGUMENTS|\$[123]\b/;
|
|
83
92
|
// Files that should never be treated as the typed asset for the surrounding
|
|
@@ -148,20 +148,28 @@ function isInsideGitRepo(dir) {
|
|
|
148
148
|
* read (e.g. permission errors).
|
|
149
149
|
*/
|
|
150
150
|
export function* walkMarkdownFiles(root) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const full = path.join(root, entry.name);
|
|
160
|
-
if (entry.isDirectory()) {
|
|
161
|
-
yield* walkMarkdownFiles(full);
|
|
151
|
+
const stack = [root];
|
|
152
|
+
while (stack.length > 0) {
|
|
153
|
+
const current = stack.pop();
|
|
154
|
+
if (!current)
|
|
155
|
+
continue;
|
|
156
|
+
let entries;
|
|
157
|
+
try {
|
|
158
|
+
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
162
159
|
}
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
catch {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
const full = path.join(current, entry.name);
|
|
165
|
+
if (entry.isSymbolicLink())
|
|
166
|
+
continue;
|
|
167
|
+
if (entry.isDirectory()) {
|
|
168
|
+
stack.push(full);
|
|
169
|
+
}
|
|
170
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
|
|
171
|
+
yield full;
|
|
172
|
+
}
|
|
165
173
|
}
|
|
166
174
|
}
|
|
167
175
|
}
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* Adding a new platform: implement `AgentCommandBuilder`, add to
|
|
13
13
|
* `BUILTIN_BUILDERS`. Nothing else changes.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { ConfigError } from "../../core/errors.js";
|
|
16
|
+
import { HARNESS_REGISTRY } from "../harnesses/index.js";
|
|
17
17
|
// Types + shared validation helpers live in the leaf module `builder-shared.ts`
|
|
18
18
|
// so per-harness builders (harnesses/claude/agent-builder.ts) can depend on them
|
|
19
19
|
// without importing this file back — avoiding an init-order cycle through
|
|
@@ -21,6 +21,7 @@ import { opencodeBuilder } from "../harnesses/opencode/agent-builder.js";
|
|
|
21
21
|
// sites keep working.
|
|
22
22
|
import { assertNotFlag } from "./builder-shared.js";
|
|
23
23
|
import { resolveModel } from "./model-aliases.js";
|
|
24
|
+
import { getBuiltinAgentProfile } from "./profiles.js";
|
|
24
25
|
export { assertNotFlag, normalizeTools } from "./builder-shared.js";
|
|
25
26
|
// ── Platform builders ─────────────────────────────────────────────────────────
|
|
26
27
|
// The OpenCode builder was migrated to its harness directory in #564
|
|
@@ -43,7 +44,7 @@ const defaultBuilder = {
|
|
|
43
44
|
args.push("--system-prompt", req.systemPrompt);
|
|
44
45
|
}
|
|
45
46
|
if (req.model) {
|
|
46
|
-
const resolved = resolveModel(req.model, profile.name, profile.modelAliases);
|
|
47
|
+
const resolved = resolveModel(req.model, profile.name, profile.modelAliases, profile.globalModelAliases);
|
|
47
48
|
args.push("--model", resolved);
|
|
48
49
|
}
|
|
49
50
|
args.push("--");
|
|
@@ -52,17 +53,42 @@ const defaultBuilder = {
|
|
|
52
53
|
},
|
|
53
54
|
};
|
|
54
55
|
// ── Registry ──────────────────────────────────────────────────────────────────
|
|
55
|
-
const BUILTIN_BUILDERS = {
|
|
56
|
-
opencode: opencodeBuilder,
|
|
57
|
-
"opencode-headless": opencodeBuilder,
|
|
58
|
-
claude: claudeBuilder,
|
|
59
|
-
"claude-headless": claudeBuilder,
|
|
60
|
-
};
|
|
61
56
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
57
|
+
* DERIVED from `HARNESS_REGISTRY` (P0.5 registry-drift fix): each harness that
|
|
58
|
+
* owns an `agentBuilder` is registered under its canonical id, its
|
|
59
|
+
* `<id>-headless` profile variant, and every alias. Previously this was a
|
|
60
|
+
* hand-maintained map that could (and did) drift from the harness registry.
|
|
61
|
+
*/
|
|
62
|
+
const BUILTIN_BUILDERS = (() => {
|
|
63
|
+
const registry = {};
|
|
64
|
+
for (const harness of HARNESS_REGISTRY) {
|
|
65
|
+
if (!harness.agentBuilder)
|
|
66
|
+
continue;
|
|
67
|
+
registry[harness.id] = harness.agentBuilder;
|
|
68
|
+
registry[`${harness.id}-headless`] = harness.agentBuilder;
|
|
69
|
+
for (const alias of harness.aliases)
|
|
70
|
+
registry[alias] = harness.agentBuilder;
|
|
71
|
+
}
|
|
72
|
+
return Object.freeze(registry);
|
|
73
|
+
})();
|
|
74
|
+
/**
|
|
75
|
+
* Return the builder for the given platform name.
|
|
76
|
+
*
|
|
77
|
+
* A *custom* profile (unknown platform) falls back to the default builder —
|
|
78
|
+
* that generic `--system-prompt`/`--model`/`--` shape is the documented
|
|
79
|
+
* contract for user-defined wrappers. A *known built-in agent CLI* with no
|
|
80
|
+
* dedicated builder (codex, gemini, aider + their `-headless` variants) is a
|
|
81
|
+
* loud `ConfigError` instead: the default flag shape is wrong for those CLIs
|
|
82
|
+
* (aider, for one, treats positionals as file names), so the old silent
|
|
83
|
+
* fallback produced a broken command that "ran" and failed downstream.
|
|
84
|
+
* Custom builders injected via tests can be passed as `registry`.
|
|
65
85
|
*/
|
|
66
86
|
export function getCommandBuilder(platform, registry = BUILTIN_BUILDERS) {
|
|
67
|
-
|
|
87
|
+
const found = registry[platform];
|
|
88
|
+
if (found)
|
|
89
|
+
return found;
|
|
90
|
+
if (getBuiltinAgentProfile(platform)) {
|
|
91
|
+
throw new ConfigError(`agent dispatch for "${platform}" is not supported yet: no command builder exists for this CLI, and the generic flag shape would produce a broken command.`, "INVALID_CONFIG_FILE", 'Use an "opencode" or "claude" profile, or — if your CLI is flag-compatible with one of those — set `profiles.agent.<name>.commandBuilder` to "opencode" or "claude".');
|
|
92
|
+
}
|
|
93
|
+
return defaultBuilder;
|
|
68
94
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import { VALID_HARNESS_IDS } from "../../core/config/config.js";
|
|
5
4
|
import { ConfigError } from "../../core/errors.js";
|
|
6
|
-
import { warn } from "../../core/warn.js";
|
|
7
5
|
import { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
|
|
8
6
|
/**
|
|
9
7
|
* Default hard timeout for an agent CLI (60s — matches the value used in
|
|
@@ -15,7 +13,7 @@ export const DEFAULT_AGENT_TIMEOUT_MS = 60_000;
|
|
|
15
13
|
* user override (`profiles.agent[name]`) on top of the built-in profile (if
|
|
16
14
|
* any). Returns `undefined` when neither yields a usable profile.
|
|
17
15
|
*/
|
|
18
|
-
export function resolveAgentProfile(name, overrides) {
|
|
16
|
+
export function resolveAgentProfile(name, overrides, globalModelAliases) {
|
|
19
17
|
const builtin = getBuiltinAgentProfile(name);
|
|
20
18
|
const platform = overrides?.platform;
|
|
21
19
|
// For opencode-sdk profiles, allow synthesizing without a built-in.
|
|
@@ -32,8 +30,14 @@ export function resolveAgentProfile(name, overrides) {
|
|
|
32
30
|
parseOutput: "text",
|
|
33
31
|
...(sdkMode ? { sdkMode: true } : {}),
|
|
34
32
|
};
|
|
35
|
-
if (!overrides)
|
|
36
|
-
return base;
|
|
33
|
+
if (!overrides) {
|
|
34
|
+
return globalModelAliases ? { ...base, globalModelAliases } : base;
|
|
35
|
+
}
|
|
36
|
+
// Per-profile aliases from config extend (and shadow) the built-in
|
|
37
|
+
// profile's own entries. (Previously always used base.modelAliases, so the
|
|
38
|
+
// documented `profiles.agent.<name>.modelAliases` config was silently
|
|
39
|
+
// dropped — same bug class as the timeoutMs override below.)
|
|
40
|
+
const modelAliases = overrides.modelAliases || base.modelAliases ? { ...base.modelAliases, ...overrides.modelAliases } : undefined;
|
|
37
41
|
return {
|
|
38
42
|
name,
|
|
39
43
|
bin: overrides.bin ?? base.bin,
|
|
@@ -41,22 +45,29 @@ export function resolveAgentProfile(name, overrides) {
|
|
|
41
45
|
stdio: base.stdio,
|
|
42
46
|
env: base.env,
|
|
43
47
|
envPassthrough: base.envPassthrough,
|
|
44
|
-
|
|
48
|
+
// Honor a user-configured `profiles.agent.<name>.timeoutMs` override; fall
|
|
49
|
+
// back to the built-in profile's value. (Previously always used base, so
|
|
50
|
+
// the documented config override was silently ignored — callers had to pass
|
|
51
|
+
// a CLI flag like `--timeout-ms`.) runAgent (spawn.ts) reads profile.timeoutMs
|
|
52
|
+
// when no per-call timeout is supplied, so this makes the config knob work.
|
|
53
|
+
timeoutMs: overrides.timeoutMs ?? base.timeoutMs,
|
|
45
54
|
parseOutput: base.parseOutput,
|
|
46
55
|
...(sdkMode ? { sdkMode: true } : {}),
|
|
47
56
|
model: overrides.model ?? base.model,
|
|
48
57
|
endpoint: base.endpoint,
|
|
49
58
|
apiKey: base.apiKey,
|
|
50
59
|
commandBuilder: base.commandBuilder,
|
|
51
|
-
modelAliases
|
|
60
|
+
modelAliases,
|
|
61
|
+
...(globalModelAliases ? { globalModelAliases } : {}),
|
|
52
62
|
};
|
|
53
63
|
}
|
|
54
64
|
/**
|
|
55
65
|
* Resolve the runnable profile for `name`, or `undefined` if none is
|
|
56
|
-
* available (no built-in and no user override).
|
|
66
|
+
* available (no built-in and no user override). Threads the config-root
|
|
67
|
+
* `modelAliases` tier table onto the resolved profile.
|
|
57
68
|
*/
|
|
58
69
|
export function resolveProfileFromConfig(name, config) {
|
|
59
|
-
return resolveAgentProfile(name, config?.profiles?.agent?.[name]);
|
|
70
|
+
return resolveAgentProfile(name, config?.profiles?.agent?.[name], config?.modelAliases);
|
|
60
71
|
}
|
|
61
72
|
/**
|
|
62
73
|
* Return the names of every agent profile available in `config` — built-ins
|
|
@@ -134,53 +145,3 @@ export function listResolvedAgentProfiles(config) {
|
|
|
134
145
|
}
|
|
135
146
|
return resolved;
|
|
136
147
|
}
|
|
137
|
-
/**
|
|
138
|
-
* Parse the v2 `profiles.agent` map (AgentProfileConfigV2 shape with required
|
|
139
|
-
* `platform` field). Returns a map of profile name → AgentProfileConfigV2.
|
|
140
|
-
*/
|
|
141
|
-
export function parseAgentProfilesMapV2(value) {
|
|
142
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
143
|
-
return undefined;
|
|
144
|
-
const out = {};
|
|
145
|
-
// Derives from the canonical harness-id source of truth (#565).
|
|
146
|
-
const VALID_PLATFORMS = VALID_HARNESS_IDS;
|
|
147
|
-
for (const [name, raw] of Object.entries(value)) {
|
|
148
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
149
|
-
warn(`[akm] Ignoring profiles.agent["${name}"]: expected an object.`);
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const obj = raw;
|
|
153
|
-
if (!VALID_PLATFORMS.includes(obj.platform)) {
|
|
154
|
-
warn(`[akm] Ignoring profiles.agent["${name}"]: missing or invalid "platform" (must be one of: ${VALID_PLATFORMS.join(", ")}).`);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
const profile = {
|
|
158
|
-
platform: obj.platform,
|
|
159
|
-
};
|
|
160
|
-
if (typeof obj.bin === "string" && obj.bin.trim())
|
|
161
|
-
profile.bin = obj.bin.trim();
|
|
162
|
-
if (Array.isArray(obj.args) && obj.args.every((a) => typeof a === "string")) {
|
|
163
|
-
profile.args = obj.args;
|
|
164
|
-
}
|
|
165
|
-
if (typeof obj.workspace === "string" && obj.workspace.trim())
|
|
166
|
-
profile.workspace = obj.workspace.trim();
|
|
167
|
-
if (typeof obj.model === "string" && obj.model.trim())
|
|
168
|
-
profile.model = obj.model.trim();
|
|
169
|
-
out[name] = profile;
|
|
170
|
-
}
|
|
171
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Stub kept for source-compat with callers that previously used the v1 agent
|
|
175
|
-
* config parser. After 0.8.0 there is no separate `agent` block to parse — the
|
|
176
|
-
* loaded `AkmConfig` already carries the agent data on `profiles.agent` and
|
|
177
|
-
* `defaults.agent`. This function is a no-op alias for those callers.
|
|
178
|
-
*
|
|
179
|
-
* @deprecated v0.8.0 — the unified `AkmConfig` IS the agent config. Use the
|
|
180
|
-
* profile/defaults accessors above instead.
|
|
181
|
-
*/
|
|
182
|
-
export function parseAgentConfig(_value) {
|
|
183
|
-
// No-op: there is no separate agent block in 0.8.0. Callers should pass
|
|
184
|
-
// their loaded `AkmConfig` directly to `requireAgentProfile` etc.
|
|
185
|
-
return undefined;
|
|
186
|
-
}
|
|
@@ -55,6 +55,11 @@ export function defaultWhich(bin, envSource = process.env) {
|
|
|
55
55
|
}
|
|
56
56
|
return undefined;
|
|
57
57
|
}
|
|
58
|
+
let detectOverrides;
|
|
59
|
+
/** TEST-ONLY. Swap the detection implementations; pass undefined to restore. */
|
|
60
|
+
export function _setAgentDetectForTests(fakes) {
|
|
61
|
+
detectOverrides = fakes;
|
|
62
|
+
}
|
|
58
63
|
/**
|
|
59
64
|
* Probe every resolvable agent profile (built-ins plus user overrides)
|
|
60
65
|
* for an installed CLI.
|
|
@@ -64,6 +69,8 @@ export function defaultWhich(bin, envSource = process.env) {
|
|
|
64
69
|
* @param whichFn Binary lookup. Tests should inject a stub.
|
|
65
70
|
*/
|
|
66
71
|
export function detectAgentCliProfiles(agent, whichFn = defaultWhich) {
|
|
72
|
+
if (detectOverrides?.detectAgentCliProfiles)
|
|
73
|
+
return detectOverrides.detectAgentCliProfiles(agent, whichFn);
|
|
67
74
|
const profiles = listResolvedAgentProfiles(agent);
|
|
68
75
|
return profiles.map((profile) => probeProfile(profile, whichFn));
|
|
69
76
|
}
|
|
@@ -87,6 +94,8 @@ function probeProfile(profile, whichFn) {
|
|
|
87
94
|
* writing `agent.default`.
|
|
88
95
|
*/
|
|
89
96
|
export function pickDefaultAgentProfile(results, existingDefault) {
|
|
97
|
+
if (detectOverrides?.pickDefaultAgentProfile)
|
|
98
|
+
return detectOverrides.pickDefaultAgentProfile(results, existingDefault);
|
|
90
99
|
if (existingDefault) {
|
|
91
100
|
const match = results.find((r) => r.name === existingDefault && r.available);
|
|
92
101
|
if (match)
|
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
/**
|
|
5
|
-
* Internal entry point for the `agent` integration. CLI-only project — no
|
|
6
|
-
* public exports map. Other akm modules import from this barrel for the
|
|
7
|
-
* sake of grouping imports.
|
|
8
|
-
*
|
|
9
|
-
* Surface:
|
|
10
|
-
* • Types: AgentProfile, AgentConfig, AgentRunResult, AgentFailureReason.
|
|
11
|
-
* • Profiles: getBuiltinAgentProfile, listBuiltinAgentProfiles, BUILTIN_AGENT_PROFILE_NAMES.
|
|
12
|
-
* • Config: parseAgentConfig, resolveProfileFromConfig, requireAgentProfile, listResolvedAgentProfiles, listAgentProfileNames.
|
|
13
|
-
* • Spawn: runAgent. Builders: getCommandBuilder, AgentCommandBuilder, AgentDispatchRequest — platform-specific argv construction.
|
|
14
|
-
* • Detection: detectAgentCliProfiles, pickDefaultAgentProfile, defaultWhich.
|
|
15
|
-
*/
|
|
16
|
-
// The OpenCode SDK runner moved to its harness directory in #564
|
|
17
|
-
// (`harnesses/opencode-sdk/`). Re-exported here so existing `agent/index`
|
|
18
|
-
// import sites keep working.
|
|
19
|
-
export { runAgentSdk } from "../harnesses/opencode-sdk/index.js";
|
|
20
4
|
export { getCommandBuilder } from "./builders.js";
|
|
21
|
-
export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles,
|
|
22
|
-
export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
|
|
5
|
+
export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
|
|
6
|
+
export { _setAgentDetectForTests, defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
|
|
23
7
|
export { listBuiltinModelAliases, resolveModel } from "./model-aliases.js";
|
|
24
8
|
export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
|
|
25
|
-
export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload,
|
|
9
|
+
export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "./prompts.js";
|
|
26
10
|
export { runAgent } from "./spawn.js";
|
|
@@ -39,13 +39,18 @@ const BUILTIN_ALIASES = [
|
|
|
39
39
|
*
|
|
40
40
|
* @param model Raw alias ("opus") or exact model ID ("claude-opus-4-7").
|
|
41
41
|
* @param platform Builder platform name ("claude", "opencode", ...).
|
|
42
|
-
* @param custom Profile-level aliases from config.json — take priority over builtins.
|
|
42
|
+
* @param custom Profile-level aliases from config.json — take priority over globals and builtins.
|
|
43
|
+
* @param global Config-root `modelAliases` tier table (alias → platform → model, `"*"` fallback).
|
|
43
44
|
* @returns Resolved model string, or `model` verbatim when no alias matches.
|
|
44
45
|
*/
|
|
45
|
-
export function resolveModel(model, platform, custom) {
|
|
46
|
+
export function resolveModel(model, platform, custom, global) {
|
|
46
47
|
const key = model.toLowerCase();
|
|
47
48
|
if (custom?.[key])
|
|
48
49
|
return custom[key];
|
|
50
|
+
const tier = global?.[key];
|
|
51
|
+
const fromGlobal = tier?.[platform] ?? tier?.["*"];
|
|
52
|
+
if (fromGlobal)
|
|
53
|
+
return fromGlobal;
|
|
49
54
|
const entry = BUILTIN_ALIASES.find((a) => a.alias === key);
|
|
50
55
|
return entry?.platforms[platform] ?? model;
|
|
51
56
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
4
|
+
// AKM_EVENT_SOURCE carries usage-event provenance (improve/task) so that akm
|
|
5
|
+
// invocations a spawned agent makes are recorded as machine traffic, not user
|
|
6
|
+
// demand (DRIFT-6). Without it in the passthrough whitelist, buildChildEnv drops
|
|
7
|
+
// the stamp at the agent boundary — e.g. `akm wiki ingest` spawns an agent whose
|
|
8
|
+
// `akm curate/show/search` tool-calls then log source='user', silently inflating
|
|
9
|
+
// every lane's read-back (GRR). It is a provenance tag, never a secret.
|
|
10
|
+
const COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR", "AKM_EVENT_SOURCE"];
|
|
5
11
|
/**
|
|
6
12
|
* Built-in profiles for the five agent CLIs the v1 spec calls out
|
|
7
13
|
* explicitly. The fields here are conservative defaults — every value is
|