akm-cli 0.7.4 → 0.8.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/CHANGELOG.md +224 -1
  2. package/README.md +22 -6
  3. package/SECURITY.md +93 -0
  4. package/dist/cli/config-migrate.js +144 -0
  5. package/dist/cli/config-validate.js +39 -0
  6. package/dist/cli/confirm.js +73 -0
  7. package/dist/cli/parse-args.js +133 -0
  8. package/dist/cli/shared.js +129 -0
  9. package/dist/cli.js +2631 -1440
  10. package/dist/commands/add-cli.js +279 -0
  11. package/dist/commands/agent-dispatch.js +110 -0
  12. package/dist/commands/agent-support.js +68 -0
  13. package/dist/commands/completions.js +3 -0
  14. package/dist/commands/config-cli.js +130 -534
  15. package/dist/commands/consolidate.js +2122 -0
  16. package/dist/commands/curate.js +45 -3
  17. package/dist/commands/db-cli.js +23 -0
  18. package/dist/commands/distill-promotion-policy.js +660 -0
  19. package/dist/commands/distill.js +1081 -73
  20. package/dist/commands/env.js +213 -0
  21. package/dist/commands/eval-cases.js +43 -0
  22. package/dist/commands/events.js +15 -24
  23. package/dist/commands/extract-cli.js +127 -0
  24. package/dist/commands/extract-prompt.js +204 -0
  25. package/dist/commands/extract.js +477 -0
  26. package/dist/commands/feedback-cli.js +331 -0
  27. package/dist/commands/graph.js +477 -0
  28. package/dist/commands/health.js +1302 -0
  29. package/dist/commands/help/help-accept.md +12 -0
  30. package/dist/commands/help/help-improve.md +69 -0
  31. package/dist/commands/help/help-proposals.md +18 -0
  32. package/dist/commands/help/help-propose.md +17 -0
  33. package/dist/commands/help/help-reject.md +11 -0
  34. package/dist/commands/history.js +54 -46
  35. package/dist/commands/improve-auto-accept.js +97 -0
  36. package/dist/commands/improve-cli.js +217 -0
  37. package/dist/commands/improve-profiles.js +166 -0
  38. package/dist/commands/improve-result-file.js +167 -0
  39. package/dist/commands/improve.js +2373 -0
  40. package/dist/commands/info.js +5 -2
  41. package/dist/commands/init.js +50 -2
  42. package/dist/commands/installed-stashes.js +102 -139
  43. package/dist/commands/knowledge.js +136 -0
  44. package/dist/commands/lint/agent-linter.js +49 -0
  45. package/dist/commands/lint/base-linter.js +479 -0
  46. package/dist/commands/lint/command-linter.js +49 -0
  47. package/dist/commands/lint/default-linter.js +16 -0
  48. package/dist/commands/lint/env-key-rules.js +154 -0
  49. package/dist/commands/lint/index.js +196 -0
  50. package/dist/commands/lint/knowledge-linter.js +16 -0
  51. package/dist/commands/lint/markdown-insertion.js +343 -0
  52. package/dist/commands/lint/memory-linter.js +61 -0
  53. package/dist/commands/lint/registry.js +36 -0
  54. package/dist/commands/lint/skill-linter.js +45 -0
  55. package/dist/commands/lint/task-linter.js +50 -0
  56. package/dist/commands/lint/types.js +4 -0
  57. package/dist/commands/lint/workflow-linter.js +56 -0
  58. package/dist/commands/lint.js +4 -0
  59. package/dist/commands/migration-help.js +3 -0
  60. package/dist/commands/proposal.js +67 -12
  61. package/dist/commands/propose.js +120 -45
  62. package/dist/commands/reflect.js +1104 -60
  63. package/dist/commands/registry-cli.js +150 -0
  64. package/dist/commands/registry-search.js +5 -2
  65. package/dist/commands/remember-cli.js +257 -0
  66. package/dist/commands/remember.js +70 -7
  67. package/dist/commands/schema-repair.js +203 -0
  68. package/dist/commands/search.js +115 -14
  69. package/dist/commands/secret.js +173 -0
  70. package/dist/commands/self-update.js +3 -0
  71. package/dist/commands/show.js +158 -60
  72. package/dist/commands/source-add.js +17 -45
  73. package/dist/commands/source-clone.js +3 -0
  74. package/dist/commands/source-manage.js +14 -19
  75. package/dist/commands/tasks.js +437 -0
  76. package/dist/commands/url-checker.js +42 -0
  77. package/dist/core/action-contributors.js +28 -0
  78. package/dist/core/asset-ref.js +17 -2
  79. package/dist/core/asset-registry.js +12 -17
  80. package/dist/core/asset-serialize.js +88 -0
  81. package/dist/core/asset-spec.js +67 -1
  82. package/dist/core/common.js +182 -0
  83. package/dist/core/concurrent.js +25 -0
  84. package/dist/core/config-io.js +347 -0
  85. package/dist/core/config-migration.js +622 -0
  86. package/dist/core/config-schema.js +534 -0
  87. package/dist/core/config-sources.js +108 -0
  88. package/dist/core/config-types.js +4 -0
  89. package/dist/core/config-walker.js +337 -0
  90. package/dist/core/config.js +364 -968
  91. package/dist/core/errors.js +42 -20
  92. package/dist/core/events.js +105 -135
  93. package/dist/core/file-lock.js +104 -0
  94. package/dist/core/frontmatter.js +75 -8
  95. package/dist/core/lesson-lint.js +3 -0
  96. package/dist/core/markdown.js +20 -0
  97. package/dist/core/memory-belief.js +62 -0
  98. package/dist/core/memory-contradiction-detect.js +274 -0
  99. package/dist/core/memory-improve.js +806 -0
  100. package/dist/core/parse.js +158 -0
  101. package/dist/core/paths.js +280 -14
  102. package/dist/core/proposal-quality-validators.js +380 -0
  103. package/dist/core/proposal-validators.js +69 -0
  104. package/dist/core/proposals.js +512 -42
  105. package/dist/core/state-db.js +1068 -0
  106. package/dist/core/text-truncation.js +107 -0
  107. package/dist/core/time.js +54 -0
  108. package/dist/core/tty.js +59 -0
  109. package/dist/core/warn.js +64 -1
  110. package/dist/core/write-source.js +3 -0
  111. package/dist/indexer/db-backup.js +391 -0
  112. package/dist/indexer/db-search.js +198 -489
  113. package/dist/indexer/db.js +990 -108
  114. package/dist/indexer/ensure-index.js +136 -0
  115. package/dist/indexer/file-context.js +3 -0
  116. package/dist/indexer/graph-boost.js +376 -101
  117. package/dist/indexer/graph-db.js +391 -0
  118. package/dist/indexer/graph-dedup.js +95 -0
  119. package/dist/indexer/graph-extraction.js +550 -114
  120. package/dist/indexer/index-context.js +4 -0
  121. package/dist/indexer/indexer.js +547 -309
  122. package/dist/indexer/llm-cache.js +52 -0
  123. package/dist/indexer/manifest.js +3 -0
  124. package/dist/indexer/matchers.js +167 -160
  125. package/dist/indexer/memory-inference.js +152 -74
  126. package/dist/indexer/metadata-contributors.js +29 -0
  127. package/dist/indexer/metadata.js +275 -196
  128. package/dist/indexer/path-resolver.js +92 -0
  129. package/dist/indexer/project-context.js +192 -0
  130. package/dist/indexer/ranking-contributors.js +331 -0
  131. package/dist/indexer/ranking.js +81 -0
  132. package/dist/indexer/search-fields.js +5 -9
  133. package/dist/indexer/search-hit-enrichers.js +111 -0
  134. package/dist/indexer/search-source.js +44 -10
  135. package/dist/indexer/semantic-status.js +6 -17
  136. package/dist/indexer/staleness-detect.js +447 -0
  137. package/dist/indexer/usage-events.js +12 -9
  138. package/dist/indexer/walker.js +28 -0
  139. package/dist/integrations/agent/builders.js +135 -0
  140. package/dist/integrations/agent/config.js +122 -230
  141. package/dist/integrations/agent/detect.js +3 -0
  142. package/dist/integrations/agent/index.js +7 -13
  143. package/dist/integrations/agent/model-aliases.js +55 -0
  144. package/dist/integrations/agent/profiles.js +70 -5
  145. package/dist/integrations/agent/prompts.js +250 -36
  146. package/dist/integrations/agent/runner.js +151 -0
  147. package/dist/integrations/agent/sdk-runner.js +126 -0
  148. package/dist/integrations/agent/spawn.js +183 -35
  149. package/dist/integrations/github.js +3 -0
  150. package/dist/integrations/lockfile.js +32 -69
  151. package/dist/integrations/session-logs/index.js +69 -0
  152. package/dist/integrations/session-logs/inline-refs.js +35 -0
  153. package/dist/integrations/session-logs/pre-filter.js +152 -0
  154. package/dist/integrations/session-logs/providers/claude-code.js +282 -0
  155. package/dist/integrations/session-logs/providers/opencode.js +258 -0
  156. package/dist/integrations/session-logs/types.js +4 -0
  157. package/dist/llm/call-ai.js +62 -0
  158. package/dist/llm/client.js +79 -88
  159. package/dist/llm/embedder.js +20 -29
  160. package/dist/llm/embedders/cache.js +3 -7
  161. package/dist/llm/embedders/local.js +42 -1
  162. package/dist/llm/embedders/remote.js +20 -8
  163. package/dist/llm/embedders/types.js +3 -7
  164. package/dist/llm/feature-gate.js +95 -48
  165. package/dist/llm/graph-extract.js +676 -72
  166. package/dist/llm/index-passes.js +44 -29
  167. package/dist/llm/memory-infer.js +80 -71
  168. package/dist/llm/metadata-enhance.js +42 -29
  169. package/dist/llm/prompts/extract-session.md +80 -0
  170. package/dist/llm/prompts/graph-extract-user-prompt.md +35 -0
  171. package/dist/output/cli-hints-full.md +292 -0
  172. package/dist/output/cli-hints-short.md +66 -0
  173. package/dist/output/cli-hints.js +7 -311
  174. package/dist/output/context.js +60 -8
  175. package/dist/output/renderers.js +306 -258
  176. package/dist/output/shapes/curate.js +56 -0
  177. package/dist/output/shapes/distill.js +10 -0
  178. package/dist/output/shapes/env-list.js +19 -0
  179. package/dist/output/shapes/events.js +11 -0
  180. package/dist/output/shapes/helpers.js +424 -0
  181. package/dist/output/shapes/history.js +7 -0
  182. package/dist/output/shapes/passthrough.js +102 -0
  183. package/dist/output/shapes/proposal-accept.js +7 -0
  184. package/dist/output/shapes/proposal-diff.js +7 -0
  185. package/dist/output/shapes/proposal-list.js +7 -0
  186. package/dist/output/shapes/proposal-producer.js +11 -0
  187. package/dist/output/shapes/proposal-reject.js +7 -0
  188. package/dist/output/shapes/proposal-show.js +7 -0
  189. package/dist/output/shapes/registry-search.js +6 -0
  190. package/dist/output/shapes/registry.js +30 -0
  191. package/dist/output/shapes/search.js +6 -0
  192. package/dist/output/shapes/secret-list.js +19 -0
  193. package/dist/output/shapes/show.js +6 -0
  194. package/dist/output/shapes/vault-list.js +19 -0
  195. package/dist/output/shapes.js +51 -511
  196. package/dist/output/text/add.js +6 -0
  197. package/dist/output/text/clone.js +6 -0
  198. package/dist/output/text/config.js +6 -0
  199. package/dist/output/text/curate.js +6 -0
  200. package/dist/output/text/distill.js +7 -0
  201. package/dist/output/text/enable-disable.js +7 -0
  202. package/dist/output/text/events.js +10 -0
  203. package/dist/output/text/feedback.js +6 -0
  204. package/dist/output/text/helpers.js +1039 -0
  205. package/dist/output/text/history.js +7 -0
  206. package/dist/output/text/import.js +6 -0
  207. package/dist/output/text/index.js +6 -0
  208. package/dist/output/text/info.js +6 -0
  209. package/dist/output/text/init.js +6 -0
  210. package/dist/output/text/list.js +6 -0
  211. package/dist/output/text/proposal-producer.js +8 -0
  212. package/dist/output/text/proposal.js +11 -0
  213. package/dist/output/text/registry-commands.js +11 -0
  214. package/dist/output/text/registry.js +30 -0
  215. package/dist/output/text/remember.js +6 -0
  216. package/dist/output/text/remove.js +6 -0
  217. package/dist/output/text/save.js +6 -0
  218. package/dist/output/text/search.js +6 -0
  219. package/dist/output/text/show.js +6 -0
  220. package/dist/output/text/update.js +6 -0
  221. package/dist/output/text/upgrade.js +6 -0
  222. package/dist/output/text/vault.js +16 -0
  223. package/dist/output/text/wiki.js +15 -0
  224. package/dist/output/text/workflow.js +14 -0
  225. package/dist/output/text.js +44 -1093
  226. package/dist/registry/build-index.js +3 -0
  227. package/dist/registry/create-provider-registry.js +3 -0
  228. package/dist/registry/factory.js +4 -1
  229. package/dist/registry/origin-resolve.js +3 -0
  230. package/dist/registry/providers/index.js +3 -0
  231. package/dist/registry/providers/skills-sh.js +71 -50
  232. package/dist/registry/providers/static-index.js +53 -48
  233. package/dist/registry/providers/types.js +3 -24
  234. package/dist/registry/resolve.js +11 -16
  235. package/dist/registry/types.js +3 -0
  236. package/dist/scripts/migrate-storage.js +17750 -0
  237. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9031 -0
  238. package/dist/scripts/migrations/v16-to-v17.js +141 -0
  239. package/dist/setup/detect.js +3 -0
  240. package/dist/setup/ripgrep-install.js +3 -0
  241. package/dist/setup/ripgrep-resolve.js +3 -0
  242. package/dist/setup/setup.js +775 -37
  243. package/dist/setup/steps.js +3 -15
  244. package/dist/sources/include.js +3 -0
  245. package/dist/sources/provider-factory.js +5 -12
  246. package/dist/sources/provider.js +3 -20
  247. package/dist/sources/providers/filesystem.js +19 -23
  248. package/dist/sources/providers/git.js +179 -20
  249. package/dist/sources/providers/index.js +3 -0
  250. package/dist/sources/providers/install-types.js +3 -13
  251. package/dist/sources/providers/npm.js +3 -4
  252. package/dist/sources/providers/provider-utils.js +3 -0
  253. package/dist/sources/providers/sync-from-ref.js +3 -11
  254. package/dist/sources/providers/tar-utils.js +3 -0
  255. package/dist/sources/providers/website.js +18 -22
  256. package/dist/sources/resolve.js +3 -0
  257. package/dist/sources/types.js +3 -0
  258. package/dist/sources/website-ingest.js +7 -0
  259. package/dist/tasks/backends/cron.js +203 -0
  260. package/dist/tasks/backends/exec-utils.js +28 -0
  261. package/dist/tasks/backends/index.js +24 -0
  262. package/dist/tasks/backends/launchd-template.xml +19 -0
  263. package/dist/tasks/backends/launchd.js +187 -0
  264. package/dist/tasks/backends/schtasks-template.xml +29 -0
  265. package/dist/tasks/backends/schtasks.js +215 -0
  266. package/dist/tasks/parser.js +211 -0
  267. package/dist/tasks/resolveAkmBin.js +87 -0
  268. package/dist/tasks/runner.js +458 -0
  269. package/dist/tasks/schedule.js +227 -0
  270. package/dist/tasks/schema.js +15 -0
  271. package/dist/tasks/validator.js +62 -0
  272. package/dist/version.js +3 -0
  273. package/dist/wiki/index-template.md +12 -0
  274. package/dist/wiki/ingest-workflow-template.md +54 -0
  275. package/dist/wiki/log-template.md +8 -0
  276. package/dist/wiki/schema-template.md +61 -0
  277. package/dist/wiki/wiki-templates.js +15 -0
  278. package/dist/wiki/wiki.js +13 -61
  279. package/dist/workflows/authoring.js +8 -25
  280. package/dist/workflows/cli.js +3 -0
  281. package/dist/workflows/db.js +141 -2
  282. package/dist/workflows/document-cache.js +3 -10
  283. package/dist/workflows/parser.js +3 -0
  284. package/dist/workflows/renderer.js +11 -3
  285. package/dist/workflows/runs.js +91 -89
  286. package/dist/workflows/schema.js +3 -0
  287. package/dist/workflows/scope-key.js +79 -0
  288. package/dist/workflows/validator.js +4 -8
  289. package/dist/workflows/workflow-template.md +24 -0
  290. package/docs/README.md +10 -2
  291. package/docs/data-and-telemetry.md +225 -0
  292. package/docs/migration/release-notes/0.7.0.md +1 -1
  293. package/docs/migration/release-notes/0.7.4.md +1 -1
  294. package/docs/migration/release-notes/0.7.5.md +20 -0
  295. package/docs/migration/release-notes/0.8.0.md +48 -0
  296. package/docs/migration/v0.7-to-v0.8.md +1307 -0
  297. package/package.json +29 -11
  298. package/dist/commands/install-audit.js +0 -381
  299. package/dist/commands/vault.js +0 -333
  300. package/dist/templates/wiki-templates.js +0 -100
@@ -1,190 +1,25 @@
1
- /**
2
- * Parser + resolver for the optional `agent` config block (v1 spec §12).
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"]);
31
- /** Keys recognised on a profile entry. */
32
- const KNOWN_PROFILE_KEYS = new Set(["bin", "args", "stdio", "env", "envPassthrough", "timeoutMs", "parseOutput"]);
33
7
  /**
34
- * Default hard timeout for an agent CLI. Spec §12.2 calls for a hard
35
- * timeout; 60s matches the example value in `docs/configuration.md`.
8
+ * Default hard timeout for an agent CLI (60s matches the value used in
9
+ * `docs/configuration.md`).
36
10
  */
37
11
  export const DEFAULT_AGENT_TIMEOUT_MS = 60_000;
38
12
  /**
39
- * Parse a raw value (typically `rawConfig.agent` from `JSON.parse`) into a
40
- * normalised {@link AgentConfig}. Returns `undefined` when the value is not
41
- * an object (i.e. the block is absent or malformed at the root level — for
42
- * malformed roots we emit a warning).
43
- *
44
- * Unknown keys (top-level and per-profile) are warn-and-ignore. Type errors
45
- * on individual fields are warn-and-ignore so a bad `timeoutMs` does not
46
- * break the rest of the block.
47
- */
48
- export function parseAgentConfig(value) {
49
- if (value === undefined)
50
- return undefined;
51
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
52
- warn('[akm] Ignoring "agent" config: expected an object.');
53
- return undefined;
54
- }
55
- const raw = value;
56
- const out = {};
57
- for (const key of Object.keys(raw)) {
58
- if (!KNOWN_AGENT_KEYS.has(key)) {
59
- warn(`[akm] Ignoring unknown agent config key: "${key}"`);
60
- }
61
- }
62
- if ("default" in raw) {
63
- if (typeof raw.default === "string" && raw.default.trim()) {
64
- out.default = raw.default.trim();
65
- }
66
- else if (raw.default !== undefined) {
67
- warn("[akm] Ignoring agent.default: expected a non-empty string.");
68
- }
69
- }
70
- if ("timeoutMs" in raw) {
71
- if (typeof raw.timeoutMs === "number" &&
72
- Number.isFinite(raw.timeoutMs) &&
73
- Number.isInteger(raw.timeoutMs) &&
74
- raw.timeoutMs > 0) {
75
- out.timeoutMs = raw.timeoutMs;
76
- }
77
- else {
78
- warn("[akm] Ignoring agent.timeoutMs: expected a positive integer (milliseconds).");
79
- }
80
- }
81
- if ("profiles" in raw) {
82
- const profiles = parseAgentProfilesMap(raw.profiles);
83
- if (profiles)
84
- out.profiles = profiles;
85
- }
86
- return out;
87
- }
88
- function parseAgentProfilesMap(value) {
89
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
90
- warn("[akm] Ignoring agent.profiles: expected an object.");
91
- return undefined;
92
- }
93
- const out = {};
94
- for (const [name, raw] of Object.entries(value)) {
95
- const parsed = parseAgentProfileConfig(name, raw);
96
- if (parsed)
97
- out[name] = parsed;
98
- }
99
- return Object.keys(out).length > 0 ? out : undefined;
100
- }
101
- function parseAgentProfileConfig(name, value) {
102
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
103
- warn(`[akm] Ignoring agent.profiles."${name}": expected an object.`);
104
- return undefined;
105
- }
106
- const raw = value;
107
- const out = {};
108
- for (const key of Object.keys(raw)) {
109
- if (!KNOWN_PROFILE_KEYS.has(key)) {
110
- warn(`[akm] Ignoring unknown agent.profiles."${name}" key: "${key}"`);
111
- }
112
- }
113
- if (typeof raw.bin === "string" && raw.bin.trim()) {
114
- out.bin = raw.bin.trim();
115
- }
116
- else if (raw.bin !== undefined) {
117
- warn(`[akm] Ignoring agent.profiles."${name}".bin: expected a non-empty string.`);
118
- }
119
- if (Array.isArray(raw.args)) {
120
- const args = raw.args.filter((a) => typeof a === "string");
121
- if (args.length === raw.args.length) {
122
- out.args = args;
123
- }
124
- else {
125
- warn(`[akm] Ignoring non-string entries in agent.profiles."${name}".args.`);
126
- if (args.length > 0)
127
- out.args = args;
128
- }
129
- }
130
- else if (raw.args !== undefined) {
131
- warn(`[akm] Ignoring agent.profiles."${name}".args: expected an array of strings.`);
132
- }
133
- if (raw.stdio === "captured" || raw.stdio === "interactive") {
134
- out.stdio = raw.stdio;
135
- }
136
- else if (raw.stdio !== undefined) {
137
- warn(`[akm] Ignoring agent.profiles."${name}".stdio: expected "captured" or "interactive".`);
138
- }
139
- if (typeof raw.env === "object" && raw.env !== null && !Array.isArray(raw.env)) {
140
- const env = {};
141
- for (const [k, v] of Object.entries(raw.env)) {
142
- if (typeof v === "string")
143
- env[k] = v;
144
- }
145
- if (Object.keys(env).length > 0)
146
- out.env = env;
147
- }
148
- else if (raw.env !== undefined) {
149
- warn(`[akm] Ignoring agent.profiles."${name}".env: expected a string-valued object.`);
150
- }
151
- if (Array.isArray(raw.envPassthrough)) {
152
- const list = raw.envPassthrough.filter((s) => typeof s === "string" && s.length > 0);
153
- if (list.length > 0)
154
- out.envPassthrough = list;
155
- }
156
- else if (raw.envPassthrough !== undefined) {
157
- warn(`[akm] Ignoring agent.profiles."${name}".envPassthrough: expected an array of strings.`);
158
- }
159
- 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 if (raw.timeoutMs !== undefined) {
166
- warn(`[akm] Ignoring agent.profiles."${name}".timeoutMs: expected a positive integer.`);
167
- }
168
- if (raw.parseOutput === "text" || raw.parseOutput === "json") {
169
- out.parseOutput = raw.parseOutput;
170
- }
171
- else if (raw.parseOutput !== undefined) {
172
- warn(`[akm] Ignoring agent.profiles."${name}".parseOutput: expected "text" or "json".`);
173
- }
174
- return out;
175
- }
176
- /**
177
- * Merge a user override (from `agent.profiles[<name>]`) on top of the
178
- * built-in profile (if any) and return the resolved profile. If `name`
179
- * matches no built-in and the user override has no `bin`, returns
180
- * `undefined` — the profile is unusable.
181
- *
182
- * Used at the spawn site, never at config-load time. Keeping merge logic
183
- * 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.
184
16
  */
185
17
  export function resolveAgentProfile(name, overrides) {
186
18
  const builtin = getBuiltinAgentProfile(name);
187
- if (!builtin && !overrides?.bin)
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)
188
23
  return undefined;
189
24
  const base = builtin ??
190
25
  {
@@ -194,99 +29,156 @@ export function resolveAgentProfile(name, overrides) {
194
29
  stdio: "captured",
195
30
  envPassthrough: [],
196
31
  parseOutput: "text",
32
+ ...(sdkMode ? { sdkMode: true } : {}),
197
33
  };
198
34
  if (!overrides)
199
35
  return base;
200
- const merged = {
36
+ return {
201
37
  name,
202
38
  bin: overrides.bin ?? base.bin,
203
39
  args: overrides.args ?? base.args,
204
- stdio: overrides.stdio ?? base.stdio,
205
- env: overrides.env ?? base.env,
206
- envPassthrough: overrides.envPassthrough
207
- ? mergePassthrough(base.envPassthrough, overrides.envPassthrough)
208
- : base.envPassthrough,
209
- timeoutMs: overrides.timeoutMs ?? base.timeoutMs,
210
- parseOutput: overrides.parseOutput ?? base.parseOutput,
40
+ stdio: base.stdio,
41
+ env: base.env,
42
+ envPassthrough: base.envPassthrough,
43
+ timeoutMs: base.timeoutMs,
44
+ parseOutput: base.parseOutput,
45
+ ...(sdkMode ? { sdkMode: true } : {}),
46
+ model: overrides.model ?? base.model,
47
+ endpoint: base.endpoint,
48
+ apiKey: base.apiKey,
49
+ commandBuilder: base.commandBuilder,
50
+ modelAliases: base.modelAliases,
211
51
  };
212
- return merged;
213
- }
214
- function mergePassthrough(base, extra) {
215
- const seen = new Set();
216
- const out = [];
217
- for (const k of [...base, ...extra]) {
218
- if (!seen.has(k)) {
219
- seen.add(k);
220
- out.push(k);
221
- }
222
- }
223
- return out;
224
52
  }
225
53
  /**
226
54
  * Resolve the runnable profile for `name`, or `undefined` if none is
227
- * available (no built-in and no user override with a `bin`).
55
+ * available (no built-in and no user override).
228
56
  */
229
- export function resolveProfileFromConfig(name, agent) {
230
- return resolveAgentProfile(name, agent?.profiles?.[name]);
57
+ export function resolveProfileFromConfig(name, config) {
58
+ return resolveAgentProfile(name, config?.profiles?.agent?.[name]);
231
59
  }
232
60
  /**
233
- * Return the names of every profile available in `agent` config (built-in
234
- * names plus any user-defined ones). Sorted, deduplicated.
61
+ * Return the names of every agent profile available in `config` built-ins
62
+ * plus any user-defined entries under `profiles.agent`. Sorted, deduplicated.
235
63
  */
236
- export function listAgentProfileNames(agent) {
64
+ export function listAgentProfileNames(config) {
237
65
  const seen = new Set(BUILTIN_AGENT_PROFILE_NAMES);
238
- for (const name of Object.keys(agent?.profiles ?? {}))
66
+ for (const name of Object.keys(config?.profiles?.agent ?? {}))
239
67
  seen.add(name);
240
68
  return [...seen].sort();
241
69
  }
242
70
  /**
243
- * Resolve the default profile name. Order: explicit `name` arg → config
244
- * `agent.default` → undefined.
71
+ * Resolve the default agent profile name. Order: explicit `requested` arg →
72
+ * `config.defaults.agent` → undefined.
245
73
  */
246
- export function resolveDefaultProfileName(agent, requested) {
74
+ export function resolveDefaultProfileName(config, requested) {
247
75
  if (requested?.trim())
248
76
  return requested.trim();
249
- if (agent?.default?.trim())
250
- return agent.default.trim();
77
+ const def = config?.defaults?.agent;
78
+ if (typeof def === "string" && def.trim())
79
+ return def.trim();
251
80
  return undefined;
252
81
  }
253
82
  /**
254
- * Throw a {@link ConfigError} with a stable hint when the caller needs
255
- * `agent` config but it is missing or unresolvable.
256
- *
257
- * Covers two cases per acceptance criteria:
258
- *
259
- * 1. The `agent` block is absent — agent commands are disabled.
260
- * 2. The block exists but no usable profile (no `default`, no requested
261
- * name, or the named profile cannot be resolved).
262
- *
263
- * 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.
264
85
  */
265
- export function requireAgentProfile(agent, requested) {
266
- if (!agent) {
267
- throw new ConfigError("agent commands are disabled: no `agent` block in config.json.", "INVALID_CONFIG_FILE", 'Run `akm setup` to detect and configure an agent CLI, or add an `agent` block manually (see docs/configuration.md "agent.*").');
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`.");
268
89
  }
269
- const name = resolveDefaultProfileName(agent, requested);
90
+ const name = resolveDefaultProfileName(config, requested);
270
91
  if (!name) {
271
- throw new ConfigError("agent commands require a profile: pass --profile or set `agent.default` in config.json.", "INVALID_CONFIG_FILE", `Available profiles: ${listAgentProfileNames(agent).join(", ")}.`);
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(", ")}.`);
272
93
  }
273
- const profile = resolveProfileFromConfig(name, agent);
94
+ const profile = resolveProfileFromConfig(name, config);
274
95
  if (!profile) {
275
- throw new ConfigError(`agent profile "${name}" is not built-in and has no \`bin\` override.`, "INVALID_CONFIG_FILE", `Define agent.profiles."${name}".bin in config.json, or pick one of: ${listAgentProfileNames(agent).join(", ")}.`);
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(", ")}.`);
276
97
  }
277
98
  return profile;
278
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
+ }
279
122
  /**
280
123
  * Convenience: list every fully-resolved profile (built-ins merged with
281
- * any user overrides). Used by setup detection to enumerate candidates.
124
+ * user overrides). Used by setup detection to enumerate candidates.
282
125
  */
283
- export function listResolvedAgentProfiles(agent) {
126
+ export function listResolvedAgentProfiles(config) {
284
127
  const resolved = [];
285
128
  const builtins = listBuiltinAgentProfiles();
286
- for (const name of listAgentProfileNames(agent)) {
287
- const profile = resolveProfileFromConfig(name, agent) ?? builtins[name];
129
+ for (const name of listAgentProfileNames(config)) {
130
+ const profile = resolveProfileFromConfig(name, config) ?? builtins[name];
288
131
  if (profile)
289
132
  resolved.push(profile);
290
133
  }
291
134
  return resolved;
292
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,3 +1,6 @@
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/.
1
4
  /**
2
5
  * Setup-time agent CLI detection (v1 spec §12.3).
3
6
  *
@@ -1,17 +1,11 @@
1
- /**
2
- * Internal entry point for the `agent` integration. CLI-only project no
3
- * public exports map. Other akm modules import from this barrel for the
4
- * sake of grouping imports.
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, parseAgentProposalPayload, stripJsonFences } from "./prompts";
9
+ export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts";
10
+ export { runAgentSdk } from "./sdk-runner";
17
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
+ }
@@ -1,8 +1,13 @@
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/.
1
4
  const COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR"];
2
5
  /**
3
6
  * Built-in profiles for the five agent CLIs the v1 spec calls out
4
7
  * explicitly. The fields here are conservative defaults — every value is
5
8
  * overridable from user config.
9
+ *
10
+ * For headless/automation use (propose, reflect, tasks), use the '-headless' variant.
6
11
  */
7
12
  const BUILTINS = {
8
13
  opencode: {
@@ -46,15 +51,75 @@ const BUILTINS = {
46
51
  parseOutput: "text",
47
52
  },
48
53
  };
49
- /** Names of every built-in profile. Stable, sorted. */
54
+ /**
55
+ * Headless variants of the five base profiles for automation use (propose, reflect, tasks).
56
+ *
57
+ * These profiles use `stdio: "captured"` and `parseOutput: "json"` so the
58
+ * agent's response can be read from stdout. They share the same `bin` and
59
+ * `envPassthrough` as the corresponding base profile but are intentionally
60
+ * kept out of `BUILTIN_AGENT_PROFILE_NAMES` (and therefore out of CLI
61
+ * detection/enumeration) to avoid showing up as separate installable profiles.
62
+ *
63
+ * Users may reference them by name via `--profile opencode-headless` or by
64
+ * setting `agent.default: "opencode-headless"` in config.json.
65
+ */
66
+ const HEADLESS_BUILTINS = {
67
+ "opencode-headless": {
68
+ name: "opencode-headless",
69
+ bin: "opencode",
70
+ args: ["run"],
71
+ stdio: "captured",
72
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENCODE_API_KEY", "OPENCODE_CONFIG"],
73
+ parseOutput: "json",
74
+ },
75
+ "claude-headless": {
76
+ name: "claude-headless",
77
+ bin: "claude",
78
+ args: [],
79
+ stdio: "captured",
80
+ envPassthrough: [...COMMON_PASSTHROUGH, "ANTHROPIC_API_KEY", "CLAUDE_CONFIG"],
81
+ parseOutput: "json",
82
+ },
83
+ "codex-headless": {
84
+ name: "codex-headless",
85
+ bin: "codex",
86
+ args: [],
87
+ stdio: "captured",
88
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "CODEX_CONFIG"],
89
+ parseOutput: "json",
90
+ },
91
+ "gemini-headless": {
92
+ name: "gemini-headless",
93
+ bin: "gemini",
94
+ args: [],
95
+ stdio: "captured",
96
+ envPassthrough: [...COMMON_PASSTHROUGH, "GEMINI_API_KEY", "GOOGLE_API_KEY"],
97
+ parseOutput: "json",
98
+ },
99
+ "aider-headless": {
100
+ name: "aider-headless",
101
+ bin: "aider",
102
+ args: ["--no-auto-commits"],
103
+ stdio: "captured",
104
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
105
+ parseOutput: "json",
106
+ },
107
+ };
108
+ /**
109
+ * Names of the five primary built-in profiles. Stable, sorted. Does NOT
110
+ * include the `-headless` variants (those are resolvable by name but are
111
+ * excluded from detection/enumeration flows).
112
+ */
50
113
  export const BUILTIN_AGENT_PROFILE_NAMES = Object.freeze(Object.keys(BUILTINS).sort());
51
- /** Returns the built-in profile by name, or `undefined` if not built-in. */
114
+ /** Returns the built-in profile by name (including headless variants), or `undefined` if not found. */
52
115
  export function getBuiltinAgentProfile(name) {
53
- return BUILTINS[name];
116
+ return BUILTINS[name] ?? HEADLESS_BUILTINS[name];
54
117
  }
55
118
  /**
56
- * Return a deep copy of every built-in profile keyed by name. Callers
57
- * should not assume reference equality with subsequent calls.
119
+ * Return a deep copy of every primary built-in profile keyed by name.
120
+ * Headless variants are NOT included use `getBuiltinAgentProfile(name)`
121
+ * to look them up by name. Callers should not assume reference equality with
122
+ * subsequent calls.
58
123
  */
59
124
  export function listBuiltinAgentProfiles() {
60
125
  const out = {};