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
@@ -14,11 +14,11 @@
14
14
  * filled from the extra positional args in order.
15
15
  */
16
16
  import fs from "node:fs";
17
- import { parseAssetRef } from "../core/asset-ref";
18
- import { NotFoundError, UsageError } from "../core/errors";
19
- import { requireAgentProfile } from "../integrations/agent/config";
20
- import { runAgentSdk } from "../integrations/agent/sdk-runner";
21
- import { runAgent } from "../integrations/agent/spawn";
17
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
18
+ import { NotFoundError, UsageError } from "../../core/errors.js";
19
+ import { requireAgentProfile } from "../../integrations/agent/config.js";
20
+ import { runAgent } from "../../integrations/agent/spawn.js";
21
+ import { runAgentSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
22
22
  /**
23
23
  * Fill `{{0}}`, `{{1}}`, ... placeholders in `template` with the
24
24
  * corresponding entries in `args`. Any placeholder index that exceeds the
@@ -46,7 +46,7 @@ async function resolveAssetBody(ref) {
46
46
  throw new UsageError(`Invalid asset ref "${ref}": ${err instanceof Error ? err.message : String(err)}`, "INVALID_FLAG_VALUE");
47
47
  }
48
48
  // Lazy import to avoid pulling the full indexer at startup.
49
- const { lookup } = await import("../indexer/indexer.js");
49
+ const { lookup } = await import("../../indexer/indexer.js");
50
50
  const entry = await lookup(parsed);
51
51
  if (!entry) {
52
52
  throw new NotFoundError(`Asset "${ref}" not found in the index. Run \`akm index\` to rebuild the index.`);
@@ -8,8 +8,8 @@
8
8
  * `reflect.ts` and `propose.ts`. Any command that shells out to an agent
9
9
  * profile can import from here rather than copy-pasting.
10
10
  */
11
- import { loadConfig } from "../core/config";
12
- import { requireAgentProfile, } from "../integrations/agent";
11
+ import { loadConfig } from "../../core/config/config.js";
12
+ import { requireAgentProfile, } from "../../integrations/agent/index.js";
13
13
  // ── Config helpers ───────────────────────────────────────────────────────────
14
14
  /**
15
15
  * Load the loaded AkmConfig from disk.
@@ -0,0 +1,200 @@
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
+ * Contribution command cluster (`akm agent`, `akm lint`, `akm propose`) —
6
+ * the asset authoring / validation / proposal-creation verbs. Extracted
7
+ * verbatim from src/cli.ts (WS6) so the God Module shrinks; the
8
+ * `main.subCommands.{agent,lint,propose}` keys and every command's args /
9
+ * output shape stay byte-identical.
10
+ *
11
+ * These three handlers each branch on the result and call `process.exit`
12
+ * conditionally (exit 1 on a failed dispatch / proposal, or on
13
+ * `--fail-on-flagged` lint findings), so they keep the inline
14
+ * `runWithJsonErrors` form rather than migrating to `defineJsonCommand`
15
+ * (which is reserved for plain runWithJsonErrors+output handlers).
16
+ *
17
+ * NOTE on `propose` vs `proposal`: the proposal MANAGEMENT family
18
+ * (list/show/accept/reject/…) lives in src/commands/proposal-cli.ts. The
19
+ * `propose` (create) verb here is the asset-authoring entry point and shares
20
+ * no private helper with that module — its path/name helpers come from the
21
+ * shared src/core/asset-create.ts module, imported below.
22
+ */
23
+ import fs from "node:fs";
24
+ import path from "node:path";
25
+ import { defineCommand } from "citty";
26
+ import { getStringArg, parsePositiveIntFlag } from "../../cli/parse-args.js";
27
+ import { EXIT_CODES, output, runWithJsonErrors } from "../../cli/shared.js";
28
+ import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../../core/asset/asset-create.js";
29
+ import { loadConfig } from "../../core/config/config.js";
30
+ import { UsageError } from "../../core/errors.js";
31
+ import { getHyphenatedArg } from "../../output/context.js";
32
+ import { akmLint } from "../lint.js";
33
+ import { akmPropose } from "../proposal/propose.js";
34
+ import { akmAgentDispatch } from "./agent-dispatch.js";
35
+ const EXIT_GENERAL = EXIT_CODES.GENERAL;
36
+ export const agentCommand = defineCommand({
37
+ meta: {
38
+ name: "agent",
39
+ description: "Dispatch an agent CLI (opencode, claude, …) with an optional agent asset that provides the system prompt, model, and tool policy. Use <agent-ref> to embody a stash agent, --model to override the model, and --prompt/--command/--workflow to provide the task.",
40
+ },
41
+ args: {
42
+ profile: {
43
+ type: "positional",
44
+ description: "Agent profile / platform to use (opencode, claude, …)",
45
+ required: false,
46
+ },
47
+ "agent-ref": {
48
+ type: "positional",
49
+ description: "Optional agent asset ref (e.g. agent:code-reviewer). Loads system prompt, model, and tool policy from the stash asset.",
50
+ required: false,
51
+ },
52
+ prompt: { type: "string", description: "Task prompt to pass to the agent" },
53
+ command: { type: "string", description: "Load prompt from a command: asset" },
54
+ workflow: { type: "string", description: "Load prompt from a workflow: asset" },
55
+ model: {
56
+ type: "string",
57
+ description: "Model override — accepts aliases (opus, sonnet, haiku) or exact platform model IDs. Overrides the model specified in the agent asset.",
58
+ },
59
+ "timeout-ms": { type: "string", description: "Override the agent CLI timeout in milliseconds" },
60
+ },
61
+ async run({ args }) {
62
+ await runWithJsonErrors(async () => {
63
+ if (!args.profile) {
64
+ throw new UsageError("Usage: akm agent <profile> [<agent-ref>] [--prompt <text>] [--model <model>]", "MISSING_REQUIRED_ARGUMENT", "Provide the agent profile name. Available profiles are listed in profiles.agent.");
65
+ }
66
+ const timeoutMs = parsePositiveIntFlag(getHyphenatedArg(args, "timeout-ms"), "--timeout-ms");
67
+ const config = loadConfig();
68
+ const { getDefaultLlmConfig } = await import("../../core/config/config.js");
69
+ // After 0.8.0 the agent block IS the loaded AkmConfig.
70
+ const agentConfig = config;
71
+ // Resolve agent asset ref → extract system prompt, model, and tool policy.
72
+ const agentRef = getStringArg(args, "agent-ref");
73
+ let systemPrompt;
74
+ let assetModel;
75
+ let assetTools;
76
+ if (agentRef) {
77
+ const { akmShowUnified } = await import("../read/show.js");
78
+ const asset = await akmShowUnified({ ref: agentRef, detail: "full" });
79
+ systemPrompt = typeof asset.content === "string" ? asset.content : undefined;
80
+ assetModel = typeof asset.modelHint === "string" ? asset.modelHint : undefined;
81
+ assetTools = asset.toolPolicy;
82
+ }
83
+ // --model flag wins over the asset's modelHint.
84
+ const model = getStringArg(args, "model") ?? assetModel;
85
+ const promptText = getStringArg(args, "prompt");
86
+ const commandRef = getStringArg(args, "command");
87
+ const workflowRef = getStringArg(args, "workflow");
88
+ // Only build a dispatch request when there is something to dispatch — a
89
+ // prompt, an agent asset, or a model override. When none of these are
90
+ // present the agent is launched interactively (no injected prompt, no
91
+ // platform-specific flags beyond the profile's base args).
92
+ const hasDispatchContent = !!(promptText ?? commandRef ?? workflowRef ?? systemPrompt ?? model ?? assetTools);
93
+ const result = await akmAgentDispatch({
94
+ profileName: String(args.profile),
95
+ prompt: promptText,
96
+ commandRef,
97
+ workflowRef,
98
+ agentConfig,
99
+ llmConfig: getDefaultLlmConfig(config),
100
+ ...(hasDispatchContent
101
+ ? {
102
+ dispatch: {
103
+ prompt: promptText ?? "",
104
+ systemPrompt,
105
+ model,
106
+ tools: assetTools,
107
+ },
108
+ }
109
+ : {}),
110
+ ...(timeoutMs !== undefined && Number.isFinite(timeoutMs) ? { timeoutMs } : {}),
111
+ });
112
+ output("agent-result", result);
113
+ if (!result.ok) {
114
+ process.exit(EXIT_GENERAL);
115
+ }
116
+ });
117
+ },
118
+ });
119
+ export const lintCommand = defineCommand({
120
+ meta: {
121
+ name: "lint",
122
+ description: "Scan stash .md files for structural issues (unquoted colons, missing updated field, orphaned stubs, placeholder stubs, missing name/type, stale paths). Use --fix to auto-fix Tier 1 issues. Exits 0 on success regardless of findings; use --fail-on-flagged for CI fail-on-finding behavior.",
123
+ },
124
+ args: {
125
+ fix: { type: "boolean", description: "Apply auto-fixes in place", default: false },
126
+ dir: { type: "string", description: "Override stash root directory (default: from config)" },
127
+ "fail-on-flagged": {
128
+ type: "boolean",
129
+ description: "Exit non-zero when summary.flagged > 0 (CI-friendly). Default: exit 0 regardless of findings.",
130
+ default: false,
131
+ },
132
+ },
133
+ async run({ args }) {
134
+ await runWithJsonErrors(async () => {
135
+ const result = akmLint({
136
+ fix: args.fix ?? false,
137
+ dir: getStringArg(args, "dir"),
138
+ });
139
+ output("lint", result);
140
+ if (args["fail-on-flagged"] && result.summary.flagged > 0)
141
+ process.exit(EXIT_GENERAL);
142
+ });
143
+ },
144
+ });
145
+ export const proposeCommand = defineCommand({
146
+ meta: {
147
+ name: "propose",
148
+ description: "Ask the configured agent CLI to author a brand-new asset and queue it as a proposal",
149
+ },
150
+ args: {
151
+ // Optional in citty so run() is invoked when omitted; we re-validate
152
+ // below to surface a structured UsageError (exit 2) instead of citty's
153
+ // default help-banner exit-0.
154
+ type: { type: "positional", description: "Asset type (skill, command, knowledge, lesson, ...)", required: false },
155
+ name: {
156
+ type: "positional",
157
+ description: "Asset name (flat, no '/'; use --path for a subdirectory)",
158
+ required: false,
159
+ },
160
+ path: {
161
+ type: "string",
162
+ description: "Relative subdirectory under the type dir to place the proposed asset in (e.g. 'release'). The filename comes from the name.",
163
+ },
164
+ task: { type: "string", description: "Task description for the agent (what should the asset do?)" },
165
+ file: { type: "string", description: "Read the task or prompt text from a UTF-8 file" },
166
+ profile: { type: "string", description: "Override the agent profile (defaults to agent.default)" },
167
+ "timeout-ms": { type: "string", description: "Override the agent CLI timeout in milliseconds" },
168
+ },
169
+ async run({ args }) {
170
+ await runWithJsonErrors(async () => {
171
+ // citty silently shows help and exits 0 when required positionals are
172
+ // omitted. Re-validate explicitly so the exit code is 2 (USAGE) and a
173
+ // structured JSON error reaches scripted callers.
174
+ const taskFromFlag = typeof args.task === "string" ? args.task : undefined;
175
+ const fileFromFlag = typeof args.file === "string" ? args.file : undefined;
176
+ if (!args.type || !args.name || (!taskFromFlag && !fileFromFlag)) {
177
+ throw new UsageError("Usage: akm propose <type> <name> (--task '<task>' | --file <path>).", "MISSING_REQUIRED_ARGUMENT", "Provide the asset type, name, and exactly one of --task or --file.");
178
+ }
179
+ if (taskFromFlag && fileFromFlag) {
180
+ throw new UsageError("Pass exactly one of --task or --file.", "INVALID_FLAG_VALUE");
181
+ }
182
+ // `name` is flat; subdirectory placement is `--path`'s job.
183
+ assertFlatAssetName(String(args.name));
184
+ const proposedName = combineCreatePath(normalizeCreateSubPath(getStringArg(args, "path")), String(args.name));
185
+ const taskText = fileFromFlag ? fs.readFileSync(path.resolve(fileFromFlag), "utf8") : (taskFromFlag ?? "");
186
+ const timeoutMs = parsePositiveIntFlag(getHyphenatedArg(args, "timeout-ms"), "--timeout-ms");
187
+ const result = await akmPropose({
188
+ type: String(args.type),
189
+ name: proposedName,
190
+ task: taskText,
191
+ profile: getStringArg(args, "profile"),
192
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
193
+ });
194
+ output("propose", result);
195
+ if (result.ok === false) {
196
+ process.exit(EXIT_GENERAL);
197
+ }
198
+ });
199
+ },
200
+ });
@@ -4,7 +4,7 @@
4
4
  import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
- import { getAssetTypes } from "../core/asset-spec";
7
+ import { getAssetTypes } from "../core/asset/asset-spec.js";
8
8
  // ── Known flag values ────────────────────────────────────────────────────────
9
9
  const FLAG_VALUES = {
10
10
  "--format": ["json", "text", "yaml", "jsonl"],
@@ -16,9 +16,13 @@
16
16
  * - `parseConfigValue` returns a Partial<AkmConfig> so it can be merged with
17
17
  * the runtime config object via `mergeConfigValue`.
18
18
  */
19
- import { DEFAULT_CONFIG, getSources } from "../core/config";
20
- import { configGet, configSet, configUnset, unknownKeyHint } from "../core/config-walker";
21
- import { UsageError } from "../core/errors";
19
+ import { hasSubcommand } from "../cli/parse-args.js";
20
+ import { defineJsonCommand, output } from "../cli/shared.js";
21
+ import { resolveStashDir } from "../core/common.js";
22
+ import { DEFAULT_CONFIG, getSources, loadConfig, loadUserConfig, saveConfig, } from "../core/config/config.js";
23
+ import { configGet, configSet, configUnset, unknownKeyHint } from "../core/config/config-walker.js";
24
+ import { UsageError } from "../core/errors.js";
25
+ import { getCacheDir, getConfigPath, getDbPath, getDefaultStashDir } from "../core/paths.js";
22
26
  // ── Legacy `llm.*` → `profiles.llm.<default>.*` aliasing ────────────────────
23
27
  /**
24
28
  * Map a legacy top-level `llm.<sub>` path onto the actual schema path. The
@@ -153,3 +157,226 @@ export function listConfig(config) {
153
157
  return result;
154
158
  }
155
159
  export { unknownKeyHint };
160
+ // ── `akm config` command surface ────────────────────────────────────────────
161
+ // Extracted verbatim from src/cli.ts (WS6). The `main.subCommands.config` key
162
+ // and every config subcommand's args/output shape are byte-identical. The
163
+ // `skills.sh` toggle helpers and the `CONFIG_SUBCOMMAND_SET` routing constant
164
+ // are used ONLY by this command, so they move with the cluster. Leaf handlers
165
+ // whose body is a plain `runWithJsonErrors(() => { … })` are migrated to
166
+ // `defineJsonCommand`, which emits the same JSON envelope (stdout/stderr/
167
+ // exit-code) as the inline form.
168
+ const SKILLS_SH_NAME = "skills.sh";
169
+ const SKILLS_SH_URL = "https://skills.sh";
170
+ const SKILLS_SH_PROVIDER = "skills-sh";
171
+ function normalizeToggleTarget(target) {
172
+ const normalized = target.trim().toLowerCase();
173
+ if (normalized === "skills.sh" || normalized === "skills-sh")
174
+ return "skills.sh";
175
+ throw new UsageError(`Unsupported target "${target}". Supported targets: skills.sh`);
176
+ }
177
+ function toggleSkillsShRegistry(enabled) {
178
+ const config = loadUserConfig();
179
+ const registries = (config.registries ?? DEFAULT_CONFIG.registries ?? []).map((registry) => ({ ...registry }));
180
+ const idx = registries.findIndex((registry) => registry.provider === SKILLS_SH_PROVIDER || registry.name === SKILLS_SH_NAME || registry.url === SKILLS_SH_URL);
181
+ if (idx >= 0) {
182
+ const existing = registries[idx];
183
+ const wasEnabled = existing.enabled !== false;
184
+ existing.enabled = enabled;
185
+ saveConfig({ ...config, registries });
186
+ return { changed: wasEnabled !== enabled, component: SKILLS_SH_NAME, enabled };
187
+ }
188
+ if (!enabled) {
189
+ // Materialize the skills.sh registry explicitly if absent.
190
+ registries.push({ url: SKILLS_SH_URL, name: SKILLS_SH_NAME, provider: SKILLS_SH_PROVIDER, enabled: false });
191
+ saveConfig({ ...config, registries });
192
+ return { changed: true, component: SKILLS_SH_NAME, enabled: false };
193
+ }
194
+ registries.push({ url: SKILLS_SH_URL, name: SKILLS_SH_NAME, provider: SKILLS_SH_PROVIDER, enabled: true });
195
+ saveConfig({ ...config, registries });
196
+ return { changed: true, component: SKILLS_SH_NAME, enabled: true };
197
+ }
198
+ function toggleComponent(targetRaw, enabled) {
199
+ const target = normalizeToggleTarget(targetRaw);
200
+ if (target === "skills.sh")
201
+ return toggleSkillsShRegistry(enabled);
202
+ // normalizeToggleTarget throws for any unsupported target; this is unreachable.
203
+ throw new UsageError(`Unsupported target "${targetRaw}". Supported targets: skills.sh`);
204
+ }
205
+ export const configCommand = defineJsonCommand({
206
+ meta: { name: "config", description: "Show and manage configuration" },
207
+ args: {
208
+ list: { type: "boolean", description: "List current configuration", default: false },
209
+ },
210
+ subCommands: {
211
+ path: defineJsonCommand({
212
+ meta: { name: "path", description: "Show paths to config, stash, cache, and index" },
213
+ args: {
214
+ all: { type: "boolean", description: "Show all paths (config, stash, cache, index)", default: false },
215
+ },
216
+ run({ args }) {
217
+ const configPath = getConfigPath();
218
+ if (args.all) {
219
+ let stashDir;
220
+ try {
221
+ stashDir = resolveStashDir({ readOnly: true });
222
+ }
223
+ catch {
224
+ stashDir = `${getDefaultStashDir()} (not initialized)`;
225
+ }
226
+ const cacheDir = getCacheDir();
227
+ const result = {
228
+ config: configPath,
229
+ stash: stashDir,
230
+ cache: cacheDir,
231
+ index: getDbPath(),
232
+ };
233
+ output("config", result);
234
+ }
235
+ else {
236
+ console.log(configPath);
237
+ }
238
+ },
239
+ }),
240
+ list: defineJsonCommand({
241
+ meta: { name: "list", description: "List current configuration" },
242
+ run() {
243
+ output("config", listConfig(loadConfig()));
244
+ },
245
+ }),
246
+ show: defineJsonCommand({
247
+ meta: { name: "show", description: "Alias for `akm config list` — list current configuration" },
248
+ run() {
249
+ output("config", listConfig(loadConfig()));
250
+ },
251
+ }),
252
+ get: defineJsonCommand({
253
+ meta: { name: "get", description: "Get a configuration value by key" },
254
+ args: {
255
+ key: { type: "positional", required: true, description: "Config key (for example: embedding, stashDir)" },
256
+ },
257
+ run({ args }) {
258
+ output("config", getConfigValue(loadConfig(), args.key));
259
+ },
260
+ }),
261
+ set: defineJsonCommand({
262
+ meta: { name: "set", description: "Set a configuration value by key" },
263
+ args: {
264
+ key: { type: "positional", required: true, description: "Config key (for example: embedding, llm)" },
265
+ value: { type: "positional", required: true, description: "Config value" },
266
+ // #463: stable machine-friendly entry point for plugins / hooks.
267
+ // `--silent` suppresses the config dump on stdout so hook-driven
268
+ // writes don't pollute their host's output stream.
269
+ silent: {
270
+ type: "boolean",
271
+ description: "Suppress the post-write config dump on stdout. Use from hooks and CI scripts; the write still happens and errors still print.",
272
+ default: false,
273
+ },
274
+ // #463: explicit layer flag for forward-compat. User layer is the only
275
+ // settable layer today; the flag exists so plugin authors can encode
276
+ // intent and the surface stays stable if project-layer writes return.
277
+ layer: {
278
+ type: "string",
279
+ description: "Config layer to write to. Currently only `user` is supported.",
280
+ default: "user",
281
+ },
282
+ },
283
+ run({ args }) {
284
+ if (args.layer && args.layer !== "user") {
285
+ throw new UsageError(`Unsupported --layer "${args.layer}". Only "user" is settable in 0.8.0.`, "INVALID_FLAG_VALUE");
286
+ }
287
+ // Use loadConfig (not loadUserConfig) so the project-config
288
+ // deprecation warning fires consistently with `akm config get`
289
+ // (#457). Effective merged shape is identical post-0.8.0.
290
+ const updated = setConfigValue(loadConfig(), args.key, args.value);
291
+ saveConfig(updated);
292
+ if (!args.silent) {
293
+ output("config", listConfig(updated));
294
+ }
295
+ },
296
+ }),
297
+ unset: defineJsonCommand({
298
+ meta: { name: "unset", description: "Unset an optional configuration key or whole embedding/llm section" },
299
+ args: {
300
+ key: { type: "positional", required: true, description: "Config key to unset" },
301
+ silent: {
302
+ type: "boolean",
303
+ description: "Suppress the post-write config dump on stdout.",
304
+ default: false,
305
+ },
306
+ layer: {
307
+ type: "string",
308
+ description: "Config layer to write to. Currently only `user` is supported.",
309
+ default: "user",
310
+ },
311
+ },
312
+ run({ args }) {
313
+ if (args.layer && args.layer !== "user") {
314
+ throw new UsageError(`Unsupported --layer "${args.layer}". Only "user" is settable in 0.8.0.`, "INVALID_FLAG_VALUE");
315
+ }
316
+ const updated = unsetConfigValue(loadConfig(), args.key);
317
+ saveConfig(updated);
318
+ if (!args.silent) {
319
+ output("config", listConfig(updated));
320
+ }
321
+ },
322
+ }),
323
+ validate: defineJsonCommand({
324
+ meta: {
325
+ name: "validate",
326
+ description: "Validate the on-disk config file against the schema. Exits non-zero on errors.",
327
+ },
328
+ async run() {
329
+ const { runConfigValidate } = await import("../cli/config-validate.js");
330
+ await runConfigValidate();
331
+ },
332
+ }),
333
+ migrate: defineJsonCommand({
334
+ meta: {
335
+ name: "migrate",
336
+ description: "Migrate the config file to the current schema version. Use --dry-run to preview without writing.",
337
+ },
338
+ args: {
339
+ "dry-run": { type: "boolean", description: "Preview the migration result without writing.", default: false },
340
+ "print-diff": {
341
+ type: "boolean",
342
+ description: "Print a unified diff of old vs new config alongside the migration output.",
343
+ default: false,
344
+ },
345
+ },
346
+ async run({ args }) {
347
+ const { runConfigMigrate } = await import("../cli/config-migrate.js");
348
+ await runConfigMigrate({ dryRun: Boolean(args["dry-run"]), printDiff: Boolean(args["print-diff"]) });
349
+ },
350
+ }),
351
+ enable: defineJsonCommand({
352
+ meta: { name: "enable", description: "Enable an optional component (skills.sh)" },
353
+ args: {
354
+ target: { type: "positional", description: "Component to enable (skills.sh)", required: true },
355
+ },
356
+ run({ args }) {
357
+ const result = toggleComponent(args.target, true);
358
+ output("enable", result);
359
+ },
360
+ }),
361
+ disable: defineJsonCommand({
362
+ meta: { name: "disable", description: "Disable an optional component (skills.sh)" },
363
+ args: {
364
+ target: { type: "positional", description: "Component to disable (skills.sh)", required: true },
365
+ },
366
+ run({ args }) {
367
+ const result = toggleComponent(args.target, false);
368
+ output("disable", result);
369
+ },
370
+ }),
371
+ },
372
+ run({ args }) {
373
+ if (hasSubcommand(args, CONFIG_SUBCOMMAND_SET))
374
+ return;
375
+ if (args.list) {
376
+ output("config", listConfig(loadConfig()));
377
+ return;
378
+ }
379
+ output("config", listConfig(loadConfig()));
380
+ },
381
+ });
382
+ const CONFIG_SUBCOMMAND_SET = new Set(["path", "list", "show", "get", "set", "unset", "enable", "disable"]);
@@ -12,8 +12,8 @@
12
12
  * plain `mv`/`cp`) to recover. Keeping the surface narrow lets us evolve the
13
13
  * backup format under the hood without locking in an API.
14
14
  */
15
- import { getDataDir } from "../core/paths";
16
- import { listBackups } from "../indexer/db-backup";
15
+ import { getDataDir } from "../core/paths.js";
16
+ import { listBackups } from "../indexer/db/db-backup.js";
17
17
  export function akmDbBackups() {
18
18
  const dataDir = getDataDir();
19
19
  return {