akm-cli 0.8.0-rc1 → 0.8.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/{.github/CHANGELOG.md → CHANGELOG.md} +191 -3
- package/README.md +22 -6
- package/SECURITY.md +93 -0
- package/dist/cli/config-migrate.js +144 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/confirm.js +73 -0
- package/dist/cli/parse-args.js +93 -3
- package/dist/cli/shared.js +129 -0
- package/dist/cli.js +2162 -1258
- package/dist/commands/add-cli.js +279 -0
- package/dist/commands/agent-dispatch.js +20 -12
- package/dist/commands/agent-support.js +11 -5
- package/dist/commands/completions.js +3 -0
- package/dist/commands/config-cli.js +129 -517
- package/dist/commands/consolidate.js +1533 -144
- package/dist/commands/curate.js +44 -3
- package/dist/commands/db-cli.js +23 -0
- package/dist/commands/distill-promotion-policy.js +5 -3
- package/dist/commands/distill.js +906 -100
- package/dist/commands/env.js +213 -0
- package/dist/commands/eval-cases.js +3 -0
- package/dist/commands/events.js +3 -0
- package/dist/commands/extract-cli.js +127 -0
- package/dist/commands/extract-prompt.js +204 -0
- package/dist/commands/extract.js +477 -0
- package/dist/commands/feedback-cli.js +331 -0
- package/dist/commands/graph.js +260 -5
- package/dist/commands/health.js +977 -51
- package/dist/commands/help/help-accept.md +6 -3
- package/dist/commands/help/help-improve.md +36 -8
- package/dist/commands/help/help-proposals.md +7 -4
- package/dist/commands/help/help-reject.md +5 -2
- package/dist/commands/history.js +51 -16
- package/dist/commands/improve-auto-accept.js +97 -0
- package/dist/commands/improve-cli.js +236 -0
- package/dist/commands/improve-profiles.js +184 -0
- package/dist/commands/improve-result-file.js +167 -0
- package/dist/commands/improve.js +1725 -332
- package/dist/commands/info.js +3 -0
- package/dist/commands/init.js +49 -1
- package/dist/commands/installed-stashes.js +6 -23
- package/dist/commands/knowledge.js +3 -0
- package/dist/commands/lint/agent-linter.js +3 -0
- package/dist/commands/lint/base-linter.js +233 -5
- package/dist/commands/lint/command-linter.js +3 -0
- package/dist/commands/lint/default-linter.js +3 -0
- package/dist/commands/lint/env-key-rules.js +154 -0
- package/dist/commands/lint/index.js +92 -3
- package/dist/commands/lint/knowledge-linter.js +3 -0
- package/dist/commands/lint/markdown-insertion.js +343 -0
- package/dist/commands/lint/memory-linter.js +3 -0
- package/dist/commands/lint/registry.js +3 -0
- package/dist/commands/lint/skill-linter.js +3 -0
- package/dist/commands/lint/task-linter.js +15 -12
- package/dist/commands/lint/types.js +3 -0
- package/dist/commands/lint/workflow-linter.js +3 -0
- package/dist/commands/lint.js +3 -0
- package/dist/commands/migration-help.js +5 -2
- package/dist/commands/proposal-drain-policies.js +128 -0
- package/dist/commands/proposal-drain.js +477 -0
- package/dist/commands/proposal.js +60 -6
- package/dist/commands/propose.js +24 -19
- package/dist/commands/reflect.js +1004 -94
- package/dist/commands/registry-cli.js +150 -0
- package/dist/commands/registry-search.js +3 -0
- package/dist/commands/remember-cli.js +257 -0
- package/dist/commands/remember.js +15 -6
- package/dist/commands/schema-repair.js +88 -15
- package/dist/commands/search.js +99 -14
- package/dist/commands/secret.js +173 -0
- package/dist/commands/self-update.js +3 -0
- package/dist/commands/show.js +32 -13
- package/dist/commands/source-add.js +7 -35
- package/dist/commands/source-clone.js +3 -0
- package/dist/commands/source-manage.js +3 -0
- package/dist/commands/tasks.js +161 -95
- package/dist/commands/url-checker.js +3 -0
- package/dist/core/action-contributors.js +3 -0
- package/dist/core/asset-ref.js +17 -2
- package/dist/core/asset-registry.js +9 -2
- package/dist/core/asset-serialize.js +88 -0
- package/dist/core/asset-spec.js +61 -5
- package/dist/core/common.js +93 -5
- package/dist/core/concurrent.js +3 -0
- package/dist/core/config-io.js +347 -0
- package/dist/core/config-migration.js +622 -0
- package/dist/core/config-schema.js +558 -0
- package/dist/core/config-sources.js +108 -0
- package/dist/core/config-types.js +4 -0
- package/dist/core/config-walker.js +337 -0
- package/dist/core/config.js +366 -1077
- package/dist/core/errors.js +42 -20
- package/dist/core/events.js +31 -25
- package/dist/core/file-lock.js +104 -0
- package/dist/core/frontmatter.js +75 -10
- package/dist/core/lesson-lint.js +3 -0
- package/dist/core/markdown.js +3 -0
- package/dist/core/memory-belief.js +62 -0
- package/dist/core/memory-contradiction-detect.js +274 -0
- package/dist/core/memory-improve.js +142 -14
- package/dist/core/parse.js +3 -0
- package/dist/core/paths.js +218 -50
- package/dist/core/proposal-quality-validators.js +380 -0
- package/dist/core/proposal-validators.js +11 -3
- package/dist/core/proposals.js +464 -5
- package/dist/core/state-db.js +349 -56
- package/dist/core/text-truncation.js +107 -0
- package/dist/core/time.js +3 -0
- package/dist/core/tty.js +59 -0
- package/dist/core/warn.js +7 -2
- package/dist/core/write-source.js +12 -0
- package/dist/indexer/db-backup.js +391 -0
- package/dist/indexer/db-search.js +136 -28
- package/dist/indexer/db.js +662 -166
- package/dist/indexer/ensure-index.js +3 -0
- package/dist/indexer/file-context.js +3 -0
- package/dist/indexer/graph-boost.js +162 -40
- package/dist/indexer/graph-db.js +241 -51
- package/dist/indexer/graph-dedup.js +3 -7
- package/dist/indexer/graph-extraction.js +242 -149
- package/dist/indexer/index-context.js +3 -9
- package/dist/indexer/indexer.js +84 -14
- package/dist/indexer/llm-cache.js +24 -19
- package/dist/indexer/manifest.js +3 -0
- package/dist/indexer/matchers.js +184 -11
- package/dist/indexer/memory-inference.js +94 -50
- package/dist/indexer/metadata-contributors.js +3 -0
- package/dist/indexer/metadata.js +114 -48
- package/dist/indexer/path-resolver.js +3 -0
- package/dist/indexer/project-context.js +192 -0
- package/dist/indexer/ranking-contributors.js +134 -7
- package/dist/indexer/ranking.js +8 -1
- package/dist/indexer/search-fields.js +5 -9
- package/dist/indexer/search-hit-enrichers.js +91 -2
- package/dist/indexer/search-source.js +20 -1
- package/dist/indexer/semantic-status.js +4 -1
- package/dist/indexer/staleness-detect.js +447 -0
- package/dist/indexer/usage-events.js +12 -9
- package/dist/indexer/walker.js +3 -0
- package/dist/integrations/agent/builders.js +135 -0
- package/dist/integrations/agent/config.js +121 -401
- package/dist/integrations/agent/detect.js +3 -0
- package/dist/integrations/agent/index.js +6 -14
- package/dist/integrations/agent/model-aliases.js +55 -0
- package/dist/integrations/agent/profiles.js +3 -0
- package/dist/integrations/agent/prompts.js +137 -8
- package/dist/integrations/agent/runner.js +208 -0
- package/dist/integrations/agent/sdk-runner.js +8 -2
- package/dist/integrations/agent/spawn.js +54 -14
- package/dist/integrations/github.js +3 -0
- package/dist/integrations/lockfile.js +22 -51
- package/dist/integrations/session-logs/index.js +4 -0
- package/dist/integrations/session-logs/inline-refs.js +35 -0
- package/dist/integrations/session-logs/pre-filter.js +152 -0
- package/dist/integrations/session-logs/providers/claude-code.js +226 -0
- package/dist/integrations/session-logs/providers/opencode.js +231 -25
- package/dist/integrations/session-logs/types.js +3 -0
- package/dist/llm/call-ai.js +14 -26
- package/dist/llm/client.js +16 -2
- package/dist/llm/embedder.js +20 -29
- package/dist/llm/embedders/cache.js +3 -7
- package/dist/llm/embedders/local.js +42 -1
- package/dist/llm/embedders/remote.js +20 -8
- package/dist/llm/embedders/types.js +3 -7
- package/dist/llm/feature-gate.js +92 -56
- package/dist/llm/graph-extract.js +401 -30
- package/dist/llm/index-passes.js +44 -29
- package/dist/llm/memory-infer.js +30 -2
- package/dist/llm/metadata-enhance.js +3 -7
- package/dist/llm/prompts/extract-session.md +80 -0
- package/dist/llm/prompts/graph-extract-user-prompt.md +24 -1
- package/dist/output/cli-hints-full.md +60 -32
- package/dist/output/cli-hints-short.md +10 -7
- package/dist/output/cli-hints.js +5 -2
- package/dist/output/context.js +60 -8
- package/dist/output/renderers.js +170 -194
- package/dist/output/shapes/curate.js +56 -0
- package/dist/output/shapes/distill.js +10 -0
- package/dist/output/shapes/env-list.js +19 -0
- package/dist/output/shapes/events.js +11 -0
- package/dist/output/shapes/helpers.js +424 -0
- package/dist/output/shapes/history.js +7 -0
- package/dist/output/shapes/passthrough.js +105 -0
- package/dist/output/shapes/proposal-accept.js +7 -0
- package/dist/output/shapes/proposal-diff.js +7 -0
- package/dist/output/shapes/proposal-list.js +7 -0
- package/dist/output/shapes/proposal-producer.js +11 -0
- package/dist/output/shapes/proposal-reject.js +7 -0
- package/dist/output/shapes/proposal-show.js +7 -0
- package/dist/output/shapes/registry-search.js +6 -0
- package/dist/output/shapes/registry.js +30 -0
- package/dist/output/shapes/search.js +6 -0
- package/dist/output/shapes/secret-list.js +19 -0
- package/dist/output/shapes/show.js +6 -0
- package/dist/output/shapes/vault-list.js +19 -0
- package/dist/output/shapes.js +51 -549
- package/dist/output/text/add.js +6 -0
- package/dist/output/text/clone.js +6 -0
- package/dist/output/text/config.js +6 -0
- package/dist/output/text/curate.js +6 -0
- package/dist/output/text/distill.js +7 -0
- package/dist/output/text/enable-disable.js +7 -0
- package/dist/output/text/events.js +10 -0
- package/dist/output/text/feedback.js +6 -0
- package/dist/output/text/helpers.js +1059 -0
- package/dist/output/text/history.js +7 -0
- package/dist/output/text/import.js +6 -0
- package/dist/output/text/index.js +6 -0
- package/dist/output/text/info.js +6 -0
- package/dist/output/text/init.js +6 -0
- package/dist/output/text/list.js +6 -0
- package/dist/output/text/proposal-producer.js +8 -0
- package/dist/output/text/proposal.js +12 -0
- package/dist/output/text/registry-commands.js +11 -0
- package/dist/output/text/registry.js +30 -0
- package/dist/output/text/remember.js +6 -0
- package/dist/output/text/remove.js +6 -0
- package/dist/output/text/save.js +6 -0
- package/dist/output/text/search.js +6 -0
- package/dist/output/text/show.js +6 -0
- package/dist/output/text/update.js +6 -0
- package/dist/output/text/upgrade.js +6 -0
- package/dist/output/text/vault.js +16 -0
- package/dist/output/text/wiki.js +15 -0
- package/dist/output/text/workflow.js +14 -0
- package/dist/output/text.js +44 -1329
- package/dist/registry/build-index.js +3 -0
- package/dist/registry/create-provider-registry.js +3 -0
- package/dist/registry/factory.js +4 -1
- package/dist/registry/origin-resolve.js +3 -0
- package/dist/registry/providers/index.js +3 -0
- package/dist/registry/providers/skills-sh.js +11 -2
- package/dist/registry/providers/static-index.js +10 -1
- package/dist/registry/providers/types.js +3 -24
- package/dist/registry/resolve.js +11 -16
- package/dist/registry/types.js +3 -0
- package/dist/scripts/migrate-storage.js +17767 -0
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9031 -0
- package/dist/scripts/migrations/v16-to-v17.js +141 -0
- package/dist/setup/detect.js +3 -0
- package/dist/setup/ripgrep-install.js +3 -0
- package/dist/setup/ripgrep-resolve.js +3 -0
- package/dist/setup/setup.js +306 -67
- package/dist/setup/steps.js +3 -15
- package/dist/sources/include.js +3 -0
- package/dist/sources/provider-factory.js +3 -11
- package/dist/sources/provider.js +3 -20
- package/dist/sources/providers/filesystem.js +19 -23
- package/dist/sources/providers/git.js +171 -21
- package/dist/sources/providers/index.js +3 -0
- package/dist/sources/providers/install-types.js +3 -13
- package/dist/sources/providers/npm.js +3 -4
- package/dist/sources/providers/provider-utils.js +3 -0
- package/dist/sources/providers/sync-from-ref.js +3 -11
- package/dist/sources/providers/tar-utils.js +3 -0
- package/dist/sources/providers/website.js +18 -22
- package/dist/sources/resolve.js +3 -0
- package/dist/sources/types.js +3 -0
- package/dist/sources/website-ingest.js +3 -0
- package/dist/tasks/backends/cron.js +3 -0
- package/dist/tasks/backends/exec-utils.js +3 -0
- package/dist/tasks/backends/index.js +3 -11
- package/dist/tasks/backends/launchd.js +3 -0
- package/dist/tasks/backends/schtasks.js +3 -0
- package/dist/tasks/parser.js +51 -38
- package/dist/tasks/resolveAkmBin.js +3 -0
- package/dist/tasks/runner.js +35 -9
- package/dist/tasks/schedule.js +20 -1
- package/dist/tasks/schema.js +5 -3
- package/dist/tasks/validator.js +6 -3
- package/dist/version.js +3 -0
- package/dist/wiki/wiki-templates.js +3 -0
- package/dist/wiki/wiki.js +3 -0
- package/dist/workflows/authoring.js +3 -0
- package/dist/workflows/cli.js +3 -0
- package/dist/workflows/db.js +140 -10
- package/dist/workflows/document-cache.js +3 -10
- package/dist/workflows/parser.js +3 -0
- package/dist/workflows/renderer.js +3 -0
- package/dist/workflows/runs.js +18 -1
- package/dist/workflows/schema.js +3 -0
- package/dist/workflows/scope-key.js +3 -0
- package/dist/workflows/validator.js +5 -9
- package/docs/README.md +7 -2
- package/docs/data-and-telemetry.md +225 -0
- package/docs/migration/release-notes/0.7.5.md +2 -2
- package/docs/migration/release-notes/0.8.0.md +57 -5
- package/docs/migration/v0.7-to-v0.8.md +1378 -0
- package/package.json +28 -11
- package/.github/LICENSE +0 -374
- package/dist/commands/install-audit.js +0 -385
- package/dist/commands/vault.js +0 -307
- package/dist/indexer/match-contributors.js +0 -141
- package/dist/integrations/agent/pipeline.js +0 -39
- package/dist/integrations/agent/runners.js +0 -31
|
@@ -1,351 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* The on-disk shape is:
|
|
5
|
-
*
|
|
6
|
-
* ```jsonc
|
|
7
|
-
* {
|
|
8
|
-
* "agent": {
|
|
9
|
-
* "default": "opencode",
|
|
10
|
-
* "timeoutMs": 60000,
|
|
11
|
-
* "profiles": {
|
|
12
|
-
* "opencode": { "bin": "opencode", "args": ["--non-interactive"], ... }
|
|
13
|
-
* }
|
|
14
|
-
* }
|
|
15
|
-
* }
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* Unknown keys at any level under `agent` are warn-and-ignored — this is the
|
|
19
|
-
* v1 §9.2 contract. Missing `agent` block disables agent commands; callers
|
|
20
|
-
* should reach for {@link requireAgentConfig} to surface a stable
|
|
21
|
-
* `ConfigError` with a hint pointing at setup.
|
|
22
|
-
*
|
|
23
|
-
* No LLM SDK is imported here. The runtime path is shell-out only (see
|
|
24
|
-
* `./spawn.ts`).
|
|
25
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
26
4
|
import { ConfigError } from "../../core/errors";
|
|
27
5
|
import { warn } from "../../core/warn";
|
|
28
6
|
import { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles";
|
|
29
|
-
/** Keys recognised at the top level of an `agent` config block. */
|
|
30
|
-
const KNOWN_AGENT_KEYS = new Set(["default", "timeoutMs", "profiles", "processes"]);
|
|
31
|
-
/** Keys recognised on a profile entry. */
|
|
32
|
-
const KNOWN_PROFILE_KEYS = new Set([
|
|
33
|
-
"bin",
|
|
34
|
-
"args",
|
|
35
|
-
"stdio",
|
|
36
|
-
"env",
|
|
37
|
-
"envPassthrough",
|
|
38
|
-
"timeoutMs",
|
|
39
|
-
"parseOutput",
|
|
40
|
-
"sdkMode",
|
|
41
|
-
"model",
|
|
42
|
-
"endpoint",
|
|
43
|
-
"apiKey",
|
|
44
|
-
]);
|
|
45
7
|
/**
|
|
46
|
-
* Default hard timeout for an agent CLI
|
|
47
|
-
*
|
|
8
|
+
* Default hard timeout for an agent CLI (60s — matches the value used in
|
|
9
|
+
* `docs/configuration.md`).
|
|
48
10
|
*/
|
|
49
11
|
export const DEFAULT_AGENT_TIMEOUT_MS = 60_000;
|
|
50
|
-
/** Keys recognised on a `processes[<name>]` object entry. */
|
|
51
|
-
const KNOWN_PROCESS_ENTRY_KEYS = new Set(["profile", "timeoutMs"]);
|
|
52
|
-
/**
|
|
53
|
-
* Parse a raw value (typically `rawConfig.agent` from `JSON.parse`) into a
|
|
54
|
-
* normalised {@link AgentConfig}. Returns `undefined` when the value is not
|
|
55
|
-
* an object (i.e. the block is absent or malformed at the root level — for
|
|
56
|
-
* malformed roots we emit a warning).
|
|
57
|
-
*
|
|
58
|
-
* Unknown keys (top-level and per-profile) are warn-and-ignore. Type errors
|
|
59
|
-
* on individual fields are warn-and-ignore so a bad `timeoutMs` does not
|
|
60
|
-
* break the rest of the block.
|
|
61
|
-
*/
|
|
62
|
-
export function parseAgentConfig(value) {
|
|
63
|
-
if (value === undefined)
|
|
64
|
-
return undefined;
|
|
65
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
66
|
-
warn('[akm] Ignoring "agent" config: expected an object.');
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
const raw = value;
|
|
70
|
-
const out = {};
|
|
71
|
-
for (const key of Object.keys(raw)) {
|
|
72
|
-
if (!KNOWN_AGENT_KEYS.has(key)) {
|
|
73
|
-
warn(`[akm] Ignoring unknown agent config key: "${key}"`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if ("default" in raw) {
|
|
77
|
-
if (typeof raw.default === "string" && raw.default.trim()) {
|
|
78
|
-
out.default = raw.default.trim();
|
|
79
|
-
}
|
|
80
|
-
else if (raw.default !== undefined) {
|
|
81
|
-
warn("[akm] Ignoring agent.default: expected a non-empty string.");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if ("timeoutMs" in raw) {
|
|
85
|
-
if (typeof raw.timeoutMs === "number" &&
|
|
86
|
-
Number.isFinite(raw.timeoutMs) &&
|
|
87
|
-
Number.isInteger(raw.timeoutMs) &&
|
|
88
|
-
raw.timeoutMs > 0) {
|
|
89
|
-
out.timeoutMs = raw.timeoutMs;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
warn("[akm] Ignoring agent.timeoutMs: expected a positive integer (milliseconds).");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if ("profiles" in raw) {
|
|
96
|
-
const profiles = parseAgentProfilesMap(raw.profiles);
|
|
97
|
-
if (profiles)
|
|
98
|
-
out.profiles = profiles;
|
|
99
|
-
}
|
|
100
|
-
if ("processes" in raw) {
|
|
101
|
-
const processes = parseProcessesMap(raw.processes);
|
|
102
|
-
if (processes)
|
|
103
|
-
out.processes = processes;
|
|
104
|
-
}
|
|
105
|
-
return out;
|
|
106
|
-
}
|
|
107
|
-
function parseAgentProfilesMap(value) {
|
|
108
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
109
|
-
warn("[akm] Ignoring agent.profiles: expected an object.");
|
|
110
|
-
return undefined;
|
|
111
|
-
}
|
|
112
|
-
const out = {};
|
|
113
|
-
for (const [name, raw] of Object.entries(value)) {
|
|
114
|
-
const parsed = parseAgentProfileConfig(name, raw);
|
|
115
|
-
if (parsed)
|
|
116
|
-
out[name] = parsed;
|
|
117
|
-
}
|
|
118
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Parse one entry in `agent.processes`. Accepts a string (profile name) or an
|
|
122
|
-
* object with optional `profile` and `timeoutMs` fields. Returns `undefined`
|
|
123
|
-
* and emits a warning for entries that are neither valid strings nor valid
|
|
124
|
-
* objects (warn-and-ignore).
|
|
125
|
-
*/
|
|
126
|
-
export function parseProcessEntry(value, name) {
|
|
127
|
-
if (typeof value === "string") {
|
|
128
|
-
if (!value.trim()) {
|
|
129
|
-
warn(`[akm] Ignoring agent.processes."${name}": string value must be non-empty (a profile name).`);
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
return value.trim();
|
|
133
|
-
}
|
|
134
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
135
|
-
warn(`[akm] Ignoring agent.processes."${name}": expected a string (profile name) or an object with optional "profile" and "timeoutMs".`);
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
const raw = value;
|
|
139
|
-
// Warn on unknown keys (warn-and-ignore contract).
|
|
140
|
-
for (const key of Object.keys(raw)) {
|
|
141
|
-
if (!KNOWN_PROCESS_ENTRY_KEYS.has(key)) {
|
|
142
|
-
warn(`[akm] Ignoring unknown agent.processes."${name}" key: "${key}"`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
const out = {};
|
|
146
|
-
if ("profile" in raw) {
|
|
147
|
-
if (typeof raw.profile === "string" && raw.profile.trim()) {
|
|
148
|
-
out.profile = raw.profile.trim();
|
|
149
|
-
}
|
|
150
|
-
else if (raw.profile !== undefined) {
|
|
151
|
-
warn(`[akm] Ignoring agent.processes."${name}".profile: expected a non-empty string.`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if ("timeoutMs" in raw) {
|
|
155
|
-
if (raw.timeoutMs === null) {
|
|
156
|
-
// null = unlimited — explicit, valid.
|
|
157
|
-
out.timeoutMs = null;
|
|
158
|
-
}
|
|
159
|
-
else if (typeof raw.timeoutMs === "number" &&
|
|
160
|
-
Number.isFinite(raw.timeoutMs) &&
|
|
161
|
-
Number.isInteger(raw.timeoutMs) &&
|
|
162
|
-
raw.timeoutMs > 0) {
|
|
163
|
-
out.timeoutMs = raw.timeoutMs;
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
warn(`[akm] Ignoring agent.processes."${name}".timeoutMs: expected a positive integer (milliseconds) or null (unlimited).`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return out;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Parse the `agent.processes` map. Returns `undefined` when the value is not
|
|
173
|
-
* a valid object; per-entry validation errors are warn-and-ignored (per spec §9.2).
|
|
174
|
-
*/
|
|
175
|
-
export function parseProcessesMap(value) {
|
|
176
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
177
|
-
warn("[akm] Ignoring agent.processes: expected an object.");
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
const out = {};
|
|
181
|
-
for (const [name, raw] of Object.entries(value)) {
|
|
182
|
-
const parsed = parseProcessEntry(raw, name);
|
|
183
|
-
if (parsed !== undefined)
|
|
184
|
-
out[name] = parsed;
|
|
185
|
-
}
|
|
186
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Resolve the agent profile and effective timeout for a named process.
|
|
190
|
-
*
|
|
191
|
-
* Resolution order:
|
|
192
|
-
* 1. `config.processes[processName]` — if a string, that is the profile name;
|
|
193
|
-
* if an object, extract `profile` (and optionally `timeoutMs`).
|
|
194
|
-
* 2. Profile name falls back to `config.default` when not specified in the
|
|
195
|
-
* process entry.
|
|
196
|
-
* 3. `timeoutMs` falls back: `process.timeoutMs` (null = unlimited) →
|
|
197
|
-
* profile.timeoutMs → agent.timeoutMs → DEFAULT_AGENT_TIMEOUT_MS.
|
|
198
|
-
*
|
|
199
|
-
* Returns `{ profile, timeoutMs }` where `timeoutMs` is `undefined` when the
|
|
200
|
-
* resolved timeout is `null` (unlimited) or when no timeout is set at any
|
|
201
|
-
* layer (callers treat `undefined` as the DEFAULT_AGENT_TIMEOUT_MS default).
|
|
202
|
-
*
|
|
203
|
-
* Throws {@link ConfigError} (via {@link requireAgentProfile}) when the agent
|
|
204
|
-
* block is missing or the resolved profile cannot be used.
|
|
205
|
-
*/
|
|
206
|
-
export function resolveProcessAgentProfile(processName, agentConfig) {
|
|
207
|
-
let profileName;
|
|
208
|
-
let processTimeoutMs; // null = unlimited from config
|
|
209
|
-
const processEntry = agentConfig?.processes?.[processName];
|
|
210
|
-
if (processEntry !== undefined) {
|
|
211
|
-
if (typeof processEntry === "string") {
|
|
212
|
-
profileName = processEntry;
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
profileName = processEntry.profile;
|
|
216
|
-
processTimeoutMs = processEntry.timeoutMs;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// Profile name falls back to agent.default when not set in the process entry.
|
|
220
|
-
const resolvedProfile = requireAgentProfile(agentConfig, profileName);
|
|
221
|
-
// Timeout resolution: process entry → profile → agent-level → undefined (caller applies DEFAULT).
|
|
222
|
-
let resolvedTimeoutMs;
|
|
223
|
-
if (processTimeoutMs === null) {
|
|
224
|
-
// null = explicit "unlimited" — surface as undefined so callers omit the timer.
|
|
225
|
-
resolvedTimeoutMs = undefined;
|
|
226
|
-
}
|
|
227
|
-
else if (processTimeoutMs !== undefined) {
|
|
228
|
-
resolvedTimeoutMs = processTimeoutMs;
|
|
229
|
-
}
|
|
230
|
-
else if (resolvedProfile.timeoutMs !== undefined) {
|
|
231
|
-
resolvedTimeoutMs = resolvedProfile.timeoutMs;
|
|
232
|
-
}
|
|
233
|
-
else if (agentConfig?.timeoutMs !== undefined) {
|
|
234
|
-
resolvedTimeoutMs = agentConfig.timeoutMs;
|
|
235
|
-
}
|
|
236
|
-
return { profile: resolvedProfile, timeoutMs: resolvedTimeoutMs };
|
|
237
|
-
}
|
|
238
|
-
function parseAgentProfileConfig(name, value) {
|
|
239
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
240
|
-
warn(`[akm] Ignoring agent.profiles."${name}": expected an object.`);
|
|
241
|
-
return undefined;
|
|
242
|
-
}
|
|
243
|
-
const raw = value;
|
|
244
|
-
const out = {};
|
|
245
|
-
for (const key of Object.keys(raw)) {
|
|
246
|
-
if (!KNOWN_PROFILE_KEYS.has(key)) {
|
|
247
|
-
warn(`[akm] Ignoring unknown agent.profiles."${name}" key: "${key}"`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
if (typeof raw.bin === "string" && raw.bin.trim()) {
|
|
251
|
-
out.bin = raw.bin.trim();
|
|
252
|
-
}
|
|
253
|
-
else if (raw.bin !== undefined) {
|
|
254
|
-
warn(`[akm] Ignoring agent.profiles."${name}".bin: expected a non-empty string.`);
|
|
255
|
-
}
|
|
256
|
-
if (Array.isArray(raw.args)) {
|
|
257
|
-
const args = raw.args.filter((a) => typeof a === "string");
|
|
258
|
-
if (args.length === raw.args.length) {
|
|
259
|
-
out.args = args;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
warn(`[akm] Ignoring non-string entries in agent.profiles."${name}".args.`);
|
|
263
|
-
if (args.length > 0)
|
|
264
|
-
out.args = args;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
else if (raw.args !== undefined) {
|
|
268
|
-
warn(`[akm] Ignoring agent.profiles."${name}".args: expected an array of strings.`);
|
|
269
|
-
}
|
|
270
|
-
if (raw.stdio === "captured" || raw.stdio === "interactive") {
|
|
271
|
-
out.stdio = raw.stdio;
|
|
272
|
-
}
|
|
273
|
-
else if (raw.stdio !== undefined) {
|
|
274
|
-
warn(`[akm] Ignoring agent.profiles."${name}".stdio: expected "captured" or "interactive".`);
|
|
275
|
-
}
|
|
276
|
-
if (typeof raw.env === "object" && raw.env !== null && !Array.isArray(raw.env)) {
|
|
277
|
-
const env = {};
|
|
278
|
-
for (const [k, v] of Object.entries(raw.env)) {
|
|
279
|
-
if (typeof v === "string")
|
|
280
|
-
env[k] = v;
|
|
281
|
-
}
|
|
282
|
-
if (Object.keys(env).length > 0)
|
|
283
|
-
out.env = env;
|
|
284
|
-
}
|
|
285
|
-
else if (raw.env !== undefined) {
|
|
286
|
-
warn(`[akm] Ignoring agent.profiles."${name}".env: expected a string-valued object.`);
|
|
287
|
-
}
|
|
288
|
-
if (Array.isArray(raw.envPassthrough)) {
|
|
289
|
-
const list = raw.envPassthrough.filter((s) => typeof s === "string" && s.length > 0);
|
|
290
|
-
if (list.length > 0)
|
|
291
|
-
out.envPassthrough = list;
|
|
292
|
-
}
|
|
293
|
-
else if (raw.envPassthrough !== undefined) {
|
|
294
|
-
warn(`[akm] Ignoring agent.profiles."${name}".envPassthrough: expected an array of strings.`);
|
|
295
|
-
}
|
|
296
|
-
if (typeof raw.timeoutMs === "number" &&
|
|
297
|
-
Number.isFinite(raw.timeoutMs) &&
|
|
298
|
-
Number.isInteger(raw.timeoutMs) &&
|
|
299
|
-
raw.timeoutMs > 0) {
|
|
300
|
-
out.timeoutMs = raw.timeoutMs;
|
|
301
|
-
}
|
|
302
|
-
else if (raw.timeoutMs !== undefined) {
|
|
303
|
-
warn(`[akm] Ignoring agent.profiles."${name}".timeoutMs: expected a positive integer.`);
|
|
304
|
-
}
|
|
305
|
-
if (raw.parseOutput === "text" || raw.parseOutput === "json") {
|
|
306
|
-
out.parseOutput = raw.parseOutput;
|
|
307
|
-
}
|
|
308
|
-
else if (raw.parseOutput !== undefined) {
|
|
309
|
-
warn(`[akm] Ignoring agent.profiles."${name}".parseOutput: expected "text" or "json".`);
|
|
310
|
-
}
|
|
311
|
-
if (raw.sdkMode === true || raw.sdkMode === false) {
|
|
312
|
-
out.sdkMode = raw.sdkMode;
|
|
313
|
-
}
|
|
314
|
-
else if (raw.sdkMode !== undefined) {
|
|
315
|
-
warn(`[akm] Ignoring agent.profiles."${name}".sdkMode: expected a boolean.`);
|
|
316
|
-
}
|
|
317
|
-
if (typeof raw.model === "string" && raw.model.trim()) {
|
|
318
|
-
out.model = raw.model.trim();
|
|
319
|
-
}
|
|
320
|
-
else if (raw.model !== undefined) {
|
|
321
|
-
warn(`[akm] Ignoring agent.profiles."${name}".model: expected a non-empty string.`);
|
|
322
|
-
}
|
|
323
|
-
if (typeof raw.endpoint === "string" && raw.endpoint.trim()) {
|
|
324
|
-
out.endpoint = raw.endpoint.trim();
|
|
325
|
-
}
|
|
326
|
-
else if (raw.endpoint !== undefined) {
|
|
327
|
-
warn(`[akm] Ignoring agent.profiles."${name}".endpoint: expected a non-empty string.`);
|
|
328
|
-
}
|
|
329
|
-
if (typeof raw.apiKey === "string" && raw.apiKey.trim()) {
|
|
330
|
-
out.apiKey = raw.apiKey.trim();
|
|
331
|
-
}
|
|
332
|
-
else if (raw.apiKey !== undefined) {
|
|
333
|
-
warn(`[akm] Ignoring agent.profiles."${name}".apiKey: expected a non-empty string.`);
|
|
334
|
-
}
|
|
335
|
-
return out;
|
|
336
|
-
}
|
|
337
12
|
/**
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
* `undefined` — the profile is unusable.
|
|
342
|
-
*
|
|
343
|
-
* Used at the spawn site, never at config-load time. Keeping merge logic
|
|
344
|
-
* here means the parser stays a pure shape-checker.
|
|
13
|
+
* Resolve the effective `AgentProfile` for `name` by merging the optional
|
|
14
|
+
* user override (`profiles.agent[name]`) on top of the built-in profile (if
|
|
15
|
+
* any). Returns `undefined` when neither yields a usable profile.
|
|
345
16
|
*/
|
|
346
17
|
export function resolveAgentProfile(name, overrides) {
|
|
347
18
|
const builtin = getBuiltinAgentProfile(name);
|
|
348
|
-
|
|
19
|
+
const platform = overrides?.platform;
|
|
20
|
+
// For opencode-sdk profiles, allow synthesizing without a built-in.
|
|
21
|
+
const sdkMode = platform === "opencode-sdk";
|
|
22
|
+
if (!builtin && !overrides?.bin && !sdkMode)
|
|
349
23
|
return undefined;
|
|
350
24
|
const base = builtin ??
|
|
351
25
|
{
|
|
@@ -355,110 +29,156 @@ export function resolveAgentProfile(name, overrides) {
|
|
|
355
29
|
stdio: "captured",
|
|
356
30
|
envPassthrough: [],
|
|
357
31
|
parseOutput: "text",
|
|
32
|
+
...(sdkMode ? { sdkMode: true } : {}),
|
|
358
33
|
};
|
|
359
34
|
if (!overrides)
|
|
360
35
|
return base;
|
|
361
|
-
|
|
36
|
+
return {
|
|
362
37
|
name,
|
|
363
38
|
bin: overrides.bin ?? base.bin,
|
|
364
39
|
args: overrides.args ?? base.args,
|
|
365
|
-
stdio:
|
|
366
|
-
env:
|
|
367
|
-
envPassthrough:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
parseOutput: overrides.parseOutput ?? base.parseOutput,
|
|
372
|
-
sdkMode: overrides.sdkMode ?? base.sdkMode,
|
|
40
|
+
stdio: base.stdio,
|
|
41
|
+
env: base.env,
|
|
42
|
+
envPassthrough: base.envPassthrough,
|
|
43
|
+
timeoutMs: base.timeoutMs,
|
|
44
|
+
parseOutput: base.parseOutput,
|
|
45
|
+
...(sdkMode ? { sdkMode: true } : {}),
|
|
373
46
|
model: overrides.model ?? base.model,
|
|
374
|
-
endpoint:
|
|
375
|
-
apiKey:
|
|
47
|
+
endpoint: base.endpoint,
|
|
48
|
+
apiKey: base.apiKey,
|
|
49
|
+
commandBuilder: base.commandBuilder,
|
|
50
|
+
modelAliases: base.modelAliases,
|
|
376
51
|
};
|
|
377
|
-
return merged;
|
|
378
|
-
}
|
|
379
|
-
function mergePassthrough(base, extra) {
|
|
380
|
-
const seen = new Set();
|
|
381
|
-
const out = [];
|
|
382
|
-
for (const k of [...base, ...extra]) {
|
|
383
|
-
if (!seen.has(k)) {
|
|
384
|
-
seen.add(k);
|
|
385
|
-
out.push(k);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return out;
|
|
389
52
|
}
|
|
390
53
|
/**
|
|
391
54
|
* Resolve the runnable profile for `name`, or `undefined` if none is
|
|
392
|
-
* available (no built-in and no user override
|
|
55
|
+
* available (no built-in and no user override).
|
|
393
56
|
*/
|
|
394
|
-
export function resolveProfileFromConfig(name,
|
|
395
|
-
return resolveAgentProfile(name,
|
|
57
|
+
export function resolveProfileFromConfig(name, config) {
|
|
58
|
+
return resolveAgentProfile(name, config?.profiles?.agent?.[name]);
|
|
396
59
|
}
|
|
397
60
|
/**
|
|
398
|
-
* Return the names of every profile available in `
|
|
399
|
-
*
|
|
61
|
+
* Return the names of every agent profile available in `config` — built-ins
|
|
62
|
+
* plus any user-defined entries under `profiles.agent`. Sorted, deduplicated.
|
|
400
63
|
*/
|
|
401
|
-
export function listAgentProfileNames(
|
|
64
|
+
export function listAgentProfileNames(config) {
|
|
402
65
|
const seen = new Set(BUILTIN_AGENT_PROFILE_NAMES);
|
|
403
|
-
for (const name of Object.keys(
|
|
66
|
+
for (const name of Object.keys(config?.profiles?.agent ?? {}))
|
|
404
67
|
seen.add(name);
|
|
405
68
|
return [...seen].sort();
|
|
406
69
|
}
|
|
407
70
|
/**
|
|
408
|
-
* Resolve the default profile name. Order: explicit `
|
|
409
|
-
* `agent
|
|
71
|
+
* Resolve the default agent profile name. Order: explicit `requested` arg →
|
|
72
|
+
* `config.defaults.agent` → undefined.
|
|
410
73
|
*/
|
|
411
|
-
export function resolveDefaultProfileName(
|
|
74
|
+
export function resolveDefaultProfileName(config, requested) {
|
|
412
75
|
if (requested?.trim())
|
|
413
76
|
return requested.trim();
|
|
414
|
-
|
|
415
|
-
|
|
77
|
+
const def = config?.defaults?.agent;
|
|
78
|
+
if (typeof def === "string" && def.trim())
|
|
79
|
+
return def.trim();
|
|
416
80
|
return undefined;
|
|
417
81
|
}
|
|
418
82
|
/**
|
|
419
|
-
* Throw a
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
* Covers two cases per acceptance criteria:
|
|
423
|
-
*
|
|
424
|
-
* 1. The `agent` block is absent — agent commands are disabled.
|
|
425
|
-
* 2. The block exists but no usable profile (no `default`, no requested
|
|
426
|
-
* name, or the named profile cannot be resolved).
|
|
427
|
-
*
|
|
428
|
-
* Use as `const profile = requireAgentProfile(config.agent, requestedName)`.
|
|
83
|
+
* Throw a stable `ConfigError` when the caller needs an agent profile but
|
|
84
|
+
* none can be resolved.
|
|
429
85
|
*/
|
|
430
|
-
export function requireAgentProfile(
|
|
431
|
-
if (!
|
|
432
|
-
throw new ConfigError("agent commands are disabled: no
|
|
86
|
+
export function requireAgentProfile(config, requested) {
|
|
87
|
+
if (!config) {
|
|
88
|
+
throw new ConfigError("agent commands are disabled: no agent configuration in config.json.", "INVALID_CONFIG_FILE", "Run `akm setup` to detect and configure an agent CLI, or add an entry under `profiles.agent` and set `defaults.agent`.");
|
|
433
89
|
}
|
|
434
|
-
const name = resolveDefaultProfileName(
|
|
90
|
+
const name = resolveDefaultProfileName(config, requested);
|
|
435
91
|
if (!name) {
|
|
436
|
-
throw new ConfigError("agent commands require a profile: pass --profile or set `agent
|
|
92
|
+
throw new ConfigError("agent commands require a profile: pass --profile or set `defaults.agent` in config.json.", "INVALID_CONFIG_FILE", `Available profiles: ${listAgentProfileNames(config).join(", ")}.`);
|
|
437
93
|
}
|
|
438
|
-
const profile = resolveProfileFromConfig(name,
|
|
94
|
+
const profile = resolveProfileFromConfig(name, config);
|
|
439
95
|
if (!profile) {
|
|
440
|
-
throw new ConfigError(`agent profile "${name}" is not built-in and has no \`bin\` override.`, "INVALID_CONFIG_FILE", `Define agent.
|
|
441
|
-
}
|
|
442
|
-
// Apply the top-level agent.timeoutMs as the effective default for this
|
|
443
|
-
// profile when the profile itself has no timeout override. This makes
|
|
444
|
-
// `agent.timeoutMs` the universal fallback without requiring every
|
|
445
|
-
// profile definition in config.json to repeat it.
|
|
446
|
-
if (profile.timeoutMs === undefined && agent?.timeoutMs !== undefined) {
|
|
447
|
-
return { ...profile, timeoutMs: agent.timeoutMs };
|
|
96
|
+
throw new ConfigError(`agent profile "${name}" is not built-in and has no \`bin\` override.`, "INVALID_CONFIG_FILE", `Define profiles.agent."${name}".bin in config.json, or pick one of: ${listAgentProfileNames(config).join(", ")}.`);
|
|
448
97
|
}
|
|
449
98
|
return profile;
|
|
450
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolve the agent profile bound to a named improve process. Reads from
|
|
102
|
+
* `profiles.improve.default.processes.<processName>` for the profile binding,
|
|
103
|
+
* then falls back to `defaults.agent`.
|
|
104
|
+
*/
|
|
105
|
+
export function resolveProcessAgentProfile(processName, config) {
|
|
106
|
+
const processEntry = config?.profiles?.improve?.default?.processes;
|
|
107
|
+
const entry = processEntry?.[processName];
|
|
108
|
+
const profileName = entry?.profile;
|
|
109
|
+
const profile = requireAgentProfile(config, profileName);
|
|
110
|
+
let resolvedTimeoutMs;
|
|
111
|
+
if (entry?.timeoutMs === null) {
|
|
112
|
+
resolvedTimeoutMs = null;
|
|
113
|
+
}
|
|
114
|
+
else if (typeof entry?.timeoutMs === "number") {
|
|
115
|
+
resolvedTimeoutMs = entry.timeoutMs;
|
|
116
|
+
}
|
|
117
|
+
else if (profile.timeoutMs !== undefined) {
|
|
118
|
+
resolvedTimeoutMs = profile.timeoutMs;
|
|
119
|
+
}
|
|
120
|
+
return { profile, timeoutMs: resolvedTimeoutMs };
|
|
121
|
+
}
|
|
451
122
|
/**
|
|
452
123
|
* Convenience: list every fully-resolved profile (built-ins merged with
|
|
453
|
-
*
|
|
124
|
+
* user overrides). Used by setup detection to enumerate candidates.
|
|
454
125
|
*/
|
|
455
|
-
export function listResolvedAgentProfiles(
|
|
126
|
+
export function listResolvedAgentProfiles(config) {
|
|
456
127
|
const resolved = [];
|
|
457
128
|
const builtins = listBuiltinAgentProfiles();
|
|
458
|
-
for (const name of listAgentProfileNames(
|
|
459
|
-
const profile = resolveProfileFromConfig(name,
|
|
129
|
+
for (const name of listAgentProfileNames(config)) {
|
|
130
|
+
const profile = resolveProfileFromConfig(name, config) ?? builtins[name];
|
|
460
131
|
if (profile)
|
|
461
132
|
resolved.push(profile);
|
|
462
133
|
}
|
|
463
134
|
return resolved;
|
|
464
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Parse the v2 `profiles.agent` map (AgentProfileConfigV2 shape with required
|
|
138
|
+
* `platform` field). Returns a map of profile name → AgentProfileConfigV2.
|
|
139
|
+
*/
|
|
140
|
+
export function parseAgentProfilesMapV2(value) {
|
|
141
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
142
|
+
return undefined;
|
|
143
|
+
const out = {};
|
|
144
|
+
const VALID_PLATFORMS = ["opencode", "claude", "opencode-sdk"];
|
|
145
|
+
for (const [name, raw] of Object.entries(value)) {
|
|
146
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
147
|
+
warn(`[akm] Ignoring profiles.agent["${name}"]: expected an object.`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const obj = raw;
|
|
151
|
+
if (!VALID_PLATFORMS.includes(obj.platform)) {
|
|
152
|
+
warn(`[akm] Ignoring profiles.agent["${name}"]: missing or invalid "platform" (must be one of: ${VALID_PLATFORMS.join(", ")}).`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const profile = {
|
|
156
|
+
platform: obj.platform,
|
|
157
|
+
};
|
|
158
|
+
if (typeof obj.bin === "string" && obj.bin.trim())
|
|
159
|
+
profile.bin = obj.bin.trim();
|
|
160
|
+
if (Array.isArray(obj.args) && obj.args.every((a) => typeof a === "string")) {
|
|
161
|
+
profile.args = obj.args;
|
|
162
|
+
}
|
|
163
|
+
if (typeof obj.workspace === "string" && obj.workspace.trim())
|
|
164
|
+
profile.workspace = obj.workspace.trim();
|
|
165
|
+
if (typeof obj.model === "string" && obj.model.trim())
|
|
166
|
+
profile.model = obj.model.trim();
|
|
167
|
+
out[name] = profile;
|
|
168
|
+
}
|
|
169
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Stub kept for source-compat with callers that previously used the v1 agent
|
|
173
|
+
* config parser. After 0.8.0 there is no separate `agent` block to parse — the
|
|
174
|
+
* loaded `AkmConfig` already carries the agent data on `profiles.agent` and
|
|
175
|
+
* `defaults.agent`. This function is a no-op alias for those callers.
|
|
176
|
+
*
|
|
177
|
+
* @deprecated v0.8.0 — the unified `AkmConfig` IS the agent config. Use the
|
|
178
|
+
* profile/defaults accessors above instead.
|
|
179
|
+
*/
|
|
180
|
+
export function parseAgentConfig(_value) {
|
|
181
|
+
// No-op: there is no separate agent block in 0.8.0. Callers should pass
|
|
182
|
+
// their loaded `AkmConfig` directly to `requireAgentProfile` etc.
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Surface:
|
|
7
|
-
* • Types: AgentProfile, AgentConfig, AgentRunResult, AgentFailureReason.
|
|
8
|
-
* • Profiles: getBuiltinAgentProfile, listBuiltinAgentProfiles, BUILTIN_AGENT_PROFILE_NAMES.
|
|
9
|
-
* • Config: parseAgentConfig, resolveProfileFromConfig, requireAgentProfile, listResolvedAgentProfiles, listAgentProfileNames.
|
|
10
|
-
* • Spawn: runAgent.
|
|
11
|
-
* • Detection: detectAgentCliProfiles, pickDefaultAgentProfile, defaultWhich.
|
|
12
|
-
*/
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
export { getCommandBuilder } from "./builders";
|
|
13
5
|
export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, parseAgentConfig, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config";
|
|
14
6
|
export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect";
|
|
7
|
+
export { listBuiltinModelAliases, resolveModel } from "./model-aliases";
|
|
15
8
|
export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles";
|
|
16
|
-
export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, parseAgentProposalPayload, stripJsonFences, } from "./prompts";
|
|
17
|
-
export { runWithAgentRunner, selectAgentRunner } from "./runners";
|
|
9
|
+
export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts";
|
|
18
10
|
export { runAgentSdk } from "./sdk-runner";
|
|
19
11
|
export { runAgent } from "./spawn";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* Built-in alias table. Alias keys are lowercase.
|
|
6
|
+
*
|
|
7
|
+
* Platform model string conventions:
|
|
8
|
+
* opencode — "<provider>/<model>" e.g. "opencode/claude-opus-4-7"
|
|
9
|
+
* claude — bare model name e.g. "claude-opus-4-7"
|
|
10
|
+
* (Claude Code also accepts its own built-in shorthands, but we
|
|
11
|
+
* always resolve to the full name for determinism)
|
|
12
|
+
*/
|
|
13
|
+
const BUILTIN_ALIASES = [
|
|
14
|
+
{
|
|
15
|
+
alias: "opus",
|
|
16
|
+
platforms: {
|
|
17
|
+
claude: "claude-opus-4-7",
|
|
18
|
+
opencode: "opencode/claude-opus-4-7",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
alias: "sonnet",
|
|
23
|
+
platforms: {
|
|
24
|
+
claude: "claude-sonnet-4-6",
|
|
25
|
+
opencode: "opencode/claude-sonnet-4-6",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
alias: "haiku",
|
|
30
|
+
platforms: {
|
|
31
|
+
claude: "claude-haiku-4-5-20251001",
|
|
32
|
+
opencode: "opencode/claude-haiku-4-5",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a model alias or exact model ID to the string the target platform
|
|
38
|
+
* CLI expects for its --model flag.
|
|
39
|
+
*
|
|
40
|
+
* @param model Raw alias ("opus") or exact model ID ("claude-opus-4-7").
|
|
41
|
+
* @param platform Builder platform name ("claude", "opencode", ...).
|
|
42
|
+
* @param custom Profile-level aliases from config.json — take priority over builtins.
|
|
43
|
+
* @returns Resolved model string, or `model` verbatim when no alias matches.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveModel(model, platform, custom) {
|
|
46
|
+
const key = model.toLowerCase();
|
|
47
|
+
if (custom?.[key])
|
|
48
|
+
return custom[key];
|
|
49
|
+
const entry = BUILTIN_ALIASES.find((a) => a.alias === key);
|
|
50
|
+
return entry?.platforms[platform] ?? model;
|
|
51
|
+
}
|
|
52
|
+
/** Return all built-in alias entries (for tests and documentation). */
|
|
53
|
+
export function listBuiltinModelAliases() {
|
|
54
|
+
return BUILTIN_ALIASES;
|
|
55
|
+
}
|