akm-cli 0.9.0-rc.4 → 0.9.0-rc.6

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 (438) hide show
  1. package/CHANGELOG.md +122 -26
  2. package/README.md +7 -7
  3. package/SECURITY.md +11 -10
  4. package/dist/akm +2 -2
  5. package/dist/akm-migrate-storage +2 -2
  6. package/dist/assets/hints/cli-hints-full.md +60 -73
  7. package/dist/assets/hints/cli-hints-short.md +8 -12
  8. package/dist/assets/improve-strategies/default.json +5 -7
  9. package/dist/assets/improve-strategies/frequent.json +2 -2
  10. package/dist/assets/improve-strategies/proactive-maintenance.json +2 -2
  11. package/dist/assets/improve-strategies/quick.json +1 -1
  12. package/dist/assets/improve-strategies/reflect-distill.json +3 -3
  13. package/dist/assets/improve-strategies/thorough.json +1 -1
  14. package/dist/assets/prompts/consolidate-system.md +5 -5
  15. package/dist/assets/prompts/extract-session.md +2 -6
  16. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  17. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  18. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  19. package/dist/assets/stash-skeleton/README.md +10 -11
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +1 -1
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +1 -1
  22. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +1 -1
  23. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -2
  24. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -2
  25. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +1 -1
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -2
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +1 -1
  28. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +18 -18
  29. package/dist/assets/stash-skeleton/facts/conventions/domains.md +8 -9
  30. package/dist/assets/stash-skeleton/facts/conventions/organization.md +13 -15
  31. package/dist/assets/tasks/core/extract.yml +2 -2
  32. package/dist/assets/tasks/core/improve.yml +1 -1
  33. package/dist/assets/templates/html/health.html +2 -3
  34. package/dist/cli/config-migrate.js +1328 -101
  35. package/dist/cli/invocation.js +255 -0
  36. package/dist/cli/parse-args.js +20 -83
  37. package/dist/cli/shared.js +15 -37
  38. package/dist/cli.js +18 -49
  39. package/dist/commands/agent/agent-dispatch.js +2 -2
  40. package/dist/commands/agent/contribute-cli.js +5 -4
  41. package/dist/commands/bundle/bundle-cli.js +68 -0
  42. package/dist/commands/bundle/bundle.js +219 -0
  43. package/dist/commands/completions.js +2 -2
  44. package/dist/commands/config-cli.js +6 -3
  45. package/dist/commands/env/env-binding.js +13 -9
  46. package/dist/commands/env/env-cli.js +49 -48
  47. package/dist/commands/env/secret-cli.js +24 -10
  48. package/dist/commands/events.js +2 -2
  49. package/dist/commands/feedback-cli.js +59 -33
  50. package/dist/commands/graph/graph.js +6 -4
  51. package/dist/commands/health/advisories.js +4 -4
  52. package/dist/commands/health/html-report.js +190 -593
  53. package/dist/commands/health/improve-metrics.js +240 -188
  54. package/dist/commands/health/metrics.js +9 -17
  55. package/dist/commands/health/report-view-model.js +509 -0
  56. package/dist/commands/health/surfaces.js +6 -3
  57. package/dist/commands/health/types-checks.js +4 -0
  58. package/dist/commands/health/types-improve.js +22 -0
  59. package/dist/commands/health/types-metrics.js +4 -0
  60. package/dist/commands/health/types-result.js +7 -0
  61. package/dist/commands/health/types-runs.js +4 -0
  62. package/dist/commands/health/types-session-log.js +4 -0
  63. package/dist/commands/health/types-windows.js +4 -0
  64. package/dist/commands/health/types.js +26 -21
  65. package/dist/commands/health/windows.js +1 -2
  66. package/dist/commands/health.js +219 -161
  67. package/dist/commands/improve/collapse-detector.js +25 -14
  68. package/dist/commands/improve/consolidate/chunking.js +7 -5
  69. package/dist/commands/improve/consolidate.js +640 -740
  70. package/dist/commands/improve/content-hash.js +39 -0
  71. package/dist/commands/improve/distill/content-repair.js +4 -10
  72. package/dist/commands/improve/distill/promote-memory.js +79 -49
  73. package/dist/commands/improve/distill/quality-gate.js +113 -35
  74. package/dist/commands/improve/distill-promotion-policy.js +24 -885
  75. package/dist/commands/improve/distill.js +565 -337
  76. package/dist/commands/improve/eligibility.js +75 -36
  77. package/dist/commands/improve/extract-cli.js +6 -6
  78. package/dist/commands/improve/extract-prompt.js +5 -34
  79. package/dist/commands/improve/extract.js +526 -357
  80. package/dist/commands/improve/feedback-valence.js +2 -12
  81. package/dist/commands/improve/improve-cli.js +11 -20
  82. package/dist/commands/improve/improve-result-file.js +7 -6
  83. package/dist/commands/improve/improve-run-types.js +4 -0
  84. package/dist/commands/improve/improve-strategies.js +3 -9
  85. package/dist/commands/improve/improve.js +822 -727
  86. package/dist/commands/improve/locks.js +27 -95
  87. package/dist/commands/improve/loop-stages.js +941 -963
  88. package/dist/commands/improve/memory/derived-ref.js +122 -0
  89. package/dist/commands/improve/memory/memory-contradiction-detect.js +35 -38
  90. package/dist/commands/improve/memory/memory-improve.js +24 -37
  91. package/dist/commands/improve/outcome-loop.js +13 -33
  92. package/dist/commands/improve/preparation.js +889 -691
  93. package/dist/commands/improve/proactive-maintenance.js +37 -9
  94. package/dist/commands/improve/proposal-envelope.js +31 -0
  95. package/dist/commands/improve/reflect.js +974 -588
  96. package/dist/commands/improve/run-context.js +119 -0
  97. package/dist/commands/improve/salience.js +8 -4
  98. package/dist/commands/improve/session-asset.js +7 -3
  99. package/dist/commands/improve/shared.js +14 -40
  100. package/dist/commands/improve/source-identity.js +39 -26
  101. package/dist/commands/improve/triage.js +20 -17
  102. package/dist/commands/lint/base-linter.js +288 -295
  103. package/dist/commands/lint/index.js +132 -19
  104. package/dist/commands/mv-cli.js +257 -234
  105. package/dist/commands/observability-cli.js +2 -1
  106. package/dist/commands/proposal/diff-format.js +50 -0
  107. package/dist/commands/proposal/drain-policies.js +0 -6
  108. package/dist/commands/proposal/drain.js +17 -16
  109. package/dist/commands/proposal/proposal-cli.js +40 -77
  110. package/dist/commands/proposal/proposal-types.js +56 -0
  111. package/dist/commands/proposal/proposal.js +39 -1
  112. package/dist/commands/proposal/propose.js +41 -19
  113. package/dist/commands/proposal/repository.js +566 -486
  114. package/dist/commands/proposal/validators/proposal-quality-validators.js +22 -6
  115. package/dist/commands/proposal/validators/proposal-validators.js +6 -5
  116. package/dist/commands/proposal/validators/proposals.js +5 -4
  117. package/dist/commands/read/curate.js +50 -28
  118. package/dist/commands/read/knowledge.js +25 -16
  119. package/dist/commands/read/remember-cli.js +12 -4
  120. package/dist/commands/read/search-cli.js +33 -33
  121. package/dist/commands/read/search.js +68 -55
  122. package/dist/commands/read/show.js +54 -135
  123. package/dist/commands/remember.js +7 -5
  124. package/dist/commands/sources/add-cli.js +10 -24
  125. package/dist/commands/sources/bundle-config-ops.js +58 -0
  126. package/dist/commands/sources/history.js +13 -8
  127. package/dist/commands/sources/info.js +10 -11
  128. package/dist/commands/sources/init.js +12 -21
  129. package/dist/commands/sources/installed-stashes.js +151 -138
  130. package/dist/commands/sources/schema-repair.js +5 -3
  131. package/dist/commands/sources/self-update.js +9 -7
  132. package/dist/commands/sources/source-add.js +116 -154
  133. package/dist/commands/sources/source-clone.js +33 -14
  134. package/dist/commands/sources/source-manage.js +43 -32
  135. package/dist/commands/sources/sources-cli.js +12 -7
  136. package/dist/commands/sources/stash-cli.js +12 -5
  137. package/dist/commands/sources/stash-skeleton.js +1 -1
  138. package/dist/commands/tasks/default-tasks.js +13 -13
  139. package/dist/commands/tasks/tasks-cli.js +3 -3
  140. package/dist/commands/tasks/tasks.js +71 -31
  141. package/dist/commands/workflow-cli.js +22 -26
  142. package/dist/core/action-contributors.js +1 -1
  143. package/dist/core/activation-policy.js +49 -0
  144. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  145. package/dist/core/adapter/adapters/akm-adapter.js +509 -0
  146. package/dist/core/adapter/adapters/akm-lint.js +381 -0
  147. package/dist/core/adapter/adapters/akm-metadata.js +416 -0
  148. package/dist/core/adapter/adapters/akm-task-adapter.js +150 -0
  149. package/dist/core/adapter/adapters/akm-workflow-adapter.js +196 -0
  150. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  151. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  152. package/dist/core/adapter/adapters/generic-files-adapter.js +117 -0
  153. package/dist/core/adapter/adapters/index.js +80 -0
  154. package/dist/core/adapter/adapters/llm-wiki-adapter.js +413 -0
  155. package/dist/core/adapter/adapters/okf-adapter.js +223 -0
  156. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  157. package/dist/core/adapter/adapters/shared.js +286 -0
  158. package/dist/core/adapter/adapters/tool-dir-shared.js +212 -0
  159. package/dist/core/adapter/adapters/website-snapshot-adapter.js +154 -0
  160. package/dist/core/adapter/bundle-adapter.js +4 -0
  161. package/dist/core/adapter/recognize-match.js +42 -0
  162. package/dist/core/adapter/registry.js +56 -0
  163. package/dist/core/adapter/types.js +4 -0
  164. package/dist/core/asset/asset-placement.js +229 -0
  165. package/dist/core/asset/asset-ref.js +107 -78
  166. package/dist/core/asset/asset-serialize.js +20 -0
  167. package/dist/core/asset/frontmatter.js +1 -1
  168. package/dist/core/asset/resolve-ref.js +223 -0
  169. package/dist/core/asset/stash-meta.js +1 -1
  170. package/dist/core/common.js +141 -49
  171. package/dist/core/config/config-io.js +0 -108
  172. package/dist/core/config/config-schema.js +94 -1039
  173. package/dist/core/config/config-sources.js +115 -36
  174. package/dist/core/config/config-types.js +16 -11
  175. package/dist/core/config/config-walker.js +4 -2
  176. package/dist/core/config/config.js +21 -26
  177. package/dist/core/config/engine-semantics.js +0 -4
  178. package/dist/core/config/schema/embedding.js +38 -0
  179. package/dist/core/config/schema/engines.js +116 -0
  180. package/dist/core/config/schema/feedback.js +31 -0
  181. package/dist/core/config/schema/improve-processes.js +395 -0
  182. package/dist/core/config/schema/improve.js +76 -0
  183. package/dist/core/config/schema/index-config.js +183 -0
  184. package/dist/core/config/schema/output.js +15 -0
  185. package/dist/core/config/schema/primitives.js +94 -0
  186. package/dist/core/config/schema/search.js +30 -0
  187. package/dist/core/config/schema/setup.js +27 -0
  188. package/dist/core/config/schema/sources-bundles.js +164 -0
  189. package/dist/core/config/schema/workflow.js +29 -0
  190. package/dist/core/env-secret-ref.js +113 -8
  191. package/dist/core/errors.js +1 -1
  192. package/dist/core/events-types.js +4 -0
  193. package/dist/core/extra-params.js +1 -0
  194. package/dist/core/file-change.js +16 -0
  195. package/dist/core/fs-txn.js +316 -0
  196. package/dist/core/git-message.js +59 -0
  197. package/dist/core/improve-result.js +9 -1
  198. package/dist/core/logs-db.js +1 -1
  199. package/dist/core/maintenance-barrier.js +16 -0
  200. package/dist/core/migration-backup.js +332 -160
  201. package/dist/core/paths.js +3 -6
  202. package/dist/core/platform.js +10 -0
  203. package/dist/core/recognition-util.js +130 -0
  204. package/dist/core/redaction.js +2 -2
  205. package/dist/core/standards/resolve-standards-context.js +47 -64
  206. package/dist/core/standards/resolve-type-conventions.js +3 -3
  207. package/dist/core/state/migrations.js +201 -8
  208. package/dist/core/state-db.js +38 -2
  209. package/dist/core/subprocess.js +303 -0
  210. package/dist/core/time.js +20 -0
  211. package/dist/core/type-presentation.js +130 -0
  212. package/dist/core/write-source.js +39 -67
  213. package/dist/indexer/bundle-identity-guard.js +91 -0
  214. package/dist/indexer/db/graph-db.js +1 -1
  215. package/dist/indexer/db/llm-cache.js +1 -1
  216. package/dist/indexer/ensure-index.js +29 -9
  217. package/dist/indexer/graph/graph-boost.js +28 -24
  218. package/dist/indexer/graph/graph-extraction.js +5 -6
  219. package/dist/indexer/graph/graph-types.js +4 -0
  220. package/dist/indexer/index-written-assets.js +44 -17
  221. package/dist/indexer/indexer.js +289 -153
  222. package/dist/indexer/init.js +18 -25
  223. package/dist/indexer/installations.js +224 -0
  224. package/dist/indexer/passes/dir-staleness.js +2 -1
  225. package/dist/indexer/passes/memory-inference.js +8 -4
  226. package/dist/indexer/passes/metadata.js +96 -243
  227. package/dist/indexer/scan/doc-to-entry.js +123 -0
  228. package/dist/indexer/scan/drain-dir.js +144 -0
  229. package/dist/indexer/search/db-search.js +171 -99
  230. package/dist/indexer/search/fts-query.js +1 -1
  231. package/dist/indexer/search/ranking-contributors.js +57 -7
  232. package/dist/indexer/search/ranking-types.js +4 -0
  233. package/dist/indexer/search/ranking.js +31 -6
  234. package/dist/indexer/search/search-attribution.js +67 -0
  235. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  236. package/dist/indexer/search/search-source.js +109 -52
  237. package/dist/indexer/search/semantic-status.js +4 -1
  238. package/dist/indexer/usage/unmigrated-vaults-guard.js +2 -1
  239. package/dist/indexer/usage/usage-events.js +72 -9
  240. package/dist/indexer/walk/file-context.js +1 -44
  241. package/dist/indexer/walk/matchers.js +16 -32
  242. package/dist/indexer/walk/path-resolver.js +6 -5
  243. package/dist/indexer/walk/walker.js +4 -2
  244. package/dist/integrations/agent/engine-resolution.js +22 -0
  245. package/dist/integrations/agent/model-aliases.js +1 -1
  246. package/dist/integrations/agent/prompts.js +35 -11
  247. package/dist/integrations/agent/spawn.js +41 -270
  248. package/dist/integrations/harnesses/aider/agent-builder.js +2 -2
  249. package/dist/integrations/harnesses/aider/index.js +2 -11
  250. package/dist/integrations/harnesses/amazonq/agent-builder.js +1 -9
  251. package/dist/integrations/harnesses/amazonq/index.js +3 -16
  252. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  253. package/dist/integrations/harnesses/claude/index.js +1 -12
  254. package/dist/integrations/harnesses/claude/session-log.js +27 -65
  255. package/dist/integrations/harnesses/codex/agent-builder.js +1 -2
  256. package/dist/integrations/harnesses/codex/index.js +2 -12
  257. package/dist/integrations/harnesses/copilot/agent-builder.js +2 -3
  258. package/dist/integrations/harnesses/copilot/index.js +1 -12
  259. package/dist/integrations/harnesses/gemini/agent-builder.js +1 -3
  260. package/dist/integrations/harnesses/gemini/index.js +1 -12
  261. package/dist/integrations/harnesses/ids.js +24 -0
  262. package/dist/integrations/harnesses/index.js +27 -2
  263. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  264. package/dist/integrations/harnesses/opencode/index.js +1 -12
  265. package/dist/integrations/harnesses/opencode/session-log.js +67 -110
  266. package/dist/integrations/harnesses/opencode-sdk/harness.js +2 -11
  267. package/dist/integrations/harnesses/openhands/agent-builder.js +3 -3
  268. package/dist/integrations/harnesses/openhands/index.js +2 -11
  269. package/dist/integrations/harnesses/pi/agent-builder.js +3 -11
  270. package/dist/integrations/harnesses/pi/index.js +3 -15
  271. package/dist/integrations/harnesses/shared.js +17 -0
  272. package/dist/integrations/harnesses/types.js +37 -2
  273. package/dist/integrations/lockfile.js +36 -0
  274. package/dist/integrations/session-logs/index.js +21 -12
  275. package/dist/integrations/session-logs/provider-base.js +113 -0
  276. package/dist/llm/client.js +7 -5
  277. package/dist/llm/embedders/deterministic.js +2 -2
  278. package/dist/llm/embedders/remote.js +8 -4
  279. package/dist/llm/graph-extract.js +7 -2
  280. package/dist/llm/metadata-enhance.js +43 -26
  281. package/dist/llm/structured-call.js +15 -7
  282. package/dist/migrate/legacy/config-source-migration.js +223 -0
  283. package/dist/migrate/legacy/content-migration.js +305 -0
  284. package/dist/migrate/legacy/legacy-layout.js +779 -0
  285. package/dist/migrate/legacy/legacy-paths.js +25 -0
  286. package/dist/migrate/legacy/legacy-stash-json.js +72 -0
  287. package/dist/migrate/legacy/proposal-fs-import.js +168 -0
  288. package/dist/migrate/legacy/task-target-ref-migration.js +272 -0
  289. package/dist/migrate/legacy/three-db-cutover.js +840 -0
  290. package/dist/migrate/legacy/workflow-migrations-bodies.js +52 -0
  291. package/dist/migrate/legacy/workflow-migrations-frozen.js +21 -0
  292. package/dist/migrate/legacy-ref-grammar.js +209 -0
  293. package/dist/output/command-registry.js +27 -0
  294. package/dist/output/html-render.js +11 -16
  295. package/dist/output/renderers.js +32 -276
  296. package/dist/output/shapes/passthrough.js +3 -9
  297. package/dist/output/shapes/registry.js +12 -6
  298. package/dist/output/text/command-format.js +547 -0
  299. package/dist/output/text/helpers.js +15 -1377
  300. package/dist/output/text/proposal-format.js +230 -0
  301. package/dist/output/text/registry.js +12 -6
  302. package/dist/output/text/show-directives.js +107 -0
  303. package/dist/output/text/show-format.js +103 -0
  304. package/dist/output/text/workflow-format.js +345 -0
  305. package/dist/output/text.js +1 -3
  306. package/dist/registry/build-index.js +13 -17
  307. package/dist/registry/providers/static-index.js +2 -2
  308. package/dist/registry/resolve.js +4 -90
  309. package/dist/registry/semver.js +93 -0
  310. package/dist/runtime.js +90 -0
  311. package/dist/schemas/akm-config.json +2956 -14890
  312. package/dist/schemas/akm-task.json +2 -2
  313. package/dist/schemas/akm-workflow.json +2 -2
  314. package/dist/scripts/migrate-storage.js +2312 -19642
  315. package/dist/setup/detect.js +5 -7
  316. package/dist/setup/engine-config.js +2 -1
  317. package/dist/setup/registry-stash-loader.js +1 -1
  318. package/dist/setup/semantic-assets.js +12 -9
  319. package/dist/setup/setup.js +109 -39
  320. package/dist/setup/steps/connection-shared.js +120 -0
  321. package/dist/setup/steps/connection.js +50 -274
  322. package/dist/setup/steps/platforms.js +1 -0
  323. package/dist/setup/steps/sources.js +13 -6
  324. package/dist/setup/steps/stashdir.js +5 -2
  325. package/dist/sources/freshness.js +39 -0
  326. package/dist/sources/providers/git-provider.js +29 -33
  327. package/dist/sources/providers/git-stash.js +10 -5
  328. package/dist/sources/providers/provider-utils.js +40 -18
  329. package/dist/sources/providers/website.js +1 -1
  330. package/dist/sources/resolve.js +5 -5
  331. package/dist/sources/snapshot-fetchers/types.js +4 -0
  332. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +105 -39
  333. package/dist/storage/database.js +47 -3
  334. package/dist/storage/engines/sqlite-migrations.js +34 -16
  335. package/dist/storage/locations.js +1 -2
  336. package/dist/storage/repositories/improve-runs-repository.js +0 -20
  337. package/dist/storage/repositories/index-connection.js +80 -0
  338. package/dist/storage/repositories/index-db.js +4 -3
  339. package/dist/storage/repositories/index-entries-repository.js +952 -0
  340. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +15 -2
  341. package/dist/storage/repositories/index-entry-types.js +4 -0
  342. package/dist/storage/repositories/index-fts-repository.js +164 -0
  343. package/dist/storage/repositories/index-llm-cache-repository.js +109 -0
  344. package/dist/storage/repositories/index-meta-repository.js +50 -0
  345. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +241 -100
  346. package/dist/storage/repositories/index-sql.js +12 -0
  347. package/dist/storage/repositories/index-utility-repository.js +369 -0
  348. package/dist/storage/repositories/index-vec-repository.js +245 -0
  349. package/dist/storage/repositories/proposals-repository.js +41 -50
  350. package/dist/storage/repositories/registry-cache.js +1 -1
  351. package/dist/storage/repositories/workflow-runs-repository.js +17 -11
  352. package/dist/tasks/backends/cron.js +5 -5
  353. package/dist/tasks/backends/exec-utils.js +21 -0
  354. package/dist/tasks/backends/index.js +6 -9
  355. package/dist/tasks/backends/launchd.js +16 -17
  356. package/dist/tasks/backends/schtasks.js +33 -41
  357. package/dist/tasks/backends/types.js +4 -0
  358. package/dist/tasks/parser.js +25 -5
  359. package/dist/tasks/runner.js +33 -39
  360. package/dist/tasks/validator.js +5 -6
  361. package/dist/workflows/authoring/authoring.js +8 -11
  362. package/dist/workflows/exec/brief.js +10 -7
  363. package/dist/workflows/exec/report.js +261 -156
  364. package/dist/workflows/exec/run-workflow.js +2 -1
  365. package/dist/workflows/exec/step-work.js +3 -9
  366. package/dist/workflows/program/parser.js +4 -60
  367. package/dist/workflows/renderer.js +11 -60
  368. package/dist/workflows/runtime/checkin.js +1 -1
  369. package/dist/workflows/runtime/plan-classifier.js +7 -4
  370. package/dist/workflows/runtime/runs.js +11 -10
  371. package/dist/workflows/runtime/unit-checkin.js +1 -1
  372. package/dist/workflows/runtime/unit-phases.js +20 -0
  373. package/dist/workflows/runtime/workflow-asset-loader.js +27 -16
  374. package/dist/workflows/validate-summary.js +2 -2
  375. package/dist/workflows/validator.js +18 -2
  376. package/docs/migration/release-notes/0.9.0.md +45 -3
  377. package/docs/migration/v0.8-to-v0.9.md +466 -262
  378. package/docs/{data-and-telemetry.md → reference/data-and-telemetry.md} +61 -17
  379. package/package.json +10 -9
  380. package/schemas/akm-config.json +2956 -14890
  381. package/schemas/akm-task.json +2 -2
  382. package/schemas/akm-workflow.json +2 -2
  383. package/dist/assets/help/help-accept.md +0 -12
  384. package/dist/assets/help/help-improve.md +0 -84
  385. package/dist/assets/help/help-proposals.md +0 -17
  386. package/dist/assets/help/help-propose.md +0 -17
  387. package/dist/assets/help/help-reject.md +0 -11
  388. package/dist/assets/improve-strategies/recombine-only.json +0 -23
  389. package/dist/assets/improve-strategies/synthesize.json +0 -17
  390. package/dist/assets/prompts/procedural-system.md +0 -44
  391. package/dist/assets/prompts/recombine-system.md +0 -40
  392. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  393. package/dist/assets/templates/html/default.html +0 -78
  394. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  395. package/dist/assets/wiki/index-template.md +0 -12
  396. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  397. package/dist/assets/wiki/log-template.md +0 -8
  398. package/dist/assets/wiki/schema-template.md +0 -61
  399. package/dist/commands/improve/calibration.js +0 -161
  400. package/dist/commands/improve/dedup.js +0 -482
  401. package/dist/commands/improve/hot-probation.js +0 -45
  402. package/dist/commands/improve/improve-auto-accept.js +0 -262
  403. package/dist/commands/improve/procedural.js +0 -403
  404. package/dist/commands/improve/recombine.js +0 -843
  405. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  406. package/dist/commands/lint/agent-linter.js +0 -44
  407. package/dist/commands/lint/command-linter.js +0 -44
  408. package/dist/commands/lint/default-linter.js +0 -16
  409. package/dist/commands/lint/fact-linter.js +0 -39
  410. package/dist/commands/lint/knowledge-linter.js +0 -16
  411. package/dist/commands/lint/memory-linter.js +0 -61
  412. package/dist/commands/lint/registry.js +0 -41
  413. package/dist/commands/lint/skill-linter.js +0 -45
  414. package/dist/commands/lint/task-linter.js +0 -50
  415. package/dist/commands/lint/workflow-linter.js +0 -81
  416. package/dist/commands/proposal/legacy-import.js +0 -115
  417. package/dist/commands/wiki-cli.js +0 -291
  418. package/dist/core/asset/asset-registry.js +0 -76
  419. package/dist/core/asset/asset-spec.js +0 -316
  420. package/dist/core/eval/rank-metrics.js +0 -113
  421. package/dist/core/ripgrep/install.js +0 -163
  422. package/dist/core/ripgrep/resolve.js +0 -81
  423. package/dist/indexer/db/db.js +0 -1585
  424. package/dist/indexer/manifest.js +0 -170
  425. package/dist/indexer/passes/metadata-contributors.js +0 -31
  426. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
  427. package/dist/output/text/wiki.js +0 -16
  428. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -18228
  429. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  430. package/dist/storage/repositories/consolidation-repository.js +0 -38
  431. package/dist/storage/repositories/recombine-repository.js +0 -213
  432. package/dist/wiki/wiki-templates.js +0 -15
  433. package/dist/wiki/wiki.js +0 -1013
  434. package/dist/workflows/db.js +0 -413
  435. package/docs/README.md +0 -103
  436. package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
  437. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  438. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -18,35 +18,9 @@ import fs from "node:fs";
18
18
  import os from "node:os";
19
19
  import path from "node:path";
20
20
  import { parseEmbeddedJsonResponse } from "../../core/parse.js";
21
- import { spawn as runtimeSpawn } from "../../runtime.js";
21
+ import { runManagedSubprocess, } from "../../core/subprocess.js";
22
22
  import { getCommandBuilder } from "./builders.js";
23
23
  import { DEFAULT_AGENT_TIMEOUT_MS } from "./config.js";
24
- /**
25
- * Kill the process group of `proc` with `signal`, falling back to
26
- * `proc.kill(signal)` when `proc.pid` is unavailable (e.g. test fakes).
27
- *
28
- * Passing a negative PID to `process.kill` targets the entire process
29
- * group, so opencode's child processes (the .opencode binary, etc.) are
30
- * reaped alongside the node wrapper. The fallback keeps test fakes working
31
- * without modification.
32
- */
33
- function killGroup(proc, signal) {
34
- if (typeof proc.pid === "number") {
35
- try {
36
- process.kill(-proc.pid, signal);
37
- return;
38
- }
39
- catch {
40
- // Process may have already exited; fall through to direct kill.
41
- }
42
- }
43
- try {
44
- proc.kill(signal);
45
- }
46
- catch {
47
- /* ignore */
48
- }
49
- }
50
24
  const DEFAULT_TIMEOUT_MS = DEFAULT_AGENT_TIMEOUT_MS;
51
25
  /**
52
26
  * Supplement `existingPath` with well-known user binary directories when
@@ -102,14 +76,6 @@ function pathCandidatesForCurrentPlatform(home) {
102
76
  "/usr/local/bin",
103
77
  ];
104
78
  }
105
- function resolveSpawnFn(options) {
106
- if (options.spawn)
107
- return options.spawn;
108
- // Default to the runtime-boundary spawn, which delegates to the native
109
- // subprocess API on each runtime. Tests inject `options.spawn` to avoid
110
- // poking real binaries.
111
- return runtimeSpawn;
112
- }
113
79
  /**
114
80
  * Build the child env. Starts empty and copies through:
115
81
  * • Every name in `profile.envPassthrough`.
@@ -143,80 +109,6 @@ function buildChildEnv(profile, options) {
143
109
  }
144
110
  return env;
145
111
  }
146
- const STREAM_READ_TIMEOUT = Symbol("stream-read-timeout");
147
- async function readStream(stream, opts) {
148
- if (!stream)
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
- }
176
- // Race the stream read against a timeout so a process that is killed via
177
- // SIGTERM/SIGKILL but whose pipe endpoints stay open (e.g. background
178
- // threads still holding the fd) cannot block the caller indefinitely.
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;
183
- const timeoutPromise = new Promise((resolve) => {
184
- timer = setTimeoutImpl(() => {
185
- timer = undefined;
186
- resolve(STREAM_READ_TIMEOUT);
187
- }, opts.timeoutMs);
188
- if (typeof timer !== "number")
189
- timer.unref?.();
190
- });
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
112
  function streamFailureMessage(profileName, stdout, stderr) {
221
113
  const failures = [];
222
114
  if (stdout.error)
@@ -300,159 +192,43 @@ export async function runAgent(profile, prompt, options = {}) {
300
192
  error: `agent CLI "${profile.name}" not started: caller signal already aborted`,
301
193
  };
302
194
  }
303
- let proc;
304
- try {
305
- const spawnFn = resolveSpawnFn(options);
306
- proc = spawnFn(finalArgv, {
307
- stdin: stdioMode === "captured" ? (options.stdin !== undefined ? "pipe" : "ignore") : "inherit",
308
- stdout: stdioMode === "captured" ? "pipe" : "inherit",
309
- stderr: stdioMode === "captured" ? "pipe" : "inherit",
310
- env,
311
- ...(options.cwd ? { cwd: options.cwd } : {}),
312
- // Spawn in its own process group so killGroup(-pid, signal) reaches all
313
- // descendants (e.g. the .opencode binary that opencode's node wrapper forks).
314
- // Only applied in captured mode — interactive mode inherits the parent
315
- // terminal's process group intentionally.
316
- ...(stdioMode === "captured" ? { detached: true } : {}),
317
- });
318
- }
319
- catch (err) {
320
- const durationMs = Date.now() - start;
321
- return {
322
- ok: false,
323
- exitCode: null,
324
- stdout: "",
325
- stderr: "",
326
- durationMs,
327
- reason: "spawn_failed",
328
- error: err instanceof Error ? err.message : String(err),
329
- };
330
- }
331
- emitSpawnEvent("spawn_start", {
332
- profile: profile.name,
333
- ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
334
- });
335
- // Hard timeout. We prefer SIGTERM, then SIGKILL if SIGTERM is ignored,
336
- // but the subprocess only exposes a single .kill() — one signal is enough
337
- // for the structured-failure contract.
195
+ // Spawn/timeout/abort/capture are owned by the managed-subprocess primitive
196
+ // (src/core/subprocess.ts): process-GROUP spawn (detached in captured mode),
197
+ // the SIGTERM→SIGKILL kill ladder on timeout/abort, bounded output capture,
198
+ // and the optional stdin payload. runAgent keeps its agent-specific surface —
199
+ // the onEvent observability seam, the failure taxonomy, and JSON parsing.
338
200
  //
339
- // BUG-M3: only flag `timedOut` when the child has not already exited. A
340
- // timer firing in the same microtask as `proc.exited` resolving could
341
- // otherwise label a clean exit as a timeout.
342
- //
343
- // When timeoutMs is null the kill timer is skipped entirely — the task runs
344
- // until the process exits naturally. Intended for long-running local-model
345
- // tasks where wall-clock time is unpredictable.
346
- let timedOut = false;
347
- let timer;
348
- if (timeoutMs !== null) {
349
- timer = setTimeoutImpl(() => {
350
- if (!proc || proc.exitCode !== null)
351
- return;
352
- timedOut = true;
353
- killGroup(proc, "SIGTERM");
354
- // Follow up with SIGKILL after 5 s in case the process ignores SIGTERM.
355
- const sigkillTimer = setTimeoutImpl(() => {
356
- if (!proc || proc.exitCode !== null)
357
- return;
358
- killGroup(proc, "SIGKILL");
359
- }, 5000);
360
- if (typeof sigkillTimer !== "number")
361
- sigkillTimer.unref?.();
362
- }, timeoutMs);
363
- }
364
- // Cooperative cancel: same SIGTERM→SIGKILL discipline as the timeout, but
365
- // flagged separately so the result carries `reason: "aborted"`.
366
- let aborted = false;
367
- const abortSignal = options.signal;
368
- const onAbort = () => {
369
- if (!proc || proc.exitCode !== null)
370
- return;
371
- aborted = true;
372
- killGroup(proc, "SIGTERM");
373
- const sigkillTimer = setTimeoutImpl(() => {
374
- if (!proc || proc.exitCode !== null)
375
- return;
376
- killGroup(proc, "SIGKILL");
377
- }, 5000);
378
- if (typeof sigkillTimer !== "number")
379
- sigkillTimer.unref?.();
380
- };
381
- if (abortSignal) {
382
- // A signal that aborted between the pre-spawn check and here is handled
383
- // by calling the listener directly.
384
- if (abortSignal.aborted)
385
- onAbort();
386
- else
387
- abortSignal.addEventListener("abort", onAbort, { once: true });
388
- }
389
- // Stream-drain timeout: the overall wall-clock budget plus a 2 s grace
390
- // period. When a process is killed via SIGTERM/SIGKILL (from our timeout
391
- // handler or from outside) some runtimes keep the pipe write-end open in
392
- // background threads, which would cause `Response.text()` to block forever.
393
- // Capping stream draining ensures the caller never hangs past the wall
394
- // budget regardless of subprocess pipe behaviour.
395
- // When there is no kill timer, allow up to 30 s for streams to drain.
396
- const streamDrainTimeoutMs = timeoutMs !== null ? timeoutMs + 2_000 : 30_000;
397
- const stdoutPromise = stdioMode === "captured"
398
- ? readStream(proc.stdout ?? null, {
399
- timeoutMs: streamDrainTimeoutMs,
400
- setTimeoutFn: setTimeoutImpl,
401
- clearTimeoutFn: clearTimeoutImpl,
402
- })
403
- : Promise.resolve({ text: "", timedOut: false });
404
- const stderrPromise = stdioMode === "captured"
405
- ? readStream(proc.stderr ?? null, {
406
- timeoutMs: streamDrainTimeoutMs,
407
- setTimeoutFn: setTimeoutImpl,
408
- clearTimeoutFn: clearTimeoutImpl,
409
- })
410
- : Promise.resolve({ text: "", timedOut: false });
411
- // Optional stdin payload (captured mode only).
412
- //
413
- // BUG-H1: race the stdin write/close against `proc.exited` and the
414
- // timeout timer. If the child never drains stdin, an unraced
415
- // `await writer.write()` would block forever and prevent `runAgent`
416
- // from ever returning.
417
- if (options.stdin !== undefined && stdioMode === "captured" && proc.stdin) {
418
- const stdinPayload = options.stdin;
419
- const stdinStream = proc.stdin;
420
- const stdinDone = (async () => {
421
- try {
422
- const writer = stdinStream.getWriter();
423
- const bytes = new TextEncoder().encode(stdinPayload);
424
- await writer.write(bytes);
425
- await writer.close();
426
- }
427
- catch {
428
- // Best-effort: ignore stdin write failures, the child will get EOF.
429
- }
430
- })();
431
- // Resolve as soon as either the write completes or the child exits.
432
- // We don't await the result — only that one of the two has settled —
433
- // so a stuck writer cannot keep us pinned past the timeout.
434
- await Promise.race([stdinDone, proc.exited.catch(() => undefined)]);
435
- }
436
- let exitCode = null;
437
- try {
438
- exitCode = await proc.exited;
439
- }
440
- catch (err) {
441
- if (timer !== undefined)
442
- clearTimeoutImpl(timer);
443
- abortSignal?.removeEventListener("abort", onAbort);
444
- // BUG-H2: drain stream readers before the early return so they don't
445
- // surface as unhandled rejections after the function resolves.
446
- // The streams already carry a built-in drain timeout so this allSettled
447
- // will not block indefinitely.
448
- await Promise.allSettled([stdoutPromise, stderrPromise]);
449
- const durationMs = Date.now() - start;
450
- emitSpawnEvent("spawn_exit", {
451
- profile: profile.name,
452
- ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
453
- exitCode: null,
454
- status: "spawn_failed",
455
- });
201
+ // `onSpawn` fires spawn_start once the child is live (never for a pre-spawn
202
+ // abort or a synchronous spawn failure), and captures the proc so spawn_exit
203
+ // can carry the same pid.
204
+ let spawnedProc;
205
+ const result = await runManagedSubprocess(finalArgv, {
206
+ capture: stdioMode === "captured",
207
+ env,
208
+ ...(options.cwd ? { cwd: options.cwd } : {}),
209
+ ...(options.stdin !== undefined ? { stdin: options.stdin } : {}),
210
+ timeoutMs,
211
+ ...(options.signal ? { signal: options.signal } : {}),
212
+ ...(options.spawn ? { spawnFn: options.spawn } : {}),
213
+ setTimeoutFn: setTimeoutImpl,
214
+ clearTimeoutFn: clearTimeoutImpl,
215
+ onSpawn: (proc) => {
216
+ spawnedProc = proc;
217
+ emitSpawnEvent("spawn_start", {
218
+ profile: profile.name,
219
+ ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
220
+ });
221
+ },
222
+ });
223
+ const pidField = spawnedProc && typeof spawnedProc.pid === "number" ? { pid: spawnedProc.pid } : {};
224
+ const durationMs = Date.now() - start;
225
+ // Spawn/exit failure. A synchronous spawn throw never reached a live child
226
+ // (no spawn_start fired, so no spawn_exit either); a rejected proc.exited did
227
+ // (spawn_start already fired, so it emits a spawn_exit with status spawn_failed).
228
+ if (result.spawnError) {
229
+ if (spawnedProc) {
230
+ emitSpawnEvent("spawn_exit", { profile: profile.name, ...pidField, exitCode: null, status: "spawn_failed" });
231
+ }
456
232
  return {
457
233
  ok: false,
458
234
  exitCode: null,
@@ -460,21 +236,16 @@ export async function runAgent(profile, prompt, options = {}) {
460
236
  stderr: "",
461
237
  durationMs,
462
238
  reason: "spawn_failed",
463
- error: err instanceof Error ? err.message : String(err),
239
+ error: result.spawnError.message,
464
240
  };
465
241
  }
466
- clearTimeoutImpl(timer);
467
- abortSignal?.removeEventListener("abort", onAbort);
242
+ const { exitCode, timedOut, aborted, stdout, stderr } = result;
468
243
  emitSpawnEvent("spawn_exit", {
469
244
  profile: profile.name,
470
- ...(typeof proc.pid === "number" ? { pid: proc.pid } : {}),
245
+ ...pidField,
471
246
  exitCode,
472
247
  status: aborted ? "aborted" : timedOut ? "timeout" : exitCode !== 0 ? "non_zero_exit" : "ok",
473
248
  });
474
- const [stdoutRead, stderrRead] = await Promise.all([stdoutPromise, stderrPromise]);
475
- const stdout = stdoutRead.text;
476
- const stderr = stderrRead.text;
477
- const durationMs = Date.now() - start;
478
249
  if (aborted) {
479
250
  return {
480
251
  ok: false,
@@ -497,7 +268,7 @@ export async function runAgent(profile, prompt, options = {}) {
497
268
  error: `agent CLI "${profile.name}" timed out after ${timeoutMs ?? 0}ms`,
498
269
  };
499
270
  }
500
- const captureFailure = streamFailureMessage(profile.name, stdoutRead, stderrRead);
271
+ const captureFailure = streamFailureMessage(profile.name, result.stdoutRead, result.stderrRead);
501
272
  if (captureFailure) {
502
273
  return {
503
274
  ok: false,
@@ -52,7 +52,7 @@
52
52
  * therefore dropped rather than approximated — never silently widened.
53
53
  * - **resume/session** — NOT expressible: Aider persists context in
54
54
  * chat-history files (`.aider.chat.history.md`), not session ids, so there
55
- * is no flag-shaped `HarnessResumeSupport` to export and the extractor
55
+ * is no flag-shaped resume to describe and the extractor
56
56
  * never yields a `sessionId`. akm's `workflow_run_units` remains the
57
57
  * durable source of truth; resume works even against a harness with no
58
58
  * session model (plan §"Session, MCP, and identity across harnesses" —
@@ -62,7 +62,7 @@
62
62
  *
63
63
  * NOT registered anywhere: `builders.ts` / `harnesses/index.ts` wiring is a
64
64
  * follow-up integration task (as is the registry entry declaring
65
- * `structuredOutput: "none"` and no `resume`). Exported standalone so that
65
+ * `structuredOutput: "none"`). Exported standalone so that
66
66
  * task only adds a registry entry.
67
67
  */
68
68
  import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
@@ -12,21 +12,12 @@
12
12
  * `HARNESS_REGISTRY` registers. Dispatch-only: no native session-log reader or
13
13
  * config importer yet.
14
14
  */
15
+ import { caps } from "../shared.js";
15
16
  import { BaseHarness } from "../types.js";
16
17
  import { aiderBuilder } from "./agent-builder.js";
17
18
  import { aiderResultExtractor } from "./result-extractor.js";
18
19
  export { AIDER_PLATFORM, aiderBuilder } from "./agent-builder.js";
19
20
  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
- ...c,
28
- };
29
- }
30
21
  /**
31
22
  * Aider.
32
23
  *
@@ -44,7 +35,7 @@ export class AiderHarness extends BaseHarness {
44
35
  // No structured-output mode at all (the matrix's "none — parse output"):
45
36
  // akm injects the schema into the prompt and extracts embedded JSON.
46
37
  structuredOutput = "none";
47
- // No `resume`: Aider persists context in chat-history files
38
+ // No flag-shaped resume: Aider persists context in chat-history files
48
39
  // (`.aider.chat.history.md`), not session ids — the plan's named example of
49
40
  // a harness with no session model. akm's `workflow_run_units` remains the
50
41
  // durable resume source of truth.
@@ -11,8 +11,7 @@
11
11
  *
12
12
  * q chat --no-interactive --trust-all-tools "<prompt>"
13
13
  *
14
- * with `--model <m>` for model selection and `--resume` for resume. Resume is
15
- * registry-side (`AkmHarness.resume`, {@link AMAZONQ_RESUME_FLAG}) — and NOTE:
14
+ * with `--model <m>` for model selection and `--resume` for resume NOTE:
16
15
  * unlike every other harness's resume, Q's `--resume` is a bare flag that
17
16
  * replays the previous conversation *of the working directory*; it takes no
18
17
  * session id. There is nothing to thread from `workflow_run_units` — akm's own
@@ -63,13 +62,6 @@
63
62
  import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
64
63
  /** Canonical harness/platform id used for model-alias resolution. */
65
64
  export const AMAZONQ_PLATFORM = "amazonq";
66
- /**
67
- * Resume flag per the capability matrix (`--resume`). Exported for the
68
- * integration task's `AkmHarness.resume` registry entry. Bare flag: Q resumes
69
- * the previous conversation of the current working directory and takes NO
70
- * session id value — do not append one after it.
71
- */
72
- export const AMAZONQ_RESUME_FLAG = "--resume";
73
65
  /**
74
66
  * Split a tool policy into individual tool names for `--trust-tools`.
75
67
  * Strings are comma-separated lists; arrays are taken as-is. Structured
@@ -13,21 +13,12 @@
13
13
  * that `HARNESS_REGISTRY` registers. Dispatch-only: no native session-log
14
14
  * reader or config importer yet.
15
15
  */
16
+ import { caps } from "../shared.js";
16
17
  import { BaseHarness } from "../types.js";
17
- import { AMAZONQ_RESUME_FLAG, amazonqBuilder } from "./agent-builder.js";
18
+ import { amazonqBuilder } from "./agent-builder.js";
18
19
  import { amazonqResultExtractor } from "./result-extractor.js";
19
- export { AMAZONQ_PLATFORM, AMAZONQ_RESUME_FLAG, amazonqBuilder } from "./agent-builder.js";
20
+ export { AMAZONQ_PLATFORM, amazonqBuilder } from "./agent-builder.js";
20
21
  export { amazonqResultExtractor, stripTerminalFraming } from "./result-extractor.js";
21
- function caps(c) {
22
- return {
23
- sessionLogs: false,
24
- agentDispatch: false,
25
- detection: false,
26
- configImport: false,
27
- runtimeIdentity: false,
28
- ...c,
29
- };
30
- }
31
22
  /**
32
23
  * Amazon Q Developer CLI (`q`).
33
24
  *
@@ -45,10 +36,6 @@ export class AmazonqHarness extends BaseHarness {
45
36
  // No documented structured output: akm injects the schema into the prompt
46
37
  // and extracts embedded JSON from plain-text stdout.
47
38
  structuredOutput = "none";
48
- // Q's `--resume` is a BARE flag (takesSessionId: false): it replays the
49
- // previous conversation of the working directory and takes no session id
50
- // (see AMAZONQ_RESUME_FLAG in ./agent-builder.ts).
51
- resume = { flag: AMAZONQ_RESUME_FLAG, takesSessionId: false };
52
39
  // No `identityEnv`: the matrix lists Q's identity markers as uncertain, and
53
40
  // Q stamps no session var onto child processes.
54
41
  capabilities = caps({
@@ -15,9 +15,7 @@
15
15
  */
16
16
  import fs from "node:fs";
17
17
  import path from "node:path";
18
- function homeDir() {
19
- return process.env.HOME ?? process.env.USERPROFILE ?? "";
20
- }
18
+ import { homeDir } from "../shared.js";
21
19
  /**
22
20
  * Imports LLM config from a Claude Code installation.
23
21
  *
@@ -1,6 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import { caps } from "../shared.js";
4
5
  import { BaseHarness } from "../types.js";
5
6
  import { claudeBuilder } from "./agent-builder.js";
6
7
  import { claudeResultExtractor } from "./result-extractor.js";
@@ -9,16 +10,6 @@ export { claudeBuilder } from "./agent-builder.js";
9
10
  export { claudeCodeImporter } from "./config-import.js";
10
11
  export { claudeResultExtractor } from "./result-extractor.js";
11
12
  export { ClaudeCodeProvider } from "./session-log.js";
12
- function caps(c) {
13
- return {
14
- sessionLogs: false,
15
- agentDispatch: false,
16
- detection: false,
17
- configImport: false,
18
- runtimeIdentity: false,
19
- ...c,
20
- };
21
- }
22
13
  /**
23
14
  * Claude Code.
24
15
  *
@@ -50,8 +41,6 @@ export class ClaudeHarness extends BaseHarness {
50
41
  // but that is a different surface than the dispatch builder — the descriptor
51
42
  // is aligned to what the builder honestly does.)
52
43
  structuredOutput = "native-json";
53
- // `claude --resume <sessionId>` replays a previous session in headless mode.
54
- resume = { flag: "--resume", takesSessionId: true };
55
44
  // Session-id env marker: presence of a concrete session id (not the bare
56
45
  // "running under Claude Code" flag) attributes a run to this harness.
57
46
  identityEnv = ["CLAUDE_SESSION_ID"];
@@ -5,6 +5,7 @@ import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
8
+ import { AbstractSessionLogProvider } from "../../session-logs/provider-base.js";
8
9
  /**
9
10
  * Root directory holding Claude Code's per-project JSONL session logs.
10
11
  *
@@ -100,12 +101,12 @@ function parseClaudeEvent(entry, sessionId, filePath, fallbackTsMs) {
100
101
  * (`getHarness`), and the `--type` flag accepts both, so the canonical id and
101
102
  * the persisted runtime string coexist without drift.
102
103
  */
103
- export class ClaudeCodeProvider {
104
+ export class ClaudeCodeProvider extends AbstractSessionLogProvider {
104
105
  // Runtime identity (NOT the canonical id) — see class doc. Equals
105
106
  // HARNESS_BY_ID.get("claude").runtimeId.
106
107
  name = "claude-code";
107
- isAvailable() {
108
- return fs.existsSync(claudeProjectsDir());
108
+ availabilityRoot() {
109
+ return claudeProjectsDir();
109
110
  }
110
111
  /**
111
112
  * Directory holding Claude Code's per-project session JSONL files
@@ -124,25 +125,13 @@ export class ClaudeCodeProvider {
124
125
  if (stat.mtimeMs < input.sinceMs)
125
126
  continue;
126
127
  const lines = fs.readFileSync(jsonlPath, "utf8").split("\n").filter(Boolean);
127
- for (const line of lines) {
128
- try {
129
- const entry = JSON.parse(line);
130
- const text = entry?.message?.content ?? entry?.content ?? "";
131
- if (typeof text !== "string" || text.length < 10)
132
- continue;
133
- yield {
134
- harness: this.name,
135
- text,
136
- ts: typeof entry?.timestamp === "number" ? entry.timestamp : stat.mtimeMs,
137
- sessionId: typeof entry?.session_id === "string" ? entry.session_id : undefined,
138
- role: typeof entry?.role === "string" ? entry.role : "unknown",
139
- filePath: jsonlPath,
140
- };
141
- }
142
- catch {
143
- // skip malformed lines
144
- }
145
- }
128
+ yield* this.logLineEvents({
129
+ lines,
130
+ filePath: jsonlPath,
131
+ fallbackTsMs: stat.mtimeMs,
132
+ selectText: (entry) => entry?.message?.content ?? entry?.content ?? "",
133
+ selectSessionId: (entry) => entry?.session_id,
134
+ });
146
135
  }
147
136
  }
148
137
  catch {
@@ -151,39 +140,23 @@ export class ClaudeCodeProvider {
151
140
  }
152
141
  listSessions(input = {}) {
153
142
  const root = input.location ?? claudeProjectsDir();
154
- const sinceMs = input.sinceMs ?? 0;
155
- const summaries = [];
156
- try {
157
- for (const jsonlPath of this.#walkJsonl(root)) {
158
- let stat;
159
- try {
160
- stat = fs.statSync(jsonlPath);
161
- }
162
- catch {
163
- continue;
164
- }
165
- if (stat.mtimeMs < sinceMs)
166
- continue;
167
- const sessionId = path.basename(jsonlPath, ".jsonl");
168
- const projectHint = path.basename(path.dirname(jsonlPath));
143
+ return this.listSessionsFromFiles({
144
+ sinceMs: input.sinceMs ?? 0,
145
+ enumerate: () => this.#walkJsonl(root),
146
+ summarize: (jsonlPath, stat) => {
169
147
  // Peek first + last non-empty line to derive start/end timestamps and
170
148
  // title. Reading the whole file would be wasteful for listing.
171
149
  const peek = this.#peekJsonl(jsonlPath);
172
- summaries.push({
173
- harness: this.name,
174
- sessionId,
150
+ return this.sessionRef({
151
+ sessionId: path.basename(jsonlPath, ".jsonl"),
175
152
  filePath: jsonlPath,
176
153
  startedAt: peek.firstTsMs ?? stat.ctimeMs,
177
154
  endedAt: peek.lastTsMs ?? stat.mtimeMs,
178
- projectHint,
179
- ...(peek.title ? { title: peek.title } : {}),
155
+ projectHint: path.basename(path.dirname(jsonlPath)),
156
+ title: peek.title,
180
157
  });
181
- }
182
- }
183
- catch {
184
- // Root missing or unreadable — return what we have.
185
- }
186
- return summaries.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
158
+ },
159
+ });
187
160
  }
188
161
  readSession(ref) {
189
162
  const stat = fs.statSync(ref.filePath);
@@ -220,15 +193,14 @@ export class ClaudeCodeProvider {
220
193
  inlineRefs.push(...extractInlineRefMentions(parsed.text, parsed.ts));
221
194
  }
222
195
  return {
223
- ref: {
224
- harness: this.name,
196
+ ref: this.sessionRef({
225
197
  sessionId: ref.sessionId,
226
198
  filePath: ref.filePath,
227
199
  startedAt: firstTsMs ?? stat.ctimeMs,
228
200
  endedAt: lastTsMs ?? stat.mtimeMs,
229
201
  projectHint,
230
- ...(title ? { title } : {}),
231
- },
202
+ title,
203
+ }),
232
204
  events,
233
205
  inlineRefs,
234
206
  };
@@ -302,18 +274,8 @@ export class ClaudeCodeProvider {
302
274
  }
303
275
  return result;
304
276
  }
305
- *#walkJsonl(dir) {
306
- try {
307
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
308
- const full = path.join(dir, entry.name);
309
- if (entry.isDirectory())
310
- yield* this.#walkJsonl(full);
311
- else if (entry.name.endsWith(".jsonl") && entry.name !== "journal.jsonl")
312
- yield full;
313
- }
314
- }
315
- catch {
316
- // permission errors etc.
317
- }
277
+ /** Session JSONL files under `dir`, excluding the shared journal file. */
278
+ #walkJsonl(dir) {
279
+ return this.walkFiles(dir, (name) => name.endsWith(".jsonl") && name !== "journal.jsonl");
318
280
  }
319
281
  }