akm-cli 0.9.0-rc.8 → 0.9.0

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 (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -10,9 +10,6 @@
10
10
  */
11
11
  import { SCRIPT_EXTENSIONS } from "../../core/recognition-util.js";
12
12
  import { presentationFor } from "../../core/type-presentation.js";
13
- import { looksLikeWorkflow } from "../../workflows/parser.js";
14
- import { looksLikeWorkflowProgram } from "../../workflows/program/parser.js";
15
- import { WORKFLOW_PROGRAM_RENDERER_NAME } from "../../workflows/program/project.js";
16
13
  // ---------------------------------------------------------------------------
17
14
  // Private data
18
15
  // ---------------------------------------------------------------------------
@@ -37,6 +34,18 @@ const DIR_TYPE_MAP = [
37
34
  type: "knowledge",
38
35
  test: (ext) => ext === ".md",
39
36
  },
37
+ {
38
+ // R-045 / Q-18 second half (owner ruling 11) — stash-resident `instruction`
39
+ // assets live under `instructions/`, mirroring the `knowledge` rule. This
40
+ // is a walker discovery rule for FILES ON DISK under a stash's
41
+ // `instructions/` dir; it is unrelated to the adapter-emitted root
42
+ // CLAUDE.md/AGENTS.md instruction docs (`tool-dir-shared.ts`), which are
43
+ // synthesized by format-family adapters, carry `ownsPresentation: true`,
44
+ // and never pass through this matcher at all.
45
+ dir: "instructions",
46
+ type: "instruction",
47
+ test: (ext) => ext === ".md",
48
+ },
40
49
  {
41
50
  dir: "workflows",
42
51
  type: "workflow",
@@ -102,6 +111,9 @@ const TYPED_DIR_DOC_FILES = new Set(["readme.md"]);
102
111
  function isTypedDirDocFile(fileName) {
103
112
  return TYPED_DIR_DOC_FILES.has(fileName.toLowerCase());
104
113
  }
114
+ function isNestedSkillResource(ctx) {
115
+ return ctx.ancestorDirs[0] === "skills" && ctx.ancestorDirs.length > 1 && ctx.fileName !== "SKILL.md";
116
+ }
105
117
  // ---------------------------------------------------------------------------
106
118
  // Private helpers
107
119
  // ---------------------------------------------------------------------------
@@ -132,6 +144,8 @@ function classifyByExtension(ctx) {
132
144
  return null;
133
145
  }
134
146
  function classifyByDirectory(ctx) {
147
+ if (isNestedSkillResource(ctx))
148
+ return null;
135
149
  for (const dir of ctx.ancestorDirs) {
136
150
  const result = matchDirectoryHint(dir, ctx, 10);
137
151
  if (result)
@@ -141,6 +155,8 @@ function classifyByDirectory(ctx) {
141
155
  }
142
156
  function classifyByParentDirHint(ctx) {
143
157
  const { parentDir, ext, fileName } = ctx;
158
+ if (isNestedSkillResource(ctx))
159
+ return null;
144
160
  if (parentDir === "skills" && (fileName === "SKILL.md" || ext === ".md")) {
145
161
  return { type: "skill", specificity: 15 };
146
162
  }
@@ -162,12 +178,19 @@ function classifyBySmartMd(ctx) {
162
178
  return { type: "knowledge", specificity: 5 };
163
179
  }
164
180
  const body = ctx.content();
165
- if (looksLikeWorkflow(body)) {
181
+ const fm = ctx.frontmatter();
182
+ // Recognition is frontmatter `type: workflow` or residence under `workflows/`
183
+ // (workflow-format-unification, spec §2.5) — no content sniffing. The
184
+ // directory rule is `classifyByDirectory`/`classifyByParentDirHint`'s job;
185
+ // this only catches a workflow living OUTSIDE `workflows/` that still
186
+ // declares its type explicitly.
187
+ if (fm && fm.type === "workflow") {
166
188
  return { type: "workflow", specificity: 19 };
167
189
  }
168
- const fm = ctx.frontmatter();
169
190
  if (fm) {
170
- if ("toolPolicy" in fm || "tools" in fm) {
191
+ // `tools` is the one authoring key for an agent's tool grant. Recognition
192
+ // covers only the key the renderer honors.
193
+ if ("tools" in fm) {
171
194
  return { type: "agent", specificity: 20 };
172
195
  }
173
196
  if ("agent" in fm) {
@@ -182,35 +205,6 @@ function classifyBySmartMd(ctx) {
182
205
  }
183
206
  return { type: "knowledge", specificity: 5 };
184
207
  }
185
- /** YAML workflow *programs* (redesign addendum, R1): `.yaml`/`.yml` files. */
186
- const WORKFLOW_PROGRAM_EXTENSIONS = new Set([".yaml", ".yml"]);
187
- /**
188
- * Classify YAML workflow programs. Two claims, mirroring the markdown rules:
189
- *
190
- * - any `.yaml`/`.yml` under a `workflows/` dir (the directory rule —
191
- * specificity 15 when `workflows` is the immediate parent, 10 for a
192
- * deeper ancestor, same ladder as `matchDirectoryHint`);
193
- * - anywhere else, a content probe via `looksLikeWorkflowProgram`
194
- * (`version: 1` + `steps:` at column 0) at specificity 19, the same
195
- * level as `classifyBySmartMd`'s `looksLikeWorkflow` claim.
196
- *
197
- * The fact does NOT go through `toMatchResult` — the workflow TYPE maps to
198
- * the markdown renderer by default, so this classifier names the
199
- * `workflow-program-yaml` renderer on its result directly.
200
- */
201
- function classifyByWorkflowProgram(ctx) {
202
- if (!WORKFLOW_PROGRAM_EXTENSIONS.has(ctx.ext))
203
- return null;
204
- if (isTypedDirDocFile(ctx.fileName))
205
- return null;
206
- if (ctx.parentDir === "workflows")
207
- return { type: "workflow", specificity: 15 };
208
- if (ctx.ancestorDirs.includes("workflows"))
209
- return { type: "workflow", specificity: 10 };
210
- if (looksLikeWorkflowProgram(ctx.content()))
211
- return { type: "workflow", specificity: 19 };
212
- return null;
213
- }
214
208
  // ---------------------------------------------------------------------------
215
209
  // Adapter: MatchFact → MatchResult
216
210
  // ---------------------------------------------------------------------------
@@ -246,14 +240,7 @@ export function parentDirHintMatcher(ctx) {
246
240
  export function smartMdMatcher(ctx) {
247
241
  return toMatchResult(ctx, classifyBySmartMd);
248
242
  }
249
- export function workflowProgramMatcher(ctx) {
250
- const fact = classifyByWorkflowProgram(ctx);
251
- if (!fact)
252
- return null;
253
- // Named directly (not via rendererNameFor) — see classifyByWorkflowProgram.
254
- return { type: fact.type, specificity: fact.specificity, renderer: WORKFLOW_PROGRAM_RENDERER_NAME };
255
- }
256
- // The five matcher functions above are consumed directly by the akm adapter's
243
+ // The four matcher functions above are consumed directly by the akm adapter's
257
244
  // synchronous `recognizeMatch()` (`core/adapter/adapters/akm-adapter.ts`, which
258
245
  // holds the same registration-order array for tie-breaking). The chunk-3 cutover
259
246
  // removed the file-context matcher registry, so there is no `registerBuiltinMatchers`
@@ -10,11 +10,16 @@ import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
10
10
  import { lookup } from "../indexer.js";
11
11
  import { resolveSourceEntries } from "../search/search-source.js";
12
12
  function normalizeRef(ref) {
13
- // Stored/resolved refs may still be in the legacy spelling → dual parser.
13
+ // String inputs use the current `[bundle//]conceptId` grammar.
14
14
  return typeof ref === "string" ? parseRefInput(ref) : ref;
15
15
  }
16
16
  function buildDiskCandidates(sourcePath, ref, preserveDirectNameFallback) {
17
- const typeDir = path.join(sourcePath, stashDirFor(ref.type) ?? `${ref.type}s`);
17
+ const placementStashDir = stashDirFor(ref.type);
18
+ // Opaque adapter conceptIds are index-resolved. Core cannot infer their
19
+ // adapter-owned serialization or path extension before indexing.
20
+ if (placementStashDir === undefined)
21
+ return [];
22
+ const typeDir = path.join(sourcePath, placementStashDir);
18
23
  const candidates = [
19
24
  assetPathForName(ref.type, typeDir, ref.name),
20
25
  path.join(sourcePath, ref.type, `${ref.name}.md`),
@@ -13,7 +13,8 @@ import path from "node:path";
13
13
  import { isRelevantAssetFile } from "../../core/asset/asset-placement.js";
14
14
  import { spawnSync } from "../../runtime.js";
15
15
  import { buildFileContext } from "./file-context.js";
16
- const SKIP_DIRS = new Set([".git", "node_modules", "bin", ".cache"]);
16
+ const ALWAYS_SKIP_DIRS = new Set([".git"]);
17
+ const AKM_SKIP_DIRS = new Set(["node_modules", "bin", ".cache"]);
17
18
  /**
18
19
  * Walk a type root directory and return files grouped by their parent directory.
19
20
  *
@@ -62,21 +63,24 @@ export function walkStash(typeRoot, assetType) {
62
63
  * Otherwise falls back to a manual walk that skips .git, node_modules, bin,
63
64
  * .cache, dot-directories, and the legacy metadata sidecar.
64
65
  */
65
- export function walkStashFlat(stashRoot) {
66
+ export function walkStashFlat(stashRoot, options = {}) {
67
+ return walkStashFlatWithStatus(stashRoot, options).files;
68
+ }
69
+ export function walkStashFlatWithStatus(stashRoot, options = {}) {
66
70
  if (!fs.existsSync(stashRoot))
67
- return [];
71
+ return { files: [], complete: false };
68
72
  // Try git-based walk first (respects .gitignore)
69
- const gitResult = walkStashGit(stashRoot);
73
+ const gitResult = walkStashGit(stashRoot, options);
70
74
  if (gitResult)
71
75
  return gitResult;
72
76
  // Fallback: manual walk
73
- return walkStashManual(stashRoot);
77
+ return walkStashManual(stashRoot, options);
74
78
  }
75
79
  /**
76
80
  * Walk using `git ls-files` to respect .gitignore.
77
81
  * Returns null if the directory is not a git repo or git fails.
78
82
  */
79
- function walkStashGit(stashRoot) {
83
+ function walkStashGit(stashRoot, options) {
80
84
  // Quick check: is this a git repo? Look for .git in this dir or parents.
81
85
  if (!isInsideGitRepo(stashRoot))
82
86
  return null;
@@ -87,6 +91,15 @@ function walkStashGit(stashRoot) {
87
91
  // result.success is false if the process exited non-zero OR git was not found
88
92
  if (!result.success)
89
93
  return null;
94
+ // `--cached` includes tracked files deleted from the worktree. They are not
95
+ // scan failures and must not make an otherwise complete snapshot look stale.
96
+ const deletedResult = spawnSync(["git", "ls-files", "--deleted", "-z", "--", "."], { cwd: stashRoot });
97
+ if (!deletedResult.success)
98
+ return null;
99
+ const deletedStdout = Buffer.isBuffer(deletedResult.stdout)
100
+ ? deletedResult.stdout.toString("utf8")
101
+ : String(deletedResult.stdout ?? "");
102
+ const deletedFiles = new Set(deletedStdout.split("\0").filter(Boolean));
90
103
  // Data-hygiene filename skips: the legacy metadata sidecar (never indexed as
91
104
  // content — Chunk-8 folds it into the bundle format) plus git dot-files.
92
105
  const SKIP_FILES = new Set([".stash.json", ".gitignore", ".gitattributes"]);
@@ -94,16 +107,19 @@ function walkStashGit(stashRoot) {
94
107
  const files = stdout
95
108
  .split("\0")
96
109
  .filter((f) => f.length > 0)
110
+ .filter((f) => !deletedFiles.has(f))
97
111
  .filter((f) => !f.startsWith("..") && !path.isAbsolute(f))
98
112
  .filter((f) => {
99
113
  const dirParts = path
100
114
  .dirname(f)
101
115
  .split(/[\\/]+/)
102
116
  .filter(Boolean);
103
- return !dirParts.some((part) => SKIP_DIRS.has(part) || part.startsWith("."));
117
+ return !dirParts.some((part) => ALWAYS_SKIP_DIRS.has(part) ||
118
+ (!options.includeAllDirectories && (AKM_SKIP_DIRS.has(part) || part.startsWith("."))));
104
119
  })
105
120
  .filter((f) => !SKIP_FILES.has(path.basename(f)));
106
121
  const results = [];
122
+ let complete = true;
107
123
  for (const relFile of files) {
108
124
  const absPath = path.join(stashRoot, relFile);
109
125
  try {
@@ -113,9 +129,10 @@ function walkStashGit(stashRoot) {
113
129
  }
114
130
  catch {
115
131
  // File may have been deleted since git ls-files ran
132
+ complete = false;
116
133
  }
117
134
  }
118
- return results;
135
+ return { files: results, complete };
119
136
  }
120
137
  /**
121
138
  * Check if a directory is inside a git repository by walking up to find .git.
@@ -176,14 +193,22 @@ export function* walkMarkdownFiles(root) {
176
193
  }
177
194
  }
178
195
  /** Manual walk for non-git directories. */
179
- function walkStashManual(stashRoot) {
196
+ function walkStashManual(stashRoot, options) {
180
197
  const results = [];
198
+ let complete = true;
181
199
  const stack = [stashRoot];
182
200
  while (stack.length > 0) {
183
201
  const current = stack.pop();
184
202
  if (!current)
185
203
  continue;
186
- const entries = fs.readdirSync(current, { withFileTypes: true });
204
+ let entries;
205
+ try {
206
+ entries = fs.readdirSync(current, { withFileTypes: true });
207
+ }
208
+ catch {
209
+ complete = false;
210
+ continue;
211
+ }
187
212
  for (const entry of entries) {
188
213
  if (entry.name === ".stash.json")
189
214
  continue;
@@ -193,7 +218,8 @@ function walkStashManual(stashRoot) {
193
218
  continue;
194
219
  }
195
220
  if (entry.isDirectory()) {
196
- if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
221
+ if (ALWAYS_SKIP_DIRS.has(entry.name) ||
222
+ (!options.includeAllDirectories && (AKM_SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))))
197
223
  continue;
198
224
  stack.push(fullPath);
199
225
  }
@@ -202,5 +228,5 @@ function walkStashManual(stashRoot) {
202
228
  }
203
229
  }
204
230
  }
205
- return results;
231
+ return { files: results, complete };
206
232
  }
@@ -14,12 +14,6 @@
14
14
  */
15
15
  import { ConfigError } from "../../core/errors.js";
16
16
  import { HARNESS_REGISTRY } from "../harnesses/index.js";
17
- export { assertNotFlag, normalizeTools } from "./builder-shared.js";
18
- // ── Platform builders ─────────────────────────────────────────────────────────
19
- // The OpenCode builder was migrated to its harness directory in #564
20
- // (`harnesses/opencode/agent-builder.ts`) and the Claude Code builder in #563
21
- // (`harnesses/claude/agent-builder.ts`). Both are imported back into
22
- // BUILTIN_BUILDERS below so platform routing is unchanged.
23
17
  // ── Registry ──────────────────────────────────────────────────────────────────
24
18
  /**
25
19
  * DERIVED from `HARNESS_REGISTRY` (P0.5 registry-drift fix): each harness that
@@ -1,7 +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
- /** Default hard timeout for an agent CLI when neither engine nor call overrides it. */
5
- export const DEFAULT_AGENT_TIMEOUT_MS = 60_000;
4
+ /** Default agent CLI timeout; null means agents run until they finish. */
5
+ export const DEFAULT_AGENT_TIMEOUT_MS = null;
6
6
  /** Default hard timeout for direct LLM calls when no engine/use override exists. */
7
7
  export const DEFAULT_LLM_TIMEOUT_MS = 600_000;
@@ -15,26 +15,34 @@
15
15
  */
16
16
  import fs from "node:fs";
17
17
  import path from "node:path";
18
- import { getBuiltinAgentProfile, listBuiltinAgentProfiles } from "./profiles.js";
18
+ import { getBuiltinAgentProfile, listBuiltinAgentProfiles, OPENCODE_SDK_SERVER_BIN, } from "./profiles.js";
19
19
  /**
20
20
  * Default PATH lookup. Walks `process.env.PATH` and returns the first
21
21
  * existing executable file. Returns `undefined` when the bin is not on
22
22
  * PATH or the env is empty.
23
23
  *
24
- * `process.env.PATH` is split on the platform-correct delimiter; on
25
- * Windows the binary may have an executable extension, but for v1 we
26
- * keep this Unix-flavoured (Bun's primary target) and look for an exact
27
- * match.
24
+ * `process.env.PATH` is split on the platform-correct delimiter. On Windows
25
+ * agent CLIs install as extension-bearing shims (`claude.cmd`, `q.exe`), so
26
+ * each PATH entry is probed for the bare name AND for `<bin><ext>` over
27
+ * PATHEXT — an exact-match-only probe reports every agent CLI as missing
28
+ * there, which silently hides the "installed CLI agent" option during setup.
28
29
  */
29
30
  export function defaultWhich(bin, envSource = process.env) {
31
+ // Computed once per call — not per PATH entry — since it never varies.
32
+ const suffixes = executableSuffixes(envSource);
30
33
  if (!bin || bin.includes("/") || bin.includes("\\")) {
31
34
  // Absolute / relative paths: caller already specified location.
32
- try {
33
- return fs.statSync(bin).isFile() ? bin : undefined;
34
- }
35
- catch {
36
- return undefined;
35
+ for (const suffix of suffixes) {
36
+ const candidate = bin + suffix;
37
+ try {
38
+ if (fs.statSync(candidate).isFile())
39
+ return candidate;
40
+ }
41
+ catch {
42
+ /* try the next extension */
43
+ }
37
44
  }
45
+ return undefined;
38
46
  }
39
47
  const pathVar = envSource.PATH ?? envSource.Path ?? envSource.path ?? "";
40
48
  if (!pathVar)
@@ -43,18 +51,40 @@ export function defaultWhich(bin, envSource = process.env) {
43
51
  for (const dir of pathVar.split(sep)) {
44
52
  if (!dir)
45
53
  continue;
46
- const candidate = path.join(dir, bin);
47
- try {
48
- const st = fs.statSync(candidate);
49
- if (st.isFile())
50
- return candidate;
51
- }
52
- catch {
53
- /* keep walking */
54
+ const base = path.join(dir, bin);
55
+ for (const suffix of suffixes) {
56
+ const candidate = base + suffix;
57
+ try {
58
+ const st = fs.statSync(candidate);
59
+ if (st.isFile())
60
+ return candidate;
61
+ }
62
+ catch {
63
+ /* keep walking */
64
+ }
54
65
  }
55
66
  }
56
67
  return undefined;
57
68
  }
69
+ /** Windows PATHEXT default, used when the env carries no explicit list. */
70
+ const DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
71
+ /**
72
+ * Executable suffixes to try for each candidate path, bare name (`""`) first
73
+ * so POSIX resolution is byte-for-byte unchanged. Extensions are appended only
74
+ * on win32 or when the env supplies PATHEXT (which is also the seam tests use
75
+ * to cover Windows resolution from a POSIX runner).
76
+ */
77
+ function executableSuffixes(envSource) {
78
+ const pathext = envSource.PATHEXT ?? envSource.Pathext ?? envSource.pathext;
79
+ if (process.platform !== "win32" && !pathext)
80
+ return [""];
81
+ const exts = (pathext ?? DEFAULT_PATHEXT)
82
+ .split(";")
83
+ .map((ext) => ext.trim())
84
+ .filter(Boolean)
85
+ .map((ext) => (ext.startsWith(".") ? ext : `.${ext}`));
86
+ return ["", ...exts];
87
+ }
58
88
  let detectOverrides;
59
89
  /** TEST-ONLY. Swap the detection implementations; pass undefined to restore. */
60
90
  export function _setAgentDetectForTests(fakes) {
@@ -79,7 +109,7 @@ export function detectAgentCliProfiles(agent, whichFn = defaultWhich) {
79
109
  profilesByName.set(name, {
80
110
  name,
81
111
  platform: engine.platform,
82
- bin: engine.bin ?? builtin?.bin ?? (engine.platform === "opencode-sdk" ? "opencode" : engine.platform),
112
+ bin: engine.bin ?? builtin?.bin ?? (engine.platform === "opencode-sdk" ? OPENCODE_SDK_SERVER_BIN : engine.platform),
83
113
  args: engine.args ?? builtin?.args ?? [],
84
114
  stdio: "captured",
85
115
  envPassthrough: builtin?.envPassthrough ?? [],
@@ -0,0 +1,76 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import { defaultWhich } from "./detect.js";
5
+ import { OPENCODE_SDK_SERVER_BIN } from "./profiles.js";
6
+ /**
7
+ * Engine name used for the synthesized entry. Matches the platform id so it
8
+ * reads correctly in `akm workflow status`, frozen plans, and error messages.
9
+ * A user-configured engine of the same name is preferred over synthesizing.
10
+ */
11
+ export const FALLBACK_ENGINE_NAME = "opencode-sdk";
12
+ /** Announcement text, surfaced once per run/dispatch. */
13
+ export const FALLBACK_ANNOUNCEMENT = `No engine is configured; falling back to \`${FALLBACK_ENGINE_NAME}\` via the ` +
14
+ `\`${OPENCODE_SDK_SERVER_BIN}\` binary on PATH — provider, model, and auth come ` +
15
+ "from opencode's own configuration. " +
16
+ "Run `akm setup`, or set `defaults.engine`, to choose explicitly.";
17
+ /**
18
+ * Failure suffix for every surface that needs an engine and found none.
19
+ * Owned HERE, beside the probe whose outcome it describes: the probe follows a
20
+ * configured `bin` when one is pinned, so a consumer restating "not on PATH"
21
+ * would misdescribe a missing absolute path.
22
+ */
23
+ export const NO_ENGINE_MESSAGE_SUFFIX = `has no selected engine, and no usable \`${OPENCODE_SDK_SERVER_BIN}\` binary was found to fall back to.`;
24
+ /**
25
+ * Guidance used when the fallback itself is unavailable.
26
+ *
27
+ * The opencode route names a BINARY install, not `npm i @opencode-ai/sdk`:
28
+ * that package is an HTTP client with no dependencies and cannot serve
29
+ * anything on its own (see the module doc).
30
+ */
31
+ export const NO_ENGINE_REMEDY = "Run `akm setup` to detect an installed agent, or set one explicitly: " +
32
+ '`akm config set engines.claude \'{"kind":"agent","platform":"claude"}\'` ' +
33
+ "then `akm config set defaults.engine claude`. " +
34
+ `Installing the \`${OPENCODE_SDK_SERVER_BIN}\` binary also works ` +
35
+ "(`npm i -g opencode-ai`) — akm falls back to it automatically.";
36
+ /**
37
+ * Return a config whose `defaults.engine` resolves, applying the implicit
38
+ * `opencode-sdk` fallback when it does not and an opencode binary is present.
39
+ *
40
+ * Pure with respect to the input: never mutates `config`. Returns the input
41
+ * object identity unchanged when no fallback is needed, so callers can cheaply
42
+ * detect the common case.
43
+ */
44
+ export function withEngineFallback(config, whichFn = defaultWhich) {
45
+ if (config.defaults?.engine)
46
+ return { config };
47
+ // An operator-configured engine of this name wins over a synthesized one —
48
+ // theirs may carry a model, an llmEngine fallback, or a pinned bin. Probe
49
+ // THAT bin rather than the bare command: a configured absolute path outside
50
+ // PATH is still a usable engine, and reporting it as missing would contradict
51
+ // the operator-configured-wins rule.
52
+ const existing = config.engines?.[FALLBACK_ENGINE_NAME];
53
+ if (!whichFn(existing?.bin ?? OPENCODE_SDK_SERVER_BIN))
54
+ return { config };
55
+ const engines = existing
56
+ ? config.engines
57
+ : { ...(config.engines ?? {}), [FALLBACK_ENGINE_NAME]: { kind: "agent", platform: "opencode-sdk" } };
58
+ return {
59
+ config: {
60
+ ...config,
61
+ engines,
62
+ defaults: { ...(config.defaults ?? {}), engine: FALLBACK_ENGINE_NAME },
63
+ },
64
+ fallbackEngineName: FALLBACK_ENGINE_NAME,
65
+ };
66
+ }
67
+ /**
68
+ * The announcement, but only when the fallback candidate is the engine that
69
+ * actually won selection. Returns `undefined` otherwise, so an explicitly
70
+ * selected engine never triggers a claim that opencode supplied the model.
71
+ */
72
+ export function fallbackAnnouncement(fallbackEngineName, selectedEngineName) {
73
+ if (!fallbackEngineName || selectedEngineName !== fallbackEngineName)
74
+ return undefined;
75
+ return FALLBACK_ANNOUNCEMENT;
76
+ }
@@ -91,6 +91,20 @@ const BUILTINS = {
91
91
  parseOutput: "text",
92
92
  },
93
93
  };
94
+ /**
95
+ * Binary the `opencode-sdk` harness needs on PATH.
96
+ *
97
+ * The embedded SDK is not self-contained, and that is the SDK's own design
98
+ * rather than a consequence of how akm drives it: `@opencode-ai/sdk` ships
99
+ * with `"dependencies": {}` and its `createOpencodeServer` is itself a
100
+ * `spawn("opencode", ["serve", ...])`. akm's runner spawns the same binary
101
+ * directly and talks HTTP to it (see `harnesses/opencode-sdk/sdk-runner.ts`),
102
+ * so the `opencode` binary gates the SDK path exactly as it gates the CLI
103
+ * path — a host with the npm package but no binary can dispatch neither.
104
+ * `opencode-sdk` deliberately has no {@link BUILTINS} entry — it dispatches
105
+ * without argv construction — so this is the one place that pairing lives.
106
+ */
107
+ export const OPENCODE_SDK_SERVER_BIN = "opencode";
94
108
  /** Names of the canonical built-in harness descriptors. Stable, sorted. */
95
109
  export const BUILTIN_AGENT_PROFILE_NAMES = Object.freeze(Object.keys(BUILTINS).sort());
96
110
  /** Returns the built-in descriptor for a canonical harness id. */
@@ -12,11 +12,11 @@
12
12
  * `src/integrations/agent/` rather than `src/llm/` is deliberate: these are
13
13
  * shell-out prompts targeting an agent CLI, not in-tree LLM API calls.
14
14
  *
15
- * The legacy stdout output an agent must produce is a *strict* JSON object:
15
+ * The stdout output an agent must produce is a strict JSON object:
16
16
  *
17
17
  * ```json
18
18
  * {
19
- * "ref": "lesson:my-lesson",
19
+ * "ref": "lessons/my-lesson",
20
20
  * "content": "---\ndescription: ...\nwhen_to_use: ...\n---\n\nbody",
21
21
  * "frontmatter": { "description": "...", "when_to_use": "..." }
22
22
  * }
@@ -29,6 +29,7 @@ import reflectLlmFramedContract from "../../assets/prompts/reflect-llm-framed-co
29
29
  import reflectLlmSchemaContract from "../../assets/prompts/reflect-llm-schema-contract.md" with { type: "text" };
30
30
  import reflectOutputRepair from "../../assets/prompts/reflect-output-repair.md" with { type: "text" };
31
31
  import { placementTypes } from "../../core/asset/asset-placement.js";
32
+ import { parseRefInput } from "../../core/asset/resolve-ref.js";
32
33
  import { authoringRulesForType, DESCRIPTION_MAX_CHARS, DESCRIPTION_MIN_CHARS, requiresDescription, } from "../../core/authoring-rules.js";
33
34
  import { parseEmbeddedJsonResponse, stripCodeFences, stripThinkBlocks } from "../../core/parse.js";
34
35
  /**
@@ -45,7 +46,7 @@ const TYPE_HINTS = {
45
46
  memory: "memory assets are short factual notes the user wants persisted across sessions. Frontmatter usually includes `description`.",
46
47
  workflow: "workflow assets are markdown describing a multi-step process. Include `# <Title>` and ordered `## Step N` sections.",
47
48
  script: "script assets are executable text files. Include a shebang and minimal usage comment.",
48
- env: "env assets are `.env` files holding a group of related CONFIGURATION for an app/service (KEY=VALUE pairs, `#` comments) — URLs, flags, and any credentials it needs. Values may or may not be sensitive; all are protected (key names discoverable, values stay on disk). Inject with `akm env run env:<name> -- <cmd>`; prefer `--clean` in agent contexts so the child starts from a minimal inherited environment. AKM itself does not print values, but the child command can print its environment, so do not run `env`, `printenv`, shell tracing, or similar diagnostics when secrets are in scope. For a single sensitive value used on its own for authentication (token, key, cert) use a `secret` instead. Never echo values back to the user.",
49
+ env: "env assets are `.env` files holding a group of related CONFIGURATION for an app/service (KEY=VALUE pairs, `#` comments) — URLs, flags, and any credentials it needs. Values may or may not be sensitive; all are protected (key names discoverable, values stay on disk). Inject with `akm env run env/<name> -- <cmd>`; prefer `--clean` in agent contexts so the child starts from a minimal inherited environment. AKM itself does not print values, but the child command can print its environment, so do not run `env`, `printenv`, shell tracing, or similar diagnostics when secrets are in scope. For a single sensitive value used on its own for authentication (token, key, cert) use a `secret` instead. Never echo values back to the user.",
49
50
  wiki: "wiki assets are markdown reference pages with `# Title` and structured headings.",
50
51
  fact: "fact assets are durable stash-level facts (personal/team/project details, coding conventions, stash-meta). Frontmatter SHOULD include `description` and a `category` (personal|team|project|convention|meta); set `pinned: true` only for the small always-injected core. Keep each fact short, high-signal, and self-contained — it is durable context, not an episodic note.",
51
52
  };
@@ -63,7 +64,10 @@ function knownTypeList() {
63
64
  */
64
65
  const RESPONSE_CONTRACT_JSON = [
65
66
  "Respond ONLY with a single JSON object. No prose before or after.",
66
- 'Shape: {"ref": "<type>:<name>", "content": "<full file contents>", "frontmatter": {...}, "confidence": <number 0..1>}',
67
+ // Slash conceptId, not the retired `<type>:<name>` colon grammar (Q-02/Q-08).
68
+ // This contract is the schema an agent copies from, so a stale spelling here
69
+ // teaches every proposal to use a ref form the CLI now rejects outright.
70
+ 'Shape: {"ref": "<type>/<name>", "content": "<full file contents>", "frontmatter": {...}, "confidence": <number 0..1>}',
67
71
  "`content` is the full file body that will be written if accepted.",
68
72
  "`frontmatter` is optional — include it if `content` starts with `---` so reviewers can sanity-check the keys.",
69
73
  "`confidence` is REQUIRED. Self-rate this proposal on [0, 1] by how certain you are it materially improves the source asset. Calibrate honestly:",
@@ -174,7 +178,7 @@ export function buildReflectPrompt(input) {
174
178
  const goalSentence = isLesson
175
179
  ? `Your task is to distill what usage signals reveal about this ${input.type} asset — when to reach for it, what goes wrong without it, and what real use has revealed that the asset itself does not say. Do not reproduce the source content; your proposal must add information the source does not contain.`
176
180
  : isSkill
177
- ? "Your task is to review this skill asset, identify what the feedback and related distilled lessons show is broken, missing, unclear, or durable enough to promote into long-term documentation, and produce a single improved proposal. If the strongest evidence points to companion reference material rather than the main SKILL.md, you may instead propose a skill-adjacent knowledge doc such as `knowledge:skills/<skill>/references/<topic>`."
181
+ ? "Your task is to review this skill asset, identify what the feedback and related distilled lessons show is broken, missing, unclear, or durable enough to promote into long-term documentation, and produce a single improved proposal. If the strongest evidence points to companion reference material rather than the main SKILL.md, you may instead propose a skill-adjacent knowledge doc such as `knowledge/skills/<skill>/references/<topic>`."
178
182
  : `Your task is to review this ${input.type} asset, identify what the feedback signals as broken, missing, or unclear, and produce an improved version. Do not reproduce the source content unchanged; your proposal must correct or add something the source lacks.`;
179
183
  sections.push(goalSentence);
180
184
  sections.push(`Target ref: ${input.ref}`);
@@ -210,7 +214,7 @@ export function buildReflectPrompt(input) {
210
214
  sections.push(input.standardsContext.trim());
211
215
  }
212
216
  {
213
- const resolvedType = input.type ?? (input.ref?.includes(":") ? input.ref.split(":")[0] : "");
217
+ const resolvedType = input.type ?? (input.ref ? parseRefInput(input.ref).type : "");
214
218
  const authoringRules = resolvedType ? authoringRulesForType(resolvedType) : "";
215
219
  if (authoringRules) {
216
220
  sections.push(authoringRules);
@@ -268,7 +272,7 @@ export function buildReflectPrompt(input) {
268
272
  }
269
273
  sections.push("Evaluate whether these lessons contain strong evidence of factual, repeatable guidance that should be promoted into long-term skill documentation.");
270
274
  sections.push("Promote only guidance that is durable, generally applicable, and supported by repeated evidence. Do not copy anecdotal details, one-off incidents, or duplicate wording verbatim.");
271
- sections.push("If the guidance belongs in the main skill instructions, update the skill proposal. If it belongs in a companion reference document, return a `knowledge:skills/<skill>/references/<topic>` proposal instead.");
275
+ sections.push("If the guidance belongs in the main skill instructions, update the skill proposal. If it belongs in a companion reference document, return a `knowledge/skills/<skill>/references/<topic>` proposal instead.");
272
276
  }
273
277
  if (input.rejectedProposals && input.rejectedProposals.length > 0) {
274
278
  const lines = ["## Previously Rejected Proposals"];
@@ -423,7 +427,7 @@ export function buildSchemaRepairPrompt(input) {
423
427
  * can map to {@link AgentFailureReason} `parse_error`.
424
428
  *
425
429
  * Resilient to two common local-LLM failure modes:
426
- * 1. `<think>…</think>` blocks emitted before the JSON (stripped by `stripJsonFences`).
430
+ * 1. `<think>…</think>` blocks emitted before the JSON (stripped before parsing).
427
431
  * 2. Prose preamble / postamble around the JSON object (handled by `extractEmbeddedJson`).
428
432
  */
429
433
  export function parseAgentProposalPayload(stdout) {
@@ -76,8 +76,10 @@ export function collectDispatchSensitiveValues(spec, opts, envSource = opts.envS
76
76
  add(value);
77
77
  }
78
78
  }
79
- for (const value of Object.values(opts.env ?? {}))
80
- add(value);
79
+ for (const [name, value] of Object.entries(opts.env ?? {})) {
80
+ if (!isEnvPassthroughValueSafeToExpose(name, value))
81
+ add(value);
82
+ }
81
83
  return collectSensitiveValues(values);
82
84
  }
83
85
  function redactResult(result, sensitiveValues) {
@@ -97,4 +97,3 @@ export function resolveImproveProcessRunner(strategy, processName, config) {
97
97
  timeoutMs: resolved.timeoutMs,
98
98
  };
99
99
  }
100
- export { isProcessEnabled } from "../../llm/feature-gate.js";
@@ -21,7 +21,6 @@ import { parseEmbeddedJsonResponse } from "../../core/parse.js";
21
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
- const DEFAULT_TIMEOUT_MS = DEFAULT_AGENT_TIMEOUT_MS;
25
24
  /**
26
25
  * Supplement `existingPath` with well-known user binary directories when
27
26
  * running in a scheduler context (cron/launchd) where PATH is stripped.
@@ -144,7 +143,7 @@ function streamFailureMessage(profileName, stdout, stderr) {
144
143
  export async function runAgent(profile, prompt, options = {}) {
145
144
  const stdioMode = options.stdio ?? profile.stdio;
146
145
  // null = explicitly disabled (no kill timer). undefined = runtime default.
147
- const timeoutMs = options.timeoutMs !== undefined ? options.timeoutMs : DEFAULT_TIMEOUT_MS;
146
+ const timeoutMs = options.timeoutMs !== undefined ? options.timeoutMs : DEFAULT_AGENT_TIMEOUT_MS;
148
147
  const parseOutput = options.parseOutput ?? profile.parseOutput;
149
148
  const setTimeoutImpl = options.setTimeoutFn ?? setTimeout;
150
149
  const clearTimeoutImpl = options.clearTimeoutFn ?? clearTimeout;
@@ -160,7 +159,7 @@ export async function runAgent(profile, prompt, options = {}) {
160
159
  }
161
160
  };
162
161
  // Build argv via the platform-specific builder when dispatch params are
163
- // provided; fall back to the legacy positional-prompt form otherwise.
162
+ // provided; otherwise use the direct positional-prompt form.
164
163
  let builtArgv;
165
164
  let builtEnv;
166
165
  if (options.dispatch !== undefined) {
@@ -170,10 +169,10 @@ export async function runAgent(profile, prompt, options = {}) {
170
169
  builtEnv = built.env;
171
170
  }
172
171
  else {
173
- const legacyArgs = [...profile.args, ...(options.args ?? [])];
172
+ const positionalArgs = [...profile.args, ...(options.args ?? [])];
174
173
  if (prompt !== undefined)
175
- legacyArgs.push(prompt);
176
- builtArgv = [profile.bin, ...legacyArgs];
174
+ positionalArgs.push(prompt);
175
+ builtArgv = [profile.bin, ...positionalArgs];
177
176
  }
178
177
  // Extra args (e.g. forwarded CLI positionals) are appended after the builder output.
179
178
  const finalArgv = [...builtArgv, ...(options.dispatch ? (options.args ?? []) : [])];