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
@@ -48,8 +48,8 @@ Everything in the cache is regenerable. It is safe to delete the entire cache di
48
48
 
49
49
  | Path | Contents | Safe to delete? |
50
50
  |---|---|---|
51
- | `config-backups/config-<timestamp>.json` | Pre-migration config snapshots (5 retained) | Yes |
52
- | `config-backups/config.latest.json` | Latest backup alias | Yes |
51
+ | `config-backups/config-<timestamp>.json` | Pre-save config snapshots (5 retained; owner-only permissions — file `0600`, dir `0700`, since 08-F4) | Yes |
52
+ | `config-backups/config.latest.json` | Latest backup alias (owner-only `0600`) | Yes |
53
53
  | `registry/` | Downloaded registry tarballs (stash packages from npm, GitHub, etc.) | Yes — re-downloaded on next `akm add` or `akm update` |
54
54
  | `registry-index/` | Legacy per-URL JSON cache (v0.7 artifact) | Yes — fully replaced by `index.db` in 0.8.0 |
55
55
  | `semantic-status.json` | Semantic index build status marker | Yes |
@@ -63,7 +63,7 @@ Override: set `AKM_CACHE_DIR` or `XDG_CACHE_HOME`.
63
63
 
64
64
  | Path | Contents | Safe to delete? |
65
65
  |---|---|---|
66
- | `<stash>/` | All your asset files: agents, skills, commands, knowledge, workflows, memories, vaults, wikis, lessons | **No** — this is YOUR data |
66
+ | `<stash>/` | All your asset files: agents, skills, commands, knowledge, workflows, memories, env files, secrets, wikis, lessons, facts | **No** — this is YOUR data |
67
67
  | `<stash>/.akm/` | Hidden AKM metadata (v0.7 proposals, legacy runs) | Caution — check for pending proposals first |
68
68
 
69
69
  Override: set `AKM_STASH_DIR` (or configure `stashDir` in `config.json`).
@@ -130,7 +130,7 @@ An append-only log of every mutating action you perform with AKM. Events are sto
130
130
 
131
131
  ### 2. Proposals Table
132
132
 
133
- The proposal queue: pending, accepted, and rejected improvement proposals for your stash assets. Generated by `akm reflect` and the improve loop.
133
+ The proposal queue: pending, accepted, and rejected improvement proposals for your stash assets. Generated by `akm improve`, `akm propose`, and related proposal-producing flows.
134
134
 
135
135
  Contents:
136
136
  - Proposal UUID (primary key)
@@ -216,6 +216,7 @@ You can redirect any AKM directory to a custom path:
216
216
  |---|---|
217
217
  | `AKM_CONFIG_DIR` | Config directory (`~/.config/akm/`) |
218
218
  | `AKM_DATA_DIR` | Data directory (`~/.local/share/akm/`) |
219
+ | `AKM_SQLITE_JOURNAL_MODE` | SQLite journal mode: `WAL` (default), `DELETE`, or `TRUNCATE`. Use `DELETE`/`TRUNCATE` on network filesystems (NFS/SMB) where WAL is impossible. When left at the `WAL` default, akm auto-detects a network FS for the data dir and falls back to `DELETE`. |
219
220
  | `AKM_STATE_DIR` | State directory (`~/.local/state/akm/`) |
220
221
  | `AKM_CACHE_DIR` | Cache directory (`~/.cache/akm/`) |
221
222
  | `AKM_STASH_DIR` | Default stash directory (`~/akm/`) |
@@ -261,6 +261,6 @@ akm proposal accept <id>
261
261
  baseline. The canonical reference for upgrading.
262
262
  - [v0.5 → v0.6](../v0.5-to-v0.6.md) — the older terminology cut and
263
263
  registry schema v3.
264
- - [v1 architecture spec](../../technical/v1-architecture-spec.md) —
264
+ - [v1 architecture spec](../../archive/v1-architecture-spec.md) —
265
265
  the architecture contract that 0.7.0 commits to maintain through
266
266
  1.0 GA.
@@ -0,0 +1,39 @@
1
+ Migration notes for akm v0.9.0
2
+
3
+ This is the final 0.9.0 cut. If you were already running a 0.9.0 beta, the
4
+ main upgrade work is to align scripts, prompts, and stash layout with the
5
+ released command surface.
6
+
7
+ Key operator-facing changes:
8
+
9
+ - Node.js is supported again for the published CLI. Install with Bun, Node.js
10
+ >= 20.12, or the prebuilt binary.
11
+ - The legacy `vault` asset type and `akm vault ...` command family are gone.
12
+ Use `env:` for whole `.env` groups and `secret:` for a single sensitive
13
+ value.
14
+ - `akm-migrate-storage` still ships and still performs the non-destructive
15
+ `vaults/` -> `env/` copy for older stashes. Run it before indexing if you are
16
+ upgrading from a stash that still stores `.env` files only under `vaults/`.
17
+ - Proposal workflow is fully consolidated around `akm improve`, `akm propose`,
18
+ and `akm proposal ...`. Update any old `akm reflect`, `akm distill`,
19
+ `akm accept`, `akm reject`, or `akm proposals` usage.
20
+
21
+ Primary public command family for 0.9.0:
22
+
23
+ - `akm improve <ref> [--task "..."]`
24
+ - `akm propose <type> <name> (--task "..." | --file <path>)`
25
+ - `akm proposal list`
26
+ - `akm proposal show <id>`
27
+ - `akm proposal diff <id>`
28
+ - `akm proposal accept <id>`
29
+ - `akm proposal reject <id> --reason "..."`
30
+
31
+ Recommended post-upgrade checks:
32
+
33
+ - Run `akm help migrate 0.9.0` on every machine where the CLI is installed.
34
+ - Run `akm-migrate-storage --yes` once if the stash ever used `vaults/`.
35
+ - Rebuild the index with `akm index`.
36
+ - Review agent instructions and docs for old `vault`, `reflect`, and `distill`
37
+ examples.
38
+
39
+ Full changelog: https://github.com/itlackey/akm/blob/main/CHANGELOG.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.0-beta.9",
3
+ "version": "0.9.0-rc.0",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [
@@ -46,28 +46,28 @@
46
46
  "docs/data-and-telemetry.md"
47
47
  ],
48
48
  "bin": {
49
- "akm": "dist/cli.js",
50
- "akm-migrate-storage": "dist/scripts/migrate-storage.js"
49
+ "akm": "dist/akm",
50
+ "akm-migrate-storage": "dist/akm-migrate-storage"
51
51
  },
52
52
  "scripts": {
53
- "preinstall": "node -e \"var ua=process.env.npm_config_user_agent||'';var major=parseInt((process.versions.node||'0').split('.')[0],10);if(process.versions.bun||ua.startsWith('bun/')||process.env.BUN_INSTALL||major>=20){process.exit(0)}console.error('\\n ERROR: akm-cli requires the Bun runtime (https://bun.sh), Node.js >= 20, or the prebuilt binary.\\n Install options:\\n 1. Bun: curl -fsSL https://bun.sh/install | bash && bun install -g akm-cli\\n 2. Binary: curl -fsSL https://github.com/itlackey/akm/releases/latest/download/install.sh | bash\\n');process.exit(1)\"",
53
+ "preinstall": "node -e \"var ua=process.env.npm_config_user_agent||'';var v=(process.versions.node||'0').split('.').map(function(n){return parseInt(n,10)||0});var ok=v[0]>20||(v[0]===20&&(v[1]>12||(v[1]===12&&v[2]>=0)));if(process.versions.bun||ua.startsWith('bun/')||process.env.BUN_INSTALL||ok){process.exit(0)}console.error('\\n ERROR: akm-cli requires the Bun runtime (https://bun.sh), Node.js >= 20.12, or the prebuilt binary.\\n Install options:\\n 1. Bun: curl -fsSL https://bun.sh/install | bash && bun install -g akm-cli\\n 2. Node: upgrade to Node.js 20.12 or newer (https://nodejs.org)\\n 3. Binary: curl -fsSL https://github.com/itlackey/akm/releases/latest/download/install.sh | bash\\n');process.exit(1)\"",
54
54
  "build": "rm -rf dist && bun scripts/gen-config-schema.ts &&bun run tsc --project ./tsconfig.build.json && bun scripts/copy-assets.ts && bun scripts/fix-esm-extensions.ts",
55
55
  "check": "bun run lint && bunx tsc --noEmit && bun run test:unit && bun run test:integration",
56
56
  "check:fast": "bun run lint && bunx tsc --noEmit && bun run test:unit",
57
57
  "check:changed": "bun test tests/output-baseline.test.ts tests/integration/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
58
- "test": "bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
59
- "test:unit": "bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
60
- "test:integration": "bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests/integration ./tests/commands ./tests/workflows",
58
+ "sweep:tmp": "bun scripts/sweep-test-tmp.ts",
59
+ "test": "bash scripts/test-unit.sh",
60
+ "test:unit": "bash scripts/test-unit.sh",
61
+ "test:integration": "bun run sweep:tmp && bun test --timeout=30000 ./tests/integration",
61
62
  "test:node-smoke": "bun scripts/node-smoke.ts",
62
63
  "test:node-compat": "AKM_NODE_COMPAT_TESTS=1 bun test --timeout=120000 tests/integration/node-compat.test.ts",
63
- "test:sharded": "bun test ./tests --shard=1/4 & bun test ./tests --shard=2/4 & bun test ./tests --shard=3/4 & bun test ./tests --shard=4/4 & wait",
64
64
  "test:time": "bun scripts/test-timing-report.ts",
65
65
  "lint:isolation": "bun scripts/lint-tests-isolation.ts",
66
66
  "lint:devto-posts": "bun scripts/lint-devto-posts.ts",
67
67
  "lint:devto-posts:fix": "bun scripts/lint-devto-posts.ts --fix",
68
68
  "publish:devto": "npx -y @sinedied/devto-cli push \"docs/posts/**/*.md\" --token \"$DEVTO_TOKEN\" --repo \"$GITHUB_REPOSITORY\" --branch \"${GITHUB_REF_NAME:-main}\" --reconcile",
69
69
  "release:check": "./tests/release-check.sh",
70
- "lint": "bunx biome check src/ tests/ && bun scripts/lint-tests-isolation.ts && bun scripts/lint-license-headers.ts && bun scripts/lint-runtime-boundary.ts",
70
+ "lint": "bunx biome check src/ tests/ && bun scripts/lint-tests-isolation.ts && bun scripts/lint-license-headers.ts && bun scripts/lint-runtime-boundary.ts && bun scripts/lint-repository-sql.ts && bun scripts/gen-config-schema.ts --check",
71
71
  "lint:runtime-boundary": "bun scripts/lint-runtime-boundary.ts",
72
72
  "lint:tests-isolation": "bun scripts/lint-tests-isolation.ts",
73
73
  "lint:fix": "bunx biome check --write src/ tests/",
@@ -93,7 +93,7 @@
93
93
  },
94
94
  "engines": {
95
95
  "bun": ">=1.0.0",
96
- "node": ">=20.0.0"
96
+ "node": ">=20.12.0"
97
97
  },
98
98
  "dependencies": {
99
99
  "@clack/prompts": "^1.3.0",
@@ -1,4 +0,0 @@
1
- schedule: "0 1 * * *"
2
- command: akm update
3
- enabled: true
4
- description: Pull latest changes for all managed stash sources
@@ -1,23 +0,0 @@
1
- // This Source Code Form is subject to the terms of the Mozilla Public
2
- // License, v. 2.0. If a copy of the MPL was not distributed with this
3
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * CLI command surface for `akm db ...`.
6
- *
7
- * MVP scope: only `akm db backups` is exposed. It lists the pre-upgrade
8
- * snapshots written by `backupDataDir()` under `<dataDir>/backups/`.
9
- *
10
- * Restoration is intentionally NOT a CLI subcommand for MVP — operators are
11
- * expected to stop akm and use `scripts/migrations/restore-data-dir.sh` (or a
12
- * plain `mv`/`cp`) to recover. Keeping the surface narrow lets us evolve the
13
- * backup format under the hood without locking in an API.
14
- */
15
- import { getDataDir } from "../core/paths.js";
16
- import { listBackups } from "../indexer/db/db-backup.js";
17
- export function akmDbBackups() {
18
- const dataDir = getDataDir();
19
- return {
20
- dataDir,
21
- backups: listBackups(dataDir),
22
- };
23
- }
@@ -1,376 +0,0 @@
1
- // This Source Code Form is subject to the terms of the Mozilla Public
2
- // License, v. 2.0. If a copy of the MPL was not distributed with this
3
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * MVP data-directory backup for AKM.
6
- *
7
- * The DB upgrade path in `src/indexer/db/db.ts` `handleVersionUpgrade()` is
8
- * intentionally destructive: when `DB_VERSION` bumps and a stored DB is at an
9
- * older version, ~17 tables are dropped and recreated. Until 0.9.0 ships a
10
- * full migration framework, this MVP captures a recursive copy of the entire
11
- * data directory just before that drop happens so an operator can manually
12
- * recover lost rows by stopping akm and moving the backup contents back over
13
- * the live data dir (see `scripts/migrations/restore-data-dir.sh`).
14
- *
15
- * The helper is intentionally narrow:
16
- * - No `VACUUM INTO`, no selective table backup — just `fs.cpSync` of the
17
- * data directory into `<dataDir>/backups/<timestamp>-pre-v<targetVersion>/`.
18
- * - Skips the `backups/` subdirectory inside the data dir so we never
19
- * recurse into our own backup history.
20
- * - Opt-out via `AKM_DB_BACKUP=0`. Backup failures NEVER abort the upgrade —
21
- * they warn and proceed (the alternative would brick a user trying to
22
- * start a binary that bumped DB_VERSION on a full disk).
23
- * - Retention is FIFO with default of 5, configurable via
24
- * `AKM_DB_BACKUP_RETAIN`.
25
- * - Disk-space guard: refuses to write when free space on the destination
26
- * filesystem is less than 1.1× the source size.
27
- */
28
- import fs from "node:fs";
29
- import path from "node:path";
30
- import { bestEffort } from "../../core/best-effort.js";
31
- import { warn } from "../../core/warn.js";
32
- /** Default reason recorded for backups that don't override it. */
33
- export const DEFAULT_BACKUP_REASON = "version-upgrade";
34
- /** Reason recorded for backups taken before the embedding-dim drop path. */
35
- export const EMBEDDING_DIM_CHANGE_REASON = "embedding-dim-change";
36
- const BACKUPS_DIR_NAME = "backups";
37
- const BACKUP_METADATA_FILE = "backup.meta.json";
38
- const DEFAULT_RETAIN = 5;
39
- const FREE_SPACE_MULTIPLIER = 1.1;
40
- /**
41
- * Resolve the configured retention count from the env, with a hard floor of 1.
42
- *
43
- * Invalid values (non-integer, negative) fall back to the default and emit a
44
- * one-line warning so operators notice their env var is wrong.
45
- */
46
- export function resolveRetention(env = process.env) {
47
- const raw = env.AKM_DB_BACKUP_RETAIN?.trim();
48
- if (!raw)
49
- return DEFAULT_RETAIN;
50
- const parsed = Number.parseInt(raw, 10);
51
- if (Number.isNaN(parsed) || parsed < 1) {
52
- warn("[akm] AKM_DB_BACKUP_RETAIN=%s is not a positive integer; falling back to %d", raw, DEFAULT_RETAIN);
53
- return DEFAULT_RETAIN;
54
- }
55
- return parsed;
56
- }
57
- /**
58
- * Returns true when the user has explicitly opted out via `AKM_DB_BACKUP=0`
59
- * (or `false`/`no`/`off`). Any other value — including unset — opts in.
60
- */
61
- export function isBackupDisabled(env = process.env) {
62
- const raw = env.AKM_DB_BACKUP?.trim().toLowerCase();
63
- if (!raw)
64
- return false;
65
- return raw === "0" || raw === "false" || raw === "no" || raw === "off";
66
- }
67
- /**
68
- * Recursively sum the byte size of `dirPath`, skipping the embedded backups
69
- * directory so the size we report (and check against free space) reflects
70
- * what we'd actually copy.
71
- */
72
- export function measureDataDirSize(dirPath) {
73
- if (!fs.existsSync(dirPath))
74
- return 0;
75
- let total = 0;
76
- const stack = [dirPath];
77
- while (stack.length > 0) {
78
- const current = stack.pop();
79
- if (current === undefined)
80
- break;
81
- let entries;
82
- try {
83
- entries = fs.readdirSync(current, { withFileTypes: true });
84
- }
85
- catch {
86
- // Unreadable directory — skip; we don't want measurement to throw.
87
- continue;
88
- }
89
- for (const entry of entries) {
90
- const full = path.join(current, entry.name);
91
- // Skip the embedded backups directory at the root so we don't
92
- // double-count prior backups in size calculations.
93
- if (current === dirPath && entry.name === BACKUPS_DIR_NAME && entry.isDirectory())
94
- continue;
95
- if (entry.isDirectory()) {
96
- stack.push(full);
97
- }
98
- else if (entry.isFile()) {
99
- bestEffort(() => {
100
- total += fs.statSync(full).size;
101
- }, "file vanished between readdir and stat");
102
- }
103
- }
104
- }
105
- return total;
106
- }
107
- /**
108
- * Best-effort free-space query for the filesystem hosting `dirPath`. Returns
109
- * `null` when the runtime cannot report statfs (older Node/Bun, exotic FS) —
110
- * the caller treats `null` as "skip the disk-space check" rather than
111
- * "abort the backup".
112
- */
113
- function getFreeSpace(dirPath) {
114
- try {
115
- // `fs.statfsSync` is available in Node 18.15+ and Bun 1.0+.
116
- const stats = fs.statfsSync;
117
- if (!stats)
118
- return null;
119
- const res = stats(dirPath);
120
- return Number(res.bavail * res.bsize);
121
- }
122
- catch {
123
- return null;
124
- }
125
- }
126
- /**
127
- * Format the current time into a filename-safe timestamp.
128
- *
129
- * Example: `2026-05-19T04-59-36`.
130
- */
131
- function formatTimestamp(d) {
132
- // ISO 8601 without colons/dots so the path is portable to Windows + tarballs.
133
- return d
134
- .toISOString()
135
- .replace(/[:.]/g, "-")
136
- .replace(/Z$/, "")
137
- .replace(/-\d{3}$/, "");
138
- }
139
- export function listBackups(dataDir) {
140
- const backupsRoot = path.join(dataDir, BACKUPS_DIR_NAME);
141
- if (!fs.existsSync(backupsRoot))
142
- return [];
143
- const entries = fs.readdirSync(backupsRoot, { withFileTypes: true });
144
- const results = [];
145
- for (const entry of entries) {
146
- if (!entry.isDirectory())
147
- continue;
148
- const full = path.join(backupsRoot, entry.name);
149
- const metaPath = path.join(full, BACKUP_METADATA_FILE);
150
- let createdAt;
151
- let sourceVersion = null;
152
- let sizeBytes;
153
- let reason = DEFAULT_BACKUP_REASON;
154
- if (fs.existsSync(metaPath)) {
155
- bestEffort(() => {
156
- const raw = fs.readFileSync(metaPath, "utf8");
157
- const parsed = JSON.parse(raw);
158
- if (typeof parsed.createdAt === "string")
159
- createdAt = parsed.createdAt;
160
- if (typeof parsed.sourceVersion === "number")
161
- sourceVersion = parsed.sourceVersion;
162
- else if (parsed.sourceVersion === null)
163
- sourceVersion = null;
164
- if (typeof parsed.sizeBytes === "number")
165
- sizeBytes = parsed.sizeBytes;
166
- if (typeof parsed.reason === "string" && parsed.reason.length > 0)
167
- reason = parsed.reason;
168
- }, "malformed backup metadata — fall back to filesystem-derived values");
169
- }
170
- if (!createdAt) {
171
- try {
172
- createdAt = fs.statSync(full).mtime.toISOString();
173
- }
174
- catch {
175
- createdAt = new Date(0).toISOString();
176
- }
177
- }
178
- if (sizeBytes === undefined) {
179
- sizeBytes = measureDataDirSize(full);
180
- }
181
- results.push({
182
- path: full,
183
- name: entry.name,
184
- createdAt,
185
- sizeBytes,
186
- sourceVersion,
187
- reason,
188
- });
189
- }
190
- // Sort newest first.
191
- results.sort((a, b) => (a.createdAt < b.createdAt ? 1 : a.createdAt > b.createdAt ? -1 : 0));
192
- return results;
193
- }
194
- /**
195
- * Drop oldest backups until at most `retain` remain. The newest backup (the
196
- * one we just created) is always preserved — pruning happens AFTER the new
197
- * backup is written, so `retain=5` plus a fresh write means we keep the new
198
- * write and prune down to 5 total entries.
199
- */
200
- function pruneOldBackups(dataDir, retain) {
201
- const existing = listBackups(dataDir);
202
- if (existing.length <= retain)
203
- return;
204
- const toRemove = existing.slice(retain);
205
- for (const entry of toRemove) {
206
- try {
207
- fs.rmSync(entry.path, { recursive: true, force: true });
208
- }
209
- catch (err) {
210
- warn("[akm] failed to prune old backup %s — %s", entry.path, err instanceof Error ? err.message : String(err));
211
- }
212
- }
213
- }
214
- /**
215
- * Capture a recursive copy of `dataDir` under `<dataDir>/backups/`, skipping
216
- * the backups subdirectory itself. Returns the BackupResult on success or
217
- * `null` when the backup was skipped (opt-out, missing data dir, insufficient
218
- * disk space, or a copy error — all of which should be non-fatal so the
219
- * upgrade path can still proceed).
220
- */
221
- export function backupDataDir(opts) {
222
- const env = opts.env ?? process.env;
223
- if (isBackupDisabled(env))
224
- return null;
225
- const { dataDir, sourceVersion, targetVersion } = opts;
226
- const reason = opts.reason && opts.reason.length > 0 ? opts.reason : DEFAULT_BACKUP_REASON;
227
- if (!fs.existsSync(dataDir)) {
228
- // Fresh install — nothing to back up.
229
- return null;
230
- }
231
- const dataDirStat = fs.statSync(dataDir);
232
- if (!dataDirStat.isDirectory()) {
233
- warn("[akm] data dir backup skipped — %s is not a directory", dataDir);
234
- return null;
235
- }
236
- // Empty data dir (or only a `backups/` subdir) → nothing meaningful to back up.
237
- const sourceSize = measureDataDirSize(dataDir);
238
- if (sourceSize === 0)
239
- return null;
240
- const backupsRoot = path.join(dataDir, BACKUPS_DIR_NAME);
241
- try {
242
- fs.mkdirSync(backupsRoot, { recursive: true });
243
- }
244
- catch (err) {
245
- warn("[akm] data dir backup skipped — could not create %s: %s", backupsRoot, err instanceof Error ? err.message : String(err));
246
- return null;
247
- }
248
- // Disk-space guard. Skip the check when statfs is unavailable.
249
- const free = getFreeSpace(backupsRoot);
250
- if (free !== null && free < sourceSize * FREE_SPACE_MULTIPLIER) {
251
- warn("[akm] data dir backup skipped — free space %d bytes is less than 1.1× source size %d bytes (need %d)", free, sourceSize, Math.ceil(sourceSize * FREE_SPACE_MULTIPLIER));
252
- return null;
253
- }
254
- const now = (opts.now ?? (() => new Date()))();
255
- const stamp = formatTimestamp(now);
256
- // Reason tags drive the directory suffix so operators can tell a
257
- // version-upgrade snapshot apart from an embedding-dim-change snapshot.
258
- // `version-upgrade` keeps the historical `pre-v<N>` suffix for backward
259
- // compatibility with `scripts/migrations/restore-data-dir.sh` and existing
260
- // tests; any other reason is appended verbatim.
261
- const dirSuffix = reason === DEFAULT_BACKUP_REASON ? `pre-v${targetVersion}` : reason;
262
- const dirName = `${stamp}-${dirSuffix}`;
263
- const destPath = path.join(backupsRoot, dirName);
264
- // If a previous run on the same second tried to write this name, append a
265
- // short disambiguator. We don't want to overwrite or merge into an existing
266
- // backup directory.
267
- let finalDest = destPath;
268
- let suffix = 1;
269
- while (fs.existsSync(finalDest)) {
270
- finalDest = `${destPath}-${suffix}`;
271
- suffix += 1;
272
- }
273
- try {
274
- // We can't use fs.cpSync directly because the destination
275
- // (<dataDir>/backups/<stamp>-pre-v<N>/) is inside the source dataDir, and
276
- // cpSync refuses to copy into a subdirectory of the source. So we do a
277
- // manual recursive walk that explicitly skips the backups subtree, plus
278
- // the lockfile/sentinel that would race with any live process.
279
- copyDataDirExcludingBackups(dataDir, finalDest);
280
- }
281
- catch (err) {
282
- warn("[akm] data dir backup failed — %s; upgrade will proceed without a snapshot", err instanceof Error ? err.message : String(err));
283
- // Best-effort cleanup of the partial copy so we don't litter the data dir.
284
- bestEffort(() => fs.rmSync(finalDest, { recursive: true, force: true }), "cleanup partial backup copy");
285
- return null;
286
- }
287
- const createdAt = now.toISOString();
288
- const metadata = {
289
- schemaVersion: 1,
290
- createdAt,
291
- sourceVersion,
292
- targetVersion,
293
- sizeBytes: sourceSize,
294
- reason,
295
- hostname: tryHostname(),
296
- notes: reason === DEFAULT_BACKUP_REASON
297
- ? "Created by AKM before a destructive DB version upgrade. Restore manually by stopping akm and copying the contents back over the live data dir."
298
- : `Created by AKM before a destructive ${reason} operation. Restore manually by stopping akm and copying the contents back over the live data dir.`,
299
- };
300
- try {
301
- fs.writeFileSync(path.join(finalDest, BACKUP_METADATA_FILE), JSON.stringify(metadata, null, 2));
302
- }
303
- catch (err) {
304
- // Metadata is non-essential — warn but keep the copy.
305
- warn("[akm] data dir backup created at %s but metadata write failed — %s", finalDest, err instanceof Error ? err.message : String(err));
306
- }
307
- const retain = resolveRetention(env);
308
- pruneOldBackups(dataDir, retain);
309
- return {
310
- path: finalDest,
311
- name: path.basename(finalDest),
312
- createdAt,
313
- sizeBytes: sourceSize,
314
- sourceVersion,
315
- targetVersion,
316
- reason,
317
- };
318
- }
319
- /**
320
- * Recursively copy `srcRoot` to `destRoot`, skipping:
321
- * - `<srcRoot>/backups` (so we don't recurse into our own backup history)
322
- * - `<srcRoot>/akm.lock` and `<srcRoot>/akm.lock.lck` (per-process state
323
- * that would race with a live process holding the lock)
324
- *
325
- * Implemented manually because `fs.cpSync` refuses to copy a directory into a
326
- * subdirectory of itself, and our destination (`<dataDir>/backups/<stamp>`)
327
- * is by design inside the source `<dataDir>`.
328
- */
329
- function copyDataDirExcludingBackups(srcRoot, destRoot) {
330
- fs.mkdirSync(destRoot, { recursive: true });
331
- const stack = [{ src: srcRoot, dest: destRoot }];
332
- while (stack.length > 0) {
333
- const frame = stack.pop();
334
- if (frame === undefined)
335
- break;
336
- const { src, dest } = frame;
337
- const entries = fs.readdirSync(src, { withFileTypes: true });
338
- for (const entry of entries) {
339
- // Skip the embedded backups directory and the lockfile/sentinel — only
340
- // at the root level. (A `backups` directory deep in a wiki source tree,
341
- // for instance, must still be copied.)
342
- if (src === srcRoot) {
343
- if (entry.name === BACKUPS_DIR_NAME && entry.isDirectory())
344
- continue;
345
- if (entry.name === "akm.lock" || entry.name === "akm.lock.lck")
346
- continue;
347
- }
348
- const srcPath = path.join(src, entry.name);
349
- const destPath = path.join(dest, entry.name);
350
- if (entry.isDirectory()) {
351
- fs.mkdirSync(destPath, { recursive: true });
352
- stack.push({ src: srcPath, dest: destPath });
353
- }
354
- else if (entry.isFile()) {
355
- fs.copyFileSync(srcPath, destPath);
356
- }
357
- else if (entry.isSymbolicLink()) {
358
- // Preserve symlinks as-is rather than dereferencing them. A stash
359
- // dir occasionally carries symlinked source roots; following them
360
- // could explode the backup size unexpectedly.
361
- const target = fs.readlinkSync(srcPath);
362
- bestEffort(() => fs.symlinkSync(target, destPath), "symlink creation can fail on Windows without admin");
363
- }
364
- // Other entry types (block/character/fifo/socket) are silently skipped.
365
- }
366
- }
367
- }
368
- function tryHostname() {
369
- try {
370
- const os = require("node:os");
371
- return os.hostname();
372
- }
373
- catch {
374
- return undefined;
375
- }
376
- }