akm-cli 0.9.0-rc.1 → 0.9.0-rc.13

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 (587) hide show
  1. package/CHANGELOG.md +1190 -52
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/stash-skeleton/README.md +38 -10
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  38. package/dist/assets/tasks/core/extract.yml +3 -2
  39. package/dist/assets/tasks/core/improve.yml +2 -1
  40. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  41. package/dist/assets/tasks/core/sync.yml +1 -0
  42. package/dist/assets/tasks/core/version-check.yml +2 -1
  43. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  44. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  45. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  46. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  48. package/dist/assets/templates/html/health.html +5 -4
  49. package/dist/assets/workflows/workflow-template.md +31 -15
  50. package/dist/cli/invocation.js +279 -0
  51. package/dist/cli/parse-args.js +5 -90
  52. package/dist/cli/retired-commands.js +78 -0
  53. package/dist/cli/shared.js +158 -48
  54. package/dist/cli-node.mjs +2 -1
  55. package/dist/cli.js +747 -293
  56. package/dist/commands/agent/agent-dispatch.js +19 -18
  57. package/dist/commands/agent/agent-support.js +0 -24
  58. package/dist/commands/agent/contribute-cli.js +43 -97
  59. package/dist/commands/completions.js +80 -23
  60. package/dist/commands/config-cli.js +44 -281
  61. package/dist/commands/env/env-binding.js +13 -9
  62. package/dist/commands/env/env-cli.js +76 -159
  63. package/dist/commands/env/env.js +12 -163
  64. package/dist/commands/env/marker-path.js +6 -0
  65. package/dist/commands/env/secret-cli.js +45 -61
  66. package/dist/commands/env/secret.js +32 -62
  67. package/dist/commands/feedback-cli.js +179 -85
  68. package/dist/commands/health/accept-rate.js +58 -0
  69. package/dist/commands/health/advisories.js +7 -8
  70. package/dist/commands/health/checks.js +279 -94
  71. package/dist/commands/health/html-report.js +197 -578
  72. package/dist/commands/health/improve-metrics.js +277 -246
  73. package/dist/commands/health/llm-usage.js +19 -19
  74. package/dist/commands/health/md-report.js +16 -7
  75. package/dist/commands/health/metrics.js +67 -32
  76. package/dist/commands/health/renderers.js +47 -0
  77. package/dist/commands/health/report-view-model.js +508 -0
  78. package/dist/commands/health/stash-exposure.js +1 -1
  79. package/dist/commands/health/surfaces.js +16 -56
  80. package/dist/commands/health/task-runs.js +3 -67
  81. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  82. package/dist/commands/health/types-improve.js +29 -0
  83. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  84. package/dist/commands/health/types-result.js +7 -0
  85. package/dist/commands/health/types-runs.js +4 -0
  86. package/dist/commands/health/types-session-log.js +4 -0
  87. package/dist/commands/health/types-windows.js +4 -0
  88. package/dist/commands/health/types.js +26 -21
  89. package/dist/commands/health/windows.js +2 -3
  90. package/dist/commands/health.js +296 -167
  91. package/dist/commands/improve/anti-collapse.js +5 -5
  92. package/dist/commands/improve/autonomy-gate.js +68 -0
  93. package/dist/commands/improve/collapse-detector.js +65 -52
  94. package/dist/commands/improve/consolidate/chunking.js +9 -7
  95. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  96. package/dist/commands/improve/consolidate/merge.js +4 -0
  97. package/dist/commands/improve/consolidate.js +454 -1354
  98. package/dist/commands/improve/content-hash.js +39 -0
  99. package/dist/commands/improve/distill/content-repair.js +4 -10
  100. package/dist/commands/improve/distill/promote-memory.js +89 -64
  101. package/dist/commands/improve/distill/quality-gate.js +118 -42
  102. package/dist/commands/improve/distill-guards.js +1 -1
  103. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  104. package/dist/commands/improve/distill.js +607 -363
  105. package/dist/commands/improve/eligibility.js +165 -79
  106. package/dist/commands/improve/extract-cli.js +35 -126
  107. package/dist/commands/improve/extract-prompt.js +6 -35
  108. package/dist/commands/improve/extract.js +640 -391
  109. package/dist/commands/improve/feedback-valence.js +2 -12
  110. package/dist/commands/improve/improve-cli.js +134 -135
  111. package/dist/commands/improve/improve-result-file.js +30 -50
  112. package/dist/commands/improve/improve-run-types.js +4 -0
  113. package/dist/commands/improve/improve-strategies.js +135 -0
  114. package/dist/commands/improve/improve.js +904 -701
  115. package/dist/commands/improve/locks.js +64 -111
  116. package/dist/commands/improve/loop-stages.js +1110 -923
  117. package/dist/commands/improve/memory/derived-ref.js +124 -0
  118. package/dist/commands/improve/memory/memory-belief.js +79 -7
  119. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  120. package/dist/commands/improve/memory/memory-improve.js +25 -37
  121. package/dist/commands/improve/outcome-loop.js +25 -88
  122. package/dist/commands/improve/preparation.js +1034 -813
  123. package/dist/commands/improve/proactive-maintenance.js +34 -9
  124. package/dist/commands/improve/proposal-envelope.js +31 -0
  125. package/dist/commands/improve/reflect.js +983 -794
  126. package/dist/commands/improve/run-context.js +119 -0
  127. package/dist/commands/improve/salience.js +24 -127
  128. package/dist/commands/improve/session-asset.js +7 -3
  129. package/dist/commands/improve/shared.js +14 -34
  130. package/dist/commands/improve/source-identity.js +28 -0
  131. package/dist/commands/improve/triage.js +20 -17
  132. package/dist/commands/lint/base-linter.js +340 -313
  133. package/dist/commands/lint/env-key-rules.js +31 -47
  134. package/dist/commands/lint/index.js +185 -30
  135. package/dist/commands/{events.js → log.js} +28 -38
  136. package/dist/commands/migrate-cli.js +54 -0
  137. package/dist/commands/migration-tool.js +55 -0
  138. package/dist/commands/observability-cli.js +70 -208
  139. package/dist/commands/proposal/diff-format.js +50 -0
  140. package/dist/commands/proposal/drain-policies.js +0 -6
  141. package/dist/commands/proposal/drain.js +91 -40
  142. package/dist/commands/proposal/proposal-cli.js +134 -132
  143. package/dist/commands/proposal/proposal-types.js +56 -0
  144. package/dist/commands/proposal/proposal.js +83 -65
  145. package/dist/commands/proposal/propose-cli.js +88 -0
  146. package/dist/commands/proposal/propose.js +105 -88
  147. package/dist/commands/proposal/repository.js +1303 -278
  148. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  149. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  150. package/dist/commands/proposal/validators/proposals.js +6 -8
  151. package/dist/commands/read/curate.js +78 -73
  152. package/dist/commands/read/knowledge.js +510 -13
  153. package/dist/commands/read/registry-search.js +2 -2
  154. package/dist/commands/read/remember-cli.js +84 -15
  155. package/dist/commands/read/search-cli.js +203 -96
  156. package/dist/commands/read/search.js +126 -94
  157. package/dist/commands/read/show.js +226 -250
  158. package/dist/commands/registry-cli.js +34 -60
  159. package/dist/commands/remember.js +18 -57
  160. package/dist/commands/sources/add-cli.js +104 -49
  161. package/dist/commands/sources/bundle-cli.js +166 -0
  162. package/dist/commands/sources/bundle-config-ops.js +63 -0
  163. package/dist/commands/sources/info.js +27 -15
  164. package/dist/commands/sources/init.js +30 -40
  165. package/dist/commands/sources/installed-stashes.js +469 -172
  166. package/dist/commands/sources/schema-repair.js +10 -9
  167. package/dist/commands/sources/self-update.js +182 -121
  168. package/dist/commands/sources/source-add.js +169 -178
  169. package/dist/commands/sources/source-clone.js +144 -41
  170. package/dist/commands/sources/source-manage.js +94 -59
  171. package/dist/commands/sources/sources-cli.js +64 -205
  172. package/dist/commands/sources/stash-cli.js +91 -54
  173. package/dist/commands/sources/stash-skeleton.js +1 -1
  174. package/dist/commands/tasks/tasks-cli.js +106 -104
  175. package/dist/commands/tasks/tasks.js +445 -262
  176. package/dist/commands/workflow-cli.js +75 -228
  177. package/dist/core/action-contributors.js +1 -1
  178. package/dist/core/activation-policy.js +49 -0
  179. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  180. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  181. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  182. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  183. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  184. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  185. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  186. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  187. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  188. package/dist/core/adapter/adapters/index.js +80 -0
  189. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  190. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  191. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  192. package/dist/core/adapter/adapters/shared.js +286 -0
  193. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  194. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  195. package/dist/core/adapter/bundle-adapter.js +4 -0
  196. package/dist/core/adapter/detect-adapter.js +17 -0
  197. package/dist/core/adapter/recognize-match.js +44 -0
  198. package/dist/core/adapter/registry.js +56 -0
  199. package/dist/core/adapter/types.js +4 -0
  200. package/dist/core/asset/akm-markdown.js +30 -0
  201. package/dist/core/asset/asset-placement.js +243 -0
  202. package/dist/core/asset/asset-ref.js +110 -79
  203. package/dist/core/asset/asset-serialize.js +20 -0
  204. package/dist/core/asset/frontmatter.js +28 -12
  205. package/dist/core/asset/markdown.js +40 -51
  206. package/dist/core/asset/resolve-ref.js +274 -0
  207. package/dist/core/asset/stash-meta.js +2 -2
  208. package/dist/core/bundle-id.js +51 -0
  209. package/dist/core/common.js +281 -86
  210. package/dist/core/config/config-io.js +42 -128
  211. package/dist/core/config/config-schema.js +233 -855
  212. package/dist/core/config/config-sources.js +162 -39
  213. package/dist/core/config/config-types.js +16 -11
  214. package/dist/core/config/config-version.js +29 -0
  215. package/dist/core/config/config-walker.js +126 -37
  216. package/dist/core/config/config.js +154 -331
  217. package/dist/core/config/deep-merge.js +41 -0
  218. package/dist/core/config/engine-semantics.js +28 -0
  219. package/dist/core/config/experimental.js +21 -0
  220. package/dist/core/config/schema/embedding.js +38 -0
  221. package/dist/core/config/schema/engines.js +116 -0
  222. package/dist/core/config/schema/experimental.js +47 -0
  223. package/dist/core/config/schema/feedback.js +31 -0
  224. package/dist/core/config/schema/improve-processes.js +389 -0
  225. package/dist/core/config/schema/improve.js +94 -0
  226. package/dist/core/config/schema/index-config.js +176 -0
  227. package/dist/core/config/schema/output.js +18 -0
  228. package/dist/core/config/schema/primitives.js +94 -0
  229. package/dist/core/config/schema/search.js +30 -0
  230. package/dist/core/config/schema/setup.js +18 -0
  231. package/dist/core/config/schema/sources-bundles.js +169 -0
  232. package/dist/core/config/schema/workflow.js +29 -0
  233. package/dist/core/env-secret-ref.js +155 -20
  234. package/dist/core/errors.js +17 -15
  235. package/dist/core/events-types.js +4 -0
  236. package/dist/core/events.js +46 -128
  237. package/dist/core/extra-params.js +62 -0
  238. package/dist/core/file-change.js +17 -0
  239. package/dist/core/file-lock.js +202 -57
  240. package/dist/core/fs-txn.js +392 -0
  241. package/dist/core/git-message.js +59 -0
  242. package/dist/core/improve-result.js +167 -0
  243. package/dist/core/lesson-lint.js +1 -17
  244. package/dist/core/logs-db.js +1 -1
  245. package/dist/core/maintenance-barrier.js +135 -0
  246. package/dist/core/migration-operation.js +44 -0
  247. package/dist/core/mutation-target.js +78 -0
  248. package/dist/core/paths.js +22 -25
  249. package/dist/core/platform.js +10 -0
  250. package/dist/core/recognition-util.js +128 -0
  251. package/dist/core/redaction.js +392 -0
  252. package/dist/core/standards/resolve-standards-context.js +36 -65
  253. package/dist/core/standards/resolve-stash-standards.js +2 -2
  254. package/dist/core/standards/resolve-type-conventions.js +5 -5
  255. package/dist/core/state/migrations.js +242 -11
  256. package/dist/core/state-db.js +98 -10
  257. package/dist/core/structured.js +1 -1
  258. package/dist/core/subprocess.js +303 -0
  259. package/dist/core/text-truncation.js +9 -5
  260. package/dist/core/time.js +20 -0
  261. package/dist/core/type-presentation.js +130 -0
  262. package/dist/core/warn.js +0 -3
  263. package/dist/core/write-source.js +834 -118
  264. package/dist/indexer/bundle-identity-guard.js +92 -0
  265. package/dist/indexer/db/graph-db.js +1 -25
  266. package/dist/indexer/db/llm-cache.js +1 -1
  267. package/dist/indexer/ensure-index.js +30 -9
  268. package/dist/indexer/graph/graph-boost.js +9 -30
  269. package/dist/indexer/graph/graph-extraction.js +41 -27
  270. package/dist/indexer/graph/graph-types.js +4 -0
  271. package/dist/indexer/index-writer-lock.js +93 -49
  272. package/dist/indexer/index-written-assets.js +100 -53
  273. package/dist/indexer/indexer.js +746 -329
  274. package/dist/indexer/init.js +18 -25
  275. package/dist/indexer/installations.js +142 -0
  276. package/dist/indexer/passes/dir-staleness.js +18 -10
  277. package/dist/indexer/passes/memory-inference.js +25 -15
  278. package/dist/indexer/passes/metadata.js +412 -243
  279. package/dist/indexer/scan/doc-to-entry.js +160 -0
  280. package/dist/indexer/scan/drain-dir.js +134 -0
  281. package/dist/indexer/search/db-search.js +292 -108
  282. package/dist/indexer/search/fts-query.js +64 -0
  283. package/dist/indexer/search/ranking-contributors.js +145 -25
  284. package/dist/indexer/search/ranking-types.js +4 -0
  285. package/dist/indexer/search/ranking.js +28 -71
  286. package/dist/indexer/search/search-attribution.js +67 -0
  287. package/dist/indexer/search/search-fields.js +18 -3
  288. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  289. package/dist/indexer/search/search-source.js +157 -111
  290. package/dist/indexer/search/semantic-status.js +4 -1
  291. package/dist/indexer/usage/usage-events.js +10 -30
  292. package/dist/indexer/walk/file-context.js +3 -45
  293. package/dist/indexer/walk/matchers.js +42 -73
  294. package/dist/indexer/walk/path-resolver.js +11 -5
  295. package/dist/indexer/walk/walker.js +42 -14
  296. package/dist/integrations/agent/builder-shared.js +7 -0
  297. package/dist/integrations/agent/builders.js +5 -58
  298. package/dist/integrations/agent/config.js +3 -143
  299. package/dist/integrations/agent/detect.js +17 -2
  300. package/dist/integrations/agent/engine-resolution.js +231 -0
  301. package/dist/integrations/agent/index.js +1 -2
  302. package/dist/integrations/agent/model-aliases.js +8 -3
  303. package/dist/integrations/agent/profiles.js +6 -99
  304. package/dist/integrations/agent/prompts.js +46 -18
  305. package/dist/integrations/agent/runner-dispatch.js +78 -13
  306. package/dist/integrations/agent/runner.js +76 -208
  307. package/dist/integrations/agent/spawn.js +48 -279
  308. package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
  309. package/dist/integrations/harnesses/aider/index.js +2 -12
  310. package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
  311. package/dist/integrations/harnesses/amazonq/index.js +3 -17
  312. package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
  313. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  314. package/dist/integrations/harnesses/claude/index.js +1 -14
  315. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  316. package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
  317. package/dist/integrations/harnesses/codex/index.js +2 -13
  318. package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
  319. package/dist/integrations/harnesses/copilot/index.js +1 -13
  320. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
  321. package/dist/integrations/harnesses/gemini/index.js +1 -13
  322. package/dist/integrations/harnesses/ids.js +24 -0
  323. package/dist/integrations/harnesses/index.js +31 -33
  324. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  325. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  326. package/dist/integrations/harnesses/opencode/index.js +1 -18
  327. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  328. package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
  329. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
  330. package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
  331. package/dist/integrations/harnesses/openhands/index.js +2 -12
  332. package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
  333. package/dist/integrations/harnesses/pi/index.js +3 -16
  334. package/dist/integrations/harnesses/shared.js +17 -0
  335. package/dist/integrations/harnesses/types.js +38 -34
  336. package/dist/integrations/lockfile.js +211 -24
  337. package/dist/integrations/session-logs/index.js +24 -40
  338. package/dist/integrations/session-logs/provider-base.js +113 -0
  339. package/dist/llm/client.js +182 -110
  340. package/dist/llm/embedders/deterministic.js +2 -2
  341. package/dist/llm/embedders/remote.js +21 -9
  342. package/dist/llm/feature-gate.js +17 -57
  343. package/dist/llm/graph-extract.js +12 -13
  344. package/dist/llm/index-passes.js +8 -42
  345. package/dist/llm/memory-infer.js +144 -1
  346. package/dist/llm/metadata-enhance.js +45 -30
  347. package/dist/llm/structured-call.js +16 -8
  348. package/dist/llm/usage-persist.js +30 -5
  349. package/dist/llm/usage-telemetry.js +59 -6
  350. package/dist/output/cli-hints.js +1 -2
  351. package/dist/output/command-registry.js +27 -0
  352. package/dist/output/context.js +22 -7
  353. package/dist/output/format-exempt.js +80 -0
  354. package/dist/output/generic-render.js +251 -0
  355. package/dist/output/html-render.js +11 -16
  356. package/dist/output/render-registry.js +57 -0
  357. package/dist/output/renderers.js +15 -281
  358. package/dist/output/shapes/curate.js +10 -1
  359. package/dist/output/shapes/events.js +12 -7
  360. package/dist/output/shapes/helpers.js +58 -84
  361. package/dist/output/shapes/passthrough.js +8 -40
  362. package/dist/output/shapes/proposal/producer.js +15 -7
  363. package/dist/output/shapes/registry.js +12 -6
  364. package/dist/output/shapes.js +0 -9
  365. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  366. package/dist/output/text/bundle-show.js +7 -0
  367. package/dist/output/text/command-format.js +562 -0
  368. package/dist/output/text/env.js +1 -3
  369. package/dist/output/text/events.js +8 -7
  370. package/dist/output/text/helpers.js +15 -1375
  371. package/dist/output/text/proposal/producer.js +4 -2
  372. package/dist/output/text/proposal-format.js +202 -0
  373. package/dist/output/text/registry-commands.js +1 -2
  374. package/dist/output/text/registry.js +12 -6
  375. package/dist/output/text/show-directives.js +117 -0
  376. package/dist/output/text/show-format.js +103 -0
  377. package/dist/output/text/sync.js +5 -0
  378. package/dist/output/text/workflow-format.js +332 -0
  379. package/dist/output/text/workflow.js +1 -2
  380. package/dist/output/text.js +10 -19
  381. package/dist/registry/factory.js +4 -6
  382. package/dist/registry/origin-resolve.js +16 -27
  383. package/dist/registry/providers/skills-sh.js +3 -3
  384. package/dist/registry/providers/static-index.js +15 -25
  385. package/dist/registry/resolve.js +43 -94
  386. package/dist/registry/semver.js +43 -0
  387. package/dist/runtime.js +81 -12
  388. package/dist/scripts/akm-migrate.js +35529 -0
  389. package/dist/setup/detect.js +5 -7
  390. package/dist/setup/detected-engines.js +136 -0
  391. package/dist/setup/engine-config.js +100 -0
  392. package/dist/setup/registry-stash-loader.js +3 -3
  393. package/dist/setup/semantic-assets.js +12 -9
  394. package/dist/setup/setup.js +444 -208
  395. package/dist/setup/steps/connection-shared.js +120 -0
  396. package/dist/setup/steps/connection.js +108 -305
  397. package/dist/setup/steps/platforms.js +13 -12
  398. package/dist/setup/steps/semantic.js +15 -3
  399. package/dist/setup/steps/sources.js +21 -15
  400. package/dist/setup/steps/stashdir.js +6 -4
  401. package/dist/setup/steps/tasks.js +236 -119
  402. package/dist/setup/steps.js +3 -2
  403. package/dist/sources/freshness.js +39 -0
  404. package/dist/sources/provider-factory.js +11 -17
  405. package/dist/sources/providers/filesystem.js +2 -3
  406. package/dist/sources/providers/git-install.js +278 -34
  407. package/dist/sources/providers/git-provider.js +54 -56
  408. package/dist/sources/providers/git-stash.js +420 -91
  409. package/dist/sources/providers/git.js +2 -2
  410. package/dist/sources/providers/npm.js +16 -19
  411. package/dist/sources/providers/provider-utils.js +47 -22
  412. package/dist/sources/providers/sync-from-ref.js +3 -9
  413. package/dist/sources/providers/website.js +2 -2
  414. package/dist/sources/resolve.js +11 -10
  415. package/dist/sources/snapshot-fetchers/types.js +4 -0
  416. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  417. package/dist/storage/database.js +60 -4
  418. package/dist/storage/engines/sqlite-migrations.js +156 -5
  419. package/dist/storage/locations.js +1 -2
  420. package/dist/storage/repositories/canaries-repository.js +1 -1
  421. package/dist/storage/repositories/events-repository.js +51 -11
  422. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  423. package/dist/storage/repositories/index-connection.js +79 -0
  424. package/dist/storage/repositories/index-db.js +4 -3
  425. package/dist/storage/repositories/index-entries-repository.js +863 -0
  426. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  427. package/dist/storage/repositories/index-entry-types.js +4 -0
  428. package/dist/storage/repositories/index-fts-repository.js +167 -0
  429. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  430. package/dist/storage/repositories/index-meta-repository.js +49 -0
  431. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  432. package/dist/storage/repositories/index-sql.js +12 -0
  433. package/dist/storage/repositories/index-utility-repository.js +356 -0
  434. package/dist/storage/repositories/index-vec-repository.js +250 -0
  435. package/dist/storage/repositories/outcome-repository.js +119 -0
  436. package/dist/storage/repositories/proposals-repository.js +317 -75
  437. package/dist/storage/repositories/registry-cache.js +1 -1
  438. package/dist/storage/repositories/salience-repository.js +172 -0
  439. package/dist/storage/repositories/task-history-repository.js +110 -3
  440. package/dist/storage/repositories/workflow-runs-repository.js +68 -35
  441. package/dist/tasks/backends/cron.js +169 -46
  442. package/dist/tasks/backends/exec-utils.js +76 -3
  443. package/dist/tasks/backends/index.js +6 -9
  444. package/dist/tasks/backends/launchd.js +292 -55
  445. package/dist/tasks/backends/schtasks.js +557 -70
  446. package/dist/tasks/backends/types.js +4 -0
  447. package/dist/tasks/command-executable.js +93 -0
  448. package/dist/tasks/embedded.js +56 -38
  449. package/dist/tasks/parser.js +156 -64
  450. package/dist/tasks/resolve-akm-bin.js +144 -51
  451. package/dist/tasks/runner.js +377 -209
  452. package/dist/tasks/schedule.js +108 -19
  453. package/dist/tasks/scheduler-invocation.js +296 -0
  454. package/dist/tasks/schema.js +1 -1
  455. package/dist/tasks/task-id.js +35 -0
  456. package/dist/tasks/validator.js +30 -16
  457. package/dist/workflows/authoring/authoring.js +96 -148
  458. package/dist/workflows/authoring/scope-key.js +1 -1
  459. package/dist/workflows/cli.js +0 -20
  460. package/dist/workflows/concurrency-policy.js +15 -0
  461. package/dist/workflows/exec/brief.js +25 -59
  462. package/dist/workflows/exec/frozen-judge.js +47 -0
  463. package/dist/workflows/exec/native-executor.js +157 -94
  464. package/dist/workflows/exec/report.js +365 -200
  465. package/dist/workflows/exec/run-workflow.js +46 -40
  466. package/dist/workflows/exec/scheduler.js +12 -41
  467. package/dist/workflows/exec/step-work.js +239 -205
  468. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  469. package/dist/workflows/ir/compile.js +141 -283
  470. package/dist/workflows/ir/freeze.js +233 -0
  471. package/dist/workflows/ir/plan-hash.js +40 -5
  472. package/dist/workflows/ir/schema.js +537 -1
  473. package/dist/workflows/parser.js +878 -306
  474. package/dist/workflows/program/expressions.js +20 -208
  475. package/dist/workflows/program/schema.js +7 -10
  476. package/dist/workflows/renderer.js +99 -121
  477. package/dist/workflows/resource-limits.js +22 -0
  478. package/dist/workflows/runtime/checkin.js +1 -1
  479. package/dist/workflows/runtime/plan-classifier.js +131 -0
  480. package/dist/workflows/runtime/runs.js +200 -113
  481. package/dist/workflows/runtime/unit-checkin.js +1 -1
  482. package/dist/workflows/runtime/unit-phases.js +20 -0
  483. package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
  484. package/dist/workflows/schema.js +1 -11
  485. package/dist/workflows/validate-summary.js +4 -26
  486. package/dist/workflows/validator.js +52 -30
  487. package/docs/README.md +42 -78
  488. package/docs/migration/README.md +8 -0
  489. package/docs/migration/release-notes/0.6.0.md +1 -1
  490. package/docs/migration/release-notes/0.7.0.md +9 -8
  491. package/docs/migration/release-notes/0.9.0.md +158 -14
  492. package/docs/migration/v0.7-to-v0.8.md +46 -47
  493. package/docs/migration/v0.8-to-v0.9.md +844 -0
  494. package/docs/reference/README.md +12 -0
  495. package/docs/reference/data-and-telemetry.md +333 -0
  496. package/package.json +21 -17
  497. package/schemas/akm-asset-envelope.json +93 -0
  498. package/schemas/akm-config.json +4636 -0
  499. package/schemas/akm-task.json +87 -0
  500. package/{dist/schemas → schemas}/akm-workflow.json +127 -82
  501. package/dist/akm-migrate-storage +0 -38
  502. package/dist/assets/help/help-accept.md +0 -12
  503. package/dist/assets/help/help-improve.md +0 -84
  504. package/dist/assets/help/help-proposals.md +0 -17
  505. package/dist/assets/help/help-propose.md +0 -17
  506. package/dist/assets/help/help-reject.md +0 -11
  507. package/dist/assets/profiles/frequent.json +0 -13
  508. package/dist/assets/profiles/recombine-only.json +0 -21
  509. package/dist/assets/profiles/reflect-distill.json +0 -30
  510. package/dist/assets/profiles/synthesize.json +0 -15
  511. package/dist/assets/prompts/procedural-system.md +0 -44
  512. package/dist/assets/prompts/recombine-system.md +0 -40
  513. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  514. package/dist/assets/tasks/core/backup.yml +0 -4
  515. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  516. package/dist/assets/templates/html/default.html +0 -78
  517. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  518. package/dist/assets/wiki/index-template.md +0 -12
  519. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  520. package/dist/assets/wiki/log-template.md +0 -8
  521. package/dist/assets/wiki/schema-template.md +0 -61
  522. package/dist/cli/config-migrate.js +0 -150
  523. package/dist/cli/config-validate.js +0 -39
  524. package/dist/commands/graph/graph-cli.js +0 -124
  525. package/dist/commands/graph/graph.js +0 -487
  526. package/dist/commands/improve/calibration.js +0 -161
  527. package/dist/commands/improve/dedup.js +0 -482
  528. package/dist/commands/improve/extract-watch.js +0 -140
  529. package/dist/commands/improve/hot-probation.js +0 -45
  530. package/dist/commands/improve/improve-auto-accept.js +0 -276
  531. package/dist/commands/improve/improve-profiles.js +0 -168
  532. package/dist/commands/improve/procedural.js +0 -398
  533. package/dist/commands/improve/recombine.js +0 -818
  534. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  535. package/dist/commands/lint/agent-linter.js +0 -44
  536. package/dist/commands/lint/command-linter.js +0 -44
  537. package/dist/commands/lint/default-linter.js +0 -16
  538. package/dist/commands/lint/fact-linter.js +0 -39
  539. package/dist/commands/lint/knowledge-linter.js +0 -16
  540. package/dist/commands/lint/memory-linter.js +0 -61
  541. package/dist/commands/lint/registry.js +0 -41
  542. package/dist/commands/lint/skill-linter.js +0 -45
  543. package/dist/commands/lint/task-linter.js +0 -50
  544. package/dist/commands/lint/workflow-linter.js +0 -81
  545. package/dist/commands/proposal/legacy-import.js +0 -115
  546. package/dist/commands/sources/history.js +0 -196
  547. package/dist/commands/tasks/default-tasks.js +0 -186
  548. package/dist/commands/wiki-cli.js +0 -292
  549. package/dist/core/asset/asset-registry.js +0 -76
  550. package/dist/core/asset/asset-spec.js +0 -316
  551. package/dist/core/config/config-migration.js +0 -602
  552. package/dist/core/deep-merge.js +0 -38
  553. package/dist/core/eval/rank-metrics.js +0 -113
  554. package/dist/core/ripgrep/install.js +0 -163
  555. package/dist/core/ripgrep/resolve.js +0 -81
  556. package/dist/indexer/db/db.js +0 -1414
  557. package/dist/indexer/manifest.js +0 -170
  558. package/dist/indexer/passes/metadata-contributors.js +0 -31
  559. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  560. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
  561. package/dist/llm/call-ai.js +0 -62
  562. package/dist/llm/memory-infer-impl.js +0 -138
  563. package/dist/output/shapes/distill.js +0 -14
  564. package/dist/output/shapes/history.js +0 -11
  565. package/dist/output/text/distill.js +0 -6
  566. package/dist/output/text/enable-disable.js +0 -8
  567. package/dist/output/text/history.js +0 -6
  568. package/dist/output/text/wiki.js +0 -16
  569. package/dist/registry/build-index.js +0 -386
  570. package/dist/schemas/akm-config.json +0 -14225
  571. package/dist/scripts/migrate-storage.js +0 -13169
  572. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
  573. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  574. package/dist/setup/legacy-config.js +0 -106
  575. package/dist/storage/repositories/consolidation-repository.js +0 -38
  576. package/dist/storage/repositories/recombine-repository.js +0 -213
  577. package/dist/wiki/wiki-templates.js +0 -15
  578. package/dist/wiki/wiki.js +0 -1012
  579. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  580. package/dist/workflows/db.js +0 -350
  581. package/dist/workflows/exec/watch.js +0 -116
  582. package/dist/workflows/program/parser.js +0 -760
  583. package/dist/workflows/program/project.js +0 -105
  584. package/docs/data-and-telemetry.md +0 -227
  585. package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
  586. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  587. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -0,0 +1,286 @@
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
+ * Shared helpers for the concrete `BundleAdapter` implementations under
6
+ * `src/core/adapter/adapters/` — akm 0.9.0 chunk-2, WI-A (the `okf` adapter).
7
+ *
8
+ * ── Cycle-safety (chunk-2 "cycle-safety watch") ──
9
+ *
10
+ * The base-check logic below is a PORT, not an import, of
11
+ * `src/commands/lint/base-linter.ts`'s `runBaseChecks` (the 4 checks every
12
+ * non-`DefaultLinter` class inherits: unquoted-colon, missing-updated,
13
+ * stale-path, missing-ref). Importing `base-linter.ts` directly would add a
14
+ * new `src/core/adapter` -> `src/commands/lint` edge; `base-linter.ts`
15
+ * itself imports `core/asset/asset-spec.ts` (a baseline cycle participant,
16
+ * `scripts/lint-import-cycles.ts`) and `commands/lint/markdown-insertion.ts`
17
+ * — pulling either into `src/core/adapter/`'s import graph risks adding a
18
+ * 19th cycle participant against the zero-tolerance ratchet (baseline 18).
19
+ * Per the brief's explicit instruction ("copy the pure logic to a leaf ...
20
+ * do NOT use dynamic import to launder"), the pure regex/string logic is
21
+ * duplicated here, adapted to `Diagnostic`/`ValidateContext`. Verified
22
+ * cycle-safe: `bun scripts/lint-import-cycles.ts` stays at 18 with this file
23
+ * present (see the WI-A report).
24
+ *
25
+ * ── What did NOT get ported ──
26
+ *
27
+ * `bundle-adapter.ts`'s own doc comment is explicit that `validate()`
28
+ * "MUST NOT write and MUST NOT read the live filesystem" — reads go through
29
+ * `ValidateContext`, which serves the run snapshot WITH pending changes
30
+ * overlaid. `stale-path`'s legacy check called `fs.existsSync` directly on
31
+ * arbitrary absolute paths found in content; here it goes through
32
+ * `ctx.readFile(candidate)` instead (a `null` result means "does not
33
+ * exist") — the interface-compliant translation of the same check, not a
34
+ * behavior change for any path that genuinely exists or doesn't.
35
+ *
36
+ * The `refs:`-frontmatter-array authoritative-list carve-out (session-
37
+ * checkpoint memories; `base-linter.ts`'s `extractFrontmatterRefs`) is NOT
38
+ * ported here — it is memory/session-specific and no OKF concept uses it. A
39
+ * later memory/note adapter should extend `extractProseRefTokens`'s caller with
40
+ * that carve-out when it ports memory/session.
41
+ *
42
+ * The fence-strip (`stripFencedBlocksSimple` below) is a simplified,
43
+ * same-INTENT reimplementation of `markdown-insertion.ts`'s
44
+ * `findFenceRegions` (which is also table/HTML-region aware, because it
45
+ * additionally powers safe line INSERTION, a concern this module doesn't
46
+ * have) — not byte-identical on every edge case, but sufficient for "don't
47
+ * flag a ref/path inside a ``` example," which is the only thing this
48
+ * module needs the strip for.
49
+ */
50
+ import { createHash } from "node:crypto";
51
+ import { parseFrontmatter } from "../../asset/frontmatter.js";
52
+ // ── Small pure helpers, reused across the concrete adapters ──────────────────
53
+ /** Content hash feeding `IndexDocument.hash` (incrementality/fingerprints, `types.ts` doc comment). */
54
+ export function hashContent(content) {
55
+ return createHash("sha256").update(content, "utf8").digest("hex");
56
+ }
57
+ /** Trim a possibly-non-string frontmatter value down to a non-empty string or `undefined` (mirrors `core/common.ts#asNonEmptyString`, duplicated locally to avoid importing a cycle-participant module for a 4-line helper). */
58
+ export function nonEmptyString(value) {
59
+ if (typeof value !== "string")
60
+ return undefined;
61
+ const trimmed = value.trim();
62
+ return trimmed.length > 0 ? trimmed : undefined;
63
+ }
64
+ /** Read a frontmatter `tags:` array down to its non-empty string entries, or `undefined` when there are none (mirrors `output/renderers.ts#readFrontmatterTags`). */
65
+ export function readTags(value) {
66
+ if (!Array.isArray(value))
67
+ return undefined;
68
+ const tags = value.filter((tag) => typeof tag === "string" && tag.trim().length > 0);
69
+ return tags.length > 0 ? tags : undefined;
70
+ }
71
+ // ── Base validate checks (port of `BaseLinter.runBaseChecks`) ────────────────
72
+ function checkUnquotedColon(frontmatterText) {
73
+ if (!frontmatterText)
74
+ return null;
75
+ for (const line of frontmatterText.split(/\r?\n/)) {
76
+ const match = line.match(/^description:\s*(.*)/);
77
+ if (!match)
78
+ continue;
79
+ const value = match[1].trim();
80
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
81
+ return null;
82
+ }
83
+ if (value.includes(":")) {
84
+ return `description value contains unquoted colon: ${value}`;
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+ function checkMissingUpdated(data, frontmatterText) {
90
+ return frontmatterText !== null && !("updated" in data);
91
+ }
92
+ function findStalePathCandidates(body) {
93
+ const pathRe = /(?:\/home\/|\/tmp\/|\/var\/|\/root\/|\/opt\/)[^\s"'`)\]>,\n]+/g;
94
+ const out = [];
95
+ let match;
96
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex loop
97
+ while ((match = pathRe.exec(body)) !== null)
98
+ out.push(match[0]);
99
+ return out;
100
+ }
101
+ /** See file header: same intent as `markdown-insertion.ts#findFenceRegions`, not byte-identical. */
102
+ function stripFencedBlocksSimple(body) {
103
+ const lines = body.split(/\r?\n/);
104
+ let inFence = false;
105
+ const out = lines.map((line) => {
106
+ if (/^\s*```/.test(line)) {
107
+ const wasInFence = inFence;
108
+ inFence = !inFence;
109
+ return wasInFence || inFence ? "" : line;
110
+ }
111
+ return inFence ? "" : line;
112
+ });
113
+ return out.join("\n");
114
+ }
115
+ // Ref-token grammar — copied from `base-linter.ts`'s `BUNDLE_REF_RE`
116
+ // (`core/asset/asset-ref.ts`, spec §11.1 / ref-grammar decision D-R3) as a VALUE,
117
+ // not an import (same cycle-avoidance rationale as the file header — the source
118
+ // string is duplicated so no new `core/adapter` -> `core/asset` edge is added for
119
+ // this scan). Recognizes the 0.9.0 FULLY-QUALIFIED `<bundle>//<concept-id>
120
+ // [#fragment]` prose body-ref anchored form ONLY. Per D-R3, a bare short
121
+ // conceptId in prose is NOT a ref, so it is never flagged here (it is a ref only
122
+ // in the ref-LIST channels — {@link refTokenFromListValue}). The pre-0.9.0
123
+ // `<type>:<slug>` colon grammar is gone from every recognition surface.
124
+ const BUNDLE_BODY_REF_RE_SRC = "(?:^|[\\s`\"'(,[])([^\\s:.#/`\"'()[\\],<>]+\\/\\/[^\\s\"'`)\\]>,\\n]+)";
125
+ /**
126
+ * A conceptId that is a lint false positive rather than a real ref — mirrors the
127
+ * `isNonRefName` guards `base-linter.ts` applies deep in its existence check:
128
+ * template placeholders (`skills/<name>`) and degenerate/incomplete tokens.
129
+ */
130
+ function isNonRefConceptId(conceptId) {
131
+ const id = conceptId.split("#", 1)[0]; // drop the export #fragment selector
132
+ if (!id || id.length <= 1 || id === "**")
133
+ return true;
134
+ if (id.includes("<"))
135
+ return true; // template placeholder, e.g. `skills/<name>`
136
+ return false;
137
+ }
138
+ /**
139
+ * Extract the fully-qualified `bundle//conceptId` refs from PROSE — the flipped
140
+ * `base-linter.ts#checkMissingRefs` semantics (`BUNDLE_REF_RE`, qualified-only;
141
+ * bare short conceptIds are NOT refs, D-R3). Fenced code is stripped first so
142
+ * example refs inside ``` are not flagged; shell-substitution (`$(`/`${`) and
143
+ * ACP (`::`) false positives are dropped.
144
+ */
145
+ function extractProseRefTokens(text) {
146
+ const re = new RegExp(BUNDLE_BODY_REF_RE_SRC, "gm");
147
+ const scanBody = stripFencedBlocksSimple(text);
148
+ const refs = [];
149
+ let match;
150
+ // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex loop
151
+ while ((match = re.exec(scanBody)) !== null) {
152
+ const token = match[1];
153
+ if (token.includes("$(") || token.includes("${") || token.includes("::"))
154
+ continue;
155
+ if (isNonRefConceptId(token.slice(token.indexOf("//") + 2)))
156
+ continue;
157
+ refs.push(token);
158
+ }
159
+ return refs;
160
+ }
161
+ /**
162
+ * Recognize a single frontmatter ref-LIST value (`xrefs:`/`supersededBy:`/
163
+ * `contradictedBy:`) as a whole ref — the flipped `base-linter.ts#
164
+ * checkMissingRefsInList` semantics. Unlike prose, a bare short `conceptId` IS a
165
+ * ref here (the value's whole purpose is to name one asset). Returns the ref
166
+ * token, or `null` for a false positive or a legacy `origin//type:name` value
167
+ * (the colon-grammar is retired — D-R3).
168
+ */
169
+ function refTokenFromListValue(value) {
170
+ const trimmed = value.trim();
171
+ if (!trimmed || trimmed.includes("$(") || trimmed.includes("${") || trimmed.includes("::"))
172
+ return null;
173
+ const boundary = trimmed.indexOf("//");
174
+ // Qualified `bundle//conceptId`: a colon in the tail marks a legacy/remote
175
+ // `origin//type:name` — not the 0.9.0 grammar — so skip it. Un-prefixed values
176
+ // are a 0.9.0 short conceptId; a colon there is likewise the retired grammar.
177
+ const conceptId = boundary >= 0 ? trimmed.slice(boundary + 2) : trimmed;
178
+ if (conceptId.includes(":") || isNonRefConceptId(conceptId))
179
+ return null;
180
+ return trimmed;
181
+ }
182
+ const XREF_FRONTMATTER_KEYS = ["xrefs", "supersededBy", "contradictedBy"];
183
+ function readRefStringOrArray(value) {
184
+ if (typeof value === "string") {
185
+ const trimmed = value.trim();
186
+ return trimmed ? [trimmed] : null;
187
+ }
188
+ if (!Array.isArray(value))
189
+ return null;
190
+ const out = value.filter((v) => typeof v === "string" && v.trim().length > 0).map((v) => v.trim());
191
+ return out.length > 0 ? out : null;
192
+ }
193
+ /**
194
+ * Port of `BaseLinter.runBaseChecks`, adapted to the read-only
195
+ * `ValidateContext`/`Diagnostic` shapes (adapter spec §12.1). Reproduces
196
+ * unquoted-colon / missing-updated / stale-path / missing-ref for ONE file's
197
+ * already-parsed content.
198
+ *
199
+ * `fixed` is always `false`: `BundleAdapter.validate` MUST NOT write the
200
+ * filesystem, so there is no fix-apply mechanism at this layer — a documented,
201
+ * intentional behavior narrowing from the legacy `--fix`-capable linter.
202
+ *
203
+ * `componentRoot` is `BundleComponent.root` — used only for the stale-path
204
+ * "portable form" hint (mirrors legacy `ctx.stashRoot`-relative substitution;
205
+ * no I/O).
206
+ */
207
+ export async function runBaseValidateChecks(relPath, parsed, componentRoot, ctx) {
208
+ const diagnostics = [];
209
+ const { data, content: body, frontmatter } = parsed;
210
+ const unquotedColonDetail = checkUnquotedColon(frontmatter);
211
+ if (unquotedColonDetail) {
212
+ diagnostics.push({ file: relPath, issue: "unquoted-colon", detail: unquotedColonDetail, fixed: false });
213
+ }
214
+ if (checkMissingUpdated(data, frontmatter)) {
215
+ diagnostics.push({
216
+ file: relPath,
217
+ issue: "missing-updated",
218
+ detail: "no updated field in frontmatter",
219
+ fixed: false,
220
+ });
221
+ }
222
+ const staleCandidates = [
223
+ ...findStalePathCandidates(body),
224
+ ...(frontmatter ? findStalePathCandidates(frontmatter) : []),
225
+ ];
226
+ for (const candidate of staleCandidates) {
227
+ const found = await ctx.readFile(candidate);
228
+ if (found !== null)
229
+ continue;
230
+ const portableHint = candidate.startsWith(componentRoot)
231
+ ? ` (portable form: $AKM_BUNDLE_DIR${candidate.slice(componentRoot.length)})`
232
+ : "";
233
+ diagnostics.push({
234
+ file: relPath,
235
+ issue: "stale-path",
236
+ detail: `nonexistent path: ${candidate}${portableHint}`,
237
+ fixed: false,
238
+ });
239
+ }
240
+ for (const ref of extractProseRefTokens(body)) {
241
+ const { exists } = await ctx.resolveRef(ref);
242
+ if (!exists)
243
+ diagnostics.push({ file: relPath, issue: "missing-ref", detail: `missing ref: ${ref}`, fixed: false });
244
+ }
245
+ if (frontmatter !== null) {
246
+ for (const key of XREF_FRONTMATTER_KEYS) {
247
+ const values = readRefStringOrArray(data[key]);
248
+ if (values === null)
249
+ continue;
250
+ for (const value of values) {
251
+ const ref = refTokenFromListValue(value);
252
+ if (ref === null)
253
+ continue;
254
+ const { exists } = await ctx.resolveRef(ref);
255
+ if (!exists) {
256
+ diagnostics.push({
257
+ file: relPath,
258
+ issue: "missing-ref",
259
+ detail: `missing ref: ${ref} (frontmatter ${key})`,
260
+ fixed: false,
261
+ });
262
+ }
263
+ }
264
+ }
265
+ }
266
+ return diagnostics;
267
+ }
268
+ /**
269
+ * Shared per-change loop: for every non-delete change with readable content,
270
+ * parse frontmatter and run {@link runBaseValidateChecks}. Adapters with extra
271
+ * per-type checks (e.g. `okf`'s missing-type / OKF-link warnings) run their own
272
+ * loop and call {@link runBaseValidateChecks} directly instead.
273
+ */
274
+ export async function validateChangesWithBaseChecks(c, changes, ctx) {
275
+ const diagnostics = [];
276
+ for (const change of changes) {
277
+ if (change.op === "delete")
278
+ continue;
279
+ const raw = change.after ?? (await ctx.readFile(change.path));
280
+ if (typeof raw !== "string")
281
+ continue;
282
+ const parsed = parseFrontmatter(raw);
283
+ diagnostics.push(...(await runBaseValidateChecks(change.path, parsed, c.root, ctx)));
284
+ }
285
+ return diagnostics;
286
+ }
@@ -0,0 +1,217 @@
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
+ * Shared recognition / placement / validation for the two AGENT TOOL-DIRECTORY
6
+ * adapters — `claude` (`.claude`) and `opencode` (`.opencode`) — akm 0.9.0
7
+ * format-family work item (#46). Both translate a foreign tool layout into the
8
+ * open AKM `type` vocabulary (spec §6/§7): a root instruction file
9
+ * (CLAUDE.md / AGENTS.md) → `instruction`, `commands/*.md` → `command`,
10
+ * `agents/*.md` → `agent`, `skills/<name>/SKILL.md` → `skill` (item = the dir).
11
+ * They differ only in three parameters carried on {@link ToolDirLayout}:
12
+ * - the instruction basename + its concept id,
13
+ * - the accepted subdir spellings (opencode accepts the SINGULAR
14
+ * `command/`/`agent/`/`skill/` aliases per open-question-6, claude does not),
15
+ * - the adapter id + component id.
16
+ *
17
+ * The SKILL.md codec is shared with the `agent-skills` adapter as functions
18
+ * (spec §8): a skill's conceptId is its DIRECTORY, and its `name` is the
19
+ * frontmatter `name` (== the dir name per the Agent Skills §4.5 hard rule).
20
+ *
21
+ * ── D-R6 (reserved files) ──
22
+ *
23
+ * `index.md` / `log.md` are OKF structural files at EVERY depth — never a
24
+ * concept. `classify` excludes them up front so a stray `commands/index.md`
25
+ * never becomes a `command` (mirrors okf/akm/llm-wiki `RESERVED_FILES`).
26
+ *
27
+ * ── validate leniency (spec §6 skill row) ──
28
+ *
29
+ * The tool-dir adapters TOLERATE the tools' native frontmatter (argument-hint,
30
+ * allowed-tools, tools, model, mode, temperature, agent, …) — the strict
31
+ * unknown-frontmatter behavior belongs to `agent-skills`, not here. So `command`
32
+ * / `agent` get a LENIENT name-or-signal check (never the akm `CommandLinter`'s
33
+ * frontmatter `name`+`type` requirement, which these tool files do not carry),
34
+ * `skill` gets the coded `missing-skill-md` directory check
35
+ * ({@link skillDirectoryDiagnostics}), and `instruction` runs the shared base
36
+ * checks (a no-op on a frontmatter-free CLAUDE.md/AGENTS.md). Notably NO base
37
+ * checks run on command/agent/skill: their tool frontmatter carries no `updated`
38
+ * field, so `missing-updated` would fire on every file and contradict the lint
39
+ * golden's clean result.
40
+ *
41
+ * ── Cycle-safety ──
42
+ *
43
+ * Imported only by `claude-adapter.ts` / `opencode-adapter.ts` (themselves
44
+ * imported by the `adapters/index.ts` barrel — NOT test-only: `core/adapter/
45
+ * registry.ts:33` imports it in production for the frozen `BUILTIN_ADAPTERS`
46
+ * list). This leaf still can never gain an inbound edge from a cycle
47
+ * participant, since nothing on that import chain imports back into it. It
48
+ * value-imports only pure leaves (`shared`, `akm-lint`, `frontmatter`) plus
49
+ * Node builtins.
50
+ */
51
+ import path from "node:path";
52
+ import { parseFrontmatter } from "../../asset/frontmatter.js";
53
+ import { skillDirectoryDiagnostics } from "./akm-lint.js";
54
+ import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
55
+ /** OKF reserved structural files (D-R6) — excluded at every depth, case-insensitive. */
56
+ const RESERVED_FILES = new Set(["index.md", "log.md"]);
57
+ /** Upper bound on the bounded `content` FTS field (mirrors okf-adapter). */
58
+ const MAX_CONTENT_CHARS = 100_000;
59
+ /** The canonical (plural) subdir spellings writes normalize to (open-question-6). */
60
+ const CANONICAL_COMMAND_DIR = "commands";
61
+ const CANONICAL_AGENT_DIR = "agents";
62
+ const CANONICAL_SKILL_DIR = "skills";
63
+ const SKILL_MANIFEST = "SKILL.md";
64
+ function toPosix(p) {
65
+ return p.replace(/\\/g, "/");
66
+ }
67
+ function isReserved(base) {
68
+ return RESERVED_FILES.has(base.toLowerCase());
69
+ }
70
+ /** Classify one component-root-relative file into a tool-dir `type` + conceptId, or abstain (null). */
71
+ function classify(relPath, layout) {
72
+ const posix = toPosix(relPath);
73
+ const segs = posix.split("/").filter((s) => s.length > 0);
74
+ if (segs.length === 0)
75
+ return null;
76
+ const base = segs[segs.length - 1];
77
+ if (isReserved(base))
78
+ return null;
79
+ // Root instruction file.
80
+ if (segs.length === 1 && base === layout.instructionFile) {
81
+ return { type: "instruction", conceptId: layout.instructionConceptId, name: layout.instructionConceptId };
82
+ }
83
+ const head = segs[0];
84
+ const ext = path.extname(base).toLowerCase();
85
+ // skill: <skillDir>/<name>/SKILL.md — the item is the DIRECTORY. Any other
86
+ // file under a skill dir (bundled resources) is part of the item, not a concept.
87
+ if (layout.skillDirs.has(head)) {
88
+ if (segs.length >= 3 && base === SKILL_MANIFEST) {
89
+ return { type: "skill", conceptId: `${segs[0]}/${segs[1]}`, name: segs[1] };
90
+ }
91
+ return null;
92
+ }
93
+ if (layout.commandDirs.has(head) && ext === ".md" && segs.length >= 2) {
94
+ return { type: "command", conceptId: posix.replace(/\.md$/i, ""), name: base.replace(/\.md$/i, "") };
95
+ }
96
+ if (layout.agentDirs.has(head) && ext === ".md" && segs.length >= 2) {
97
+ return { type: "agent", conceptId: posix.replace(/\.md$/i, ""), name: base.replace(/\.md$/i, "") };
98
+ }
99
+ return null;
100
+ }
101
+ /** recognize() for a tool-dir adapter: derive the open `type`, project the OKF-shaped fields. */
102
+ export function recognizeToolDir(layout, c, file) {
103
+ const cls = classify(file.relPath, layout);
104
+ if (cls === null)
105
+ return null;
106
+ const raw = file.content();
107
+ const parsed = parseFrontmatter(raw);
108
+ const data = parsed.data;
109
+ const body = parsed.content;
110
+ // For a skill, `name` is the frontmatter `name` (== dir name); otherwise the
111
+ // basename-derived concept name.
112
+ const name = cls.type === "skill" ? (nonEmptyString(data.name) ?? cls.name) : cls.name;
113
+ const description = nonEmptyString(data.description);
114
+ const tags = readTags(data.tags);
115
+ const doc = {
116
+ ref: `${c.id}//${cls.conceptId}`,
117
+ bundle: c.id,
118
+ component: layout.componentId,
119
+ conceptId: cls.conceptId,
120
+ path: file.absPath,
121
+ hash: hashContent(raw),
122
+ adapterId: layout.adapterId,
123
+ type: cls.type,
124
+ name,
125
+ content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
126
+ };
127
+ if (cls.type === "instruction")
128
+ doc.ownsPresentation = true;
129
+ if (description !== undefined)
130
+ doc.description = description;
131
+ if (tags !== undefined)
132
+ doc.tags = tags;
133
+ return doc;
134
+ }
135
+ /**
136
+ * placeNew() for a tool-dir adapter (spec §7: "AKM workspace layout IS the tool
137
+ * dir minus the prefix"). Writes NORMALIZE to the canonical plural subdir
138
+ * (open-question-6): a `command/foo` concept still places at `commands/foo.md`.
139
+ * The instruction file is fixed at the component root.
140
+ */
141
+ export function placeNewToolDir(layout, c, conceptId) {
142
+ const posix = toPosix(conceptId);
143
+ if (posix === layout.instructionConceptId)
144
+ return path.join(c.root, layout.instructionFile);
145
+ const segs = posix.split("/").filter((s) => s.length > 0);
146
+ const head = segs[0];
147
+ const rest = segs.slice(1).join("/");
148
+ if (rest.length > 0) {
149
+ if (layout.skillDirs.has(head))
150
+ return path.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST);
151
+ if (layout.commandDirs.has(head))
152
+ return path.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
153
+ if (layout.agentDirs.has(head))
154
+ return path.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
155
+ }
156
+ return path.join(c.root, `${posix}.md`);
157
+ }
158
+ /** LENIENT command/agent check: a diagnostic only when NEITHER a name/description NOR a type-shaped signal is present. */
159
+ function nameOrSignalDiagnostics(type, relPath, data, body) {
160
+ if (nonEmptyString(data.name) !== undefined || nonEmptyString(data.description) !== undefined)
161
+ return [];
162
+ // command-shaped body/frontmatter signals (spec §6 command row): $ARGUMENTS / $1 / an `agent` frontmatter key.
163
+ if (type === "command" &&
164
+ (/\$ARGUMENTS\b/.test(body) || /\$\d/.test(body) || nonEmptyString(data.agent) !== undefined)) {
165
+ return [];
166
+ }
167
+ return [
168
+ {
169
+ file: relPath,
170
+ issue: "missing-name-or-type",
171
+ detail: `${type} has neither a name/description nor a ${type}-shaped signal`,
172
+ fixed: false,
173
+ },
174
+ ];
175
+ }
176
+ /** validate() for a tool-dir adapter — see file header for the leniency contract. */
177
+ export async function validateToolDir(layout, c, changes, ctx) {
178
+ const diagnostics = [];
179
+ const seenSkillDirs = new Set();
180
+ for (const change of changes) {
181
+ if (change.op === "delete")
182
+ continue;
183
+ const raw = change.after ?? (await ctx.readFile(change.path));
184
+ if (typeof raw !== "string")
185
+ continue;
186
+ const relPath = toPosix(change.path);
187
+ // The one coded skill check (missing-skill-md) fires on ANY change under a
188
+ // `skills/<name>/…` package (self-gated + deduped), even a bundled resource —
189
+ // mirrors the akm adapter's per-change SkillLinter.lintDirectory pass.
190
+ diagnostics.push(...(await skillDirectoryDiagnostics(relPath, seenSkillDirs, ctx)));
191
+ const cls = classify(change.path, layout);
192
+ if (cls === null)
193
+ continue;
194
+ if (cls.type === "instruction") {
195
+ diagnostics.push(...(await runBaseValidateChecks(relPath, parseFrontmatter(raw), c.root, ctx)));
196
+ }
197
+ else if (cls.type === "command" || cls.type === "agent") {
198
+ const parsed = parseFrontmatter(raw);
199
+ diagnostics.push(...nameOrSignalDiagnostics(cls.type, relPath, parsed.data, parsed.content));
200
+ }
201
+ // skill: covered by skillDirectoryDiagnostics above; no additional per-file check.
202
+ }
203
+ return diagnostics;
204
+ }
205
+ /** Build the concrete `BundleAdapter` from a layout + a `looksLikeRoot` probe (claude/opencode share everything else). */
206
+ export function makeToolDirAdapter(layout, looksLikeRoot) {
207
+ return {
208
+ id: layout.adapterId,
209
+ version: "0.9.0",
210
+ extensions: [".md"],
211
+ recognize: (c, file) => recognizeToolDir(layout, c, file),
212
+ validate: (c, changes, ctx) => validateToolDir(layout, c, changes, ctx),
213
+ placeNew: (c, conceptId) => placeNewToolDir(layout, c, conceptId),
214
+ directoryList: () => [CANONICAL_COMMAND_DIR, CANONICAL_AGENT_DIR, CANONICAL_SKILL_DIR],
215
+ looksLikeRoot,
216
+ };
217
+ }
@@ -0,0 +1,155 @@
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
+ * The `website-snapshot` adapter — akm 0.9.0 format-family work item (#46).
6
+ *
7
+ * A READ-ONLY (Mode A) view over a materialized crawl snapshot written by
8
+ * `src/sources/snapshot-fetchers/website-ingest.ts` (spec §6/§7). The on-disk
9
+ * pages are KNOWLEDGE-shaped markdown under `stash/knowledge/**` with no `type:`
10
+ * field; this adapter RE-TYPES them to the open `type: website`. Per
11
+ * open-question-3 (RESOLVED, maintainer 2026-07) the re-type is GATED — it
12
+ * applies only to a page carrying the `website` tag / a `sourceUrl` (a page
13
+ * lacking both is not re-typed); the document KEEPS its `sourceUrl` (surfaced as
14
+ * `sourceRef` on `documentJson`); and the conceptId STRIPS the
15
+ * `stash/knowledge/` prefix. `manifest.json` is snapshot PROVENANCE
16
+ * (`{url, fetchedAt}`), read by the probe but never indexed as a concept.
17
+ *
18
+ * Read-only ⇒ NO `placeNew` (Mode B export routes content through the
19
+ * DESTINATION adapter, which owns placement). `validate` runs base checks only
20
+ * (a mirror the adapter does not author has no native validators); `updated`
21
+ * never appears on a snapshot page, so `missing-updated` is filtered out.
22
+ *
23
+ * Conformance oracle (authored, DO NOT modify): fixture
24
+ * `tests/fixtures/bundles/website-snapshot/` + goldens
25
+ * `tests/fixtures/format-family-goldens/website-snapshot/{recognition,placement,lint,renderer}.json`.
26
+ */
27
+ import fs from "node:fs";
28
+ import path from "node:path";
29
+ import { parse as parseYaml } from "yaml";
30
+ import { parseFrontmatter, parseFrontmatterBlock } from "../../asset/frontmatter.js";
31
+ import { hashContent, nonEmptyString, runBaseValidateChecks } from "./shared.js";
32
+ /** A snapshot bundle is single-component; its one component is `main`. */
33
+ const COMPONENT_ID = "main";
34
+ /** The crawl page root the snapshot writer materializes pages under. */
35
+ const PAGES_PREFIX = "stash/knowledge/";
36
+ /** The provenance manifest basename (probe marker only, never indexed). */
37
+ const MANIFEST_FILE = "manifest.json";
38
+ /** The tag the snapshot writer stamps on every crawled page. */
39
+ const WEBSITE_TAG = "website";
40
+ /** Upper bound on the bounded `content` FTS field (mirrors okf-adapter). */
41
+ const MAX_CONTENT_CHARS = 100_000;
42
+ function toPosix(p) {
43
+ return p.replace(/\\/g, "/");
44
+ }
45
+ function parseSnapshotFrontmatter(raw) {
46
+ const out = { tags: [] };
47
+ const block = parseFrontmatterBlock(raw);
48
+ if (!block)
49
+ return out;
50
+ let data = {};
51
+ try {
52
+ const value = parseYaml(block.frontmatter);
53
+ if (value && typeof value === "object" && !Array.isArray(value))
54
+ data = value;
55
+ }
56
+ catch {
57
+ return out;
58
+ }
59
+ out.title = nonEmptyString(data.title);
60
+ out.description = nonEmptyString(data.description);
61
+ out.sourceUrl = nonEmptyString(data.sourceUrl);
62
+ if (Array.isArray(data.tags)) {
63
+ out.tags = data.tags.filter((t) => typeof t === "string" && t.trim().length > 0).map((t) => t.trim());
64
+ }
65
+ return out;
66
+ }
67
+ /** True when a page is a crawl snapshot page under `stash/knowledge/**`. */
68
+ function isSnapshotPage(relPath) {
69
+ const posix = toPosix(relPath);
70
+ return posix.startsWith(PAGES_PREFIX) && posix.toLowerCase().endsWith(".md");
71
+ }
72
+ /** The GATED re-type predicate (open-question-3): the page carries the `website` tag OR a `sourceUrl`. */
73
+ function isReTypeGated(fm) {
74
+ return fm.sourceUrl !== undefined || fm.tags.includes(WEBSITE_TAG);
75
+ }
76
+ /** conceptId = page path − `stash/knowledge/` prefix − `.md`. */
77
+ function conceptIdOf(relPath) {
78
+ return toPosix(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
79
+ }
80
+ function recognize(c, file) {
81
+ if (file.ext !== ".md" || !isSnapshotPage(file.relPath))
82
+ return null;
83
+ const raw = file.content();
84
+ const fm = parseSnapshotFrontmatter(raw);
85
+ if (!isReTypeGated(fm))
86
+ return null; // not a re-typed website page
87
+ const conceptId = conceptIdOf(file.relPath);
88
+ const name = fm.title ?? conceptId.split("/").pop() ?? conceptId;
89
+ const body = parseFrontmatter(raw).content;
90
+ const doc = {
91
+ ref: `${c.id}//${conceptId}`,
92
+ bundle: c.id,
93
+ component: COMPONENT_ID,
94
+ conceptId,
95
+ path: file.absPath,
96
+ hash: hashContent(raw),
97
+ adapterId: "website-snapshot",
98
+ ownsPresentation: true,
99
+ type: "website",
100
+ name,
101
+ content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body,
102
+ };
103
+ if (fm.description !== undefined)
104
+ doc.description = fm.description;
105
+ if (fm.sourceUrl !== undefined)
106
+ doc.documentJson = { sourceRef: fm.sourceUrl };
107
+ return doc;
108
+ }
109
+ async function validate(c, changes, ctx) {
110
+ const diagnostics = [];
111
+ for (const change of changes) {
112
+ if (change.op === "delete")
113
+ continue;
114
+ const raw = change.after ?? (await ctx.readFile(change.path));
115
+ if (typeof raw !== "string")
116
+ continue;
117
+ if (!isSnapshotPage(change.path))
118
+ continue;
119
+ const base = await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx);
120
+ // A read-only crawl mirror carries `fetchedAt` provenance, never an `updated`
121
+ // field — so `missing-updated` is not a defect on a snapshot page.
122
+ diagnostics.push(...base.filter((d) => d.issue !== "missing-updated"));
123
+ }
124
+ return diagnostics;
125
+ }
126
+ export const websiteSnapshotAdapter = {
127
+ id: "website-snapshot",
128
+ version: "0.9.0",
129
+ extensions: [".md"],
130
+ recognize,
131
+ validate,
132
+ // No placeNew: the snapshot is READ-ONLY (Mode A). Export (Mode B) routes
133
+ // content through the DESTINATION adapter, which owns placement.
134
+ /**
135
+ * Install-time probe (§1.2): a root carrying the snapshot provenance
136
+ * `manifest.json` (`{url, fetchedAt}`). No other bundle root carries this
137
+ * exact marker, so the probe is unambiguous.
138
+ */
139
+ looksLikeRoot(root) {
140
+ let raw;
141
+ try {
142
+ raw = fs.readFileSync(path.join(root, MANIFEST_FILE), "utf8");
143
+ }
144
+ catch {
145
+ return false;
146
+ }
147
+ try {
148
+ const manifest = JSON.parse(raw);
149
+ return typeof manifest.url === "string" && typeof manifest.fetchedAt === "string";
150
+ }
151
+ catch {
152
+ return false;
153
+ }
154
+ },
155
+ };
@@ -0,0 +1,4 @@
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
+ export {};