akm-cli 0.9.0-rc.0 → 0.9.0-rc.13

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 (598) hide show
  1. package/CHANGELOG.md +1283 -22
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  26. package/dist/assets/stash-skeleton/README.md +38 -10
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  39. package/dist/assets/tasks/core/extract.yml +3 -2
  40. package/dist/assets/tasks/core/improve.yml +2 -1
  41. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  42. package/dist/assets/tasks/core/sync.yml +1 -0
  43. package/dist/assets/tasks/core/version-check.yml +2 -1
  44. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  45. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  46. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  48. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  49. package/dist/assets/templates/html/health.html +5 -4
  50. package/dist/assets/workflows/workflow-template.md +31 -15
  51. package/dist/cli/invocation.js +279 -0
  52. package/dist/cli/parse-args.js +5 -90
  53. package/dist/cli/retired-commands.js +78 -0
  54. package/dist/cli/shared.js +158 -48
  55. package/dist/cli-node.mjs +2 -1
  56. package/dist/cli.js +747 -293
  57. package/dist/commands/agent/agent-dispatch.js +19 -18
  58. package/dist/commands/agent/agent-support.js +0 -24
  59. package/dist/commands/agent/contribute-cli.js +43 -97
  60. package/dist/commands/completions.js +80 -23
  61. package/dist/commands/config-cli.js +44 -281
  62. package/dist/commands/env/env-binding.js +99 -0
  63. package/dist/commands/env/env-cli.js +84 -224
  64. package/dist/commands/env/env.js +12 -163
  65. package/dist/commands/env/marker-path.js +6 -0
  66. package/dist/commands/env/secret-cli.js +45 -61
  67. package/dist/commands/env/secret.js +32 -62
  68. package/dist/commands/feedback-cli.js +179 -85
  69. package/dist/commands/health/accept-rate.js +58 -0
  70. package/dist/commands/health/advisories.js +7 -8
  71. package/dist/commands/health/checks.js +279 -94
  72. package/dist/commands/health/html-report.js +197 -578
  73. package/dist/commands/health/improve-metrics.js +277 -246
  74. package/dist/commands/health/llm-usage.js +19 -19
  75. package/dist/commands/health/md-report.js +16 -7
  76. package/dist/commands/health/metrics.js +67 -32
  77. package/dist/commands/health/renderers.js +47 -0
  78. package/dist/commands/health/report-view-model.js +508 -0
  79. package/dist/commands/health/stash-exposure.js +1 -1
  80. package/dist/commands/health/surfaces.js +16 -56
  81. package/dist/commands/health/task-runs.js +3 -67
  82. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  83. package/dist/commands/health/types-improve.js +29 -0
  84. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  85. package/dist/commands/health/types-result.js +7 -0
  86. package/dist/commands/health/types-runs.js +4 -0
  87. package/dist/commands/health/types-session-log.js +4 -0
  88. package/dist/commands/health/types-windows.js +4 -0
  89. package/dist/commands/health/types.js +26 -21
  90. package/dist/commands/health/windows.js +2 -3
  91. package/dist/commands/health.js +296 -167
  92. package/dist/commands/improve/anti-collapse.js +5 -5
  93. package/dist/commands/improve/autonomy-gate.js +68 -0
  94. package/dist/commands/improve/collapse-detector.js +65 -52
  95. package/dist/commands/improve/consolidate/chunking.js +9 -7
  96. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  97. package/dist/commands/improve/consolidate/merge.js +4 -0
  98. package/dist/commands/improve/consolidate.js +454 -1354
  99. package/dist/commands/improve/content-hash.js +39 -0
  100. package/dist/commands/improve/distill/content-repair.js +4 -10
  101. package/dist/commands/improve/distill/promote-memory.js +89 -64
  102. package/dist/commands/improve/distill/quality-gate.js +118 -42
  103. package/dist/commands/improve/distill-guards.js +1 -1
  104. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  105. package/dist/commands/improve/distill.js +607 -363
  106. package/dist/commands/improve/eligibility.js +165 -79
  107. package/dist/commands/improve/extract-cli.js +35 -126
  108. package/dist/commands/improve/extract-prompt.js +6 -35
  109. package/dist/commands/improve/extract.js +640 -391
  110. package/dist/commands/improve/feedback-valence.js +2 -12
  111. package/dist/commands/improve/improve-cli.js +134 -135
  112. package/dist/commands/improve/improve-result-file.js +30 -50
  113. package/dist/commands/improve/improve-run-types.js +4 -0
  114. package/dist/commands/improve/improve-strategies.js +135 -0
  115. package/dist/commands/improve/improve.js +904 -701
  116. package/dist/commands/improve/locks.js +64 -111
  117. package/dist/commands/improve/loop-stages.js +1110 -923
  118. package/dist/commands/improve/memory/derived-ref.js +124 -0
  119. package/dist/commands/improve/memory/memory-belief.js +79 -7
  120. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  121. package/dist/commands/improve/memory/memory-improve.js +25 -37
  122. package/dist/commands/improve/outcome-loop.js +25 -88
  123. package/dist/commands/improve/preparation.js +1034 -813
  124. package/dist/commands/improve/proactive-maintenance.js +34 -9
  125. package/dist/commands/improve/proposal-envelope.js +31 -0
  126. package/dist/commands/improve/reflect.js +983 -794
  127. package/dist/commands/improve/run-context.js +119 -0
  128. package/dist/commands/improve/salience.js +24 -127
  129. package/dist/commands/improve/session-asset.js +7 -3
  130. package/dist/commands/improve/shared.js +14 -34
  131. package/dist/commands/improve/source-identity.js +28 -0
  132. package/dist/commands/improve/triage.js +20 -17
  133. package/dist/commands/lint/base-linter.js +340 -313
  134. package/dist/commands/lint/env-key-rules.js +31 -47
  135. package/dist/commands/lint/index.js +185 -30
  136. package/dist/commands/{events.js → log.js} +28 -38
  137. package/dist/commands/migrate-cli.js +54 -0
  138. package/dist/commands/migration-tool.js +55 -0
  139. package/dist/commands/observability-cli.js +70 -208
  140. package/dist/commands/proposal/diff-format.js +50 -0
  141. package/dist/commands/proposal/drain-policies.js +0 -6
  142. package/dist/commands/proposal/drain.js +91 -40
  143. package/dist/commands/proposal/proposal-cli.js +134 -132
  144. package/dist/commands/proposal/proposal-types.js +56 -0
  145. package/dist/commands/proposal/proposal.js +83 -65
  146. package/dist/commands/proposal/propose-cli.js +88 -0
  147. package/dist/commands/proposal/propose.js +105 -88
  148. package/dist/commands/proposal/repository.js +1303 -278
  149. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  150. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  151. package/dist/commands/proposal/validators/proposals.js +6 -8
  152. package/dist/commands/read/curate.js +78 -73
  153. package/dist/commands/read/knowledge.js +510 -13
  154. package/dist/commands/read/registry-search.js +2 -2
  155. package/dist/commands/read/remember-cli.js +84 -15
  156. package/dist/commands/read/search-cli.js +203 -96
  157. package/dist/commands/read/search.js +126 -94
  158. package/dist/commands/read/show.js +226 -250
  159. package/dist/commands/registry-cli.js +34 -60
  160. package/dist/commands/remember.js +18 -57
  161. package/dist/commands/sources/add-cli.js +104 -49
  162. package/dist/commands/sources/bundle-cli.js +166 -0
  163. package/dist/commands/sources/bundle-config-ops.js +63 -0
  164. package/dist/commands/sources/info.js +27 -15
  165. package/dist/commands/sources/init.js +30 -40
  166. package/dist/commands/sources/installed-stashes.js +469 -172
  167. package/dist/commands/sources/migration-help.js +7 -4
  168. package/dist/commands/sources/schema-repair.js +10 -9
  169. package/dist/commands/sources/self-update.js +182 -121
  170. package/dist/commands/sources/source-add.js +169 -178
  171. package/dist/commands/sources/source-clone.js +144 -41
  172. package/dist/commands/sources/source-manage.js +94 -59
  173. package/dist/commands/sources/sources-cli.js +64 -205
  174. package/dist/commands/sources/stash-cli.js +91 -54
  175. package/dist/commands/sources/stash-skeleton.js +1 -1
  176. package/dist/commands/tasks/tasks-cli.js +106 -104
  177. package/dist/commands/tasks/tasks.js +445 -262
  178. package/dist/commands/workflow-cli.js +232 -121
  179. package/dist/core/action-contributors.js +1 -1
  180. package/dist/core/activation-policy.js +49 -0
  181. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  182. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  183. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  184. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  185. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  186. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  187. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  188. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  189. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  190. package/dist/core/adapter/adapters/index.js +80 -0
  191. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  192. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  193. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  194. package/dist/core/adapter/adapters/shared.js +286 -0
  195. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  196. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  197. package/dist/core/adapter/bundle-adapter.js +4 -0
  198. package/dist/core/adapter/detect-adapter.js +17 -0
  199. package/dist/core/adapter/recognize-match.js +44 -0
  200. package/dist/core/adapter/registry.js +56 -0
  201. package/dist/core/adapter/types.js +4 -0
  202. package/dist/core/asset/akm-markdown.js +30 -0
  203. package/dist/core/asset/asset-placement.js +243 -0
  204. package/dist/core/asset/asset-ref.js +110 -79
  205. package/dist/core/asset/asset-serialize.js +20 -0
  206. package/dist/core/asset/frontmatter.js +28 -12
  207. package/dist/core/asset/markdown.js +40 -51
  208. package/dist/core/asset/resolve-ref.js +274 -0
  209. package/dist/core/asset/stash-meta.js +2 -2
  210. package/dist/core/bundle-id.js +51 -0
  211. package/dist/core/common.js +281 -86
  212. package/dist/core/config/config-io.js +42 -128
  213. package/dist/core/config/config-schema.js +233 -834
  214. package/dist/core/config/config-sources.js +162 -39
  215. package/dist/core/config/config-types.js +16 -11
  216. package/dist/core/config/config-version.js +29 -0
  217. package/dist/core/config/config-walker.js +126 -37
  218. package/dist/core/config/config.js +154 -331
  219. package/dist/core/config/deep-merge.js +41 -0
  220. package/dist/core/config/engine-semantics.js +28 -0
  221. package/dist/core/config/experimental.js +21 -0
  222. package/dist/core/config/schema/embedding.js +38 -0
  223. package/dist/core/config/schema/engines.js +116 -0
  224. package/dist/core/config/schema/experimental.js +47 -0
  225. package/dist/core/config/schema/feedback.js +31 -0
  226. package/dist/core/config/schema/improve-processes.js +389 -0
  227. package/dist/core/config/schema/improve.js +94 -0
  228. package/dist/core/config/schema/index-config.js +176 -0
  229. package/dist/core/config/schema/output.js +18 -0
  230. package/dist/core/config/schema/primitives.js +94 -0
  231. package/dist/core/config/schema/search.js +30 -0
  232. package/dist/core/config/schema/setup.js +18 -0
  233. package/dist/core/config/schema/sources-bundles.js +169 -0
  234. package/dist/core/config/schema/workflow.js +29 -0
  235. package/dist/core/env-secret-ref.js +155 -20
  236. package/dist/core/errors.js +17 -15
  237. package/dist/core/events-types.js +4 -0
  238. package/dist/core/events.js +46 -128
  239. package/dist/core/extra-params.js +62 -0
  240. package/dist/core/file-change.js +17 -0
  241. package/dist/core/file-lock.js +202 -57
  242. package/dist/core/fs-txn.js +392 -0
  243. package/dist/core/git-message.js +59 -0
  244. package/dist/core/improve-result.js +167 -0
  245. package/dist/core/json-schema.js +142 -0
  246. package/dist/core/lesson-lint.js +1 -17
  247. package/dist/core/logs-db.js +1 -1
  248. package/dist/core/maintenance-barrier.js +135 -0
  249. package/dist/core/migration-operation.js +44 -0
  250. package/dist/core/mutation-target.js +78 -0
  251. package/dist/core/paths.js +22 -25
  252. package/dist/core/platform.js +10 -0
  253. package/dist/core/recognition-util.js +128 -0
  254. package/dist/core/redaction.js +392 -0
  255. package/dist/core/standards/resolve-standards-context.js +36 -65
  256. package/dist/core/standards/resolve-stash-standards.js +2 -2
  257. package/dist/core/standards/resolve-type-conventions.js +5 -5
  258. package/dist/core/state/migrations.js +242 -11
  259. package/dist/core/state-db.js +98 -10
  260. package/dist/core/structured.js +1 -1
  261. package/dist/core/subprocess.js +303 -0
  262. package/dist/core/text-truncation.js +9 -5
  263. package/dist/core/time.js +20 -0
  264. package/dist/core/type-presentation.js +130 -0
  265. package/dist/core/warn.js +0 -3
  266. package/dist/core/write-source.js +834 -118
  267. package/dist/indexer/bundle-identity-guard.js +92 -0
  268. package/dist/indexer/db/graph-db.js +1 -25
  269. package/dist/indexer/db/llm-cache.js +1 -1
  270. package/dist/indexer/ensure-index.js +30 -9
  271. package/dist/indexer/graph/graph-boost.js +9 -30
  272. package/dist/indexer/graph/graph-extraction.js +41 -27
  273. package/dist/indexer/graph/graph-types.js +4 -0
  274. package/dist/indexer/index-writer-lock.js +93 -49
  275. package/dist/indexer/index-written-assets.js +100 -53
  276. package/dist/indexer/indexer.js +746 -329
  277. package/dist/indexer/init.js +18 -25
  278. package/dist/indexer/installations.js +142 -0
  279. package/dist/indexer/passes/dir-staleness.js +18 -10
  280. package/dist/indexer/passes/memory-inference.js +25 -15
  281. package/dist/indexer/passes/metadata.js +412 -243
  282. package/dist/indexer/scan/doc-to-entry.js +160 -0
  283. package/dist/indexer/scan/drain-dir.js +134 -0
  284. package/dist/indexer/search/db-search.js +292 -108
  285. package/dist/indexer/search/fts-query.js +64 -0
  286. package/dist/indexer/search/ranking-contributors.js +145 -25
  287. package/dist/indexer/search/ranking-types.js +4 -0
  288. package/dist/indexer/search/ranking.js +28 -71
  289. package/dist/indexer/search/search-attribution.js +67 -0
  290. package/dist/indexer/search/search-fields.js +18 -3
  291. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  292. package/dist/indexer/search/search-source.js +157 -111
  293. package/dist/indexer/search/semantic-status.js +4 -1
  294. package/dist/indexer/usage/usage-events.js +10 -30
  295. package/dist/indexer/walk/file-context.js +3 -45
  296. package/dist/indexer/walk/matchers.js +42 -34
  297. package/dist/indexer/walk/path-resolver.js +11 -5
  298. package/dist/indexer/walk/walker.js +42 -14
  299. package/dist/integrations/agent/builder-shared.js +7 -0
  300. package/dist/integrations/agent/builders.js +5 -56
  301. package/dist/integrations/agent/config.js +3 -143
  302. package/dist/integrations/agent/detect.js +17 -2
  303. package/dist/integrations/agent/engine-resolution.js +231 -0
  304. package/dist/integrations/agent/index.js +1 -2
  305. package/dist/integrations/agent/model-aliases.js +16 -2
  306. package/dist/integrations/agent/profiles.js +36 -62
  307. package/dist/integrations/agent/prompts.js +46 -18
  308. package/dist/integrations/agent/runner-dispatch.js +93 -4
  309. package/dist/integrations/agent/runner.js +76 -208
  310. package/dist/integrations/agent/spawn.js +88 -196
  311. package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
  312. package/dist/integrations/harnesses/aider/index.js +48 -0
  313. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  314. package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
  315. package/dist/integrations/harnesses/amazonq/index.js +45 -0
  316. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  317. package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
  318. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  319. package/dist/integrations/harnesses/claude/index.js +24 -35
  320. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  321. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  322. package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
  323. package/dist/integrations/harnesses/codex/index.js +52 -0
  324. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  325. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  326. package/dist/integrations/harnesses/copilot/index.js +48 -0
  327. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  328. package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
  329. package/dist/integrations/harnesses/gemini/index.js +48 -0
  330. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  331. package/dist/integrations/harnesses/ids.js +24 -0
  332. package/dist/integrations/harnesses/index.js +54 -34
  333. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  334. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  335. package/dist/integrations/harnesses/opencode/index.js +14 -32
  336. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  337. package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
  338. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
  339. package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
  340. package/dist/integrations/harnesses/openhands/index.js +48 -0
  341. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  342. package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
  343. package/dist/integrations/harnesses/pi/index.js +45 -0
  344. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  345. package/dist/integrations/harnesses/shared.js +17 -0
  346. package/dist/integrations/harnesses/types.js +43 -32
  347. package/dist/integrations/lockfile.js +211 -24
  348. package/dist/integrations/session-logs/index.js +36 -39
  349. package/dist/integrations/session-logs/provider-base.js +113 -0
  350. package/dist/llm/client.js +182 -110
  351. package/dist/llm/embedders/deterministic.js +2 -2
  352. package/dist/llm/embedders/remote.js +21 -9
  353. package/dist/llm/feature-gate.js +17 -57
  354. package/dist/llm/graph-extract.js +12 -13
  355. package/dist/llm/index-passes.js +8 -42
  356. package/dist/llm/memory-infer.js +144 -1
  357. package/dist/llm/metadata-enhance.js +45 -30
  358. package/dist/llm/structured-call.js +16 -8
  359. package/dist/llm/usage-persist.js +30 -5
  360. package/dist/llm/usage-telemetry.js +59 -6
  361. package/dist/output/cli-hints.js +1 -2
  362. package/dist/output/command-registry.js +27 -0
  363. package/dist/output/context.js +22 -7
  364. package/dist/output/format-exempt.js +80 -0
  365. package/dist/output/generic-render.js +251 -0
  366. package/dist/output/html-render.js +11 -16
  367. package/dist/output/render-registry.js +57 -0
  368. package/dist/output/renderers.js +14 -279
  369. package/dist/output/shapes/curate.js +10 -1
  370. package/dist/output/shapes/events.js +12 -7
  371. package/dist/output/shapes/helpers.js +58 -84
  372. package/dist/output/shapes/passthrough.js +11 -39
  373. package/dist/output/shapes/proposal/producer.js +15 -7
  374. package/dist/output/shapes/registry.js +12 -6
  375. package/dist/output/shapes.js +0 -9
  376. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  377. package/dist/output/text/bundle-show.js +7 -0
  378. package/dist/output/text/command-format.js +562 -0
  379. package/dist/output/text/env.js +1 -3
  380. package/dist/output/text/events.js +8 -7
  381. package/dist/output/text/helpers.js +15 -1164
  382. package/dist/output/text/proposal/producer.js +4 -2
  383. package/dist/output/text/proposal-format.js +202 -0
  384. package/dist/output/text/registry-commands.js +1 -2
  385. package/dist/output/text/registry.js +12 -6
  386. package/dist/output/text/show-directives.js +117 -0
  387. package/dist/output/text/show-format.js +103 -0
  388. package/dist/output/text/sync.js +5 -0
  389. package/dist/output/text/workflow-format.js +332 -0
  390. package/dist/output/text/workflow.js +3 -2
  391. package/dist/output/text.js +10 -19
  392. package/dist/registry/factory.js +4 -6
  393. package/dist/registry/origin-resolve.js +16 -27
  394. package/dist/registry/providers/skills-sh.js +3 -3
  395. package/dist/registry/providers/static-index.js +15 -25
  396. package/dist/registry/resolve.js +43 -94
  397. package/dist/registry/semver.js +43 -0
  398. package/dist/runtime.js +81 -12
  399. package/dist/scripts/akm-migrate.js +35529 -0
  400. package/dist/setup/detect.js +5 -7
  401. package/dist/setup/detected-engines.js +136 -0
  402. package/dist/setup/engine-config.js +100 -0
  403. package/dist/setup/registry-stash-loader.js +3 -3
  404. package/dist/setup/semantic-assets.js +12 -9
  405. package/dist/setup/setup.js +444 -208
  406. package/dist/setup/steps/connection-shared.js +120 -0
  407. package/dist/setup/steps/connection.js +108 -305
  408. package/dist/setup/steps/platforms.js +13 -12
  409. package/dist/setup/steps/semantic.js +15 -3
  410. package/dist/setup/steps/sources.js +21 -15
  411. package/dist/setup/steps/stashdir.js +6 -4
  412. package/dist/setup/steps/tasks.js +236 -119
  413. package/dist/setup/steps.js +3 -2
  414. package/dist/sources/freshness.js +39 -0
  415. package/dist/sources/provider-factory.js +11 -17
  416. package/dist/sources/providers/filesystem.js +2 -3
  417. package/dist/sources/providers/git-install.js +278 -34
  418. package/dist/sources/providers/git-provider.js +54 -56
  419. package/dist/sources/providers/git-stash.js +420 -91
  420. package/dist/sources/providers/git.js +2 -2
  421. package/dist/sources/providers/npm.js +16 -19
  422. package/dist/sources/providers/provider-utils.js +47 -22
  423. package/dist/sources/providers/sync-from-ref.js +3 -9
  424. package/dist/sources/providers/website.js +2 -2
  425. package/dist/sources/resolve.js +11 -10
  426. package/dist/sources/snapshot-fetchers/types.js +4 -0
  427. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  428. package/dist/storage/database.js +60 -4
  429. package/dist/storage/engines/sqlite-migrations.js +156 -5
  430. package/dist/storage/locations.js +1 -2
  431. package/dist/storage/repositories/canaries-repository.js +1 -1
  432. package/dist/storage/repositories/events-repository.js +51 -11
  433. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  434. package/dist/storage/repositories/index-connection.js +79 -0
  435. package/dist/storage/repositories/index-db.js +4 -3
  436. package/dist/storage/repositories/index-entries-repository.js +863 -0
  437. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  438. package/dist/storage/repositories/index-entry-types.js +4 -0
  439. package/dist/storage/repositories/index-fts-repository.js +167 -0
  440. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  441. package/dist/storage/repositories/index-meta-repository.js +49 -0
  442. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  443. package/dist/storage/repositories/index-sql.js +12 -0
  444. package/dist/storage/repositories/index-utility-repository.js +356 -0
  445. package/dist/storage/repositories/index-vec-repository.js +250 -0
  446. package/dist/storage/repositories/outcome-repository.js +119 -0
  447. package/dist/storage/repositories/proposals-repository.js +317 -75
  448. package/dist/storage/repositories/registry-cache.js +1 -1
  449. package/dist/storage/repositories/salience-repository.js +172 -0
  450. package/dist/storage/repositories/task-history-repository.js +110 -3
  451. package/dist/storage/repositories/workflow-runs-repository.js +240 -19
  452. package/dist/tasks/backends/cron.js +169 -46
  453. package/dist/tasks/backends/exec-utils.js +76 -3
  454. package/dist/tasks/backends/index.js +6 -9
  455. package/dist/tasks/backends/launchd.js +292 -55
  456. package/dist/tasks/backends/schtasks.js +557 -70
  457. package/dist/tasks/backends/types.js +4 -0
  458. package/dist/tasks/command-executable.js +93 -0
  459. package/dist/tasks/embedded.js +56 -38
  460. package/dist/tasks/parser.js +156 -64
  461. package/dist/tasks/resolve-akm-bin.js +144 -51
  462. package/dist/tasks/runner.js +377 -209
  463. package/dist/tasks/schedule.js +108 -19
  464. package/dist/tasks/scheduler-invocation.js +296 -0
  465. package/dist/tasks/schema.js +1 -1
  466. package/dist/tasks/task-id.js +35 -0
  467. package/dist/tasks/validator.js +30 -16
  468. package/dist/text-import-hook.mjs +1 -1
  469. package/dist/workflows/authoring/authoring.js +104 -43
  470. package/dist/workflows/authoring/scope-key.js +1 -1
  471. package/dist/workflows/cli.js +0 -16
  472. package/dist/workflows/concurrency-policy.js +15 -0
  473. package/dist/workflows/exec/brief.js +450 -0
  474. package/dist/workflows/exec/frozen-judge.js +47 -0
  475. package/dist/workflows/exec/native-executor.js +1038 -0
  476. package/dist/workflows/exec/param-secrets.js +115 -0
  477. package/dist/workflows/exec/report.js +1460 -0
  478. package/dist/workflows/exec/run-workflow.js +602 -0
  479. package/dist/workflows/exec/scheduler.js +71 -0
  480. package/dist/workflows/exec/step-work.js +1190 -0
  481. package/dist/workflows/exec/unit-writer.js +23 -0
  482. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  483. package/dist/workflows/exec/worktree.js +171 -0
  484. package/dist/workflows/ir/compile.js +246 -0
  485. package/dist/workflows/ir/freeze.js +233 -0
  486. package/dist/workflows/ir/params.js +54 -0
  487. package/dist/workflows/ir/plan-hash.js +68 -0
  488. package/dist/workflows/ir/schema.js +540 -0
  489. package/dist/workflows/parser.js +878 -304
  490. package/dist/workflows/program/expressions.js +181 -0
  491. package/dist/workflows/program/schema.js +51 -0
  492. package/dist/workflows/renderer.js +100 -45
  493. package/dist/workflows/resource-limits.js +22 -0
  494. package/dist/workflows/runtime/agent-identity.js +59 -14
  495. package/dist/workflows/runtime/checkin.js +1 -1
  496. package/dist/workflows/runtime/plan-classifier.js +131 -0
  497. package/dist/workflows/runtime/runs.js +376 -119
  498. package/dist/workflows/runtime/unit-checkin.js +45 -0
  499. package/dist/workflows/runtime/unit-phases.js +20 -0
  500. package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
  501. package/dist/workflows/schema.js +1 -11
  502. package/dist/workflows/validate-summary.js +2 -3
  503. package/dist/workflows/validator.js +52 -30
  504. package/docs/README.md +42 -78
  505. package/docs/migration/README.md +8 -0
  506. package/docs/migration/release-notes/0.6.0.md +1 -1
  507. package/docs/migration/release-notes/0.7.0.md +9 -8
  508. package/docs/migration/release-notes/0.9.0.md +158 -14
  509. package/docs/migration/v0.7-to-v0.8.md +46 -47
  510. package/docs/migration/v0.8-to-v0.9.md +844 -0
  511. package/docs/reference/README.md +12 -0
  512. package/docs/reference/data-and-telemetry.md +333 -0
  513. package/package.json +21 -17
  514. package/schemas/akm-asset-envelope.json +93 -0
  515. package/schemas/akm-config.json +4636 -0
  516. package/schemas/akm-task.json +87 -0
  517. package/schemas/akm-workflow.json +373 -0
  518. package/dist/akm-migrate-storage +0 -38
  519. package/dist/assets/help/help-accept.md +0 -12
  520. package/dist/assets/help/help-improve.md +0 -84
  521. package/dist/assets/help/help-proposals.md +0 -17
  522. package/dist/assets/help/help-propose.md +0 -17
  523. package/dist/assets/help/help-reject.md +0 -11
  524. package/dist/assets/profiles/frequent.json +0 -13
  525. package/dist/assets/profiles/recombine-only.json +0 -21
  526. package/dist/assets/profiles/reflect-distill.json +0 -30
  527. package/dist/assets/profiles/synthesize.json +0 -15
  528. package/dist/assets/prompts/procedural-system.md +0 -44
  529. package/dist/assets/prompts/recombine-system.md +0 -40
  530. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  531. package/dist/assets/tasks/core/backup.yml +0 -4
  532. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  533. package/dist/assets/templates/html/default.html +0 -78
  534. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  535. package/dist/assets/wiki/index-template.md +0 -12
  536. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  537. package/dist/assets/wiki/log-template.md +0 -8
  538. package/dist/assets/wiki/schema-template.md +0 -61
  539. package/dist/cli/config-migrate.js +0 -150
  540. package/dist/cli/config-validate.js +0 -39
  541. package/dist/commands/graph/graph-cli.js +0 -124
  542. package/dist/commands/graph/graph.js +0 -487
  543. package/dist/commands/improve/calibration.js +0 -161
  544. package/dist/commands/improve/dedup.js +0 -482
  545. package/dist/commands/improve/extract-watch.js +0 -140
  546. package/dist/commands/improve/hot-probation.js +0 -45
  547. package/dist/commands/improve/improve-auto-accept.js +0 -276
  548. package/dist/commands/improve/improve-profiles.js +0 -168
  549. package/dist/commands/improve/procedural.js +0 -398
  550. package/dist/commands/improve/recombine.js +0 -818
  551. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  552. package/dist/commands/lint/agent-linter.js +0 -44
  553. package/dist/commands/lint/command-linter.js +0 -44
  554. package/dist/commands/lint/default-linter.js +0 -16
  555. package/dist/commands/lint/fact-linter.js +0 -39
  556. package/dist/commands/lint/knowledge-linter.js +0 -16
  557. package/dist/commands/lint/memory-linter.js +0 -61
  558. package/dist/commands/lint/registry.js +0 -41
  559. package/dist/commands/lint/skill-linter.js +0 -45
  560. package/dist/commands/lint/task-linter.js +0 -50
  561. package/dist/commands/lint/workflow-linter.js +0 -81
  562. package/dist/commands/proposal/legacy-import.js +0 -115
  563. package/dist/commands/sources/history.js +0 -196
  564. package/dist/commands/tasks/default-tasks.js +0 -186
  565. package/dist/commands/wiki-cli.js +0 -292
  566. package/dist/core/asset/asset-registry.js +0 -76
  567. package/dist/core/asset/asset-spec.js +0 -259
  568. package/dist/core/config/config-migration.js +0 -602
  569. package/dist/core/deep-merge.js +0 -38
  570. package/dist/core/eval/rank-metrics.js +0 -113
  571. package/dist/core/ripgrep/install.js +0 -163
  572. package/dist/core/ripgrep/resolve.js +0 -81
  573. package/dist/indexer/db/db.js +0 -1413
  574. package/dist/indexer/manifest.js +0 -170
  575. package/dist/indexer/passes/metadata-contributors.js +0 -31
  576. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  577. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
  578. package/dist/llm/call-ai.js +0 -62
  579. package/dist/llm/memory-infer-impl.js +0 -138
  580. package/dist/output/shapes/distill.js +0 -14
  581. package/dist/output/shapes/history.js +0 -11
  582. package/dist/output/text/distill.js +0 -6
  583. package/dist/output/text/enable-disable.js +0 -8
  584. package/dist/output/text/history.js +0 -6
  585. package/dist/output/text/wiki.js +0 -16
  586. package/dist/registry/build-index.js +0 -386
  587. package/dist/scripts/migrate-storage.js +0 -19108
  588. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
  589. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  590. package/dist/setup/legacy-config.js +0 -106
  591. package/dist/storage/repositories/consolidation-repository.js +0 -38
  592. package/dist/storage/repositories/recombine-repository.js +0 -213
  593. package/dist/wiki/wiki-templates.js +0 -15
  594. package/dist/wiki/wiki.js +0 -1012
  595. package/dist/workflows/db.js +0 -215
  596. package/docs/data-and-telemetry.md +0 -226
  597. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  598. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -2,7 +2,7 @@
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 tasks run <id>` — what cron / launchd / schtasks invoke at the
5
+ * `akm task run <id>` — what cron / launchd / schtasks invoke at the
6
6
  * scheduled moment.
7
7
  *
8
8
  * Responsibilities:
@@ -12,155 +12,187 @@
12
12
  * `tasks sync` time, not here — at run time we still want to attempt
13
13
  * execution and surface the actual failure rather than re-fail on a
14
14
  * validation error that the user already knows about.)
15
- * 3. Refuse to run when `enabled === false` (defense-in-depth).
15
+ * 3. Skip disabled tasks only when the invocation is scheduler-generated;
16
+ * explicit manual runs are allowed for catch-up and testing.
16
17
  * 4. Dispatch by target kind:
17
18
  * • workflow → `startWorkflowRun(ref, params)`
18
- * • prompt → `runAgent(profile, prompt, { stdio: "captured" })`
19
+ * • prompt → `executeRunner(engine, prompt, { stdio: "captured" })`
19
20
  * 5. Capture stdout / stderr as structured rows in logs.db (task_logs) and,
20
21
  * transitionally, as a flat text tail at `<cacheDir>/tasks/logs/<id>/<ts>.log`
21
- * (see docs/technical/logs-audit.md).
22
+ * (per the #579 logs audit).
22
23
  * 6. Write a history row to state.db task_history table.
23
24
  *
24
25
  * Returns a structured result so the CLI handler can shape it for `output()`
25
26
  * and so tests can assert against it without scraping stdout.
26
27
  */
27
28
  import fs from "node:fs";
29
+ import os from "node:os";
28
30
  import path from "node:path";
31
+ import { shouldSkipUnactivatedTask } from "../core/activation-policy.js";
29
32
  import { assertNever } from "../core/assert.js";
30
- import { parseAssetRef } from "../core/asset/asset-ref.js";
31
- import { resolveStashDir } from "../core/common.js";
33
+ import { placementSpecFor } from "../core/asset/asset-placement.js";
34
+ import { parseRefInput } from "../core/asset/resolve-ref.js";
32
35
  import { loadConfig } from "../core/config/config.js";
33
- import { NotFoundError, rethrowIfTestIsolationError } from "../core/errors.js";
36
+ import { AkmError, NotFoundError, rethrowIfTestIsolationError } from "../core/errors.js";
34
37
  import { buildTaskRunId, insertTaskLogLines, openLogsDatabase, } from "../core/logs-db.js";
35
38
  import { getTaskLogDir } from "../core/paths.js";
39
+ import { redactCredentialPatterns } from "../core/redaction.js";
36
40
  import { withStateDb } from "../core/state-db.js";
37
- import { error } from "../core/warn.js";
38
- import { requireAgentProfile, runAgent } from "../integrations/agent/index.js";
39
- import { resolveProcessAgentProfile } from "../integrations/agent/config.js";
40
- import { resolveRunner } from "../integrations/agent/runner.js";
41
- import { spawn } from "../runtime.js";
41
+ import { runManagedSubprocess } from "../core/subprocess.js";
42
+ import { resolveEngine, resolveLlmEngineUse } from "../integrations/agent/engine-resolution.js";
43
+ import { resolveModel } from "../integrations/agent/model-aliases.js";
44
+ import { executeRunner } from "../integrations/agent/runner-dispatch.js";
45
+ import { chatCompletion } from "../llm/client.js";
42
46
  import { resolveAssetPath } from "../sources/resolve.js";
43
- import { getTaskHistory, queryTaskHistory, upsertTaskHistory } from "../storage/repositories/task-history-repository.js";
47
+ import { decodeTaskHistoryMetadata, finalizeTaskHistoryAttempt, getTaskHistory, queryTaskHistory, reserveTaskHistoryAttempt, upsertTaskHistory, } from "../storage/repositories/task-history-repository.js";
44
48
  import { startWorkflowRun } from "../workflows/runtime/runs.js";
49
+ import { findBareAkmExecutableIndex } from "./command-executable.js";
45
50
  import { parseTaskDocument } from "./parser.js";
46
- export async function runTask(id, options = {}) {
47
- const stashDir = options.stashDir ?? resolveStashDir();
48
- const runAgentImpl = options.runAgentImpl ?? runAgent;
51
+ import { resolveAkmInvocation } from "./resolve-akm-bin.js";
52
+ import { validateTaskId } from "./task-id.js";
53
+ export const INVALID_TASK_ATTEMPT_ID = "_invalid-task-id";
54
+ export async function runTask(id, options) {
55
+ const runAgentImpl = options.runAgentImpl;
49
56
  const startWorkflowRunImpl = options.startWorkflowRunImpl ?? startWorkflowRun;
50
57
  const now = options.now ?? (() => new Date());
51
- const logDir = options.logDir ?? getTaskLogDir();
52
- const filePath = await resolveAssetPath(stashDir, "task", id);
53
- const yaml = fs.readFileSync(filePath, "utf8");
54
- const task = parseTaskDocument({ yaml, filePath, id });
55
- const startedAt = now();
56
- const startedIso = startedAt.toISOString();
57
- const tsSlug = startedIso.replace(/[:.]/g, "-");
58
- const taskLogDir = path.join(logDir, id);
59
- fs.mkdirSync(taskLogDir, { recursive: true });
60
- const logPath = path.join(taskLogDir, `${tsSlug}.log`);
61
- if (!task.enabled) {
62
- const finishedAt = now();
63
- const disabledTarget = task.target.kind === "workflow"
64
- ? { kind: "workflow", ref: task.target.ref }
65
- : task.target.kind === "command"
66
- ? { kind: "prompt", profile: undefined }
67
- : { kind: "prompt", profile: task.target.profile };
68
- const result = {
69
- id,
70
- status: "disabled",
71
- startedAt: startedIso,
72
- finishedAt: finishedAt.toISOString(),
73
- durationMs: finishedAt.getTime() - startedAt.getTime(),
74
- log: logPath,
75
- target: disabledTarget,
76
- };
77
- const disabledLine = `[akm tasks] task "${id}" is disabled — skipping run.`;
78
- persistRunLog({
79
- taskId: id,
80
- startedAtIso: startedIso,
81
- finishedAtIso: result.finishedAt,
82
- logPath,
83
- fileText: `${disabledLine}\n`,
84
- dbLines: [{ line: disabledLine }],
58
+ const requestedStartedAt = now();
59
+ try {
60
+ validateTaskId(id);
61
+ }
62
+ catch (failure) {
63
+ const attempt = reserveTaskAttempt(INVALID_TASK_ATTEMPT_ID, requestedStartedAt);
64
+ recordTaskAttemptFailure({
65
+ taskId: INVALID_TASK_ATTEMPT_ID,
66
+ reason: "invalid_task_id",
67
+ failure,
68
+ startedAt: attempt.startedAt,
69
+ finishedAt: now(),
70
+ logDir: options.logDir,
71
+ historyReserved: attempt.historyReserved,
85
72
  });
86
- appendHistory(result);
87
- return result;
73
+ throw failure;
88
74
  }
89
- if (task.target.kind === "workflow") {
90
- return await runWorkflowTask({
75
+ const attempt = reserveTaskAttempt(id, requestedStartedAt);
76
+ const startedAt = attempt.startedAt;
77
+ let failureReason = "task_load_failed";
78
+ try {
79
+ const stashDir = options.stashDir;
80
+ const filePath = await resolveAssetPath(stashDir, "task", id);
81
+ const yaml = fs.readFileSync(filePath, "utf8");
82
+ failureReason = "task_parse_failed";
83
+ const task = parseTaskDocument({ yaml, filePath, id });
84
+ failureReason = "task_dispatch_failed";
85
+ const startedIso = startedAt.toISOString();
86
+ const logPath = resolveTaskLogPath(options.logDir, id, startedIso);
87
+ if (shouldSkipUnactivatedTask({ enabled: task.enabled, scheduled: options.scheduled === true })) {
88
+ const finishedAt = finishAttempt(startedAt, now());
89
+ const disabledTarget = task.target.kind === "workflow"
90
+ ? { kind: "workflow", ref: task.target.ref }
91
+ : task.target.kind === "command"
92
+ ? { kind: "command", cmd: task.target.cmd }
93
+ : { kind: "prompt", engine: task.target.engine ?? null };
94
+ const result = {
95
+ id,
96
+ status: "disabled",
97
+ startedAt: startedIso,
98
+ finishedAt: finishedAt.toISOString(),
99
+ durationMs: finishedAt.getTime() - startedAt.getTime(),
100
+ log: logPath,
101
+ target: disabledTarget,
102
+ };
103
+ const disabledLine = `[akm task] task "${id}" is disabled — skipping run.`;
104
+ persistRunLog({
105
+ taskId: id,
106
+ startedAtIso: startedIso,
107
+ finishedAtIso: result.finishedAt,
108
+ logPath,
109
+ fileText: `${disabledLine}\n`,
110
+ dbLines: [{ line: disabledLine }],
111
+ });
112
+ appendHistory(result, attempt.historyReserved);
113
+ return result;
114
+ }
115
+ if (task.target.kind === "workflow") {
116
+ return await runWorkflowTask({
117
+ task,
118
+ logPath,
119
+ startedAt,
120
+ now,
121
+ startWorkflowRunImpl,
122
+ historyReserved: attempt.historyReserved,
123
+ });
124
+ }
125
+ if (task.target.kind === "command") {
126
+ return await runCommandTask({
127
+ task,
128
+ logPath,
129
+ startedAt,
130
+ now,
131
+ historyReserved: attempt.historyReserved,
132
+ ...(options.spawnFn ? { spawnFn: options.spawnFn } : {}),
133
+ ...(options.setTimeoutFn ? { setTimeoutFn: options.setTimeoutFn } : {}),
134
+ ...(options.clearTimeoutFn ? { clearTimeoutFn: options.clearTimeoutFn } : {}),
135
+ });
136
+ }
137
+ return await runPromptTask({
91
138
  task,
139
+ stashDir,
92
140
  logPath,
93
141
  startedAt,
94
142
  now,
95
- startWorkflowRunImpl,
143
+ runAgentImpl,
144
+ agentOptions: options.agentOptions,
145
+ chatCompletionImpl: options.chatCompletionImpl ?? chatCompletion,
146
+ historyReserved: attempt.historyReserved,
96
147
  });
97
148
  }
98
- if (task.target.kind === "command") {
99
- return await runCommandTask({ task, logPath, startedAt, now });
149
+ catch (failure) {
150
+ recordTaskAttemptFailure({
151
+ taskId: id,
152
+ reason: failureReason,
153
+ failure,
154
+ startedAt,
155
+ finishedAt: now(),
156
+ logDir: options.logDir,
157
+ historyReserved: attempt.historyReserved,
158
+ });
159
+ throw failure;
100
160
  }
101
- // Resolve config once here so runPromptTask does not call loadConfig()
102
- // on every dispatch in a batch run (Fix C6).
103
- const config = loadConfig();
104
- return await runPromptTask({
105
- task,
106
- stashDir,
107
- logPath,
108
- startedAt,
109
- now,
110
- runAgentImpl,
111
- agentOptions: options.agentOptions,
112
- agentConfig: config,
113
- agentTimeoutMs: undefined,
114
- });
115
161
  }
116
162
  // ── command target ──────────────────────────────────────────────────────────
117
163
  async function runCommandTask(input) {
118
- const { task, logPath, startedAt, now } = input;
164
+ const { task, logPath, startedAt, now, historyReserved } = input;
119
165
  if (task.target.kind !== "command")
120
166
  throw new Error("invariant: command target");
121
167
  const { cmd } = task.target;
168
+ const spawnCmd = resolveNestedAkmCommand(cmd);
122
169
  const timeoutMs = task.timeoutMs !== undefined ? task.timeoutMs : null;
123
- const header = `[akm tasks] task=${task.id} kind=command cmd=${cmd.join(" ")}`;
170
+ const header = `[akm task] task=${task.id} kind=command cmd=${cmd.join(" ")}`;
124
171
  const logLines = [header];
125
172
  const dbLines = [{ line: header }];
126
- let stdout = "";
127
- let stderr = "";
128
173
  let exitCode = null;
129
174
  try {
130
- const proc = spawn(cmd, {
131
- stdin: "ignore",
132
- stdout: "pipe",
133
- stderr: "pipe",
134
- cwd: process.env.HOME ?? "/tmp",
175
+ // Managed spawn (src/core/subprocess.ts): process-GROUP kill so a timeout
176
+ // reaps the whole command tree (no orphans), and a SIGTERM→SIGKILL ladder
177
+ // so a child that ignores SIGTERM can't wedge the run forever.
178
+ const result = await runManagedSubprocess(spawnCmd, {
179
+ capture: true,
180
+ cwd: process.env.HOME ?? os.tmpdir(),
135
181
  // Stamp task-runner provenance so any akm invocation in the command tree
136
182
  // records usage events as machine traffic, not user demand (DRIFT-6).
137
183
  // A more specific stamp already in the environment (e.g. improve's
138
184
  // AKM_EVENT_SOURCE=improve on its child spawns) still wins in children.
139
185
  env: { ...process.env, AKM_EVENT_SOURCE: process.env.AKM_EVENT_SOURCE ?? "task" },
186
+ timeoutMs,
187
+ ...(input.spawnFn ? { spawnFn: input.spawnFn } : {}),
188
+ ...(input.setTimeoutFn ? { setTimeoutFn: input.setTimeoutFn } : {}),
189
+ ...(input.clearTimeoutFn ? { clearTimeoutFn: input.clearTimeoutFn } : {}),
140
190
  });
141
- let timer;
142
- let timedOut = false;
143
- if (timeoutMs !== null) {
144
- timer = setTimeout(() => {
145
- timedOut = true;
146
- try {
147
- proc.kill("SIGTERM");
148
- }
149
- catch {
150
- /* ignore */
151
- }
152
- }, timeoutMs);
153
- }
154
- const [stdoutBuf, stderrBuf] = await Promise.all([
155
- new Response(proc.stdout).text(),
156
- new Response(proc.stderr).text(),
157
- ]);
158
- await proc.exited;
159
- if (timer !== undefined)
160
- clearTimeout(timer);
161
- stdout = stdoutBuf;
162
- stderr = stderrBuf;
163
- exitCode = proc.exitCode ?? (timedOut ? 143 : 1);
191
+ // A synchronous spawn throw / exit rejection surfaces as spawn_error below.
192
+ if (result.spawnError)
193
+ throw result.spawnError;
194
+ const { stdout, stderr, timedOut } = result;
195
+ exitCode = result.exitCode ?? (timedOut ? 143 : 1);
164
196
  if (timedOut) {
165
197
  logLines.push(`timed_out=true timeout_ms=${timeoutMs}`);
166
198
  dbLines.push({ level: "error", line: `timed_out=true timeout_ms=${timeoutMs}` });
@@ -184,7 +216,7 @@ async function runCommandTask(input) {
184
216
  dbLines.push({ level: "error", line: `spawn_error=${msg}` });
185
217
  exitCode = 1;
186
218
  }
187
- const finishedAt = now();
219
+ const finishedAt = finishAttempt(startedAt, now());
188
220
  persistRunLog({
189
221
  taskId: task.id,
190
222
  startedAtIso: startedAt.toISOString(),
@@ -201,18 +233,25 @@ async function runCommandTask(input) {
201
233
  finishedAt: finishedAt.toISOString(),
202
234
  durationMs: finishedAt.getTime() - startedAt.getTime(),
203
235
  log: logPath,
204
- target: { kind: "prompt", profile: undefined },
236
+ target: { kind: "command", cmd },
205
237
  detail: { exitCode },
206
238
  };
207
- appendHistory(result);
239
+ appendHistory(result, historyReserved);
208
240
  return result;
209
241
  }
242
+ /** Avoid a second PATH lookup when a task invokes the same AKM installation. */
243
+ function resolveNestedAkmCommand(cmd) {
244
+ const akmIndex = findBareAkmExecutableIndex(cmd);
245
+ if (akmIndex === undefined)
246
+ return cmd;
247
+ return [...cmd.slice(0, akmIndex), ...resolveAkmInvocation().argv, ...cmd.slice(akmIndex + 1)];
248
+ }
210
249
  // ── workflow target ─────────────────────────────────────────────────────────
211
250
  async function runWorkflowTask(input) {
212
- const { task, logPath, startedAt, now, startWorkflowRunImpl } = input;
251
+ const { task, logPath, startedAt, now, startWorkflowRunImpl, historyReserved } = input;
213
252
  if (task.target.kind !== "workflow")
214
253
  throw new Error("invariant: workflow target");
215
- const ref = parseAssetRef(task.target.ref);
254
+ const ref = parseRefInput(task.target.ref);
216
255
  if (ref.type !== "workflow") {
217
256
  throw new NotFoundError(`Task "${task.id}" workflow target must be a workflow ref (got "${task.target.ref}").`, "WORKFLOW_NOT_FOUND");
218
257
  }
@@ -222,9 +261,11 @@ async function runWorkflowTask(input) {
222
261
  detail = await startWorkflowRunImpl(task.target.ref, task.target.params);
223
262
  }
224
263
  catch (e) {
264
+ if (e instanceof AkmError && e.kind === "config")
265
+ throw e;
225
266
  error = e instanceof Error ? e : new Error(String(e));
226
267
  }
227
- const finishedAt = now();
268
+ const finishedAt = finishAttempt(startedAt, now());
228
269
  const status = error ? "failed" : mapWorkflowStatus(detail?.run.status);
229
270
  const log = renderWorkflowLog({ task, detail, error });
230
271
  persistRunLog({
@@ -248,7 +289,7 @@ async function runWorkflowTask(input) {
248
289
  ...(error ? { error: error.message } : {}),
249
290
  },
250
291
  };
251
- appendHistory(result);
292
+ appendHistory(result, historyReserved);
252
293
  // Don't re-throw on workflow failure: the OS scheduler reads exit codes,
253
294
  // not exceptions, and the CLI maps `status: "failed"` to a non-zero exit
254
295
  // via exitCodeForStatus(). Throwing here would route through the generic
@@ -287,7 +328,7 @@ function mapWorkflowStatus(status) {
287
328
  }
288
329
  function renderWorkflowLog(input) {
289
330
  const dbLines = [
290
- { line: `[akm tasks] task=${input.task.id} kind=workflow ref=${input.task.target.ref}` },
331
+ { line: `[akm task] task=${input.task.id} kind=workflow ref=${input.task.target.ref}` },
291
332
  ];
292
333
  if (input.detail) {
293
334
  dbLines.push({ line: `run_id=${input.detail.run.id} status=${input.detail.run.status}` });
@@ -300,70 +341,70 @@ function renderWorkflowLog(input) {
300
341
  }
301
342
  // ── prompt target ───────────────────────────────────────────────────────────
302
343
  async function runPromptTask(input) {
303
- const { task, stashDir, logPath, startedAt, now, runAgentImpl, agentOptions } = input;
344
+ const { task, stashDir, logPath, startedAt, now, agentOptions } = input;
304
345
  if (task.target.kind !== "prompt")
305
346
  throw new Error("invariant: prompt target");
306
- // Use pre-resolved agent config when available to avoid redundant loadConfig()
307
- // calls in batch task runs (Fix C6). Fall back to loadConfig() for callers
308
- // that invoke runPromptTask directly without threading config.
309
- const fullConfig = loadConfig();
310
- const agentCfg = input.agentConfig !== undefined ? input.agentConfig : fullConfig;
311
- // Resolve the profile for this task. When the task doc specifies a profile,
312
- // use it directly. Otherwise fall back to the per-process config for "task"
313
- // (agent.processes["task"]), which itself falls back to agent.default.
314
- let profile;
315
- let processTimeoutMs;
316
- if (task.target.profile) {
317
- // v2: if profiles.agent is configured, resolve through new runner
318
- if (fullConfig.profiles?.agent) {
319
- const mode = task.target.mode ?? "agent";
320
- if (mode !== "llm") {
321
- const runnerSpec = resolveRunner(mode, task.target.profile, fullConfig);
322
- if (runnerSpec.kind === "agent" || runnerSpec.kind === "sdk") {
323
- profile = runnerSpec.profile;
324
- processTimeoutMs = runnerSpec.timeoutMs;
325
- }
326
- else {
327
- profile = requireAgentProfile(agentCfg, task.target.profile);
328
- }
329
- }
330
- else {
331
- profile = requireAgentProfile(agentCfg, task.target.profile);
332
- }
333
- }
334
- else {
335
- // v1: Task doc explicitly names a profile — honour it directly.
336
- profile = requireAgentProfile(agentCfg, task.target.profile);
337
- }
347
+ const promptTarget = task.target;
348
+ const config = loadConfig();
349
+ const engineName = promptTarget.engine ?? config.defaults?.engine;
350
+ if (!engineName)
351
+ throw new NotFoundError(`Task "${task.id}" has no selected engine.`, "ASSET_NOT_FOUND");
352
+ let runner = resolveEngine(engineName, config);
353
+ if (runner.kind === "llm") {
354
+ const resolved = resolveLlmEngineUse(config, [
355
+ {
356
+ engine: engineName,
357
+ ...(promptTarget.model !== undefined ? { model: promptTarget.model } : {}),
358
+ ...(promptTarget.timeoutMs !== undefined ? { timeoutMs: promptTarget.timeoutMs } : {}),
359
+ ...(promptTarget.llm !== undefined ? { llm: promptTarget.llm } : {}),
360
+ },
361
+ ]);
362
+ runner = {
363
+ kind: "llm",
364
+ engine: resolved.engine,
365
+ connection: resolved.connection,
366
+ ...(resolved.credential ? { credential: resolved.credential } : {}),
367
+ timeoutMs: resolved.timeoutMs,
368
+ };
338
369
  }
339
370
  else {
340
- // No per-task profile: use process config for "task" as a fallback.
341
- const resolved = resolveProcessAgentProfile("task", agentCfg);
342
- profile = resolved.profile;
343
- processTimeoutMs = resolved.timeoutMs;
371
+ if (promptTarget.llm !== undefined) {
372
+ throw new NotFoundError(`Task "${task.id}" uses llm overrides with non-LLM engine "${engineName}".`, "ASSET_NOT_FOUND");
373
+ }
374
+ const requestedModel = promptTarget.model;
375
+ const platform = runner.profile.platform;
376
+ if (!platform)
377
+ throw new Error(`Engine "${engineName}" resolved without a platform.`);
378
+ const model = requestedModel
379
+ ? resolveModel(requestedModel, platform, runner.profile.modelAliases, runner.profile.globalModelAliases)
380
+ : runner.profile.model;
381
+ runner = {
382
+ ...runner,
383
+ profile: { ...runner.profile, ...(model ? { model, modelIsExact: true } : {}) },
384
+ ...(promptTarget.timeoutMs !== undefined ? { timeoutMs: promptTarget.timeoutMs } : {}),
385
+ };
344
386
  }
345
- // Task-level timeoutMs (including null = disabled) wins over global config.
346
- // Resolution: task.timeoutMs → process entry timeoutMs → input.agentTimeoutMs → agentCfg.timeoutMs.
347
- const agentTimeoutMs = task.timeoutMs !== undefined
348
- ? task.timeoutMs
349
- : processTimeoutMs !== undefined
350
- ? processTimeoutMs
351
- : input.agentTimeoutMs !== undefined
352
- ? input.agentTimeoutMs
353
- : undefined;
354
387
  const promptText = await resolvePromptText(task, stashDir);
355
- const result = await runAgentImpl(profile, promptText, {
388
+ const result = await executeRunner(runner, promptText, {
356
389
  stdio: "captured",
357
- timeoutMs: agentTimeoutMs,
358
390
  cwd: stashDir,
359
391
  ...agentOptions,
360
392
  // Stamp task-runner provenance for any akm invocation the agent makes
361
393
  // (DRIFT-6: agent-task traffic must not be recorded as user demand).
362
394
  // Caller-supplied env still wins on conflicts.
363
395
  env: { AKM_EVENT_SOURCE: "task", ...agentOptions?.env },
396
+ }, {
397
+ ...(input.runAgentImpl ? { runAgent: input.runAgentImpl } : {}),
398
+ llm: async (spec, prompt, options) => {
399
+ const started = Date.now();
400
+ const stdout = await input.chatCompletionImpl(spec.connection, [{ role: "user", content: prompt }], {
401
+ ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
402
+ });
403
+ return { ok: true, exitCode: 0, stdout, stderr: "", durationMs: Date.now() - started };
404
+ },
364
405
  });
365
- const finishedAt = now();
366
- const log = renderPromptLog({ task, profileName: profile.name, result });
406
+ const finishedAt = finishAttempt(startedAt, now());
407
+ const log = renderPromptLog({ task, engineName, result });
367
408
  persistRunLog({
368
409
  taskId: task.id,
369
410
  startedAtIso: startedAt.toISOString(),
@@ -380,12 +421,12 @@ async function runPromptTask(input) {
380
421
  finishedAt: finishedAt.toISOString(),
381
422
  durationMs: finishedAt.getTime() - startedAt.getTime(),
382
423
  log: logPath,
383
- target: { kind: "prompt", profile: profile.name },
424
+ target: { kind: "prompt", engine: engineName },
384
425
  detail: result.ok
385
426
  ? { exitCode: result.exitCode }
386
427
  : { reason: result.reason, error: result.error, exitCode: result.exitCode },
387
428
  };
388
- appendHistory(out);
429
+ appendHistory(out, input.historyReserved);
389
430
  return out;
390
431
  }
391
432
  async function resolvePromptText(task, stashDir) {
@@ -403,14 +444,20 @@ async function resolvePromptText(task, stashDir) {
403
444
  return fs.readFileSync(filePath, "utf8");
404
445
  }
405
446
  // asset
406
- const ref = parseAssetRef(src.ref);
447
+ const ref = parseRefInput(src.ref);
448
+ // D11 — see the matching guard in validator.ts: `resolveAssetPath`
449
+ // (src/sources/resolve.ts) is placement-dir-only and cannot route an
450
+ // opaque adapter conceptId, which `parseRefInput` now otherwise accepts.
451
+ if (placementSpecFor(ref.type) === undefined) {
452
+ throw new NotFoundError(`Task "${task.id}" prompt asset ref "${src.ref}" is not an AKM-placed asset — adapter-owned (opaque) prompt sources are not resolvable as task inputs yet.`, "ASSET_NOT_FOUND");
453
+ }
407
454
  const assetPath = await resolveAssetPath(stashDir, ref.type, ref.name);
408
455
  return fs.readFileSync(assetPath, "utf8");
409
456
  }
410
457
  function renderPromptLog(input) {
411
458
  const lines = [];
412
459
  const dbLines = [];
413
- const header = `[akm tasks] task=${input.task.id} kind=prompt profile=${input.profileName}`;
460
+ const header = `[akm task] task=${input.task.id} kind=prompt engine=${input.engineName}`;
414
461
  const summary = `ok=${input.result.ok} exit_code=${input.result.exitCode ?? "null"} duration_ms=${input.result.durationMs}`;
415
462
  lines.push(header, summary);
416
463
  dbLines.push({ line: header }, { level: input.result.ok ? "info" : "error", line: summary });
@@ -431,6 +478,19 @@ function renderPromptLog(input) {
431
478
  }
432
479
  return { fileText: `${lines.join("\n")}\n`, dbLines };
433
480
  }
481
+ function taskLogPath(logDir, taskId, startedAtIso) {
482
+ const tsSlug = startedAtIso.replace(/[:.]/g, "-");
483
+ return path.join(logDir, taskId, `${tsSlug}.log`);
484
+ }
485
+ function resolveTaskLogPath(logDir, taskId, startedAtIso) {
486
+ try {
487
+ return taskLogPath(logDir ?? getTaskLogDir(), taskId, startedAtIso);
488
+ }
489
+ catch (error) {
490
+ rethrowIfTestIsolationError(error);
491
+ return "";
492
+ }
493
+ }
434
494
  /** Split captured pipe output into per-line logs.db rows (blank lines dropped). */
435
495
  function streamLines(text, stream, level) {
436
496
  return text
@@ -443,11 +503,27 @@ function streamLines(text, stream, level) {
443
503
  * task_history keeps resolving for humans and older consumers) plus
444
504
  * structured rows in logs.db keyed by `buildTaskRunId(taskId, startedAt)`.
445
505
  *
506
+ * Both sinks are pattern-redacted (`redactCredentialPatterns`) before being
507
+ * written — task output is raw command/agent/LLM text that can echo a
508
+ * credential-bearing URL (e.g. a Discord webhook) nothing upstream expects to
509
+ * scrub.
510
+ *
446
511
  * The DB write is best-effort, mirroring {@link appendHistory}: an unwritable
447
512
  * logs.db must never fail a task run.
448
513
  */
449
514
  function persistRunLog(input) {
450
- fs.writeFileSync(input.logPath, input.fileText);
515
+ const fileText = redactCredentialPatterns(input.fileText);
516
+ const dbLines = input.dbLines.map((entry) => ({ ...entry, line: redactCredentialPatterns(entry.line) }));
517
+ if (input.logPath) {
518
+ try {
519
+ fs.mkdirSync(path.dirname(input.logPath), { recursive: true });
520
+ fs.writeFileSync(input.logPath, fileText);
521
+ }
522
+ catch (error) {
523
+ rethrowIfTestIsolationError(error);
524
+ // Transitional file logging is fully best-effort.
525
+ }
526
+ }
451
527
  try {
452
528
  const db = openLogsDatabase();
453
529
  try {
@@ -455,59 +531,147 @@ function persistRunLog(input) {
455
531
  taskId: input.taskId,
456
532
  runId: buildTaskRunId(input.taskId, input.startedAtIso),
457
533
  ts: input.finishedAtIso,
458
- lines: input.dbLines,
534
+ lines: dbLines,
459
535
  });
460
536
  }
461
537
  finally {
462
538
  db.close();
463
539
  }
464
540
  }
465
- catch (err) {
466
- rethrowIfTestIsolationError(err);
467
- error(`[akm] task log DB write failed: ${String(err)}`);
541
+ catch (error) {
542
+ rethrowIfTestIsolationError(error);
543
+ // Structured logging is fully best-effort and must not alter CLI output.
544
+ }
545
+ }
546
+ /** Reserve a collision-free identity through state.db's existing unique index. */
547
+ function reserveTaskAttempt(taskId, requestedStartedAt) {
548
+ try {
549
+ return withStateDb((db) => {
550
+ for (let offsetMs = 0;; offsetMs++) {
551
+ const startedAt = new Date(requestedStartedAt.getTime() + offsetMs);
552
+ const reserved = reserveTaskHistoryAttempt(db, {
553
+ task_id: taskId,
554
+ status: "active",
555
+ started_at: startedAt.toISOString(),
556
+ completed_at: null,
557
+ failed_at: null,
558
+ log_path: null,
559
+ target_kind: null,
560
+ target_ref: null,
561
+ metadata_json: JSON.stringify({ metadataVersion: 2, durationMs: 0, detail: null }),
562
+ });
563
+ if (reserved)
564
+ return { startedAt, historyReserved: true };
565
+ }
566
+ });
567
+ }
568
+ catch (error) {
569
+ rethrowIfTestIsolationError(error);
570
+ // Attempt recording cannot prevent or replace task execution.
571
+ return { startedAt: requestedStartedAt, historyReserved: false };
468
572
  }
469
573
  }
574
+ function finishAttempt(startedAt, observedFinishedAt) {
575
+ return observedFinishedAt.getTime() < startedAt.getTime() ? new Date(startedAt) : observedFinishedAt;
576
+ }
577
+ const SAFE_TASK_ATTEMPT_ERROR_CODES = new Set([
578
+ "CONFIG_DIR_UNRESOLVABLE",
579
+ "STASH_DIR_NOT_FOUND",
580
+ "STASH_DIR_NOT_A_DIRECTORY",
581
+ "STASH_DIR_UNREADABLE",
582
+ "LLM_NOT_CONFIGURED",
583
+ "INVALID_CONFIG_FILE",
584
+ "UNSUPPORTED_CONFIG_VERSION",
585
+ "TEST_ISOLATION_MISSING",
586
+ "INVALID_FLAG_VALUE",
587
+ "MISSING_REQUIRED_ARGUMENT",
588
+ "PATH_ESCAPE_VIOLATION",
589
+ "TASK_SCHEMA_VERSION_UNSUPPORTED",
590
+ "ASSET_NOT_FOUND",
591
+ "WORKFLOW_NOT_FOUND",
592
+ "FILE_NOT_FOUND",
593
+ ]);
594
+ function safeTaskAttemptErrorCode(failure) {
595
+ if (failure instanceof AkmError && SAFE_TASK_ATTEMPT_ERROR_CODES.has(failure.code))
596
+ return failure.code;
597
+ return "INTERNAL";
598
+ }
599
+ export function recordTaskAttemptFailure(input) {
600
+ let taskId = input.taskId;
601
+ try {
602
+ validateTaskId(taskId);
603
+ }
604
+ catch {
605
+ taskId = INVALID_TASK_ATTEMPT_ID;
606
+ }
607
+ const attempt = input.historyReserved === undefined
608
+ ? reserveTaskAttempt(taskId, input.startedAt)
609
+ : { startedAt: input.startedAt, historyReserved: input.historyReserved };
610
+ const finishedAt = finishAttempt(attempt.startedAt, input.finishedAt ?? new Date());
611
+ const startedAtIso = attempt.startedAt.toISOString();
612
+ const finishedAtIso = finishedAt.toISOString();
613
+ const errorCode = safeTaskAttemptErrorCode(input.failure);
614
+ const logPath = resolveTaskLogPath(input.logDir, taskId, startedAtIso);
615
+ const line = `[akm task] status=failed reason=${input.reason} code=${errorCode}`;
616
+ const result = {
617
+ id: taskId,
618
+ status: "failed",
619
+ startedAt: startedAtIso,
620
+ finishedAt: finishedAtIso,
621
+ durationMs: Math.max(0, finishedAt.getTime() - attempt.startedAt.getTime()),
622
+ log: logPath,
623
+ target: { kind: "unknown" },
624
+ detail: { reason: input.reason, error: errorCode },
625
+ };
626
+ persistRunLog({
627
+ taskId,
628
+ startedAtIso,
629
+ finishedAtIso,
630
+ logPath,
631
+ fileText: `${line}\n`,
632
+ dbLines: [{ level: "error", line }],
633
+ });
634
+ appendHistory(result, attempt.historyReserved);
635
+ }
470
636
  // ── history ─────────────────────────────────────────────────────────────────
471
- function appendHistory(result) {
637
+ function appendHistory(result, historyReserved = false) {
638
+ const row = {
639
+ task_id: result.id,
640
+ status: result.status,
641
+ started_at: result.startedAt,
642
+ completed_at: result.finishedAt,
643
+ failed_at: result.status === "failed" ? result.finishedAt : null,
644
+ log_path: result.log || null,
645
+ target_kind: result.target.kind === "unknown" ? null : result.target.kind,
646
+ target_ref: result.target.kind === "workflow" ? result.target.ref : null,
647
+ metadata_json: JSON.stringify({
648
+ metadataVersion: 2,
649
+ durationMs: result.durationMs,
650
+ detail: result.detail ?? null,
651
+ ...(result.target.kind === "prompt" ? { engine: result.target.engine } : {}),
652
+ }),
653
+ };
472
654
  try {
473
655
  withStateDb((db) => {
474
- upsertTaskHistory(db, {
475
- task_id: result.id,
476
- status: result.status,
477
- started_at: result.startedAt,
478
- completed_at: result.finishedAt,
479
- failed_at: result.status === "failed" ? result.finishedAt : null,
480
- log_path: result.log,
481
- target_kind: result.target.kind,
482
- target_ref: result.target.kind === "workflow" ? result.target.ref : null,
483
- metadata_json: JSON.stringify({
484
- durationMs: result.durationMs,
485
- detail: result.detail ?? null,
486
- profile: result.target.kind === "prompt" ? result.target.profile : undefined,
487
- }),
488
- });
656
+ if (historyReserved && finalizeTaskHistoryAttempt(db, row))
657
+ return;
658
+ upsertTaskHistory(db, row);
489
659
  });
490
660
  }
491
- catch (err) {
492
- rethrowIfTestIsolationError(err);
493
- error(`[akm] task history DB write failed: ${String(err)}`);
661
+ catch (error) {
662
+ rethrowIfTestIsolationError(error);
663
+ // History recording is fully best-effort and must not alter CLI output.
494
664
  }
495
665
  }
496
666
  export function readTaskHistory(options = {}) {
497
667
  return withStateDb((db) => {
498
- let rows;
668
+ if (options.limit === 0)
669
+ return [];
499
670
  if (options.id) {
500
671
  const row = getTaskHistory(db, options.id);
501
- rows = row ? [taskHistoryRowToResult(row)] : [];
502
- }
503
- else {
504
- rows = queryTaskHistory(db, {}).map(taskHistoryRowToResult);
505
- }
506
- rows.sort((a, b) => (a.startedAt < b.startedAt ? 1 : -1));
507
- if (options.limit !== undefined && options.limit >= 0) {
508
- return rows.slice(0, options.limit);
672
+ return row ? [taskHistoryRowToResult(row)] : [];
509
673
  }
510
- return rows;
674
+ return queryTaskHistory(db, options.limit !== undefined && options.limit > 0 ? { limit: options.limit } : {}).map(taskHistoryRowToResult);
511
675
  });
512
676
  }
513
677
  /**
@@ -515,25 +679,29 @@ export function readTaskHistory(options = {}) {
515
679
  * that callers of `readTaskHistory()` expect.
516
680
  */
517
681
  function taskHistoryRowToResult(row) {
518
- let meta = {};
519
- try {
520
- meta = JSON.parse(row.metadata_json);
521
- }
522
- catch {
523
- // ignore corrupt JSON
524
- }
682
+ const meta = decodeTaskHistoryMetadata(row.metadata_json);
525
683
  const target = row.target_kind === "workflow"
526
684
  ? { kind: "workflow", ref: row.target_ref ?? "" }
527
- : { kind: "prompt", profile: meta.profile };
685
+ : row.target_kind === "command"
686
+ ? { kind: "command" }
687
+ : row.target_kind === "prompt"
688
+ ? meta.metadataVersion === 1
689
+ ? {
690
+ kind: "prompt",
691
+ engine: null,
692
+ ...(meta.legacyProfile !== undefined ? { legacyProfile: meta.legacyProfile } : {}),
693
+ }
694
+ : { kind: "prompt", engine: meta.engine ?? null }
695
+ : { kind: "unknown" };
528
696
  return {
529
697
  id: row.task_id,
530
698
  status: row.status,
531
699
  startedAt: row.started_at,
532
700
  finishedAt: row.completed_at ?? row.failed_at ?? row.started_at,
533
- durationMs: meta.durationMs ?? 0,
701
+ durationMs: meta.durationMs,
534
702
  log: row.log_path ?? "",
535
703
  target,
536
- ...(meta.detail !== undefined ? { detail: meta.detail } : {}),
704
+ ...(meta.detail ? { detail: meta.detail } : {}),
537
705
  };
538
706
  }
539
707
  /**