akm-cli 0.9.1 → 0.9.2-alpha.2

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 (350) hide show
  1. package/CHANGELOG.md +103 -28
  2. package/README.md +3 -1
  3. package/SECURITY.md +1 -1
  4. package/STABILITY.md +1 -1
  5. package/dist/akm +2 -2
  6. package/dist/akm-migrate +2 -2
  7. package/dist/assets/hints/cli-hints-full.md +14 -9
  8. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
  9. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  10. package/dist/assets/models.json +35 -0
  11. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
  12. package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
  13. package/dist/assets/tasks/core/extract.yml +6 -5
  14. package/dist/assets/tasks/core/improve.yml +6 -5
  15. package/dist/assets/tasks/core/index-refresh.yml +6 -5
  16. package/dist/assets/tasks/core/sync.yml +6 -5
  17. package/dist/assets/tasks/core/version-check.yml +6 -5
  18. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
  19. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
  20. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
  21. package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
  22. package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
  23. package/dist/cli/confirm.js +2 -2
  24. package/dist/cli/parse-args.js +3 -24
  25. package/dist/cli/retired-commands.js +1 -1
  26. package/dist/cli/shared.js +2 -2
  27. package/dist/cli.js +11 -9
  28. package/dist/commands/agent/agent-dispatch.js +55 -89
  29. package/dist/commands/agent/contribute-cli.js +12 -45
  30. package/dist/commands/command/builtin-action.js +32 -0
  31. package/dist/commands/command/command-cli.js +99 -0
  32. package/dist/commands/command/command-execution.js +308 -0
  33. package/dist/commands/command/execution-source-loader.js +176 -0
  34. package/dist/commands/command/portable-template.js +60 -0
  35. package/dist/commands/config-cli.js +10 -4
  36. package/dist/commands/env/env.js +4 -2
  37. package/dist/commands/feedback-cli.js +1 -1
  38. package/dist/commands/health/checks.js +241 -29
  39. package/dist/commands/health/html-report.js +0 -14
  40. package/dist/commands/health/report-view-model.js +0 -1
  41. package/dist/commands/health/surfaces.js +6 -7
  42. package/dist/commands/health/types.js +0 -2
  43. package/dist/commands/health.js +63 -18
  44. package/dist/commands/improve/collapse-detector.js +5 -6
  45. package/dist/commands/improve/consolidate.js +251 -214
  46. package/dist/commands/improve/distill/promote-memory.js +71 -34
  47. package/dist/commands/improve/distill/quality-gate.js +17 -5
  48. package/dist/commands/improve/distill.js +232 -155
  49. package/dist/commands/improve/eligibility.js +112 -79
  50. package/dist/commands/improve/execution.js +57 -0
  51. package/dist/commands/improve/extract-cli.js +5 -5
  52. package/dist/commands/improve/extract-prompt.js +64 -22
  53. package/dist/commands/improve/extract.js +608 -360
  54. package/dist/commands/improve/improve-strategies.js +43 -14
  55. package/dist/commands/improve/improve.js +249 -29
  56. package/dist/commands/improve/loop-stages.js +11 -17
  57. package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
  58. package/dist/commands/improve/outcome-loop.js +22 -38
  59. package/dist/commands/improve/planner.js +134 -0
  60. package/dist/commands/improve/preparation.js +730 -409
  61. package/dist/commands/improve/reflect.js +386 -223
  62. package/dist/commands/improve/run-context.js +3 -4
  63. package/dist/commands/improve/salience.js +6 -58
  64. package/dist/commands/improve/session-asset.js +12 -12
  65. package/dist/commands/lint/index.js +101 -29
  66. package/dist/commands/migrate-cli.js +11 -69
  67. package/dist/commands/migration-tool.js +6 -9
  68. package/dist/commands/models-cli.js +27 -0
  69. package/dist/commands/proposal/drain.js +258 -186
  70. package/dist/commands/proposal/proposal-cli.js +32 -10
  71. package/dist/commands/proposal/proposal.js +2 -5
  72. package/dist/commands/proposal/propose.js +192 -172
  73. package/dist/commands/proposal/repository.js +54 -91
  74. package/dist/commands/proposal/validators/proposal-validators.js +9 -7
  75. package/dist/commands/read/curate.js +53 -22
  76. package/dist/commands/read/registry-search.js +25 -9
  77. package/dist/commands/read/remember-cli.js +14 -2
  78. package/dist/commands/read/search.js +10 -4
  79. package/dist/commands/read/show.js +139 -153
  80. package/dist/commands/registry-cli.js +16 -7
  81. package/dist/commands/remember.js +33 -18
  82. package/dist/commands/sources/add-cli.js +19 -178
  83. package/dist/commands/sources/bundle-cli.js +15 -3
  84. package/dist/commands/sources/dangerous-env-audit.js +135 -0
  85. package/dist/commands/sources/info.js +2 -1
  86. package/dist/commands/sources/installed-stashes.js +901 -177
  87. package/dist/commands/sources/schema-repair.js +174 -95
  88. package/dist/commands/sources/self-update.js +30 -74
  89. package/dist/commands/sources/source-add.js +3 -5
  90. package/dist/commands/sources/sources-cli.js +2 -15
  91. package/dist/commands/sources/update-transaction.js +220 -0
  92. package/dist/commands/tasks/tasks-cli.js +3 -3
  93. package/dist/commands/tasks/tasks.js +736 -317
  94. package/dist/commands/workflow-cli.js +2 -2
  95. package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
  96. package/dist/core/adapter/adapters/akm-adapter.js +85 -35
  97. package/dist/core/adapter/adapters/akm-lint.js +54 -39
  98. package/dist/core/adapter/adapters/akm-metadata.js +45 -45
  99. package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
  100. package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
  101. package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
  102. package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
  103. package/dist/core/adapter/adapters/index.js +0 -9
  104. package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
  105. package/dist/core/adapter/adapters/okf-adapter.js +4 -0
  106. package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
  107. package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
  108. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
  109. package/dist/core/adapter/execution-source.js +308 -0
  110. package/dist/core/adapter/recognize-match.js +36 -13
  111. package/dist/core/adapter/registry.js +0 -9
  112. package/dist/core/asset/stash-meta.js +94 -4
  113. package/dist/core/common.js +6 -11
  114. package/dist/core/config/config-io.js +3 -3
  115. package/dist/core/config/config-schema.js +18 -40
  116. package/dist/core/config/config-sources.js +11 -21
  117. package/dist/core/config/config-walker.js +31 -13
  118. package/dist/core/config/config.js +23 -26
  119. package/dist/core/config/schema/engines.js +8 -7
  120. package/dist/core/config/schema/improve-processes.js +29 -5
  121. package/dist/core/config/schema/index-config.js +0 -27
  122. package/dist/core/config/schema/primitives.js +1 -23
  123. package/dist/core/config/schema/sources-bundles.js +13 -16
  124. package/dist/core/errors.js +2 -0
  125. package/dist/core/events.js +68 -32
  126. package/dist/core/extra-params.js +1 -0
  127. package/dist/core/improve-result.js +315 -0
  128. package/dist/core/lesson-lint.js +0 -6
  129. package/dist/core/maintenance-barrier.js +4 -4
  130. package/dist/core/network-policy.js +152 -0
  131. package/dist/core/paths.js +1 -1
  132. package/dist/core/recognition-util.js +4 -4
  133. package/dist/core/registry-url.js +456 -0
  134. package/dist/core/state/migrations.js +161 -47
  135. package/dist/core/state-db.js +453 -80
  136. package/dist/core/system-error.js +32 -0
  137. package/dist/core/time.js +2 -12
  138. package/dist/core/write-source.js +0 -18
  139. package/dist/execution/directory-identity.js +52 -0
  140. package/dist/execution/executable-identity.js +107 -0
  141. package/dist/execution/guarded-source.js +398 -0
  142. package/dist/execution/json.js +95 -0
  143. package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
  144. package/dist/execution/record.js +55 -0
  145. package/dist/execution/resolved-request.js +730 -0
  146. package/dist/execution/source.js +320 -0
  147. package/dist/indexer/bundle-identity-guard.js +5 -4
  148. package/dist/indexer/db/graph-db.js +33 -0
  149. package/dist/indexer/graph/graph-boost.js +3 -4
  150. package/dist/indexer/graph/graph-extraction.js +562 -373
  151. package/dist/indexer/index-written-assets.js +78 -39
  152. package/dist/indexer/indexer.js +471 -432
  153. package/dist/indexer/installations.js +6 -0
  154. package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
  155. package/dist/indexer/materialize-embeddings.js +155 -0
  156. package/dist/indexer/passes/memory-inference.js +227 -174
  157. package/dist/indexer/passes/metadata.js +263 -118
  158. package/dist/indexer/scan/doc-to-entry.js +7 -10
  159. package/dist/indexer/scan/drain-dir.js +51 -23
  160. package/dist/indexer/search/db-search.js +156 -50
  161. package/dist/indexer/search/fts-query.js +40 -40
  162. package/dist/indexer/search/ranking.js +36 -1
  163. package/dist/indexer/search/search-attribution.js +3 -1
  164. package/dist/indexer/search/search-fields.js +23 -14
  165. package/dist/indexer/search/search-hit-enrichers.js +1 -1
  166. package/dist/indexer/search/search-source.js +7 -16
  167. package/dist/indexer/search/semantic-status.js +10 -1
  168. package/dist/indexer/usage/show-usage.js +105 -0
  169. package/dist/indexer/usage/usage-events.js +7 -2
  170. package/dist/indexer/walk/matchers.js +40 -10
  171. package/dist/indexer/walk/path-resolver.js +5 -2
  172. package/dist/indexer/walk/walker.js +20 -2
  173. package/dist/integrations/agent/builder-shared.js +3 -6
  174. package/dist/integrations/agent/conversation-fallback.js +16 -0
  175. package/dist/integrations/agent/engine-resolution.js +87 -87
  176. package/dist/integrations/agent/execution-cascade.js +566 -0
  177. package/dist/integrations/agent/execution-definitions.js +211 -0
  178. package/dist/integrations/agent/execution-lowering.js +811 -0
  179. package/dist/integrations/agent/execution-preparation.js +67 -0
  180. package/dist/integrations/agent/index.js +0 -2
  181. package/dist/integrations/agent/inline-execution.js +74 -0
  182. package/dist/integrations/agent/model-map.js +515 -0
  183. package/dist/integrations/agent/persona-fallback.js +30 -0
  184. package/dist/integrations/agent/request-lowering.js +186 -0
  185. package/dist/integrations/agent/runner-dispatch.js +230 -37
  186. package/dist/integrations/agent/runner.js +12 -83
  187. package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
  188. package/dist/integrations/harnesses/aider/index.js +0 -1
  189. package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
  190. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  191. package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
  192. package/dist/integrations/harnesses/claude/index.js +1 -5
  193. package/dist/integrations/harnesses/claude/session-log.js +3 -33
  194. package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
  195. package/dist/integrations/harnesses/codex/index.js +0 -1
  196. package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
  197. package/dist/integrations/harnesses/copilot/index.js +0 -1
  198. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
  199. package/dist/integrations/harnesses/gemini/index.js +0 -1
  200. package/dist/integrations/harnesses/index.js +4 -44
  201. package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
  202. package/dist/integrations/harnesses/opencode/index.js +0 -2
  203. package/dist/integrations/harnesses/opencode/session-log.js +14 -204
  204. package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
  205. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
  206. package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
  207. package/dist/integrations/harnesses/openhands/index.js +0 -1
  208. package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
  209. package/dist/integrations/harnesses/pi/index.js +0 -1
  210. package/dist/integrations/harnesses/shared.js +0 -1
  211. package/dist/integrations/harnesses/types.js +1 -3
  212. package/dist/integrations/lockfile.js +82 -79
  213. package/dist/integrations/session-logs/index.js +6 -17
  214. package/dist/integrations/session-logs/provider-base.js +1 -29
  215. package/dist/llm/client.js +10 -5
  216. package/dist/llm/embedder.js +6 -7
  217. package/dist/llm/embedders/local.js +37 -88
  218. package/dist/llm/embedders/types.js +1 -1
  219. package/dist/llm/graph-extract.js +75 -50
  220. package/dist/llm/index-passes.js +43 -5
  221. package/dist/llm/memory-infer.js +8 -6
  222. package/dist/llm/metadata-enhance.js +5 -3
  223. package/dist/llm/structured-call.js +122 -25
  224. package/dist/output/format-exempt.js +1 -1
  225. package/dist/output/render-registry.js +0 -16
  226. package/dist/output/renderers.js +12 -7
  227. package/dist/output/shapes/curate.js +1 -0
  228. package/dist/output/shapes/helpers.js +10 -2
  229. package/dist/output/shapes/passthrough.js +2 -0
  230. package/dist/output/text/command-format.js +31 -33
  231. package/dist/output/text/health-format.js +1 -29
  232. package/dist/output/text/migrate.js +6 -56
  233. package/dist/output/text/proposal-format.js +16 -1
  234. package/dist/output/text/workflow-format.js +16 -0
  235. package/dist/registry/network.js +279 -0
  236. package/dist/registry/pinned-request-helper.js +247 -0
  237. package/dist/registry/pinned-transport.js +717 -0
  238. package/dist/registry/providers/skills-sh.js +18 -6
  239. package/dist/registry/providers/static-index.js +20 -7
  240. package/dist/registry/resolve.js +53 -28
  241. package/dist/scripts/akm-migrate-node.js +19334 -52269
  242. package/dist/scripts/akm-migrate.js +19270 -51612
  243. package/dist/setup/registry-stash-loader.js +64 -20
  244. package/dist/setup/semantic-assets.js +9 -34
  245. package/dist/setup/setup.js +12 -30
  246. package/dist/setup/source-identity.js +17 -0
  247. package/dist/setup/steps/sources.js +36 -15
  248. package/dist/setup/steps/tasks.js +39 -11
  249. package/dist/sources/providers/git-provider.js +3 -3
  250. package/dist/sources/providers/npm.js +2 -2
  251. package/dist/sources/providers/provider-utils.js +4 -3
  252. package/dist/sources/providers/website.js +11 -7
  253. package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
  254. package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
  255. package/dist/sources/website-url.js +73 -0
  256. package/dist/storage/engines/sqlite-migrations.js +81 -26
  257. package/dist/storage/managed-db.js +27 -24
  258. package/dist/storage/repositories/events-repository.js +3 -0
  259. package/dist/storage/repositories/index-connection.js +42 -10
  260. package/dist/storage/repositories/index-entries-repository.js +203 -229
  261. package/dist/storage/repositories/index-entry-mapper.js +8 -12
  262. package/dist/storage/repositories/index-entry-schema.js +255 -0
  263. package/dist/storage/repositories/index-fts-repository.js +64 -71
  264. package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
  265. package/dist/storage/repositories/index-meta-repository.js +0 -11
  266. package/dist/storage/repositories/index-schema.js +74 -350
  267. package/dist/storage/repositories/index-utility-repository.js +12 -17
  268. package/dist/storage/repositories/index-vec-repository.js +56 -7
  269. package/dist/storage/repositories/proposals-repository.js +4 -127
  270. package/dist/storage/repositories/registry-cache.js +2 -1
  271. package/dist/storage/repositories/task-history-repository.js +20 -40
  272. package/dist/storage/repositories/workflow-runs-repository.js +228 -129
  273. package/dist/storage/sqlite-read-snapshot.js +148 -0
  274. package/dist/tasks/backends/cron.js +170 -42
  275. package/dist/tasks/backends/index.js +1 -1
  276. package/dist/tasks/backends/launchd.js +787 -202
  277. package/dist/tasks/backends/schtasks.js +282 -83
  278. package/dist/tasks/embedded.js +7 -7
  279. package/dist/tasks/frozen-script.js +50 -0
  280. package/dist/tasks/resolve-akm-bin.js +5 -1
  281. package/dist/tasks/runner.js +239 -251
  282. package/dist/tasks/runtime-v3.js +281 -0
  283. package/dist/tasks/scheduler-binding.js +272 -0
  284. package/dist/tasks/scheduler-invocation.js +57 -43
  285. package/dist/tasks/scheduler-sync.js +654 -0
  286. package/dist/tasks/source-v3.js +752 -0
  287. package/dist/tasks/standalone-script-entry.js +5 -0
  288. package/dist/tasks/task-id.js +29 -0
  289. package/dist/workflows/authoring/authoring.js +15 -32
  290. package/dist/workflows/exec/dispatch-redaction.js +14 -8
  291. package/dist/workflows/exec/exec-unit.js +7 -28
  292. package/dist/workflows/exec/frozen-judge.js +57 -89
  293. package/dist/workflows/exec/lowering-notices.js +23 -0
  294. package/dist/workflows/exec/native-executor.js +301 -458
  295. package/dist/workflows/exec/param-secrets.js +4 -3
  296. package/dist/workflows/exec/run-workflow.js +26 -32
  297. package/dist/workflows/exec/step-work.js +105 -109
  298. package/dist/workflows/exec/unit-dispatch.js +103 -27
  299. package/dist/workflows/exec/unit-writer.js +3 -3
  300. package/dist/workflows/exec/worktree.js +2 -2
  301. package/dist/workflows/ir/compile.js +86 -72
  302. package/dist/workflows/ir/environment-v4.js +328 -0
  303. package/dist/workflows/ir/freeze-v4.js +122 -0
  304. package/dist/workflows/ir/plan-hash.js +13 -7
  305. package/dist/workflows/ir/schema-v4.js +525 -0
  306. package/dist/workflows/ir/schema.js +25 -284
  307. package/dist/workflows/ir/source-freeze-v4.js +506 -0
  308. package/dist/workflows/parser.js +27 -24
  309. package/dist/workflows/program/schema.js +1 -2
  310. package/dist/workflows/renderer.js +42 -29
  311. package/dist/workflows/resource-limits.js +4 -5
  312. package/dist/workflows/runtime/agent-identity.js +11 -13
  313. package/dist/workflows/runtime/plan-classifier.js +8 -8
  314. package/dist/workflows/runtime/runs.js +27 -43
  315. package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
  316. package/dist/workflows/source-files.js +373 -0
  317. package/dist/workflows/source-ir/compile.js +196 -0
  318. package/dist/workflows/source-ir/github-yaml.js +577 -0
  319. package/dist/workflows/source-ir/ordering.js +38 -0
  320. package/dist/workflows/source-ir/program.js +50 -0
  321. package/dist/workflows/source-ir/result.js +26 -0
  322. package/dist/workflows/source-ir/schema.js +772 -0
  323. package/dist/workflows/source-ir/semantics.js +242 -0
  324. package/dist/workflows/source-ir/uses.js +14 -0
  325. package/docs/README.md +2 -0
  326. package/docs/migration/README.md +3 -1
  327. package/docs/migration/release-notes/0.9.2.md +55 -0
  328. package/docs/migration/release-notes/README.md +5 -0
  329. package/docs/migration/v0.8-to-v0.9.md +76 -1077
  330. package/docs/migration/v0.9.0-troubleshooting.md +104 -516
  331. package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
  332. package/docs/reference/README.md +1 -0
  333. package/docs/reference/cli.md +230 -98
  334. package/docs/reference/configuration.md +159 -36
  335. package/docs/reference/data-and-telemetry.md +19 -1
  336. package/docs/reference/supported-formats.md +23 -3
  337. package/docs/reference/tasks.md +182 -0
  338. package/docs/reference/workflow-schema.md +91 -40
  339. package/docs/reference/workflows.md +33 -6
  340. package/package.json +10 -6
  341. package/schemas/akm-config.json +372 -224
  342. package/schemas/akm-task.json +324 -80
  343. package/schemas/akm-workflow.json +6 -9
  344. package/dist/core/migration-operation.js +0 -75
  345. package/dist/integrations/agent/model-aliases.js +0 -74
  346. package/dist/tasks/parser.js +0 -380
  347. package/dist/tasks/schema.js +0 -123
  348. package/dist/tasks/validator.js +0 -80
  349. package/dist/workflows/ir/freeze.js +0 -320
  350. package/dist/workflows/runtime/document-cache.js +0 -13
@@ -3,12 +3,12 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { isSourceWriteActivated } from "../../core/activation-policy.js";
7
6
  import { isWithin, resolveStashDir } from "../../core/common.js";
8
7
  import { bundleComponentConfig, bundlesToSourceEntries, getSources, loadConfig } from "../../core/config/config.js";
9
8
  import { resolveGitContentRoot, resolveWritable } from "../../core/write-source.js";
10
9
  import { lockContentRootFor } from "../../integrations/lockfile.js";
11
10
  import { resolveSourceProviderFactory } from "../../sources/provider-factory.js";
11
+ import { ensureWebsiteMirror } from "../../sources/snapshot-fetchers/website-ingest.js";
12
12
  // Eager side-effect imports so all built-in source providers self-register
13
13
  // before resolveEntryContentDir() runs.
14
14
  import "../../sources/providers/index.js";
@@ -22,9 +22,8 @@ import { warn } from "../../core/warn.js";
22
22
  * 2. The configured `defaultBundle`, after component-root validation.
23
23
  * 3. Remaining configured bundles in installation-priority order.
24
24
  *
25
- * Replaces the previous four-pass loop that walked `stashes[]` separately
26
- * for each provider kind. Disabled entries (`enabled: false`) are filtered
27
- * after deduplication. Missing configured roots remain in the result so the
25
+ * Disabled entries (`enabled: false`) are filtered after deduplication.
26
+ * Missing configured roots remain in the result so the
28
27
  * indexer can classify their scan as incomplete instead of mistaking them for
29
28
  * removed sources.
30
29
  */
@@ -126,8 +125,8 @@ export function resolveEntryContentDir(entry) {
126
125
  // and writes agree on where content is); the localRoot is the already-walkable
127
126
  // content root (installed sources are extracted to their content dir), so no
128
127
  // content/-subdir step is applied. Fall back to the provider path logic when no
129
- // lock entry exists (e.g. a git bundle migrated from a `sources[]` url, whose
130
- // provider re-derives the mirror path).
128
+ // lock entry exists (for example while a configured source is being
129
+ // materialized for the first time).
131
130
  const localRoot = lockContentRootFor(entry.name, entry.type);
132
131
  if (localRoot != null)
133
132
  return localRoot;
@@ -165,14 +164,6 @@ export function resolveEntryContentDir(entry) {
165
164
  export function resolveAllStashDirs(overrideStashDir) {
166
165
  return resolveSourceEntries(overrideStashDir).map((s) => s.path);
167
166
  }
168
- /**
169
- * Return the resolved absolute paths of all writable stash sources.
170
- */
171
- export function getWritableStashDirs(overrideStashDir, existingConfig) {
172
- return resolveSourceEntries(overrideStashDir, existingConfig)
173
- .filter((s) => isSourceWriteActivated(s))
174
- .map((s) => s.path);
175
- }
176
167
  /**
177
168
  * Find which source a file path belongs to.
178
169
  *
@@ -263,7 +254,7 @@ export async function ensureSourceCaches(config, options) {
263
254
  // provider and call `sync()`. Every cache-backed kind (git, website, npm)
264
255
  // refreshes the same way — a bad source warns and is skipped without
265
256
  // aborting the others. The git content/-subdir layout convention stays in
266
- // resolveEntryContentDir. NEW shape reads `bundles`; old shape reads sources[].
257
+ // resolveEntryContentDir. Provider projection comes only from `bundles`.
267
258
  //
268
259
  // DISTINCTION (deliberately NOT lock-first): refresh derives the PROVIDER's
269
260
  // own cache path to git-pull/re-materialize INTO — that derived path is where
@@ -304,7 +295,7 @@ export async function ensureSourceCaches(config, options) {
304
295
  continue;
305
296
  }
306
297
  try {
307
- await provider.sync({ force, secrets: options?.secrets });
298
+ await provider.sync({ force, secrets: options?.secrets, ensureWebsiteMirror });
308
299
  }
309
300
  catch (err) {
310
301
  warn(`Warning: failed to refresh ${provider.kind} source "${provider.name}": ${err instanceof Error ? err.message : String(err)}`);
@@ -6,6 +6,11 @@ import { writeFileAtomic } from "../../core/common.js";
6
6
  import { getCacheDir, getSemanticStatusPath } from "../../core/paths.js";
7
7
  import { DETERMINISTIC_EMBED_MODEL_ID, isDeterministicEmbedEnabled } from "../../llm/embedders/deterministic.js";
8
8
  import { DEFAULT_LOCAL_MODEL } from "../../llm/embedders/local.js";
9
+ let semanticStatusMutationForTests;
10
+ /** TEST-ONLY. Inject a semantic-status filesystem publication fault. */
11
+ export function _setSemanticStatusMutationForTests(mutation) {
12
+ semanticStatusMutationForTests = mutation;
13
+ }
9
14
  export function deriveSemanticProviderFingerprint(embedding) {
10
15
  if (isDeterministicEmbedEnabled()) {
11
16
  return `deterministic:${DETERMINISTIC_EMBED_MODEL_ID}`;
@@ -49,11 +54,13 @@ export function readSemanticStatus() {
49
54
  return undefined;
50
55
  }
51
56
  export function writeSemanticStatus(status) {
57
+ semanticStatusMutationForTests?.("write");
52
58
  const dir = getCacheDir();
53
59
  fs.mkdirSync(dir, { recursive: true });
54
60
  writeFileAtomic(getSemanticStatusPath(), `${JSON.stringify(status, null, 2)}\n`);
55
61
  }
56
62
  export function clearSemanticStatus() {
63
+ semanticStatusMutationForTests?.("clear");
57
64
  try {
58
65
  fs.unlinkSync(getSemanticStatusPath());
59
66
  }
@@ -110,7 +117,9 @@ export function classifySemanticFailure(message) {
110
117
  if (lower.includes("404") || lower.includes("model not found") || lower.includes("bad request")) {
111
118
  return "remote-model";
112
119
  }
113
- if (lower.includes("transformers") || lower.includes("missing-package")) {
120
+ if (lower.includes("transformers") ||
121
+ lower.includes("missing-package") ||
122
+ lower.includes("local embedding dependency is unavailable")) {
114
123
  return "missing-package";
115
124
  }
116
125
  if (lower.includes("download")) {
@@ -0,0 +1,105 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import { makeBundleRef, parseBundleRef } from "../../core/asset/asset-ref.js";
5
+ import { rethrowIfTestIsolationError } from "../../core/errors.js";
6
+ import { appendEvent, readEvents } from "../../core/events.js";
7
+ import { withStateDbTelemetry } from "../../core/state-db.js";
8
+ import { TELEMETRY_BUSY_TIMEOUT_MS, withIndexDb } from "../../storage/repositories/index-db.js";
9
+ import { findEntryIdByRef, getEntryById, getEntryIdByFilePath, getItemRefById, } from "../../storage/repositories/index-entries-repository.js";
10
+ import { usageEventAttributionMetadata } from "../search/search-attribution.js";
11
+ import { insertUsageEvent } from "./usage-events.js";
12
+ /** Count prior show events in the current one-hour loop-detection window. */
13
+ export function recentShowCount(ref) {
14
+ try {
15
+ return readEvents({
16
+ type: "show",
17
+ ref,
18
+ since: new Date(Date.now() - 60 * 60 * 1000).toISOString(),
19
+ }).events.length;
20
+ }
21
+ catch {
22
+ return 0;
23
+ }
24
+ }
25
+ function appendShowTrace(ref, type, name) {
26
+ appendEvent({ eventType: "show", ref, metadata: { type, name } });
27
+ try {
28
+ const { events: recentSearches } = readEvents({
29
+ type: "search",
30
+ since: new Date(Date.now() - 60_000).toISOString(),
31
+ });
32
+ const cutoffMs = Date.now() - 60_000;
33
+ const matchingSearch = [...recentSearches].reverse().find((event) => {
34
+ if (!event.ts || new Date(event.ts).getTime() < cutoffMs)
35
+ return false;
36
+ const refs = event.metadata?.resultRefs ?? [];
37
+ return refs.includes(ref);
38
+ });
39
+ if (!matchingSearch)
40
+ return;
41
+ const resultRefs = matchingSearch.metadata?.resultRefs ?? [];
42
+ appendEvent({
43
+ eventType: "select",
44
+ ref,
45
+ metadata: {
46
+ query: matchingSearch.metadata?.query,
47
+ searchTs: matchingSearch.ts,
48
+ rankPosition: resultRefs.indexOf(ref),
49
+ },
50
+ });
51
+ }
52
+ catch {
53
+ // Selection attribution is best-effort.
54
+ }
55
+ }
56
+ function insertShowUsage(entryId, entryRef, derivedFrom, eventSource) {
57
+ withStateDbTelemetry((stateDb) => {
58
+ insertUsageEvent(stateDb, {
59
+ event_type: "show",
60
+ entry_ref: entryRef,
61
+ entry_id: entryId,
62
+ metadata: usageEventAttributionMetadata(derivedFrom ? { memoryInference: { exposure: "direct" } } : undefined, entryRef),
63
+ source: eventSource,
64
+ });
65
+ }, TELEMETRY_BUSY_TIMEOUT_MS);
66
+ }
67
+ /** Record a successful show using the already-rendered response identity. */
68
+ export function recordShowUsage(ref, type, name, eventSource = "user", filePath) {
69
+ const parsed = parseBundleRef(ref);
70
+ const eventRef = makeBundleRef(parsed.bundle, parsed.conceptId);
71
+ appendShowTrace(eventRef, type, name);
72
+ try {
73
+ withIndexDb((db) => {
74
+ const entryId = filePath ? getEntryIdByFilePath(db, filePath) : findEntryIdByRef(db, eventRef);
75
+ if (entryId === undefined)
76
+ return;
77
+ const entryRef = getItemRefById(db, entryId);
78
+ if (!entryRef)
79
+ return;
80
+ insertShowUsage(entryId, entryRef, getEntryById(db, entryId)?.entry.derivedFrom, eventSource);
81
+ }, { busyTimeoutMs: TELEMETRY_BUSY_TIMEOUT_MS });
82
+ }
83
+ catch (error) {
84
+ rethrowIfTestIsolationError(error);
85
+ }
86
+ }
87
+ /** Record a nested execution-source read only after dispatch has crossed preflight. */
88
+ export function recordIndexedShowUsage(ref, eventSource = "user") {
89
+ try {
90
+ withIndexDb((db) => {
91
+ const entryId = findEntryIdByRef(db, ref);
92
+ if (entryId === undefined)
93
+ return;
94
+ const indexed = getEntryById(db, entryId);
95
+ const entryRef = getItemRefById(db, entryId);
96
+ if (!indexed || !entryRef)
97
+ return;
98
+ appendShowTrace(entryRef, indexed.entry.type, indexed.entry.name);
99
+ insertShowUsage(entryId, entryRef, indexed.entry.derivedFrom, eventSource);
100
+ }, { busyTimeoutMs: TELEMETRY_BUSY_TIMEOUT_MS });
101
+ }
102
+ catch (error) {
103
+ rethrowIfTestIsolationError(error);
104
+ }
105
+ }
@@ -75,12 +75,17 @@ export function countUsageEventsByType(db, eventType) {
75
75
  /**
76
76
  * Delete usage events older than the given number of days.
77
77
  */
78
- export function purgeOldUsageEvents(db, retentionDays) {
78
+ export function purgeOldUsageEvents(db, retentionDays, options) {
79
79
  if (!Number.isFinite(retentionDays) || retentionDays <= 0)
80
80
  return;
81
81
  try {
82
+ const stateSchema = options?.stateSchema;
83
+ if (stateSchema !== undefined && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(stateSchema)) {
84
+ throw new Error("Invalid attached state schema name.");
85
+ }
86
+ const usageEvents = stateSchema === undefined ? "usage_events" : `"${stateSchema}".usage_events`;
82
87
  const cutoff = new Date(Date.now() - retentionDays * 86_400_000).toISOString();
83
- db.prepare("DELETE FROM usage_events WHERE created_at < ?").run(cutoff);
88
+ db.prepare(`DELETE FROM ${usageEvents} WHERE created_at < ?`).run(cutoff);
84
89
  }
85
90
  catch {
86
91
  /* Table may not exist yet */
@@ -49,7 +49,7 @@ const DIR_TYPE_MAP = [
49
49
  {
50
50
  dir: "workflows",
51
51
  type: "workflow",
52
- test: (ext) => ext === ".md",
52
+ test: (ext) => ext === ".md" || ext === ".yml",
53
53
  },
54
54
  {
55
55
  dir: "memories",
@@ -102,6 +102,13 @@ const DIR_TYPE_MAP = [
102
102
  },
103
103
  ];
104
104
  const COMMAND_PLACEHOLDER_RE = /\$ARGUMENTS|\$[123]\b/;
105
+ const SMART_MD_FACTS = {
106
+ workflow: { type: "workflow", specificity: 19 },
107
+ toolsAgent: { type: "agent", specificity: 20 },
108
+ command: { type: "command", specificity: 18 },
109
+ modelAgent: { type: "agent", specificity: 8 },
110
+ knowledge: { type: "knowledge", specificity: 5 },
111
+ };
105
112
  // Files that should never be treated as the typed asset for the surrounding
106
113
  // directory (e.g. `workflows/README.md` is documentation, not a workflow).
107
114
  // Lower-cased and matched case-insensitively against `ctx.fileName`. They are
@@ -175,7 +182,7 @@ function classifyBySmartMd(ctx) {
175
182
  // body shape would otherwise classify (e.g. step-list inside a project
176
183
  // README under workflows/). Fall straight through to `knowledge`.
177
184
  if (isTypedDirDocFile(ctx.fileName)) {
178
- return { type: "knowledge", specificity: 5 };
185
+ return SMART_MD_FACTS.knowledge;
179
186
  }
180
187
  const body = ctx.content();
181
188
  const fm = ctx.frontmatter();
@@ -185,33 +192,34 @@ function classifyBySmartMd(ctx) {
185
192
  // this only catches a workflow living OUTSIDE `workflows/` that still
186
193
  // declares its type explicitly.
187
194
  if (fm && fm.type === "workflow") {
188
- return { type: "workflow", specificity: 19 };
195
+ return SMART_MD_FACTS.workflow;
189
196
  }
190
197
  if (fm) {
191
198
  // `tools` is the one authoring key for an agent's tool grant. Recognition
192
199
  // covers only the key the renderer honors.
193
200
  if ("tools" in fm) {
194
- return { type: "agent", specificity: 20 };
201
+ return SMART_MD_FACTS.toolsAgent;
195
202
  }
196
203
  if ("agent" in fm) {
197
- return { type: "command", specificity: 18 };
204
+ return SMART_MD_FACTS.command;
198
205
  }
199
206
  }
200
207
  if (COMMAND_PLACEHOLDER_RE.test(body)) {
201
- return { type: "command", specificity: 18 };
208
+ return SMART_MD_FACTS.command;
202
209
  }
203
210
  if (fm && "model" in fm) {
204
- return { type: "agent", specificity: 8 };
211
+ return SMART_MD_FACTS.modelAgent;
205
212
  }
206
- return { type: "knowledge", specificity: 5 };
213
+ return SMART_MD_FACTS.knowledge;
207
214
  }
208
215
  // ---------------------------------------------------------------------------
209
216
  // Adapter: MatchFact → MatchResult
210
217
  // ---------------------------------------------------------------------------
211
218
  function toMatchResult(ctx, classify) {
212
219
  const fact = classify(ctx);
213
- if (!fact)
214
- return null;
220
+ return fact ? matchResultForFact(fact) : null;
221
+ }
222
+ function matchResultForFact(fact) {
215
223
  // Renderer name resolved via TYPE_PRESENTATION (core leaf), so matchers.ts
216
224
  // carries no edge into the taxonomy SCC (chunk-3 cutover enabler).
217
225
  // TYPE_PRESENTATION.renderer is the single source of truth for renderer names.
@@ -225,6 +233,28 @@ function toMatchResult(ctx, classify) {
225
233
  ...(fact.meta ? { meta: fact.meta } : {}),
226
234
  };
227
235
  }
236
+ /**
237
+ * Every smart-Markdown result possible from path fields alone. The actual
238
+ * classifier above returns only facts from this shared table, so owner
239
+ * discovery can conservatively model a byte request without reading bytes.
240
+ */
241
+ export function smartMdPathCandidates(ctx) {
242
+ if (ctx.ext !== ".md" || ctx.ancestorDirs.includes("secrets"))
243
+ return [];
244
+ const facts = isTypedDirDocFile(ctx.fileName)
245
+ ? [SMART_MD_FACTS.knowledge]
246
+ : [
247
+ SMART_MD_FACTS.workflow,
248
+ SMART_MD_FACTS.toolsAgent,
249
+ SMART_MD_FACTS.command,
250
+ SMART_MD_FACTS.modelAgent,
251
+ SMART_MD_FACTS.knowledge,
252
+ ];
253
+ return facts.flatMap((fact) => {
254
+ const result = matchResultForFact(fact);
255
+ return result ? [result] : [];
256
+ });
257
+ }
228
258
  // ---------------------------------------------------------------------------
229
259
  // Public matchers (API unchanged)
230
260
  // ---------------------------------------------------------------------------
@@ -8,6 +8,7 @@ import { parseRefInput } from "../../core/asset/resolve-ref.js";
8
8
  import { isWithin } from "../../core/common.js";
9
9
  import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
10
10
  import { lookup } from "../indexer.js";
11
+ import { deriveInstallations } from "../installations.js";
11
12
  import { resolveSourceEntries } from "../search/search-source.js";
12
13
  function normalizeRef(ref) {
13
14
  // String inputs use the current `[bundle//]conceptId` grammar.
@@ -65,8 +66,10 @@ function resolveViaDisk(ref, options) {
65
66
  }
66
67
  const directoryIndexNames = options.directoryIndexNames ?? ["SKILL.md"];
67
68
  const preserveDirectNameFallback = options.preserveDirectNameFallback ?? true;
68
- for (const source of sources) {
69
- if (options.writableDirSet && !options.writableDirSet.has(path.resolve(source.path)))
69
+ const installations = deriveInstallations(sources);
70
+ for (const [index, source] of sources.entries()) {
71
+ const bundleId = installations[index]?.id;
72
+ if (options.writableBundleIds && (!bundleId || !options.writableBundleIds.has(bundleId)))
70
73
  continue;
71
74
  const candidates = buildDiskCandidates(source.path, ref, preserveDirectNameFallback);
72
75
  for (const candidate of candidates) {
@@ -11,6 +11,7 @@
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
13
  import { isRelevantAssetFile } from "../../core/asset/asset-placement.js";
14
+ import { WORKFLOW_EXTENSIONS } from "../../core/recognition-util.js";
14
15
  import { spawnSync } from "../../runtime.js";
15
16
  import { buildFileContext } from "./file-context.js";
16
17
  const ALWAYS_SKIP_DIRS = new Set([".git"]);
@@ -128,7 +129,8 @@ function walkStashGit(stashRoot, options) {
128
129
  // indexed. The manual walk below already skips symlinks for exactly this
129
130
  // reason; the two walkers have to agree regardless of whether the stash
130
131
  // happens to sit inside a git repo.
131
- if (fs.lstatSync(absPath).isFile()) {
132
+ const stat = fs.lstatSync(absPath);
133
+ if (stat.isFile() || (stat.isSymbolicLink() && isOwnedWorkflowSymlink(stashRoot, absPath, options))) {
132
134
  results.push(buildFileContext(stashRoot, absPath));
133
135
  }
134
136
  }
@@ -219,7 +221,11 @@ function walkStashManual(stashRoot, options) {
219
221
  continue;
220
222
  const fullPath = path.join(current, entry.name);
221
223
  if (entry.isSymbolicLink()) {
222
- // Skip symlinks entirely to prevent potential path traversal outside stashRoot
224
+ // Native workflow components arbitrate file symlinks explicitly in the
225
+ // drain before reading them. Directory symlinks remain unfollowed.
226
+ if (isOwnedWorkflowSymlink(stashRoot, fullPath, options)) {
227
+ results.push(buildFileContext(stashRoot, fullPath));
228
+ }
223
229
  continue;
224
230
  }
225
231
  if (entry.isDirectory()) {
@@ -235,3 +241,15 @@ function walkStashManual(stashRoot, options) {
235
241
  }
236
242
  return { files: results, complete };
237
243
  }
244
+ function isOwnedWorkflowSymlink(stashRoot, candidatePath, options) {
245
+ const adapterId = options.workflowSymlinkAdapter;
246
+ if (!adapterId)
247
+ return false;
248
+ const relativePath = path.relative(path.resolve(stashRoot), path.resolve(candidatePath)).replaceAll("\\", "/");
249
+ if (!relativePath || relativePath.startsWith("../") || path.posix.isAbsolute(relativePath))
250
+ return false;
251
+ if (adapterId === "akm" && !relativePath.startsWith("workflows/"))
252
+ return false;
253
+ const extension = path.posix.extname(relativePath).toLowerCase();
254
+ return WORKFLOW_EXTENSIONS.includes(extension);
255
+ }
@@ -14,12 +14,9 @@
14
14
  * their previous home in `builders.ts`.
15
15
  */
16
16
  import { UsageError } from "../../core/errors.js";
17
- import { resolveModel } from "./model-aliases.js";
18
- /** Resolve a raw dispatch model once, while preserving frozen/lowered models verbatim. */
19
- export function resolveDispatchModel(request, profile, platform) {
20
- if (!request.model || request.modelIsExact)
21
- return request.model;
22
- return resolveModel(request.model, platform, profile.modelAliases, profile.globalModelAliases);
17
+ /** Models reaching a harness have already crossed the single model-map boundary. */
18
+ export function resolveDispatchModel(request, _profile, _platform) {
19
+ return request.model;
23
20
  }
24
21
  /**
25
22
  * Guard against values that start with `--`, which would be mis-interpreted as
@@ -0,0 +1,16 @@
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 const CONVERSATION_FALLBACK_BEGIN = "<AKM_CONVERSATION_JSON>";
5
+ export const CONVERSATION_FALLBACK_END = "</AKM_CONVERSATION_JSON>";
6
+ /**
7
+ * Preserve ordered message roles for a one-shot transport with no native
8
+ * conversation channel. The fixed `{role,content}` projection and UTF-8 byte
9
+ * length make the embedded JSON unambiguous even when content contains marker
10
+ * text. The terminal command remains outside the prefix block.
11
+ */
12
+ export function composeConversationFallbackPrompt(conversation, command) {
13
+ const json = JSON.stringify(conversation.map((message) => ({ role: message.role, content: message.content })));
14
+ const byteLength = new TextEncoder().encode(json).byteLength;
15
+ return `${CONVERSATION_FALLBACK_BEGIN} ${byteLength}\n${json}\n${CONVERSATION_FALLBACK_END}\n\n${command}`;
16
+ }