akm-cli 0.9.0-beta.9 → 0.9.0-rc.1

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 (381) hide show
  1. package/CHANGELOG.md +715 -0
  2. package/README.md +12 -4
  3. package/dist/akm +38 -0
  4. package/dist/akm-migrate-storage +38 -0
  5. package/dist/assets/help/help-improve.md +9 -6
  6. package/dist/assets/hints/cli-hints-full.md +6 -5
  7. package/dist/assets/profiles/default.json +9 -4
  8. package/dist/assets/profiles/frequent.json +1 -1
  9. package/dist/assets/profiles/memory-focus.json +1 -1
  10. package/dist/assets/profiles/proactive-maintenance.json +25 -0
  11. package/dist/assets/profiles/quick.json +1 -1
  12. package/dist/assets/profiles/recombine-only.json +21 -0
  13. package/dist/assets/profiles/reflect-distill.json +30 -0
  14. package/dist/assets/profiles/synthesize.json +15 -0
  15. package/dist/assets/profiles/thorough.json +1 -1
  16. package/dist/assets/prompts/consolidate-system.md +23 -0
  17. package/dist/assets/prompts/contradiction-judge.md +33 -0
  18. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  19. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  20. package/dist/assets/prompts/extract-session.md +11 -3
  21. package/dist/assets/prompts/graph-extract-system.md +1 -0
  22. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  23. package/dist/assets/prompts/memory-infer-system.md +1 -0
  24. package/dist/assets/prompts/memory-infer-user.md +5 -0
  25. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  26. package/dist/assets/prompts/procedural-system.md +44 -0
  27. package/dist/assets/prompts/recombine-system.md +40 -0
  28. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  29. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  30. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  39. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  40. package/dist/assets/templates/html/health.html +281 -111
  41. package/dist/assets/wiki/ingest-workflow-template.md +45 -16
  42. package/dist/assets/wiki/schema-template.md +4 -4
  43. package/dist/cli/clack.js +56 -0
  44. package/dist/cli/config-migrate.js +7 -1
  45. package/dist/cli/confirm.js +1 -1
  46. package/dist/cli/parse-args.js +46 -1
  47. package/dist/cli/shared.js +28 -0
  48. package/dist/cli.js +25 -21
  49. package/dist/commands/agent/agent-dispatch.js +3 -2
  50. package/dist/commands/agent/agent-support.js +0 -7
  51. package/dist/commands/agent/contribute-cli.js +26 -7
  52. package/dist/commands/config-cli.js +26 -13
  53. package/dist/commands/env/child-env.js +47 -0
  54. package/dist/commands/env/env-binding.js +95 -0
  55. package/dist/commands/env/env-cli.js +228 -292
  56. package/dist/commands/env/env.js +14 -67
  57. package/dist/commands/env/secret-cli.js +140 -138
  58. package/dist/commands/feedback-cli.js +156 -155
  59. package/dist/commands/graph/graph-cli.js +5 -13
  60. package/dist/commands/graph/graph.js +3 -3
  61. package/dist/commands/health/advisories.js +151 -0
  62. package/dist/commands/health/checks.js +103 -16
  63. package/dist/commands/health/html-report.js +447 -81
  64. package/dist/commands/health/improve-metrics.js +771 -0
  65. package/dist/commands/health/llm-usage.js +65 -0
  66. package/dist/commands/health/md-report.js +103 -0
  67. package/dist/commands/health/metrics.js +278 -0
  68. package/dist/commands/health/stash-exposure.js +46 -0
  69. package/dist/commands/health/surfaces.js +216 -0
  70. package/dist/commands/health/task-runs.js +135 -0
  71. package/dist/commands/health/types.js +26 -0
  72. package/dist/commands/health/windows.js +195 -0
  73. package/dist/commands/health.js +91 -1091
  74. package/dist/commands/improve/anti-collapse.js +170 -0
  75. package/dist/commands/improve/calibration.js +161 -0
  76. package/dist/commands/improve/collapse-detector.js +421 -0
  77. package/dist/commands/improve/consolidate/chunking.js +141 -0
  78. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  79. package/dist/commands/improve/consolidate/merge.js +145 -0
  80. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  81. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  82. package/dist/commands/improve/consolidate.js +1295 -1277
  83. package/dist/commands/improve/dedup.js +482 -0
  84. package/dist/commands/improve/distill/content-repair.js +202 -0
  85. package/dist/commands/improve/distill/promote-memory.js +229 -0
  86. package/dist/commands/improve/distill/quality-gate.js +236 -0
  87. package/dist/commands/improve/distill-guards.js +127 -0
  88. package/dist/commands/improve/distill-promotion-policy.js +826 -167
  89. package/dist/commands/improve/distill.js +228 -605
  90. package/dist/commands/improve/eligibility.js +434 -0
  91. package/dist/commands/improve/encoding-salience.js +205 -0
  92. package/dist/commands/improve/extract-cli.js +179 -59
  93. package/dist/commands/improve/extract-prompt.js +54 -3
  94. package/dist/commands/improve/extract-watch.js +140 -0
  95. package/dist/commands/improve/extract.js +409 -43
  96. package/dist/commands/improve/feedback-valence.js +54 -0
  97. package/dist/commands/improve/hot-probation.js +45 -0
  98. package/dist/commands/improve/improve-auto-accept.js +157 -10
  99. package/dist/commands/improve/improve-cli.js +115 -73
  100. package/dist/commands/improve/improve-profiles.js +28 -8
  101. package/dist/commands/improve/improve-result-file.js +15 -25
  102. package/dist/commands/improve/improve-session.js +58 -0
  103. package/dist/commands/improve/improve.js +485 -2764
  104. package/dist/commands/improve/locks.js +154 -0
  105. package/dist/commands/improve/loop-stages.js +1100 -0
  106. package/dist/commands/improve/memory/memory-belief.js +14 -15
  107. package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
  108. package/dist/commands/improve/memory/memory-improve.js +27 -27
  109. package/dist/commands/improve/outcome-loop.js +270 -0
  110. package/dist/commands/improve/preparation.js +2002 -0
  111. package/dist/commands/improve/proactive-maintenance.js +37 -35
  112. package/dist/commands/improve/procedural.js +398 -0
  113. package/dist/commands/improve/recombine.js +818 -0
  114. package/dist/commands/improve/reflect-noise.js +0 -0
  115. package/dist/commands/improve/reflect.js +206 -45
  116. package/dist/commands/improve/salience.js +455 -0
  117. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  118. package/dist/commands/improve/shared.js +51 -0
  119. package/dist/commands/improve/triage.js +93 -0
  120. package/dist/commands/lint/agent-linter.js +19 -24
  121. package/dist/commands/lint/base-linter.js +173 -60
  122. package/dist/commands/lint/command-linter.js +19 -24
  123. package/dist/commands/lint/env-key-rules.js +38 -1
  124. package/dist/commands/lint/fact-linter.js +39 -0
  125. package/dist/commands/lint/index.js +31 -13
  126. package/dist/commands/lint/memory-linter.js +1 -1
  127. package/dist/commands/lint/registry.js +7 -2
  128. package/dist/commands/lint/task-linter.js +3 -3
  129. package/dist/commands/lint/workflow-linter.js +26 -1
  130. package/dist/commands/observability-cli.js +4 -4
  131. package/dist/commands/proposal/drain-policies.js +13 -4
  132. package/dist/commands/proposal/drain.js +45 -51
  133. package/dist/commands/proposal/legacy-import.js +115 -0
  134. package/dist/commands/proposal/proposal-cli.js +24 -34
  135. package/dist/commands/proposal/proposal.js +2 -1
  136. package/dist/commands/proposal/propose.js +8 -3
  137. package/dist/commands/proposal/repository.js +829 -0
  138. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  139. package/dist/commands/proposal/validators/proposals.js +93 -895
  140. package/dist/commands/read/curate.js +410 -111
  141. package/dist/commands/read/knowledge.js +10 -3
  142. package/dist/commands/read/remember-cli.js +133 -138
  143. package/dist/commands/read/search-cli.js +15 -8
  144. package/dist/commands/read/search.js +22 -11
  145. package/dist/commands/read/show.js +106 -14
  146. package/dist/commands/registry-cli.js +76 -87
  147. package/dist/commands/remember.js +11 -12
  148. package/dist/commands/sources/add-cli.js +91 -95
  149. package/dist/commands/sources/history.js +1 -1
  150. package/dist/commands/sources/init.js +66 -18
  151. package/dist/commands/sources/installed-stashes.js +11 -3
  152. package/dist/commands/sources/migration-help.js +7 -4
  153. package/dist/commands/sources/schema-repair.js +44 -46
  154. package/dist/commands/sources/self-update.js +2 -2
  155. package/dist/commands/sources/source-add.js +7 -3
  156. package/dist/commands/sources/sources-cli.js +3 -3
  157. package/dist/commands/sources/stash-cli.js +19 -39
  158. package/dist/commands/sources/stash-skeleton.js +57 -8
  159. package/dist/commands/tasks/default-tasks.js +15 -2
  160. package/dist/commands/tasks/tasks-cli.js +20 -29
  161. package/dist/commands/tasks/tasks.js +39 -11
  162. package/dist/commands/wiki-cli.js +23 -38
  163. package/dist/commands/workflow-cli.js +291 -13
  164. package/dist/core/asset/asset-registry.js +3 -1
  165. package/dist/core/asset/asset-spec.js +79 -5
  166. package/dist/core/asset/frontmatter.js +188 -167
  167. package/dist/core/asset/markdown.js +8 -0
  168. package/dist/core/authoring-rules.js +92 -0
  169. package/dist/core/common.js +4 -23
  170. package/dist/core/concurrent.js +10 -1
  171. package/dist/core/config/config-io.js +10 -1
  172. package/dist/core/config/config-migration.js +18 -40
  173. package/dist/core/config/config-schema.js +403 -62
  174. package/dist/core/config/config-types.js +3 -3
  175. package/dist/core/config/config.js +67 -22
  176. package/dist/core/deep-merge.js +38 -0
  177. package/dist/core/errors.js +1 -0
  178. package/dist/core/eval/rank-metrics.js +113 -0
  179. package/dist/core/events.js +4 -7
  180. package/dist/core/improve-types.js +47 -8
  181. package/dist/core/json-schema.js +142 -0
  182. package/dist/core/logs-db.js +14 -75
  183. package/dist/core/parse.js +36 -16
  184. package/dist/core/paths.js +18 -18
  185. package/dist/core/standards/resolve-standards-context.js +87 -0
  186. package/dist/core/standards/resolve-stash-standards.js +99 -0
  187. package/dist/core/standards/resolve-type-conventions.js +66 -0
  188. package/dist/core/state/migrations.js +770 -0
  189. package/dist/core/state-db.js +132 -1126
  190. package/dist/core/structured.js +69 -0
  191. package/dist/core/time.js +53 -0
  192. package/dist/core/warn.js +21 -0
  193. package/dist/core/write-source.js +37 -0
  194. package/dist/indexer/db/db.js +261 -770
  195. package/dist/indexer/db/entry-mapper.js +41 -0
  196. package/dist/indexer/db/graph-db.js +129 -86
  197. package/dist/indexer/db/llm-cache.js +2 -2
  198. package/dist/indexer/db/schema.js +516 -0
  199. package/dist/indexer/ensure-index.js +36 -92
  200. package/dist/indexer/feedback/utility-policy.js +75 -0
  201. package/dist/indexer/graph/graph-boost.js +51 -41
  202. package/dist/indexer/graph/graph-extraction.js +207 -4
  203. package/dist/indexer/index-writer-lock.js +18 -11
  204. package/dist/indexer/index-written-assets.js +105 -0
  205. package/dist/indexer/indexer.js +182 -204
  206. package/dist/indexer/passes/dir-staleness.js +114 -0
  207. package/dist/indexer/passes/memory-inference.js +13 -5
  208. package/dist/indexer/passes/metadata.js +20 -0
  209. package/dist/indexer/read-preflight.js +23 -0
  210. package/dist/indexer/search/db-search.js +89 -13
  211. package/dist/indexer/search/fts-query.js +51 -0
  212. package/dist/indexer/search/ranking-contributors.js +95 -9
  213. package/dist/indexer/search/ranking.js +79 -3
  214. package/dist/indexer/search/search-fields.js +6 -0
  215. package/dist/indexer/search/search-source.js +32 -21
  216. package/dist/indexer/search/semantic-status.js +4 -0
  217. package/dist/indexer/walk/matchers.js +48 -0
  218. package/dist/indexer/walk/walker.js +21 -13
  219. package/dist/integrations/agent/builders.js +41 -13
  220. package/dist/integrations/agent/config.js +20 -59
  221. package/dist/integrations/agent/detect.js +9 -0
  222. package/dist/integrations/agent/index.js +3 -19
  223. package/dist/integrations/agent/model-aliases.js +16 -2
  224. package/dist/integrations/agent/profiles.js +79 -6
  225. package/dist/integrations/agent/prompts.js +75 -9
  226. package/dist/integrations/agent/runner-dispatch.js +83 -0
  227. package/dist/integrations/agent/runner.js +13 -9
  228. package/dist/integrations/agent/spawn.js +206 -81
  229. package/dist/integrations/harnesses/aider/agent-builder.js +113 -0
  230. package/dist/integrations/harnesses/aider/index.js +58 -0
  231. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  232. package/dist/integrations/harnesses/amazonq/agent-builder.js +153 -0
  233. package/dist/integrations/harnesses/amazonq/index.js +59 -0
  234. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  235. package/dist/integrations/harnesses/claude/agent-builder.js +46 -7
  236. package/dist/integrations/harnesses/claude/index.js +27 -23
  237. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  238. package/dist/integrations/harnesses/claude/session-log.js +10 -0
  239. package/dist/integrations/harnesses/codex/agent-builder.js +137 -0
  240. package/dist/integrations/harnesses/codex/index.js +63 -0
  241. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  242. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  243. package/dist/integrations/harnesses/copilot/index.js +60 -0
  244. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  245. package/dist/integrations/harnesses/gemini/agent-builder.js +121 -0
  246. package/dist/integrations/harnesses/gemini/index.js +60 -0
  247. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  248. package/dist/integrations/harnesses/index.js +28 -7
  249. package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
  250. package/dist/integrations/harnesses/opencode/index.js +17 -16
  251. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  252. package/dist/integrations/harnesses/opencode-sdk/harness.js +65 -0
  253. package/dist/integrations/harnesses/opencode-sdk/index.js +10 -34
  254. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +642 -71
  255. package/dist/integrations/harnesses/openhands/agent-builder.js +126 -0
  256. package/dist/integrations/harnesses/openhands/index.js +58 -0
  257. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  258. package/dist/integrations/harnesses/pi/agent-builder.js +104 -0
  259. package/dist/integrations/harnesses/pi/index.js +58 -0
  260. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  261. package/dist/integrations/harnesses/types.js +8 -0
  262. package/dist/integrations/session-logs/index.js +40 -11
  263. package/dist/llm/call-ai.js +2 -2
  264. package/dist/llm/client.js +34 -11
  265. package/dist/llm/embedder.js +67 -4
  266. package/dist/llm/embedders/cache.js +3 -1
  267. package/dist/llm/embedders/deterministic.js +66 -0
  268. package/dist/llm/embedders/local.js +73 -3
  269. package/dist/llm/feature-gate.js +16 -15
  270. package/dist/llm/graph-extract.js +67 -44
  271. package/dist/llm/memory-infer-impl.js +138 -0
  272. package/dist/llm/memory-infer.js +1 -127
  273. package/dist/llm/metadata-enhance.js +44 -31
  274. package/dist/llm/structured-call.js +49 -0
  275. package/dist/migrate-storage-node.mjs +8 -0
  276. package/dist/output/context.js +5 -5
  277. package/dist/output/renderers.js +87 -15
  278. package/dist/output/shapes/curate.js +14 -2
  279. package/dist/output/shapes/helpers.js +0 -3
  280. package/dist/output/shapes/passthrough.js +6 -1
  281. package/dist/output/text/helpers.js +241 -2
  282. package/dist/output/text/workflow.js +4 -1
  283. package/dist/registry/providers/skills-sh.js +21 -147
  284. package/dist/registry/providers/static-index.js +15 -157
  285. package/dist/registry/resolve.js +27 -9
  286. package/dist/runtime.js +25 -1
  287. package/dist/schemas/akm-config.json +14225 -0
  288. package/dist/schemas/akm-workflow.json +328 -0
  289. package/dist/scripts/migrate-storage.js +2743 -8390
  290. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +1652 -607
  291. package/dist/setup/detect.js +9 -0
  292. package/dist/setup/legacy-config.js +106 -0
  293. package/dist/setup/prompt.js +57 -0
  294. package/dist/setup/providers.js +14 -0
  295. package/dist/setup/registry-stash-loader.js +12 -0
  296. package/dist/setup/semantic-assets.js +124 -0
  297. package/dist/setup/setup.js +52 -1614
  298. package/dist/setup/steps/connection.js +734 -0
  299. package/dist/setup/steps/output.js +31 -0
  300. package/dist/setup/steps/platforms.js +124 -0
  301. package/dist/setup/steps/semantic.js +27 -0
  302. package/dist/setup/steps/sources.js +222 -0
  303. package/dist/setup/steps/stashdir.js +42 -0
  304. package/dist/setup/steps/tasks.js +152 -0
  305. package/dist/sources/include.js +6 -2
  306. package/dist/sources/providers/filesystem.js +0 -1
  307. package/dist/sources/providers/git-install.js +210 -0
  308. package/dist/sources/providers/git-provider.js +234 -0
  309. package/dist/sources/providers/git-stash.js +248 -0
  310. package/dist/sources/providers/git.js +10 -661
  311. package/dist/sources/providers/npm.js +2 -6
  312. package/dist/sources/providers/provider-utils.js +13 -7
  313. package/dist/sources/providers/sync-from-ref.js +9 -1
  314. package/dist/sources/providers/website.js +9 -5
  315. package/dist/sources/website-ingest.js +187 -29
  316. package/dist/sources/wiki-fetchers/registry.js +53 -0
  317. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  318. package/dist/storage/database.js +45 -10
  319. package/dist/storage/managed-db.js +82 -0
  320. package/dist/storage/repositories/canaries-repository.js +107 -0
  321. package/dist/storage/repositories/consolidation-repository.js +38 -0
  322. package/dist/storage/repositories/embeddings-repository.js +72 -0
  323. package/dist/storage/repositories/events-repository.js +187 -0
  324. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  325. package/dist/storage/repositories/improve-runs-repository.js +146 -0
  326. package/dist/storage/repositories/index-db.js +14 -8
  327. package/dist/storage/repositories/proposals-repository.js +220 -0
  328. package/dist/storage/repositories/recombine-repository.js +213 -0
  329. package/dist/storage/repositories/registry-cache.js +93 -0
  330. package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
  331. package/dist/storage/repositories/task-history-repository.js +93 -0
  332. package/dist/storage/repositories/workflow-runs-repository.js +189 -1
  333. package/dist/storage/sqlite-pragmas.js +146 -0
  334. package/dist/tasks/backends/cron.js +1 -1
  335. package/dist/tasks/backends/index.js +9 -0
  336. package/dist/tasks/backends/launchd.js +1 -1
  337. package/dist/tasks/backends/schtasks.js +1 -1
  338. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  339. package/dist/tasks/runner.js +15 -13
  340. package/dist/text-import-hook.mjs +1 -1
  341. package/dist/wiki/wiki.js +52 -11
  342. package/dist/workflows/authoring/authoring.js +123 -10
  343. package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
  344. package/dist/workflows/cli.js +5 -0
  345. package/dist/workflows/db.js +138 -4
  346. package/dist/workflows/exec/brief.js +484 -0
  347. package/dist/workflows/exec/native-executor.js +975 -0
  348. package/dist/workflows/exec/param-secrets.js +115 -0
  349. package/dist/workflows/exec/report.js +1295 -0
  350. package/dist/workflows/exec/run-workflow.js +596 -0
  351. package/dist/workflows/exec/scheduler.js +100 -0
  352. package/dist/workflows/exec/step-work.js +1156 -0
  353. package/dist/workflows/exec/unit-writer.js +23 -0
  354. package/dist/workflows/exec/watch.js +116 -0
  355. package/dist/workflows/exec/worktree.js +171 -0
  356. package/dist/workflows/ir/compile.js +388 -0
  357. package/dist/workflows/ir/params.js +54 -0
  358. package/dist/workflows/ir/plan-hash.js +33 -0
  359. package/dist/workflows/ir/schema.js +4 -0
  360. package/dist/workflows/parser.js +3 -1
  361. package/dist/workflows/program/expressions.js +369 -0
  362. package/dist/workflows/program/parser.js +760 -0
  363. package/dist/workflows/program/project.js +105 -0
  364. package/dist/workflows/program/schema.js +54 -0
  365. package/dist/workflows/renderer.js +82 -5
  366. package/dist/workflows/runtime/agent-identity.js +59 -14
  367. package/dist/workflows/runtime/runs.js +248 -153
  368. package/dist/workflows/runtime/unit-checkin.js +45 -0
  369. package/dist/workflows/runtime/workflow-asset-loader.js +188 -0
  370. package/dist/workflows/validate-summary.js +26 -10
  371. package/dist/workflows/validator.js +1 -1
  372. package/docs/README.md +69 -18
  373. package/docs/data-and-telemetry.md +7 -5
  374. package/docs/migration/release-notes/0.7.0.md +1 -1
  375. package/docs/migration/release-notes/0.9.0-beta.60.md +19 -0
  376. package/docs/migration/release-notes/0.9.0.md +39 -0
  377. package/package.json +10 -10
  378. package/dist/assets/tasks/core/update-stashes.yml +0 -4
  379. package/dist/commands/db-cli.js +0 -23
  380. package/dist/indexer/db/db-backup.js +0 -376
  381. package/dist/indexer/passes/staleness-detect.js +0 -488
@@ -17,6 +17,7 @@
17
17
  import fs from "node:fs";
18
18
  import os from "node:os";
19
19
  import path from "node:path";
20
+ import { parseEmbeddedJsonResponse } from "../../core/parse.js";
20
21
  import { spawn as runtimeSpawn } from "../../runtime.js";
21
22
  import { getCommandBuilder } from "./builders.js";
22
23
  import { DEFAULT_AGENT_TIMEOUT_MS } from "./config.js";
@@ -142,21 +143,93 @@ function buildChildEnv(profile, options) {
142
143
  }
143
144
  return env;
144
145
  }
146
+ const STREAM_READ_TIMEOUT = Symbol("stream-read-timeout");
145
147
  async function readStream(stream, opts) {
146
148
  if (!stream)
147
- return "";
148
- const readPromise = new Response(stream).text().catch(() => "");
149
- if (!opts?.timeoutMs)
150
- return readPromise;
149
+ return { text: "", timedOut: false };
150
+ const reader = stream.getReader();
151
+ const decoder = new TextDecoder();
152
+ let text = "";
153
+ if (!opts?.timeoutMs) {
154
+ try {
155
+ while (true) {
156
+ const chunk = await reader.read();
157
+ if (chunk.done)
158
+ break;
159
+ text += decoder.decode(chunk.value, { stream: true });
160
+ }
161
+ text += decoder.decode();
162
+ return { text, timedOut: false };
163
+ }
164
+ catch (error) {
165
+ return { text, timedOut: false, error };
166
+ }
167
+ finally {
168
+ try {
169
+ reader.releaseLock();
170
+ }
171
+ catch {
172
+ /* ignore */
173
+ }
174
+ }
175
+ }
151
176
  // Race the stream read against a timeout so a process that is killed via
152
177
  // SIGTERM/SIGKILL but whose pipe endpoints stay open (e.g. background
153
178
  // threads still holding the fd) cannot block the caller indefinitely.
154
- // On timeout we return whatever we received so far (empty string here since
155
- // `readPromise` is all-or-nothing with `Response.text()`).
179
+ // On timeout we return whatever was decoded before the pipe stopped draining.
180
+ const setTimeoutImpl = opts.setTimeoutFn ?? setTimeout;
181
+ const clearTimeoutImpl = opts.clearTimeoutFn ?? clearTimeout;
182
+ let timer;
156
183
  const timeoutPromise = new Promise((resolve) => {
157
- setTimeout(() => resolve(""), opts.timeoutMs);
184
+ timer = setTimeoutImpl(() => {
185
+ timer = undefined;
186
+ resolve(STREAM_READ_TIMEOUT);
187
+ }, opts.timeoutMs);
188
+ if (typeof timer !== "number")
189
+ timer.unref?.();
158
190
  });
159
- return Promise.race([readPromise, timeoutPromise]);
191
+ try {
192
+ while (true) {
193
+ const chunk = await Promise.race([reader.read(), timeoutPromise]);
194
+ if (chunk === STREAM_READ_TIMEOUT) {
195
+ void reader.cancel().catch(() => { });
196
+ return { text, timedOut: true };
197
+ }
198
+ if (chunk.done)
199
+ break;
200
+ text += decoder.decode(chunk.value, { stream: true });
201
+ }
202
+ text += decoder.decode();
203
+ return { text, timedOut: false };
204
+ }
205
+ catch (error) {
206
+ return { text, timedOut: false, error };
207
+ }
208
+ finally {
209
+ if (timer !== undefined) {
210
+ clearTimeoutImpl(timer);
211
+ }
212
+ try {
213
+ reader.releaseLock();
214
+ }
215
+ catch {
216
+ /* ignore */
217
+ }
218
+ }
219
+ }
220
+ function streamFailureMessage(profileName, stdout, stderr) {
221
+ const failures = [];
222
+ if (stdout.error)
223
+ failures.push(`stdout read failed: ${stdout.error instanceof Error ? stdout.error.message : String(stdout.error)}`);
224
+ if (stderr.error)
225
+ failures.push(`stderr read failed: ${stderr.error instanceof Error ? stderr.error.message : String(stderr.error)}`);
226
+ if (stdout.timedOut)
227
+ failures.push("stdout drain timed out");
228
+ if (stderr.timedOut)
229
+ failures.push("stderr drain timed out");
230
+ if (failures.length === 0)
231
+ return undefined;
232
+ return `agent CLI "${profileName}" output capture failed: ${failures.join("; ")}`;
160
233
  }
161
234
  /**
162
235
  * Spawn the agent CLI described by `profile` with `prompt` (forwarded as
@@ -183,6 +256,17 @@ export async function runAgent(profile, prompt, options = {}) {
183
256
  const parseOutput = options.parseOutput ?? profile.parseOutput;
184
257
  const setTimeoutImpl = options.setTimeoutFn ?? setTimeout;
185
258
  const clearTimeoutImpl = options.clearTimeoutFn ?? clearTimeout;
259
+ // Observability seam — ids/status only, best-effort (see RunAgentOptions.onEvent).
260
+ const emitSpawnEvent = (type, data) => {
261
+ if (!options.onEvent)
262
+ return;
263
+ try {
264
+ options.onEvent({ type, data });
265
+ }
266
+ catch {
267
+ // Observability must never break the dispatch.
268
+ }
269
+ };
186
270
  // Build argv via the platform-specific builder when dispatch params are
187
271
  // provided; fall back to the legacy positional-prompt form otherwise.
188
272
  let builtArgv;
@@ -203,6 +287,19 @@ export async function runAgent(profile, prompt, options = {}) {
203
287
  const finalArgv = [...builtArgv, ...(options.dispatch ? (options.args ?? []) : [])];
204
288
  const env = { ...buildChildEnv(profile, options), ...(builtEnv ?? {}) };
205
289
  const start = Date.now();
290
+ // Cooperative cancel: refuse to spawn at all when the caller's signal is
291
+ // already aborted (e.g. the run's budget was exhausted before this unit).
292
+ if (options.signal?.aborted) {
293
+ return {
294
+ ok: false,
295
+ exitCode: null,
296
+ stdout: "",
297
+ stderr: "",
298
+ durationMs: 0,
299
+ reason: "aborted",
300
+ error: `agent CLI "${profile.name}" not started: caller signal already aborted`,
301
+ };
302
+ }
206
303
  let proc;
207
304
  try {
208
305
  const spawnFn = resolveSpawnFn(options);
@@ -211,7 +308,9 @@ export async function runAgent(profile, prompt, options = {}) {
211
308
  stdout: stdioMode === "captured" ? "pipe" : "inherit",
212
309
  stderr: stdioMode === "captured" ? "pipe" : "inherit",
213
310
  env,
214
- ...(options.cwd ? { cwd: options.cwd } : {}),
311
+ // options.cwd wins; dispatch.cwd is the request-level fallback (it was
312
+ // declared on AgentDispatchRequest but consumed by nothing — P0.5 fix).
313
+ ...((options.cwd ?? options.dispatch?.cwd) ? { cwd: options.cwd ?? options.dispatch?.cwd } : {}),
215
314
  // Spawn in its own process group so killGroup(-pid, signal) reaches all
216
315
  // descendants (e.g. the .opencode binary that opencode's node wrapper forks).
217
316
  // Only applied in captured mode — interactive mode inherits the parent
@@ -231,6 +330,10 @@ export async function runAgent(profile, prompt, options = {}) {
231
330
  error: err instanceof Error ? err.message : String(err),
232
331
  };
233
332
  }
333
+ emitSpawnEvent("spawn_start", {
334
+ profile: profile.name,
335
+ ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
336
+ });
234
337
  // Hard timeout. We prefer SIGTERM, then SIGKILL if SIGTERM is ignored,
235
338
  // but the subprocess only exposes a single .kill() — one signal is enough
236
339
  // for the structured-failure contract.
@@ -251,13 +354,40 @@ export async function runAgent(profile, prompt, options = {}) {
251
354
  timedOut = true;
252
355
  killGroup(proc, "SIGTERM");
253
356
  // Follow up with SIGKILL after 5 s in case the process ignores SIGTERM.
254
- setTimeoutImpl(() => {
357
+ const sigkillTimer = setTimeoutImpl(() => {
255
358
  if (!proc || proc.exitCode !== null)
256
359
  return;
257
360
  killGroup(proc, "SIGKILL");
258
361
  }, 5000);
362
+ if (typeof sigkillTimer !== "number")
363
+ sigkillTimer.unref?.();
259
364
  }, timeoutMs);
260
365
  }
366
+ // Cooperative cancel: same SIGTERM→SIGKILL discipline as the timeout, but
367
+ // flagged separately so the result carries `reason: "aborted"`.
368
+ let aborted = false;
369
+ const abortSignal = options.signal;
370
+ const onAbort = () => {
371
+ if (!proc || proc.exitCode !== null)
372
+ return;
373
+ aborted = true;
374
+ killGroup(proc, "SIGTERM");
375
+ const sigkillTimer = setTimeoutImpl(() => {
376
+ if (!proc || proc.exitCode !== null)
377
+ return;
378
+ killGroup(proc, "SIGKILL");
379
+ }, 5000);
380
+ if (typeof sigkillTimer !== "number")
381
+ sigkillTimer.unref?.();
382
+ };
383
+ if (abortSignal) {
384
+ // A signal that aborted between the pre-spawn check and here is handled
385
+ // by calling the listener directly.
386
+ if (abortSignal.aborted)
387
+ onAbort();
388
+ else
389
+ abortSignal.addEventListener("abort", onAbort, { once: true });
390
+ }
261
391
  // Stream-drain timeout: the overall wall-clock budget plus a 2 s grace
262
392
  // period. When a process is killed via SIGTERM/SIGKILL (from our timeout
263
393
  // handler or from outside) some runtimes keep the pipe write-end open in
@@ -267,11 +397,19 @@ export async function runAgent(profile, prompt, options = {}) {
267
397
  // When there is no kill timer, allow up to 30 s for streams to drain.
268
398
  const streamDrainTimeoutMs = timeoutMs !== null ? timeoutMs + 2_000 : 30_000;
269
399
  const stdoutPromise = stdioMode === "captured"
270
- ? readStream(proc.stdout ?? null, { timeoutMs: streamDrainTimeoutMs })
271
- : Promise.resolve("");
400
+ ? readStream(proc.stdout ?? null, {
401
+ timeoutMs: streamDrainTimeoutMs,
402
+ setTimeoutFn: setTimeoutImpl,
403
+ clearTimeoutFn: clearTimeoutImpl,
404
+ })
405
+ : Promise.resolve({ text: "", timedOut: false });
272
406
  const stderrPromise = stdioMode === "captured"
273
- ? readStream(proc.stderr ?? null, { timeoutMs: streamDrainTimeoutMs })
274
- : Promise.resolve("");
407
+ ? readStream(proc.stderr ?? null, {
408
+ timeoutMs: streamDrainTimeoutMs,
409
+ setTimeoutFn: setTimeoutImpl,
410
+ clearTimeoutFn: clearTimeoutImpl,
411
+ })
412
+ : Promise.resolve({ text: "", timedOut: false });
275
413
  // Optional stdin payload (captured mode only).
276
414
  //
277
415
  // BUG-H1: race the stdin write/close against `proc.exited` and the
@@ -304,12 +442,19 @@ export async function runAgent(profile, prompt, options = {}) {
304
442
  catch (err) {
305
443
  if (timer !== undefined)
306
444
  clearTimeoutImpl(timer);
445
+ abortSignal?.removeEventListener("abort", onAbort);
307
446
  // BUG-H2: drain stream readers before the early return so they don't
308
447
  // surface as unhandled rejections after the function resolves.
309
448
  // The streams already carry a built-in drain timeout so this allSettled
310
449
  // will not block indefinitely.
311
450
  await Promise.allSettled([stdoutPromise, stderrPromise]);
312
451
  const durationMs = Date.now() - start;
452
+ emitSpawnEvent("spawn_exit", {
453
+ profile: profile.name,
454
+ ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
455
+ exitCode: null,
456
+ status: "spawn_failed",
457
+ });
313
458
  return {
314
459
  ok: false,
315
460
  exitCode: null,
@@ -321,8 +466,28 @@ export async function runAgent(profile, prompt, options = {}) {
321
466
  };
322
467
  }
323
468
  clearTimeoutImpl(timer);
324
- const [stdout, stderr] = await Promise.all([stdoutPromise, stderrPromise]);
469
+ abortSignal?.removeEventListener("abort", onAbort);
470
+ emitSpawnEvent("spawn_exit", {
471
+ profile: profile.name,
472
+ ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
473
+ exitCode,
474
+ status: aborted ? "aborted" : timedOut ? "timeout" : exitCode !== 0 ? "non_zero_exit" : "ok",
475
+ });
476
+ const [stdoutRead, stderrRead] = await Promise.all([stdoutPromise, stderrPromise]);
477
+ const stdout = stdoutRead.text;
478
+ const stderr = stderrRead.text;
325
479
  const durationMs = Date.now() - start;
480
+ if (aborted) {
481
+ return {
482
+ ok: false,
483
+ exitCode,
484
+ stdout,
485
+ stderr,
486
+ durationMs,
487
+ reason: "aborted",
488
+ error: `agent CLI "${profile.name}" aborted by caller signal`,
489
+ };
490
+ }
326
491
  if (timedOut) {
327
492
  return {
328
493
  ok: false,
@@ -334,6 +499,18 @@ export async function runAgent(profile, prompt, options = {}) {
334
499
  error: `agent CLI "${profile.name}" timed out after ${timeoutMs ?? 0}ms`,
335
500
  };
336
501
  }
502
+ const captureFailure = streamFailureMessage(profile.name, stdoutRead, stderrRead);
503
+ if (captureFailure) {
504
+ return {
505
+ ok: false,
506
+ exitCode,
507
+ stdout,
508
+ stderr,
509
+ durationMs,
510
+ reason: "spawn_failed",
511
+ error: captureFailure,
512
+ };
513
+ }
337
514
  if (exitCode !== 0) {
338
515
  return {
339
516
  ok: false,
@@ -346,72 +523,20 @@ export async function runAgent(profile, prompt, options = {}) {
346
523
  };
347
524
  }
348
525
  if (parseOutput === "json" && stdioMode === "captured") {
349
- // Strip <think> blocks and code fences, then try direct parse with
350
- // embedded-JSON fallback for local LLMs that emit prose around the payload.
351
- const cleaned = stdout
352
- .trim()
353
- .replace(/<think>[\s\S]*?<\/think>/gi, "")
354
- .trim()
355
- .replace(/^```(?:json)?\s*\n?/, "")
356
- .replace(/\n?```\s*$/, "")
357
- .trim();
358
- let parsed;
359
- try {
360
- parsed = JSON.parse(cleaned);
361
- }
362
- catch {
363
- // Fallback: extract the first balanced {…} from prose output.
364
- let found;
365
- for (let s = 0; s < cleaned.length; s++) {
366
- if (cleaned[s] !== "{")
367
- continue;
368
- let depth = 0, inStr = false, esc = false;
369
- for (let i = s; i < cleaned.length; i++) {
370
- const c = cleaned[i];
371
- if (inStr) {
372
- if (esc) {
373
- esc = false;
374
- }
375
- else if (c === "\\") {
376
- esc = true;
377
- }
378
- else if (c === '"') {
379
- inStr = false;
380
- }
381
- continue;
382
- }
383
- if (c === '"') {
384
- inStr = true;
385
- continue;
386
- }
387
- if (c === "{")
388
- depth++;
389
- if (c === "}") {
390
- depth--;
391
- if (depth === 0) {
392
- try {
393
- found = JSON.parse(cleaned.slice(s, i + 1));
394
- }
395
- catch { }
396
- break;
397
- }
398
- }
399
- }
400
- if (found !== undefined)
401
- break;
402
- }
403
- if (found === undefined) {
404
- return {
405
- ok: false,
406
- exitCode,
407
- stdout,
408
- stderr,
409
- durationMs,
410
- reason: "parse_error",
411
- error: "no JSON object found in agent output",
412
- };
413
- }
414
- parsed = found;
526
+ // Strip <think> blocks and code fences, then parse with embedded-JSON
527
+ // fallback for local LLMs that emit prose around the payload. Handles
528
+ // both top-level `{…}` and `[…]` structures.
529
+ const parsed = parseEmbeddedJsonResponse(stdout);
530
+ if (parsed === undefined) {
531
+ return {
532
+ ok: false,
533
+ exitCode,
534
+ stdout,
535
+ stderr,
536
+ durationMs,
537
+ reason: "parse_error",
538
+ error: "no JSON structure found in agent output",
539
+ };
415
540
  }
416
541
  return { ok: true, exitCode, stdout, stderr, durationMs, parsed };
417
542
  }
@@ -0,0 +1,113 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Aider CLI agent command builder (P2, plan §"The adapter contract" step 2 /
6
+ * §"Capability matrix").
7
+ *
8
+ * Translates a platform-agnostic {@link AgentDispatchRequest} into the exact
9
+ * headless argv the `aider` CLI expects. Per the capability matrix the
10
+ * headless invocation is:
11
+ *
12
+ * aider -m "<p>" --yes-always
13
+ *
14
+ * with `--model <m>` for model selection, NO structured-output mode (Aider is
15
+ * the "none" tier — prompt-injected schema + embedded-JSON extraction), and
16
+ * NO session flag (resume is chat-history files, not an id).
17
+ *
18
+ * Platform-specific mapping decisions (all localized here, per the adapter
19
+ * contract):
20
+ *
21
+ * - **prompt** — `--message` is Aider's one-shot non-interactive mode (the
22
+ * matrix's `-m`; the long form is used for self-documenting argv). Unlike
23
+ * claude/codex/pi there is NO positional prompt and NO `--` end-of-options
24
+ * separator to hide behind: the prompt is a *flag value*. The glued
25
+ * `--message=<payload>` form is therefore used so a payload that begins
26
+ * with `-`/`--` binds to the flag lexically and can never be parsed as a
27
+ * separate option by Aider's argument parser.
28
+ * - **--yes-always** — always emitted: auto-confirms every interactive
29
+ * prompt (create file? run command? …), which is what makes a captured,
30
+ * unattended run possible. This is the matrix's documented headless shape.
31
+ * - **--no-pretty** — always emitted: disables colored/pretty terminal
32
+ * rendering so captured stdout is clean text for `./result-extractor.ts`
33
+ * (the same "dispatch is the captured path" reasoning as the Claude
34
+ * builder's unconditional `--print` and Codex's unconditional `--json`).
35
+ * - **systemPrompt** — Aider has no system-prompt flag (its nearest concept
36
+ * is conventions files via `--read`, which take a path, not text). Folded
37
+ * into the message payload — system text first, blank line, then the task —
38
+ * mirroring the codex builder's treatment.
39
+ * - **schema** — the matrix places Aider in the "via prompt+validate" tier
40
+ * with *no* structured output mode at all (plan §"Structured-output
41
+ * normalization", tier "none"): there is no schema flag and no JSON output
42
+ * flag, so the JSON Schema is injected into the message payload using the
43
+ * exact directive wording of the engine's prompt assembly
44
+ * (`step-work.ts` `buildUnitPrompt`) and the pi builder, so all
45
+ * dispatch paths speak one dialect. Downstream, embedded-JSON extraction +
46
+ * the engine's shared retry-until-valid loop supply the validation Aider
47
+ * lacks. No temp schema file is written — that is Codex's native-schema
48
+ * mechanism (`--output-schema`), which Aider does not have.
49
+ * - **tools** — deliberately unconsumed. Aider has no per-tool allowlist
50
+ * flag; tool-ish behaviour is governed by its own switches (`--yes-always`,
51
+ * git integration, shell-command confirmation). A restrictive policy is
52
+ * therefore dropped rather than approximated — never silently widened.
53
+ * - **resume/session** — NOT expressible: Aider persists context in
54
+ * chat-history files (`.aider.chat.history.md`), not session ids, so there
55
+ * is no flag-shaped `HarnessResumeSupport` to export and the extractor
56
+ * never yields a `sessionId`. akm's `workflow_run_units` remains the
57
+ * durable source of truth; resume works even against a harness with no
58
+ * session model (plan §"Session, MCP, and identity across harnesses" —
59
+ * Aider is the plan's named example).
60
+ * - **effort** — stays unconsumed (reserved; the shared request contract's
61
+ * "no builder consumes it yet" note stays true).
62
+ *
63
+ * NOT registered anywhere: `builders.ts` / `harnesses/index.ts` wiring is a
64
+ * follow-up integration task (as is the registry entry declaring
65
+ * `structuredOutput: "none"` and no `resume`). Exported standalone so that
66
+ * task only adds a registry entry.
67
+ */
68
+ import { assertNotFlag } from "../../agent/builder-shared.js";
69
+ import { resolveModel } from "../../agent/model-aliases.js";
70
+ /** Canonical harness/platform id used for model-alias resolution. */
71
+ export const AIDER_PLATFORM = "aider";
72
+ /**
73
+ * Assemble the `--message` payload: optional system text, the task prompt,
74
+ * and — when a schema is requested — the same schema directive the workflow
75
+ * engine's prompt assembly uses (Aider has no native structured output, so
76
+ * the prompt is the only channel; plan §"Structured-output normalization",
77
+ * tier "none").
78
+ */
79
+ function buildMessagePayload(req) {
80
+ const sections = [];
81
+ if (req.systemPrompt)
82
+ sections.push(req.systemPrompt);
83
+ sections.push(req.prompt);
84
+ if (req.schema) {
85
+ sections.push(`Respond with ONLY a JSON value matching this JSON Schema (no prose, no code fences):\n${JSON.stringify(req.schema)}`);
86
+ }
87
+ return sections.join("\n\n");
88
+ }
89
+ /**
90
+ * Aider builder.
91
+ * Command shape:
92
+ * aider [--model <m>] --yes-always --no-pretty --message=<[system\n\n]prompt[\n\nschema directive]>
93
+ */
94
+ export const aiderBuilder = {
95
+ platform: AIDER_PLATFORM,
96
+ build(profile, req) {
97
+ assertNotFlag(req.systemPrompt, "systemPrompt");
98
+ assertNotFlag(req.model, "model");
99
+ const args = [...profile.args];
100
+ if (req.model) {
101
+ const resolved = resolveModel(req.model, AIDER_PLATFORM, profile.modelAliases, profile.globalModelAliases);
102
+ args.push("--model", resolved);
103
+ }
104
+ // Headless essentials (matrix shape): auto-confirm everything, and keep
105
+ // captured stdout free of pretty/ANSI rendering for the extractor.
106
+ args.push("--yes-always");
107
+ args.push("--no-pretty");
108
+ // Glued form: the payload is a flag VALUE (no positional prompt exists),
109
+ // so `=` binding keeps a dash-leading payload from parsing as an option.
110
+ args.push(`--message=${buildMessagePayload(req)}`);
111
+ return { argv: [profile.bin, ...args] };
112
+ },
113
+ };
@@ -0,0 +1,58 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Aider CLI harness (P2 integration, plan §"The adapter contract").
6
+ *
7
+ * Per-harness barrel gathering the Aider integration surfaces:
8
+ * - agent command builder → ./agent-builder.ts (aiderBuilder)
9
+ * - result extractor → ./result-extractor.ts (aiderResultExtractor)
10
+ *
11
+ * It also defines {@link AiderHarness}, the {@link AkmHarness} descriptor that
12
+ * `HARNESS_REGISTRY` registers. Dispatch-only: no native session-log reader or
13
+ * config importer yet.
14
+ */
15
+ import { BaseHarness } from "../types.js";
16
+ import { aiderBuilder } from "./agent-builder.js";
17
+ import { aiderResultExtractor } from "./result-extractor.js";
18
+ export { AIDER_PLATFORM, aiderBuilder } from "./agent-builder.js";
19
+ export { aiderResultExtractor } from "./result-extractor.js";
20
+ function caps(c) {
21
+ return {
22
+ sessionLogs: false,
23
+ agentDispatch: false,
24
+ detection: false,
25
+ configImport: false,
26
+ runtimeIdentity: false,
27
+ v1Migration: false,
28
+ ...c,
29
+ };
30
+ }
31
+ /**
32
+ * Aider.
33
+ *
34
+ * Canonical id is `'aider'`; no alias or distinct runtime identity.
35
+ */
36
+ export class AiderHarness extends BaseHarness {
37
+ id = "aider";
38
+ displayName = "Aider";
39
+ aliases = [];
40
+ agentBuilder = aiderBuilder;
41
+ resultExtractor = aiderResultExtractor;
42
+ // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
43
+ // akm spawns the `aider` CLI locally per unit ⇒ local-runner.
44
+ pattern = "local-runner";
45
+ // No structured-output mode at all (the matrix's "none — parse output"):
46
+ // akm injects the schema into the prompt and extracts embedded JSON.
47
+ structuredOutput = "none";
48
+ // No `resume`: Aider persists context in chat-history files
49
+ // (`.aider.chat.history.md`), not session ids — the plan's named example of
50
+ // a harness with no session model. akm's `workflow_run_units` remains the
51
+ // durable resume source of truth.
52
+ // No `identityEnv`: the matrix lists Aider's identity markers as uncertain,
53
+ // and Aider stamps no session var onto child processes.
54
+ capabilities = caps({
55
+ agentDispatch: true,
56
+ detection: true,
57
+ });
58
+ }
@@ -0,0 +1,53 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * ANSI escape sequences (CSI color/cursor codes). Defensive only: the builder
6
+ * always passes `--no-pretty`, but a user profile may override that.
7
+ * Constructed from a char code so no literal control character appears in
8
+ * source (lint-friendly, same bytes).
9
+ */
10
+ const ANSI_ESCAPE_RE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g");
11
+ /**
12
+ * Aider's own announcement lines — banner, model/repo configuration echo,
13
+ * chat-history notices, edit/commit/usage reports. All patterns are anchored
14
+ * at line start and match documented phrasings only; anything else is treated
15
+ * as reply content.
16
+ */
17
+ const NOISE_LINE_PATTERNS = [
18
+ /^aider v\d/, // version banner
19
+ /^(Main model|Weak model|Editor model|Model):\s/, // model announcements
20
+ /^Git repo:\s/, // repo detection
21
+ /^Repo-map:\s/, // repo-map status
22
+ /^Added .+ to the chat\.?$/, // file add notices
23
+ /^Restored previous conversation history\.?$/, // chat-history reload notice
24
+ /^Use \/help\b/, // onboarding hint line
25
+ /^Tokens: .+/, // usage/cost footer
26
+ /^Cost: .+/, // standalone cost footer
27
+ /^Applied edit to .+/, // edit application notices
28
+ /^Commit [0-9a-f]{6,}\b/, // auto-commit notices
29
+ /^You can use \/undo\b/, // undo hint after auto-commit
30
+ /^[─━-]{4,}$/, // ── / ━━ / ---- separator rules
31
+ ];
32
+ function isNoiseLine(line) {
33
+ return NOISE_LINE_PATTERNS.some((pattern) => pattern.test(line));
34
+ }
35
+ /**
36
+ * Normalize a raw aider run result into `{ text, sessionId? }`.
37
+ * See the module doc for the stdout shape handled.
38
+ */
39
+ export const aiderResultExtractor = (result) => {
40
+ const raw = result.stdout.replace(ANSI_ESCAPE_RE, "").trim();
41
+ const kept = raw
42
+ .split("\n")
43
+ .filter((line) => !isNoiseLine(line.trim()))
44
+ .join("\n")
45
+ .trim();
46
+ // Never return empty text when stdout had content: an all-noise filter
47
+ // outcome means the patterns over-matched for this capture, so fall back to
48
+ // the full trimmed stdout (downstream parsing still gets material).
49
+ const text = kept.length > 0 ? kept : raw;
50
+ // No session model (chat-history files, not ids): only a spawn-layer id
51
+ // passes through; output never supplies one.
52
+ return result.sessionId === undefined ? { text } : { text, sessionId: result.sessionId };
53
+ };