akm-cli 0.9.0-beta.9 → 0.9.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/CHANGELOG.md +592 -0
  2. package/README.md +12 -4
  3. package/dist/akm +38 -0
  4. package/dist/akm-migrate-storage +38 -0
  5. package/dist/assets/help/help-improve.md +9 -6
  6. package/dist/assets/hints/cli-hints-full.md +6 -5
  7. package/dist/assets/profiles/default.json +9 -4
  8. package/dist/assets/profiles/frequent.json +1 -1
  9. package/dist/assets/profiles/memory-focus.json +1 -1
  10. package/dist/assets/profiles/proactive-maintenance.json +25 -0
  11. package/dist/assets/profiles/quick.json +1 -1
  12. package/dist/assets/profiles/recombine-only.json +21 -0
  13. package/dist/assets/profiles/reflect-distill.json +30 -0
  14. package/dist/assets/profiles/synthesize.json +15 -0
  15. package/dist/assets/profiles/thorough.json +1 -1
  16. package/dist/assets/prompts/consolidate-system.md +23 -0
  17. package/dist/assets/prompts/contradiction-judge.md +33 -0
  18. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  19. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  20. package/dist/assets/prompts/extract-session.md +11 -3
  21. package/dist/assets/prompts/graph-extract-system.md +1 -0
  22. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  23. package/dist/assets/prompts/memory-infer-system.md +1 -0
  24. package/dist/assets/prompts/memory-infer-user.md +5 -0
  25. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  26. package/dist/assets/prompts/procedural-system.md +44 -0
  27. package/dist/assets/prompts/recombine-system.md +40 -0
  28. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  29. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  39. package/dist/assets/templates/html/health.html +281 -111
  40. package/dist/assets/wiki/ingest-workflow-template.md +45 -16
  41. package/dist/assets/wiki/schema-template.md +4 -4
  42. package/dist/cli/clack.js +56 -0
  43. package/dist/cli/config-migrate.js +7 -1
  44. package/dist/cli/confirm.js +1 -1
  45. package/dist/cli/parse-args.js +46 -1
  46. package/dist/cli/shared.js +28 -0
  47. package/dist/cli.js +25 -21
  48. package/dist/commands/agent/agent-dispatch.js +3 -2
  49. package/dist/commands/agent/agent-support.js +0 -7
  50. package/dist/commands/agent/contribute-cli.js +26 -7
  51. package/dist/commands/config-cli.js +26 -13
  52. package/dist/commands/env/child-env.js +47 -0
  53. package/dist/commands/env/env-cli.js +220 -227
  54. package/dist/commands/env/env.js +14 -67
  55. package/dist/commands/env/secret-cli.js +140 -138
  56. package/dist/commands/feedback-cli.js +156 -155
  57. package/dist/commands/graph/graph-cli.js +5 -13
  58. package/dist/commands/graph/graph.js +3 -3
  59. package/dist/commands/health/advisories.js +151 -0
  60. package/dist/commands/health/checks.js +103 -16
  61. package/dist/commands/health/html-report.js +447 -81
  62. package/dist/commands/health/improve-metrics.js +771 -0
  63. package/dist/commands/health/llm-usage.js +65 -0
  64. package/dist/commands/health/md-report.js +103 -0
  65. package/dist/commands/health/metrics.js +278 -0
  66. package/dist/commands/health/stash-exposure.js +46 -0
  67. package/dist/commands/health/surfaces.js +216 -0
  68. package/dist/commands/health/task-runs.js +135 -0
  69. package/dist/commands/health/types.js +26 -0
  70. package/dist/commands/health/windows.js +195 -0
  71. package/dist/commands/health.js +91 -1091
  72. package/dist/commands/improve/anti-collapse.js +170 -0
  73. package/dist/commands/improve/calibration.js +161 -0
  74. package/dist/commands/improve/collapse-detector.js +421 -0
  75. package/dist/commands/improve/consolidate/chunking.js +141 -0
  76. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  77. package/dist/commands/improve/consolidate/merge.js +145 -0
  78. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  79. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  80. package/dist/commands/improve/consolidate.js +1295 -1277
  81. package/dist/commands/improve/dedup.js +482 -0
  82. package/dist/commands/improve/distill/content-repair.js +202 -0
  83. package/dist/commands/improve/distill/promote-memory.js +229 -0
  84. package/dist/commands/improve/distill/quality-gate.js +236 -0
  85. package/dist/commands/improve/distill-guards.js +127 -0
  86. package/dist/commands/improve/distill-promotion-policy.js +826 -167
  87. package/dist/commands/improve/distill.js +228 -605
  88. package/dist/commands/improve/eligibility.js +434 -0
  89. package/dist/commands/improve/encoding-salience.js +205 -0
  90. package/dist/commands/improve/extract-cli.js +179 -59
  91. package/dist/commands/improve/extract-prompt.js +54 -3
  92. package/dist/commands/improve/extract-watch.js +140 -0
  93. package/dist/commands/improve/extract.js +409 -43
  94. package/dist/commands/improve/feedback-valence.js +54 -0
  95. package/dist/commands/improve/hot-probation.js +45 -0
  96. package/dist/commands/improve/improve-auto-accept.js +157 -10
  97. package/dist/commands/improve/improve-cli.js +115 -73
  98. package/dist/commands/improve/improve-profiles.js +28 -8
  99. package/dist/commands/improve/improve-result-file.js +15 -25
  100. package/dist/commands/improve/improve-session.js +58 -0
  101. package/dist/commands/improve/improve.js +485 -2764
  102. package/dist/commands/improve/locks.js +154 -0
  103. package/dist/commands/improve/loop-stages.js +1100 -0
  104. package/dist/commands/improve/memory/memory-belief.js +14 -15
  105. package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
  106. package/dist/commands/improve/memory/memory-improve.js +27 -27
  107. package/dist/commands/improve/outcome-loop.js +270 -0
  108. package/dist/commands/improve/preparation.js +2002 -0
  109. package/dist/commands/improve/proactive-maintenance.js +37 -35
  110. package/dist/commands/improve/procedural.js +398 -0
  111. package/dist/commands/improve/recombine.js +818 -0
  112. package/dist/commands/improve/reflect-noise.js +0 -0
  113. package/dist/commands/improve/reflect.js +206 -45
  114. package/dist/commands/improve/salience.js +455 -0
  115. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  116. package/dist/commands/improve/shared.js +51 -0
  117. package/dist/commands/improve/triage.js +93 -0
  118. package/dist/commands/lint/agent-linter.js +19 -24
  119. package/dist/commands/lint/base-linter.js +173 -60
  120. package/dist/commands/lint/command-linter.js +19 -24
  121. package/dist/commands/lint/env-key-rules.js +38 -1
  122. package/dist/commands/lint/fact-linter.js +39 -0
  123. package/dist/commands/lint/index.js +31 -13
  124. package/dist/commands/lint/memory-linter.js +1 -1
  125. package/dist/commands/lint/registry.js +7 -2
  126. package/dist/commands/lint/task-linter.js +3 -3
  127. package/dist/commands/lint/workflow-linter.js +26 -1
  128. package/dist/commands/observability-cli.js +4 -4
  129. package/dist/commands/proposal/drain-policies.js +13 -4
  130. package/dist/commands/proposal/drain.js +45 -51
  131. package/dist/commands/proposal/legacy-import.js +115 -0
  132. package/dist/commands/proposal/proposal-cli.js +24 -34
  133. package/dist/commands/proposal/proposal.js +2 -1
  134. package/dist/commands/proposal/propose.js +8 -3
  135. package/dist/commands/proposal/repository.js +829 -0
  136. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  137. package/dist/commands/proposal/validators/proposals.js +93 -895
  138. package/dist/commands/read/curate.js +410 -111
  139. package/dist/commands/read/knowledge.js +10 -3
  140. package/dist/commands/read/remember-cli.js +133 -138
  141. package/dist/commands/read/search-cli.js +15 -8
  142. package/dist/commands/read/search.js +22 -11
  143. package/dist/commands/read/show.js +106 -14
  144. package/dist/commands/registry-cli.js +76 -87
  145. package/dist/commands/remember.js +11 -12
  146. package/dist/commands/sources/add-cli.js +91 -95
  147. package/dist/commands/sources/history.js +1 -1
  148. package/dist/commands/sources/init.js +66 -18
  149. package/dist/commands/sources/installed-stashes.js +11 -3
  150. package/dist/commands/sources/schema-repair.js +44 -46
  151. package/dist/commands/sources/self-update.js +2 -2
  152. package/dist/commands/sources/source-add.js +7 -3
  153. package/dist/commands/sources/sources-cli.js +3 -3
  154. package/dist/commands/sources/stash-cli.js +19 -39
  155. package/dist/commands/sources/stash-skeleton.js +57 -8
  156. package/dist/commands/tasks/default-tasks.js +15 -2
  157. package/dist/commands/tasks/tasks-cli.js +20 -29
  158. package/dist/commands/tasks/tasks.js +39 -11
  159. package/dist/commands/wiki-cli.js +23 -38
  160. package/dist/commands/workflow-cli.js +15 -1
  161. package/dist/core/asset/asset-registry.js +3 -1
  162. package/dist/core/asset/asset-spec.js +21 -4
  163. package/dist/core/asset/frontmatter.js +188 -167
  164. package/dist/core/asset/markdown.js +8 -0
  165. package/dist/core/authoring-rules.js +92 -0
  166. package/dist/core/common.js +4 -23
  167. package/dist/core/concurrent.js +10 -1
  168. package/dist/core/config/config-io.js +10 -1
  169. package/dist/core/config/config-migration.js +18 -40
  170. package/dist/core/config/config-schema.js +382 -62
  171. package/dist/core/config/config-types.js +3 -3
  172. package/dist/core/config/config.js +67 -22
  173. package/dist/core/deep-merge.js +38 -0
  174. package/dist/core/errors.js +1 -0
  175. package/dist/core/eval/rank-metrics.js +113 -0
  176. package/dist/core/events.js +4 -7
  177. package/dist/core/improve-types.js +47 -8
  178. package/dist/core/logs-db.js +14 -75
  179. package/dist/core/parse.js +36 -16
  180. package/dist/core/paths.js +18 -18
  181. package/dist/core/standards/resolve-standards-context.js +87 -0
  182. package/dist/core/standards/resolve-stash-standards.js +99 -0
  183. package/dist/core/standards/resolve-type-conventions.js +66 -0
  184. package/dist/core/state/migrations.js +770 -0
  185. package/dist/core/state-db.js +132 -1126
  186. package/dist/core/structured.js +69 -0
  187. package/dist/core/time.js +53 -0
  188. package/dist/core/warn.js +21 -0
  189. package/dist/core/write-source.js +37 -0
  190. package/dist/indexer/db/db.js +259 -769
  191. package/dist/indexer/db/entry-mapper.js +41 -0
  192. package/dist/indexer/db/graph-db.js +129 -86
  193. package/dist/indexer/db/llm-cache.js +2 -2
  194. package/dist/indexer/db/schema.js +516 -0
  195. package/dist/indexer/ensure-index.js +36 -92
  196. package/dist/indexer/feedback/utility-policy.js +75 -0
  197. package/dist/indexer/graph/graph-boost.js +51 -41
  198. package/dist/indexer/graph/graph-extraction.js +207 -4
  199. package/dist/indexer/index-writer-lock.js +18 -11
  200. package/dist/indexer/index-written-assets.js +105 -0
  201. package/dist/indexer/indexer.js +182 -204
  202. package/dist/indexer/passes/dir-staleness.js +114 -0
  203. package/dist/indexer/passes/memory-inference.js +13 -5
  204. package/dist/indexer/passes/metadata.js +20 -0
  205. package/dist/indexer/read-preflight.js +23 -0
  206. package/dist/indexer/search/db-search.js +89 -13
  207. package/dist/indexer/search/fts-query.js +51 -0
  208. package/dist/indexer/search/ranking-contributors.js +95 -9
  209. package/dist/indexer/search/ranking.js +79 -3
  210. package/dist/indexer/search/search-fields.js +6 -0
  211. package/dist/indexer/search/search-source.js +32 -21
  212. package/dist/indexer/search/semantic-status.js +4 -0
  213. package/dist/indexer/walk/matchers.js +9 -0
  214. package/dist/indexer/walk/walker.js +21 -13
  215. package/dist/integrations/agent/builders.js +39 -13
  216. package/dist/integrations/agent/config.js +20 -59
  217. package/dist/integrations/agent/detect.js +9 -0
  218. package/dist/integrations/agent/index.js +3 -19
  219. package/dist/integrations/agent/model-aliases.js +7 -2
  220. package/dist/integrations/agent/profiles.js +7 -1
  221. package/dist/integrations/agent/prompts.js +75 -9
  222. package/dist/integrations/agent/runner-dispatch.js +59 -0
  223. package/dist/integrations/agent/runner.js +13 -9
  224. package/dist/integrations/agent/spawn.js +69 -67
  225. package/dist/integrations/harnesses/claude/agent-builder.js +1 -1
  226. package/dist/integrations/harnesses/claude/index.js +2 -0
  227. package/dist/integrations/harnesses/claude/session-log.js +10 -0
  228. package/dist/integrations/harnesses/index.js +2 -3
  229. package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
  230. package/dist/integrations/harnesses/opencode/index.js +2 -0
  231. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  232. package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
  233. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +98 -17
  234. package/dist/integrations/harnesses/types.js +1 -0
  235. package/dist/integrations/session-logs/index.js +16 -0
  236. package/dist/llm/call-ai.js +2 -2
  237. package/dist/llm/client.js +34 -11
  238. package/dist/llm/embedder.js +67 -4
  239. package/dist/llm/embedders/cache.js +3 -1
  240. package/dist/llm/embedders/deterministic.js +66 -0
  241. package/dist/llm/embedders/local.js +73 -3
  242. package/dist/llm/feature-gate.js +16 -15
  243. package/dist/llm/graph-extract.js +67 -44
  244. package/dist/llm/memory-infer-impl.js +138 -0
  245. package/dist/llm/memory-infer.js +1 -127
  246. package/dist/llm/metadata-enhance.js +44 -31
  247. package/dist/llm/structured-call.js +49 -0
  248. package/dist/migrate-storage-node.mjs +8 -0
  249. package/dist/output/context.js +5 -5
  250. package/dist/output/renderers.js +85 -14
  251. package/dist/output/shapes/curate.js +14 -2
  252. package/dist/output/shapes/helpers.js +0 -3
  253. package/dist/output/shapes/passthrough.js +2 -1
  254. package/dist/output/text/helpers.js +29 -1
  255. package/dist/output/text/workflow.js +1 -0
  256. package/dist/registry/providers/skills-sh.js +21 -147
  257. package/dist/registry/providers/static-index.js +15 -157
  258. package/dist/registry/resolve.js +27 -9
  259. package/dist/runtime.js +25 -1
  260. package/dist/scripts/migrate-storage.js +2661 -2369
  261. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +883 -596
  262. package/dist/setup/detect.js +9 -0
  263. package/dist/setup/legacy-config.js +106 -0
  264. package/dist/setup/prompt.js +57 -0
  265. package/dist/setup/providers.js +14 -0
  266. package/dist/setup/registry-stash-loader.js +12 -0
  267. package/dist/setup/semantic-assets.js +124 -0
  268. package/dist/setup/setup.js +52 -1614
  269. package/dist/setup/steps/connection.js +734 -0
  270. package/dist/setup/steps/output.js +31 -0
  271. package/dist/setup/steps/platforms.js +124 -0
  272. package/dist/setup/steps/semantic.js +27 -0
  273. package/dist/setup/steps/sources.js +222 -0
  274. package/dist/setup/steps/stashdir.js +42 -0
  275. package/dist/setup/steps/tasks.js +152 -0
  276. package/dist/sources/include.js +6 -2
  277. package/dist/sources/providers/filesystem.js +0 -1
  278. package/dist/sources/providers/git-install.js +210 -0
  279. package/dist/sources/providers/git-provider.js +234 -0
  280. package/dist/sources/providers/git-stash.js +248 -0
  281. package/dist/sources/providers/git.js +10 -661
  282. package/dist/sources/providers/npm.js +2 -6
  283. package/dist/sources/providers/provider-utils.js +13 -7
  284. package/dist/sources/providers/sync-from-ref.js +9 -1
  285. package/dist/sources/providers/website.js +9 -5
  286. package/dist/sources/website-ingest.js +187 -29
  287. package/dist/sources/wiki-fetchers/registry.js +53 -0
  288. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  289. package/dist/storage/database.js +45 -10
  290. package/dist/storage/managed-db.js +82 -0
  291. package/dist/storage/repositories/canaries-repository.js +107 -0
  292. package/dist/storage/repositories/consolidation-repository.js +38 -0
  293. package/dist/storage/repositories/embeddings-repository.js +72 -0
  294. package/dist/storage/repositories/events-repository.js +187 -0
  295. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  296. package/dist/storage/repositories/improve-runs-repository.js +146 -0
  297. package/dist/storage/repositories/index-db.js +14 -8
  298. package/dist/storage/repositories/proposals-repository.js +220 -0
  299. package/dist/storage/repositories/recombine-repository.js +213 -0
  300. package/dist/storage/repositories/registry-cache.js +93 -0
  301. package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
  302. package/dist/storage/repositories/task-history-repository.js +93 -0
  303. package/dist/storage/sqlite-pragmas.js +146 -0
  304. package/dist/tasks/backends/cron.js +1 -1
  305. package/dist/tasks/backends/index.js +9 -0
  306. package/dist/tasks/backends/launchd.js +1 -1
  307. package/dist/tasks/backends/schtasks.js +1 -1
  308. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  309. package/dist/tasks/runner.js +15 -13
  310. package/dist/text-import-hook.mjs +0 -0
  311. package/dist/wiki/wiki.js +52 -11
  312. package/dist/workflows/cli.js +1 -0
  313. package/dist/workflows/db.js +3 -4
  314. package/dist/workflows/runtime/runs.js +43 -118
  315. package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
  316. package/dist/workflows/validate-summary.js +2 -7
  317. package/docs/README.md +69 -18
  318. package/docs/data-and-telemetry.md +5 -4
  319. package/docs/migration/release-notes/0.7.0.md +1 -1
  320. package/docs/migration/release-notes/0.9.0.md +39 -0
  321. package/package.json +10 -10
  322. package/dist/assets/tasks/core/update-stashes.yml +0 -4
  323. package/dist/commands/db-cli.js +0 -23
  324. package/dist/indexer/db/db-backup.js +0 -376
  325. package/dist/indexer/passes/staleness-detect.js +0 -488
@@ -5,39 +5,39 @@
5
5
  * Stash-lifecycle command cluster — the create/index/ingest/inspect verbs for
6
6
  * the working stash and its index database: `akm init` (create the stash +
7
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).
8
+ * (ingest a knowledge doc/URL), and `akm info` (system capabilities + index
9
+ * stats).
10
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
11
+ * `main.subCommands.{init,index,import,info}` keys and every subcommand's
12
12
  * args/output shape stay byte-identical.
13
13
  *
14
14
  * These share no private helper with any command still inline in cli.ts — every
15
15
  * dependency is already exported from a shared module (core/paths, core/warn,
16
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,
17
+ * per-command implementations in ./init, ./indexer, ./info, ./knowledge,
18
18
  * ./core/asset-create, ./core/common), so the cluster moves with zero hoisting.
19
19
  *
20
20
  * The leaf handlers whose body is a plain `runWithJsonErrors(...) + output(...)`
21
- * (`init`, `import`, `info`, `db`, `db backups`) are migrated onto
21
+ * (`init`, `import`, `info`) are migrated onto
22
22
  * `defineJsonCommand`, which emits the same JSON envelope (stdout/stderr/
23
23
  * exit-code) as the inline form. `index` keeps a plain `defineCommand` wrapping
24
24
  * `runWithJsonErrors` because its body owns a spinner, an AbortController, and
25
25
  * SIGINT/SIGTERM handlers in a try/finally — left byte-for-byte untouched.
26
26
  */
27
27
  import path from "node:path";
28
- import * as p from "@clack/prompts";
29
28
  import { defineCommand } from "citty";
30
- import { hasSubcommand } from "../../cli/parse-args.js";
29
+ import * as p from "../../cli/clack.js";
31
30
  import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
32
31
  import { assertFlatAssetName } from "../../core/asset/asset-create.js";
33
32
  import { isHttpUrl } from "../../core/common.js";
33
+ import { loadConfig } from "../../core/config/config.js";
34
34
  import { UsageError } from "../../core/errors.js";
35
35
  import { appendEvent } from "../../core/events.js";
36
36
  import { getCacheDir } from "../../core/paths.js";
37
37
  import { clearLogFile, info, isVerbose, setLogFile } from "../../core/warn.js";
38
+ import { resolveWriteTarget } from "../../core/write-source.js";
38
39
  import { akmIndex } from "../../indexer/indexer.js";
39
40
  import { getHyphenatedBoolean, getOutputMode, parseFlagValue } from "../../output/context.js";
40
- import { akmDbBackups } from "../db-cli.js";
41
41
  import { readKnowledgeInput, writeMarkdownAsset } from "../read/knowledge.js";
42
42
  import { assembleInfo } from "./info.js";
43
43
  import { akmInit } from "./init.js";
@@ -48,12 +48,20 @@ export const initCommand = defineJsonCommand({
48
48
  },
49
49
  args: {
50
50
  dir: { type: "string", description: "Custom stash directory path (default: ~/akm)" },
51
+ "set-default": {
52
+ type: "boolean",
53
+ description: "Make --dir the default stash (write stashDir to config.json). Without this, `akm init --dir X` scaffolds X but leaves your existing default stash unchanged.",
54
+ default: false,
55
+ },
51
56
  },
52
57
  async run({ args }) {
53
58
  // Accept both historical spellings for backwards compatibility with
54
59
  // older docs/scripts that used `--stashDir`.
55
60
  const legacyDir = parseFlagValue(process.argv, "--stashDir") ?? parseFlagValue(process.argv, "--stash-dir");
56
- const result = await akmInit({ dir: args.dir ?? legacyDir });
61
+ const result = await akmInit({
62
+ dir: args.dir ?? legacyDir,
63
+ setDefault: args["set-default"],
64
+ });
57
65
  output("init", result);
58
66
  },
59
67
  });
@@ -145,35 +153,6 @@ export const infoCommand = defineJsonCommand({
145
153
  output("info", result);
146
154
  },
147
155
  });
148
- // MVP DB administration. Currently only `akm db backups`; restore is manual —
149
- // stop akm and run `scripts/migrations/restore-data-dir.sh <backup>`.
150
- // Single source of truth: the routing set is derived from the subCommands keys
151
- // (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
152
- const dbSubCommands = {
153
- backups: defineJsonCommand({
154
- meta: {
155
- name: "backups",
156
- 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.",
157
- },
158
- run() {
159
- output("db-backups", akmDbBackups());
160
- },
161
- }),
162
- };
163
- const DB_SUBCOMMAND_SET = new Set(Object.keys(dbSubCommands));
164
- export const dbCommand = defineJsonCommand({
165
- meta: {
166
- name: "db",
167
- 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.",
168
- },
169
- subCommands: dbSubCommands,
170
- run({ args }) {
171
- if (hasSubcommand(args, DB_SUBCOMMAND_SET))
172
- return;
173
- // Default action: list backups.
174
- output("db-backups", akmDbBackups());
175
- },
176
- });
177
156
  export const importKnowledgeCommand = defineJsonCommand({
178
157
  meta: {
179
158
  name: "import",
@@ -206,7 +185,8 @@ export const importKnowledgeCommand = defineJsonCommand({
206
185
  async run({ args }) {
207
186
  // `--name` is a flat name; subdirectory placement is `--path`'s job.
208
187
  assertFlatAssetName(args.name);
209
- const { content, preferredName } = await readKnowledgeInput(args.source);
188
+ const stashDir = resolveWriteTarget(loadConfig(), args.target).source.path;
189
+ const { content, preferredName } = await readKnowledgeInput(args.source, { stashDir });
210
190
  const result = await writeMarkdownAsset({
211
191
  type: "knowledge",
212
192
  content,
@@ -6,27 +6,42 @@ import path from "node:path";
6
6
  import { getDirname } from "../../runtime.js";
7
7
  const SKELETON_DIR = path.join(getDirname(import.meta.url), "../../assets/stash-skeleton");
8
8
  /**
9
- * Copy the default stash skeleton into a newly created stash directory.
9
+ * Copy the default stash skeleton into a stash directory.
10
10
  *
11
- * Each file in src/assets/stash-skeleton/ is written to the stash root only
12
- * if the destination does not already exist — existing files are never
13
- * overwritten. Non-fatal: if the skeleton directory is missing or a copy
14
- * fails the caller continues normally.
11
+ * The skeleton tree under src/assets/stash-skeleton/ is mirrored **recursively**
12
+ * into the stash root, preserving relative subpaths (e.g.
13
+ * `facts/conventions/assets/skill.md` lands at the matching stash subpath).
14
+ * Each file is written only if the destination does not already exist — existing
15
+ * (possibly user-edited) files are never overwritten. Intermediate directories
16
+ * are created as needed.
17
+ *
18
+ * Idempotent and absent-only: running it again on an existing stash backfills
19
+ * any skeleton files that are missing without clobbering present ones. Non-fatal:
20
+ * if the skeleton directory is missing or a copy fails the caller continues.
15
21
  */
16
22
  export function copyStashSkeleton(stashDir) {
23
+ copySkeletonDir(SKELETON_DIR, stashDir);
24
+ }
25
+ /** Recursively mirror `srcDir` into `destDir`, writing files only when absent. */
26
+ function copySkeletonDir(srcDir, destDir) {
17
27
  let entries;
18
28
  try {
19
- entries = fs.readdirSync(SKELETON_DIR);
29
+ entries = fs.readdirSync(srcDir, { withFileTypes: true });
20
30
  }
21
31
  catch {
22
32
  return;
23
33
  }
24
34
  for (const entry of entries) {
25
- const src = path.join(SKELETON_DIR, entry);
26
- const dest = path.join(stashDir, entry);
35
+ const src = path.join(srcDir, entry.name);
36
+ const dest = path.join(destDir, entry.name);
37
+ if (entry.isDirectory()) {
38
+ copySkeletonDir(src, dest);
39
+ continue;
40
+ }
27
41
  if (fs.existsSync(dest))
28
42
  continue;
29
43
  try {
44
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
30
45
  fs.copyFileSync(src, dest);
31
46
  }
32
47
  catch {
@@ -56,6 +71,40 @@ export function scaffoldStashMeta(stashDir) {
56
71
  // Non-fatal — stash is usable without the .meta orientation doc
57
72
  }
58
73
  }
74
+ /** Marks the akm-authored block in a stash `.gitignore` (idempotency anchor). */
75
+ const STASH_GITIGNORE_MARKER = "# akm: keep secret material out of git by default";
76
+ const STASH_GITIGNORE_BLOCK = [
77
+ STASH_GITIGNORE_MARKER,
78
+ "# env/ and secrets/ assets hold tokens and keys. They are ignored by default",
79
+ "# so `git push` can never leak them. To version a specific one (e.g. for a",
80
+ "# private-remote backup), un-ignore its path below once you accept the risk.",
81
+ "env/",
82
+ "secrets/",
83
+ "",
84
+ ].join("\n");
85
+ /**
86
+ * Ensure the stash `.gitignore` keeps `env/` and `secrets/` out of git by
87
+ * default (08-F1: the v0.8.0 `vaults/` → `env/`+`secrets/` migration never
88
+ * carried the ignore rules forward, and init scaffolded none).
89
+ *
90
+ * Idempotent + non-clobbering: creates the file when absent, appends the akm
91
+ * block when the file exists but lacks it (preserving the user's own rules),
92
+ * and no-ops once the marker is present. The user opts INTO versioning by
93
+ * un-ignoring a path.
94
+ */
95
+ export function ensureStashGitignore(stashDir) {
96
+ try {
97
+ const gitignorePath = path.join(stashDir, ".gitignore");
98
+ const existing = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf8") : "";
99
+ if (existing.includes(STASH_GITIGNORE_MARKER))
100
+ return;
101
+ const gap = existing.length === 0 ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
102
+ fs.writeFileSync(gitignorePath, `${existing}${gap}${STASH_GITIGNORE_BLOCK}`);
103
+ }
104
+ catch {
105
+ // Non-fatal — the stash is usable without the ignore scaffold.
106
+ }
107
+ }
59
108
  const STASH_META_INDEX_TEMPLATE = `---
60
109
  # Optional, human-authored orientation for this stash. Not indexed; surfaced
61
110
  # on demand via \`akm show meta\` (this file) or \`akm show <stash>//meta\`.
@@ -20,8 +20,9 @@ import fs from "node:fs";
20
20
  import os from "node:os";
21
21
  import { akmTasksAdd, akmTasksList } from "./tasks.js";
22
22
  /**
23
- * The canonical default improve task set. `update-stashes` is deliberately NOT
24
- * listed here it ships as an embedded core template and is left unchanged.
23
+ * The canonical default improve task set. The `update-stashes` embedded core
24
+ * template (nightly `akm update --all`) was retired in meta-review 06-M2:
25
+ * third-party stash pulls are on-demand only now, not a scheduled cron.
25
26
  */
26
27
  export const DEFAULT_IMPROVE_TASKS = [
27
28
  {
@@ -76,12 +77,19 @@ const DEFAULT_DEPS = {
76
77
  list: akmTasksList,
77
78
  add: akmTasksAdd,
78
79
  };
80
+ let defaultTasksOverrides;
81
+ /** TEST-ONLY. Swap the CI/server/register functions; pass undefined to restore. */
82
+ export function _setDefaultTasksForTests(fakes) {
83
+ defaultTasksOverrides = fakes;
84
+ }
79
85
  /**
80
86
  * Decide whether `akm setup` is running in a CI environment, where it must
81
87
  * register NO scheduled tasks. Mirrors the common `CI=true` convention used by
82
88
  * GitHub Actions, GitLab CI, CircleCI, etc.
83
89
  */
84
90
  export function isCiEnvironment(env = process.env) {
91
+ if (defaultTasksOverrides?.isCiEnvironment)
92
+ return defaultTasksOverrides.isCiEnvironment(env);
85
93
  const ci = env.CI;
86
94
  if (ci === undefined || ci === null)
87
95
  return false;
@@ -95,6 +103,8 @@ export function isCiEnvironment(env = process.env) {
95
103
  * Used as the default when setup is non-interactive (no TTY / --yes / CI).
96
104
  */
97
105
  export function detectServerDefault() {
106
+ if (defaultTasksOverrides?.detectServerDefault)
107
+ return defaultTasksOverrides.detectServerDefault();
98
108
  if (os.platform() !== "linux")
99
109
  return false;
100
110
  // A laptop exposes a battery under /sys/class/power_supply/BAT*. Absence of
@@ -121,6 +131,9 @@ export function detectServerDefault() {
121
131
  * never re-disable a user-enabled task).
122
132
  */
123
133
  export async function registerDefaultTasks(options = {}) {
134
+ if (defaultTasksOverrides?.registerDefaultTasks) {
135
+ return defaultTasksOverrides.registerDefaultTasks(options);
136
+ }
124
137
  if (isCiEnvironment()) {
125
138
  return { skipped: true, reason: "ci", created: [], existing: [], toggled: [] };
126
139
  }
@@ -13,9 +13,8 @@
13
13
  * with the family.
14
14
  */
15
15
  import { defineCommand } from "citty";
16
- import { hasSubcommand, parsePositiveIntFlag } from "../../cli/parse-args.js";
17
- import { defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
18
- import { getHyphenatedArg } from "../../output/context.js";
16
+ import { parsePositiveIntFlag } from "../../cli/parse-args.js";
17
+ import { defineGroupCommand, defineJsonCommand, output, runWithJsonErrors } from "../../cli/shared.js";
19
18
  import { detectServerDefault, registerDefaultTasks } from "./default-tasks.js";
20
19
  import { akmTasksAdd, akmTasksDoctor, akmTasksHistory, akmTasksList, akmTasksRemove, akmTasksRun, akmTasksSetEnabled, akmTasksShow, akmTasksSync, parseTaskRef, } from "./tasks.js";
21
20
  const tasksAddCommand = defineJsonCommand({
@@ -51,7 +50,7 @@ const tasksAddCommand = defineJsonCommand({
51
50
  profile: args.profile,
52
51
  params: args.params,
53
52
  name: args.name,
54
- when_to_use: getHyphenatedArg(args, "when-to-use"),
53
+ when_to_use: args["when-to-use"],
55
54
  description: args.description,
56
55
  tags: args.tags
57
56
  ? args.tags
@@ -176,35 +175,27 @@ const tasksDoctorCommand = defineJsonCommand({
176
175
  output("tasks-doctor", result);
177
176
  },
178
177
  });
179
- // Single source of truth: the routing set is derived from the subCommands keys
180
- // (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
181
- const tasksSubCommands = {
182
- add: tasksAddCommand,
183
- init: tasksInitCommand,
184
- list: tasksListCommand,
185
- show: tasksShowCommand,
186
- remove: tasksRemoveCommand,
187
- enable: tasksEnableCommand,
188
- disable: tasksDisableCommand,
189
- run: tasksRunCommand,
190
- history: tasksHistoryCommand,
191
- sync: tasksSyncCommand,
192
- doctor: tasksDoctorCommand,
193
- };
194
- const TASKS_SUBCOMMAND_SET = new Set(Object.keys(tasksSubCommands));
195
- export const tasksCommand = defineCommand({
178
+ export const tasksCommand = defineGroupCommand({
196
179
  meta: {
197
180
  name: "tasks",
198
181
  alias: "task",
199
182
  description: "Schedule workflows or prompts via the OS-native scheduler (cron / launchd / schtasks)",
200
183
  },
201
- subCommands: tasksSubCommands,
202
- run({ args }) {
203
- return runWithJsonErrors(async () => {
204
- if (hasSubcommand(args, TASKS_SUBCOMMAND_SET))
205
- return;
206
- const result = await akmTasksList();
207
- output("tasks-list", result);
208
- });
184
+ subCommands: {
185
+ add: tasksAddCommand,
186
+ init: tasksInitCommand,
187
+ list: tasksListCommand,
188
+ show: tasksShowCommand,
189
+ remove: tasksRemoveCommand,
190
+ enable: tasksEnableCommand,
191
+ disable: tasksDisableCommand,
192
+ run: tasksRunCommand,
193
+ history: tasksHistoryCommand,
194
+ sync: tasksSyncCommand,
195
+ doctor: tasksDoctorCommand,
196
+ },
197
+ async defaultRun() {
198
+ const result = await akmTasksList();
199
+ output("tasks-list", result);
209
200
  },
210
201
  });
@@ -16,11 +16,12 @@ import { isWithin, resolveStashDir } from "../../core/common.js";
16
16
  import { loadConfig } from "../../core/config/config.js";
17
17
  import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
18
18
  import { getTaskHistoryDir, getTaskLogDir } from "../../core/paths.js";
19
+ import { commitWriteTargetBoundary, deleteAssetFromSource, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
19
20
  import { listAgentProfileNames } from "../../integrations/agent/index.js";
20
21
  import { resolveAssetPath } from "../../sources/resolve.js";
21
22
  import { backendNameForPlatform, selectBackend } from "../../tasks/backends/index.js";
22
23
  import { parseTaskDocument } from "../../tasks/parser.js";
23
- import { resolveAkmInvocation } from "../../tasks/resolveAkmBin.js";
24
+ import { resolveAkmInvocation } from "../../tasks/resolve-akm-bin.js";
24
25
  import { exitCodeForStatus, readTaskHistory, runTask } from "../../tasks/runner.js";
25
26
  import { parseSchedule, SCHEDULE_SUPPORTED_SUBSET_HINT, translateToCron } from "../../tasks/schedule.js";
26
27
  import { validateTaskDocument } from "../../tasks/validator.js";
@@ -38,7 +39,8 @@ export async function akmTasksAdd(input) {
38
39
  // Validate the schedule for the active backend before writing anything.
39
40
  const backend = backendNameForPlatform();
40
41
  parseSchedule(input.schedule, backend);
41
- const stashDir = resolveStashDir();
42
+ const target = resolveTaskWriteTarget();
43
+ const stashDir = target.source.path;
42
44
  const typeRoot = path.join(stashDir, "tasks");
43
45
  fs.mkdirSync(typeRoot, { recursive: true });
44
46
  const assetPath = resolveAssetPathFromName("task", typeRoot, id);
@@ -64,7 +66,8 @@ export async function akmTasksAdd(input) {
64
66
  });
65
67
  const task = parseTaskDocument({ yaml, filePath: assetPath, id });
66
68
  await validateTaskDocument(task, { backend, stashDir });
67
- fs.writeFileSync(assetPath, yaml.endsWith("\n") ? yaml : `${yaml}\n`, "utf8");
69
+ const ref = taskAssetRef(id);
70
+ await writeAssetToSource(target.source, target.config, ref, yaml);
68
71
  // Install in the OS scheduler. If install fails after the file was written,
69
72
  // delete the file so the on-disk state never claims a task is registered
70
73
  // when it isn't.
@@ -74,13 +77,14 @@ export async function akmTasksAdd(input) {
74
77
  }
75
78
  catch (err) {
76
79
  try {
77
- fs.rmSync(assetPath, { force: true });
80
+ await deleteAssetFromSource(target.source, target.config, ref);
78
81
  }
79
82
  catch {
80
83
  /* ignore */
81
84
  }
82
85
  throw err;
83
86
  }
87
+ commitWriteTargetBoundary(target, `Update task:${id}`);
84
88
  return {
85
89
  id,
86
90
  ref: `task:${id}`,
@@ -192,30 +196,47 @@ export async function akmTasksShow(id) {
192
196
  }
193
197
  export async function akmTasksRemove(id) {
194
198
  const normalised = normaliseTaskId(id);
195
- const stashDir = resolveStashDir();
199
+ const target = resolveTaskWriteTarget();
200
+ const stashDir = target.source.path;
196
201
  const typeRoot = path.join(stashDir, "tasks");
197
202
  if (fs.existsSync(typeRoot))
198
203
  warnLegacyMdTaskFiles(typeRoot);
199
- const filePath = await resolveAssetPath(stashDir, "task", normalised);
204
+ await resolveAssetPath(stashDir, "task", normalised);
205
+ const ref = taskAssetRef(normalised);
200
206
  const sched = selectBackend();
207
+ let uninstallError;
208
+ let deleteError;
201
209
  try {
202
210
  await sched.uninstall(normalised);
203
211
  }
204
- finally {
205
- fs.rmSync(filePath, { force: true });
212
+ catch (err) {
213
+ uninstallError = err;
214
+ }
215
+ try {
216
+ await deleteAssetFromSource(target.source, target.config, ref);
206
217
  }
218
+ catch (err) {
219
+ deleteError = err;
220
+ }
221
+ if (uninstallError !== undefined)
222
+ throw uninstallError;
223
+ if (deleteError !== undefined)
224
+ throw deleteError;
225
+ commitWriteTargetBoundary(target, `Remove task:${normalised}`);
207
226
  return { id: normalised, removed: true, backend: sched.name };
208
227
  }
209
228
  export async function akmTasksSetEnabled(id, enabled) {
210
229
  const normalised = normaliseTaskId(id);
211
- const stashDir = resolveStashDir();
230
+ const target = resolveTaskWriteTarget();
231
+ const stashDir = target.source.path;
212
232
  const typeRoot = path.join(stashDir, "tasks");
213
233
  if (fs.existsSync(typeRoot))
214
234
  warnLegacyMdTaskFiles(typeRoot);
215
235
  const filePath = await resolveAssetPath(stashDir, "task", normalised);
216
236
  const yaml = fs.readFileSync(filePath, "utf8");
217
237
  const updated = setEnabledInYaml(yaml, enabled);
218
- fs.writeFileSync(filePath, updated, "utf8");
238
+ const ref = taskAssetRef(normalised);
239
+ await writeAssetToSource(target.source, target.config, ref, updated);
219
240
  const sched = selectBackend();
220
241
  try {
221
242
  // Reinstall from the (just-updated) definition rather than only toggling
@@ -229,9 +250,10 @@ export async function akmTasksSetEnabled(id, enabled) {
229
250
  catch (err) {
230
251
  // Roll the file back so the YAML source-of-truth and the OS
231
252
  // scheduler don't diverge silently when the backend call fails.
232
- fs.writeFileSync(filePath, yaml, "utf8");
253
+ await writeAssetToSource(target.source, target.config, ref, yaml);
233
254
  throw err;
234
255
  }
256
+ commitWriteTargetBoundary(target, `Update task:${normalised}`);
235
257
  return { id: normalised, enabled, backend: sched.name };
236
258
  }
237
259
  export async function akmTasksRun(id) {
@@ -392,6 +414,12 @@ function normaliseTaskId(raw) {
392
414
  }
393
415
  return id;
394
416
  }
417
+ function taskAssetRef(id) {
418
+ return { type: "task", name: id };
419
+ }
420
+ function resolveTaskWriteTarget() {
421
+ return resolveWriteTarget(loadConfig());
422
+ }
395
423
  function renderTaskYaml(input) {
396
424
  const obj = { schedule: input.schedule };
397
425
  if (input.workflow) {
@@ -11,12 +11,11 @@
11
11
  * `process.exit(1)` after the wrapper when findings exist.
12
12
  */
13
13
  import { defineCommand } from "citty";
14
- import { getStringArg, hasSubcommand, parsePositiveIntFlag } from "../cli/parse-args.js";
15
- import { defineJsonCommand, output, runWithJsonErrors } from "../cli/shared.js";
16
- import { isHttpUrl, resolveStashDir } from "../core/common.js";
14
+ import { getStringArg, parsePositiveIntFlag } from "../cli/parse-args.js";
15
+ import { defineGroupCommand, defineJsonCommand, output, runWithJsonErrors } from "../cli/shared.js";
16
+ import { resolveStashDir } from "../core/common.js";
17
17
  import { loadConfig, resolveConfiguredSources } from "../core/config/config.js";
18
18
  import { ConfigError, UsageError } from "../core/errors.js";
19
- import { getHyphenatedArg, getHyphenatedBoolean } from "../output/context.js";
20
19
  import { akmAgentDispatch } from "./agent/agent-dispatch.js";
21
20
  import { readKnowledgeInput } from "./read/knowledge.js";
22
21
  import { buildWebsiteOptions } from "./sources/add-cli.js";
@@ -108,7 +107,7 @@ const wikiRemoveCommand = defineJsonCommand({
108
107
  process.stderr.write("Aborted.\n");
109
108
  return;
110
109
  }
111
- const withSources = getHyphenatedBoolean(args, "with-sources");
110
+ const withSources = args["with-sources"];
112
111
  const { removeWiki } = await import("../wiki/wiki.js");
113
112
  const { akmIndex } = await import("../indexer/indexer.js");
114
113
  const stashDir = resolveStashDir();
@@ -168,13 +167,6 @@ const wikiStashCommand = defineJsonCommand({
168
167
  },
169
168
  async run({ args }) {
170
169
  const { stashRaw } = await import("../wiki/wiki.js");
171
- const { content, preferredName } = await (async () => {
172
- if (!isHttpUrl(args.source))
173
- return readKnowledgeInput(args.source);
174
- const { fetchWebsiteMarkdownSnapshot } = await import("../sources/website-ingest.js");
175
- const snapshot = await fetchWebsiteMarkdownSnapshot(args.source);
176
- return { content: snapshot.content, preferredName: args.as ?? snapshot.preferredName };
177
- })();
178
170
  let stashDir;
179
171
  if (args.target) {
180
172
  // Resolve the named source to its filesystem path.
@@ -193,6 +185,7 @@ const wikiStashCommand = defineJsonCommand({
193
185
  else {
194
186
  stashDir = resolveStashDir();
195
187
  }
188
+ const { content, preferredName } = await readKnowledgeInput(args.source, { stashDir });
196
189
  const result = stashRaw({
197
190
  stashDir,
198
191
  wikiName: args.name,
@@ -250,7 +243,7 @@ const wikiIngestCommand = defineJsonCommand({
250
243
  if (!profileName) {
251
244
  throw new UsageError("akm wiki ingest requires an agent profile. Pass --profile <name> or set defaults.agent in config.", "MISSING_REQUIRED_ARGUMENT", "Available profiles are listed under profiles.agent in your config. Run `akm config get profiles.agent` to inspect.");
252
245
  }
253
- const timeoutMs = parsePositiveIntFlag(getHyphenatedArg(args, "timeout-ms"), "--timeout-ms");
246
+ const timeoutMs = parsePositiveIntFlag(args["timeout-ms"], "--timeout-ms");
254
247
  const model = getStringArg(args, "model");
255
248
  const { getDefaultLlmConfig } = await import("../core/config/config.js");
256
249
  const dispatchResult = await akmAgentDispatch({
@@ -274,34 +267,26 @@ const wikiIngestCommand = defineJsonCommand({
274
267
  });
275
268
  },
276
269
  });
277
- // Single source of truth: the routing set is derived from the subCommands keys
278
- // (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
279
- const wikiSubCommands = {
280
- create: wikiCreateCommand,
281
- register: wikiRegisterCommand,
282
- list: wikiListCommand,
283
- show: wikiShowCommand,
284
- remove: wikiRemoveCommand,
285
- pages: wikiPagesCommand,
286
- search: wikiSearchCommand,
287
- stash: wikiStashCommand,
288
- lint: wikiLintCommand,
289
- ingest: wikiIngestCommand,
290
- };
291
- const WIKI_SUBCOMMAND_SET = new Set(Object.keys(wikiSubCommands));
292
- export const wikiCommand = defineCommand({
270
+ export const wikiCommand = defineGroupCommand({
293
271
  meta: {
294
272
  name: "wiki",
295
273
  description: "Manage multiple markdown wikis (Karpathy-style). akm surfaces (lifecycle, raw/, lint, index); the agent writes pages.",
296
274
  },
297
- subCommands: wikiSubCommands,
298
- run({ args }) {
299
- return runWithJsonErrors(async () => {
300
- if (hasSubcommand(args, WIKI_SUBCOMMAND_SET))
301
- return;
302
- // Default action: list wikis
303
- const { listWikis } = await import("../wiki/wiki.js");
304
- output("wiki-list", { wikis: listWikis(resolveStashDir()) });
305
- });
275
+ subCommands: {
276
+ create: wikiCreateCommand,
277
+ register: wikiRegisterCommand,
278
+ list: wikiListCommand,
279
+ show: wikiShowCommand,
280
+ remove: wikiRemoveCommand,
281
+ pages: wikiPagesCommand,
282
+ search: wikiSearchCommand,
283
+ stash: wikiStashCommand,
284
+ lint: wikiLintCommand,
285
+ ingest: wikiIngestCommand,
286
+ },
287
+ async defaultRun() {
288
+ // Default action: list wikis
289
+ const { listWikis } = await import("../wiki/wiki.js");
290
+ output("wiki-list", { wikis: listWikis(resolveStashDir()) });
306
291
  },
307
292
  });
@@ -24,7 +24,7 @@ import { resolveSourcesForOrigin } from "../registry/origin-resolve.js";
24
24
  import { resolveAssetPath } from "../sources/resolve.js";
25
25
  import { createWorkflowAsset, formatWorkflowErrors, getWorkflowTemplate, validateWorkflowSource, } from "../workflows/authoring/authoring.js";
26
26
  import { hasWorkflowSubcommand, parseWorkflowJsonObject, parseWorkflowStepState, WORKFLOW_STEP_STATES, } from "../workflows/cli.js";
27
- import { completeWorkflowStep, getNextWorkflowStep, getWorkflowStatus, listWorkflowRuns, resumeWorkflowRun, startWorkflowRun, } from "../workflows/runtime/runs.js";
27
+ import { abandonWorkflowRun, completeWorkflowStep, getNextWorkflowStep, getWorkflowStatus, listWorkflowRuns, resumeWorkflowRun, startWorkflowRun, } from "../workflows/runtime/runs.js";
28
28
  const workflowStartCommand = defineJsonCommand({
29
29
  meta: {
30
30
  name: "start",
@@ -290,6 +290,19 @@ async function resolveWorkflowFilePath(target) {
290
290
  }
291
291
  throw new UsageError(`Workflow not found for ref: workflow:${parsed.name}`);
292
292
  }
293
+ const workflowAbandonCommand = defineJsonCommand({
294
+ meta: {
295
+ name: "abandon",
296
+ description: "Give up on a workflow run: mark it failed so it stops counting as active (resume can reopen it)",
297
+ },
298
+ args: {
299
+ runId: { type: "positional", description: "Workflow run id", required: true },
300
+ },
301
+ async run({ args }) {
302
+ const result = await abandonWorkflowRun(args.runId);
303
+ output("workflow-abandon", result);
304
+ },
305
+ });
293
306
  const workflowResumeCommand = defineJsonCommand({
294
307
  meta: {
295
308
  name: "resume",
@@ -317,6 +330,7 @@ export const workflowCommand = defineCommand({
317
330
  create: workflowCreateCommand,
318
331
  template: workflowTemplateCommand,
319
332
  resume: workflowResumeCommand,
333
+ abandon: workflowAbandonCommand,
320
334
  validate: workflowValidateCommand,
321
335
  },
322
336
  run({ args }) {
@@ -29,6 +29,7 @@ export const TYPE_TO_RENDERER = {
29
29
  wiki: "wiki-md",
30
30
  task: "task-yaml",
31
31
  session: "session-md",
32
+ fact: "fact-md",
32
33
  };
33
34
  /** Map asset types to action builder functions for search results. */
34
35
  export const ACTION_BUILDERS = {
@@ -40,11 +41,12 @@ export const ACTION_BUILDERS = {
40
41
  lesson: (ref) => `akm show ${ref} -> read the lesson and apply when_to_use`,
41
42
  memory: (ref) => `akm show ${ref} -> recall context`,
42
43
  workflow: (ref) => buildWorkflowAction(ref),
43
- env: (ref) => `akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with the whole .env injected (the agent-safe path values never reach stdout). akm env export ${ref} --out <file> writes a sourceable script (values to a file, not stdout).`,
44
+ env: (ref) => `akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with the whole .env injected (prefer --clean to minimize inherited parent env; child stdout is not redacted). akm env export ${ref} --out <file> writes a sourceable script (values to a file, not stdout).`,
44
45
  secret: (ref) => `akm show ${ref} -> name only (value never shown); akm secret path ${ref} -> file path; akm secret run ${ref} <VAR> -- <command> -> run with value injected into $VAR`,
45
46
  wiki: (ref) => `akm show ${ref} -> read the wiki page`,
46
47
  task: (ref) => `akm tasks show ${ref.replace(/^task:/, "")} -> inspect; akm tasks run <id> -> run now; akm tasks remove <id> -> unschedule`,
47
48
  session: (ref) => `akm show ${ref} -> read the session summary; follow the \`access\` frontmatter to open the raw log at \`log_path\``,
49
+ fact: (ref) => `akm show ${ref} -> read the stash fact and apply it as durable context`,
48
50
  };
49
51
  /**
50
52
  * Register a type-to-renderer mapping.