akm-cli 0.7.0-rc1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/dist/{src/cli.js → cli.js} +100 -16
  2. package/dist/{src/commands → commands}/config-cli.js +42 -0
  3. package/dist/{src/commands → commands}/history.js +78 -7
  4. package/dist/{src/commands → commands}/registry-search.js +69 -6
  5. package/dist/{src/commands → commands}/search.js +30 -3
  6. package/dist/{src/commands → commands}/show.js +29 -0
  7. package/dist/{src/commands → commands}/source-add.js +5 -1
  8. package/dist/{src/commands → commands}/source-manage.js +7 -1
  9. package/dist/{src/core → core}/config.js +28 -0
  10. package/dist/{src/indexer → indexer}/db-search.js +1 -0
  11. package/dist/{src/indexer → indexer}/indexer.js +16 -2
  12. package/dist/{src/indexer → indexer}/matchers.js +1 -1
  13. package/dist/{src/indexer → indexer}/search-source.js +4 -2
  14. package/dist/{src/integrations → integrations}/agent/profiles.js +1 -1
  15. package/dist/{src/integrations → integrations}/agent/spawn.js +67 -16
  16. package/dist/{src/integrations → integrations}/github.js +9 -3
  17. package/dist/{src/llm → llm}/embedders/remote.js +37 -3
  18. package/dist/{src/output → output}/cli-hints.js +15 -2
  19. package/dist/{src/output → output}/renderers.js +3 -1
  20. package/dist/{src/output → output}/shapes.js +8 -1
  21. package/dist/{src/output → output}/text.js +156 -3
  22. package/dist/{src/registry → registry}/build-index.js +5 -4
  23. package/dist/{src/registry → registry}/providers/static-index.js +3 -1
  24. package/dist/{src/setup → setup}/setup.js +9 -0
  25. package/dist/{src/wiki → wiki}/wiki.js +54 -6
  26. package/dist/{src/workflows → workflows}/runs.js +37 -3
  27. package/package.json +8 -8
  28. package/dist/tests/add-website-source.test.js +0 -119
  29. package/dist/tests/agent/agent-config-loader.test.js +0 -70
  30. package/dist/tests/agent/agent-config.test.js +0 -221
  31. package/dist/tests/agent/agent-detect.test.js +0 -100
  32. package/dist/tests/agent/agent-spawn.test.js +0 -234
  33. package/dist/tests/agent-output.test.js +0 -186
  34. package/dist/tests/architecture/agent-no-llm-sdk-guard.test.js +0 -103
  35. package/dist/tests/architecture/agent-spawn-seam.test.js +0 -193
  36. package/dist/tests/architecture/llm-stateless-seam.test.js +0 -112
  37. package/dist/tests/asset-ref.test.js +0 -192
  38. package/dist/tests/asset-registry.test.js +0 -103
  39. package/dist/tests/asset-spec.test.js +0 -241
  40. package/dist/tests/bench/attribution.test.js +0 -995
  41. package/dist/tests/bench/cleanup-sigint.test.js +0 -83
  42. package/dist/tests/bench/cleanup.js +0 -203
  43. package/dist/tests/bench/cleanup.test.js +0 -166
  44. package/dist/tests/bench/cli.js +0 -683
  45. package/dist/tests/bench/cli.test.js +0 -177
  46. package/dist/tests/bench/compare.test.js +0 -556
  47. package/dist/tests/bench/corpus.js +0 -314
  48. package/dist/tests/bench/corpus.test.js +0 -258
  49. package/dist/tests/bench/driver.js +0 -346
  50. package/dist/tests/bench/driver.test.js +0 -443
  51. package/dist/tests/bench/evolve-metrics.js +0 -179
  52. package/dist/tests/bench/evolve-metrics.test.js +0 -187
  53. package/dist/tests/bench/evolve.js +0 -580
  54. package/dist/tests/bench/evolve.test.js +0 -616
  55. package/dist/tests/bench/failure-modes.test.js +0 -300
  56. package/dist/tests/bench/feedback-integrity.test.js +0 -456
  57. package/dist/tests/bench/leakage.test.js +0 -125
  58. package/dist/tests/bench/learning-curve.test.js +0 -133
  59. package/dist/tests/bench/metrics.js +0 -2319
  60. package/dist/tests/bench/metrics.test.js +0 -1144
  61. package/dist/tests/bench/no-os-tmpdir-invariant.test.js +0 -43
  62. package/dist/tests/bench/report.js +0 -1821
  63. package/dist/tests/bench/report.test.js +0 -989
  64. package/dist/tests/bench/runner.js +0 -536
  65. package/dist/tests/bench/runner.test.js +0 -958
  66. package/dist/tests/bench/search-bridge.test.js +0 -331
  67. package/dist/tests/bench/tmp.js +0 -41
  68. package/dist/tests/bench/trajectory.js +0 -116
  69. package/dist/tests/bench/trajectory.test.js +0 -127
  70. package/dist/tests/bench/verifier.js +0 -109
  71. package/dist/tests/bench/verifier.test.js +0 -118
  72. package/dist/tests/bench/workflow-evaluator.js +0 -557
  73. package/dist/tests/bench/workflow-evaluator.test.js +0 -421
  74. package/dist/tests/bench/workflow-spec.js +0 -358
  75. package/dist/tests/bench/workflow-spec.test.js +0 -363
  76. package/dist/tests/bench/workflow-trace.js +0 -438
  77. package/dist/tests/bench/workflow-trace.test.js +0 -254
  78. package/dist/tests/benchmark-search-quality.js +0 -536
  79. package/dist/tests/benchmark-suite.js +0 -1441
  80. package/dist/tests/capture-cli.test.js +0 -112
  81. package/dist/tests/cli-errors.test.js +0 -203
  82. package/dist/tests/commands/events.test.js +0 -370
  83. package/dist/tests/commands/history.test.js +0 -223
  84. package/dist/tests/commands/import.test.js +0 -103
  85. package/dist/tests/commands/proposal-cli.test.js +0 -209
  86. package/dist/tests/commands/reflect-propose-cli.test.js +0 -333
  87. package/dist/tests/commands/remember.test.js +0 -97
  88. package/dist/tests/commands/scope-flags.test.js +0 -300
  89. package/dist/tests/commands/search.test.js +0 -537
  90. package/dist/tests/commands/show-indexer-parity.test.js +0 -117
  91. package/dist/tests/commands/show.test.js +0 -294
  92. package/dist/tests/common.test.js +0 -266
  93. package/dist/tests/completions.test.js +0 -142
  94. package/dist/tests/config-cli.test.js +0 -193
  95. package/dist/tests/config-llm-features.test.js +0 -139
  96. package/dist/tests/config.test.js +0 -544
  97. package/dist/tests/contracts/migration-baseline.test.js +0 -43
  98. package/dist/tests/contracts/reflect-propose-envelope.test.js +0 -139
  99. package/dist/tests/contracts/spec-helpers.js +0 -46
  100. package/dist/tests/contracts/v1-spec-section-11-proposal-queue.test.js +0 -228
  101. package/dist/tests/contracts/v1-spec-section-12-agent-config.test.js +0 -56
  102. package/dist/tests/contracts/v1-spec-section-13-lesson-type.test.js +0 -34
  103. package/dist/tests/contracts/v1-spec-section-14-llm-features.test.js +0 -94
  104. package/dist/tests/contracts/v1-spec-section-4-1-asset-types.test.js +0 -39
  105. package/dist/tests/contracts/v1-spec-section-4-2-quality-rules.test.js +0 -44
  106. package/dist/tests/contracts/v1-spec-section-5-configuration.test.js +0 -47
  107. package/dist/tests/contracts/v1-spec-section-6-orchestration.test.js +0 -40
  108. package/dist/tests/contracts/v1-spec-section-7-module-layout.test.js +0 -58
  109. package/dist/tests/contracts/v1-spec-section-8-extension-points.test.js +0 -34
  110. package/dist/tests/contracts/v1-spec-section-9-4-cli-surface.test.js +0 -75
  111. package/dist/tests/contracts/v1-spec-section-9-7-llm-agent-boundary.test.js +0 -36
  112. package/dist/tests/core/write-source.test.js +0 -366
  113. package/dist/tests/curate-command.test.js +0 -87
  114. package/dist/tests/db-scoring.test.js +0 -201
  115. package/dist/tests/db.test.js +0 -654
  116. package/dist/tests/distill-cli-flag.test.js +0 -208
  117. package/dist/tests/distill.test.js +0 -515
  118. package/dist/tests/docker-install.test.js +0 -120
  119. package/dist/tests/e2e.test.js +0 -1398
  120. package/dist/tests/embedder.test.js +0 -340
  121. package/dist/tests/embedding-model-config.test.js +0 -379
  122. package/dist/tests/feedback-command.test.js +0 -172
  123. package/dist/tests/file-context.test.js +0 -552
  124. package/dist/tests/fixtures/scripts/git/summarize-diff.js +0 -9
  125. package/dist/tests/fixtures/scripts/lint/eslint-check.js +0 -7
  126. package/dist/tests/fixtures/stashes/load.js +0 -166
  127. package/dist/tests/fixtures/stashes/load.test.js +0 -88
  128. package/dist/tests/fixtures/stashes/ranking-baseline/scripts/mem0-search.js +0 -12
  129. package/dist/tests/frontmatter.test.js +0 -190
  130. package/dist/tests/fts-field-weighting.test.js +0 -254
  131. package/dist/tests/fuzzy-search.test.js +0 -230
  132. package/dist/tests/git-provider-clone.test.js +0 -45
  133. package/dist/tests/github.test.js +0 -161
  134. package/dist/tests/graph-boost-ranking.test.js +0 -305
  135. package/dist/tests/graph-extraction.test.js +0 -282
  136. package/dist/tests/helpers/usage-events.js +0 -8
  137. package/dist/tests/index-pass-llm.test.js +0 -161
  138. package/dist/tests/indexer.test.js +0 -559
  139. package/dist/tests/info-command.test.js +0 -166
  140. package/dist/tests/init.test.js +0 -69
  141. package/dist/tests/install-script.test.js +0 -246
  142. package/dist/tests/integration/agent-real-profile.test.js +0 -94
  143. package/dist/tests/issue-36-repro.test.js +0 -304
  144. package/dist/tests/issues-191-194.test.js +0 -160
  145. package/dist/tests/lesson-lint.test.js +0 -111
  146. package/dist/tests/llm-client.test.js +0 -115
  147. package/dist/tests/llm-feature-gate.test.js +0 -151
  148. package/dist/tests/llm.test.js +0 -139
  149. package/dist/tests/lockfile.test.js +0 -216
  150. package/dist/tests/manifest.test.js +0 -205
  151. package/dist/tests/markdown.test.js +0 -126
  152. package/dist/tests/matchers-unit.test.js +0 -189
  153. package/dist/tests/memory-inference.test.js +0 -299
  154. package/dist/tests/merge-scoring.test.js +0 -136
  155. package/dist/tests/metadata.test.js +0 -313
  156. package/dist/tests/migration-help.test.js +0 -89
  157. package/dist/tests/origin-resolve.test.js +0 -124
  158. package/dist/tests/output-baseline.test.js +0 -217
  159. package/dist/tests/output-shapes-unit.test.js +0 -476
  160. package/dist/tests/parallel-search.test.js +0 -272
  161. package/dist/tests/parameter-metadata.test.js +0 -365
  162. package/dist/tests/paths.test.js +0 -177
  163. package/dist/tests/progressive-disclosure.test.js +0 -280
  164. package/dist/tests/proposals.test.js +0 -279
  165. package/dist/tests/proposed-quality.test.js +0 -271
  166. package/dist/tests/provider-registry.test.js +0 -32
  167. package/dist/tests/ranking-regression.test.js +0 -548
  168. package/dist/tests/reflect-propose.test.js +0 -455
  169. package/dist/tests/registry-build-index.test.js +0 -378
  170. package/dist/tests/registry-cli.test.js +0 -290
  171. package/dist/tests/registry-index-v2.test.js +0 -430
  172. package/dist/tests/registry-install.test.js +0 -728
  173. package/dist/tests/registry-providers/parity.test.js +0 -189
  174. package/dist/tests/registry-providers/skills-sh.test.js +0 -309
  175. package/dist/tests/registry-providers/static-index.test.js +0 -204
  176. package/dist/tests/registry-resolve.test.js +0 -126
  177. package/dist/tests/registry-search.test.js +0 -723
  178. package/dist/tests/remember-frontmatter.test.js +0 -380
  179. package/dist/tests/remember-unit.test.js +0 -123
  180. package/dist/tests/ripgrep-install.test.js +0 -251
  181. package/dist/tests/ripgrep-resolve.test.js +0 -108
  182. package/dist/tests/ripgrep.test.js +0 -163
  183. package/dist/tests/save-command.test.js +0 -94
  184. package/dist/tests/save-trust-qa-fixes.test.js +0 -270
  185. package/dist/tests/scoring-pipeline.test.js +0 -648
  186. package/dist/tests/search-include-proposed-cli.test.js +0 -118
  187. package/dist/tests/self-update.test.js +0 -442
  188. package/dist/tests/semantic-search-e2e.test.js +0 -512
  189. package/dist/tests/semantic-status.test.js +0 -471
  190. package/dist/tests/setup-run.integration.js +0 -877
  191. package/dist/tests/setup-wizard.test.js +0 -198
  192. package/dist/tests/setup.test.js +0 -131
  193. package/dist/tests/source-add.test.js +0 -11
  194. package/dist/tests/source-clone.test.js +0 -254
  195. package/dist/tests/source-manage.test.js +0 -366
  196. package/dist/tests/source-providers/filesystem.test.js +0 -82
  197. package/dist/tests/source-providers/git.test.js +0 -252
  198. package/dist/tests/source-providers/website.test.js +0 -128
  199. package/dist/tests/source-qa-fixes.test.js +0 -268
  200. package/dist/tests/source-registry.test.js +0 -350
  201. package/dist/tests/source-resolve.test.js +0 -100
  202. package/dist/tests/source-source.test.js +0 -221
  203. package/dist/tests/source.test.js +0 -533
  204. package/dist/tests/tar-utils-scan.test.js +0 -73
  205. package/dist/tests/toggle-components.test.js +0 -73
  206. package/dist/tests/usage-telemetry.test.js +0 -265
  207. package/dist/tests/utility-scoring.test.js +0 -558
  208. package/dist/tests/vault-load-error.test.js +0 -78
  209. package/dist/tests/vault-qa-fixes.test.js +0 -194
  210. package/dist/tests/vault.test.js +0 -429
  211. package/dist/tests/vector-search.test.js +0 -608
  212. package/dist/tests/walker.test.js +0 -252
  213. package/dist/tests/wave2-cluster-bc.test.js +0 -228
  214. package/dist/tests/wave2-cluster-d.test.js +0 -180
  215. package/dist/tests/wave2-cluster-e.test.js +0 -179
  216. package/dist/tests/wiki-qa-fixes.test.js +0 -270
  217. package/dist/tests/wiki.test.js +0 -529
  218. package/dist/tests/workflow-cli.test.js +0 -271
  219. package/dist/tests/workflow-markdown.test.js +0 -171
  220. package/dist/tests/workflow-path-escape.test.js +0 -132
  221. package/dist/tests/workflow-qa-fixes.test.js +0 -377
  222. package/dist/tests/workflows/indexer-rejection.test.js +0 -213
  223. /package/dist/{src/commands → commands}/completions.js +0 -0
  224. /package/dist/{src/commands → commands}/curate.js +0 -0
  225. /package/dist/{src/commands → commands}/distill.js +0 -0
  226. /package/dist/{src/commands → commands}/events.js +0 -0
  227. /package/dist/{src/commands → commands}/info.js +0 -0
  228. /package/dist/{src/commands → commands}/init.js +0 -0
  229. /package/dist/{src/commands → commands}/install-audit.js +0 -0
  230. /package/dist/{src/commands → commands}/installed-stashes.js +0 -0
  231. /package/dist/{src/commands → commands}/migration-help.js +0 -0
  232. /package/dist/{src/commands → commands}/proposal.js +0 -0
  233. /package/dist/{src/commands → commands}/propose.js +0 -0
  234. /package/dist/{src/commands → commands}/reflect.js +0 -0
  235. /package/dist/{src/commands → commands}/remember.js +0 -0
  236. /package/dist/{src/commands → commands}/self-update.js +0 -0
  237. /package/dist/{src/commands → commands}/source-clone.js +0 -0
  238. /package/dist/{src/commands → commands}/vault.js +0 -0
  239. /package/dist/{src/core → core}/asset-ref.js +0 -0
  240. /package/dist/{src/core → core}/asset-registry.js +0 -0
  241. /package/dist/{src/core → core}/asset-spec.js +0 -0
  242. /package/dist/{src/core → core}/common.js +0 -0
  243. /package/dist/{src/core → core}/errors.js +0 -0
  244. /package/dist/{src/core → core}/events.js +0 -0
  245. /package/dist/{src/core → core}/frontmatter.js +0 -0
  246. /package/dist/{src/core → core}/lesson-lint.js +0 -0
  247. /package/dist/{src/core → core}/markdown.js +0 -0
  248. /package/dist/{src/core → core}/paths.js +0 -0
  249. /package/dist/{src/core → core}/proposals.js +0 -0
  250. /package/dist/{src/core → core}/warn.js +0 -0
  251. /package/dist/{src/core → core}/write-source.js +0 -0
  252. /package/dist/{src/indexer → indexer}/db.js +0 -0
  253. /package/dist/{src/indexer → indexer}/file-context.js +0 -0
  254. /package/dist/{src/indexer → indexer}/graph-boost.js +0 -0
  255. /package/dist/{src/indexer → indexer}/graph-extraction.js +0 -0
  256. /package/dist/{src/indexer → indexer}/manifest.js +0 -0
  257. /package/dist/{src/indexer → indexer}/memory-inference.js +0 -0
  258. /package/dist/{src/indexer → indexer}/metadata.js +0 -0
  259. /package/dist/{src/indexer → indexer}/search-fields.js +0 -0
  260. /package/dist/{src/indexer → indexer}/semantic-status.js +0 -0
  261. /package/dist/{src/indexer → indexer}/usage-events.js +0 -0
  262. /package/dist/{src/indexer → indexer}/walker.js +0 -0
  263. /package/dist/{src/integrations → integrations}/agent/config.js +0 -0
  264. /package/dist/{src/integrations → integrations}/agent/detect.js +0 -0
  265. /package/dist/{src/integrations → integrations}/agent/index.js +0 -0
  266. /package/dist/{src/integrations → integrations}/agent/prompts.js +0 -0
  267. /package/dist/{src/integrations → integrations}/lockfile.js +0 -0
  268. /package/dist/{src/llm → llm}/client.js +0 -0
  269. /package/dist/{src/llm → llm}/embedder.js +0 -0
  270. /package/dist/{src/llm → llm}/embedders/cache.js +0 -0
  271. /package/dist/{src/llm → llm}/embedders/local.js +0 -0
  272. /package/dist/{src/llm → llm}/embedders/types.js +0 -0
  273. /package/dist/{src/llm → llm}/feature-gate.js +0 -0
  274. /package/dist/{src/llm → llm}/graph-extract.js +0 -0
  275. /package/dist/{src/llm → llm}/index-passes.js +0 -0
  276. /package/dist/{src/llm → llm}/memory-infer.js +0 -0
  277. /package/dist/{src/llm → llm}/metadata-enhance.js +0 -0
  278. /package/dist/{src/output → output}/context.js +0 -0
  279. /package/dist/{src/registry → registry}/create-provider-registry.js +0 -0
  280. /package/dist/{src/registry → registry}/factory.js +0 -0
  281. /package/dist/{src/registry → registry}/origin-resolve.js +0 -0
  282. /package/dist/{src/registry → registry}/providers/index.js +0 -0
  283. /package/dist/{src/registry → registry}/providers/skills-sh.js +0 -0
  284. /package/dist/{src/registry → registry}/providers/types.js +0 -0
  285. /package/dist/{src/registry → registry}/resolve.js +0 -0
  286. /package/dist/{src/registry → registry}/types.js +0 -0
  287. /package/dist/{src/setup → setup}/detect.js +0 -0
  288. /package/dist/{src/setup → setup}/ripgrep-install.js +0 -0
  289. /package/dist/{src/setup → setup}/ripgrep-resolve.js +0 -0
  290. /package/dist/{src/setup → setup}/steps.js +0 -0
  291. /package/dist/{src/sources → sources}/include.js +0 -0
  292. /package/dist/{src/sources → sources}/provider-factory.js +0 -0
  293. /package/dist/{src/sources → sources}/provider.js +0 -0
  294. /package/dist/{src/sources → sources}/providers/filesystem.js +0 -0
  295. /package/dist/{src/sources → sources}/providers/git.js +0 -0
  296. /package/dist/{src/sources → sources}/providers/index.js +0 -0
  297. /package/dist/{src/sources → sources}/providers/install-types.js +0 -0
  298. /package/dist/{src/sources → sources}/providers/npm.js +0 -0
  299. /package/dist/{src/sources → sources}/providers/provider-utils.js +0 -0
  300. /package/dist/{src/sources → sources}/providers/sync-from-ref.js +0 -0
  301. /package/dist/{src/sources → sources}/providers/tar-utils.js +0 -0
  302. /package/dist/{src/sources → sources}/providers/website.js +0 -0
  303. /package/dist/{src/sources → sources}/resolve.js +0 -0
  304. /package/dist/{src/sources → sources}/types.js +0 -0
  305. /package/dist/{src/templates → templates}/wiki-templates.js +0 -0
  306. /package/dist/{src/version.js → version.js} +0 -0
  307. /package/dist/{src/workflows → workflows}/authoring.js +0 -0
  308. /package/dist/{src/workflows → workflows}/cli.js +0 -0
  309. /package/dist/{src/workflows → workflows}/db.js +0 -0
  310. /package/dist/{src/workflows → workflows}/document-cache.js +0 -0
  311. /package/dist/{src/workflows → workflows}/parser.js +0 -0
  312. /package/dist/{src/workflows → workflows}/renderer.js +0 -0
  313. /package/dist/{src/workflows → workflows}/schema.js +0 -0
  314. /package/dist/{src/workflows → workflows}/validator.js +0 -0
@@ -120,6 +120,8 @@ export function formatPlain(command, result, detail) {
120
120
  const flagText = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
121
121
  lines.push(`[${kind}] ${name}${ver}${prov}${flagText}`);
122
122
  }
123
+ lines.push("");
124
+ lines.push("To search: akm search '<query>' | To view an asset: akm show <ref>");
123
125
  return lines.join("\n");
124
126
  }
125
127
  case "add": {
@@ -597,6 +599,10 @@ export function formatHistoryPlain(r) {
597
599
  headerParts.push(`since: ${r.since}`);
598
600
  const totalCount = typeof r.totalCount === "number" ? r.totalCount : entries.length;
599
601
  headerParts.push(`${totalCount} event(s)`);
602
+ // Show active event sources so operators know which streams were consulted.
603
+ if (Array.isArray(r.sources) && r.sources.length > 0) {
604
+ headerParts.push(`sources: ${r.sources.join(", ")}`);
605
+ }
600
606
  const header = headerParts.join(" ");
601
607
  if (entries.length === 0) {
602
608
  const scope = typeof r.ref === "string" && r.ref ? ` for ${r.ref}` : "";
@@ -627,6 +633,9 @@ function formatShowPlain(r, detail) {
627
633
  if (r.type || r.name) {
628
634
  lines.push(`# ${String(r.type ?? "asset")}: ${String(r.name ?? "unknown")}`);
629
635
  }
636
+ if (r.path && r.editable !== false) {
637
+ lines.push(`file: ${String(r.path)}`);
638
+ }
630
639
  if (r.origin !== undefined)
631
640
  lines.push(`# origin: ${String(r.origin)}`);
632
641
  if (r.action)
@@ -677,7 +686,10 @@ function formatShowPlain(r, detail) {
677
686
  const id = typeof step.id === "string" ? step.id : "unknown";
678
687
  lines.push(` ${index + 1}. ${title} [${id}]`);
679
688
  if (typeof step.instructions === "string" && step.instructions.trim()) {
680
- lines.push(` instructions: ${step.instructions.replace(/\n+/g, " ").trim()}`);
689
+ const instrLines = step.instructions.trim().split("\n");
690
+ lines.push(` instructions: ${instrLines[0]}`);
691
+ for (const instrLine of instrLines.slice(1))
692
+ lines.push(` ${instrLine}`);
681
693
  }
682
694
  if (Array.isArray(step.completionCriteria) && step.completionCriteria.length > 0) {
683
695
  lines.push(" completion:");
@@ -692,8 +704,94 @@ function formatShowPlain(r, detail) {
692
704
  lines.push("");
693
705
  lines.push(...payloads);
694
706
  }
707
+ // REC-01 / REC-09: Append a type-specific directive so agents apply the
708
+ // content rather than substituting training-data approximations.
709
+ const assetType = typeof r.type === "string" ? r.type : null;
710
+ const assetRef = typeof r.name === "string" && assetType ? `${assetType}:${r.name}` : null;
711
+ // Show-loop detection: if the agent has shown this asset 3+ times without
712
+ // writing anything, surface a warning so it stops cycling and acts.
713
+ const showLoopCount = typeof r.showLoopWarning === "number" ? r.showLoopWarning : 0;
714
+ if (showLoopCount >= 3) {
715
+ lines.push("");
716
+ lines.push(`WARNING: You have shown this asset ${showLoopCount} times without completing the task.`);
717
+ lines.push("Stop re-reading — you have the information you need. Act on it now:");
718
+ lines.push(" - Write your output file using the content above.");
719
+ lines.push(` - If this asset does not contain what you need, run \`akm feedback '${assetRef ?? "<ref>"}' --negative\` and search for a different asset.`);
720
+ }
721
+ if (assetType === "skill" || assetType === "knowledge") {
722
+ const activeRun = r.activeRun;
723
+ if (activeRun) {
724
+ // Active workflow: redirect agent to workflow commands instead of direct apply
725
+ lines.unshift(` akm workflow complete '${activeRun.runId}'${activeRun.stepId ? ` --step '${activeRun.stepId}'` : ""}`);
726
+ lines.unshift("Read this schema, then follow your workflow step's instructions to edit the workspace file. When done, mark the step complete:");
727
+ lines.unshift(`WORKFLOW ACTIVE — schema shown as reference (run: ${activeRun.runId})`);
728
+ lines.unshift("---");
729
+ lines.unshift("");
730
+ // Still show feedback line at the end but skip the APPLY directive
731
+ lines.push("");
732
+ lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` if the step succeeds, or \`--negative\` if this schema did not help.`);
733
+ }
734
+ else {
735
+ // No active workflow: show the APPLY directive. Branch on whether this
736
+ // skill primarily teaches CLI commands (shell output) vs YAML schema.
737
+ const preApplyLines = [...lines];
738
+ lines.push("");
739
+ lines.push("---");
740
+ if (isCommandOutputSkill(preApplyLines)) {
741
+ lines.push("APPLY (only if no workflow step is required for this task):");
742
+ lines.push(" 1. Identify the output file from README.md (typically commands.txt).");
743
+ lines.push(" 2. Write the exact command syntax from the code blocks above — replace every placeholder (`<name>`, `<value>`) with a real, concrete value from your task context. Do not write placeholder text.");
744
+ lines.push(" 3. Each command should be on a single line (no backslash line continuation unless the verifier expects it).");
745
+ lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if this reference did not contain the needed command syntax.`);
746
+ }
747
+ else {
748
+ lines.push("APPLY (only if no workflow step is required for this task):");
749
+ lines.push(" 1. Identify the target file from README.md — write or edit it. If the file does not yet exist, CREATE it with the full structure from this schema.");
750
+ lines.push(" 2. Add/edit the fields shown above using the exact field names from this schema.");
751
+ lines.push(" 3. COPY the exact YAML structure and field names from the code blocks above — do not substitute synonyms or invent nesting. Replace every placeholder value with a real, concrete value from your task context. Do not leave any field as null, empty, or a placeholder.");
752
+ lines.push(`Run \`akm feedback ${assetRef ? `'${assetRef}'` : "<ref>"} --positive\` after the task succeeds, or \`--negative\` if the task fails after following this guidance.`);
753
+ }
754
+ }
755
+ }
756
+ else if (assetType === "workflow") {
757
+ const workflowName = typeof r.name === "string" ? r.name : null;
758
+ const workflowRef = workflowName ? `workflow:${workflowName}` : "<ref>";
759
+ // Insert action directive BEFORE the workflow content by prepending to lines at the
760
+ // separator position. We find where the header ends and insert after the first `---`.
761
+ // Since lines already contain the full content at this point, we locate the insertion
762
+ // index: right after the first `---` separator if present, otherwise after the header.
763
+ const separatorIdx = lines.indexOf("---");
764
+ const insertIdx = separatorIdx >= 0 ? separatorIdx + 1 : r.type || r.name ? 1 : 0;
765
+ const actionDirective = [
766
+ `ACTION REQUIRED: Do not execute steps manually from this output.`,
767
+ `Run \`akm workflow next '${workflowRef}'\` to get your current step with exact instructions.`,
768
+ "---",
769
+ ];
770
+ lines.splice(insertIdx, 0, "", ...actionDirective);
771
+ lines.push("");
772
+ lines.push("---");
773
+ lines.push(`NEXT STEP: Run \`akm workflow next '${workflowRef}'\` to see the current workflow step.`);
774
+ lines.push("Do not edit workspace files before completing each step with `akm workflow complete`.");
775
+ }
695
776
  return lines.length > 0 ? lines.join("\n") : null;
696
777
  }
778
+ /**
779
+ * Detect whether a skill's rendered content primarily teaches CLI commands
780
+ * rather than YAML schema. Used to select the right APPLY directive variant.
781
+ *
782
+ * Heuristic: count code-block lines that start with known shell command
783
+ * prefixes vs lines that look like YAML key-value pairs. If CLI lines
784
+ * outnumber YAML lines (and there is at least one CLI line), treat the
785
+ * skill as command-output.
786
+ */
787
+ function isCommandOutputSkill(lines) {
788
+ const codeLines = lines.filter((l) => l.startsWith(" ") || l.startsWith("\t") || /^`/.test(l));
789
+ const cliPattern = /^(az |kubectl |docker |git |helm |terraform |aws |gcloud )/;
790
+ const yamlPattern = /^\s+\w+:/;
791
+ const cliCount = codeLines.filter((l) => cliPattern.test(l.trim())).length;
792
+ const yamlCount = codeLines.filter((l) => yamlPattern.test(l)).length;
793
+ return cliCount > yamlCount && cliCount > 0;
794
+ }
697
795
  export function formatWorkflowListPlain(result) {
698
796
  const runs = Array.isArray(result.runs) ? result.runs : [];
699
797
  if (runs.length === 0) {
@@ -747,7 +845,10 @@ export function formatWorkflowNextPlain(result) {
747
845
  const lines = base ? [base, "", "next:"] : ["next:"];
748
846
  lines.push(` ${String(step.title ?? "Untitled step")} [${String(step.id ?? "unknown")}]`);
749
847
  if (typeof step.instructions === "string" && step.instructions.trim()) {
750
- lines.push(` instructions: ${step.instructions.replace(/\n+/g, " ").trim()}`);
848
+ const instrLines = step.instructions.trim().split("\n");
849
+ lines.push(` instructions: ${instrLines[0]}`);
850
+ for (const instrLine of instrLines.slice(1))
851
+ lines.push(` ${instrLine}`);
751
852
  }
752
853
  const completion = Array.isArray(step.completionCriteria) ? step.completionCriteria : [];
753
854
  if (completion.length > 0) {
@@ -756,6 +857,25 @@ export function formatWorkflowNextPlain(result) {
756
857
  lines.push(` - ${String(criterion)}`);
757
858
  }
758
859
  }
860
+ // T2-3: surface run-id as labeled field
861
+ const run = typeof result.run === "object" && result.run !== null ? result.run : undefined;
862
+ const runId = typeof run?.id === "string" ? run.id : null;
863
+ const stepId = typeof step?.id === "string" ? step.id : null;
864
+ if (runId) {
865
+ lines.push("");
866
+ lines.push(`runId: ${runId}`);
867
+ }
868
+ // T1-6: complete command
869
+ if (runId && stepId) {
870
+ lines.push("");
871
+ lines.push("COMPLETE THIS STEP:");
872
+ lines.push(` akm workflow complete '${runId}' --step '${stepId}'`);
873
+ }
874
+ else if (runId) {
875
+ lines.push("");
876
+ lines.push("COMPLETE THIS STEP:");
877
+ lines.push(` akm workflow complete '${runId}' --step '<step-id>'`);
878
+ }
759
879
  return lines.join("\n");
760
880
  }
761
881
  export function formatSearchPlain(r, detail) {
@@ -763,7 +883,13 @@ export function formatSearchPlain(r, detail) {
763
883
  const registryHits = r.registryHits ?? [];
764
884
  const allHits = [...hits, ...registryHits];
765
885
  if (allHits.length === 0) {
766
- return r.tip ? String(r.tip) : "No results found.";
886
+ const warnings = Array.isArray(r.warnings) ? r.warnings : [];
887
+ const hasSetupWarning = warnings.some((w) => String(w).toLowerCase().includes("no stash") || String(w).toLowerCase().includes("not configured"));
888
+ if (hasSetupWarning) {
889
+ return "No stash configured. Run `akm init` to create your working stash, then `akm index` to build the search index.";
890
+ }
891
+ const base = r.tip ? String(r.tip) : "No matches found.";
892
+ return `${base}\nTry:\n akm search '<broader-term>' # fewer keywords\n akm list # see all configured sources\n akm curate '<query>' # let akm select the best match`;
767
893
  }
768
894
  const lines = [];
769
895
  for (const hit of allHits) {
@@ -822,6 +948,27 @@ export function formatSearchPlain(r, detail) {
822
948
  if (parts.length > 0)
823
949
  lines.push(`timing: ${parts.join(", ")}`);
824
950
  }
951
+ // REC-02: When stash hits exist, tell the agent the next required step so it
952
+ // doesn't skip `akm show` and write from training memory instead.
953
+ if (hits.length >= 1) {
954
+ // Prefer skill/command/agent type hits for the "Next:" ref — knowledge docs are
955
+ // supplementary context, not the authoritative schema agents should load first.
956
+ const preferredHit = hits.find((h) => h.type === "skill" || h.type === "command" || h.type === "agent") ?? hits[0];
957
+ const topRef = typeof preferredHit.ref === "string" ? preferredHit.ref : null;
958
+ const hasWorkflowHit = hits.some((h) => h.type === "workflow");
959
+ if (topRef) {
960
+ if (hasWorkflowHit) {
961
+ const workflowRef = hits.find((h) => h.type === "workflow");
962
+ const wfRef = workflowRef && typeof workflowRef.ref === "string" ? workflowRef.ref : topRef;
963
+ lines.push(`Next: akm show '${topRef}' | To start a workflow: akm workflow next '${wfRef}'`);
964
+ lines.push("After running workflow next: follow each step and run `akm workflow complete <run-id> --step <step-id>` when done.");
965
+ }
966
+ else {
967
+ lines.push(`Next: akm show '${topRef}'`);
968
+ lines.push("After reading the asset: check whether a workflow applies before editing — if so, use `akm workflow next` instead.");
969
+ }
970
+ }
971
+ }
825
972
  return lines.join("\n").trimEnd();
826
973
  }
827
974
  export function formatWikiListPlain(r) {
@@ -959,5 +1106,11 @@ export function formatCuratePlain(r, detail) {
959
1106
  lines.push(`- ${String(warning)}`);
960
1107
  }
961
1108
  }
1109
+ lines.push("");
1110
+ lines.push("Next steps:");
1111
+ lines.push(" 1. Run `akm show <ref>` for the best result above to read the full schema.");
1112
+ lines.push(" 2. Edit the workspace file using the schema field names and your task-specific values.");
1113
+ lines.push(" 3. Run `akm feedback <ref> --positive` when the task succeeds.");
1114
+ lines.push("To search further: akm search '<query>'");
962
1115
  return lines.join("\n");
963
1116
  }
@@ -19,15 +19,16 @@ import { detectStashRoot } from "../sources/providers/provider-utils";
19
19
  import { extractTarGzSecure } from "../sources/providers/tar-utils";
20
20
  import { parseRegistryIndex } from "./providers/static-index";
21
21
  const DEFAULT_NPM_REGISTRY_BASE = "https://registry.npmjs.org";
22
- const DEFAULT_MANUAL_ENTRIES_PATH = path.resolve("manual-entries.json");
23
- const DEFAULT_OUTPUT_PATH = path.resolve("index.json");
24
22
  const REQUIRED_KEYWORDS = ["akm-stash"];
25
23
  const GITHUB_TOPICS = ["akm-stash"];
26
24
  const EXCLUDED_REPOS = new Set(["itlackey/akm"]);
27
25
  const EXCLUDED_NPM_PACKAGES = new Set(["akm-cli"]);
28
26
  const EMPTY_INSPECTION = {};
27
+ function getDefaultRegistryBuildDir() {
28
+ return path.join(getCacheDir(), "registry-build");
29
+ }
29
30
  export async function buildRegistryIndex(options) {
30
- const manualEntriesPath = path.resolve(options?.manualEntriesPath ?? DEFAULT_MANUAL_ENTRIES_PATH);
31
+ const manualEntriesPath = path.resolve(options?.manualEntriesPath ?? path.join(getDefaultRegistryBuildDir(), "manual-entries.json"));
31
32
  const npmRegistryBase = trimTrailingSlash(options?.npmRegistryBase ?? DEFAULT_NPM_REGISTRY_BASE);
32
33
  const githubApiBase = trimTrailingSlash(options?.githubApiBase ?? GITHUB_API_BASE);
33
34
  const [manualKits, npmKits, githubKits] = await Promise.all([
@@ -55,7 +56,7 @@ export async function buildRegistryIndex(options) {
55
56
  };
56
57
  }
57
58
  export function writeRegistryIndex(index, outPath) {
58
- const resolved = path.resolve(outPath ?? DEFAULT_OUTPUT_PATH);
59
+ const resolved = path.resolve(outPath ?? path.join(getDefaultRegistryBuildDir(), "index.json"));
59
60
  fs.mkdirSync(path.dirname(resolved), { recursive: true });
60
61
  fs.writeFileSync(resolved, `${JSON.stringify(index, null, 2)}\n`, "utf8");
61
62
  return resolved;
@@ -190,7 +190,9 @@ export function parseRegistryIndex(data) {
190
190
  if (typeof data !== "object" || data === null || Array.isArray(data))
191
191
  return null;
192
192
  const obj = data;
193
- if (typeof obj.version !== "number" || obj.version !== 3)
193
+ // Accept version 2 and 3 both use the same stashes[] wire format.
194
+ // The live official registry currently publishes version 2.
195
+ if (typeof obj.version !== "number" || (obj.version !== 2 && obj.version !== 3))
194
196
  return null;
195
197
  if (typeof obj.updatedAt !== "string")
196
198
  return null;
@@ -283,6 +283,7 @@ async function stepOllama(current) {
283
283
  mxbai: 1024,
284
284
  minilm: 384,
285
285
  bge: 384,
286
+ qwen3: 1024,
286
287
  };
287
288
  const guessedDim = Object.entries(knownDims).find(([k]) => embChoice.includes(k))?.[1] ?? 384;
288
289
  p.note("Embedding dimension must match the model. Common values: 384 (BGE small), 768 (BGE base), 1024 (BGE large). Press Enter to accept the detected default.", "Embedding dimension");
@@ -302,6 +303,14 @@ async function stepOllama(current) {
302
303
  model: embChoice,
303
304
  dimension: Number(dimChoice),
304
305
  };
306
+ p.note([
307
+ "Recommended Qwen embedding models (modern, high context support):",
308
+ " • qwen3-embedding-0.6b — fast and lightweight (ollama pull qwen3-embedding-0.6b)",
309
+ " • qwen3-embedding-4b — higher quality (ollama pull qwen3-embedding-4b)",
310
+ "",
311
+ "For long documents (wiki pages, large files), set context length to avoid 400 errors:",
312
+ " akm config set embedding.contextLength 8192",
313
+ ].join("\n"), "Embedding tips");
305
314
  }
306
315
  // else: undefined → use built-in local
307
316
  // Surface Ollama details to the LLM step so it can offer Ollama as a preset.
@@ -11,6 +11,32 @@
11
11
  * Principle: "akm surfaces. The agent writes." akm owns lifecycle, raw-slug
12
12
  * generation, structural lint, and `index.md` regeneration. The agent uses
13
13
  * its native file tools for every other page operation.
14
+ *
15
+ * ## Canonical wiki content contract
16
+ *
17
+ * The three "infrastructure" files at the wiki root — `schema.md`, `index.md`,
18
+ * and `log.md` — are excluded from all user-facing content surfaces:
19
+ *
20
+ * | Surface | schema/index/log | raw/<slug>.md | <page>.md |
21
+ * | -------------------- | ---------------- | ------------- | --------- |
22
+ * | `wiki pages` | excluded | included | included |
23
+ * | scoped wiki search | excluded | included | included |
24
+ * | stash-wide FTS index | excluded | included | included |
25
+ * | `wiki lint` | excluded | tracked | tracked |
26
+ *
27
+ * `raw/` files are first-class addressable content (`wiki:<n>/raw/<slug>`),
28
+ * searchable, and listed. They are NOT authored pages — they are source
29
+ * material the agent turns into pages. `lint` tracks whether each raw file
30
+ * has been cited by a page's `sources:` frontmatter field.
31
+ *
32
+ * ## Regeneration contract
33
+ *
34
+ * `regenerateWikiIndex` / `regenerateAllWikiIndexes` apply ONLY to
35
+ * stash-owned wikis (directories under `<stashDir>/wikis/`). External wikis
36
+ * registered via `akm wiki register` are read-only caches; mutating their
37
+ * `index.md` would corrupt source-of-truth content that akm does not own.
38
+ * The indexer therefore calls `regenerateAllWikiIndexes(stashDir)` — which
39
+ * only iterates `<stashDir>/wikis/` — and never touches registered sources.
14
40
  */
15
41
  import fs from "node:fs";
16
42
  import path from "node:path";
@@ -496,10 +522,15 @@ function readPageFrontmatter(absPath) {
496
522
  return out;
497
523
  }
498
524
  /**
499
- * List the addressable markdown entries in a wiki, excluding only the
500
- * infrastructure files `schema.md`, `index.md`, and `log.md`. This includes
501
- * both authored pages and `raw/` sources so `wiki pages` can inventory content
502
- * written via `akm wiki stash`.
525
+ * List all addressable wiki content entries.
526
+ *
527
+ * Per the canonical wiki contract: `schema.md`, `index.md`, and `log.md` at
528
+ * the wiki root are infrastructure files and are excluded. Everything else —
529
+ * authored pages AND `raw/<slug>.md` sources — is included and addressable as
530
+ * `wiki:<name>/<rel-path-without-.md>`.
531
+ *
532
+ * Callers that need to distinguish authored pages from raw sources should
533
+ * check whether the returned `name` starts with `"raw/"`.
503
534
  */
504
535
  export function listPages(stashDir, name) {
505
536
  const wikiDir = resolveWikiSource(stashDir, name).path;
@@ -521,6 +552,10 @@ export function listPages(stashDir, name) {
521
552
  * Uses `akmSearch({ type: "wiki" })` to reuse the full FTS5+boost pipeline,
522
553
  * then drops hits that aren't inside `wikis/<name>/`. No parallel scorer.
523
554
  *
555
+ * Per the canonical wiki contract: infrastructure files (`schema.md`,
556
+ * `index.md`, `log.md`) at the wiki root are excluded. `raw/<slug>.md`
557
+ * sources are included — they are first-class addressable content.
558
+ *
524
559
  * When the index is absent (e.g. fresh stash), `akmSearch` falls back to its
525
560
  * substring walker; hits still come through path-filtered here.
526
561
  */
@@ -795,7 +830,13 @@ export function lintWiki(stashDir, name) {
795
830
  }
796
831
  // ── Index regeneration ─────────────────────────────────────────────────────
797
832
  /**
798
- * Rebuild a wiki's `index.md` from its pages' frontmatter.
833
+ * Rebuild a stash-owned wiki's `index.md` from its pages' frontmatter.
834
+ *
835
+ * This function uses `resolveWikiDir` (not `resolveWikiSource`) so it only
836
+ * ever operates on the stash-owned path `<stashDir>/wikis/<name>/`. External
837
+ * wikis registered via `akm wiki register` are never regenerated here — they
838
+ * are read-only caches. See the canonical wiki contract at the top of this
839
+ * file for the full regeneration rule.
799
840
  *
800
841
  * Pages are grouped by `pageKind` (falling back to `uncategorised`) and
801
842
  * listed alphabetically inside each group. If the wiki directory doesn't
@@ -861,7 +902,14 @@ export function regenerateWikiIndex(stashDir, name) {
861
902
  }
862
903
  }
863
904
  /**
864
- * Regenerate `index.md` for every wiki found under `<stashDir>/wikis/`.
905
+ * Regenerate `index.md` for every stash-owned wiki under `<stashDir>/wikis/`.
906
+ *
907
+ * Per the canonical wiki contract: regeneration applies ONLY to stash-owned
908
+ * wikis. External wikis registered via `akm wiki register` are read-only
909
+ * caches whose source-of-truth lives outside this stash; mutating their
910
+ * `index.md` would corrupt content that akm does not own. Those wikis
911
+ * therefore appear only in the FTS index (read), never in regeneration
912
+ * (write).
865
913
  *
866
914
  * Called from `akmIndex()` as a side effect after the FTS rebuild. Never
867
915
  * throws; returns the list of wiki names that were regenerated.
@@ -3,6 +3,7 @@ import fs from "node:fs";
3
3
  import { parseAssetRef } from "../core/asset-ref";
4
4
  import { loadConfig } from "../core/config";
5
5
  import { NotFoundError, UsageError } from "../core/errors";
6
+ import { appendEvent } from "../core/events";
6
7
  import { getDbPath } from "../core/paths";
7
8
  import { closeDatabase, openDatabase } from "../indexer/db";
8
9
  import { resolveSourceEntries } from "../indexer/search-source";
@@ -32,7 +33,13 @@ export async function startWorkflowRun(ref, params = {}) {
32
33
  insertStep.run(runId, step.id, step.title, step.instructions, step.completionCriteria ? JSON.stringify(step.completionCriteria) : null, step.sequenceIndex ?? 0);
33
34
  }
34
35
  })();
35
- return getWorkflowStatus(runId);
36
+ const result = getWorkflowStatus(runId);
37
+ appendEvent({
38
+ eventType: "workflow_started",
39
+ ref: ref,
40
+ metadata: { runId: result.run.id, title: result.run.workflowTitle },
41
+ });
42
+ return result;
36
43
  }
37
44
  finally {
38
45
  closeWorkflowDatabase(workflowDb);
@@ -173,7 +180,16 @@ export function completeWorkflowStep(input) {
173
180
  completed_at: state.completedAt,
174
181
  };
175
182
  })();
176
- return buildWorkflowRunDetail(updatedRun, refreshedSteps);
183
+ const detail = buildWorkflowRunDetail(updatedRun, refreshedSteps);
184
+ appendEvent({
185
+ eventType: "workflow_step_completed",
186
+ ref: detail.run.workflowRef,
187
+ metadata: { runId: input.runId, stepId: input.stepId, notes: input.notes },
188
+ });
189
+ if (detail.run.status === "completed") {
190
+ appendEvent({ eventType: "workflow_finished", ref: detail.run.workflowRef, metadata: { runId: input.runId } });
191
+ }
192
+ return detail;
177
193
  }
178
194
  finally {
179
195
  closeWorkflowDatabase(workflowDb);
@@ -187,6 +203,9 @@ async function resolveRunSpecifier(db, specifier, params) {
187
203
  }
188
204
  return { run: explicitRun, autoStarted: false };
189
205
  }
206
+ if (!specifier.includes(":")) {
207
+ throw new NotFoundError(`Workflow run "${specifier}" not found.`, "WORKFLOW_NOT_FOUND");
208
+ }
190
209
  const parsed = parseAssetRef(specifier);
191
210
  if (parsed.type !== "workflow") {
192
211
  throw new UsageError(`Expected a workflow ref or workflow run id, got "${specifier}".`);
@@ -316,7 +335,7 @@ function resolveWorkflowEntryId(sourcePath, ref) {
316
335
  function readWorkflowRun(db, runId) {
317
336
  const run = db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(runId);
318
337
  if (!run) {
319
- throw new NotFoundError(`Workflow run not found: ${runId}`);
338
+ throw new NotFoundError(`Workflow run "${runId}" not found.`, "WORKFLOW_NOT_FOUND");
320
339
  }
321
340
  return run;
322
341
  }
@@ -416,3 +435,18 @@ function parseJsonArray(value) {
416
435
  }
417
436
  return undefined;
418
437
  }
438
+ export function getActiveWorkflowRun() {
439
+ try {
440
+ const workflowDb = openWorkflowDatabase();
441
+ const row = workflowDb
442
+ .query("SELECT id, current_step_id, workflow_ref FROM workflow_runs WHERE status IN ('active', 'blocked') ORDER BY updated_at DESC LIMIT 1")
443
+ .get();
444
+ closeWorkflowDatabase(workflowDb);
445
+ if (!row)
446
+ return null;
447
+ return { runId: row.id, stepId: row.current_step_id, workflowRef: row.workflow_ref };
448
+ }
449
+ catch {
450
+ return null; // fail-open: never crash show output due to DB error
451
+ }
452
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.7.0-rc1",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Kit Manager) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "akm": "dist/cli.js"
43
43
  },
44
44
  "scripts": {
45
- "build": "rm -rf dist && bun run tsc --project ./tsconfig.json --outDir dist",
45
+ "build": "rm -rf dist && bun run tsc --project ./tsconfig.build.json",
46
46
  "check": "bun run lint && bunx tsc --noEmit && bun test ./tests",
47
47
  "check:changed": "bun test tests/output-baseline.test.ts tests/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
48
48
  "test": "bun test ./tests",
@@ -57,9 +57,9 @@
57
57
  "access": "public"
58
58
  },
59
59
  "devDependencies": {
60
- "@biomejs/biome": "^2.4.6",
61
- "@types/node": "^22.0.0",
62
- "bun-types": "^1.3.10",
60
+ "@biomejs/biome": "^2.4.14",
61
+ "@types/node": "^22.19.17",
62
+ "bun-types": "^1.3.13",
63
63
  "typescript": "^5.9.3"
64
64
  },
65
65
  "optionalDependencies": {
@@ -70,9 +70,9 @@
70
70
  "bun": ">=1.0.0"
71
71
  },
72
72
  "dependencies": {
73
- "@clack/prompts": "^1.1.0",
74
- "citty": "^0.2.1",
73
+ "@clack/prompts": "^1.3.0",
74
+ "citty": "^0.2.2",
75
75
  "dotenv": "^17.4.2",
76
- "yaml": "^2.8.2"
76
+ "yaml": "^2.8.4"
77
77
  }
78
78
  }
@@ -1,119 +0,0 @@
1
- import { afterAll, afterEach, describe, expect, test } from "bun:test";
2
- import { spawn } from "node:child_process";
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- const CLI = path.join(__dirname, "..", "src", "cli.ts");
7
- const tempDirs = [];
8
- const servers = [];
9
- const CLI_TIMEOUT_MS = 30_000;
10
- const TEST_TIMEOUT_MS = 60_000;
11
- function makeTempDir(prefix) {
12
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
13
- tempDirs.push(dir);
14
- return dir;
15
- }
16
- function createWorkingStash() {
17
- const dir = makeTempDir("akm-add-website-stash-");
18
- for (const sub of ["skills", "commands", "agents", "knowledge", "scripts"]) {
19
- fs.mkdirSync(path.join(dir, sub), { recursive: true });
20
- }
21
- return dir;
22
- }
23
- function serveWebsite() {
24
- const server = Bun.serve({
25
- port: 0,
26
- fetch(request) {
27
- const url = new URL(request.url);
28
- if (url.pathname === "/") {
29
- return new Response("<html><head><title>Example Docs</title></head><body><h1>Example Docs</h1><p>Welcome to the docs.</p><a href='/getting-started'>Getting started</a></body></html>", {
30
- headers: { "Content-Type": "text/html; charset=utf-8" },
31
- });
32
- }
33
- if (url.pathname === "/getting-started") {
34
- return new Response("<html><body><h1>Getting started</h1><p>Run setup first.</p></body></html>", {
35
- headers: { "Content-Type": "text/html; charset=utf-8" },
36
- });
37
- }
38
- return new Response("not found", { status: 404 });
39
- },
40
- });
41
- servers.push(server);
42
- return `http://127.0.0.1:${server.port}`;
43
- }
44
- afterEach(() => {
45
- for (const server of servers.splice(0)) {
46
- server.stop(true);
47
- }
48
- for (const dir of tempDirs.splice(0)) {
49
- fs.rmSync(dir, { recursive: true, force: true });
50
- }
51
- });
52
- afterAll(() => {
53
- for (const server of servers.splice(0)) {
54
- server.stop(true);
55
- }
56
- });
57
- describe("akm add website", () => {
58
- test("adds a website stash source, caches markdown, and indexes it", async () => {
59
- const stashDir = createWorkingStash();
60
- const xdgCache = makeTempDir("akm-add-website-cache-");
61
- const xdgConfig = makeTempDir("akm-add-website-config-");
62
- const websiteUrl = serveWebsite();
63
- const configDir = path.join(xdgConfig, "akm");
64
- fs.mkdirSync(configDir, { recursive: true });
65
- fs.writeFileSync(path.join(configDir, "config.json"), `${JSON.stringify({ semanticSearchMode: "off" }, null, 2)}\n`);
66
- const child = spawn("bun", [CLI, "add", websiteUrl, "--name", "docs-site", "--format=json"], {
67
- stdio: ["ignore", "pipe", "pipe"],
68
- env: {
69
- ...process.env,
70
- AKM_STASH_DIR: stashDir,
71
- XDG_CACHE_HOME: xdgCache,
72
- XDG_CONFIG_HOME: xdgConfig,
73
- },
74
- });
75
- let stdout = "";
76
- let stderr = "";
77
- child.stdout.on("data", (chunk) => {
78
- stdout += String(chunk);
79
- });
80
- child.stderr.on("data", (chunk) => {
81
- stderr += String(chunk);
82
- });
83
- const exitCode = await new Promise((resolve, reject) => {
84
- const timer = setTimeout(() => {
85
- child.kill("SIGKILL");
86
- reject(new Error("CLI website add timed out"));
87
- }, CLI_TIMEOUT_MS);
88
- child.on("error", (err) => {
89
- clearTimeout(timer);
90
- reject(err);
91
- });
92
- child.on("close", (code) => {
93
- clearTimeout(timer);
94
- resolve(code ?? 1);
95
- });
96
- });
97
- expect(exitCode).toBe(0);
98
- expect(stderr.trim()).toBe("");
99
- const parsed = JSON.parse(stdout.trim());
100
- const normalizedWebsiteUrl = `${websiteUrl}/`;
101
- expect(parsed.sourceAdded).toBeDefined();
102
- expect(parsed.sourceAdded?.type).toBe("website");
103
- expect(parsed.sourceAdded?.url).toBe(normalizedWebsiteUrl);
104
- expect(parsed.sourceAdded?.name).toBe("docs-site");
105
- expect(parsed.index?.totalEntries).toBeGreaterThanOrEqual(2);
106
- const configPath = path.join(xdgConfig, "akm", "config.json");
107
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
108
- expect(config.sources).toContainEqual({
109
- type: "website",
110
- url: normalizedWebsiteUrl,
111
- name: "docs-site",
112
- });
113
- expect(parsed.sourceAdded?.stashRoot).toBeDefined();
114
- const knowledgeFiles = fs.readdirSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge")).sort();
115
- expect(knowledgeFiles).toEqual(["getting-started.md", "index.md"]);
116
- const homeDoc = fs.readFileSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge", "index.md"), "utf8");
117
- expect(homeDoc).toContain("Example Docs");
118
- }, { timeout: TEST_TIMEOUT_MS });
119
- });