akm-cli 0.9.17-alpha.3 → 0.9.17-alpha.5

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 (346) hide show
  1. package/CHANGELOG.md +760 -0
  2. package/dist/akm +94 -196
  3. package/dist/cli/shared.js +6 -2
  4. package/dist/cli.js +22 -9
  5. package/dist/commands/agent/agent-dispatch.js +1 -1
  6. package/dist/commands/command/command-execution.js +24 -62
  7. package/dist/commands/feedback-cli.js +0 -1
  8. package/dist/commands/health/accept-rate.js +2 -2
  9. package/dist/commands/health/checks.js +30 -75
  10. package/dist/commands/health/config-skew.js +38 -0
  11. package/dist/commands/health/egress.js +54 -0
  12. package/dist/commands/health/html-report.js +0 -38
  13. package/dist/commands/health/improve-metrics.js +123 -562
  14. package/dist/commands/health/plugin-staleness.js +53 -3
  15. package/dist/commands/health/renderers.js +12 -4
  16. package/dist/commands/health/report-view-model.js +11 -106
  17. package/dist/commands/health/types-improve.js +4 -19
  18. package/dist/commands/health/windows.js +64 -73
  19. package/dist/commands/health.js +122 -143
  20. package/dist/commands/improve/consolidate/chunking.js +25 -100
  21. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  22. package/dist/commands/improve/consolidate.js +538 -1075
  23. package/dist/commands/improve/content-hash.js +16 -24
  24. package/dist/commands/improve/distill/content-repair.js +18 -100
  25. package/dist/commands/improve/distill-guards.js +20 -81
  26. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  27. package/dist/commands/improve/distill.js +608 -1075
  28. package/dist/commands/improve/eligibility.js +126 -400
  29. package/dist/commands/improve/execution.js +3 -5
  30. package/dist/commands/improve/extract.js +487 -1046
  31. package/dist/commands/improve/feedback-valence.js +0 -25
  32. package/dist/commands/improve/improve-cli.js +29 -166
  33. package/dist/commands/improve/improve-result-file.js +10 -66
  34. package/dist/commands/improve/improve-strategies.js +12 -7
  35. package/dist/commands/improve/improve-usage-report.js +18 -64
  36. package/dist/commands/improve/improve.js +443 -1063
  37. package/dist/commands/improve/ledger.js +114 -0
  38. package/dist/commands/improve/locks.js +2 -8
  39. package/dist/commands/improve/loop-stages.js +459 -1172
  40. package/dist/commands/improve/memory/derived-ref.js +12 -77
  41. package/dist/commands/improve/memory/memory-belief.js +14 -118
  42. package/dist/commands/improve/memory/memory-improve.js +4 -3
  43. package/dist/commands/improve/outcome-loop.js +28 -156
  44. package/dist/commands/improve/planner.js +5 -10
  45. package/dist/commands/improve/preparation.js +851 -2339
  46. package/dist/commands/improve/proactive-maintenance.js +34 -101
  47. package/dist/commands/improve/reflect-noise.js +104 -280
  48. package/dist/commands/improve/reflect.js +621 -1367
  49. package/dist/commands/improve/salience.js +46 -232
  50. package/dist/commands/improve/session-asset.js +19 -100
  51. package/dist/commands/improve/stage.js +323 -0
  52. package/dist/commands/lint/base-linter.js +19 -5
  53. package/dist/commands/proposal/drain.js +251 -644
  54. package/dist/commands/proposal/proposal-cli.js +3 -18
  55. package/dist/commands/proposal/proposal-types.js +20 -41
  56. package/dist/commands/proposal/proposal.js +1 -2
  57. package/dist/commands/proposal/propose.js +134 -160
  58. package/dist/commands/proposal/repository.js +502 -1487
  59. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  60. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  61. package/dist/commands/proposal/validators/proposals.js +13 -89
  62. package/dist/commands/read/curate.js +63 -413
  63. package/dist/commands/read/search-cli.js +16 -33
  64. package/dist/commands/read/search.js +17 -23
  65. package/dist/commands/read/show.js +2 -13
  66. package/dist/commands/sources/bundle-cli.js +25 -2
  67. package/dist/commands/sources/bundle-config-ops.js +4 -0
  68. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  69. package/dist/commands/sources/info.js +2 -11
  70. package/dist/commands/sources/installed-stashes.js +197 -746
  71. package/dist/commands/sources/schema-repair.js +98 -129
  72. package/dist/commands/sources/source-add.js +62 -12
  73. package/dist/commands/sources/source-manage.js +9 -2
  74. package/dist/commands/sources/stash-cli.js +1 -1
  75. package/dist/commands/tasks/explain.js +10 -13
  76. package/dist/commands/tasks/tasks-cli.js +9 -8
  77. package/dist/commands/tasks/tasks.js +326 -930
  78. package/dist/commands/tasks/validate.js +42 -21
  79. package/dist/commands/workflow/plan.js +22 -29
  80. package/dist/commands/workflow-cli.js +4 -4
  81. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  82. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  83. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  84. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  85. package/dist/core/adapter/execution-source.js +17 -29
  86. package/dist/core/asset/asset-placement.js +4 -13
  87. package/dist/core/asset/resolve-ref.js +1 -1
  88. package/dist/core/bundle-id.js +42 -5
  89. package/dist/core/bundle-rename.js +291 -0
  90. package/dist/core/config/config-io.js +1 -2
  91. package/dist/core/config/config-schema.js +1 -33
  92. package/dist/core/config/config-walker.js +1 -1
  93. package/dist/core/config/config.js +163 -68
  94. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  95. package/dist/core/config/schema/embedding.js +20 -5
  96. package/dist/core/config/schema/engines.js +5 -0
  97. package/dist/core/config/schema/execution.js +1 -1
  98. package/dist/core/config/schema/experimental.js +1 -1
  99. package/dist/core/config/schema/improve-processes.js +21 -95
  100. package/dist/core/config/schema/improve.js +4 -42
  101. package/dist/core/config/schema/scheduler.js +12 -12
  102. package/dist/core/config/schema/search.js +6 -22
  103. package/dist/core/env-secret-ref.js +0 -1
  104. package/dist/core/errors.js +8 -9
  105. package/dist/core/file-lock.js +76 -173
  106. package/dist/core/logs-db.js +2 -2
  107. package/dist/core/paths.js +0 -27
  108. package/dist/core/redaction.js +109 -2
  109. package/dist/core/run-lock.js +2 -5
  110. package/dist/core/spawn-env.js +1 -1
  111. package/dist/core/state/migrations.js +108 -61
  112. package/dist/core/state-db-scope.js +2 -4
  113. package/dist/core/state-db.js +126 -692
  114. package/dist/core/type-presentation.js +1 -9
  115. package/dist/core/write-source.js +293 -1012
  116. package/dist/execution/input-contract.js +1 -1
  117. package/dist/execution/resolved-request.js +135 -689
  118. package/dist/execution/source.js +63 -257
  119. package/dist/execution/target-ref.js +1 -1
  120. package/dist/indexer/bundle-identity-guard.js +2 -2
  121. package/dist/indexer/db/graph-db.js +106 -46
  122. package/dist/indexer/ensure-index.js +44 -85
  123. package/dist/indexer/graph/graph-extraction.js +340 -562
  124. package/dist/indexer/graph/graph-related.js +130 -0
  125. package/dist/indexer/index-rebuild-lock.js +3 -11
  126. package/dist/indexer/index-writer-lock.js +8 -17
  127. package/dist/indexer/index-written-assets.js +139 -151
  128. package/dist/indexer/indexer.js +524 -846
  129. package/dist/indexer/materialize-embeddings.js +60 -397
  130. package/dist/indexer/passes/memory-inference.js +81 -90
  131. package/dist/indexer/passes/metadata.js +132 -200
  132. package/dist/indexer/read-preflight.js +0 -7
  133. package/dist/indexer/scan/doc-to-entry.js +1 -3
  134. package/dist/indexer/scan/drain-dir.js +1 -1
  135. package/dist/indexer/search/db-search.js +181 -590
  136. package/dist/indexer/search/fts-query.js +30 -41
  137. package/dist/indexer/search/ranking.js +28 -154
  138. package/dist/indexer/search/search-attribution.js +12 -32
  139. package/dist/indexer/search/search-fields.js +11 -15
  140. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  141. package/dist/indexer/search/search-source.js +1 -4
  142. package/dist/indexer/usage/usage-events.js +2 -7
  143. package/dist/integrations/agent/engine-fallback.js +23 -40
  144. package/dist/integrations/agent/engine-resolution.js +93 -183
  145. package/dist/integrations/agent/execution.js +507 -0
  146. package/dist/integrations/agent/model-map.js +28 -156
  147. package/dist/integrations/agent/request-lowering.js +66 -141
  148. package/dist/integrations/agent/runner-dispatch.js +143 -321
  149. package/dist/integrations/agent/runner.js +54 -14
  150. package/dist/integrations/lockfile.js +53 -101
  151. package/dist/llm/embedders/deterministic.js +2 -3
  152. package/dist/llm/embedders/profile.js +71 -0
  153. package/dist/llm/embedders/remote.js +10 -15
  154. package/dist/llm/graph-extract.js +3 -12
  155. package/dist/llm/index-passes.js +3 -5
  156. package/dist/llm/memory-infer.js +1 -2
  157. package/dist/llm/metadata-enhance.js +1 -2
  158. package/dist/llm/structured-call.js +5 -24
  159. package/dist/output/generic-render.js +23 -11
  160. package/dist/output/html-render.js +13 -10
  161. package/dist/output/render-registry.js +3 -32
  162. package/dist/output/shapes/helpers.js +2 -34
  163. package/dist/output/shapes/passthrough.js +1 -9
  164. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  165. package/dist/output/text/command-format.js +60 -23
  166. package/dist/output/text/helpers.js +1 -1
  167. package/dist/output/text/migrate.js +5 -14
  168. package/dist/output/text/proposal-format.js +1 -2
  169. package/dist/output/text/workflow-format.js +0 -32
  170. package/dist/output/text.js +2 -0
  171. package/dist/registry/factory.js +4 -19
  172. package/dist/registry/network.js +66 -220
  173. package/dist/registry/providers/index.js +0 -2
  174. package/dist/registry/providers/skills-sh.js +3 -14
  175. package/dist/registry/providers/static-index.js +24 -26
  176. package/dist/registry/resolve.js +55 -131
  177. package/dist/scripts/akm-migrate-node.js +43940 -93320
  178. package/dist/scripts/akm-migrate.js +43700 -93078
  179. package/dist/setup/registry-stash-loader.js +4 -13
  180. package/dist/setup/semantic-assets.js +3 -44
  181. package/dist/setup/setup.js +1 -1
  182. package/dist/setup/steps/tasks.js +25 -15
  183. package/dist/sources/provider-factory.js +17 -18
  184. package/dist/sources/providers/filesystem.js +2 -3
  185. package/dist/sources/providers/git-install.js +7 -1
  186. package/dist/sources/providers/git-provider.js +0 -3
  187. package/dist/sources/providers/git-stash.js +0 -17
  188. package/dist/sources/providers/npm.js +2 -4
  189. package/dist/sources/providers/provider-utils.js +5 -10
  190. package/dist/sources/providers/website.js +0 -2
  191. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  192. package/dist/sources/website-url.js +2 -2
  193. package/dist/storage/database.js +9 -35
  194. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  195. package/dist/storage/repositories/index-connection.js +34 -70
  196. package/dist/storage/repositories/index-entries-repository.js +69 -111
  197. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  198. package/dist/storage/repositories/index-entry-schema.js +83 -269
  199. package/dist/storage/repositories/index-fts-repository.js +86 -256
  200. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  201. package/dist/storage/repositories/index-meta-repository.js +6 -4
  202. package/dist/storage/repositories/index-schema.js +192 -220
  203. package/dist/storage/repositories/index-utility-repository.js +8 -29
  204. package/dist/storage/repositories/index-vec-repository.js +133 -414
  205. package/dist/storage/repositories/outcome-repository.js +2 -1
  206. package/dist/storage/repositories/proposals-repository.js +35 -0
  207. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  208. package/dist/storage/repositories/task-history-repository.js +26 -4
  209. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  210. package/dist/storage/sqlite-migrations.js +136 -0
  211. package/dist/storage/sqlite-pragmas.js +11 -9
  212. package/dist/storage/sqlite-transaction.js +170 -0
  213. package/dist/storage/state-db-integrity.js +34 -27
  214. package/dist/tasks/activation-config.js +134 -62
  215. package/dist/tasks/backends/cron.js +129 -277
  216. package/dist/tasks/backends/exec-utils.js +2 -5
  217. package/dist/tasks/backends/launchd.js +125 -745
  218. package/dist/tasks/backends/schtasks.js +101 -620
  219. package/dist/tasks/prepare/prepare-support.js +5 -15
  220. package/dist/tasks/prepare/prepare.js +0 -2
  221. package/dist/tasks/resolve-akm-bin.js +20 -79
  222. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  223. package/dist/tasks/scheduler-binding.js +18 -238
  224. package/dist/tasks/scheduler-invocation.js +52 -52
  225. package/dist/tasks/scheduler-lock.js +53 -0
  226. package/dist/tasks/scheduler-sync.js +361 -751
  227. package/dist/tasks/source/parse-task-source.js +160 -10
  228. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  229. package/dist/tasks/source/task-to-v4.js +2 -2
  230. package/dist/workflows/authoring/authoring.js +3 -12
  231. package/dist/workflows/compile.js +211 -0
  232. package/dist/workflows/concurrency-policy.js +13 -74
  233. package/dist/workflows/exec/child-invocation.js +3 -17
  234. package/dist/workflows/exec/child-workflow.js +32 -141
  235. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  236. package/dist/workflows/exec/environment.js +98 -0
  237. package/dist/workflows/exec/exec-unit.js +33 -140
  238. package/dist/workflows/exec/frozen-judge.js +7 -59
  239. package/dist/workflows/exec/native-executor.js +82 -341
  240. package/dist/workflows/exec/param-secrets.js +29 -47
  241. package/dist/workflows/exec/run-workflow.js +154 -387
  242. package/dist/workflows/exec/scheduler.js +9 -36
  243. package/dist/workflows/exec/step-work.js +127 -430
  244. package/dist/workflows/exec/unit-dispatch.js +11 -63
  245. package/dist/workflows/exec/unit-writer.js +8 -52
  246. package/dist/workflows/exec/worktree.js +39 -273
  247. package/dist/workflows/freeze/child-output-references.js +4 -15
  248. package/dist/workflows/freeze/environment.js +99 -92
  249. package/dist/workflows/freeze/freeze.js +172 -0
  250. package/dist/workflows/freeze/step-values.js +19 -21
  251. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  252. package/dist/workflows/freeze/targets/command.js +10 -33
  253. package/dist/workflows/freeze/targets/script.js +5 -12
  254. package/dist/workflows/freeze/targets/shell.js +3 -6
  255. package/dist/workflows/freeze/targets/task.js +25 -80
  256. package/dist/workflows/freeze/task-bindings.js +20 -67
  257. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  258. package/dist/workflows/ir/params.js +6 -51
  259. package/dist/workflows/ir/plan-hash.js +2 -34
  260. package/dist/workflows/parser.js +140 -43
  261. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  262. package/dist/workflows/renderer.js +36 -69
  263. package/dist/workflows/resource-limits.js +12 -120
  264. package/dist/workflows/runtime/agent-identity.js +8 -40
  265. package/dist/workflows/runtime/run-outputs.js +3 -6
  266. package/dist/workflows/runtime/run-plan.js +316 -0
  267. package/dist/workflows/runtime/runs.js +48 -200
  268. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  269. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  270. package/dist/workflows/validate-summary.js +2 -7
  271. package/docs/integration/bundling-akm.md +49 -42
  272. package/docs/migration/README.md +1 -0
  273. package/docs/migration/release-notes/0.9.17.md +41 -0
  274. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  275. package/docs/reference/cli.md +182 -125
  276. package/docs/reference/configuration.md +49 -56
  277. package/docs/reference/data-and-telemetry.md +19 -20
  278. package/docs/reference/tasks.md +86 -38
  279. package/docs/reference/workflow-schema.md +14 -18
  280. package/docs/reference/workflows.md +6 -9
  281. package/package.json +1 -1
  282. package/schemas/akm-config.json +87 -406
  283. package/dist/commands/health/advisories.js +0 -150
  284. package/dist/commands/health/metrics.js +0 -329
  285. package/dist/commands/health/surfaces.js +0 -102
  286. package/dist/commands/improve/anti-collapse.js +0 -83
  287. package/dist/commands/improve/collapse-detector.js +0 -432
  288. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  289. package/dist/commands/improve/consolidate/merge.js +0 -146
  290. package/dist/commands/improve/distill/promote-memory.js +0 -329
  291. package/dist/commands/improve/distill/quality-gate.js +0 -500
  292. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  293. package/dist/commands/improve/proposal-envelope.js +0 -31
  294. package/dist/commands/improve/run-context.js +0 -123
  295. package/dist/commands/improve/shared.js +0 -21
  296. package/dist/commands/improve/source-identity.js +0 -28
  297. package/dist/commands/improve/triage.js +0 -96
  298. package/dist/commands/proposal/drain-policies.js +0 -151
  299. package/dist/commands/sources/update-transaction.js +0 -220
  300. package/dist/core/action-contributors.js +0 -28
  301. package/dist/core/config/config-version-shim.js +0 -101
  302. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  303. package/dist/core/fs-txn.js +0 -405
  304. package/dist/core/lexical-score.js +0 -25
  305. package/dist/core/maintenance-barrier.js +0 -167
  306. package/dist/execution/executable-identity.js +0 -105
  307. package/dist/execution/guarded-source.js +0 -441
  308. package/dist/indexer/graph/graph-boost.js +0 -427
  309. package/dist/indexer/graph/graph-dedup.js +0 -95
  310. package/dist/indexer/search/name-match.js +0 -35
  311. package/dist/indexer/search/ranking-contributors.js +0 -515
  312. package/dist/indexer/walk/project-context.js +0 -192
  313. package/dist/integrations/agent/execution-cascade.js +0 -566
  314. package/dist/integrations/agent/execution-definitions.js +0 -202
  315. package/dist/integrations/agent/execution-lowering.js +0 -841
  316. package/dist/integrations/agent/execution-preparation.js +0 -98
  317. package/dist/integrations/agent/inline-execution.js +0 -74
  318. package/dist/registry/create-provider-registry.js +0 -29
  319. package/dist/registry/pinned-request-helper.js +0 -247
  320. package/dist/registry/pinned-transport.js +0 -717
  321. package/dist/sources/providers/index.js +0 -14
  322. package/dist/storage/engines/sqlite-migrations.js +0 -271
  323. package/dist/storage/repositories/canaries-repository.js +0 -107
  324. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  325. package/dist/storage/repositories/registry-cache.js +0 -113
  326. package/dist/tasks/scheduler-sync-preview.js +0 -52
  327. package/dist/workflows/freeze/resolve-steps.js +0 -86
  328. package/dist/workflows/freeze/source-freeze.js +0 -64
  329. package/dist/workflows/ir/compile.js +0 -321
  330. package/dist/workflows/ir/environment-v4.js +0 -330
  331. package/dist/workflows/ir/freeze-v4.js +0 -153
  332. package/dist/workflows/ir/schema-v4.js +0 -745
  333. package/dist/workflows/ir/schema.js +0 -354
  334. package/dist/workflows/program/schema.js +0 -78
  335. package/dist/workflows/runtime/checkin.js +0 -57
  336. package/dist/workflows/runtime/plan-classifier.js +0 -196
  337. package/dist/workflows/runtime/unit-checkin.js +0 -45
  338. package/dist/workflows/runtime/unit-phases.js +0 -20
  339. package/dist/workflows/schema.js +0 -4
  340. package/dist/workflows/source-ir/compile.js +0 -200
  341. package/dist/workflows/source-ir/program.js +0 -50
  342. package/dist/workflows/source-ir/result.js +0 -26
  343. package/dist/workflows/source-ir/schema.js +0 -786
  344. package/dist/workflows/source-ir/triggers.js +0 -79
  345. package/dist/workflows/source-ir/uses.js +0 -40
  346. package/dist/workflows/validator.js +0 -60
@@ -0,0 +1,323 @@
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 { getImproveProcessConfig } from "../../core/config/config.js";
5
+ import { ConfigError } from "../../core/errors.js";
6
+ import { parseEmbeddedJsonResponse } from "../../core/parse.js";
7
+ import { warn } from "../../core/warn.js";
8
+ import { LlmCallError } from "../../llm/client.js";
9
+ import { callStructured } from "../../llm/structured-call.js";
10
+ import { withLlmStage } from "../../llm/usage-telemetry.js";
11
+ import { isProceduralRejection } from "../proposal/proposal-types.js";
12
+ import { createProposal, listProposalsReadOnly, proposalContentHash, recordGateDecision, } from "../proposal/repository.js";
13
+ import { resolveImproveLlmExecution } from "./execution.js";
14
+ /** Normalize an unknown thrown value to a message. */
15
+ export function errMessage(e) {
16
+ return e instanceof Error ? e.message : String(e);
17
+ }
18
+ /** The lowering notices a stage's dispatches emitted, each once. */
19
+ export function noticeSet(forward) {
20
+ const byKey = new Map();
21
+ const add = (notices) => {
22
+ for (const notice of notices)
23
+ byKey.set(JSON.stringify(notice), notice);
24
+ forward?.(notices);
25
+ };
26
+ const list = () => Object.freeze([...byKey.values()]);
27
+ return { add, list, fields: () => (byKey.size > 0 ? { notices: list() } : {}) };
28
+ }
29
+ /**
30
+ * A stage's LLM runner: the one the improve plan froze for it (an own
31
+ * `llmRunner` key, `null` meaning "none"), else the process engine cascade.
32
+ */
33
+ export function stageRunner(frozen, config, profile, processName, onNotices) {
34
+ if (Object.hasOwn(frozen, "llmRunner"))
35
+ return frozen.llmRunner ?? undefined;
36
+ const resolved = resolveImproveLlmExecution({
37
+ config,
38
+ profile,
39
+ process: getImproveProcessConfig(processName, profile),
40
+ processName,
41
+ });
42
+ if (resolved)
43
+ onNotices?.(resolved.notices);
44
+ return resolved?.runner;
45
+ }
46
+ /**
47
+ * One model call. Provider trouble (transport error, timeout, a disabled
48
+ * feature) comes back as `{ ok: false }`; only a configuration failure throws.
49
+ */
50
+ export async function callStage(call) {
51
+ const messages = [
52
+ ...(call.system ? [{ role: "system", content: call.system }] : []),
53
+ ...(call.history ?? []),
54
+ { role: "user", content: call.prompt },
55
+ ];
56
+ let failure;
57
+ try {
58
+ const raw = await callStructured({
59
+ feature: call.feature,
60
+ ...(call.gate
61
+ ? { akmConfig: call.gate.config, ...(call.gate.enabled !== undefined ? { enabled: call.gate.enabled } : {}) }
62
+ : {}),
63
+ runner: call.runner,
64
+ messages,
65
+ ...(call.request ? { request: call.request } : {}),
66
+ ...(call.onNotices ? { onNotices: call.onNotices } : {}),
67
+ parse: (r) => r ?? "",
68
+ onError: (_cls, err) => {
69
+ failure = { ok: false, reason: "error", error: errMessage(err) };
70
+ return undefined;
71
+ },
72
+ fallback: undefined,
73
+ onFallback: (event) => {
74
+ failure ??= { ok: false, reason: event.reason, ...(event.error ? { error: event.error.message } : {}) };
75
+ },
76
+ });
77
+ return raw === undefined ? (failure ?? { ok: false, reason: "error" }) : { ok: true, raw };
78
+ }
79
+ catch (err) {
80
+ if (err instanceof ConfigError)
81
+ throw err;
82
+ const timedOut = err instanceof LlmCallError && err.code === "timeout";
83
+ return { ok: false, reason: timedOut ? "timeout" : "error", error: errMessage(err) };
84
+ }
85
+ }
86
+ /** Attribute a stage's LLM calls to its process and planned engine (the usage report). */
87
+ const STAGE_LABELS = {
88
+ reflect: "reflect",
89
+ distill: "distill",
90
+ consolidate: "consolidate",
91
+ extract: "session-extraction",
92
+ memoryInference: "memory-inference",
93
+ graphExtraction: "graph-extraction",
94
+ validation: "validation",
95
+ };
96
+ export function attributeStage(plan, process, fn) {
97
+ return withLlmStage(STAGE_LABELS[process], fn, { engine: plan?.processes[process].runner?.engine, process });
98
+ }
99
+ /** How many prior rejected proposals are shown to the model as "don't repeat this". */
100
+ export const MAX_REJECTED_PROPOSALS = 3;
101
+ /**
102
+ * Reflexion context: the newest reviewer rejections for `ref`. Procedural
103
+ * refusals (expiry, stale target, missing asset) are not judgements on the
104
+ * content and are left out. Reads never create state.db.
105
+ */
106
+ export function rejectedProposalContext(stash, ref, ctx) {
107
+ if (!ref)
108
+ return [];
109
+ return listProposalsReadOnly(stash, { ref, status: "rejected", includeArchive: true }, ctx)
110
+ .filter((p) => !isProceduralRejection(p))
111
+ .sort((a, b) => new Date(b.updatedAt ?? 0).getTime() - new Date(a.updatedAt ?? 0).getTime())
112
+ .slice(0, MAX_REJECTED_PROPOSALS)
113
+ .map((p) => ({
114
+ ref: p.ref,
115
+ reason: p.review?.reason ?? "no reason given",
116
+ // `payload.content` is populated on every row, including legacy ones.
117
+ contentPreview: p.payload.content.slice(0, 500),
118
+ }));
119
+ }
120
+ // ── Mint ─────────────────────────────────────────────────────────────────────
121
+ /**
122
+ * Create a stage's proposal. `judged` stamps a `staged` gate decision with the
123
+ * judged content's hash (the triage drain accepts it while the content still
124
+ * matches); `review` leaves it `deferred` for a human (`review_needed` in the
125
+ * improve ledger).
126
+ */
127
+ export function mintProposal(stash, proposalsCtx, input, verdict = {}) {
128
+ const proposal = createProposal(stash, input, proposalsCtx);
129
+ if (verdict.review) {
130
+ return recordGateDecision(stash, proposal.id, { outcome: "deferred", ...verdict.review }, proposalsCtx) ?? proposal;
131
+ }
132
+ return verdict.judged ? stageJudgedProposal(stash, proposal, proposalsCtx) : proposal;
133
+ }
134
+ /**
135
+ * Stamp a proposal the quality judge passed. Best-effort: a failed stamp only
136
+ * means the triage drain judges it again.
137
+ */
138
+ export function stageJudgedProposal(stash, proposal, proposalsCtx) {
139
+ try {
140
+ return (recordGateDecision(stash, proposal.id, {
141
+ outcome: "staged",
142
+ reason: "quality-judge",
143
+ gate: "quality-gate",
144
+ contentHash: proposalContentHash(proposal),
145
+ }, proposalsCtx) ?? proposal);
146
+ }
147
+ catch (error) {
148
+ warn(`[akm] failed to record the quality-judge pass for ${proposal.id}: ${errMessage(error)}`);
149
+ return proposal;
150
+ }
151
+ }
152
+ /** Lesson judge prompt; similar existing lessons let it mark near-duplicates down. */
153
+ export function buildJudgePrompt(lessonContent, sourceContent, similarLessons) {
154
+ const lines = [
155
+ "You are evaluating a proposed lesson asset for an akm knowledge base.",
156
+ "",
157
+ "Score this lesson on each criterion from 1 (poor) to 5 (excellent):",
158
+ "1. NOVELTY: Does the lesson add information not already present in the source asset?",
159
+ "2. NON-REDUNDANCY: Is this lesson meaningfully different from what the source already says?",
160
+ "",
161
+ "Source asset content:",
162
+ "```",
163
+ sourceContent.slice(0, 2000),
164
+ "```",
165
+ ];
166
+ if (similarLessons && similarLessons.length > 0) {
167
+ lines.push("", "Existing similar lessons (top-3 by similarity). Rate lower if the proposed lesson is substantially similar to any of these:");
168
+ for (const sl of similarLessons)
169
+ lines.push(`\nExisting lesson ref: ${sl.ref}`, "```", sl.content.slice(0, 500), "```");
170
+ }
171
+ lines.push("", "Proposed lesson content:", "```", lessonContent.slice(0, 1000), "```", "", 'Return ONLY valid JSON, no prose: {"scores": {"novelty": <1-5 integer>, "nonRedundancy": <1-5 integer>}, "reason": "<one sentence>"}');
172
+ return lines.join("\n");
173
+ }
174
+ function boundedDocument(content, maxChars = 6000) {
175
+ if (content.length <= maxChars)
176
+ return content;
177
+ const half = Math.floor((maxChars - 80) / 2);
178
+ return `${content.slice(0, half)}\n\n[... middle omitted for bounded judge context ...]\n\n${content.slice(-half)}`;
179
+ }
180
+ function buildChangedRegion(sourceContent, candidateContent) {
181
+ const source = sourceContent.split("\n");
182
+ const candidate = candidateContent.split("\n");
183
+ let prefix = 0;
184
+ while (prefix < source.length && prefix < candidate.length && source[prefix] === candidate[prefix])
185
+ prefix++;
186
+ let suffix = 0;
187
+ while (suffix < source.length - prefix &&
188
+ suffix < candidate.length - prefix &&
189
+ source[source.length - 1 - suffix] === candidate[candidate.length - 1 - suffix]) {
190
+ suffix++;
191
+ }
192
+ const removed = source.slice(prefix, source.length - suffix).join("\n");
193
+ const added = candidate.slice(prefix, candidate.length - suffix).join("\n");
194
+ return boundedDocument(`Removed or replaced:\n${removed || "(none)"}\n\nAdded or replacement:\n${added || "(none)"}`);
195
+ }
196
+ /** Judge prompt for an in-place revision (overlap with the source is expected). */
197
+ export function buildReflectJudgePrompt(candidateContent, sourceContent, feedback) {
198
+ return [
199
+ "You are evaluating a proposed revision to an existing akm asset.",
200
+ "",
201
+ "Score this revision on each criterion from 1 (poor) to 5 (excellent):",
202
+ "1. FEEDBACK ALIGNMENT: Does the revision address the supplied feedback or improve retrieval and clarity?",
203
+ "2. PRESERVATION: Does it retain the source's concrete facts, code, commands, examples, and structure without truncation?",
204
+ "3. QUALITY: Is the revision coherent, actionable, complete, and free of unsupported claims?",
205
+ "",
206
+ "Overlap with the source is expected and must not lower the score by itself; this is an in-place revision, not a new lesson.",
207
+ "",
208
+ "Feedback:",
209
+ "```",
210
+ (feedback.length > 0 ? feedback.join("\n") : "No explicit feedback supplied.").slice(0, 1000),
211
+ "```",
212
+ "",
213
+ "Source asset content:",
214
+ "```",
215
+ boundedDocument(sourceContent),
216
+ "```",
217
+ "",
218
+ "Proposed revision:",
219
+ "```",
220
+ boundedDocument(candidateContent),
221
+ "```",
222
+ "",
223
+ "Changed region:",
224
+ "```",
225
+ buildChangedRegion(sourceContent, candidateContent),
226
+ "```",
227
+ "",
228
+ 'Return ONLY valid JSON, no prose: {"scores": {"feedbackAlignment": <1-5 integer>, "preservation": <1-5 integer>, "quality": <1-5 integer>}, "reason": "<one sentence>"}',
229
+ ].join("\n");
230
+ }
231
+ const LESSON_JUDGE_CRITERIA = ["novelty", "nonRedundancy"];
232
+ const REFLECT_JUDGE_CRITERIA = ["feedbackAlignment", "preservation", "quality"];
233
+ /**
234
+ * Read a judge response: the per-criterion shape (averaged here) or the older
235
+ * `{"score"}` shape. Only the expected criteria are read; any missing or
236
+ * out-of-range (1..5) value is a parse failure, extra keys are ignored.
237
+ */
238
+ function parseJudgeResponse(raw, keys) {
239
+ const parsed = parseEmbeddedJsonResponse(raw);
240
+ if (!parsed || typeof parsed.reason !== "string")
241
+ return undefined;
242
+ const reason = parsed.reason;
243
+ const inRange = (value) => typeof value === "number" && Number.isFinite(value) && value >= 1 && value <= 5;
244
+ if (parsed.scores !== undefined) {
245
+ if (typeof parsed.scores !== "object" || parsed.scores === null || Array.isArray(parsed.scores))
246
+ return undefined;
247
+ const scores = parsed.scores;
248
+ const criteria = {};
249
+ for (const key of keys) {
250
+ const value = scores[key];
251
+ if (!inRange(value))
252
+ return undefined;
253
+ criteria[key] = value;
254
+ }
255
+ return { score: Object.values(criteria).reduce((a, b) => a + b, 0) / keys.length, reason, criteria };
256
+ }
257
+ return inRange(parsed.score) ? { score: parsed.score, reason } : undefined;
258
+ }
259
+ function judgeResponseSchema(keys) {
260
+ return {
261
+ type: "object",
262
+ required: ["scores", "reason"],
263
+ additionalProperties: false,
264
+ properties: {
265
+ scores: {
266
+ type: "object",
267
+ required: [...keys],
268
+ additionalProperties: false,
269
+ properties: Object.fromEntries(keys.map((key) => [key, { type: "integer", minimum: 1, maximum: 5 }])),
270
+ },
271
+ reason: { type: "string" },
272
+ },
273
+ };
274
+ }
275
+ /**
276
+ * The quality judge. Fails closed: no runner, an unparseable verdict or a
277
+ * provider failure never passes content. Bands: >= 3.5 pass, 2.5-3.5 review,
278
+ * < 2.5 reject. Temperature is pinned to 0 so verdicts do not flip.
279
+ */
280
+ async function runQualityJudge(feature, config, prompt, keys, chat, options) {
281
+ const resolved = !options.runnerSelectionFrozen && !options.llmRunner
282
+ ? resolveImproveLlmExecution({ config, processName: `${feature}-judge` })
283
+ : null;
284
+ if (resolved)
285
+ options.onNotices?.(resolved.notices);
286
+ const runner = options.llmRunner ?? resolved?.runner;
287
+ if (!runner)
288
+ return { pass: false, score: -1, reason: "no LLM configured — cannot judge, failing closed" };
289
+ const outcome = await callStage({
290
+ feature,
291
+ runner,
292
+ system: "Return only valid JSON. No prose.",
293
+ prompt,
294
+ request: {
295
+ enableThinking: false,
296
+ temperature: 0,
297
+ responseSchema: judgeResponseSchema(keys),
298
+ ...(Object.hasOwn(options, "timeoutMs") ? { timeoutMs: options.timeoutMs } : {}),
299
+ ...(options.signal ? { signal: options.signal } : {}),
300
+ ...(chat ? { chat } : {}),
301
+ },
302
+ ...(options.onNotices ? { onNotices: options.onNotices } : {}),
303
+ });
304
+ if (!outcome.ok) {
305
+ return { pass: false, score: -1, reason: "judge timeout/error — routed to review", reviewNeeded: true };
306
+ }
307
+ const parsed = parseJudgeResponse(outcome.raw, keys);
308
+ if (!parsed)
309
+ return { pass: false, score: -1, reason: "judge parse failed — routed to review", reviewNeeded: true };
310
+ const { score, reason, criteria } = parsed;
311
+ const verdict = score >= 3.5 ? { pass: true } : score >= 2.5 ? { pass: false, reviewNeeded: true } : { pass: false };
312
+ return { ...verdict, score, reason, ...(criteria ? { criteria } : {}) };
313
+ }
314
+ /** Judge a proposed lesson (or knowledge promotion) against its source. */
315
+ export function runLessonQualityJudge(config, lessonContent, sourceContent, chat, options = {}) {
316
+ const prompt = buildJudgePrompt(lessonContent, sourceContent, options.similarLessons);
317
+ return runQualityJudge("lesson_quality_gate", config, prompt, LESSON_JUDGE_CRITERIA, chat, options);
318
+ }
319
+ /** Judge an in-place reflect revision without new-lesson novelty criteria. */
320
+ export function runReflectQualityJudge(config, candidateContent, sourceContent, feedback, chat, options = {}) {
321
+ const prompt = buildReflectJudgePrompt(candidateContent, sourceContent, feedback);
322
+ return runQualityJudge("proposal_quality_gate", config, prompt, REFLECT_JUDGE_CRITERIA, chat, options);
323
+ }
@@ -42,6 +42,7 @@ import { isArchivedRelPath } from "../../core/asset/memory-archive.js";
42
42
  import { conceptIdFromTypeName, typeNameFromConceptId } from "../../core/asset/resolve-ref.js";
43
43
  import { localDateStamp } from "../../core/common.js";
44
44
  import { containsRedactedContent, REDACTED_CONTENT_MARKER } from "../../core/content-safety.js";
45
+ import { DERIVED_SUFFIX } from "../../core/recognition-util.js";
45
46
  import { findFenceRegions } from "./markdown-insertion.js";
46
47
  // ── Helpers ───────────────────────────────────────────────────────────────────
47
48
  /** Fold physically wrapped prose the same way a YAML plain scalar does. */
@@ -216,10 +217,23 @@ export function refExistsInAnyStash(relPath, refType, refName, stashRoots) {
216
217
  // record while leaving the live stash untouched.
217
218
  return memoryArchiveHasRef(refType, refName, stashRoots);
218
219
  }
220
+ /**
221
+ * The stash-relative files that satisfy a ref, in preference order: its own
222
+ * placement spellings, then, for a memory, the `<name>.derived.md` child (#882),
223
+ * so an edge to a parent whose plain `.md` is gone still reaches the child it was
224
+ * distilled into. This is lint's reachability rule only; the child owns
225
+ * `memories/<name>.derived`, never `memories/<name>`.
226
+ */
227
+ function refPathCandidates(refType, typeDir, refName) {
228
+ const candidates = assetPathCandidatesForName(refType, typeDir, refName);
229
+ if (refType !== "memory" || refName.endsWith(DERIVED_SUFFIX))
230
+ return candidates;
231
+ return [...candidates, assetPathForName(refType, typeDir, `${refName}${DERIVED_SUFFIX}`)];
232
+ }
219
233
  /**
220
234
  * True when `(refType, refName)` names a memory that prune archived in any
221
235
  * root. Mirrors `resolveRefPathInStash`'s candidate set so a ref that resolved
222
- * through the `.derived.md` twin (#882) still resolves once archived.
236
+ * through the `.derived.md` child (#882) still resolves once archived.
223
237
  */
224
238
  function memoryArchiveHasRef(refType, refName, stashRoots) {
225
239
  if (refType !== "memory")
@@ -227,7 +241,7 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
227
241
  const typeDir = stashDirFor(refType);
228
242
  if (typeDir === undefined)
229
243
  return false;
230
- const candidates = assetPathCandidatesForName(refType, typeDir, refName);
244
+ const candidates = refPathCandidates(refType, typeDir, refName);
231
245
  for (const root of stashRoots) {
232
246
  for (const candidate of candidates) {
233
247
  if (isArchivedRelPath(candidate, root))
@@ -241,8 +255,8 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
241
255
  * the same reachability rules (in the same order) as
242
256
  * {@link refExistsInAnyStash}, which delegates here. Returns the absolute path
243
257
  * of the file that makes the ref "exist" — for a multi-file skill directory
244
- * that is its `SKILL.md` primary, for a `memory` ref its `.derived.md` twin
245
- * when the plain `.md` is absent (#882, see `assetPathCandidatesForName`) —
258
+ * that is its `SKILL.md` primary, for a `memory` ref its `.derived.md` child
259
+ * when the plain `.md` is absent (#882, see {@link refPathCandidates}) —
246
260
  * or `null` when the ref does not resolve in this root.
247
261
  *
248
262
  * Extracted for SPEC-5 (`--supersedes` demotion): write commands need the
@@ -253,7 +267,7 @@ function memoryArchiveHasRef(refType, refName, stashRoots) {
253
267
  */
254
268
  export function resolveRefPathInStash(relPath, refType, refName, root) {
255
269
  const typeDir = stashDirFor(refType);
256
- const candidates = typeDir === undefined ? [relPath] : assetPathCandidatesForName(refType, typeDir, refName);
270
+ const candidates = typeDir === undefined ? [relPath] : refPathCandidates(refType, typeDir, refName);
257
271
  for (const candidate of candidates) {
258
272
  const absPath = path.join(root, candidate);
259
273
  if (fs.existsSync(absPath))