akm-cli 0.9.0-rc.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -261,9 +261,8 @@ export async function stepSmallModelConnection(current) {
261
261
  p.note([
262
262
  "This connection is used for background processing:",
263
263
  " • akm index (metadata enhancement)",
264
- " • akm distill (lesson distillation)",
264
+ " • akm improve (lesson distillation)",
265
265
  " • akm remember --enrich (memory compression)",
266
- " • akm curate --rerank (search reranking)",
267
266
  ].join("\n"));
268
267
  // Probe for Ollama and LM Studio in the background while showing the note.
269
268
  const spin = p.spinner();
@@ -303,9 +302,8 @@ export async function stepSmallModelConnection(current) {
303
302
  p.note([
304
303
  "Enrichment features disabled:",
305
304
  " • akm index — metadata enhancement disabled",
306
- " • akm distill — lesson generation",
305
+ " • akm improve — lesson generation",
307
306
  " • akm remember --enrich",
308
- " • akm curate --rerank",
309
307
  "",
310
308
  "You can configure this later with `akm setup`.",
311
309
  ].join("\n"), "Warning");
@@ -384,9 +382,9 @@ export async function stepAgentConnection(current, smallModel) {
384
382
  p.log.step("Step 2/2: Configure your agent connection");
385
383
  p.note([
386
384
  "This connection is used for agentic commands:",
387
- " • akm propose (generate improvement proposals)",
388
- " • akm improve (run the reflect/distill/consolidate self-improvement pipeline)",
389
- " • akm tasks run (run automated task prompts)",
385
+ " • akm proposal new (generate improvement proposals)",
386
+ " • akm improve (run the reflect/distill/consolidate self-improvement pipeline)",
387
+ " • akm task run (run automated task prompts)",
390
388
  ].join("\n"));
391
389
  // Detect available CLI agents.
392
390
  const detections = detectAgentCliProfiles(current);
@@ -437,9 +435,9 @@ export async function stepAgentConnection(current, smallModel) {
437
435
  if (agentChoice === "none") {
438
436
  p.note([
439
437
  "Agentic features disabled:",
440
- ' • akm propose — will show "no agent configured" error',
438
+ ' • akm proposal new — will show "no agent configured" error',
441
439
  ' • akm improve — will show "no agent configured" error',
442
- ' • akm tasks run — will show "no agent configured" error',
440
+ ' • akm task run — will show "no agent configured" error',
443
441
  "",
444
442
  "You can configure this later with `akm setup`.",
445
443
  ].join("\n"), "Warning");
@@ -10,22 +10,22 @@ import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../../integrati
10
10
  import { detectAgentPlatforms } from "../detect.js";
11
11
  import { readAgentEngineSelection } from "../engine-config.js";
12
12
  import { prompt } from "../prompt.js";
13
- // The just-computed source list is threaded in as the draft's scratch `sources`.
13
+ // The just-computed source list is threaded through the private setup draft.
14
14
  export async function stepAgentPlatforms(current) {
15
15
  const platforms = detectAgentPlatforms();
16
16
  if (platforms.length === 0) {
17
17
  p.log.info("No agent platform configurations detected.");
18
18
  return [];
19
19
  }
20
- const existingPaths = new Set((current.sources ?? []).map((s) => s.path));
20
+ const existingPaths = new Set((current.additionalSources ?? []).map((s) => s.path));
21
21
  // Filter out platforms already configured
22
22
  const newPlatforms = platforms.filter((pl) => !existingPaths.has(pl.path));
23
23
  if (newPlatforms.length === 0) {
24
- p.log.info(`Detected ${platforms.length} agent platform(s), all already configured as stash sources.`);
24
+ p.log.info(`Detected ${platforms.length} agent platform(s), all already configured as bundle sources.`);
25
25
  return [];
26
26
  }
27
27
  const selected = await prompt(() => p.multiselect({
28
- message: "Found agent platform configurations. Add as stash sources?",
28
+ message: "Found agent platform configurations. Add as bundle sources?",
29
29
  options: newPlatforms.map((pl) => ({
30
30
  value: pl.path,
31
31
  label: pl.name,
@@ -51,18 +51,18 @@ export async function stepAgentPlatforms(current) {
51
51
  */
52
52
  export function printCapabilitySummary(smallModelSkipped, agentConfigured) {
53
53
  const lines = ["Setup complete. Here's what's enabled:", ""];
54
- lines.push(" ✓ akm search, akm curate, akm show — always available");
54
+ lines.push(" ✓ akm search, akm curate, akm show, akm index, akm remember — always available");
55
55
  if (!smallModelSkipped) {
56
- lines.push(" ✓ akm index, akm distill, akm remember — small model configured");
56
+ lines.push(" ✓ index metadata enhancement, akm improve, akm remember --enrich — small model configured");
57
57
  }
58
58
  else {
59
- lines.push(" ✗ akm index, akm distill, akm remember — run `akm setup` to enable");
59
+ lines.push(" ✗ index metadata enhancement, akm improve, akm remember --enrich — run `akm setup` to enable");
60
60
  }
61
61
  if (agentConfigured) {
62
- lines.push(" ✓ akm propose, akm improve, akm tasks — agent configured");
62
+ lines.push(" ✓ akm proposal new, akm improve, akm task — agent configured");
63
63
  }
64
64
  else {
65
- lines.push(" ✗ akm propose, akm improve, akm tasks — run `akm setup` to enable");
65
+ lines.push(" ✗ akm proposal new, akm improve, akm task — run `akm setup` to enable");
66
66
  }
67
67
  p.note(lines.join("\n"), "Feature Summary");
68
68
  }
@@ -8,15 +8,27 @@
8
8
  import * as p from "../../cli/clack.js";
9
9
  import { prompt } from "../prompt.js";
10
10
  import { describeSemanticSearchAssets, isRemoteEmbeddingConfig } from "../semantic-assets.js";
11
- export async function stepSemanticSearch(current, embedding) {
11
+ export async function stepSemanticSearch(
12
+ // Owner ruling 9 (R-039): the runtime default is "off" (a bare/headless
13
+ // install must never silently pull the ~130 MB model), but the interactive
14
+ // wizard pre-selects semantic search ON — a human is present to read the
15
+ // warning below and decide. `_current` is intentionally unused for the
16
+ // enable/disable pre-selection below: it must NOT track
17
+ // `semanticSearchMode`, or this pre-selection would silently flip to off
18
+ // along with the runtime default. Kept in the signature for call-site
19
+ // stability (callers pass the in-progress setup config positionally).
20
+ _current, embedding) {
21
+ // Show the warning (asset sizes; "no local model download" when a remote
22
+ // embedding endpoint is configured) BEFORE the prompt so the pre-checked
23
+ // default is an informed choice, not a surprise.
24
+ p.note(describeSemanticSearchAssets(embedding).join("\n"), "Semantic Search Assets");
12
25
  const enabled = await prompt(() => p.confirm({
13
26
  message: "Enable semantic search?",
14
- initialValue: current.semanticSearchMode !== "off",
27
+ initialValue: true,
15
28
  }));
16
29
  if (!enabled) {
17
30
  return { mode: "off", prepareAssets: false };
18
31
  }
19
- p.note(describeSemanticSearchAssets(embedding).join("\n"), "Semantic Search Assets");
20
32
  const prepareAssets = await prompt(() => p.confirm({
21
33
  message: isRemoteEmbeddingConfig(embedding)
22
34
  ? "Check the embedding endpoint and verify semantic search now?"
@@ -39,7 +39,7 @@ export async function stepAdditionalSources(currentSources) {
39
39
  let addMore = true;
40
40
  while (addMore) {
41
41
  const action = await prompt(() => p.select({
42
- message: "Add another stash source?",
42
+ message: "Add another bundle source?",
43
43
  options: [
44
44
  { value: "done", label: "Done — no more sources" },
45
45
  { value: "github-repo", label: "GitHub repository", hint: "custom URL" },
@@ -63,7 +63,7 @@ export async function stepAdditionalSources(currentSources) {
63
63
  if (url === null)
64
64
  continue;
65
65
  const name = await promptOrBack(() => p.text({
66
- message: "Give this stash a name (optional):",
66
+ message: "Give this bundle a name (optional):",
67
67
  placeholder: "my-repo",
68
68
  }));
69
69
  if (name === null)
@@ -81,7 +81,7 @@ export async function stepAdditionalSources(currentSources) {
81
81
  if (action === "filesystem") {
82
82
  const fsPath = await promptOrBack(() => p.text({
83
83
  message: "Enter the directory path:",
84
- placeholder: "/path/to/stash",
84
+ placeholder: "/path/to/bundle",
85
85
  validate: (v) => {
86
86
  if (!v?.trim())
87
87
  return "Path cannot be empty";
@@ -91,8 +91,8 @@ export async function stepAdditionalSources(currentSources) {
91
91
  continue;
92
92
  const resolved = fsPath.trim();
93
93
  const name = await promptOrBack(() => p.text({
94
- message: "Give this stash a name (optional):",
95
- placeholder: "my-stash",
94
+ message: "Give this bundle a name (optional):",
95
+ placeholder: "my-bundle",
96
96
  }));
97
97
  if (name === null)
98
98
  continue;
@@ -151,19 +151,18 @@ export async function stepRegistries(current) {
151
151
  * @internal Exported for testing only.
152
152
  */
153
153
  export async function stepAddSources(current, options) {
154
- // 0.9.0 (spec §10.1): existing sources come from the `bundles` map. The
155
- // wizard toggles the PLAIN additional sources (not the primary, not the
156
- // lock-backed registry installs, which are preserved untouched).
154
+ // The wizard toggles plain additional bundles, not the default bundle or
155
+ // lock-backed registry installs, which are preserved untouched.
157
156
  const lockIds = new Set(readLockfile().map((entry) => entry.id));
158
157
  const allSources = getSources(current);
159
158
  const existingSources = allSources.filter((source) => !source.primary && !(source.name && lockIds.has(source.name)));
160
159
  const managedSources = allSources.filter((source) => source.name != null && lockIds.has(source.name));
161
160
  const sources = [];
162
161
  if (existingSources.length > 0) {
163
- p.note(renderConfiguredSourceList(existingSources), "Configured stash sources");
162
+ p.note(renderConfiguredSourceList(existingSources), "Configured bundle sources");
164
163
  const options = existingSources.map(describeConfiguredSource);
165
164
  const selected = await prompt(() => p.multiselect({
166
- message: "Configured stash sources — uncheck any you want to disable:",
165
+ message: "Configured bundle sources — uncheck any you want to disable:",
167
166
  options,
168
167
  initialValues: options.map((option) => option.value),
169
168
  required: false,
@@ -175,7 +174,7 @@ export async function stepAddSources(current, options) {
175
174
  }
176
175
  }
177
176
  if (managedSources.length > 0) {
178
- p.note(renderInstalledSourceList(managedSources), "Installed managed stashes (preserved)");
177
+ p.note(renderInstalledSourceList(managedSources), "Installed managed bundles (preserved)");
179
178
  }
180
179
  // ── Registry-driven stash recommendations ─────────────────────────────
181
180
  // Fetch available stashes from the official registry (cached, stale-ok).
@@ -196,8 +195,8 @@ export async function stepAddSources(current, options) {
196
195
  : availableStashes.filter((s) => s.defaultSelected).map((s) => s.url);
197
196
  const selectedUrls = await prompt(() => p.multiselect({
198
197
  message: availableStashes[0]?.source === "registry"
199
- ? "Available stashes from the AKM registry — toggle to add or remove:"
200
- : "Recommended stash sources — toggle to add or remove:",
198
+ ? "Available bundles from the AKM registry — toggle to add or remove:"
199
+ : "Recommended bundle sources — toggle to add or remove:",
201
200
  options: stashOptions,
202
201
  initialValues,
203
202
  required: false,
@@ -10,7 +10,6 @@ import { primaryBundlePath } from "../../core/config/config.js";
10
10
  import { assertSafeStashDir, getDefaultStashDir } from "../../core/paths.js";
11
11
  import { prompt } from "../prompt.js";
12
12
  export async function stepStashDir(current, options) {
13
- // 0.9.0 (spec §10.1): the current primary stash is the defaultBundle's path.
14
13
  const currentPrimary = primaryBundlePath(current);
15
14
  const defaultDir = options?.preferredDir ?? currentPrimary ?? getDefaultStashDir();
16
15
  if (options?.nonInteractive) {
@@ -26,7 +25,7 @@ export async function stepStashDir(current, options) {
26
25
  if (choice === "default")
27
26
  return defaultDir;
28
27
  const customPath = await prompt(() => p.text({
29
- message: "Enter the stash directory path:",
28
+ message: "Enter the bundle directory path:",
30
29
  placeholder: defaultDir,
31
30
  validate: (v) => {
32
31
  if (!v?.trim())
@@ -37,7 +36,7 @@ export async function stepStashDir(current, options) {
37
36
  catch (err) {
38
37
  if (err instanceof Error)
39
38
  return err.message;
40
- return "Refused: unsafe stash directory";
39
+ return "Refused: unsafe bundle directory";
41
40
  }
42
41
  },
43
42
  }));
@@ -1,152 +1,269 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * Setup wizard steps: register the default improve task set and enable/disable
6
- * scheduled core tasks.
7
- */
4
+ /** Setup wizard step for reviewing task definitions and activating schedules. */
5
+ import fs from "node:fs";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { parse as yamlParse, stringify as yamlStringify } from "yaml";
8
9
  import * as p from "../../cli/clack.js";
9
- import { detectServerDefault, isCiEnvironment, registerDefaultTasks } from "../../commands/tasks/default-tasks.js";
10
- import { akmTasksAdd, akmTasksList, akmTasksSetEnabled, akmTasksSync } from "../../commands/tasks/tasks.js";
11
- import { saveGitStash } from "../../sources/providers/git.js";
10
+ import { akmTasksSync, setEnabledInYaml } from "../../commands/tasks/tasks.js";
11
+ import { loadConfig } from "../../core/config/config.js";
12
+ import { UsageError } from "../../core/errors.js";
13
+ import { commitWriteTargetBoundary, deleteAssetFromSource, prepareWriteTargetForMutation, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
12
14
  import { backendNameForPlatform } from "../../tasks/backends/index.js";
13
15
  import { listEmbeddedTasks } from "../../tasks/embedded.js";
16
+ import { parseTaskDocument } from "../../tasks/parser.js";
14
17
  import { parseSchedule } from "../../tasks/schedule.js";
15
18
  import { prompt } from "../prompt.js";
16
19
  /**
17
- * Normalise a task id the same way `akm tasks` does (strip a trailing `.yml`
18
- * / `.md` suffix, trim) so the wizard can match embedded template ids against
19
- * the ids reported by `akmTasksList()`.
20
+ * A scheduled server-only nightly full sweep exists among the embedded
21
+ * improve-schedule templates (folded in from the retired
22
+ * `registerDefaultTasks`/`akm tasks init` path in 0.9, S6). This id is
23
+ * preselected in the review multiselect on a detected server install — the
24
+ * "battery heuristic" {@link detectServerDefault} preserved from that path.
20
25
  */
21
- function normaliseTaskIdForMatch(raw) {
22
- return raw.trim().replace(/\.(yml|md)$/, "");
26
+ const SERVER_SUGGESTED_TASK_ID = "akm-improve-nightly";
27
+ let scheduledTasksEnvOverrides;
28
+ /** TEST-ONLY. Swap the CI/server-detection probes; pass undefined to restore. */
29
+ export function _setScheduledTasksEnvForTests(fakes) {
30
+ scheduledTasksEnvOverrides = fakes;
23
31
  }
24
32
  /**
25
- * Setup sub-step (issue #552): idempotently register the default improve task
26
- * set. Asks a single "Is this a server install?" question (defaulting per
27
- * platform) to decide whether the nightly sweep is enabled, then delegates to
28
- * {@link registerDefaultTasks}, which is CI-aware and never duplicates an
29
- * existing task. Skipped entirely under CI (the registration helper short-
30
- * circuits, and we never even prompt).
31
- *
32
- * Exported for testing.
33
+ * Decide whether `akm setup` is running in a CI environment, where it must
34
+ * register NO scheduled tasks. Mirrors the common `CI=true` convention used by
35
+ * GitHub Actions, GitLab CI, CircleCI, etc.
33
36
  */
34
- export async function stepDefaultImproveTasks(register = registerDefaultTasks) {
35
- // CI: register nothing and don't prompt.
36
- if (isCiEnvironment()) {
37
- p.log.info("CI detected skipping default improve task registration.");
38
- return;
37
+ export function isCiEnvironment(env = process.env) {
38
+ if (scheduledTasksEnvOverrides?.isCiEnvironment)
39
+ return scheduledTasksEnvOverrides.isCiEnvironment(env);
40
+ const ci = env.CI;
41
+ if (ci === undefined || ci === null)
42
+ return false;
43
+ const v = String(ci).trim().toLowerCase();
44
+ return v !== "" && v !== "0" && v !== "false";
45
+ }
46
+ /**
47
+ * Platform-appropriate default for "Is this a server install?":
48
+ * - Linux without a battery → `true` (server).
49
+ * - macOS / any host with a battery (laptop) → `false`.
50
+ * Used to preselect {@link SERVER_SUGGESTED_TASK_ID} in the task-review
51
+ * multiselect.
52
+ */
53
+ export function detectServerDefault() {
54
+ if (scheduledTasksEnvOverrides?.detectServerDefault)
55
+ return scheduledTasksEnvOverrides.detectServerDefault();
56
+ if (os.platform() !== "linux")
57
+ return false;
58
+ // A laptop exposes a battery under /sys/class/power_supply/BAT*. Absence of
59
+ // any battery is our heuristic for "server / desktop".
60
+ try {
61
+ const entries = fs.readdirSync("/sys/class/power_supply");
62
+ const hasBattery = entries.some((e) => /^BAT/i.test(e));
63
+ return !hasBattery;
64
+ }
65
+ catch {
66
+ // If we cannot read power-supply info, prefer the safe server default on
67
+ // Linux (the nightly sweep is low-impact and re-runnable).
68
+ return true;
39
69
  }
40
- const platformDefault = detectServerDefault();
41
- const serverInstall = await prompt(() => p.confirm({
42
- message: "Is this a server install? (enables the nightly quality sweep at 2am)",
43
- initialValue: platformDefault,
44
- }));
45
- const result = await register({ serverInstall: serverInstall === true });
46
- if (result.skipped)
47
- return;
48
- const total = result.created.length + result.existing.length;
49
- p.log.success(`Default improve tasks registered (${result.created.length} new, ${result.existing.length} already present, ${total} total).`);
70
+ }
71
+ function normaliseTaskIdForMatch(raw) {
72
+ return raw.trim().replace(/\.(yml|md)$/, "");
73
+ }
74
+ export function listSetupTaskDefinitions() {
75
+ const config = loadConfig();
76
+ const target = resolveWriteTarget(config, config.defaultBundle, { requireWritable: false });
77
+ const taskDir = path.join(target.source.path, "tasks");
78
+ if (!fs.existsSync(taskDir))
79
+ return [];
80
+ const tasks = [];
81
+ for (const file of fs.readdirSync(taskDir)) {
82
+ if (!file.endsWith(".yml"))
83
+ continue;
84
+ const id = file.slice(0, -4);
85
+ const filePath = path.join(taskDir, file);
86
+ try {
87
+ const task = parseTaskDocument({ yaml: fs.readFileSync(filePath, "utf8"), filePath, id });
88
+ tasks.push({ id: task.id, schedule: task.schedule, enabled: task.enabled, description: task.description });
89
+ }
90
+ catch (error) {
91
+ throw new UsageError(`Cannot review task definition ${filePath}: ${error instanceof Error ? error.message : String(error)} ` +
92
+ "Fix or remove the invalid task, then rerun `akm setup`. No task files or scheduler state were changed.", "INVALID_FLAG_VALUE", "Fix or remove the invalid task definition, then rerun `akm setup`.");
93
+ }
94
+ }
95
+ return tasks.sort((a, b) => a.id.localeCompare(b.id));
96
+ }
97
+ export async function prepareSetupTaskDefinitions(tasks, deps = {}) {
98
+ const config = loadConfig();
99
+ const target = prepareWriteTargetForMutation(resolveWriteTarget(config, config.defaultBundle, { requireWritable: true }));
100
+ const taskDir = path.join(target.source.path, "tasks");
101
+ const writeAsset = deps.writeAsset ?? writeAssetToSource;
102
+ const deleteAsset = deps.deleteAsset ?? deleteAssetFromSource;
103
+ const commitBoundary = deps.commitBoundary ?? commitWriteTargetBoundary;
104
+ const prepared = tasks.map((plan) => {
105
+ const filePath = path.join(taskDir, `${plan.task.id}.yml`);
106
+ const original = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : undefined;
107
+ let yaml;
108
+ if (original !== undefined) {
109
+ yaml = setEnabledInYaml(original, plan.enabled);
110
+ }
111
+ else {
112
+ const document = yamlParse(plan.task.yaml);
113
+ document.schedule = plan.schedule;
114
+ document.enabled = plan.enabled;
115
+ yaml = yamlStringify(document);
116
+ }
117
+ parseTaskDocument({ yaml, filePath, id: plan.task.id });
118
+ parseSchedule(plan.schedule, backendNameForPlatform());
119
+ return { filePath, original, yaml, ref: { type: "task", name: plan.task.id } };
120
+ });
121
+ const changed = prepared.filter((entry) => entry.original !== entry.yaml);
122
+ if (changed.length === 0)
123
+ return 0;
124
+ const attempted = [];
125
+ try {
126
+ for (const entry of changed) {
127
+ attempted.push(entry);
128
+ await writeAsset(target.source, target.config, entry.ref, entry.yaml);
129
+ }
130
+ commitBoundary(target, "Prepare scheduled tasks");
131
+ }
132
+ catch (error) {
133
+ const rollbackErrors = [];
134
+ for (const entry of [...attempted].reverse()) {
135
+ try {
136
+ if (entry.original === undefined) {
137
+ if (fs.existsSync(entry.filePath))
138
+ await deleteAsset(target.source, target.config, entry.ref);
139
+ }
140
+ else {
141
+ await writeAsset(target.source, target.config, entry.ref, entry.original);
142
+ fs.writeFileSync(entry.filePath, entry.original, "utf8");
143
+ }
144
+ }
145
+ catch (rollbackError) {
146
+ rollbackErrors.push(rollbackError);
147
+ }
148
+ }
149
+ try {
150
+ commitBoundary(target, "Restore scheduled tasks after failed setup");
151
+ }
152
+ catch (rollbackError) {
153
+ rollbackErrors.push(rollbackError);
154
+ }
155
+ if (rollbackErrors.length > 0) {
156
+ throw new AggregateError([error, ...rollbackErrors], `Task definition preparation failed and rollback was incomplete: ${error instanceof Error ? error.message : String(error)}`);
157
+ }
158
+ throw error;
159
+ }
160
+ return changed.length;
50
161
  }
51
162
  const DEFAULT_SCHEDULED_TASKS_DEPS = {
52
- list: akmTasksList,
53
- add: akmTasksAdd,
54
- setEnabled: akmTasksSetEnabled,
163
+ list: listSetupTaskDefinitions,
164
+ prepare: prepareSetupTaskDefinitions,
55
165
  sync: akmTasksSync,
56
- gitSync: saveGitStash,
57
166
  };
58
- export async function stepScheduledTasks(deps = DEFAULT_SCHEDULED_TASKS_DEPS) {
59
- const embedded = listEmbeddedTasks().filter((task) => task.enabled);
60
- if (embedded.length === 0)
167
+ export async function stepScheduledTasks(deps = DEFAULT_SCHEDULED_TASKS_DEPS, options = {}) {
168
+ if (options.nonInteractive || isCiEnvironment()) {
169
+ p.log.info("Non-interactive setup leaves task files and scheduler state unchanged. Run `akm setup` interactively to review tasks.");
61
170
  return;
62
- // Snapshot current state so we can diff against the user's selection.
63
- let installed = [];
64
- try {
65
- installed = (await deps.list()).tasks;
66
- }
67
- catch {
68
- // A missing/empty tasks dir is fine — treat as nothing installed.
69
- installed = [];
70
171
  }
172
+ // ALL templates are offered, including ships-disabled ones (e.g. the
173
+ // manual-recovery catchup task): an unselected template is still PREPARED
174
+ // with `enabled: false`, so its YAML exists for `akm task run <id>` while
175
+ // nothing lands in the scheduler uncommented. Filtering on `task.enabled`
176
+ // here would make ships-disabled templates invisible and unpreparable.
177
+ const embedded = listEmbeddedTasks();
178
+ if (embedded.length === 0)
179
+ return;
180
+ const installed = await deps.list();
71
181
  const byId = new Map();
72
- for (const t of installed)
73
- byId.set(normaliseTaskIdForMatch(t.id), t);
74
- // Pre-check tasks that are installed AND enabled.
75
- const preChecked = embedded.filter((e) => byId.get(e.id)?.enabled === true).map((e) => e.id);
76
- const stateLabel = (e) => {
77
- const cur = byId.get(e.id);
78
- if (!cur)
79
- return "not installed";
80
- return cur.enabled ? "enabled" : "disabled";
81
- };
182
+ for (const task of installed)
183
+ byId.set(normaliseTaskIdForMatch(task.id), task);
184
+ const preChecked = embedded.filter((task) => byId.get(task.id)?.enabled === true).map((task) => task.id);
185
+ // Battery heuristic preserved from the retired `registerDefaultTasks` path
186
+ // (S6): suggest the nightly full sweep on a detected server install, same
187
+ // as every other embedded template, still gated behind the confirmation
188
+ // below.
189
+ if (!byId.has(SERVER_SUGGESTED_TASK_ID) &&
190
+ !preChecked.includes(SERVER_SUGGESTED_TASK_ID) &&
191
+ embedded.some((task) => task.id === SERVER_SUGGESTED_TASK_ID) &&
192
+ detectServerDefault()) {
193
+ preChecked.push(SERVER_SUGGESTED_TASK_ID);
194
+ }
82
195
  const selected = await prompt(() => p.multiselect({
83
- message: "Enable scheduled core tasks? (space to toggle, enter to confirm)",
196
+ message: "Which task definitions should be enabled? (scheduler activation is confirmed separately)",
84
197
  required: false,
85
198
  initialValues: preChecked,
86
- options: embedded.map((e) => ({
87
- value: e.id,
88
- label: e.label,
89
- hint: `${e.description} ${e.schedule} [${stateLabel(e)}]`,
90
- })),
199
+ options: embedded.map((task) => {
200
+ const current = byId.get(task.id);
201
+ const schedule = current?.schedule ?? task.schedule;
202
+ const state = current ? (current.enabled ? "enabled" : "disabled") : "not prepared";
203
+ return {
204
+ value: task.id,
205
+ label: task.label,
206
+ hint: `${task.description} - ${schedule} [${state}]`,
207
+ };
208
+ }),
91
209
  }));
92
210
  const selectedSet = new Set(selected);
93
- // Resolve per-task schedule edits for newly-checked, not-yet-installed tasks.
94
211
  const scheduleFor = new Map();
95
- for (const e of embedded) {
96
- const cur = byId.get(e.id);
97
- if (selectedSet.has(e.id) && !cur) {
98
- const edited = await prompt(() => p.text({
99
- message: `Schedule for ${e.label}?`,
100
- initialValue: e.schedule,
101
- validate(value) {
102
- const candidate = (value ?? "").trim() || e.schedule;
103
- try {
104
- parseSchedule(candidate, backendNameForPlatform());
105
- }
106
- catch (err) {
107
- return err instanceof Error ? err.message : "Invalid schedule.";
108
- }
109
- return undefined;
110
- },
111
- }));
112
- const sched = (edited ?? "").trim() || e.schedule;
113
- scheduleFor.set(e.id, sched);
114
- }
212
+ for (const task of embedded) {
213
+ if (!selectedSet.has(task.id) || byId.has(task.id))
214
+ continue;
215
+ const edited = await prompt(() => p.text({
216
+ message: `Schedule for ${task.label}?`,
217
+ initialValue: task.schedule,
218
+ validate(value) {
219
+ const candidate = (value ?? "").trim() || task.schedule;
220
+ try {
221
+ parseSchedule(candidate, backendNameForPlatform());
222
+ }
223
+ catch (error) {
224
+ return error instanceof Error ? error.message : "Invalid schedule.";
225
+ }
226
+ return undefined;
227
+ },
228
+ }));
229
+ scheduleFor.set(task.id, (edited ?? "").trim() || task.schedule);
115
230
  }
116
- let syncNeeded = false;
117
- for (const e of embedded) {
118
- const cur = byId.get(e.id);
119
- const checked = selectedSet.has(e.id);
120
- if (checked && !cur) {
121
- // New task: copy template into the primary stash + install scheduler entry.
122
- const schedule = scheduleFor.get(e.id) ?? e.schedule;
123
- await deps.add({
124
- id: e.id,
125
- schedule,
126
- command: e.command,
127
- description: e.description,
128
- });
129
- syncNeeded = true;
130
- }
131
- else if (checked && cur && !cur.enabled) {
132
- // Present but disabled re-enable.
133
- await deps.setEnabled(e.id, true);
134
- }
135
- else if (!checked && cur?.enabled) {
136
- // Previously enabled, now unchecked disable (keep the stash file).
137
- await deps.setEnabled(e.id, false);
138
- }
139
- // No state change → no action.
231
+ const plans = embedded.map((task) => {
232
+ const current = byId.get(task.id);
233
+ return {
234
+ task,
235
+ schedule: current?.schedule ?? scheduleFor.get(task.id) ?? task.schedule,
236
+ enabled: selectedSet.has(task.id),
237
+ installed: current !== undefined,
238
+ };
239
+ });
240
+ const embeddedIds = new Set(embedded.map((task) => task.id));
241
+ const custom = installed.filter((task) => !embeddedIds.has(normaliseTaskIdForMatch(task.id)));
242
+ p.note([
243
+ ...plans.map((plan) => `${plan.task.label}: ${plan.enabled ? "enabled" : "disabled"} | ${plan.schedule} | ${plan.task.description}`),
244
+ ...custom.map((task) => `${task.id}: ${task.enabled ? "enabled" : "disabled"} | ${task.schedule}${task.description ? ` | ${task.description}` : ""}`),
245
+ ].join("\n"), "Task Schedule Review");
246
+ const activate = await prompt(() => p.confirm({
247
+ message: `Activate these schedules now? This will update task files and sync them to the ${backendNameForPlatform()} scheduler.`,
248
+ initialValue: false,
249
+ }));
250
+ if (!activate) {
251
+ p.log.info("Task definitions and scheduler state were not changed.");
252
+ return;
140
253
  }
141
- if (syncNeeded) {
142
- // Reconcile scheduler entries with on-disk YAML, then commit the new file
143
- // to git (a no-op for non-git stashes).
144
- await deps.sync();
145
- try {
146
- deps.gitSync(undefined, "akm setup: enable scheduled tasks");
147
- }
148
- catch {
149
- // Non-fatal — the task is installed regardless of git sync outcome.
254
+ const changed = await deps.prepare(plans);
255
+ if (changed > 0)
256
+ p.log.success(`Prepared ${changed} task definition${changed === 1 ? "" : "s"}.`);
257
+ const syncResult = await deps.sync();
258
+ if (syncResult.skipped.length > 0) {
259
+ for (const skipped of syncResult.skipped) {
260
+ p.log.warn(`Task "${skipped.id}" was not activated: ${skipped.reason}`);
150
261
  }
262
+ const activeCount = syncResult.installed.length + syncResult.updated.length + syncResult.unchanged.length;
263
+ p.log.warn(`${activeCount === 0 ? "No task schedules were activated." : "Task schedule activation was incomplete."} ` +
264
+ "If you are running AKM from source, run the installed `akm setup`. " +
265
+ "To migrate or repair existing scheduler bindings explicitly, run `akm task sync --rebind`.");
266
+ return;
151
267
  }
268
+ p.log.success("Task schedules activated. Verify them with `akm task doctor`.");
152
269
  }
@@ -31,7 +31,7 @@ export async function withFreshnessCache(options) {
31
31
  await options.refresh();
32
32
  }
33
33
  catch (err) {
34
- if (mtime && !isExpired(mtime, options.staleMs) && usable()) {
34
+ if (options.allowStaleOnRefreshFailure !== false && mtime && !isExpired(mtime, options.staleMs) && usable()) {
35
35
  return;
36
36
  }
37
37
  throw err;