akm-cli 0.9.0-rc.1 → 0.9.0-rc.3

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 (257) hide show
  1. package/CHANGELOG.md +249 -9
  2. package/SECURITY.md +23 -24
  3. package/dist/assets/help/help-improve.md +10 -10
  4. package/dist/assets/hints/cli-hints-full.md +44 -10
  5. package/dist/assets/hints/cli-hints-short.md +6 -2
  6. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  7. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  8. package/dist/assets/{profiles → improve-strategies}/default.json +1 -0
  9. package/dist/assets/{profiles → improve-strategies}/frequent.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  11. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  12. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +3 -3
  13. package/dist/assets/{profiles → improve-strategies}/quick.json +3 -1
  14. package/dist/assets/{profiles → improve-strategies}/recombine-only.json +2 -0
  15. package/dist/assets/{profiles → improve-strategies}/reflect-distill.json +4 -4
  16. package/dist/assets/{profiles → improve-strategies}/synthesize.json +2 -0
  17. package/dist/assets/stash-skeleton/README.md +28 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +6 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +6 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +12 -1
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +11 -1
  22. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +6 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +9 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +7 -0
  25. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +7 -0
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +6 -0
  27. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +98 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/domains.md +63 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/organization.md +127 -0
  30. package/dist/assets/tasks/core/backup.yml +3 -2
  31. package/dist/assets/tasks/core/extract.yml +1 -0
  32. package/dist/assets/tasks/core/improve.yml +1 -0
  33. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  34. package/dist/assets/tasks/core/sync.yml +1 -0
  35. package/dist/assets/tasks/core/version-check.yml +1 -0
  36. package/dist/assets/tasks/graph-refresh-weekly.yml +4 -4
  37. package/dist/assets/templates/html/health.html +5 -1
  38. package/dist/cli/config-migrate.js +547 -126
  39. package/dist/cli/config-validate.js +10 -8
  40. package/dist/cli.js +50 -14
  41. package/dist/commands/agent/agent-dispatch.js +17 -16
  42. package/dist/commands/agent/agent-support.js +0 -24
  43. package/dist/commands/agent/contribute-cli.js +5 -15
  44. package/dist/commands/backup-cli.js +56 -0
  45. package/dist/commands/config-cli.js +48 -155
  46. package/dist/commands/env/secret.js +8 -5
  47. package/dist/commands/feedback-cli.js +24 -7
  48. package/dist/commands/health/checks.js +200 -74
  49. package/dist/commands/health/html-report.js +4 -0
  50. package/dist/commands/health/improve-metrics.js +30 -32
  51. package/dist/commands/health/llm-usage.js +19 -19
  52. package/dist/commands/health/md-report.js +4 -0
  53. package/dist/commands/health/metrics.js +2 -1
  54. package/dist/commands/health/surfaces.js +7 -5
  55. package/dist/commands/health.js +1 -1
  56. package/dist/commands/improve/anti-collapse.js +3 -3
  57. package/dist/commands/improve/collapse-detector.js +5 -5
  58. package/dist/commands/improve/consolidate/chunking.js +2 -2
  59. package/dist/commands/improve/consolidate.js +148 -88
  60. package/dist/commands/improve/distill/promote-memory.js +13 -18
  61. package/dist/commands/improve/distill/quality-gate.js +6 -8
  62. package/dist/commands/improve/distill-guards.js +1 -1
  63. package/dist/commands/improve/distill-promotion-policy.js +32 -26
  64. package/dist/commands/improve/distill.js +68 -41
  65. package/dist/commands/improve/eligibility.js +31 -20
  66. package/dist/commands/improve/extract-cli.js +47 -19
  67. package/dist/commands/improve/extract-prompt.js +2 -2
  68. package/dist/commands/improve/extract.js +153 -73
  69. package/dist/commands/improve/improve-auto-accept.js +14 -28
  70. package/dist/commands/improve/improve-cli.js +41 -17
  71. package/dist/commands/improve/improve-result-file.js +30 -24
  72. package/dist/commands/improve/improve-strategies.js +138 -0
  73. package/dist/commands/improve/improve.js +109 -38
  74. package/dist/commands/improve/locks.js +66 -45
  75. package/dist/commands/improve/loop-stages.js +86 -39
  76. package/dist/commands/improve/memory/memory-belief.js +79 -7
  77. package/dist/commands/improve/memory/memory-contradiction-detect.js +12 -4
  78. package/dist/commands/improve/preparation.js +122 -90
  79. package/dist/commands/improve/procedural.js +13 -8
  80. package/dist/commands/improve/recombine.js +33 -8
  81. package/dist/commands/improve/reflect.js +143 -228
  82. package/dist/commands/improve/salience.js +5 -1
  83. package/dist/commands/improve/shared.js +11 -5
  84. package/dist/commands/improve/source-identity.js +43 -0
  85. package/dist/commands/lint/base-linter.js +152 -42
  86. package/dist/commands/migrate-cli.js +36 -0
  87. package/dist/commands/mv-cli.js +1198 -0
  88. package/dist/commands/proposal/drain.js +16 -4
  89. package/dist/commands/proposal/proposal-cli.js +21 -10
  90. package/dist/commands/proposal/proposal.js +16 -55
  91. package/dist/commands/proposal/propose.js +64 -69
  92. package/dist/commands/proposal/repository.js +664 -58
  93. package/dist/commands/read/curate.js +4 -2
  94. package/dist/commands/read/knowledge.js +440 -5
  95. package/dist/commands/read/remember-cli.js +39 -2
  96. package/dist/commands/read/search-cli.js +6 -1
  97. package/dist/commands/read/search.js +6 -2
  98. package/dist/commands/read/show.js +8 -7
  99. package/dist/commands/registry-cli.js +29 -14
  100. package/dist/commands/remember.js +2 -0
  101. package/dist/commands/sources/init.js +13 -14
  102. package/dist/commands/sources/schema-repair.js +2 -4
  103. package/dist/commands/sources/self-update.js +156 -112
  104. package/dist/commands/sources/source-add.js +62 -73
  105. package/dist/commands/sources/source-manage.js +50 -46
  106. package/dist/commands/sources/sources-cli.js +7 -2
  107. package/dist/commands/sources/stash-cli.js +41 -4
  108. package/dist/commands/tasks/default-tasks.js +12 -12
  109. package/dist/commands/tasks/tasks-cli.js +7 -3
  110. package/dist/commands/tasks/tasks.js +113 -18
  111. package/dist/commands/wiki-cli.js +9 -10
  112. package/dist/core/asset/frontmatter.js +12 -2
  113. package/dist/core/common.js +41 -6
  114. package/dist/core/config/config-io.js +30 -19
  115. package/dist/core/config/config-schema.js +373 -69
  116. package/dist/core/config/config-types.js +3 -3
  117. package/dist/core/config/config-version.js +29 -0
  118. package/dist/core/config/config-walker.js +98 -27
  119. package/dist/core/config/config.js +135 -268
  120. package/dist/core/config/deep-merge.js +41 -0
  121. package/dist/core/config/engine-semantics.js +32 -0
  122. package/dist/core/errors.js +2 -2
  123. package/dist/core/extra-params.js +61 -0
  124. package/dist/core/file-lock.js +202 -57
  125. package/dist/core/improve-result.js +178 -0
  126. package/dist/core/maintenance-barrier.js +119 -0
  127. package/dist/core/migration-backup.js +1061 -0
  128. package/dist/core/migration-operation.js +44 -0
  129. package/dist/core/paths.js +3 -0
  130. package/dist/core/redaction.js +358 -0
  131. package/dist/core/state/migrations.js +15 -3
  132. package/dist/core/state-db.js +60 -2
  133. package/dist/core/write-source.js +86 -18
  134. package/dist/indexer/db/db.js +212 -41
  135. package/dist/indexer/graph/graph-extraction.js +28 -16
  136. package/dist/indexer/index-writer-lock.js +59 -51
  137. package/dist/indexer/index-written-assets.js +75 -49
  138. package/dist/indexer/indexer.js +52 -3
  139. package/dist/indexer/passes/memory-inference.js +10 -6
  140. package/dist/indexer/passes/metadata.js +250 -0
  141. package/dist/indexer/search/db-search.js +111 -44
  142. package/dist/indexer/search/fts-query.js +41 -0
  143. package/dist/indexer/search/ranking-contributors.js +48 -0
  144. package/dist/indexer/search/ranking.js +36 -23
  145. package/dist/indexer/search/search-fields.js +11 -1
  146. package/dist/indexer/search/search-source.js +2 -2
  147. package/dist/indexer/usage/usage-events.js +8 -2
  148. package/dist/integrations/agent/builder-shared.js +7 -0
  149. package/dist/integrations/agent/builders.js +5 -52
  150. package/dist/integrations/agent/config.js +3 -143
  151. package/dist/integrations/agent/detect.js +17 -2
  152. package/dist/integrations/agent/engine-resolution.js +209 -0
  153. package/dist/integrations/agent/index.js +1 -2
  154. package/dist/integrations/agent/model-aliases.js +7 -2
  155. package/dist/integrations/agent/profiles.js +6 -99
  156. package/dist/integrations/agent/runner-dispatch.js +76 -13
  157. package/dist/integrations/agent/runner.js +76 -207
  158. package/dist/integrations/agent/spawn.js +4 -6
  159. package/dist/integrations/harnesses/aider/agent-builder.js +2 -3
  160. package/dist/integrations/harnesses/aider/index.js +0 -1
  161. package/dist/integrations/harnesses/amazonq/agent-builder.js +2 -3
  162. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  163. package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
  164. package/dist/integrations/harnesses/claude/index.js +0 -2
  165. package/dist/integrations/harnesses/codex/agent-builder.js +2 -3
  166. package/dist/integrations/harnesses/codex/index.js +0 -1
  167. package/dist/integrations/harnesses/copilot/agent-builder.js +2 -3
  168. package/dist/integrations/harnesses/copilot/index.js +0 -1
  169. package/dist/integrations/harnesses/gemini/agent-builder.js +2 -3
  170. package/dist/integrations/harnesses/gemini/index.js +0 -1
  171. package/dist/integrations/harnesses/index.js +1 -24
  172. package/dist/integrations/harnesses/opencode/agent-builder.js +2 -3
  173. package/dist/integrations/harnesses/opencode/index.js +0 -6
  174. package/dist/integrations/harnesses/opencode-sdk/harness.js +1 -6
  175. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
  176. package/dist/integrations/harnesses/openhands/agent-builder.js +2 -3
  177. package/dist/integrations/harnesses/openhands/index.js +0 -1
  178. package/dist/integrations/harnesses/pi/agent-builder.js +2 -3
  179. package/dist/integrations/harnesses/pi/index.js +0 -1
  180. package/dist/integrations/harnesses/types.js +1 -32
  181. package/dist/integrations/lockfile.js +32 -21
  182. package/dist/llm/client.js +48 -14
  183. package/dist/llm/feature-gate.js +15 -47
  184. package/dist/llm/graph-extract.js +1 -1
  185. package/dist/llm/index-passes.js +8 -42
  186. package/dist/llm/memory-infer-impl.js +1 -1
  187. package/dist/llm/usage-persist.js +4 -0
  188. package/dist/llm/usage-telemetry.js +35 -5
  189. package/dist/output/shapes/helpers.js +2 -1
  190. package/dist/output/shapes/passthrough.js +2 -0
  191. package/dist/output/text/helpers.js +3 -1
  192. package/dist/schemas/akm-config.json +11013 -8600
  193. package/dist/schemas/akm-task.json +87 -0
  194. package/dist/schemas/akm-workflow.json +57 -13
  195. package/dist/scripts/migrate-storage.js +8502 -543
  196. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8493 -515
  197. package/dist/setup/detected-engines.js +136 -0
  198. package/dist/setup/engine-config.js +99 -0
  199. package/dist/setup/setup.js +237 -133
  200. package/dist/setup/steps/connection.js +62 -33
  201. package/dist/setup/steps/platforms.js +4 -4
  202. package/dist/setup/steps/tasks.js +1 -1
  203. package/dist/setup/steps.js +3 -2
  204. package/dist/sources/providers/git-stash.js +58 -21
  205. package/dist/sources/providers/git.js +1 -1
  206. package/dist/storage/database.js +13 -1
  207. package/dist/storage/engines/sqlite-migrations.js +139 -3
  208. package/dist/storage/repositories/events-repository.js +24 -0
  209. package/dist/storage/repositories/improve-runs-repository.js +5 -5
  210. package/dist/storage/repositories/proposals-repository.js +14 -0
  211. package/dist/storage/repositories/task-history-repository.js +78 -0
  212. package/dist/storage/repositories/workflow-runs-repository.js +9 -8
  213. package/dist/tasks/embedded.js +2 -0
  214. package/dist/tasks/parser.js +138 -52
  215. package/dist/tasks/runner.js +71 -75
  216. package/dist/tasks/schema.js +1 -1
  217. package/dist/tasks/validator.js +11 -6
  218. package/dist/wiki/wiki.js +9 -8
  219. package/dist/workflows/authoring/workflow-program-template.yaml +3 -3
  220. package/dist/workflows/concurrency-policy.js +15 -0
  221. package/dist/workflows/db.js +78 -15
  222. package/dist/workflows/exec/brief.js +18 -24
  223. package/dist/workflows/exec/frozen-judge.js +47 -0
  224. package/dist/workflows/exec/native-executor.js +124 -65
  225. package/dist/workflows/exec/report.js +93 -33
  226. package/dist/workflows/exec/run-workflow.js +38 -25
  227. package/dist/workflows/exec/scheduler.js +12 -41
  228. package/dist/workflows/exec/step-work.js +91 -35
  229. package/dist/workflows/ir/compile.js +13 -26
  230. package/dist/workflows/ir/freeze.js +243 -0
  231. package/dist/workflows/ir/plan-hash.js +40 -5
  232. package/dist/workflows/ir/schema.js +542 -1
  233. package/dist/workflows/parser.js +7 -0
  234. package/dist/workflows/program/parser.js +132 -23
  235. package/dist/workflows/program/project.js +3 -4
  236. package/dist/workflows/program/schema.js +2 -2
  237. package/dist/workflows/resource-limits.js +20 -0
  238. package/dist/workflows/runtime/plan-classifier.js +187 -0
  239. package/dist/workflows/runtime/runs.js +54 -47
  240. package/dist/workflows/runtime/workflow-asset-loader.js +0 -22
  241. package/dist/workflows/validator.js +49 -2
  242. package/docs/data-and-telemetry.md +2 -2
  243. package/docs/migration/release-notes/0.6.0.md +1 -1
  244. package/docs/migration/release-notes/0.7.0.md +5 -4
  245. package/docs/migration/release-notes/0.9.0.md +24 -7
  246. package/docs/migration/v0.8-to-v0.9.md +506 -0
  247. package/package.json +4 -2
  248. package/schemas/akm-config.json +16638 -0
  249. package/schemas/akm-task.json +87 -0
  250. package/schemas/akm-workflow.json +372 -0
  251. package/dist/commands/improve/improve-profiles.js +0 -168
  252. package/dist/core/config/config-migration.js +0 -602
  253. package/dist/core/deep-merge.js +0 -38
  254. package/dist/llm/call-ai.js +0 -62
  255. package/dist/setup/legacy-config.js +0 -106
  256. package/docs/README.md +0 -104
  257. /package/dist/assets/{profiles → improve-strategies}/thorough.json +0 -0
@@ -8,27 +8,29 @@
8
8
  * prints "All checks passed." or a list of structured errors (path + message).
9
9
  * Exits non-zero on errors so it composes well in CI hooks.
10
10
  */
11
- import fs from "node:fs";
12
- import { parseConfigText } from "../core/config/config-io.js";
13
- import { validateConfigShape } from "../core/config/config-schema.js";
11
+ import { parseConfigText, readConfigText } from "../core/config/config-io.js";
12
+ import { CURRENT_CONFIG_VERSION, validateConfigShape } from "../core/config/config-schema.js";
14
13
  import { ConfigError } from "../core/errors.js";
15
14
  import { getConfigPath } from "../core/paths.js";
16
15
  export async function runConfigValidate() {
17
16
  const configPath = getConfigPath();
18
- if (!fs.existsSync(configPath)) {
19
- console.log(`No config file at ${configPath} — nothing to validate.`);
20
- return;
21
- }
22
17
  let text;
23
18
  try {
24
- text = fs.readFileSync(configPath, "utf8");
19
+ text = readConfigText(configPath);
25
20
  }
26
21
  catch (err) {
27
22
  const detail = err instanceof Error ? err.message : String(err);
28
23
  throw new ConfigError(`Could not read config at ${configPath}: ${detail}`, "INVALID_CONFIG_FILE");
29
24
  }
25
+ if (text === undefined) {
26
+ console.log(`No config file at ${configPath} — nothing to validate.`);
27
+ return;
28
+ }
30
29
  // parseConfigText throws ConfigError on malformed JSON (#458). Surface as-is.
31
30
  const raw = parseConfigText(text, configPath);
31
+ if (raw.configVersion !== CURRENT_CONFIG_VERSION) {
32
+ throw new ConfigError(`Unsupported configVersion at ${configPath}: expected "${CURRENT_CONFIG_VERSION}".`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually; AKM 0.9 never translates profile-based configuration.");
33
+ }
32
34
  const result = validateConfigShape(raw);
33
35
  if (result.ok) {
34
36
  console.log(`All checks passed. (${configPath})`);
package/dist/cli.js CHANGED
@@ -63,6 +63,7 @@ import { defineCommand, runMain } from "citty";
63
63
  import { findCittyTopLevelCommand } from "./cli/parse-args.js";
64
64
  import { EXIT_CODES, emitJsonError, output, parseAllFlagValues, runWithJsonErrors } from "./cli/shared.js";
65
65
  import { agentCommand, lintCommand, proposeCommand } from "./commands/agent/contribute-cli.js";
66
+ import { backupCommand } from "./commands/backup-cli.js";
66
67
  import { generateBashCompletions, installBashCompletions } from "./commands/completions.js";
67
68
  import { configCommand } from "./commands/config-cli.js";
68
69
  import { envCommand } from "./commands/env/env-cli.js";
@@ -74,6 +75,8 @@ import { renderRunsDetailMd, renderWindowCompareMd } from "./commands/health/md-
74
75
  import { parseWindowSpec } from "./commands/health/windows.js";
75
76
  import { extractCommand } from "./commands/improve/extract-cli.js";
76
77
  import { improveCommand } from "./commands/improve/improve-cli.js";
78
+ import { migrateCommand } from "./commands/migrate-cli.js";
79
+ import { mvCommand } from "./commands/mv-cli.js";
77
80
  import { hintsCommand, lessonsCommand, logCommand } from "./commands/observability-cli.js";
78
81
  import { proposalCommand } from "./commands/proposal/proposal-cli.js";
79
82
  import { rememberCommand } from "./commands/read/remember-cli.js";
@@ -88,11 +91,12 @@ import { tasksCommand } from "./commands/tasks/tasks-cli.js";
88
91
  import { wikiCommand } from "./commands/wiki-cli.js";
89
92
  import { workflowCommand } from "./commands/workflow-cli.js";
90
93
  import { bestEffort } from "./core/best-effort.js";
91
- import { loadConfig } from "./core/config/config.js";
94
+ import { DEFAULT_CONFIG, loadConfig } from "./core/config/config.js";
92
95
  import { UsageError } from "./core/errors.js";
93
96
  import { getCacheDir, getConfigPath, getDbPath } from "./core/paths.js";
94
97
  import { plainize } from "./core/tty.js";
95
98
  import { info, isQuiet, setQuiet, setVerbose, warn } from "./core/warn.js";
99
+ import { disposeDispatchResources } from "./integrations/agent/runner-dispatch.js";
96
100
  import { getHyphenatedBoolean, getOutputMode, initOutputMode, parseFlagValue } from "./output/context.js";
97
101
  import { deliverRendered, renderHtml, resolveTemplatePath } from "./output/html-render.js";
98
102
  import { pkgVersion } from "./version.js";
@@ -195,10 +199,15 @@ const setupCommand = defineCommand({
195
199
  type: "string",
196
200
  description: "Stash directory path (overrides stashDir in config or --config JSON)",
197
201
  },
202
+ "no-init": {
203
+ type: "boolean",
204
+ default: false,
205
+ description: "Write configuration without scaffolding the stash directory",
206
+ },
198
207
  probe: {
199
208
  type: "boolean",
200
209
  default: false,
201
- description: "Probe LLM/embedding endpoints after writing config to verify connectivity",
210
+ description: "Probe LLM/embedding endpoints before writing config to verify connectivity",
202
211
  },
203
212
  "detect-only": {
204
213
  type: "boolean",
@@ -213,7 +222,9 @@ const setupCommand = defineCommand({
213
222
  },
214
223
  async run({ args }) {
215
224
  await runWithJsonErrors(async () => {
216
- const noInit = getHyphenatedBoolean(args, "no-init");
225
+ // citty treats a leading `no-` as boolean negation on some parse paths,
226
+ // so retain the raw argv spelling as the authoritative compatibility form.
227
+ const noInit = getHyphenatedBoolean(args, "no-init") || process.argv.includes("--no-init");
217
228
  const detectOnly = args["detect-only"];
218
229
  const resetRecommended = args["reset-recommended"];
219
230
  if (detectOnly) {
@@ -505,7 +516,10 @@ export const main = defineCommand({
505
516
  import: importKnowledgeCommand,
506
517
  sync: syncCommand,
507
518
  clone: cloneCommand,
519
+ mv: mvCommand,
508
520
  registry: registryCommand,
521
+ migrate: migrateCommand,
522
+ backup: backupCommand,
509
523
  config: configCommand,
510
524
  feedback: feedbackCommand,
511
525
  history: historyCommand,
@@ -527,6 +541,20 @@ export const main = defineCommand({
527
541
  },
528
542
  });
529
543
  const MAIN_TOP_LEVEL_ARGS = main.args;
544
+ /** Recovery/setup surfaces must remain reachable when config.json is invalid. */
545
+ export function shouldBypassConfigStartup(argv) {
546
+ const args = argv.slice(2);
547
+ if (args.includes("--help") || args.includes("-h") || args.includes("--version") || args.includes("-v"))
548
+ return true;
549
+ const command = findCittyTopLevelCommand([...args], MAIN_TOP_LEVEL_ARGS);
550
+ if (command === "setup" || command === "backup" || command === "migrate")
551
+ return true;
552
+ if (command !== "config")
553
+ return false;
554
+ const configIndex = args.indexOf("config");
555
+ const subcommand = args.slice(configIndex + 1).find((arg) => !arg.startsWith("-"));
556
+ return subcommand === "path" || subcommand === "validate" || subcommand === "migrate";
557
+ }
530
558
  // ── Exit codes ──────────────────────────────────────────────────────────────
531
559
  // Canonical table lives in `src/cli/shared.ts` (EXIT_CODES). These aliases keep
532
560
  // the local call sites terse. EXIT_HEALTH_WARN (4) is the `akm health` "warn"
@@ -556,7 +584,8 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
556
584
  // rather than letting the raw exception escape with a stack trace.
557
585
  try {
558
586
  applyEarlyStderrFlags(process.argv);
559
- initOutputMode(process.argv, loadConfig().output ?? {});
587
+ const bypassConfig = shouldBypassConfigStartup(process.argv);
588
+ initOutputMode(process.argv, bypassConfig ? (DEFAULT_CONFIG.output ?? {}) : (loadConfig().output ?? {}));
560
589
  }
561
590
  catch (error) {
562
591
  emitJsonError(error);
@@ -575,15 +604,17 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
575
604
  // 0.8.0 moved the index to $XDG_DATA_HOME/akm/index.db (getDataDir()).
576
605
  // If the old file exists at $XDG_CACHE_HOME/akm/index.db, remove it so the
577
606
  // user isn't confused by a phantom DB. Best-effort; never fatal.
578
- bestEffort(() => {
579
- const oldIndexPath = path.join(getCacheDir(), "index.db");
580
- if (fs.existsSync(oldIndexPath)) {
581
- fs.rmSync(oldIndexPath, { force: true });
582
- fs.rmSync(`${oldIndexPath}-shm`, { force: true });
583
- fs.rmSync(`${oldIndexPath}-wal`, { force: true });
584
- warn(`Cleaned up stale 0.7.x index from ${oldIndexPath}. Canonical path is now ${getDbPath()}.`);
585
- }
586
- }, "stale 0.7.x index cleanup is non-fatal");
607
+ if (!shouldBypassConfigStartup(process.argv)) {
608
+ bestEffort(() => {
609
+ const oldIndexPath = path.join(getCacheDir(), "index.db");
610
+ if (fs.existsSync(oldIndexPath)) {
611
+ fs.rmSync(oldIndexPath, { force: true });
612
+ fs.rmSync(`${oldIndexPath}-shm`, { force: true });
613
+ fs.rmSync(`${oldIndexPath}-wal`, { force: true });
614
+ warn(`Cleaned up stale 0.7.x index from ${oldIndexPath}. Canonical path is now ${getDbPath()}.`);
615
+ }
616
+ }, "stale 0.7.x index cleanup is non-fatal");
617
+ }
587
618
  // First-time-user breadcrumb: when run with no subcommand AND no config
588
619
  // exists yet AND stderr is a TTY, print a friendly pointer to `akm setup`
589
620
  // above citty's auto-generated usage block. Triggers only when stdin/stderr
@@ -608,5 +639,10 @@ if (import.meta.main || process.env.AKM_NODE_ENTRY === "1") {
608
639
  }
609
640
  console.error(plainize("👋 First time with akm? Run `akm setup` to get started.\n Docs: https://github.com/itlackey/akm#readme\n"));
610
641
  })();
611
- runMain(main);
642
+ try {
643
+ await runMain(main);
644
+ }
645
+ finally {
646
+ await disposeDispatchResources();
647
+ }
612
648
  }
@@ -2,9 +2,9 @@
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
  /**
5
- * `akm agent <profile> [--prompt <text>] [--command <ref>] [--workflow <ref>] [args...]`
5
+ * `akm agent [--engine <name>] [--prompt <text>] [--command <ref>] [--workflow <ref>] [args...]`
6
6
  *
7
- * Dispatch an agent by named profile, optionally injecting a prompt from
7
+ * Dispatch an agent by named engine, optionally injecting a prompt from
8
8
  * inline text, a stash command: asset, or a stash workflow: asset.
9
9
  *
10
10
  * When none of --prompt, --command, or --workflow are given, the agent is
@@ -16,9 +16,8 @@
16
16
  import fs from "node:fs";
17
17
  import { parseAssetRef } from "../../core/asset/asset-ref.js";
18
18
  import { NotFoundError, UsageError } from "../../core/errors.js";
19
- import { requireAgentProfile } from "../../integrations/agent/config.js";
20
- import { runAgent } from "../../integrations/agent/spawn.js";
21
- import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
19
+ import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
20
+ import { executeRunner } from "../../integrations/agent/runner-dispatch.js";
22
21
  /**
23
22
  * Fill `{{0}}`, `{{1}}`, ... placeholders in `template` with the
24
23
  * corresponding entries in `args`. Any placeholder index that exceeds the
@@ -59,12 +58,16 @@ async function resolveAssetBody(ref) {
59
58
  }
60
59
  }
61
60
  export async function akmAgentDispatch(options) {
62
- if (!options.profileName?.trim()) {
63
- throw new UsageError("agent: <profile> is required.", "MISSING_REQUIRED_ARGUMENT");
61
+ if (!options.agentConfig)
62
+ throw new UsageError("agent requires a valid config with an agent engine.", "MISSING_REQUIRED_ARGUMENT");
63
+ const engineName = options.engine ?? options.agentConfig.defaults?.engine;
64
+ if (!engineName)
65
+ throw new UsageError("agent requires --engine or defaults.engine.", "MISSING_REQUIRED_ARGUMENT");
66
+ const runner = resolveEngine(engineName, options.agentConfig);
67
+ if (runner.kind === "llm") {
68
+ throw new UsageError(`Engine "${engineName}" is an LLM engine; akm agent requires an agent engine.`, "INVALID_FLAG_VALUE");
64
69
  }
65
- // Resolve the profile — throws ConfigError with an actionable hint when
66
- // agent config is absent or the profile is not found.
67
- const profile = requireAgentProfile(options.agentConfig, options.profileName.trim());
70
+ const profile = runner.profile;
68
71
  // Resolve the prompt text from whichever source was provided.
69
72
  let prompt;
70
73
  if (options.commandRef) {
@@ -79,7 +82,7 @@ export async function akmAgentDispatch(options) {
79
82
  prompt = options.prompt;
80
83
  }
81
84
  // When prompt is undefined, the agent is launched interactively.
82
- const stdio = prompt === undefined && profile.sdkMode !== true ? "interactive" : profile.stdio;
85
+ const stdio = prompt === undefined && runner.kind !== "sdk" ? "interactive" : profile.stdio;
83
86
  // Build the final dispatch request: merge the caller-supplied dispatch with
84
87
  // the resolved prompt so the builder has all context in one place.
85
88
  const dispatchRequest = options.dispatch
@@ -93,14 +96,12 @@ export async function akmAgentDispatch(options) {
93
96
  ...(options.cwd ? { cwd: options.cwd } : {}),
94
97
  ...(dispatchRequest !== undefined ? { dispatch: dispatchRequest } : {}),
95
98
  };
96
- const result = profile.sdkMode
97
- ? await runOpencodeSdk(profile, prompt ?? "", runOptions, options.llmConfig)
98
- : await runAgent(profile, prompt, runOptions);
99
+ const result = await executeRunner(runner, prompt ?? "", runOptions);
99
100
  return {
100
- schemaVersion: 1,
101
+ schemaVersion: 2,
101
102
  ok: result.ok,
102
103
  shape: "agent-result",
103
- profileName: profile.name,
104
+ engine: engineName,
104
105
  exitCode: result.exitCode,
105
106
  stdout: result.stdout ?? "",
106
107
  stderr: result.stderr ?? "",
@@ -1,30 +1,6 @@
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 { loadConfig } from "../../core/config/config.js";
5
- import { requireAgentProfile, } from "../../integrations/agent/index.js";
6
- // ── Config helpers ───────────────────────────────────────────────────────────
7
- /**
8
- * Load the loaded AkmConfig from disk.
9
- *
10
- * After 0.8.0, the legacy `agent` top-level block was removed — the agent
11
- * profile data now lives on the unified `AkmConfig` (via `profiles.agent` and
12
- * `defaults.agent`). This helper remains for source-compat with callers that
13
- * still expect an "AgentConfig"; it now returns the loaded `AkmConfig`.
14
- */
15
- export function loadAgentConfigFromDisk() {
16
- return loadConfig();
17
- }
18
- /**
19
- * Resolve the agent profile for a command's options.
20
- * Prefers an injected `agentProfile` (test seam) over the on-disk config.
21
- */
22
- export function resolveAgentProfile(options) {
23
- if (options.agentProfile)
24
- return options.agentProfile;
25
- const agent = options.agentConfig ?? loadAgentConfigFromDisk();
26
- return requireAgentProfile(agent, options.profile);
27
- }
28
4
  // ── Failure helpers ──────────────────────────────────────────────────────────
29
5
  /**
30
6
  * Base failure envelope shared by all agent command failures.
@@ -38,17 +38,13 @@ export const agentCommand = defineCommand({
38
38
  description: "Dispatch an agent CLI (opencode, claude, …) with an optional agent asset that provides the system prompt, model, and tool policy. Use <agent-ref> to embody a stash agent, --model to override the model, and --prompt/--command/--workflow to provide the task.",
39
39
  },
40
40
  args: {
41
- profile: {
42
- type: "positional",
43
- description: "Agent profile / platform to use (opencode, claude, …)",
44
- required: false,
45
- },
46
41
  "agent-ref": {
47
42
  type: "positional",
48
43
  description: "Optional agent asset ref (e.g. agent:code-reviewer). Loads system prompt, model, and tool policy from the stash asset.",
49
44
  required: false,
50
45
  },
51
46
  prompt: { type: "string", description: "Task prompt to pass to the agent" },
47
+ engine: { type: "string", description: "Agent engine to use (default: defaults.engine)" },
52
48
  command: { type: "string", description: "Load prompt from a command: asset" },
53
49
  workflow: { type: "string", description: "Load prompt from a workflow: asset" },
54
50
  model: {
@@ -63,13 +59,8 @@ export const agentCommand = defineCommand({
63
59
  },
64
60
  async run({ args }) {
65
61
  await runWithJsonErrors(async () => {
66
- if (!args.profile) {
67
- throw new UsageError("Usage: akm agent <profile> [<agent-ref>] [--prompt <text>] [--model <model>]", "MISSING_REQUIRED_ARGUMENT", "Provide the agent profile name. Available profiles are listed in profiles.agent.");
68
- }
69
62
  const timeoutMs = parsePositiveIntFlag(args["timeout-ms"], "--timeout-ms");
70
63
  const config = loadConfig();
71
- const { getDefaultLlmConfig } = await import("../../core/config/config.js");
72
- // After 0.8.0 the agent block IS the loaded AkmConfig.
73
64
  const agentConfig = config;
74
65
  // Resolve agent asset ref → extract system prompt, model, and tool policy.
75
66
  const agentRef = getStringArg(args, "agent-ref");
@@ -95,12 +86,11 @@ export const agentCommand = defineCommand({
95
86
  // platform-specific flags beyond the profile's base args).
96
87
  const hasDispatchContent = !!(promptText ?? commandRef ?? workflowRef ?? systemPrompt ?? model ?? assetTools);
97
88
  const result = await akmAgentDispatch({
98
- profileName: String(args.profile),
89
+ engine: getStringArg(args, "engine"),
99
90
  prompt: promptText,
100
91
  commandRef,
101
92
  workflowRef,
102
93
  agentConfig,
103
- llmConfig: getDefaultLlmConfig(config),
104
94
  ...(hasDispatchContent
105
95
  ? {
106
96
  dispatch: {
@@ -125,7 +115,7 @@ export const agentCommand = defineCommand({
125
115
  export const lintCommand = defineCommand({
126
116
  meta: {
127
117
  name: "lint",
128
- description: "Scan stash .md files for structural issues (unquoted colons, missing updated field, orphaned stubs, placeholder stubs, missing name/type, stale paths). Use --fix to auto-fix Tier 1 issues. Exits 0 on success regardless of findings; use --fail-on-flagged for CI fail-on-finding behavior.",
118
+ description: "Scan stash .md files for structural issues (unquoted colons, missing updated field, orphaned stubs, placeholder stubs, missing name/type, stale paths, broken refs in body text and in refs/xrefs/supersededBy/contradictedBy frontmatter). Use --fix to auto-fix Tier 1 issues. Exits 0 on success regardless of findings; use --fail-on-flagged for CI fail-on-finding behavior.",
129
119
  },
130
120
  args: {
131
121
  fix: {
@@ -182,7 +172,7 @@ export const proposeCommand = defineCommand({
182
172
  },
183
173
  task: { type: "string", description: "Task description for the agent (what should the asset do?)" },
184
174
  file: { type: "string", description: "Read the task or prompt text from a UTF-8 file" },
185
- profile: { type: "string", description: "Override the agent profile (defaults to agent.default)" },
175
+ engine: { type: "string", description: "Engine to use (defaults to defaults.engine)" },
186
176
  "timeout-ms": { type: "string", description: "Override the agent CLI timeout in milliseconds" },
187
177
  },
188
178
  async run({ args }) {
@@ -207,7 +197,7 @@ export const proposeCommand = defineCommand({
207
197
  type: String(args.type),
208
198
  name: proposedName,
209
199
  task: taskText,
210
- profile: getStringArg(args, "profile"),
200
+ engine: getStringArg(args, "engine"),
211
201
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
212
202
  });
213
203
  output("propose", result);
@@ -0,0 +1,56 @@
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
+ import { defineGroupCommand, defineJsonCommand, output } from "../cli/shared.js";
5
+ import { UsageError } from "../core/errors.js";
6
+ import { createMigrationBackup, MIGRATION_BACKUP_VERSION, restoreMigrationBackup } from "../core/migration-backup.js";
7
+ function requireVersion(value) {
8
+ if (value !== MIGRATION_BACKUP_VERSION) {
9
+ throw new UsageError(`Unsupported migration backup target ${JSON.stringify(value)}; expected ${MIGRATION_BACKUP_VERSION}.`, "INVALID_FLAG_VALUE");
10
+ }
11
+ }
12
+ export const backupCommand = defineGroupCommand({
13
+ meta: { name: "backup", description: "Create or restore a verified migration recovery run" },
14
+ subCommands: {
15
+ create: defineJsonCommand({
16
+ meta: { name: "create", description: "Create a unique installation-scoped migration recovery run" },
17
+ args: {
18
+ for: { type: "string", required: true, description: "Migration target version (0.9.0)" },
19
+ },
20
+ run({ args }) {
21
+ requireVersion(args.for);
22
+ const result = createMigrationBackup();
23
+ output("backup", {
24
+ action: "create",
25
+ for: MIGRATION_BACKUP_VERSION,
26
+ path: result.path,
27
+ created: result.created,
28
+ manifest: result.manifest,
29
+ });
30
+ },
31
+ }),
32
+ restore: defineJsonCommand({
33
+ meta: { name: "restore", description: "Restore a recovery run after preserving a rescue snapshot" },
34
+ args: {
35
+ for: { type: "string", required: true, description: "Migration target version (0.9.0)" },
36
+ run: { type: "string", description: "Backup run ID (defaults to the newest applicable run)" },
37
+ confirm: { type: "boolean", default: false, description: "Confirm destructive restoration" },
38
+ },
39
+ run({ args }) {
40
+ requireVersion(args.for);
41
+ const result = restoreMigrationBackup(args.confirm, args.run);
42
+ output("backup", {
43
+ action: "restore",
44
+ for: MIGRATION_BACKUP_VERSION,
45
+ path: result.path,
46
+ restored: true,
47
+ rescuePath: result.rescuePath,
48
+ manifest: result.manifest,
49
+ });
50
+ },
51
+ }),
52
+ },
53
+ defaultRun() {
54
+ throw new UsageError("Choose `backup create` or `backup restore`.", "MISSING_REQUIRED_ARGUMENT");
55
+ },
56
+ });