akm-cli 0.8.6 → 0.8.14

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 (324) hide show
  1. package/CHANGELOG.md +442 -0
  2. package/dist/assets/help/help-proposals.md +1 -2
  3. package/dist/assets/hints/cli-hints-full.md +34 -19
  4. package/dist/assets/hints/cli-hints-short.md +1 -1
  5. package/dist/assets/profiles/catchup.json +13 -0
  6. package/dist/assets/profiles/consolidate.json +13 -0
  7. package/dist/assets/profiles/frequent.json +13 -0
  8. package/dist/assets/tasks/core/backup.yml +4 -0
  9. package/dist/assets/tasks/core/extract.yml +4 -0
  10. package/dist/assets/tasks/core/improve.yml +4 -0
  11. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  12. package/dist/assets/tasks/core/sync.yml +4 -0
  13. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  14. package/dist/assets/tasks/core/version-check.yml +4 -0
  15. package/dist/assets/templates/html/default.html +78 -0
  16. package/dist/assets/templates/html/health.html +560 -0
  17. package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
  18. package/dist/cli/config-migrate.js +6 -6
  19. package/dist/cli/config-validate.js +4 -4
  20. package/dist/cli/confirm.js +3 -3
  21. package/dist/cli/parse-args.js +1 -1
  22. package/dist/cli/shared.js +72 -19
  23. package/dist/cli-node.mjs +26 -0
  24. package/dist/cli.js +206 -3866
  25. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  26. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  27. package/dist/commands/agent/contribute-cli.js +200 -0
  28. package/dist/commands/completions.js +1 -1
  29. package/dist/commands/config-cli.js +230 -3
  30. package/dist/commands/db-cli.js +2 -2
  31. package/dist/commands/env/env-cli.js +529 -0
  32. package/dist/commands/env/env.js +410 -0
  33. package/dist/commands/env/secret-cli.js +259 -0
  34. package/dist/commands/{secret.js → env/secret.js} +6 -47
  35. package/dist/commands/events.js +4 -4
  36. package/dist/commands/feedback-cli.js +18 -34
  37. package/dist/commands/graph/graph-cli.js +132 -0
  38. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  39. package/dist/commands/health/checks.js +279 -0
  40. package/dist/commands/health/html-report.js +448 -0
  41. package/dist/commands/health.js +189 -266
  42. package/dist/commands/{consolidate.js → improve/consolidate.js} +63 -38
  43. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  44. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  45. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  46. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  47. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  48. package/dist/commands/{extract.js → improve/extract.js} +221 -26
  49. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
  50. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
  51. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  52. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
  53. package/dist/commands/{improve.js → improve/improve.js} +672 -292
  54. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  55. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  56. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  57. package/dist/commands/improve/reflect-noise.js +0 -0
  58. package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
  59. package/dist/commands/improve/session-asset.js +248 -0
  60. package/dist/commands/lint/agent-linter.js +1 -1
  61. package/dist/commands/lint/base-linter.js +55 -37
  62. package/dist/commands/lint/command-linter.js +1 -1
  63. package/dist/commands/lint/default-linter.js +1 -1
  64. package/dist/commands/lint/env-key-rules.js +1 -1
  65. package/dist/commands/lint/index.js +19 -25
  66. package/dist/commands/lint/knowledge-linter.js +1 -1
  67. package/dist/commands/lint/memory-linter.js +1 -1
  68. package/dist/commands/lint/registry.js +8 -8
  69. package/dist/commands/lint/skill-linter.js +1 -1
  70. package/dist/commands/lint/task-linter.js +1 -1
  71. package/dist/commands/lint/workflow-linter.js +1 -1
  72. package/dist/commands/lint.js +1 -1
  73. package/dist/commands/observability-cli.js +244 -0
  74. package/dist/commands/proposal/drain-policies.js +3 -3
  75. package/dist/commands/proposal/drain.js +87 -15
  76. package/dist/commands/proposal/proposal-cli.js +490 -0
  77. package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
  78. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  79. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  80. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  81. package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
  82. package/dist/commands/{curate.js → read/curate.js} +7 -7
  83. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  84. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  85. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  86. package/dist/commands/read/search-cli.js +207 -0
  87. package/dist/commands/{search.js → read/search.js} +22 -27
  88. package/dist/commands/{show.js → read/show.js} +31 -45
  89. package/dist/commands/registry-cli.js +8 -8
  90. package/dist/commands/remember.js +14 -10
  91. package/dist/commands/sources/add-cli.js +293 -0
  92. package/dist/commands/{history.js → sources/history.js} +27 -25
  93. package/dist/commands/{info.js → sources/info.js} +6 -6
  94. package/dist/commands/{init.js → sources/init.js} +6 -6
  95. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  96. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  97. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  98. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  99. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  100. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  101. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  102. package/dist/commands/sources/sources-cli.js +305 -0
  103. package/dist/commands/sources/stash-cli.js +219 -0
  104. package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
  105. package/dist/commands/tasks/default-tasks.js +173 -0
  106. package/dist/commands/tasks/tasks-cli.js +210 -0
  107. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  108. package/dist/commands/wiki-cli.js +307 -0
  109. package/dist/commands/workflow-cli.js +329 -0
  110. package/dist/core/action-contributors.js +1 -1
  111. package/dist/core/assert.js +40 -0
  112. package/dist/core/asset/asset-create.js +54 -0
  113. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  114. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  115. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  116. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  117. package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
  118. package/dist/core/best-effort.js +64 -0
  119. package/dist/core/common.js +32 -18
  120. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  121. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  122. package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
  123. package/dist/core/config/config-types.js +16 -0
  124. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  125. package/dist/core/{config.js → config/config.js} +10 -8
  126. package/dist/core/env-secret-ref.js +90 -0
  127. package/dist/core/errors.js +13 -3
  128. package/dist/core/events.js +27 -4
  129. package/dist/core/file-lock.js +1 -1
  130. package/dist/core/improve-types.js +48 -0
  131. package/dist/core/lesson-lint.js +2 -2
  132. package/dist/core/logs-db.js +304 -0
  133. package/dist/core/paths.js +2 -2
  134. package/dist/core/ripgrep/install.js +2 -2
  135. package/dist/core/ripgrep/resolve.js +2 -2
  136. package/dist/core/state-db.js +195 -60
  137. package/dist/core/text-truncation.js +148 -0
  138. package/dist/core/time.js +1 -1
  139. package/dist/core/write-source.js +98 -85
  140. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  141. package/dist/indexer/{db.js → db/db.js} +128 -118
  142. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  143. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  144. package/dist/indexer/ensure-index.js +4 -4
  145. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  146. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  147. package/dist/indexer/indexer.js +37 -30
  148. package/dist/indexer/init.js +54 -0
  149. package/dist/indexer/manifest.js +10 -10
  150. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
  151. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  152. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  153. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  154. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  155. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  156. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  157. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  158. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  159. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  160. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  161. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  162. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  163. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  164. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  165. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  166. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  167. package/dist/integrations/agent/builder-shared.js +39 -0
  168. package/dist/integrations/agent/builders.js +14 -81
  169. package/dist/integrations/agent/config.js +6 -4
  170. package/dist/integrations/agent/detect.js +1 -1
  171. package/dist/integrations/agent/index.js +23 -8
  172. package/dist/integrations/agent/prompts.js +2 -3
  173. package/dist/integrations/agent/runner.js +22 -3
  174. package/dist/integrations/agent/spawn.js +9 -10
  175. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  176. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  177. package/dist/integrations/harnesses/claude/index.js +64 -0
  178. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
  179. package/dist/integrations/harnesses/index.js +144 -0
  180. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  181. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  182. package/dist/integrations/harnesses/opencode/index.js +59 -0
  183. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  184. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  185. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  186. package/dist/integrations/harnesses/types.js +43 -0
  187. package/dist/integrations/lockfile.js +7 -16
  188. package/dist/integrations/session-logs/index.js +82 -9
  189. package/dist/llm/call-ai.js +4 -4
  190. package/dist/llm/client.js +146 -6
  191. package/dist/llm/embedder.js +6 -6
  192. package/dist/llm/embedders/local.js +9 -22
  193. package/dist/llm/embedders/remote.js +2 -2
  194. package/dist/llm/embedders/types.js +1 -1
  195. package/dist/llm/graph-extract.js +31 -12
  196. package/dist/llm/index-passes.js +1 -1
  197. package/dist/llm/memory-infer.js +12 -5
  198. package/dist/llm/metadata-enhance.js +2 -2
  199. package/dist/llm/usage-persist.js +77 -0
  200. package/dist/llm/usage-telemetry.js +103 -0
  201. package/dist/output/context.js +9 -46
  202. package/dist/output/html-render.js +73 -0
  203. package/dist/output/renderers.js +88 -58
  204. package/dist/output/shapes/curate.js +7 -3
  205. package/dist/output/shapes/distill.js +7 -3
  206. package/dist/output/shapes/env-list.js +18 -16
  207. package/dist/output/shapes/events.js +5 -4
  208. package/dist/output/shapes/helpers.js +19 -5
  209. package/dist/output/shapes/history.js +7 -3
  210. package/dist/output/shapes/passthrough.js +8 -11
  211. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  212. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  213. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  214. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  215. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  216. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  217. package/dist/output/shapes/registry-search.js +7 -3
  218. package/dist/output/shapes/registry.js +12 -0
  219. package/dist/output/shapes/search.js +7 -3
  220. package/dist/output/shapes/secret-list.js +18 -16
  221. package/dist/output/shapes/show.js +7 -3
  222. package/dist/output/shapes.js +55 -30
  223. package/dist/output/text/add.js +2 -3
  224. package/dist/output/text/clone.js +2 -3
  225. package/dist/output/text/config.js +2 -3
  226. package/dist/output/text/curate.js +4 -3
  227. package/dist/output/text/distill.js +2 -3
  228. package/dist/output/text/enable-disable.js +5 -4
  229. package/dist/output/text/env.js +13 -0
  230. package/dist/output/text/events.js +5 -4
  231. package/dist/output/text/feedback.js +4 -3
  232. package/dist/output/text/helpers.js +123 -40
  233. package/dist/output/text/history.js +2 -3
  234. package/dist/output/text/import.js +2 -3
  235. package/dist/output/text/index.js +2 -3
  236. package/dist/output/text/info.js +2 -3
  237. package/dist/output/text/init.js +2 -3
  238. package/dist/output/text/list.js +2 -3
  239. package/dist/output/text/proposal/producer.js +9 -0
  240. package/dist/output/text/proposal/proposal.js +13 -0
  241. package/dist/output/text/registry-commands.js +8 -7
  242. package/dist/output/text/registry.js +12 -0
  243. package/dist/output/text/remember.js +4 -3
  244. package/dist/output/text/remove.js +2 -3
  245. package/dist/output/text/save.js +2 -3
  246. package/dist/output/text/search.js +4 -3
  247. package/dist/output/text/show.js +4 -3
  248. package/dist/output/text/update.js +2 -3
  249. package/dist/output/text/upgrade.js +2 -3
  250. package/dist/output/text/wiki.js +12 -11
  251. package/dist/output/text/workflow.js +12 -10
  252. package/dist/output/text.js +66 -32
  253. package/dist/registry/build-index.js +11 -10
  254. package/dist/registry/factory.js +1 -1
  255. package/dist/registry/origin-resolve.js +1 -1
  256. package/dist/registry/providers/index.js +2 -2
  257. package/dist/registry/providers/skills-sh.js +91 -72
  258. package/dist/registry/providers/static-index.js +75 -52
  259. package/dist/registry/resolve.js +3 -3
  260. package/dist/runtime.js +242 -0
  261. package/dist/scripts/migrate-storage.js +1654 -683
  262. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
  263. package/dist/setup/detect.js +311 -9
  264. package/dist/setup/harness-config-import.js +6 -120
  265. package/dist/setup/setup.js +454 -43
  266. package/dist/sources/include.js +1 -1
  267. package/dist/sources/provider-factory.js +2 -2
  268. package/dist/sources/providers/filesystem.js +3 -3
  269. package/dist/sources/providers/git.js +9 -9
  270. package/dist/sources/providers/index.js +4 -4
  271. package/dist/sources/providers/npm.js +6 -6
  272. package/dist/sources/providers/provider-utils.js +13 -20
  273. package/dist/sources/providers/sync-from-ref.js +5 -5
  274. package/dist/sources/providers/tar-utils.js +2 -2
  275. package/dist/sources/providers/website.js +2 -2
  276. package/dist/sources/resolve.js +5 -5
  277. package/dist/sources/website-ingest.js +5 -5
  278. package/dist/storage/database.js +102 -0
  279. package/dist/storage/engines/sqlite-migrations.js +42 -0
  280. package/dist/storage/locations.js +25 -0
  281. package/dist/storage/repositories/index-db.js +43 -0
  282. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  283. package/dist/tasks/backends/cron.js +4 -4
  284. package/dist/tasks/backends/exec-utils.js +32 -0
  285. package/dist/tasks/backends/index.js +3 -3
  286. package/dist/tasks/backends/launchd.js +7 -14
  287. package/dist/tasks/backends/schtasks.js +7 -16
  288. package/dist/tasks/embedded.js +71 -0
  289. package/dist/tasks/parser.js +2 -2
  290. package/dist/tasks/resolveAkmBin.js +1 -1
  291. package/dist/tasks/runner.js +127 -31
  292. package/dist/tasks/schedule.js +1 -1
  293. package/dist/tasks/validator.js +7 -7
  294. package/dist/text-import-hook.mjs +51 -0
  295. package/dist/version.js +2 -1
  296. package/dist/wiki/wiki.js +7 -7
  297. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  298. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  299. package/dist/workflows/cli.js +1 -1
  300. package/dist/workflows/db.js +54 -32
  301. package/dist/workflows/parser.js +4 -4
  302. package/dist/workflows/renderer.js +5 -5
  303. package/dist/workflows/runtime/agent-identity.js +56 -0
  304. package/dist/workflows/runtime/checkin.js +57 -0
  305. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  306. package/dist/workflows/validate-summary.js +82 -0
  307. package/docs/README.md +1 -1
  308. package/docs/data-and-telemetry.md +6 -6
  309. package/package.json +17 -8
  310. package/dist/commands/add-cli.js +0 -279
  311. package/dist/commands/env.js +0 -213
  312. package/dist/integrations/agent/sdk-runner.js +0 -126
  313. package/dist/output/shapes/vault-list.js +0 -19
  314. package/dist/output/text/proposal-producer.js +0 -8
  315. package/dist/output/text/proposal.js +0 -12
  316. package/dist/output/text/vault.js +0 -16
  317. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  318. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  319. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  320. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  321. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  322. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  323. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  324. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -3,13 +3,13 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { makeAssetRef, parseAssetRef } from "../core/asset-ref";
7
- import { TYPE_DIRS } from "../core/asset-spec";
8
- import { NotFoundError, UsageError } from "../core/errors";
9
- import { findSourceForPath, getPrimarySource, resolveSourceEntries } from "../indexer/search-source";
10
- import { isRemoteOrigin, resolveSourcesForOrigin } from "../registry/origin-resolve";
11
- import { syncFromRef } from "../sources/providers/sync-from-ref";
12
- import { resolveAssetPath } from "../sources/resolve";
6
+ import { makeAssetRef, parseAssetRef } from "../../core/asset/asset-ref.js";
7
+ import { TYPE_DIRS } from "../../core/asset/asset-spec.js";
8
+ import { NotFoundError, UsageError } from "../../core/errors.js";
9
+ import { findSourceForPath, getPrimarySource, resolveSourceEntries, } from "../../indexer/search/search-source.js";
10
+ import { isRemoteOrigin, resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
11
+ import { syncFromRef } from "../../sources/providers/sync-from-ref.js";
12
+ import { resolveAssetPath } from "../../sources/resolve.js";
13
13
  export async function akmClone(options) {
14
14
  const parsed = parseAssetRef(options.sourceRef);
15
15
  // When --dest is provided, the working stash is optional
@@ -2,10 +2,10 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import path from "node:path";
5
- import { isRemoteUrl } from "../core/common";
6
- import { getSources, loadConfig, loadUserConfig, saveConfig } from "../core/config";
7
- import { ConfigError, UsageError } from "../core/errors";
8
- import { resolveSourceEntries } from "../indexer/search-source";
5
+ import { isRemoteUrl } from "../../core/common.js";
6
+ import { getSources, loadConfig, loadUserConfig, saveConfig } from "../../core/config/config.js";
7
+ import { ConfigError, UsageError } from "../../core/errors.js";
8
+ import { resolveSourceEntries } from "../../indexer/search/search-source.js";
9
9
  // ── Operations ──────────────────────────────────────────────────────────────
10
10
  /**
11
11
  * Add a stash source (filesystem path or remote provider URL) to config.
@@ -0,0 +1,305 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Source-management CLI commands — `akm list/remove/update/upgrade/sync/clone/history`.
6
+ *
7
+ * Extracted verbatim from src/cli.ts (WS6). Each `main.subCommands.<key>`
8
+ * registration line stays byte-identical; the args/output shape of every
9
+ * subcommand is unchanged. The `--kind` filter helper (`parseKindFilter` +
10
+ * `VALID_SOURCE_KINDS`), the `runSyncBody` git-commit/push body, and the
11
+ * `wasFormatValueConsumedAsName` citty-mis-parse workaround are used ONLY by
12
+ * this cluster, so they move with it.
13
+ *
14
+ * Leaf handlers whose body is a plain `runWithJsonErrors(async () => { … })`
15
+ * are migrated to `defineJsonCommand`, which emits the same JSON envelope
16
+ * (stdout/stderr/exit-code) as the inline form. `sync` keeps `defineCommand`
17
+ * because its `run` delegates to `runSyncBody` (which owns the
18
+ * `runWithJsonErrors` wrapper) rather than wrapping inline.
19
+ */
20
+ import { defineCommand } from "citty";
21
+ import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
22
+ import { loadConfig } from "../../core/config/config.js";
23
+ import { UsageError } from "../../core/errors.js";
24
+ import { appendEvent } from "../../core/events.js";
25
+ import { resolveSourceEntries } from "../../indexer/search/search-source.js";
26
+ import { getHyphenatedBoolean, parseFlagValue } from "../../output/context.js";
27
+ import { resolveWritableOverride, saveGitStash } from "../../sources/providers/git.js";
28
+ import { pkgVersion } from "../../version.js";
29
+ import { akmHistory } from "./history.js";
30
+ import { akmListSources, akmRemove, akmUpdate } from "./installed-stashes.js";
31
+ import { checkForUpdate, performUpgrade } from "./self-update.js";
32
+ import { akmClone } from "./source-clone.js";
33
+ const VALID_SOURCE_KINDS = new Set(["local", "managed", "remote"]);
34
+ function parseKindFilter(raw) {
35
+ if (!raw)
36
+ return undefined;
37
+ const kinds = raw.split(",").map((s) => s.trim());
38
+ for (const k of kinds) {
39
+ if (!VALID_SOURCE_KINDS.has(k)) {
40
+ throw new UsageError(`Invalid --kind value: "${k}". Expected one of: local, managed, remote`);
41
+ }
42
+ }
43
+ return kinds;
44
+ }
45
+ export const listCommand = defineJsonCommand({
46
+ meta: { name: "list", description: "List all sources (local directories, managed packages, remote providers)" },
47
+ args: {
48
+ kind: { type: "string", description: "Filter by source kind (local, managed, remote). Comma-separated." },
49
+ },
50
+ async run({ args }) {
51
+ const kind = parseKindFilter(args.kind);
52
+ const result = await akmListSources({ kind });
53
+ output("list", result);
54
+ },
55
+ });
56
+ export const removeCommand = defineJsonCommand({
57
+ meta: { name: "remove", description: "Remove a source by id, ref, path, URL, or name" },
58
+ args: {
59
+ target: { type: "positional", description: "Source to remove (id, ref, path, URL, or name)", required: true },
60
+ yes: { type: "boolean", alias: "y", description: "Skip confirmation prompt", default: false },
61
+ },
62
+ async run({ args }) {
63
+ const { confirmDestructive } = await import("../../cli/confirm.js");
64
+ const confirmed = await confirmDestructive(`Remove source "${args.target}"? This cannot be undone.`, {
65
+ yes: args.yes === true,
66
+ });
67
+ if (!confirmed) {
68
+ process.stderr.write("Aborted.\n");
69
+ return;
70
+ }
71
+ const result = await akmRemove({ target: args.target });
72
+ appendEvent({
73
+ eventType: "remove",
74
+ metadata: {
75
+ target: args.target,
76
+ ref: typeof result.removed?.ref === "string" ? result.removed.ref : null,
77
+ id: typeof result.removed?.id === "string" ? result.removed.id : null,
78
+ },
79
+ });
80
+ output("remove", result);
81
+ },
82
+ });
83
+ export const updateCommand = defineJsonCommand({
84
+ meta: { name: "update", description: "Update one or all managed sources" },
85
+ args: {
86
+ target: { type: "positional", description: "Source to update (id or ref)", required: false },
87
+ all: { type: "boolean", description: "Update all installed entries", default: false },
88
+ force: { type: "boolean", description: "Force fresh download even if version is unchanged", default: false },
89
+ },
90
+ async run({ args }) {
91
+ const result = await akmUpdate({ target: args.target, all: args.all, force: args.force });
92
+ appendEvent({
93
+ eventType: "update",
94
+ metadata: {
95
+ target: args.target ?? null,
96
+ all: args.all === true,
97
+ force: args.force === true,
98
+ processed: Array.isArray(result.processed)
99
+ ? result.processed.length
100
+ : 0,
101
+ },
102
+ });
103
+ output("update", result);
104
+ },
105
+ });
106
+ export const upgradeCommand = defineJsonCommand({
107
+ meta: { name: "upgrade", description: "Upgrade akm to the latest release" },
108
+ args: {
109
+ check: { type: "boolean", description: "Check for updates without installing", default: false },
110
+ force: { type: "boolean", description: "Force upgrade even if on latest", default: false },
111
+ "skip-checksum": {
112
+ type: "boolean",
113
+ description: "Skip checksum verification (not recommended)",
114
+ default: false,
115
+ },
116
+ "skip-post-upgrade": {
117
+ type: "boolean",
118
+ description: "Skip the post-upgrade `akm index` rebuild (config auto-migration still runs on next `akm` invocation)",
119
+ default: false,
120
+ },
121
+ },
122
+ async run({ args }) {
123
+ const check = await checkForUpdate(pkgVersion);
124
+ if (args.check) {
125
+ output("upgrade", check);
126
+ return;
127
+ }
128
+ const skipChecksum = getHyphenatedBoolean(args, "skip-checksum");
129
+ const skipPostUpgrade = getHyphenatedBoolean(args, "skip-post-upgrade");
130
+ const result = await performUpgrade(check, { force: args.force, skipChecksum, skipPostUpgrade });
131
+ output("upgrade", result);
132
+ },
133
+ });
134
+ // `sync` body. Kept as a standalone function so the git-commit/push logic and
135
+ // the `--format`-as-name workaround stay in one place.
136
+ async function runSyncBody(args, verb) {
137
+ await runWithJsonErrors(async () => {
138
+ // Fix: citty can consume `--format json` (space-separated) as the
139
+ // positional `name` argument (e.g. `akm sync --format json` parses
140
+ // name="json"). Detect the mis-parse by checking argv order — only
141
+ // treat the positional as consumed by --format when --format appears
142
+ // before any standalone occurrence of the same value in the sync
143
+ // subcommand's argv slice. This preserves legitimate invocations
144
+ // like `akm sync json --format json`.
145
+ const parsedFormat = parseFlagValue(process.argv, "--format");
146
+ const effectiveName = args.name !== undefined &&
147
+ parsedFormat !== undefined &&
148
+ args.name === parsedFormat &&
149
+ wasFormatValueConsumedAsName(args.name, parsedFormat, verb)
150
+ ? undefined
151
+ : args.name;
152
+ let writable;
153
+ if (effectiveName === undefined) {
154
+ // Primary stash — honour the root-level writable flag from config.
155
+ writable = resolveWritableOverride(loadConfig());
156
+ }
157
+ const result = saveGitStash(effectiveName, args.message, writable, { push: args.push !== false });
158
+ appendEvent({
159
+ eventType: "save",
160
+ metadata: {
161
+ name: effectiveName ?? null,
162
+ message: args.message ?? null,
163
+ ok: result.ok !== false,
164
+ },
165
+ });
166
+ output("save", result);
167
+ });
168
+ }
169
+ export const syncCommand = defineCommand({
170
+ meta: {
171
+ name: "sync",
172
+ description: "Sync changes in a git-backed stash: commits (and pushes when writable + remote is configured). No-op for non-git stashes.",
173
+ },
174
+ args: {
175
+ name: {
176
+ type: "positional",
177
+ description: "Name of the git stash to sync (default: primary stash directory)",
178
+ required: false,
179
+ },
180
+ message: {
181
+ type: "string",
182
+ alias: "m",
183
+ description: "Commit message (default: timestamp)",
184
+ },
185
+ push: {
186
+ type: "boolean",
187
+ description: "Push after commit when writable + remote configured (use --no-push to commit only). Default: true.",
188
+ default: true,
189
+ },
190
+ },
191
+ async run({ args }) {
192
+ await runSyncBody(args, "sync");
193
+ },
194
+ });
195
+ /**
196
+ * Detect whether `--format <value>` was consumed by citty as the optional
197
+ * `name` positional of `akm sync`. Returns true only when `--format` appears
198
+ * in the sync subcommand's argv slice AND the candidate name does NOT
199
+ * appear as a standalone positional elsewhere (before or after the flag).
200
+ *
201
+ * This keeps `akm sync json --format json` routing `json` as the stash name,
202
+ * while `akm sync --format json` (no separate positional) is treated as a
203
+ * primary-stash sync. `verb` is the subcommand token to anchor on.
204
+ */
205
+ function wasFormatValueConsumedAsName(name, formatValue, verb) {
206
+ const argv = process.argv.slice(2);
207
+ const verbIndex = argv.indexOf(verb);
208
+ const tokens = verbIndex >= 0 ? argv.slice(verbIndex + 1) : argv;
209
+ let formatIndex = -1;
210
+ let formatConsumesNextToken = false;
211
+ for (let i = 0; i < tokens.length; i += 1) {
212
+ const token = tokens[i];
213
+ if (token === "--format") {
214
+ formatIndex = i;
215
+ formatConsumesNextToken = true;
216
+ break;
217
+ }
218
+ if (token === `--format=${formatValue}`) {
219
+ formatIndex = i;
220
+ break;
221
+ }
222
+ }
223
+ if (formatIndex === -1)
224
+ return false;
225
+ // If the name appears as a standalone token before --format, it's the
226
+ // real positional and --format did not consume it.
227
+ if (tokens.slice(0, formatIndex).includes(name))
228
+ return false;
229
+ // If --format has a space-separated value, skip past the value token
230
+ // when scanning after the flag; otherwise start right after the flag.
231
+ const firstTokenAfterFormat = formatIndex + (formatConsumesNextToken ? 2 : 1);
232
+ if (tokens.slice(firstTokenAfterFormat).includes(name))
233
+ return false;
234
+ return true;
235
+ }
236
+ export const cloneCommand = defineJsonCommand({
237
+ meta: {
238
+ name: "clone",
239
+ description: "Clone an asset from any source into the working stash or a custom destination",
240
+ },
241
+ args: {
242
+ ref: { type: "positional", description: "Asset ref (e.g. npm:@scope/pkg//script:deploy.sh)", required: true },
243
+ name: { type: "string", description: "New name for the cloned asset" },
244
+ force: { type: "boolean", description: "Overwrite if asset already exists in working stash", default: false },
245
+ dest: { type: "string", description: "Destination directory (default: working stash)" },
246
+ },
247
+ async run({ args }) {
248
+ const result = await akmClone({
249
+ sourceRef: args.ref,
250
+ newName: args.name,
251
+ force: args.force,
252
+ dest: args.dest,
253
+ });
254
+ output("clone", result);
255
+ },
256
+ });
257
+ export const historyCommand = defineJsonCommand({
258
+ meta: {
259
+ name: "history",
260
+ description: "Show mutation/usage history for a single asset (--ref) or stash-wide.\n\n" +
261
+ "Event sources:\n" +
262
+ " usage_events (default): search, show, and feedback events from the local index.\n" +
263
+ " state.db events (--include-proposals): proposal lifecycle events (promoted, rejected)\n" +
264
+ " emitted by `akm accept` / `akm reject`.\n\n" +
265
+ "Results from all active sources are merged and sorted chronologically.",
266
+ },
267
+ args: {
268
+ ref: { type: "string", description: "Asset ref (type:name). Omit for stash-wide history." },
269
+ since: { type: "string", description: "ISO timestamp or epoch ms — only events on/after this time" },
270
+ generator: {
271
+ type: "string",
272
+ description: 'Filter by event generator: "user" (default) or "improve" (akm improve operations).',
273
+ },
274
+ "include-proposals": {
275
+ type: "boolean",
276
+ description: "Also include proposal lifecycle events (promoted, rejected) from state.db events. " +
277
+ "Default: false (usage_events only).",
278
+ default: false,
279
+ },
280
+ "accept-rate-by-source": {
281
+ type: "boolean",
282
+ description: "Compute accept-rate-per-source metrics from the proposal store and include them in the output (F-4 / #385). " +
283
+ "Useful for measuring which generators (reflect, distill, …) produce the most accepted proposals.",
284
+ default: false,
285
+ },
286
+ format: { type: "string", description: "Output format (json|jsonl|text|yaml)" },
287
+ },
288
+ async run({ args }) {
289
+ const generatorFlag = args.generator;
290
+ if (generatorFlag !== undefined && generatorFlag !== "user" && generatorFlag !== "improve") {
291
+ throw new UsageError(`Invalid --generator value: "${generatorFlag}". Must be "user" or "improve".`, "INVALID_FLAG_VALUE");
292
+ }
293
+ const sources = resolveSourceEntries();
294
+ const stashDir = sources[0]?.path;
295
+ const result = await akmHistory({
296
+ ref: args.ref,
297
+ since: args.since,
298
+ source: generatorFlag,
299
+ includeProposals: args["include-proposals"],
300
+ acceptRateBySource: args["accept-rate-by-source"],
301
+ stashDir,
302
+ });
303
+ output("history", result);
304
+ },
305
+ });
@@ -0,0 +1,219 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Stash-lifecycle command cluster — the create/index/ingest/inspect verbs for
6
+ * the working stash and its index database: `akm init` (create the stash +
7
+ * persist stashDir), `akm index` (build/refresh the search index), `akm import`
8
+ * (ingest a knowledge doc/URL), `akm db` (+ nested `backups` — inspect the
9
+ * SQLite data dir), and `akm info` (system capabilities + index stats).
10
+ * Extracted verbatim from src/cli.ts (WS6) so the God Module shrinks; the
11
+ * `main.subCommands.{init,index,import,db,info}` keys and every subcommand's
12
+ * args/output shape stay byte-identical.
13
+ *
14
+ * These share no private helper with any command still inline in cli.ts — every
15
+ * dependency is already exported from a shared module (core/paths, core/warn,
16
+ * core/errors, core/events, output/context, cli/shared, cli/parse-args, plus the
17
+ * per-command implementations in ./init, ./indexer, ./info, ./db-cli, ./knowledge,
18
+ * ./core/asset-create, ./core/common), so the cluster moves with zero hoisting.
19
+ *
20
+ * The leaf handlers whose body is a plain `runWithJsonErrors(...) + output(...)`
21
+ * (`init`, `import`, `info`, `db`, `db backups`) are migrated onto
22
+ * `defineJsonCommand`, which emits the same JSON envelope (stdout/stderr/
23
+ * exit-code) as the inline form. `index` keeps a plain `defineCommand` wrapping
24
+ * `runWithJsonErrors` because its body owns a spinner, an AbortController, and
25
+ * SIGINT/SIGTERM handlers in a try/finally — left byte-for-byte untouched.
26
+ */
27
+ import path from "node:path";
28
+ import * as p from "@clack/prompts";
29
+ import { defineCommand } from "citty";
30
+ import { hasSubcommand } from "../../cli/parse-args.js";
31
+ import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
32
+ import { assertFlatAssetName } from "../../core/asset/asset-create.js";
33
+ import { isHttpUrl } from "../../core/common.js";
34
+ import { UsageError } from "../../core/errors.js";
35
+ import { appendEvent } from "../../core/events.js";
36
+ import { getCacheDir } from "../../core/paths.js";
37
+ import { clearLogFile, info, isVerbose, setLogFile } from "../../core/warn.js";
38
+ import { akmIndex } from "../../indexer/indexer.js";
39
+ import { getHyphenatedBoolean, getOutputMode, parseFlagValue } from "../../output/context.js";
40
+ import { akmDbBackups } from "../db-cli.js";
41
+ import { readKnowledgeInput, writeMarkdownAsset } from "../read/knowledge.js";
42
+ import { assembleInfo } from "./info.js";
43
+ import { akmInit } from "./init.js";
44
+ export const initCommand = defineJsonCommand({
45
+ meta: {
46
+ name: "init",
47
+ description: "Initialize akm's working stash directory and persist stashDir in config",
48
+ },
49
+ args: {
50
+ dir: { type: "string", description: "Custom stash directory path (default: ~/akm)" },
51
+ },
52
+ async run({ args }) {
53
+ // Accept both historical spellings for backwards compatibility with
54
+ // older docs/scripts that used `--stashDir`.
55
+ const legacyDir = parseFlagValue(process.argv, "--stashDir") ?? parseFlagValue(process.argv, "--stash-dir");
56
+ const result = await akmInit({ dir: args.dir ?? legacyDir });
57
+ output("init", result);
58
+ },
59
+ });
60
+ export const indexCommand = defineCommand({
61
+ meta: { name: "index", description: "Build search index (incremental by default; --full forces full reindex)" },
62
+ args: {
63
+ full: { type: "boolean", description: "Force full reindex", default: false },
64
+ clean: {
65
+ type: "boolean",
66
+ description: "After indexing, remove any entries whose source file no longer exists on disk.",
67
+ default: false,
68
+ },
69
+ "dry-run": {
70
+ type: "boolean",
71
+ description: "When combined with --clean, report stale entries without deleting them.",
72
+ default: false,
73
+ },
74
+ },
75
+ async run({ args }) {
76
+ await runWithJsonErrors(async () => {
77
+ if (getHyphenatedBoolean(args, "enrich") || parseFlagValue(process.argv, "--enrich") !== undefined) {
78
+ throw new UsageError("`akm index --enrich` has been removed. Plain `akm index` now performs metadata enrichment by default.");
79
+ }
80
+ if (getHyphenatedBoolean(args, "re-enrich") || parseFlagValue(process.argv, "--re-enrich") !== undefined) {
81
+ throw new UsageError("`akm index --re-enrich` has been removed. Re-enrichment of index-time LLM passes is not exposed in this slice.");
82
+ }
83
+ const outputMode = getOutputMode();
84
+ const controller = new AbortController();
85
+ const abort = () => controller.abort(new Error("index interrupted"));
86
+ process.once("SIGINT", abort);
87
+ process.once("SIGTERM", abort);
88
+ const indexLogFile = path.join(getCacheDir(), "logs", "index", `${new Date().toISOString().replace(/[:.]/g, "-")}.log`);
89
+ setLogFile(indexLogFile);
90
+ const verbose = isVerbose();
91
+ const spin = !verbose && outputMode.format === "text" ? p.spinner() : null;
92
+ if (spin) {
93
+ spin.start(`Building search index${args.full ? " (full rebuild)" : ""}...`);
94
+ }
95
+ let latestMessage = "";
96
+ try {
97
+ const result = await akmIndex({
98
+ full: args.full,
99
+ clean: args.clean,
100
+ dryRun: args["dry-run"],
101
+ onProgress: ({ phase, message, processed, total }) => {
102
+ latestMessage = message;
103
+ const progressPrefix = processed !== undefined && total !== undefined ? `[${processed}/${total}] ` : "";
104
+ if (verbose) {
105
+ info(`[index:${phase}] ${progressPrefix}${message}`);
106
+ }
107
+ else if (spin) {
108
+ spin.stop(`${progressPrefix}${message}`);
109
+ spin.start(`${progressPrefix}${message}`);
110
+ }
111
+ },
112
+ signal: controller.signal,
113
+ });
114
+ if (spin) {
115
+ spin.stop(`Indexed ${result.totalEntries} assets.`);
116
+ }
117
+ output("index", result);
118
+ }
119
+ catch (error) {
120
+ if (spin) {
121
+ spin.stop(latestMessage ? `Indexing failed after: ${latestMessage}` : "Indexing failed.");
122
+ }
123
+ throw error;
124
+ }
125
+ finally {
126
+ clearLogFile();
127
+ process.off("SIGINT", abort);
128
+ process.off("SIGTERM", abort);
129
+ }
130
+ });
131
+ },
132
+ });
133
+ export const infoCommand = defineJsonCommand({
134
+ meta: { name: "info", description: "Show system capabilities, configuration, and index stats" },
135
+ run() {
136
+ const result = assembleInfo();
137
+ output("info", result);
138
+ },
139
+ });
140
+ // MVP DB administration. Currently only `akm db backups`; restore is manual —
141
+ // stop akm and run `scripts/migrations/restore-data-dir.sh <backup>`.
142
+ // Single source of truth: the routing set is derived from the subCommands keys
143
+ // (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
144
+ const dbSubCommands = {
145
+ backups: defineJsonCommand({
146
+ meta: {
147
+ name: "backups",
148
+ description: "List pre-upgrade snapshots of the data directory (newest first). Backups are created automatically before destructive DB version upgrades unless AKM_DB_BACKUP=0.",
149
+ },
150
+ run() {
151
+ output("db-backups", akmDbBackups());
152
+ },
153
+ }),
154
+ };
155
+ const DB_SUBCOMMAND_SET = new Set(Object.keys(dbSubCommands));
156
+ export const dbCommand = defineJsonCommand({
157
+ meta: {
158
+ name: "db",
159
+ description: "Inspect the AKM SQLite data directory. Currently exposes `backups`; to restore from a snapshot, stop akm and run scripts/migrations/restore-data-dir.sh against the chosen backup.",
160
+ },
161
+ subCommands: dbSubCommands,
162
+ run({ args }) {
163
+ if (hasSubcommand(args, DB_SUBCOMMAND_SET))
164
+ return;
165
+ // Default action: list backups.
166
+ output("db-backups", akmDbBackups());
167
+ },
168
+ });
169
+ export const importKnowledgeCommand = defineJsonCommand({
170
+ meta: {
171
+ name: "import",
172
+ description: "Import a knowledge document or URL into the default stash",
173
+ },
174
+ args: {
175
+ source: {
176
+ type: "positional",
177
+ description: 'Source file path, URL, or "-" to read from stdin',
178
+ required: true,
179
+ },
180
+ name: {
181
+ type: "string",
182
+ description: "Knowledge name (flat, no '/'; defaults to the source filename or content slug). Use --path for a subdirectory.",
183
+ },
184
+ path: {
185
+ type: "string",
186
+ description: "Relative subdirectory under knowledge/ to place the document in (e.g. 'projects/example'). The filename still comes from --name or the source slug.",
187
+ },
188
+ force: {
189
+ type: "boolean",
190
+ description: "Overwrite an existing knowledge document with the same name",
191
+ default: false,
192
+ },
193
+ target: {
194
+ type: "string",
195
+ description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working stash.",
196
+ },
197
+ },
198
+ async run({ args }) {
199
+ // `--name` is a flat name; subdirectory placement is `--path`'s job.
200
+ assertFlatAssetName(args.name);
201
+ const { content, preferredName } = await readKnowledgeInput(args.source);
202
+ const result = await writeMarkdownAsset({
203
+ type: "knowledge",
204
+ content,
205
+ name: args.name ?? (isHttpUrl(args.source) ? preferredName : undefined),
206
+ fallbackPrefix: "knowledge",
207
+ preferredName,
208
+ force: args.force,
209
+ target: args.target,
210
+ path: args.path,
211
+ });
212
+ appendEvent({
213
+ eventType: "import",
214
+ ref: result.ref,
215
+ metadata: { source: args.source, path: result.path, force: args.force === true },
216
+ });
217
+ output("import", { ok: true, source: args.source, ...result });
218
+ },
219
+ });
@@ -3,7 +3,8 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- const SKELETON_DIR = path.join(import.meta.dir, "../assets/stash-skeleton");
6
+ import { getDirname } from "../../runtime.js";
7
+ const SKELETON_DIR = path.join(getDirname(import.meta.url), "../../assets/stash-skeleton");
7
8
  /**
8
9
  * Copy the default stash skeleton into a newly created stash directory.
9
10
  *