akm-cli 0.8.0-rc2 → 0.8.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 (295) hide show
  1. package/{.github/CHANGELOG.md → CHANGELOG.md} +191 -3
  2. package/README.md +22 -6
  3. package/SECURITY.md +93 -0
  4. package/dist/cli/config-migrate.js +144 -0
  5. package/dist/cli/config-validate.js +39 -0
  6. package/dist/cli/confirm.js +73 -0
  7. package/dist/cli/parse-args.js +93 -3
  8. package/dist/cli/shared.js +129 -0
  9. package/dist/cli.js +2141 -1268
  10. package/dist/commands/add-cli.js +279 -0
  11. package/dist/commands/agent-dispatch.js +20 -12
  12. package/dist/commands/agent-support.js +11 -5
  13. package/dist/commands/completions.js +3 -0
  14. package/dist/commands/config-cli.js +129 -517
  15. package/dist/commands/consolidate.js +1533 -144
  16. package/dist/commands/curate.js +44 -3
  17. package/dist/commands/db-cli.js +23 -0
  18. package/dist/commands/distill-promotion-policy.js +5 -3
  19. package/dist/commands/distill.js +906 -100
  20. package/dist/commands/env.js +213 -0
  21. package/dist/commands/eval-cases.js +3 -0
  22. package/dist/commands/events.js +3 -0
  23. package/dist/commands/extract-cli.js +127 -0
  24. package/dist/commands/extract-prompt.js +204 -0
  25. package/dist/commands/extract.js +477 -0
  26. package/dist/commands/feedback-cli.js +331 -0
  27. package/dist/commands/graph.js +260 -5
  28. package/dist/commands/health.js +977 -51
  29. package/dist/commands/help/help-accept.md +6 -3
  30. package/dist/commands/help/help-improve.md +36 -8
  31. package/dist/commands/help/help-proposals.md +7 -4
  32. package/dist/commands/help/help-reject.md +5 -2
  33. package/dist/commands/history.js +51 -16
  34. package/dist/commands/improve-auto-accept.js +97 -0
  35. package/dist/commands/improve-cli.js +236 -0
  36. package/dist/commands/improve-profiles.js +184 -0
  37. package/dist/commands/improve-result-file.js +167 -0
  38. package/dist/commands/improve.js +1725 -332
  39. package/dist/commands/info.js +3 -0
  40. package/dist/commands/init.js +49 -1
  41. package/dist/commands/installed-stashes.js +6 -23
  42. package/dist/commands/knowledge.js +3 -0
  43. package/dist/commands/lint/agent-linter.js +3 -0
  44. package/dist/commands/lint/base-linter.js +199 -5
  45. package/dist/commands/lint/command-linter.js +3 -0
  46. package/dist/commands/lint/default-linter.js +3 -0
  47. package/dist/commands/lint/env-key-rules.js +154 -0
  48. package/dist/commands/lint/index.js +92 -3
  49. package/dist/commands/lint/knowledge-linter.js +3 -0
  50. package/dist/commands/lint/markdown-insertion.js +343 -0
  51. package/dist/commands/lint/memory-linter.js +3 -0
  52. package/dist/commands/lint/registry.js +3 -0
  53. package/dist/commands/lint/skill-linter.js +3 -0
  54. package/dist/commands/lint/task-linter.js +15 -12
  55. package/dist/commands/lint/types.js +3 -0
  56. package/dist/commands/lint/workflow-linter.js +3 -0
  57. package/dist/commands/lint.js +3 -0
  58. package/dist/commands/migration-help.js +5 -2
  59. package/dist/commands/proposal-drain-policies.js +128 -0
  60. package/dist/commands/proposal-drain.js +477 -0
  61. package/dist/commands/proposal.js +60 -6
  62. package/dist/commands/propose.js +24 -19
  63. package/dist/commands/reflect.js +1004 -94
  64. package/dist/commands/registry-cli.js +150 -0
  65. package/dist/commands/registry-search.js +3 -0
  66. package/dist/commands/remember-cli.js +257 -0
  67. package/dist/commands/remember.js +15 -6
  68. package/dist/commands/schema-repair.js +88 -15
  69. package/dist/commands/search.js +99 -14
  70. package/dist/commands/secret.js +173 -0
  71. package/dist/commands/self-update.js +3 -0
  72. package/dist/commands/show.js +32 -13
  73. package/dist/commands/source-add.js +7 -35
  74. package/dist/commands/source-clone.js +3 -0
  75. package/dist/commands/source-manage.js +3 -0
  76. package/dist/commands/tasks.js +161 -95
  77. package/dist/commands/url-checker.js +3 -0
  78. package/dist/core/action-contributors.js +3 -0
  79. package/dist/core/asset-ref.js +13 -2
  80. package/dist/core/asset-registry.js +9 -2
  81. package/dist/core/asset-serialize.js +88 -0
  82. package/dist/core/asset-spec.js +61 -5
  83. package/dist/core/common.js +93 -5
  84. package/dist/core/concurrent.js +3 -0
  85. package/dist/core/config-io.js +347 -0
  86. package/dist/core/config-migration.js +622 -0
  87. package/dist/core/config-schema.js +558 -0
  88. package/dist/core/config-sources.js +108 -0
  89. package/dist/core/config-types.js +4 -0
  90. package/dist/core/config-walker.js +337 -0
  91. package/dist/core/config.js +366 -1077
  92. package/dist/core/errors.js +42 -20
  93. package/dist/core/events.js +31 -25
  94. package/dist/core/file-lock.js +104 -0
  95. package/dist/core/frontmatter.js +75 -10
  96. package/dist/core/lesson-lint.js +3 -0
  97. package/dist/core/markdown.js +3 -0
  98. package/dist/core/memory-belief.js +62 -0
  99. package/dist/core/memory-contradiction-detect.js +274 -0
  100. package/dist/core/memory-improve.js +142 -14
  101. package/dist/core/parse.js +3 -0
  102. package/dist/core/paths.js +218 -50
  103. package/dist/core/proposal-quality-validators.js +380 -0
  104. package/dist/core/proposal-validators.js +11 -3
  105. package/dist/core/proposals.js +464 -5
  106. package/dist/core/state-db.js +349 -56
  107. package/dist/core/text-truncation.js +107 -0
  108. package/dist/core/time.js +3 -0
  109. package/dist/core/tty.js +59 -0
  110. package/dist/core/warn.js +7 -2
  111. package/dist/core/write-source.js +12 -0
  112. package/dist/indexer/db-backup.js +391 -0
  113. package/dist/indexer/db-search.js +136 -28
  114. package/dist/indexer/db.js +661 -166
  115. package/dist/indexer/ensure-index.js +3 -0
  116. package/dist/indexer/file-context.js +3 -0
  117. package/dist/indexer/graph-boost.js +162 -40
  118. package/dist/indexer/graph-db.js +241 -51
  119. package/dist/indexer/graph-dedup.js +3 -7
  120. package/dist/indexer/graph-extraction.js +242 -149
  121. package/dist/indexer/index-context.js +3 -9
  122. package/dist/indexer/indexer.js +84 -14
  123. package/dist/indexer/llm-cache.js +24 -19
  124. package/dist/indexer/manifest.js +3 -0
  125. package/dist/indexer/matchers.js +184 -11
  126. package/dist/indexer/memory-inference.js +94 -50
  127. package/dist/indexer/metadata-contributors.js +3 -0
  128. package/dist/indexer/metadata.js +110 -50
  129. package/dist/indexer/path-resolver.js +3 -0
  130. package/dist/indexer/project-context.js +192 -0
  131. package/dist/indexer/ranking-contributors.js +134 -7
  132. package/dist/indexer/ranking.js +8 -1
  133. package/dist/indexer/search-fields.js +5 -9
  134. package/dist/indexer/search-hit-enrichers.js +91 -2
  135. package/dist/indexer/search-source.js +20 -1
  136. package/dist/indexer/semantic-status.js +4 -1
  137. package/dist/indexer/staleness-detect.js +447 -0
  138. package/dist/indexer/usage-events.js +12 -9
  139. package/dist/indexer/walker.js +3 -0
  140. package/dist/integrations/agent/builders.js +135 -0
  141. package/dist/integrations/agent/config.js +121 -401
  142. package/dist/integrations/agent/detect.js +3 -0
  143. package/dist/integrations/agent/index.js +6 -14
  144. package/dist/integrations/agent/model-aliases.js +55 -0
  145. package/dist/integrations/agent/profiles.js +3 -0
  146. package/dist/integrations/agent/prompts.js +137 -8
  147. package/dist/integrations/agent/runner.js +208 -0
  148. package/dist/integrations/agent/sdk-runner.js +8 -2
  149. package/dist/integrations/agent/spawn.js +54 -14
  150. package/dist/integrations/github.js +3 -0
  151. package/dist/integrations/lockfile.js +22 -51
  152. package/dist/integrations/session-logs/index.js +4 -0
  153. package/dist/integrations/session-logs/inline-refs.js +35 -0
  154. package/dist/integrations/session-logs/pre-filter.js +152 -0
  155. package/dist/integrations/session-logs/providers/claude-code.js +226 -0
  156. package/dist/integrations/session-logs/providers/opencode.js +231 -25
  157. package/dist/integrations/session-logs/types.js +3 -0
  158. package/dist/llm/call-ai.js +14 -26
  159. package/dist/llm/client.js +16 -2
  160. package/dist/llm/embedder.js +20 -29
  161. package/dist/llm/embedders/cache.js +3 -7
  162. package/dist/llm/embedders/local.js +42 -1
  163. package/dist/llm/embedders/remote.js +20 -8
  164. package/dist/llm/embedders/types.js +3 -7
  165. package/dist/llm/feature-gate.js +92 -56
  166. package/dist/llm/graph-extract.js +401 -30
  167. package/dist/llm/index-passes.js +44 -29
  168. package/dist/llm/memory-infer.js +30 -2
  169. package/dist/llm/metadata-enhance.js +3 -7
  170. package/dist/llm/prompts/extract-session.md +80 -0
  171. package/dist/llm/prompts/graph-extract-user-prompt.md +24 -1
  172. package/dist/output/cli-hints-full.md +60 -32
  173. package/dist/output/cli-hints-short.md +10 -7
  174. package/dist/output/cli-hints.js +5 -2
  175. package/dist/output/context.js +60 -8
  176. package/dist/output/renderers.js +170 -194
  177. package/dist/output/shapes/curate.js +56 -0
  178. package/dist/output/shapes/distill.js +10 -0
  179. package/dist/output/shapes/env-list.js +19 -0
  180. package/dist/output/shapes/events.js +11 -0
  181. package/dist/output/shapes/helpers.js +424 -0
  182. package/dist/output/shapes/history.js +7 -0
  183. package/dist/output/shapes/passthrough.js +105 -0
  184. package/dist/output/shapes/proposal-accept.js +7 -0
  185. package/dist/output/shapes/proposal-diff.js +7 -0
  186. package/dist/output/shapes/proposal-list.js +7 -0
  187. package/dist/output/shapes/proposal-producer.js +11 -0
  188. package/dist/output/shapes/proposal-reject.js +7 -0
  189. package/dist/output/shapes/proposal-show.js +7 -0
  190. package/dist/output/shapes/registry-search.js +6 -0
  191. package/dist/output/shapes/registry.js +30 -0
  192. package/dist/output/shapes/search.js +6 -0
  193. package/dist/output/shapes/secret-list.js +19 -0
  194. package/dist/output/shapes/show.js +6 -0
  195. package/dist/output/shapes/vault-list.js +19 -0
  196. package/dist/output/shapes.js +51 -549
  197. package/dist/output/text/add.js +6 -0
  198. package/dist/output/text/clone.js +6 -0
  199. package/dist/output/text/config.js +6 -0
  200. package/dist/output/text/curate.js +6 -0
  201. package/dist/output/text/distill.js +7 -0
  202. package/dist/output/text/enable-disable.js +7 -0
  203. package/dist/output/text/events.js +10 -0
  204. package/dist/output/text/feedback.js +6 -0
  205. package/dist/output/text/helpers.js +1059 -0
  206. package/dist/output/text/history.js +7 -0
  207. package/dist/output/text/import.js +6 -0
  208. package/dist/output/text/index.js +6 -0
  209. package/dist/output/text/info.js +6 -0
  210. package/dist/output/text/init.js +6 -0
  211. package/dist/output/text/list.js +6 -0
  212. package/dist/output/text/proposal-producer.js +8 -0
  213. package/dist/output/text/proposal.js +12 -0
  214. package/dist/output/text/registry-commands.js +11 -0
  215. package/dist/output/text/registry.js +30 -0
  216. package/dist/output/text/remember.js +6 -0
  217. package/dist/output/text/remove.js +6 -0
  218. package/dist/output/text/save.js +6 -0
  219. package/dist/output/text/search.js +6 -0
  220. package/dist/output/text/show.js +6 -0
  221. package/dist/output/text/update.js +6 -0
  222. package/dist/output/text/upgrade.js +6 -0
  223. package/dist/output/text/vault.js +16 -0
  224. package/dist/output/text/wiki.js +15 -0
  225. package/dist/output/text/workflow.js +14 -0
  226. package/dist/output/text.js +44 -1329
  227. package/dist/registry/build-index.js +3 -0
  228. package/dist/registry/create-provider-registry.js +3 -0
  229. package/dist/registry/factory.js +4 -1
  230. package/dist/registry/origin-resolve.js +3 -0
  231. package/dist/registry/providers/index.js +3 -0
  232. package/dist/registry/providers/skills-sh.js +11 -2
  233. package/dist/registry/providers/static-index.js +10 -1
  234. package/dist/registry/providers/types.js +3 -24
  235. package/dist/registry/resolve.js +11 -16
  236. package/dist/registry/types.js +3 -0
  237. package/dist/scripts/migrate-storage.js +17767 -0
  238. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9031 -0
  239. package/dist/scripts/migrations/v16-to-v17.js +141 -0
  240. package/dist/setup/detect.js +3 -0
  241. package/dist/setup/ripgrep-install.js +3 -0
  242. package/dist/setup/ripgrep-resolve.js +3 -0
  243. package/dist/setup/setup.js +306 -67
  244. package/dist/setup/steps.js +3 -15
  245. package/dist/sources/include.js +3 -0
  246. package/dist/sources/provider-factory.js +3 -11
  247. package/dist/sources/provider.js +3 -20
  248. package/dist/sources/providers/filesystem.js +19 -23
  249. package/dist/sources/providers/git.js +171 -21
  250. package/dist/sources/providers/index.js +3 -0
  251. package/dist/sources/providers/install-types.js +3 -13
  252. package/dist/sources/providers/npm.js +3 -4
  253. package/dist/sources/providers/provider-utils.js +3 -0
  254. package/dist/sources/providers/sync-from-ref.js +3 -11
  255. package/dist/sources/providers/tar-utils.js +3 -0
  256. package/dist/sources/providers/website.js +18 -22
  257. package/dist/sources/resolve.js +3 -0
  258. package/dist/sources/types.js +3 -0
  259. package/dist/sources/website-ingest.js +3 -0
  260. package/dist/tasks/backends/cron.js +3 -0
  261. package/dist/tasks/backends/exec-utils.js +3 -0
  262. package/dist/tasks/backends/index.js +3 -11
  263. package/dist/tasks/backends/launchd.js +3 -0
  264. package/dist/tasks/backends/schtasks.js +3 -0
  265. package/dist/tasks/parser.js +51 -38
  266. package/dist/tasks/resolveAkmBin.js +3 -0
  267. package/dist/tasks/runner.js +35 -9
  268. package/dist/tasks/schedule.js +20 -1
  269. package/dist/tasks/schema.js +5 -3
  270. package/dist/tasks/validator.js +6 -3
  271. package/dist/version.js +3 -0
  272. package/dist/wiki/wiki-templates.js +3 -0
  273. package/dist/wiki/wiki.js +3 -0
  274. package/dist/workflows/authoring.js +3 -0
  275. package/dist/workflows/cli.js +3 -0
  276. package/dist/workflows/db.js +140 -10
  277. package/dist/workflows/document-cache.js +3 -10
  278. package/dist/workflows/parser.js +3 -0
  279. package/dist/workflows/renderer.js +3 -0
  280. package/dist/workflows/runs.js +18 -1
  281. package/dist/workflows/schema.js +3 -0
  282. package/dist/workflows/scope-key.js +3 -0
  283. package/dist/workflows/validator.js +5 -9
  284. package/docs/README.md +7 -2
  285. package/docs/data-and-telemetry.md +225 -0
  286. package/docs/migration/release-notes/0.7.5.md +2 -2
  287. package/docs/migration/release-notes/0.8.0.md +57 -5
  288. package/docs/migration/v0.7-to-v0.8.md +1378 -0
  289. package/package.json +28 -11
  290. package/.github/LICENSE +0 -374
  291. package/dist/commands/install-audit.js +0 -385
  292. package/dist/commands/vault.js +0 -310
  293. package/dist/indexer/match-contributors.js +0 -141
  294. package/dist/integrations/agent/pipeline.js +0 -39
  295. package/dist/integrations/agent/runners.js +0 -31
@@ -0,0 +1,184 @@
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
+ import { parseAssetRef } from "../core/asset-ref";
5
+ import { warn } from "../core/warn";
6
+ /** Profile name used as the final fallback when nothing else resolves. */
7
+ const FALLBACK_PROFILE_NAME = "default";
8
+ // Built-in default allowed types per process
9
+ export const DEFAULT_ALLOWED_TYPES = {
10
+ reflect: ["agent", "command", "knowledge", "lesson", "memory", "skill", "wiki", "workflow"],
11
+ distill: ["memory"],
12
+ consolidate: ["memory"],
13
+ };
14
+ const BUILTIN_PROFILES = {
15
+ default: {
16
+ description: "Standard improve pass — all sub-processes, markdown asset types.",
17
+ processes: {
18
+ reflect: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.reflect },
19
+ distill: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.distill },
20
+ consolidate: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.consolidate },
21
+ memoryInference: { enabled: true },
22
+ graphExtraction: { enabled: true },
23
+ // validation: deliberately undefined — third-tier classifier is opt-in.
24
+ triage: { enabled: false, applyMode: "queue", policy: "personal-stash" },
25
+ },
26
+ sync: { enabled: true, push: true },
27
+ },
28
+ quick: {
29
+ description: "Reflect-only pass — no distill, consolidate, memoryInference, or graphExtraction.",
30
+ processes: {
31
+ reflect: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.reflect },
32
+ distill: { enabled: false },
33
+ consolidate: { enabled: false },
34
+ memoryInference: { enabled: false },
35
+ graphExtraction: { enabled: false },
36
+ triage: { enabled: false },
37
+ },
38
+ // Lightweight passes opt out of end-of-run sync: a reflect-only `quick`
39
+ // run should not auto-commit/push the git-backed stash to its remote.
40
+ // (The auto-sync gate in improve.ts treats an absent sync block as
41
+ // ENABLED + push, so we set this explicitly to avoid a surprise push.)
42
+ sync: { enabled: false },
43
+ },
44
+ thorough: {
45
+ // Reserved for future divergence; for now behaviorally identical to
46
+ // `default`. Documented here so callers picking `--profile thorough` do
47
+ // not expect a different code path until we wire stricter limits in.
48
+ description: "All sub-processes enabled (currently identical to default; reserved for future divergence).",
49
+ processes: {
50
+ reflect: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.reflect },
51
+ distill: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.distill },
52
+ consolidate: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.consolidate },
53
+ memoryInference: { enabled: true },
54
+ graphExtraction: { enabled: true },
55
+ triage: { enabled: true, applyMode: "queue" },
56
+ },
57
+ sync: { enabled: true, push: true },
58
+ },
59
+ "memory-focus": {
60
+ description: "Memory and lesson improvement only — no distill or consolidate.",
61
+ processes: {
62
+ reflect: { enabled: true, allowedTypes: ["memory", "lesson"] },
63
+ distill: { enabled: false },
64
+ consolidate: { enabled: false },
65
+ memoryInference: { enabled: true },
66
+ graphExtraction: { enabled: false },
67
+ triage: { enabled: false },
68
+ },
69
+ // Limited pass opts out of end-of-run sync for the same reason as `quick`:
70
+ // a memory/lesson-only run should not auto-commit/push the stash. Explicit
71
+ // here because improve.ts treats an absent sync block as ENABLED + push.
72
+ sync: { enabled: false },
73
+ },
74
+ };
75
+ /**
76
+ * Default enabled-state for known improve processes when neither the user
77
+ * profile nor the built-in default profile specifies an override.
78
+ *
79
+ * These mirror the legacy `LlmFeatureFlags` defaults so callers that bypass
80
+ * the profile system (rare — most run through `resolveImproveProfile`) get
81
+ * the same answer.
82
+ */
83
+ const IMPROVE_PROCESS_DEFAULTS = {
84
+ reflect: true,
85
+ distill: true,
86
+ consolidate: true,
87
+ memoryInference: true,
88
+ graphExtraction: true,
89
+ validation: false,
90
+ // session-extraction reads native session files from claude-code / opencode
91
+ // and queues durable-insight proposals. Default on — opt out via
92
+ // profiles.improve.default.processes.extract.enabled: false.
93
+ extract: true,
94
+ // proposal-queue triage drains the standing backlog. Opt-in (default off),
95
+ // like `validation` — needs an explicit `enabled: true`.
96
+ triage: false,
97
+ };
98
+ /**
99
+ * Compute the effective enabled-state for a named improve process.
100
+ *
101
+ * Resolution order: explicit `profile.processes.<name>.enabled` (boolean) →
102
+ * the built-in {@link IMPROVE_PROCESS_DEFAULTS} fallback → `false`.
103
+ */
104
+ export function resolveProcessEnabled(processName, profile) {
105
+ const processes = profile.processes;
106
+ const entry = processes?.[processName];
107
+ if (entry && typeof entry.enabled === "boolean")
108
+ return entry.enabled;
109
+ return IMPROVE_PROCESS_DEFAULTS[processName] ?? false;
110
+ }
111
+ function deepMerge(base, override) {
112
+ if (typeof base !== "object" || base === null)
113
+ return override ?? base;
114
+ const result = { ...base };
115
+ for (const key of Object.keys(override)) {
116
+ const ov = override[key];
117
+ // Treat `null` the same as `undefined` so user overrides never wipe a
118
+ // built-in field with `null`. The on-disk parser already strips nulls,
119
+ // but the programmatic API exposes this path and callers occasionally
120
+ // pass JSON-shaped objects with explicit nulls.
121
+ if (ov !== undefined && ov !== null) {
122
+ const bv = base[key];
123
+ if (typeof bv === "object" && bv !== null && typeof ov === "object" && ov !== null && !Array.isArray(bv)) {
124
+ result[key] = deepMerge(bv, ov);
125
+ }
126
+ else {
127
+ result[key] = ov;
128
+ }
129
+ }
130
+ }
131
+ return result;
132
+ }
133
+ export function resolveImproveProfile(name, config) {
134
+ const requestedName = name ??
135
+ (typeof config.defaults?.improve === "string" ? config.defaults.improve : undefined) ??
136
+ FALLBACK_PROFILE_NAME;
137
+ const hasBuiltin = requestedName in BUILTIN_PROFILES;
138
+ const hasUserDefined = !!config.profiles?.improve?.[requestedName];
139
+ let effectiveName = requestedName;
140
+ if (!hasBuiltin && !hasUserDefined && requestedName !== FALLBACK_PROFILE_NAME) {
141
+ warn(`[akm] Improve profile "${requestedName}" not found in built-ins or config. ` +
142
+ `Falling back to "${FALLBACK_PROFILE_NAME}".`);
143
+ effectiveName = FALLBACK_PROFILE_NAME;
144
+ }
145
+ const builtin = BUILTIN_PROFILES[effectiveName] ?? BUILTIN_PROFILES[FALLBACK_PROFILE_NAME];
146
+ const userOverride = config.profiles?.improve?.[effectiveName] ?? {};
147
+ return deepMerge(builtin, userOverride);
148
+ }
149
+ export function shouldSkipRef(ref, processName, profile) {
150
+ const cfg = profile.processes?.[processName];
151
+ // Check if the process itself is disabled
152
+ if (cfg?.enabled === false)
153
+ return { skip: true, reason: "process-disabled" };
154
+ const parsed = parseAssetRef(ref);
155
+ const allowed = cfg?.allowedTypes ?? DEFAULT_ALLOWED_TYPES[processName];
156
+ if (!allowed.includes(parsed.type))
157
+ return { skip: true, reason: "type-filter" };
158
+ // Hardcoded: wiki raw directories are never processed by any improve process.
159
+ if (parsed.type === "wiki" && parsed.name.split("/")[1] === "raw") {
160
+ return { skip: true, reason: "raw-wiki" };
161
+ }
162
+ return { skip: false, reason: "" };
163
+ }
164
+ /**
165
+ * Planner-level pre-filter: return `true` when every per-ref improve pass that
166
+ * participates in the in-loop dispatch (today: `reflect` and `distill`) would
167
+ * refuse this ref under the active profile. Such refs cannot produce any work
168
+ * downstream — they only generate synthetic skip actions and inflate
169
+ * `plannedRefs` by a constant factor per cron run.
170
+ *
171
+ * Companion to `shouldSkipRef`. The 2026-05-27 planner/profile/metrics deep
172
+ * analysis (`/tmp/akm-health-investigations/planner-profile-metrics-deep-analysis.md`)
173
+ * documents the 99.07% synthetic-skip emission rate this pre-filter eliminates.
174
+ *
175
+ * NOTE: passes that operate on their own candidate set (consolidate,
176
+ * memoryInference, graphExtraction) are deliberately excluded — they do not
177
+ * iterate `plannedRefs` per-ref, so a ref being profile-incompatible at the
178
+ * reflect+distill layer says nothing about their work.
179
+ */
180
+ export function isProfileFilteredForAllPasses(ref, profile) {
181
+ const reflectSkip = shouldSkipRef(ref, "reflect", profile);
182
+ const distillSkip = shouldSkipRef(ref, "distill", profile);
183
+ return reflectSkip.skip && distillSkip.skip;
184
+ }
@@ -0,0 +1,167 @@
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
+ * Helpers for persisting the `akm improve` result envelope.
6
+ *
7
+ * v0.8.0 behavioural default change:
8
+ * - Default: the full result is recorded as a single row in the
9
+ * `improve_runs` table of `state.db` (migration 003). Stdout is empty.
10
+ * The existing `[improve] ...` progress log lines on stderr remain the
11
+ * canonical console UX.
12
+ * - `--json-to-stdout` restores the prior behaviour: full JSON to stdout,
13
+ * nothing written to state.db.
14
+ *
15
+ * v0.8.0 storage change (this module): the previous on-disk artifact at
16
+ * `<stash>/.akm/runs/<runId>/improve-result.json` is no longer written. The
17
+ * canonical record now lives in `improve_runs` (see
18
+ * `src/core/state-db.ts`). Pre-existing files from older runs are not
19
+ * deleted by this change — they become historical artifacts. Zero current
20
+ * code paths read them, so no consumers needed to update.
21
+ *
22
+ * Run-id format: ISO-8601 timestamp (colons/dots replaced by `-`) plus an
23
+ * 8-char hex random suffix. There is no existing canonical run-id helper for
24
+ * persistent per-command artefacts on disk — the `workflow_runs` table uses
25
+ * `randomUUID()` but is database-scoped, and `consolidate-journal.json` is a
26
+ * single-slot artefact. We mint a fresh timestamped id for each improve run.
27
+ */
28
+ import crypto from "node:crypto";
29
+ import path from "node:path";
30
+ import { openStateDatabase, recordImproveRun } from "../core/state-db";
31
+ /**
32
+ * Build a stable run-id for a single improve invocation.
33
+ *
34
+ * Shape: `<iso-8601-utc-with-dashes>-<8 hex chars>`, e.g.
35
+ * `2026-05-19T17-30-22-123Z-a1b2c3d4`.
36
+ *
37
+ * The hex suffix protects against same-millisecond collisions when multiple
38
+ * runs happen back-to-back in tests or scripts.
39
+ */
40
+ export function buildImproveRunId(now = new Date()) {
41
+ const iso = now.toISOString().replace(/[:.]/g, "-");
42
+ const rand = crypto.randomBytes(4).toString("hex");
43
+ return `${iso}-${rand}`;
44
+ }
45
+ /**
46
+ * Return a stable, human-recognisable reference for a given improve run.
47
+ *
48
+ * Historical compatibility shim: callers used to receive a stash-relative
49
+ * file path like `.akm/runs/<runId>/improve-result.json`. With the state.db
50
+ * migration, no such file exists, but several callers still log "wrote to
51
+ * <path>" style messages. Returning a `state.db//improve_runs/<runId>`
52
+ * locator preserves the "the result is at <thing>" signature so existing
53
+ * log lines and error messages continue to make sense without rewriting
54
+ * every call site.
55
+ */
56
+ export function relativeImproveResultPath(runId) {
57
+ return path.join("state.db", "improve_runs", runId);
58
+ }
59
+ /**
60
+ * Persist the full improve result into the `improve_runs` table of state.db.
61
+ *
62
+ * Backwards-compatible signature: the function name, argument list, and
63
+ * return type all match the pre-0.8.0 file-writing helper. The returned
64
+ * string is the `state.db//improve_runs/<runId>` locator (see
65
+ * {@link relativeImproveResultPath}), which is intended for log messages
66
+ * only — no caller should treat it as a filesystem path. Zero current
67
+ * readers existed for the previous file path, so this is a pure storage
68
+ * swap.
69
+ *
70
+ * The state.db row carries the scope and dry-run flag from `result.scope`
71
+ * and `result.dryRun`, plus the full result JSON for full fidelity. The
72
+ * dry-run column is indexed so productivity audits can filter cleanly
73
+ * (closes the dry-run/real-run artifact-trap recorded in MEMORY.md
74
+ * `feedback_akm_dryrun_artifact_trap`).
75
+ */
76
+ export function writeImproveResultFile(stashDir, runId, result) {
77
+ const db = openStateDatabase();
78
+ try {
79
+ const startedAt = new Date().toISOString();
80
+ recordImproveRun(db, {
81
+ id: runId,
82
+ startedAt,
83
+ completedAt: startedAt,
84
+ stashDir,
85
+ dryRun: Boolean(result.dryRun),
86
+ profile: null,
87
+ scopeMode: result.scope?.mode ?? "all",
88
+ scopeValue: result.scope?.value ?? null,
89
+ guidance: result.guidance ?? null,
90
+ ok: Boolean(result.ok),
91
+ result,
92
+ });
93
+ }
94
+ finally {
95
+ try {
96
+ db.close();
97
+ }
98
+ catch {
99
+ // best-effort
100
+ }
101
+ }
102
+ return relativeImproveResultPath(runId);
103
+ }
104
+ /**
105
+ * Persist an improve_runs row for a run that did NOT complete normally.
106
+ * 2026-05-26 incident: the cron's `timeout_ms: 1800000` SIGTERM'd an
107
+ * akm-improve invocation at 30:00 with 54 actionable refs in-flight. No
108
+ * `improve_runs` row was written because the writer only fired at successful
109
+ * end-of-run, so the run vanished from `akm health --detail per-run` even
110
+ * though it had consumed 30 min of LLM time and produced 29 ref-level
111
+ * proposals. This helper closes that gap: signal handlers and the CLI
112
+ * try/catch wrapper call it on the abnormal-exit paths so the row exists
113
+ * with `ok: false` and `metadata.terminated.reason` set.
114
+ *
115
+ * The persisted result envelope is minimal — we don't try to reconstruct
116
+ * the in-flight `actions[]` because that state lives inside `akmImprove`
117
+ * and is gone by the time the signal handler runs. The row captures
118
+ * enough to know: a run started, was scoped to X, did NOT complete, and
119
+ * why.
120
+ */
121
+ export function recordTerminatedImproveRun(stashDir, runId, startedAt, reason, ctx) {
122
+ const completedAt = new Date().toISOString();
123
+ const minimalResult = {
124
+ schemaVersion: 1,
125
+ ok: false,
126
+ scope: { mode: ctx?.scopeMode ?? "all", ...(ctx?.scopeValue ? { value: ctx.scopeValue } : {}) },
127
+ dryRun: Boolean(ctx?.dryRun),
128
+ actions: [],
129
+ plannedRefs: [],
130
+ terminated: {
131
+ reason,
132
+ at: completedAt,
133
+ ...(ctx?.errorMessage ? { errorMessage: ctx.errorMessage } : {}),
134
+ },
135
+ };
136
+ const db = openStateDatabase();
137
+ try {
138
+ recordImproveRun(db, {
139
+ id: runId,
140
+ startedAt,
141
+ completedAt,
142
+ stashDir,
143
+ dryRun: Boolean(ctx?.dryRun),
144
+ profile: ctx?.profile ?? null,
145
+ scopeMode: ctx?.scopeMode ?? "all",
146
+ scopeValue: ctx?.scopeValue ?? null,
147
+ guidance: null,
148
+ ok: false,
149
+ result: minimalResult,
150
+ metadata: {
151
+ terminated: {
152
+ reason,
153
+ at: completedAt,
154
+ ...(ctx?.errorMessage ? { errorMessage: ctx.errorMessage } : {}),
155
+ },
156
+ },
157
+ });
158
+ }
159
+ finally {
160
+ try {
161
+ db.close();
162
+ }
163
+ catch {
164
+ // best-effort
165
+ }
166
+ }
167
+ }