akm-cli 0.8.7 → 0.8.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/CHANGELOG.md +428 -0
  2. package/dist/assets/help/help-proposals.md +1 -2
  3. package/dist/assets/hints/cli-hints-full.md +34 -19
  4. package/dist/assets/hints/cli-hints-short.md +1 -1
  5. package/dist/assets/profiles/catchup.json +13 -0
  6. package/dist/assets/profiles/consolidate.json +13 -0
  7. package/dist/assets/profiles/frequent.json +13 -0
  8. package/dist/assets/tasks/core/backup.yml +4 -0
  9. package/dist/assets/tasks/core/extract.yml +4 -0
  10. package/dist/assets/tasks/core/improve.yml +4 -0
  11. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  12. package/dist/assets/tasks/core/sync.yml +4 -0
  13. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  14. package/dist/assets/tasks/core/version-check.yml +4 -0
  15. package/dist/assets/templates/html/default.html +78 -0
  16. package/dist/assets/templates/html/health.html +560 -0
  17. package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
  18. package/dist/cli/config-migrate.js +6 -6
  19. package/dist/cli/config-validate.js +4 -4
  20. package/dist/cli/confirm.js +3 -3
  21. package/dist/cli/parse-args.js +1 -1
  22. package/dist/cli/shared.js +72 -19
  23. package/dist/cli-node.mjs +26 -0
  24. package/dist/cli.js +206 -3866
  25. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  26. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  27. package/dist/commands/agent/contribute-cli.js +200 -0
  28. package/dist/commands/completions.js +1 -1
  29. package/dist/commands/config-cli.js +230 -3
  30. package/dist/commands/db-cli.js +2 -2
  31. package/dist/commands/env/env-cli.js +529 -0
  32. package/dist/commands/env/env.js +410 -0
  33. package/dist/commands/env/secret-cli.js +259 -0
  34. package/dist/commands/{secret.js → env/secret.js} +6 -47
  35. package/dist/commands/events.js +4 -4
  36. package/dist/commands/feedback-cli.js +18 -34
  37. package/dist/commands/graph/graph-cli.js +132 -0
  38. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  39. package/dist/commands/health/checks.js +279 -0
  40. package/dist/commands/health/html-report.js +448 -0
  41. package/dist/commands/health.js +189 -266
  42. package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
  43. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  44. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  45. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  46. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  47. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  48. package/dist/commands/{extract.js → improve/extract.js} +221 -26
  49. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
  50. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
  51. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  52. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
  53. package/dist/commands/{improve.js → improve/improve.js} +672 -292
  54. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  55. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  56. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  57. package/dist/commands/improve/reflect-noise.js +0 -0
  58. package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
  59. package/dist/commands/improve/session-asset.js +248 -0
  60. package/dist/commands/lint/agent-linter.js +1 -1
  61. package/dist/commands/lint/base-linter.js +55 -37
  62. package/dist/commands/lint/command-linter.js +1 -1
  63. package/dist/commands/lint/default-linter.js +1 -1
  64. package/dist/commands/lint/env-key-rules.js +1 -1
  65. package/dist/commands/lint/index.js +19 -25
  66. package/dist/commands/lint/knowledge-linter.js +1 -1
  67. package/dist/commands/lint/memory-linter.js +1 -1
  68. package/dist/commands/lint/registry.js +8 -8
  69. package/dist/commands/lint/skill-linter.js +1 -1
  70. package/dist/commands/lint/task-linter.js +1 -1
  71. package/dist/commands/lint/workflow-linter.js +1 -1
  72. package/dist/commands/lint.js +1 -1
  73. package/dist/commands/observability-cli.js +244 -0
  74. package/dist/commands/proposal/drain-policies.js +3 -3
  75. package/dist/commands/proposal/drain.js +87 -15
  76. package/dist/commands/proposal/proposal-cli.js +490 -0
  77. package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
  78. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  79. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  80. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  81. package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
  82. package/dist/commands/{curate.js → read/curate.js} +7 -7
  83. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  84. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  85. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  86. package/dist/commands/read/search-cli.js +207 -0
  87. package/dist/commands/{search.js → read/search.js} +22 -27
  88. package/dist/commands/{show.js → read/show.js} +31 -45
  89. package/dist/commands/registry-cli.js +8 -8
  90. package/dist/commands/remember.js +14 -10
  91. package/dist/commands/sources/add-cli.js +293 -0
  92. package/dist/commands/{history.js → sources/history.js} +27 -25
  93. package/dist/commands/{info.js → sources/info.js} +6 -6
  94. package/dist/commands/{init.js → sources/init.js} +6 -6
  95. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  96. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  97. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  98. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  99. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  100. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  101. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  102. package/dist/commands/sources/sources-cli.js +305 -0
  103. package/dist/commands/sources/stash-cli.js +219 -0
  104. package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
  105. package/dist/commands/tasks/default-tasks.js +173 -0
  106. package/dist/commands/tasks/tasks-cli.js +210 -0
  107. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  108. package/dist/commands/wiki-cli.js +307 -0
  109. package/dist/commands/workflow-cli.js +329 -0
  110. package/dist/core/action-contributors.js +1 -1
  111. package/dist/core/assert.js +40 -0
  112. package/dist/core/asset/asset-create.js +54 -0
  113. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  114. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  115. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  116. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  117. package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
  118. package/dist/core/best-effort.js +64 -0
  119. package/dist/core/common.js +32 -18
  120. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  121. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  122. package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
  123. package/dist/core/config/config-types.js +16 -0
  124. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  125. package/dist/core/{config.js → config/config.js} +10 -8
  126. package/dist/core/env-secret-ref.js +90 -0
  127. package/dist/core/errors.js +13 -3
  128. package/dist/core/events.js +27 -4
  129. package/dist/core/file-lock.js +1 -1
  130. package/dist/core/improve-types.js +48 -0
  131. package/dist/core/lesson-lint.js +2 -2
  132. package/dist/core/logs-db.js +304 -0
  133. package/dist/core/paths.js +2 -2
  134. package/dist/core/ripgrep/install.js +2 -2
  135. package/dist/core/ripgrep/resolve.js +2 -2
  136. package/dist/core/state-db.js +195 -60
  137. package/dist/core/text-truncation.js +148 -0
  138. package/dist/core/time.js +1 -1
  139. package/dist/core/write-source.js +98 -85
  140. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  141. package/dist/indexer/{db.js → db/db.js} +128 -118
  142. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  143. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  144. package/dist/indexer/ensure-index.js +4 -4
  145. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  146. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  147. package/dist/indexer/indexer.js +37 -30
  148. package/dist/indexer/init.js +54 -0
  149. package/dist/indexer/manifest.js +10 -10
  150. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
  151. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  152. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  153. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  154. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  155. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  156. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  157. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  158. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  159. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  160. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  161. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  162. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  163. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  164. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  165. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  166. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  167. package/dist/integrations/agent/builder-shared.js +39 -0
  168. package/dist/integrations/agent/builders.js +14 -81
  169. package/dist/integrations/agent/config.js +6 -4
  170. package/dist/integrations/agent/detect.js +1 -1
  171. package/dist/integrations/agent/index.js +23 -8
  172. package/dist/integrations/agent/prompts.js +2 -3
  173. package/dist/integrations/agent/runner.js +22 -3
  174. package/dist/integrations/agent/spawn.js +9 -10
  175. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  176. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  177. package/dist/integrations/harnesses/claude/index.js +64 -0
  178. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
  179. package/dist/integrations/harnesses/index.js +144 -0
  180. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  181. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  182. package/dist/integrations/harnesses/opencode/index.js +59 -0
  183. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  184. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  185. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  186. package/dist/integrations/harnesses/types.js +43 -0
  187. package/dist/integrations/lockfile.js +7 -16
  188. package/dist/integrations/session-logs/index.js +82 -9
  189. package/dist/llm/call-ai.js +4 -4
  190. package/dist/llm/client.js +146 -6
  191. package/dist/llm/embedder.js +6 -6
  192. package/dist/llm/embedders/local.js +9 -22
  193. package/dist/llm/embedders/remote.js +2 -2
  194. package/dist/llm/embedders/types.js +1 -1
  195. package/dist/llm/graph-extract.js +31 -12
  196. package/dist/llm/index-passes.js +1 -1
  197. package/dist/llm/memory-infer.js +12 -5
  198. package/dist/llm/metadata-enhance.js +2 -2
  199. package/dist/llm/usage-persist.js +77 -0
  200. package/dist/llm/usage-telemetry.js +103 -0
  201. package/dist/output/context.js +9 -46
  202. package/dist/output/html-render.js +73 -0
  203. package/dist/output/renderers.js +88 -58
  204. package/dist/output/shapes/curate.js +7 -3
  205. package/dist/output/shapes/distill.js +7 -3
  206. package/dist/output/shapes/env-list.js +18 -16
  207. package/dist/output/shapes/events.js +5 -4
  208. package/dist/output/shapes/helpers.js +19 -5
  209. package/dist/output/shapes/history.js +7 -3
  210. package/dist/output/shapes/passthrough.js +8 -11
  211. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  212. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  213. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  214. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  215. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  216. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  217. package/dist/output/shapes/registry-search.js +7 -3
  218. package/dist/output/shapes/registry.js +12 -0
  219. package/dist/output/shapes/search.js +7 -3
  220. package/dist/output/shapes/secret-list.js +18 -16
  221. package/dist/output/shapes/show.js +7 -3
  222. package/dist/output/shapes.js +55 -30
  223. package/dist/output/text/add.js +2 -3
  224. package/dist/output/text/clone.js +2 -3
  225. package/dist/output/text/config.js +2 -3
  226. package/dist/output/text/curate.js +4 -3
  227. package/dist/output/text/distill.js +2 -3
  228. package/dist/output/text/enable-disable.js +5 -4
  229. package/dist/output/text/env.js +13 -0
  230. package/dist/output/text/events.js +5 -4
  231. package/dist/output/text/feedback.js +4 -3
  232. package/dist/output/text/helpers.js +123 -40
  233. package/dist/output/text/history.js +2 -3
  234. package/dist/output/text/import.js +2 -3
  235. package/dist/output/text/index.js +2 -3
  236. package/dist/output/text/info.js +2 -3
  237. package/dist/output/text/init.js +2 -3
  238. package/dist/output/text/list.js +2 -3
  239. package/dist/output/text/proposal/producer.js +9 -0
  240. package/dist/output/text/proposal/proposal.js +13 -0
  241. package/dist/output/text/registry-commands.js +8 -7
  242. package/dist/output/text/registry.js +12 -0
  243. package/dist/output/text/remember.js +4 -3
  244. package/dist/output/text/remove.js +2 -3
  245. package/dist/output/text/save.js +2 -3
  246. package/dist/output/text/search.js +4 -3
  247. package/dist/output/text/show.js +4 -3
  248. package/dist/output/text/update.js +2 -3
  249. package/dist/output/text/upgrade.js +2 -3
  250. package/dist/output/text/wiki.js +12 -11
  251. package/dist/output/text/workflow.js +12 -10
  252. package/dist/output/text.js +66 -32
  253. package/dist/registry/build-index.js +11 -10
  254. package/dist/registry/factory.js +1 -1
  255. package/dist/registry/origin-resolve.js +1 -1
  256. package/dist/registry/providers/index.js +2 -2
  257. package/dist/registry/providers/skills-sh.js +91 -72
  258. package/dist/registry/providers/static-index.js +75 -52
  259. package/dist/registry/resolve.js +3 -3
  260. package/dist/runtime.js +242 -0
  261. package/dist/scripts/migrate-storage.js +1654 -683
  262. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
  263. package/dist/setup/detect.js +311 -9
  264. package/dist/setup/harness-config-import.js +6 -120
  265. package/dist/setup/setup.js +454 -43
  266. package/dist/sources/include.js +1 -1
  267. package/dist/sources/provider-factory.js +2 -2
  268. package/dist/sources/providers/filesystem.js +3 -3
  269. package/dist/sources/providers/git.js +9 -9
  270. package/dist/sources/providers/index.js +4 -4
  271. package/dist/sources/providers/npm.js +6 -6
  272. package/dist/sources/providers/provider-utils.js +13 -20
  273. package/dist/sources/providers/sync-from-ref.js +5 -5
  274. package/dist/sources/providers/tar-utils.js +2 -2
  275. package/dist/sources/providers/website.js +2 -2
  276. package/dist/sources/resolve.js +5 -5
  277. package/dist/sources/website-ingest.js +5 -5
  278. package/dist/storage/database.js +102 -0
  279. package/dist/storage/engines/sqlite-migrations.js +42 -0
  280. package/dist/storage/locations.js +25 -0
  281. package/dist/storage/repositories/index-db.js +43 -0
  282. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  283. package/dist/tasks/backends/cron.js +4 -4
  284. package/dist/tasks/backends/exec-utils.js +32 -0
  285. package/dist/tasks/backends/index.js +3 -3
  286. package/dist/tasks/backends/launchd.js +7 -14
  287. package/dist/tasks/backends/schtasks.js +7 -16
  288. package/dist/tasks/embedded.js +71 -0
  289. package/dist/tasks/parser.js +2 -2
  290. package/dist/tasks/resolveAkmBin.js +1 -1
  291. package/dist/tasks/runner.js +127 -31
  292. package/dist/tasks/schedule.js +1 -1
  293. package/dist/tasks/validator.js +7 -7
  294. package/dist/text-import-hook.mjs +51 -0
  295. package/dist/version.js +2 -1
  296. package/dist/wiki/wiki.js +7 -7
  297. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  298. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  299. package/dist/workflows/cli.js +1 -1
  300. package/dist/workflows/db.js +54 -32
  301. package/dist/workflows/parser.js +4 -4
  302. package/dist/workflows/renderer.js +5 -5
  303. package/dist/workflows/runtime/agent-identity.js +56 -0
  304. package/dist/workflows/runtime/checkin.js +57 -0
  305. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  306. package/dist/workflows/validate-summary.js +82 -0
  307. package/docs/README.md +1 -1
  308. package/docs/data-and-telemetry.md +6 -6
  309. package/package.json +17 -8
  310. package/dist/commands/add-cli.js +0 -279
  311. package/dist/commands/env.js +0 -213
  312. package/dist/integrations/agent/sdk-runner.js +0 -126
  313. package/dist/output/shapes/vault-list.js +0 -19
  314. package/dist/output/text/proposal-producer.js +0 -8
  315. package/dist/output/text/proposal.js +0 -12
  316. package/dist/output/text/vault.js +0 -16
  317. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  318. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  319. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  320. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  321. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  322. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  323. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  324. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -5,28 +5,28 @@ import { createHash } from "node:crypto";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import readline from "node:readline";
8
- import { parse as yamlParse, stringify as yamlStringify } from "yaml";
9
- import { parseAssetRef } from "../core/asset-ref";
10
- import { assembleAssetFromString } from "../core/asset-serialize";
11
- import { resolveStashDir, timestampForFilename } from "../core/common";
12
- import { getDefaultLlmConfig, loadConfig } from "../core/config";
13
- import { ConfigError } from "../core/errors";
14
- import { appendEvent } from "../core/events";
15
- import { parseFrontmatter } from "../core/frontmatter";
16
- import { writeContradictEdge } from "../core/memory-belief";
17
- import { parseEmbeddedJsonResponse } from "../core/parse";
18
- import { hasHotCaptureMode, hasSupersededStatus, MERGE_ABSOLUTE_FLOOR_CHARS, MERGE_SHRINK_RATIO_MIN, validateProposalFrontmatter, } from "../core/proposal-quality-validators";
19
- import { createProposal, isProposalSkipped, listProposals } from "../core/proposals";
20
- import { detectTruncatedDescription } from "../core/text-truncation";
8
+ import { parse as yamlParse } from "yaml";
9
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
10
+ import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
11
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
12
+ import { resolveStashDir, timestampForFilename } from "../../core/common.js";
13
+ import { getDefaultLlmConfig, loadConfig } from "../../core/config/config.js";
14
+ import { ConfigError } from "../../core/errors.js";
15
+ import { appendEvent } from "../../core/events.js";
16
+ import { parseEmbeddedJsonResponse } from "../../core/parse.js";
17
+ import { detectTruncatedDescription } from "../../core/text-truncation.js";
18
+ import { hasHotCaptureMode, hasSupersededStatus, MERGE_ABSOLUTE_FLOOR_CHARS, MERGE_SHRINK_RATIO_MIN, validateProposalFrontmatter, } from "../proposal/validators/proposal-quality-validators.js";
19
+ import { createProposal, isProposalSkipped, listProposals } from "../proposal/validators/proposals.js";
20
+ import { writeContradictEdge } from "./memory/memory-belief.js";
21
21
  // Re-export the moved helpers so existing test imports continue to resolve.
22
22
  export { hasSupersededStatus, validateProposalFrontmatter };
23
- import { warn } from "../core/warn";
24
- import { deleteAssetFromSource, resolveWriteTarget, writeAssetToSource } from "../core/write-source";
25
- import { closeDatabase, findEntryIdByRef, getAllEntries, getEntryById, getNeighborsByEntryId, openExistingDatabase, } from "../indexer/db";
26
- import { resolveImproveProcessRunnerFromProfile } from "../integrations/agent/runner";
27
- import { chatCompletion } from "../llm/client";
28
- import { cosineSimilarity, embedBatch } from "../llm/embedder";
29
- import { isLlmFeatureEnabled, tryLlmFeature } from "../llm/feature-gate";
23
+ import { warn } from "../../core/warn.js";
24
+ import { commitWriteTargetBoundary, deleteAssetFromSource, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
25
+ import { closeDatabase, findEntryIdByRef, getAllEntries, getEntryById, getNeighborsByEntryId, openExistingDatabase, } from "../../indexer/db/db.js";
26
+ import { resolveImproveProcessRunnerFromProfile, runnerIsLlm } from "../../integrations/agent/runner.js";
27
+ import { chatCompletion } from "../../llm/client.js";
28
+ import { cosineSimilarity, embedBatch } from "../../llm/embedder.js";
29
+ import { isLlmFeatureEnabled, tryLlmFeature } from "../../llm/feature-gate.js";
30
30
  // ── Prompts ─────────────────────────────────────────────────────────────────
31
31
  const CONSOLIDATE_SYSTEM_PROMPT = `You are the akm consolidate assistant analyzing memory assets.
32
32
 
@@ -704,7 +704,7 @@ function archiveMemory(filePath, stashDir, ref, reason, opIndex, supersededBy, w
704
704
  ...(supersededBy ? { superseded_by: supersededBy } : {}),
705
705
  superseded_reason: reason,
706
706
  };
707
- content = assembleAssetFromString(yamlStringify(newFm).trimEnd(), parsed.content);
707
+ content = assembleAssetFromString(serializeFrontmatter(newFm), parsed.content);
708
708
  }
709
709
  catch {
710
710
  if (warnings)
@@ -745,7 +745,7 @@ function archiveMemory(filePath, stashDir, ref, reason, opIndex, supersededBy, w
745
745
  function resolveConsolidateLlmConfig(config) {
746
746
  const consolidateProcess = config.profiles?.improve?.default?.processes?.consolidate;
747
747
  const runnerSpec = resolveImproveProcessRunnerFromProfile(consolidateProcess, config);
748
- if (runnerSpec && runnerSpec.kind === "llm") {
748
+ if (runnerSpec && runnerIsLlm(runnerSpec)) {
749
749
  return runnerSpec.connection;
750
750
  }
751
751
  // Non-LLM runner modes (agent/sdk) don't apply to consolidate's HTTP path;
@@ -877,11 +877,12 @@ export async function akmConsolidate(opts = {}) {
877
877
  // health rollup can aggregate without regex-parsing English warning
878
878
  // strings. See `/tmp/akm-health-investigations/tuning-reasons-investigation.md` §Q2.
879
879
  const skipReasons = [];
880
- // Tracks refs already emitted to skipReasons. A ref can only occupy one
881
- // accounting bucket; subsequent skip ops for the same ref are recorded as
882
- // warnings but must not push a second skipReasons entry (that would inflate
880
+ // Per-ref grouping of skipReasons entries. A ref occupies exactly one
881
+ // accounting bucket and therefore exactly one skipReasons array entry;
882
+ // subsequent skip ops for the same ref append to that entry's `skips[]`
883
+ // rather than pushing a second array entry (that would inflate
883
884
  // Σ(skipReasons) and break the invariant by +1 per duplicate).
884
- const skipReasonEmittedRefs = new Set();
885
+ const skipReasonByRef = new Map();
885
886
  const pushSkipReason = (op, ref, reason) => {
886
887
  // 2026-05-27 cross-chunk double-count fix: if `ref` already contributed
887
888
  // to judgedNoAction in its own chunk (a different chunk proposed an op
@@ -891,14 +892,17 @@ export async function akmConsolidate(opts = {}) {
891
892
  // Σ(skipReasons) + failedChunkMemories.
892
893
  if (judgedNoActionRefs.delete(ref))
893
894
  judgedNoAction--;
894
- if (skipReasonEmittedRefs.has(ref)) {
895
- // Already counted once. Record the extra skip for observability but
896
- // don't push to skipReasons that would break the accounting invariant.
897
- warnings.push(`Skip: ${ref} already in skipReasons (${reason} via ${op}); not re-counted.`);
895
+ const existing = skipReasonByRef.get(ref);
896
+ if (existing) {
897
+ // Already counted once for accounting. Append the extra skip to the
898
+ // ref's grouped entry for observability without adding a new array
899
+ // entry (which would break the accounting invariant).
900
+ existing.skips.push({ op, reason });
898
901
  return;
899
902
  }
900
- skipReasonEmittedRefs.add(ref);
901
- skipReasons.push({ op, ref, reason });
903
+ const entry = { ref, skips: [{ op, reason }] };
904
+ skipReasonByRef.set(ref, entry);
905
+ skipReasons.push(entry);
902
906
  };
903
907
  // judgedNoAction tracks memories the LLM saw inside a chunk but proposed
904
908
  // no op for. Computed per chunk as `chunk.length − unique(targetRefs in ops)`.
@@ -1560,7 +1564,7 @@ export async function akmConsolidate(opts = {}) {
1560
1564
  ...(parsedMemory.data ?? {}),
1561
1565
  description,
1562
1566
  };
1563
- const serializedMergedFm = yamlStringify(mergedBodyFm).trimEnd();
1567
+ const serializedMergedFm = serializeFrontmatter(mergedBodyFm);
1564
1568
  const proposalContent = assembleAssetFromString(serializedMergedFm, parsedMemory.content);
1565
1569
  // Pre-emit dedup against pending consolidate proposals from the
1566
1570
  // same improve run (slug-variant match). The cross-run content-hash
@@ -1634,6 +1638,14 @@ export async function akmConsolidate(opts = {}) {
1634
1638
  }
1635
1639
  }
1636
1640
  }
1641
+ // 0.9.0 (issue #507): batch-at-boundary commit. The merge/delete loop above
1642
+ // wrote one merged primary and deleted N secondaries to the resolved target
1643
+ // with NO per-asset commit. If the target is a writable git source and any
1644
+ // asset was mutated, commit the whole batch ONCE here (stages .akm/ +
1645
+ // siblings together). No-op for filesystem/primary-stash targets.
1646
+ if (merged > 0 || deleted > 0) {
1647
+ commitWriteTargetBoundary(target, `Consolidate: ${merged} merged, ${deleted} removed`);
1648
+ }
1637
1649
  cleanupJournal(stashDir, timestamp);
1638
1650
  // TTL cleanup: remove archive entries older than archiveRetentionDays (default 90).
1639
1651
  // C-5 / #391: emit an `archive_cleanup` event before each deletion so the
@@ -1828,7 +1840,7 @@ export function sanitizeMergedContent(raw) {
1828
1840
  // Recovery: if the strict yaml library fails, fall back to the lenient
1829
1841
  // hand-rolled parseFrontmatter parser, which tolerates common LLM YAML
1830
1842
  // quirks (unescaped special chars, bare scalars, etc.). If it recovers
1831
- // at least one key, proceed — yamlStringify below will re-serialize
1843
+ // at least one key, proceed — serializeFrontmatter below will re-serialize
1832
1844
  // cleanly. Only reject if both parsers fail to extract any data.
1833
1845
  let parsedFm;
1834
1846
  try {
@@ -1855,7 +1867,7 @@ export function sanitizeMergedContent(raw) {
1855
1867
  // Re-serialise via yaml.stringify to fix any quoting quirks.
1856
1868
  let serialized;
1857
1869
  try {
1858
- serialized = yamlStringify(fm).trimEnd();
1870
+ serialized = serializeFrontmatter(fm);
1859
1871
  }
1860
1872
  catch (e) {
1861
1873
  return { ok: false, reason: `YAML_STRINGIFY_FAILED: ${e instanceof Error ? e.message : String(e)}` };
@@ -2218,7 +2230,7 @@ async function generateMergedContent(config, primaryRef, primaryBody, secondaryR
2218
2230
  : secFm.data[key];
2219
2231
  }
2220
2232
  normalizeUpdatedField(repairedFmData);
2221
- const repairedYaml = yamlStringify(repairedFmData).trimEnd();
2233
+ const repairedYaml = serializeFrontmatter(repairedFmData);
2222
2234
  const bodyPart = mergedFm.content ?? "";
2223
2235
  return { content: `---\n${repairedYaml}\n---\n${bodyPart}` };
2224
2236
  }
@@ -1,9 +1,9 @@
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
- import { parseAssetRef } from "../core/asset-ref";
5
- import { assembleAsset } from "../core/asset-serialize";
6
- import { parseFrontmatter } from "../core/frontmatter";
4
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
5
+ import { assembleAsset } from "../../core/asset/asset-serialize.js";
6
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
7
7
  function hasNonEmptyList(value) {
8
8
  return Array.isArray(value) && value.some((item) => typeof item === "string" && item.trim().length > 0);
9
9
  }
@@ -52,22 +52,22 @@
52
52
  */
53
53
  import fs from "node:fs";
54
54
  import path from "node:path";
55
- import { parseAssetRef } from "../core/asset-ref";
56
- import { assembleAssetFromString } from "../core/asset-serialize";
57
- import { resolveStashDir, timestampForFilename } from "../core/common";
58
- import { getDefaultLlmConfig, loadConfig } from "../core/config";
59
- import { ConfigError, UsageError } from "../core/errors";
60
- import { appendEvent, readEvents } from "../core/events";
61
- import { parseFrontmatter } from "../core/frontmatter";
62
- import { lintLessonContent } from "../core/lesson-lint";
63
- import { stripMarkdownFences } from "../core/markdown";
64
- import { createProposal, isProposalSkipped, listProposals, } from "../core/proposals";
65
- import { warnVerbose } from "../core/warn";
66
- import { resolveAssetPath } from "../indexer/path-resolver";
67
- import { chatCompletion, parseEmbeddedJsonResponse } from "../llm/client";
68
- import { isLlmFeatureEnabled, tryLlmFeature } from "../llm/feature-gate";
69
- import { assessMemoryKnowledgePromotionCandidate, deriveKnowledgeRef } from "./distill-promotion-policy";
70
- import { akmSearch } from "./search";
55
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
56
+ import { assembleAssetFromString } from "../../core/asset/asset-serialize.js";
57
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
58
+ import { stripMarkdownFences } from "../../core/asset/markdown.js";
59
+ import { resolveStashDir, timestampForFilename } from "../../core/common.js";
60
+ import { getDefaultLlmConfig, loadConfig } from "../../core/config/config.js";
61
+ import { ConfigError, UsageError } from "../../core/errors.js";
62
+ import { appendEvent, readEvents } from "../../core/events.js";
63
+ import { lintLessonContent } from "../../core/lesson-lint.js";
64
+ import { warnVerbose } from "../../core/warn.js";
65
+ import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
66
+ import { chatCompletion, parseEmbeddedJsonResponse } from "../../llm/client.js";
67
+ import { isLlmFeatureEnabled, tryLlmFeature } from "../../llm/feature-gate.js";
68
+ import { createProposal, isProposalSkipped, listProposals, } from "../proposal/validators/proposals.js";
69
+ import { akmSearch } from "../read/search.js";
70
+ import { assessMemoryKnowledgePromotionCandidate, deriveKnowledgeRef } from "./distill-promotion-policy.js";
71
71
  /**
72
72
  * Asset-ref types that `akm distill` structurally refuses as inputs.
73
73
  *
@@ -112,13 +112,14 @@ export function deriveLessonRef(inputRef) {
112
112
  .replace(/^-|-$/g, "");
113
113
  return `lesson:${safe}-lesson`;
114
114
  }
115
+ import { repairTruncatedDescription } from "../../core/text-truncation.js";
115
116
  // ── Content quality validators ──────────────────────────────────────────────
116
117
  //
117
118
  // The actual implementations now live in `core/proposal-quality-validators.ts`
118
119
  // so the same checks run inside `runProposalValidators` on `proposal accept`.
119
120
  // We re-export the public-facing helpers here so existing imports
120
- // (`from "../src/commands/distill"`) continue to resolve.
121
- import { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse } from "../core/proposal-quality-validators";
121
+ // (`from "../../src/commands/distill"`) continue to resolve.
122
+ import { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse, } from "../proposal/validators/proposal-quality-validators.js";
122
123
  export { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse };
123
124
  // ── Prompt assembly ─────────────────────────────────────────────────────────
124
125
  const LESSON_SYSTEM_PROMPT = [
@@ -1121,6 +1122,26 @@ export async function akmDistill(options) {
1121
1122
  }
1122
1123
  }
1123
1124
  }
1125
+ // Post-generation truncation repair (#556): if the LLM sliced the
1126
+ // description mid-sentence, deterministically complete it from its own text
1127
+ // / the lesson body BEFORE the lint + quality validators run. No-op
1128
+ // (byte-identical) for already-complete descriptions, so this never alters
1129
+ // a valid proposal. Runs on the lesson path only (knowledge has no
1130
+ // description field gate here).
1131
+ if (effectiveProposalKind !== "knowledge") {
1132
+ const parsedRepair = parseFrontmatter(content);
1133
+ const fmRepair = (parsedRepair.data ?? {});
1134
+ const descRepairRaw = typeof fmRepair.description === "string" ? fmRepair.description : "";
1135
+ if (descRepairRaw) {
1136
+ const repaired = repairTruncatedDescription(descRepairRaw, parsedRepair.content);
1137
+ if (repaired !== descRepairRaw) {
1138
+ const repairedFmLines = Object.entries({ ...fmRepair, description: repaired })
1139
+ .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
1140
+ .join("\n");
1141
+ content = assembleAssetFromString(repairedFmLines, parsedRepair.content);
1142
+ }
1143
+ }
1144
+ }
1124
1145
  // Parse + lint the lesson before creating the proposal. The lint is the
1125
1146
  // canonical gate for required frontmatter (v1 spec §13). On failure we
1126
1147
  // surface a structured error and exit non-zero — but still emit
@@ -3,7 +3,7 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { writeFileAtomic } from "../core/common";
6
+ import { writeFileAtomic } from "../../core/common.js";
7
7
  export function writeEvalCase(stashDir, evalCase) {
8
8
  const evalDir = path.join(stashDir, ".akm", "eval-cases");
9
9
  fs.mkdirSync(evalDir, { recursive: true });
@@ -15,10 +15,10 @@
15
15
  * `--auto` runs multiple harnesses).
16
16
  */
17
17
  import { defineCommand } from "citty";
18
- import { output, runWithJsonErrors } from "../cli/shared";
19
- import { UsageError } from "../core/errors";
20
- import { getAvailableHarnesses } from "../integrations/session-logs";
21
- import { akmExtract } from "./extract";
18
+ import { output, runWithJsonErrors } from "../../cli/shared.js";
19
+ import { UsageError } from "../../core/errors.js";
20
+ import { getAvailableHarnesses } from "../../integrations/session-logs/index.js";
21
+ import { akmExtract } from "./extract.js";
22
22
  export const extractCommand = defineCommand({
23
23
  meta: {
24
24
  name: "extract",
@@ -14,7 +14,7 @@
14
14
  * happy path. `additionalProperties: false` means any hallucinated keys
15
15
  * the model emits get dropped before we parse.
16
16
  */
17
- import promptTemplate from "../assets/prompts/extract-session.md" with { type: "text" };
17
+ import promptTemplate from "../../assets/prompts/extract-session.md" with { type: "text" };
18
18
  /**
19
19
  * JSON Schema for the structured extract output. Passed to `chatCompletion`
20
20
  * when the configured LLM connection has `supportsJsonSchema: true`.
@@ -55,7 +55,7 @@ export const EXTRACT_JSON_SCHEMA = {
55
55
  type: "string",
56
56
  minLength: 20,
57
57
  maxLength: 400,
58
- description: "One-sentence summary of the candidate.",
58
+ description: "One-sentence summary of the candidate. Must be a complete sentence; do not end mid-clause.",
59
59
  },
60
60
  when_to_use: {
61
61
  type: "string",