akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4

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 (343) hide show
  1. package/CHANGELOG.md +756 -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/proposal/drain.js +251 -644
  53. package/dist/commands/proposal/proposal-cli.js +3 -18
  54. package/dist/commands/proposal/proposal-types.js +20 -41
  55. package/dist/commands/proposal/proposal.js +1 -2
  56. package/dist/commands/proposal/propose.js +134 -160
  57. package/dist/commands/proposal/repository.js +502 -1487
  58. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  59. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  60. package/dist/commands/proposal/validators/proposals.js +13 -89
  61. package/dist/commands/read/curate.js +63 -413
  62. package/dist/commands/read/search-cli.js +16 -33
  63. package/dist/commands/read/search.js +17 -23
  64. package/dist/commands/read/show.js +2 -13
  65. package/dist/commands/sources/bundle-cli.js +25 -2
  66. package/dist/commands/sources/bundle-config-ops.js +7 -0
  67. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  68. package/dist/commands/sources/info.js +2 -11
  69. package/dist/commands/sources/installed-stashes.js +197 -746
  70. package/dist/commands/sources/schema-repair.js +98 -129
  71. package/dist/commands/sources/source-add.js +62 -12
  72. package/dist/commands/sources/stash-cli.js +1 -1
  73. package/dist/commands/tasks/explain.js +10 -13
  74. package/dist/commands/tasks/tasks-cli.js +9 -8
  75. package/dist/commands/tasks/tasks.js +326 -930
  76. package/dist/commands/tasks/validate.js +42 -21
  77. package/dist/commands/workflow/plan.js +22 -29
  78. package/dist/commands/workflow-cli.js +4 -4
  79. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  80. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  81. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  82. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  83. package/dist/core/adapter/execution-source.js +17 -29
  84. package/dist/core/asset/resolve-ref.js +1 -1
  85. package/dist/core/bundle-id.js +42 -5
  86. package/dist/core/bundle-rename.js +291 -0
  87. package/dist/core/config/config-io.js +1 -2
  88. package/dist/core/config/config-schema.js +1 -33
  89. package/dist/core/config/config-walker.js +1 -1
  90. package/dist/core/config/config.js +163 -68
  91. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  92. package/dist/core/config/schema/embedding.js +20 -5
  93. package/dist/core/config/schema/engines.js +5 -0
  94. package/dist/core/config/schema/execution.js +1 -1
  95. package/dist/core/config/schema/experimental.js +1 -1
  96. package/dist/core/config/schema/improve-processes.js +21 -95
  97. package/dist/core/config/schema/improve.js +4 -42
  98. package/dist/core/config/schema/scheduler.js +12 -12
  99. package/dist/core/config/schema/search.js +6 -22
  100. package/dist/core/env-secret-ref.js +0 -1
  101. package/dist/core/errors.js +8 -9
  102. package/dist/core/file-lock.js +76 -173
  103. package/dist/core/logs-db.js +2 -2
  104. package/dist/core/paths.js +0 -27
  105. package/dist/core/redaction.js +109 -2
  106. package/dist/core/run-lock.js +2 -5
  107. package/dist/core/spawn-env.js +1 -1
  108. package/dist/core/state/migrations.js +108 -61
  109. package/dist/core/state-db-scope.js +2 -4
  110. package/dist/core/state-db.js +126 -692
  111. package/dist/core/type-presentation.js +1 -9
  112. package/dist/core/write-source.js +293 -1012
  113. package/dist/execution/input-contract.js +1 -1
  114. package/dist/execution/resolved-request.js +135 -689
  115. package/dist/execution/source.js +63 -257
  116. package/dist/execution/target-ref.js +1 -1
  117. package/dist/indexer/bundle-identity-guard.js +2 -2
  118. package/dist/indexer/db/graph-db.js +106 -46
  119. package/dist/indexer/ensure-index.js +44 -85
  120. package/dist/indexer/graph/graph-extraction.js +340 -562
  121. package/dist/indexer/graph/graph-related.js +130 -0
  122. package/dist/indexer/index-rebuild-lock.js +3 -11
  123. package/dist/indexer/index-writer-lock.js +8 -17
  124. package/dist/indexer/index-written-assets.js +139 -151
  125. package/dist/indexer/indexer.js +524 -846
  126. package/dist/indexer/materialize-embeddings.js +60 -397
  127. package/dist/indexer/passes/memory-inference.js +81 -90
  128. package/dist/indexer/passes/metadata.js +132 -200
  129. package/dist/indexer/read-preflight.js +0 -7
  130. package/dist/indexer/scan/doc-to-entry.js +1 -3
  131. package/dist/indexer/scan/drain-dir.js +1 -1
  132. package/dist/indexer/search/db-search.js +181 -590
  133. package/dist/indexer/search/fts-query.js +30 -41
  134. package/dist/indexer/search/ranking.js +28 -154
  135. package/dist/indexer/search/search-attribution.js +12 -32
  136. package/dist/indexer/search/search-fields.js +11 -15
  137. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  138. package/dist/indexer/search/search-source.js +1 -4
  139. package/dist/indexer/usage/usage-events.js +2 -7
  140. package/dist/integrations/agent/engine-fallback.js +23 -40
  141. package/dist/integrations/agent/engine-resolution.js +93 -183
  142. package/dist/integrations/agent/execution.js +507 -0
  143. package/dist/integrations/agent/model-map.js +28 -156
  144. package/dist/integrations/agent/request-lowering.js +66 -141
  145. package/dist/integrations/agent/runner-dispatch.js +143 -321
  146. package/dist/integrations/agent/runner.js +54 -14
  147. package/dist/integrations/lockfile.js +53 -101
  148. package/dist/llm/embedders/deterministic.js +2 -3
  149. package/dist/llm/embedders/profile.js +71 -0
  150. package/dist/llm/embedders/remote.js +10 -15
  151. package/dist/llm/graph-extract.js +3 -12
  152. package/dist/llm/index-passes.js +3 -5
  153. package/dist/llm/memory-infer.js +1 -2
  154. package/dist/llm/metadata-enhance.js +1 -2
  155. package/dist/llm/structured-call.js +5 -24
  156. package/dist/output/generic-render.js +23 -11
  157. package/dist/output/html-render.js +13 -10
  158. package/dist/output/render-registry.js +3 -32
  159. package/dist/output/shapes/helpers.js +2 -34
  160. package/dist/output/shapes/passthrough.js +1 -9
  161. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  162. package/dist/output/text/command-format.js +60 -23
  163. package/dist/output/text/helpers.js +1 -1
  164. package/dist/output/text/migrate.js +5 -14
  165. package/dist/output/text/proposal-format.js +1 -2
  166. package/dist/output/text/workflow-format.js +0 -32
  167. package/dist/output/text.js +2 -0
  168. package/dist/registry/factory.js +4 -19
  169. package/dist/registry/network.js +66 -220
  170. package/dist/registry/providers/index.js +0 -2
  171. package/dist/registry/providers/skills-sh.js +3 -14
  172. package/dist/registry/providers/static-index.js +24 -26
  173. package/dist/registry/resolve.js +55 -131
  174. package/dist/scripts/akm-migrate-node.js +43937 -93313
  175. package/dist/scripts/akm-migrate.js +43697 -93071
  176. package/dist/setup/registry-stash-loader.js +4 -13
  177. package/dist/setup/semantic-assets.js +3 -44
  178. package/dist/setup/setup.js +1 -1
  179. package/dist/setup/steps/tasks.js +25 -15
  180. package/dist/sources/provider-factory.js +17 -18
  181. package/dist/sources/providers/filesystem.js +2 -3
  182. package/dist/sources/providers/git-install.js +7 -1
  183. package/dist/sources/providers/git-provider.js +0 -3
  184. package/dist/sources/providers/git-stash.js +0 -17
  185. package/dist/sources/providers/npm.js +2 -4
  186. package/dist/sources/providers/provider-utils.js +5 -10
  187. package/dist/sources/providers/website.js +0 -2
  188. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  189. package/dist/sources/website-url.js +2 -2
  190. package/dist/storage/database.js +9 -35
  191. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  192. package/dist/storage/repositories/index-connection.js +34 -70
  193. package/dist/storage/repositories/index-entries-repository.js +69 -111
  194. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  195. package/dist/storage/repositories/index-entry-schema.js +83 -269
  196. package/dist/storage/repositories/index-fts-repository.js +86 -256
  197. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  198. package/dist/storage/repositories/index-meta-repository.js +6 -4
  199. package/dist/storage/repositories/index-schema.js +192 -220
  200. package/dist/storage/repositories/index-utility-repository.js +8 -29
  201. package/dist/storage/repositories/index-vec-repository.js +133 -414
  202. package/dist/storage/repositories/outcome-repository.js +2 -1
  203. package/dist/storage/repositories/proposals-repository.js +35 -0
  204. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  205. package/dist/storage/repositories/task-history-repository.js +26 -4
  206. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  207. package/dist/storage/sqlite-migrations.js +136 -0
  208. package/dist/storage/sqlite-pragmas.js +11 -9
  209. package/dist/storage/sqlite-transaction.js +170 -0
  210. package/dist/storage/state-db-integrity.js +34 -27
  211. package/dist/tasks/activation-config.js +134 -62
  212. package/dist/tasks/backends/cron.js +129 -277
  213. package/dist/tasks/backends/exec-utils.js +2 -5
  214. package/dist/tasks/backends/launchd.js +125 -745
  215. package/dist/tasks/backends/schtasks.js +101 -620
  216. package/dist/tasks/prepare/prepare-support.js +5 -15
  217. package/dist/tasks/prepare/prepare.js +0 -2
  218. package/dist/tasks/resolve-akm-bin.js +20 -79
  219. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  220. package/dist/tasks/scheduler-binding.js +18 -238
  221. package/dist/tasks/scheduler-invocation.js +52 -52
  222. package/dist/tasks/scheduler-lock.js +53 -0
  223. package/dist/tasks/scheduler-sync.js +363 -679
  224. package/dist/tasks/source/parse-task-source.js +160 -10
  225. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  226. package/dist/tasks/source/task-to-v4.js +2 -2
  227. package/dist/workflows/authoring/authoring.js +3 -12
  228. package/dist/workflows/compile.js +211 -0
  229. package/dist/workflows/concurrency-policy.js +13 -74
  230. package/dist/workflows/exec/child-invocation.js +3 -17
  231. package/dist/workflows/exec/child-workflow.js +32 -141
  232. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  233. package/dist/workflows/exec/environment.js +98 -0
  234. package/dist/workflows/exec/exec-unit.js +33 -140
  235. package/dist/workflows/exec/frozen-judge.js +7 -59
  236. package/dist/workflows/exec/native-executor.js +82 -341
  237. package/dist/workflows/exec/param-secrets.js +29 -47
  238. package/dist/workflows/exec/run-workflow.js +154 -387
  239. package/dist/workflows/exec/scheduler.js +9 -36
  240. package/dist/workflows/exec/step-work.js +127 -430
  241. package/dist/workflows/exec/unit-dispatch.js +11 -63
  242. package/dist/workflows/exec/unit-writer.js +8 -52
  243. package/dist/workflows/exec/worktree.js +39 -273
  244. package/dist/workflows/freeze/child-output-references.js +4 -15
  245. package/dist/workflows/freeze/environment.js +99 -92
  246. package/dist/workflows/freeze/freeze.js +172 -0
  247. package/dist/workflows/freeze/step-values.js +19 -21
  248. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  249. package/dist/workflows/freeze/targets/command.js +10 -33
  250. package/dist/workflows/freeze/targets/script.js +5 -12
  251. package/dist/workflows/freeze/targets/shell.js +3 -6
  252. package/dist/workflows/freeze/targets/task.js +25 -80
  253. package/dist/workflows/freeze/task-bindings.js +20 -67
  254. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  255. package/dist/workflows/ir/params.js +6 -51
  256. package/dist/workflows/ir/plan-hash.js +2 -34
  257. package/dist/workflows/parser.js +140 -43
  258. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  259. package/dist/workflows/renderer.js +36 -69
  260. package/dist/workflows/resource-limits.js +12 -120
  261. package/dist/workflows/runtime/agent-identity.js +8 -40
  262. package/dist/workflows/runtime/run-outputs.js +3 -6
  263. package/dist/workflows/runtime/run-plan.js +316 -0
  264. package/dist/workflows/runtime/runs.js +48 -200
  265. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  266. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  267. package/dist/workflows/validate-summary.js +2 -7
  268. package/docs/integration/bundling-akm.md +49 -42
  269. package/docs/migration/README.md +1 -0
  270. package/docs/migration/release-notes/0.9.17.md +41 -0
  271. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  272. package/docs/reference/cli.md +182 -125
  273. package/docs/reference/configuration.md +49 -56
  274. package/docs/reference/data-and-telemetry.md +19 -20
  275. package/docs/reference/tasks.md +86 -38
  276. package/docs/reference/workflow-schema.md +14 -18
  277. package/docs/reference/workflows.md +6 -9
  278. package/package.json +1 -1
  279. package/schemas/akm-config.json +87 -406
  280. package/dist/commands/health/advisories.js +0 -150
  281. package/dist/commands/health/metrics.js +0 -329
  282. package/dist/commands/health/surfaces.js +0 -102
  283. package/dist/commands/improve/anti-collapse.js +0 -83
  284. package/dist/commands/improve/collapse-detector.js +0 -432
  285. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  286. package/dist/commands/improve/consolidate/merge.js +0 -146
  287. package/dist/commands/improve/distill/promote-memory.js +0 -329
  288. package/dist/commands/improve/distill/quality-gate.js +0 -500
  289. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  290. package/dist/commands/improve/proposal-envelope.js +0 -31
  291. package/dist/commands/improve/run-context.js +0 -123
  292. package/dist/commands/improve/shared.js +0 -21
  293. package/dist/commands/improve/source-identity.js +0 -28
  294. package/dist/commands/improve/triage.js +0 -96
  295. package/dist/commands/proposal/drain-policies.js +0 -151
  296. package/dist/commands/sources/update-transaction.js +0 -220
  297. package/dist/core/action-contributors.js +0 -28
  298. package/dist/core/config/config-version-shim.js +0 -101
  299. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  300. package/dist/core/fs-txn.js +0 -405
  301. package/dist/core/lexical-score.js +0 -25
  302. package/dist/core/maintenance-barrier.js +0 -167
  303. package/dist/execution/executable-identity.js +0 -105
  304. package/dist/execution/guarded-source.js +0 -427
  305. package/dist/indexer/graph/graph-boost.js +0 -427
  306. package/dist/indexer/graph/graph-dedup.js +0 -95
  307. package/dist/indexer/search/name-match.js +0 -35
  308. package/dist/indexer/search/ranking-contributors.js +0 -515
  309. package/dist/indexer/walk/project-context.js +0 -192
  310. package/dist/integrations/agent/execution-cascade.js +0 -566
  311. package/dist/integrations/agent/execution-definitions.js +0 -202
  312. package/dist/integrations/agent/execution-lowering.js +0 -841
  313. package/dist/integrations/agent/execution-preparation.js +0 -98
  314. package/dist/integrations/agent/inline-execution.js +0 -74
  315. package/dist/registry/create-provider-registry.js +0 -29
  316. package/dist/registry/pinned-request-helper.js +0 -247
  317. package/dist/registry/pinned-transport.js +0 -717
  318. package/dist/sources/providers/index.js +0 -14
  319. package/dist/storage/engines/sqlite-migrations.js +0 -271
  320. package/dist/storage/repositories/canaries-repository.js +0 -107
  321. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  322. package/dist/storage/repositories/registry-cache.js +0 -113
  323. package/dist/tasks/scheduler-sync-preview.js +0 -52
  324. package/dist/workflows/freeze/resolve-steps.js +0 -86
  325. package/dist/workflows/freeze/source-freeze.js +0 -64
  326. package/dist/workflows/ir/compile.js +0 -321
  327. package/dist/workflows/ir/environment-v4.js +0 -330
  328. package/dist/workflows/ir/freeze-v4.js +0 -153
  329. package/dist/workflows/ir/schema-v4.js +0 -745
  330. package/dist/workflows/ir/schema.js +0 -354
  331. package/dist/workflows/program/schema.js +0 -78
  332. package/dist/workflows/runtime/checkin.js +0 -57
  333. package/dist/workflows/runtime/plan-classifier.js +0 -196
  334. package/dist/workflows/runtime/unit-checkin.js +0 -45
  335. package/dist/workflows/runtime/unit-phases.js +0 -20
  336. package/dist/workflows/schema.js +0 -4
  337. package/dist/workflows/source-ir/compile.js +0 -200
  338. package/dist/workflows/source-ir/program.js +0 -50
  339. package/dist/workflows/source-ir/result.js +0 -26
  340. package/dist/workflows/source-ir/schema.js +0 -786
  341. package/dist/workflows/source-ir/triggers.js +0 -79
  342. package/dist/workflows/source-ir/uses.js +0 -40
  343. package/dist/workflows/validator.js +0 -60
@@ -125,13 +125,8 @@ export function validateStashEntry(entry) {
125
125
  result.cwd = e.cwd.trim();
126
126
  if (typeof e.fileSize === "number" && Number.isFinite(e.fileSize) && e.fileSize >= 0)
127
127
  result.fileSize = e.fileSize;
128
- if (e.wikiRole === "schema" ||
129
- e.wikiRole === "index" ||
130
- e.wikiRole === "log" ||
131
- e.wikiRole === "raw" ||
132
- e.wikiRole === "page") {
128
+ if (isWikiRole(e.wikiRole))
133
129
  result.wikiRole = e.wikiRole;
134
- }
135
130
  if (typeof e.pageKind === "string" && e.pageKind.trim().length > 0) {
136
131
  result.pageKind = e.pageKind.trim();
137
132
  }
@@ -155,12 +150,6 @@ export function validateStashEntry(entry) {
155
150
  const contradictedBy = normalizeNonEmptyStringList(e.contradictedBy);
156
151
  if (contradictedBy)
157
152
  result.contradictedBy = contradictedBy;
158
- // R5 — consolidation provenance fields must survive the whitelist too, or
159
- // stash.json-overridden merge products lose merge-following + generation
160
- // counting in the collapse detector.
161
- if (typeof e.generation === "number" && Number.isFinite(e.generation) && e.generation > 0) {
162
- result.generation = Math.floor(e.generation);
163
- }
164
153
  const currentBeliefRefs = normalizeNonEmptyStringList(e.currentBeliefRefs);
165
154
  if (currentBeliefRefs)
166
155
  result.currentBeliefRefs = currentBeliefRefs;
@@ -269,9 +258,6 @@ function normalizeIntent(value) {
269
258
  intent.output = output;
270
259
  return Object.keys(intent).length > 0 ? intent : undefined;
271
260
  }
272
- function normalizeStringListOrUndefined(value) {
273
- return normalizeNonEmptyStringList(value);
274
- }
275
261
  /**
276
262
  * Normalize a current derived-memory parent ref to its `memories/<name>`
277
263
  * conceptId for the `derived_from` column. Returns `undefined` for a non-memory
@@ -318,19 +304,19 @@ export function applyCuratedFrontmatter(entry, fmData) {
318
304
  entry.source = "frontmatter";
319
305
  entry.confidence = 0.9;
320
306
  }
321
- const tags = normalizeStringListOrUndefined(fmData.tags);
307
+ const tags = normalizeNonEmptyStringList(fmData.tags);
322
308
  if (tags)
323
309
  entry.tags = normalizeTerms(tags);
324
- const aliases = normalizeStringListOrUndefined(fmData.aliases);
310
+ const aliases = normalizeNonEmptyStringList(fmData.aliases);
325
311
  if (aliases)
326
312
  entry.aliases = normalizeTerms(aliases);
327
- const searchHints = normalizeStringListOrUndefined(fmData.searchHints);
313
+ const searchHints = normalizeNonEmptyStringList(fmData.searchHints);
328
314
  if (searchHints)
329
315
  entry.searchHints = searchHints;
330
- const usage = normalizeStringListOrUndefined(fmData.usage);
316
+ const usage = normalizeNonEmptyStringList(fmData.usage);
331
317
  if (usage)
332
318
  entry.usage = usage;
333
- const examples = normalizeStringListOrUndefined(fmData.examples);
319
+ const examples = normalizeNonEmptyStringList(fmData.examples);
334
320
  if (examples)
335
321
  entry.examples = examples;
336
322
  const run = asNonEmptyString(fmData.run);
@@ -354,19 +340,13 @@ export function applyCuratedFrontmatter(entry, fmData) {
354
340
  const beliefState = asNonEmptyString(fmData.beliefState);
355
341
  if (beliefState)
356
342
  entry.beliefState = beliefState;
357
- const supersededBy = normalizeStringListOrUndefined(fmData.supersededBy);
343
+ const supersededBy = normalizeNonEmptyStringList(fmData.supersededBy);
358
344
  if (supersededBy)
359
345
  entry.supersededBy = supersededBy;
360
- const contradictedBy = normalizeStringListOrUndefined(fmData.contradictedBy);
346
+ const contradictedBy = normalizeNonEmptyStringList(fmData.contradictedBy);
361
347
  if (contradictedBy)
362
348
  entry.contradictedBy = contradictedBy;
363
- // R5 — consolidation generation depth is captured so the collapse detector
364
- // can count over-generation assets without filesystem reads.
365
- const generation = fmData.generation;
366
- if (typeof generation === "number" && Number.isFinite(generation) && generation > 0) {
367
- entry.generation = Math.floor(generation);
368
- }
369
- const currentBeliefRefs = normalizeStringListOrUndefined(fmData.currentBeliefRefs);
349
+ const currentBeliefRefs = normalizeNonEmptyStringList(fmData.currentBeliefRefs);
370
350
  if (currentBeliefRefs)
371
351
  entry.currentBeliefRefs = currentBeliefRefs;
372
352
  // captureMode: "hot" | "background" — strict whitelist; unknown values are ignored.
@@ -384,7 +364,7 @@ export function applyCuratedFrontmatter(entry, fmData) {
384
364
  else if (typeof fmData.lessonStrength === "number" && Number.isFinite(fmData.lessonStrength)) {
385
365
  entry.lessonStrength = Math.max(0, Math.floor(fmData.lessonStrength));
386
366
  }
387
- const evidenceSources = normalizeStringListOrUndefined(fmData.evidenceSources);
367
+ const evidenceSources = normalizeNonEmptyStringList(fmData.evidenceSources);
388
368
  if (evidenceSources)
389
369
  entry.evidenceSources = evidenceSources;
390
370
  // Phase 5A / Advantage D5: capture parent ref for derived memories.
@@ -456,30 +436,22 @@ export function extractCommandParameters(template) {
456
436
  * frontmatter block and apply them to the entry. Tolerates missing or malformed values.
457
437
  */
458
438
  export function applyWikiFrontmatter(entry, fmData) {
459
- const role = fmData.wikiRole;
460
- if (role === "schema" || role === "index" || role === "log" || role === "raw" || role === "page") {
461
- entry.wikiRole = role;
462
- }
439
+ if (isWikiRole(fmData.wikiRole))
440
+ entry.wikiRole = fmData.wikiRole;
463
441
  const pageKind = fmData.pageKind;
464
442
  if (typeof pageKind === "string" && pageKind.trim().length > 0) {
465
443
  entry.pageKind = pageKind.trim();
466
444
  }
467
- const xrefs = fmData.xrefs;
468
- if (Array.isArray(xrefs)) {
469
- const filtered = xrefs
470
- .filter((x) => typeof x === "string" && x.trim().length > 0)
471
- .map((x) => x.trim());
472
- if (filtered.length > 0)
473
- entry.xrefs = filtered;
474
- }
475
- const sources = fmData.sources;
476
- if (Array.isArray(sources)) {
477
- const filtered = sources
478
- .filter((s) => typeof s === "string" && s.trim().length > 0)
479
- .map((s) => s.trim());
480
- if (filtered.length > 0)
481
- entry.sources = filtered;
482
- }
445
+ // Only lists: a bare string is not a citation list here.
446
+ const xrefs = Array.isArray(fmData.xrefs) ? normalizeNonEmptyStringList(fmData.xrefs) : undefined;
447
+ if (xrefs)
448
+ entry.xrefs = xrefs;
449
+ const sources = Array.isArray(fmData.sources) ? normalizeNonEmptyStringList(fmData.sources) : undefined;
450
+ if (sources)
451
+ entry.sources = sources;
452
+ }
453
+ function isWikiRole(value) {
454
+ return value === "schema" || value === "index" || value === "log" || value === "raw" || value === "page";
483
455
  }
484
456
  /**
485
457
  * Parse one `verified:` family value into the `IndexDocument.provenance` shape.
@@ -679,6 +651,26 @@ function parseIntentCommentLine(cleaned, metadata) {
679
651
  metadata.intent.when ??= value;
680
652
  return true;
681
653
  }
654
+ /** `@tag value` comment lines, in match order; the first matching tag wins a line. */
655
+ const COMMENT_TAGS = [
656
+ [/^@description\s+(.+)$/, (m, v) => (m.description = v.trim())],
657
+ [/^@tags?\s+(.+)$/, (m, v) => (m.tags = splitCommentList(v))],
658
+ [/^@aliases?\s+(.+)$/, (m, v) => (m.aliases = splitCommentList(v))],
659
+ [/^@searchHints?\s+(.+)$/, (m, v) => (m.searchHints = splitCommentList(v))],
660
+ [/^@usage\s+(.+)$/, (m, v) => (m.usage = [...(m.usage ?? []), v.trim()])],
661
+ [/^@examples?\s+(.+)$/, (m, v) => (m.examples = [...(m.examples ?? []), v.trim()])],
662
+ [/^@run\s+(.+)$/, (m, v) => (m.run = v.trim())],
663
+ [/^@setup\s+(.+)$/, (m, v) => (m.setup = v.trim())],
664
+ [/^@cwd\s+(.+)$/, (m, v) => (m.cwd = v.trim())],
665
+ [
666
+ /^@scope\s+(.+)$/,
667
+ (m, v) => {
668
+ const scope = parseCommentScope(v);
669
+ if (scope)
670
+ m.scope = scope;
671
+ },
672
+ ],
673
+ ];
682
674
  export function extractCommentMetadata(filePath, content) {
683
675
  if (content === undefined) {
684
676
  try {
@@ -702,56 +694,12 @@ export function extractCommentMetadata(filePath, content) {
702
694
  continue;
703
695
  if (parseIntentCommentLine(cleaned, metadata))
704
696
  continue;
705
- const descMatch = cleaned.match(/^@description\s+(.+)$/);
706
- if (descMatch) {
707
- metadata.description = descMatch[1].trim();
708
- continue;
709
- }
710
- const tagsMatch = cleaned.match(/^@tags?\s+(.+)$/);
711
- if (tagsMatch) {
712
- metadata.tags = splitCommentList(tagsMatch[1]);
713
- continue;
714
- }
715
- const aliasesMatch = cleaned.match(/^@aliases?\s+(.+)$/);
716
- if (aliasesMatch) {
717
- metadata.aliases = splitCommentList(aliasesMatch[1]);
718
- continue;
719
- }
720
- const hintsMatch = cleaned.match(/^@searchHints?\s+(.+)$/);
721
- if (hintsMatch) {
722
- metadata.searchHints = splitCommentList(hintsMatch[1]);
723
- continue;
724
- }
725
- const usageMatch = cleaned.match(/^@usage\s+(.+)$/);
726
- if (usageMatch) {
727
- metadata.usage = [...(metadata.usage ?? []), usageMatch[1].trim()];
728
- continue;
729
- }
730
- const examplesMatch = cleaned.match(/^@examples?\s+(.+)$/);
731
- if (examplesMatch) {
732
- metadata.examples = [...(metadata.examples ?? []), examplesMatch[1].trim()];
733
- continue;
734
- }
735
- const runMatch = cleaned.match(/^@run\s+(.+)$/);
736
- if (runMatch) {
737
- metadata.run = runMatch[1].trim();
738
- continue;
739
- }
740
- const setupMatch = cleaned.match(/^@setup\s+(.+)$/);
741
- if (setupMatch) {
742
- metadata.setup = setupMatch[1].trim();
743
- continue;
744
- }
745
- const cwdMatch = cleaned.match(/^@cwd\s+(.+)$/);
746
- if (cwdMatch) {
747
- metadata.cwd = cwdMatch[1].trim();
748
- continue;
749
- }
750
- const scopeMatch = cleaned.match(/^@scope\s+(.+)$/);
751
- if (scopeMatch) {
752
- const scope = parseCommentScope(scopeMatch[1]);
753
- if (scope)
754
- metadata.scope = scope;
697
+ for (const [pattern, apply] of COMMENT_TAGS) {
698
+ const match = cleaned.match(pattern);
699
+ if (match) {
700
+ apply(metadata, match[1]);
701
+ break;
702
+ }
755
703
  }
756
704
  }
757
705
  return Object.keys(metadata).length > 0 ? metadata : undefined;
@@ -760,50 +708,32 @@ export function applyCommentMetadata(entry, metadata) {
760
708
  if (!metadata)
761
709
  return;
762
710
  let usedCommentMetadata = false;
763
- if (metadata.description && !entry.description) {
764
- entry.description = metadata.description;
765
- usedCommentMetadata = true;
766
- }
767
- if (metadata.tags?.length && (!entry.tags || entry.tags.length === 0)) {
768
- entry.tags = normalizeTerms(metadata.tags);
769
- usedCommentMetadata = true;
770
- }
771
- if (metadata.aliases?.length) {
772
- entry.aliases = normalizeTerms(metadata.aliases);
711
+ const use = (key, value) => {
712
+ entry[key] = value;
773
713
  usedCommentMetadata = true;
774
- }
775
- if (metadata.searchHints?.length) {
776
- entry.searchHints = metadata.searchHints;
777
- usedCommentMetadata = true;
778
- }
779
- if (metadata.usage?.length) {
780
- entry.usage = metadata.usage;
781
- usedCommentMetadata = true;
782
- }
783
- if (metadata.examples?.length) {
784
- entry.examples = metadata.examples;
785
- usedCommentMetadata = true;
786
- }
787
- if (metadata.intent && Object.keys(metadata.intent).length > 0) {
788
- entry.intent = metadata.intent;
789
- usedCommentMetadata = true;
790
- }
791
- if (metadata.run) {
792
- entry.run = metadata.run;
793
- usedCommentMetadata = true;
794
- }
795
- if (metadata.setup) {
796
- entry.setup = metadata.setup;
797
- usedCommentMetadata = true;
798
- }
799
- if (metadata.cwd) {
800
- entry.cwd = metadata.cwd;
801
- usedCommentMetadata = true;
802
- }
803
- if (metadata.scope) {
804
- entry.scope = metadata.scope;
805
- usedCommentMetadata = true;
806
- }
714
+ };
715
+ if (metadata.description && !entry.description)
716
+ use("description", metadata.description);
717
+ if (metadata.tags?.length && (!entry.tags || entry.tags.length === 0))
718
+ use("tags", normalizeTerms(metadata.tags));
719
+ if (metadata.aliases?.length)
720
+ use("aliases", normalizeTerms(metadata.aliases));
721
+ if (metadata.searchHints?.length)
722
+ use("searchHints", metadata.searchHints);
723
+ if (metadata.usage?.length)
724
+ use("usage", metadata.usage);
725
+ if (metadata.examples?.length)
726
+ use("examples", metadata.examples);
727
+ if (metadata.intent && Object.keys(metadata.intent).length > 0)
728
+ use("intent", metadata.intent);
729
+ if (metadata.run)
730
+ use("run", metadata.run);
731
+ if (metadata.setup)
732
+ use("setup", metadata.setup);
733
+ if (metadata.cwd)
734
+ use("cwd", metadata.cwd);
735
+ if (metadata.scope)
736
+ use("scope", metadata.scope);
807
737
  if (usedCommentMetadata && entry.source !== "frontmatter" && entry.source !== "manual") {
808
738
  entry.source = "comments";
809
739
  entry.confidence = Math.max(entry.confidence ?? 0, 0.7);
@@ -1131,36 +1061,14 @@ export function projectMarkdownContent(body, truncationInfo) {
1131
1061
  const innerBlock = findInnerFrontmatterBlock(lines);
1132
1062
  const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
1133
1063
  const projected = [];
1134
- let fence;
1135
- const htmlComment = { inComment: false };
1136
- for (let i = start; i < lines.length; i += 1) {
1137
- const rawLine = lines[i];
1138
- if (fence) {
1139
- if (isMarkdownFenceClosing(rawLine, fence))
1140
- fence = undefined;
1141
- continue;
1142
- }
1143
- // A leading fence owns the whole line, including any info string that
1144
- // resembles HTML. Comment state therefore cannot begin inside a fence.
1145
- if (!htmlComment.inComment) {
1146
- const openingFence = parseMarkdownFenceOpening(rawLine);
1147
- if (openingFence) {
1148
- fence = openingFence;
1149
- continue;
1150
- }
1151
- }
1152
- let trimmed = stripMarkdownHtmlComments(rawLine, htmlComment).trim();
1153
- const openingFence = parseMarkdownFenceOpening(trimmed);
1154
- if (openingFence) {
1155
- fence = openingFence;
1156
- continue;
1157
- }
1064
+ forEachVisibleMarkdownLine(lines, start, (_index, visible) => {
1065
+ let trimmed = visible.trim();
1158
1066
  if (!trimmed || /^(-{3,}|\*{3,}|_{3,}|=+)$/.test(trimmed))
1159
- continue;
1067
+ return;
1160
1068
  if (/^\s*\[[^\]]+\]:\s*\S+/.test(trimmed))
1161
- continue;
1069
+ return;
1162
1070
  if (/^<[^>]+>$/.test(trimmed))
1163
- continue;
1071
+ return;
1164
1072
  // Preserve human-facing labels and inline identifiers, never destinations.
1165
1073
  trimmed = stripMarkdownLinkDestinations(trimmed);
1166
1074
  trimmed = trimmed.replace(/`{1,2}([^`]+)`{1,2}/g, "$1");
@@ -1171,7 +1079,7 @@ export function projectMarkdownContent(body, truncationInfo) {
1171
1079
  trimmed = trimmed.replace(/\s+/g, " ").trim();
1172
1080
  if (trimmed)
1173
1081
  projected.push(trimmed);
1174
- }
1082
+ });
1175
1083
  const text = projected.join(" ").replace(/\s+/g, " ").trim();
1176
1084
  if (!text)
1177
1085
  return undefined;
@@ -1179,6 +1087,36 @@ export function projectMarkdownContent(body, truncationInfo) {
1179
1087
  truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
1180
1088
  return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
1181
1089
  }
1090
+ /**
1091
+ * Visit each line from `start` that lies outside fenced code, with HTML
1092
+ * comments removed (`visible`); fence lines themselves are never visited.
1093
+ */
1094
+ function forEachVisibleMarkdownLine(lines, start, visit) {
1095
+ let fence;
1096
+ const htmlComment = { inComment: false };
1097
+ for (let index = start; index < lines.length; index += 1) {
1098
+ const rawLine = lines[index];
1099
+ if (fence) {
1100
+ if (isMarkdownFenceClosing(rawLine, fence))
1101
+ fence = undefined;
1102
+ continue;
1103
+ }
1104
+ // A leading fence owns the whole line, including any info string that
1105
+ // resembles HTML. Comment state therefore cannot begin inside a fence.
1106
+ const leadingFence = htmlComment.inComment ? undefined : parseMarkdownFenceOpening(rawLine);
1107
+ if (leadingFence) {
1108
+ fence = leadingFence;
1109
+ continue;
1110
+ }
1111
+ const visible = stripMarkdownHtmlComments(rawLine, htmlComment);
1112
+ const openingFence = parseMarkdownFenceOpening(visible.trim());
1113
+ if (openingFence) {
1114
+ fence = openingFence;
1115
+ continue;
1116
+ }
1117
+ visit(index, visible);
1118
+ }
1119
+ }
1182
1120
  // Fragment text is intentionally not an IndexDocument field. IndexDocument is
1183
1121
  // an adapter/search payload boundary; this is an internal, derived index input
1184
1122
  // that is persisted separately by the entries repository for deterministic FTS
@@ -1197,6 +1135,21 @@ export function getMarkdownFragmentContent(entry) {
1197
1135
  export function hasMarkdownFragmentContent(entry) {
1198
1136
  return markdownFragmentProjectionEntries.has(entry);
1199
1137
  }
1138
+ /**
1139
+ * A copy of `entry` carrying `filePath`'s size (and its fragment projection),
1140
+ * or `entry` itself when the file cannot be stat'ed.
1141
+ */
1142
+ export function withFileSize(entry, filePath) {
1143
+ try {
1144
+ const sized = { ...entry, fileSize: fs.statSync(filePath).size };
1145
+ if (hasMarkdownFragmentContent(entry))
1146
+ setMarkdownFragmentContent(sized, getMarkdownFragmentContent(entry));
1147
+ return sized;
1148
+ }
1149
+ catch {
1150
+ return entry;
1151
+ }
1152
+ }
1200
1153
  /**
1201
1154
  * Produce a safe, structure-preserving projection for fragment indexing.
1202
1155
  * Excluded source lines are retained as blank lines so fragment locations map
@@ -1206,37 +1159,16 @@ export function hasMarkdownFragmentContent(entry) {
1206
1159
  export function projectMarkdownFragmentContent(raw) {
1207
1160
  const lines = raw.split(/\r?\n/);
1208
1161
  const parsed = parseFrontmatter(raw);
1209
- const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0;
1210
1162
  const projected = lines.map(() => "");
1211
- let fence;
1212
- const htmlComment = { inComment: false };
1213
- for (let index = start; index < lines.length; index++) {
1214
- const rawLine = lines[index];
1215
- if (fence) {
1216
- if (isMarkdownFenceClosing(rawLine, fence))
1217
- fence = undefined;
1218
- continue;
1219
- }
1220
- if (!htmlComment.inComment) {
1221
- const opening = parseMarkdownFenceOpening(rawLine);
1222
- if (opening) {
1223
- fence = opening;
1224
- continue;
1225
- }
1226
- }
1227
- let safe = stripMarkdownHtmlComments(rawLine, htmlComment);
1228
- const opening = parseMarkdownFenceOpening(safe.trim());
1229
- if (opening) {
1230
- fence = opening;
1231
- continue;
1232
- }
1163
+ forEachVisibleMarkdownLine(lines, parsed.frontmatter ? parsed.bodyStartLine - 1 : 0, (index, visible) => {
1233
1164
  // Reference link destinations and standalone HTML are not retrieval
1234
1165
  // evidence and can contain credential-bearing URLs.
1235
- if (/^\s*\[[^\]]+\]:\s*\S+/.test(safe) || /^\s*<[^>]+>\s*$/.test(safe))
1236
- continue;
1237
- safe = stripMarkdownLinkDestinations(safe).replace(/<[^>]+>/g, " ");
1238
- projected[index] = safe.replace(/[ \t]+$/g, "");
1239
- }
1166
+ if (/^\s*\[[^\]]+\]:\s*\S+/.test(visible) || /^\s*<[^>]+>\s*$/.test(visible))
1167
+ return;
1168
+ projected[index] = stripMarkdownLinkDestinations(visible)
1169
+ .replace(/<[^>]+>/g, " ")
1170
+ .replace(/[ \t]+$/g, "");
1171
+ });
1240
1172
  const text = projected.join("\n");
1241
1173
  return text.trim() ? text : undefined;
1242
1174
  }
@@ -1350,7 +1282,7 @@ export function applyPostContributorFields(entry, file, canonicalName, dirPath)
1350
1282
  entry.tags = [...(entry.tags ?? []), ...extractDirTagsFromName(canonicalName)];
1351
1283
  entry.tags = normalizeTerms(entry.tags ?? []);
1352
1284
  entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
1353
- // Search hints are only generated when LLM is configured (via enhanceStashWithLlm)
1285
+ // Search hints are only generated when LLM is configured (via enhanceEntriesWithLlm)
1354
1286
  // Heuristic search hints are too noisy to be useful for search quality
1355
1287
  entry.filename = path.basename(file);
1356
1288
  }
@@ -14,10 +14,3 @@ export async function ensurePrimaryIndexForRead(primarySource) {
14
14
  return false;
15
15
  return ensureIndex(primarySource.path);
16
16
  }
17
- /**
18
- * Convenience helper for callers that only need to ensure a read index from a
19
- * configured stash path and default config.
20
- */
21
- export async function ensurePrimaryIndexFromConfig(overrideStashDir, existingConfig) {
22
- return ensurePrimaryIndexForRead(resolveReadSources(overrideStashDir, existingConfig).primarySource);
23
- }
@@ -27,7 +27,7 @@
27
27
  * `basename(file)` in `applyPostContributorFields`, and `doc.path` IS that
28
28
  * file, so the value is identical.
29
29
  * - `fileSize` — never set by `recognize` NOR by the legacy flat-walk pass;
30
- * both pipelines attach it at PERSIST time (`attachFileSize`). It is therefore
30
+ * both pipelines attach it at PERSIST time (`withFileSize`). It is therefore
31
31
  * intentionally absent here and added by the persist layer, exactly as
32
32
  * before.
33
33
  *
@@ -137,8 +137,6 @@ export function indexDocumentToStashEntry(doc) {
137
137
  if (dj.wikiRole !== undefined)
138
138
  entry.wikiRole = dj.wikiRole;
139
139
  assignStringList(entry, "sources", dj.sources);
140
- if (typeof dj.generation === "number")
141
- entry.generation = dj.generation;
142
140
  assignStringList(entry, "evidenceSources", dj.evidenceSources);
143
141
  // D2 (#730): OKF v0.2 provenance promoteProposal stamps onto AKM-native
144
142
  // writes, carried via DOCUMENT_JSON_CARRIED_FIELDS (akm-adapter.ts) —
@@ -30,8 +30,8 @@ import path from "node:path";
30
30
  import { akmAdapter } from "../../core/adapter/adapters/akm-adapter.js";
31
31
  import { compareCodePoints } from "../../core/common.js";
32
32
  import { canonicalizeWorkflowName } from "../../core/recognition-util.js";
33
+ import { compileWorkflowSource } from "../../workflows/compile.js";
33
34
  import { resolveWorkflowSourceDomains, workflowNameForSourcePath } from "../../workflows/source-files.js";
34
- import { compileWorkflowSource } from "../../workflows/source-ir/compile.js";
35
35
  import { buildMetadataSkipWarning } from "../passes/metadata.js";
36
36
  import { buildFileContext } from "../walk/file-context.js";
37
37
  import { indexDocumentToStashEntry } from "./doc-to-entry.js";