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
@@ -0,0 +1,320 @@
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 { bundleRefToString, isBundleSlug, parseBundleRef } from "../core/asset/asset-ref.js";
5
+ import { cloneExecutionJson, cloneExecutionJsonObject, } from "./json.js";
6
+ import { assertSnapshotKeys, snapshotStrictRecord } from "./record.js";
7
+ export const EXECUTION_SOURCE_SCHEMA_VERSION = 1;
8
+ /** Current internal adapter identifiers are lowercase kebab-case registry keys. */
9
+ export const EXECUTION_ADAPTER_ID_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
10
+ const CONTROL_OR_LINE_SEPARATOR_PATTERN = /[\p{Cc}\p{Zl}\p{Zp}]/u;
11
+ const FORMAT_CHARACTER_PATTERN = /\p{Cf}/u;
12
+ const WINDOWS_DRIVE_PREFIX_PATTERN = /^[A-Za-z]:/;
13
+ const RESERVED_EXTENSION_OWNERS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
14
+ const renderedSourceBrand = Symbol("akm.adapter-rendered-execution-source");
15
+ const renderedSourceInstances = new WeakSet();
16
+ function requireRecord(value, path) {
17
+ return snapshotStrictRecord(value, path);
18
+ }
19
+ function assertOnlyKeys(value, allowed, path) {
20
+ assertSnapshotKeys(value, allowed, path);
21
+ }
22
+ function validateExtensionOwner(owner) {
23
+ const normalized = owner.toLowerCase();
24
+ if (!EXECUTION_ADAPTER_ID_PATTERN.test(owner) || RESERVED_EXTENSION_OWNERS.has(normalized)) {
25
+ throw new TypeError(`extension owner must be a canonical, non-reserved adapter identifier: ${owner}`);
26
+ }
27
+ }
28
+ function frozenNullPrototypeMap(entries) {
29
+ const out = Object.create(null);
30
+ for (const [key, value] of entries) {
31
+ Object.defineProperty(out, key, { value, enumerable: true, configurable: false, writable: false });
32
+ }
33
+ return Object.freeze(out);
34
+ }
35
+ function cloneExtensionEntry(value, index) {
36
+ const path = `extension entry ${index}`;
37
+ const cloned = cloneExecutionJson(value, path);
38
+ if (!Array.isArray(cloned) || cloned.length !== 2) {
39
+ throw new TypeError(`${path} must be a two-element [owner, values] array`);
40
+ }
41
+ const [owner, values] = cloned;
42
+ if (typeof owner !== "string")
43
+ throw new TypeError(`${path} owner must be a string`);
44
+ if (values === null || Array.isArray(values) || typeof values !== "object") {
45
+ throw new TypeError(`${path} values must be a JSON object`);
46
+ }
47
+ return [owner, values];
48
+ }
49
+ export function createAdapterExtensions(first, second, ...rest) {
50
+ const rawEntries = typeof first === "string"
51
+ ? [[first, second]]
52
+ : [first, ...(second === undefined ? [] : [second]), ...rest];
53
+ const seen = new Set();
54
+ const cloned = [];
55
+ for (const [index, rawEntry] of rawEntries.entries()) {
56
+ const [owner, values] = cloneExtensionEntry(rawEntry, index);
57
+ validateExtensionOwner(owner);
58
+ if (seen.has(owner))
59
+ throw new TypeError(`duplicate extension owner: ${owner}`);
60
+ seen.add(owner);
61
+ cloned.push([owner, cloneExecutionJsonObject(values, `extensions.${owner}`)]);
62
+ }
63
+ return frozenNullPrototypeMap(cloned);
64
+ }
65
+ export function cloneAdapterExtensions(value, path) {
66
+ const record = requireRecord(value, path);
67
+ const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path}.${owner}`)]);
68
+ const [first, ...rest] = entries;
69
+ return first ? createAdapterExtensions(first, ...rest) : frozenNullPrototypeMap([]);
70
+ }
71
+ function requireCanonicalString(value, path) {
72
+ if (typeof value !== "string" ||
73
+ value.length === 0 ||
74
+ !isWellFormedUnicode(value) ||
75
+ value.normalize("NFC") !== value) {
76
+ throw new TypeError(`${path} must be a non-empty NFC string`);
77
+ }
78
+ if (hasUnsafeIdentityCharacter(value)) {
79
+ throw new TypeError(`${path} must not contain Unicode control or dangerous format characters`);
80
+ }
81
+ return value;
82
+ }
83
+ /**
84
+ * Validate a selector/layer identifier that may cross the durable execution
85
+ * boundary. Keep this shared with the cascade planner so resume cannot admit a
86
+ * selector the live planner would reject.
87
+ */
88
+ export function requireStableExecutionSelector(value, path) {
89
+ let selector;
90
+ try {
91
+ selector = requireCanonicalString(value, path);
92
+ }
93
+ catch (cause) {
94
+ throw new TypeError(`${path} must be a non-empty stable NFC identifier`, { cause });
95
+ }
96
+ if (selector.length > 512 || selector.trim() !== selector) {
97
+ throw new TypeError(`${path} must be a non-empty stable NFC identifier`);
98
+ }
99
+ return selector;
100
+ }
101
+ export function isPortableExecutionAgentSelector(value) {
102
+ return /^(?:[^/]+\/\/)?agents\/[^/]/.test(value);
103
+ }
104
+ export function executionPersonaMatchesSelector(selector, personaRef) {
105
+ return selector.includes("//") ? selector === personaRef : personaRef.endsWith(`//${selector}`);
106
+ }
107
+ function hasUnsafeIdentityCharacter(value) {
108
+ for (const character of value) {
109
+ if (CONTROL_OR_LINE_SEPARATOR_PATTERN.test(character))
110
+ return true;
111
+ // Join controls are meaningful in emoji and several writing systems. All
112
+ // other format controls are rejected because they can conceal identity.
113
+ if (FORMAT_CHARACTER_PATTERN.test(character) && character !== "\u200C" && character !== "\u200D")
114
+ return true;
115
+ }
116
+ return false;
117
+ }
118
+ function isWellFormedUnicode(value) {
119
+ for (let index = 0; index < value.length; index += 1) {
120
+ const code = value.charCodeAt(index);
121
+ if (code >= 0xd800 && code <= 0xdbff) {
122
+ const next = value.charCodeAt(index + 1);
123
+ if (!(next >= 0xdc00 && next <= 0xdfff))
124
+ return false;
125
+ index += 1;
126
+ }
127
+ else if (code >= 0xdc00 && code <= 0xdfff) {
128
+ return false;
129
+ }
130
+ }
131
+ return true;
132
+ }
133
+ function validateCanonicalIdentity(input, path) {
134
+ assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path);
135
+ const ref = requireCanonicalString(input.ref, `${path}.ref`);
136
+ const bundle = requireCanonicalString(input.bundle, `${path}.bundle`);
137
+ const adapter = requireCanonicalString(input.adapter, `${path}.adapter`);
138
+ const file = requireCanonicalString(input.file, `${path}.file`);
139
+ const hash = requireCanonicalString(input.hash, `${path}.hash`);
140
+ let parsed;
141
+ try {
142
+ parsed = parseBundleRef(ref);
143
+ }
144
+ catch (cause) {
145
+ throw new TypeError(`${path}.ref is not a canonical bundle ref`, { cause });
146
+ }
147
+ if (parsed.bundle === undefined ||
148
+ parsed.bundle !== bundle ||
149
+ parsed.fragment !== undefined ||
150
+ !isBundleSlug(bundle) ||
151
+ bundleRefToString(parsed) !== ref) {
152
+ throw new TypeError(`${path}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
153
+ }
154
+ if (!EXECUTION_ADAPTER_ID_PATTERN.test(adapter)) {
155
+ throw new TypeError(`${path}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
156
+ }
157
+ const segments = file.split("/");
158
+ if (file.startsWith("/") ||
159
+ WINDOWS_DRIVE_PREFIX_PATTERN.test(file) ||
160
+ file.includes("\\") ||
161
+ segments.some((segment) => !segment || segment === "." || segment === "..")) {
162
+ throw new TypeError(`${path}.file must be a normalized relative POSIX path`);
163
+ }
164
+ if (!/^[a-f0-9]{64}$/.test(hash))
165
+ throw new TypeError(`${path}.hash must be a SHA-256 hex digest`);
166
+ return { ref, bundle, adapter, file, hash };
167
+ }
168
+ /** Validate, clone, and freeze an identity produced by an adapter renderer. */
169
+ export function createExecutionSourceIdentity(input) {
170
+ return Object.freeze(validateCanonicalIdentity(requireRecord(input, "execution source identity"), "execution source identity"));
171
+ }
172
+ /** Validate and freeze a source identity read back from a frozen request. */
173
+ export function decodeExecutionSourceIdentity(value, path = "execution source identity") {
174
+ return Object.freeze(validateCanonicalIdentity(requireRecord(value, path), path));
175
+ }
176
+ export function cloneUnresolvedExecutionDefaults(input, path = "execution source defaults") {
177
+ const record = requireRecord(input, path);
178
+ assertOnlyKeys(record, [
179
+ "agent",
180
+ "engine",
181
+ "model",
182
+ "inference",
183
+ "outputSchema",
184
+ "tools",
185
+ "timeout",
186
+ "workspace",
187
+ "environment",
188
+ "runtime",
189
+ ], path);
190
+ const json = { ...cloneExecutionJsonObject(record, path) };
191
+ for (const key of ["agent", "engine", "model", "workspace"]) {
192
+ const value = json[key];
193
+ if (value !== undefined && value !== null && typeof value !== "string") {
194
+ throw new TypeError(`${path}.${key} must be a string or null`);
195
+ }
196
+ }
197
+ const timeout = json.timeout;
198
+ if (timeout !== undefined && timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
199
+ throw new TypeError(`${path}.timeout must be a string, number, or null`);
200
+ }
201
+ for (const key of ["inference", "outputSchema", "runtime"]) {
202
+ const value = json[key];
203
+ if (value !== undefined && value !== null && (Array.isArray(value) || typeof value !== "object")) {
204
+ throw new TypeError(`${path}.${key} must be an object or null`);
205
+ }
206
+ }
207
+ const environment = json.environment;
208
+ if (environment !== undefined && environment !== null) {
209
+ if (Array.isArray(environment) || typeof environment !== "object") {
210
+ throw new TypeError(`${path}.environment must be an object or null`);
211
+ }
212
+ if (Object.values(environment).some((value) => typeof value !== "string")) {
213
+ throw new TypeError(`${path}.environment values must be strings`);
214
+ }
215
+ }
216
+ if (Object.hasOwn(json, "tools"))
217
+ json.tools = cloneToolSelection(json.tools, `${path}.tools`);
218
+ return Object.freeze(json);
219
+ }
220
+ export function cloneToolSelection(value, path = "tools") {
221
+ if (value === null || typeof value === "string")
222
+ return value;
223
+ const cloned = cloneExecutionJson(value, path);
224
+ if (Array.isArray(cloned)) {
225
+ if (cloned.some((tool) => typeof tool !== "string"))
226
+ throw new TypeError(`${path} array values must be strings`);
227
+ return cloned;
228
+ }
229
+ return cloneExecutionJsonObject(cloned, path);
230
+ }
231
+ export function createAdapterRenderedExecutionSource(input) {
232
+ const record = requireRecord(input, "adapter-rendered execution source");
233
+ assertOnlyKeys(record, ["kind", "content", "identity", "defaults", "extensions"], "adapter-rendered execution source");
234
+ const kind = record.kind;
235
+ const content = record.content;
236
+ if (kind !== "command" && kind !== "persona")
237
+ throw new TypeError("execution source kind is invalid");
238
+ if (typeof content !== "string")
239
+ throw new TypeError("execution source content must be a string");
240
+ const defaults = Object.hasOwn(record, "defaults") ? record.defaults : {};
241
+ if (defaults === undefined) {
242
+ throw new TypeError("execution source defaults must be omitted or be an object");
243
+ }
244
+ const source = {
245
+ schemaVersion: EXECUTION_SOURCE_SCHEMA_VERSION,
246
+ kind,
247
+ content,
248
+ defaults: cloneUnresolvedExecutionDefaults(defaults),
249
+ identity: createExecutionSourceIdentity(record.identity),
250
+ };
251
+ if (Object.hasOwn(record, "extensions")) {
252
+ source.extensions = cloneAdapterExtensions(record.extensions, "execution source extensions");
253
+ }
254
+ Object.defineProperty(source, renderedSourceBrand, { value: true, enumerable: false });
255
+ const frozen = Object.freeze(source);
256
+ renderedSourceInstances.add(frozen);
257
+ return frozen;
258
+ }
259
+ function isAdapterRenderedSource(value, kind) {
260
+ if (typeof value !== "object" || value === null)
261
+ return false;
262
+ if (!renderedSourceInstances.has(value))
263
+ return false;
264
+ if (Object.getPrototypeOf(value) !== Object.prototype || !Object.isFrozen(value))
265
+ return false;
266
+ if (!Object.hasOwn(value, renderedSourceBrand))
267
+ return false;
268
+ const required = new Set(["schemaVersion", "kind", "content", "defaults", "identity"]);
269
+ const optional = new Set(["extensions"]);
270
+ for (const key of Reflect.ownKeys(value)) {
271
+ if (key === renderedSourceBrand)
272
+ continue;
273
+ if (typeof key !== "string" || (!required.delete(key) && !optional.has(key)))
274
+ return false;
275
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
276
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable)
277
+ return false;
278
+ }
279
+ if (required.size > 0)
280
+ return false;
281
+ const brand = Object.getOwnPropertyDescriptor(value, renderedSourceBrand);
282
+ const source = value;
283
+ if (brand?.value !== true ||
284
+ brand.enumerable !== false ||
285
+ brand.configurable !== false ||
286
+ brand.writable !== false ||
287
+ source.schemaVersion !== EXECUTION_SOURCE_SCHEMA_VERSION ||
288
+ source.kind !== kind ||
289
+ typeof source.content !== "string" ||
290
+ typeof source.defaults !== "object" ||
291
+ source.defaults === null ||
292
+ !Object.isFrozen(source.defaults) ||
293
+ typeof source.identity !== "object" ||
294
+ source.identity === null ||
295
+ Object.getPrototypeOf(source.identity) !== Object.prototype ||
296
+ !Object.isFrozen(source.identity)) {
297
+ return false;
298
+ }
299
+ if (Object.hasOwn(source, "extensions")) {
300
+ if (typeof source.extensions !== "object" ||
301
+ source.extensions === null ||
302
+ Object.getPrototypeOf(source.extensions) !== null ||
303
+ !Object.isFrozen(source.extensions)) {
304
+ return false;
305
+ }
306
+ }
307
+ try {
308
+ decodeExecutionSourceIdentity(source.identity);
309
+ }
310
+ catch {
311
+ return false;
312
+ }
313
+ return true;
314
+ }
315
+ export function isAdapterRenderedCommandSource(value) {
316
+ return isAdapterRenderedSource(value, "command");
317
+ }
318
+ export function isAdapterRenderedPersonaSource(value) {
319
+ return isAdapterRenderedSource(value, "persona");
320
+ }
@@ -31,7 +31,7 @@ import fs from "node:fs";
31
31
  import { loadConfig } from "../core/config/config.js";
32
32
  import { getDbPath } from "../core/paths.js";
33
33
  import { warn } from "../core/warn.js";
34
- import { openDatabase } from "../storage/database.js";
34
+ import { closeDatabase, openReadonlyExistingDatabase } from "../storage/repositories/index-connection.js";
35
35
  let guardSettled = false;
36
36
  /** TEST-ONLY: re-arm the once-per-process guard between cases. */
37
37
  export function resetBundleIdentityGuardForTests() {
@@ -43,8 +43,8 @@ function indexBundlePrefixes(dbPath) {
43
43
  return undefined;
44
44
  let db;
45
45
  try {
46
- db = openDatabase(dbPath, { readonly: true });
47
- if (!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='entries'").get())
46
+ db = openReadonlyExistingDatabase(dbPath);
47
+ if (!db)
48
48
  return undefined;
49
49
  return db
50
50
  .prepare("SELECT DISTINCT bundle_id AS b FROM entries WHERE bundle_id IS NOT NULL AND bundle_id != ''")
@@ -54,7 +54,8 @@ function indexBundlePrefixes(dbPath) {
54
54
  return undefined;
55
55
  }
56
56
  finally {
57
- db?.close();
57
+ if (db)
58
+ closeDatabase(db);
58
59
  }
59
60
  }
60
61
  /**
@@ -219,6 +219,39 @@ export function drainExtractionQueue(db, stashRoot, limit) {
219
219
  return [];
220
220
  }
221
221
  }
222
+ /** Read queued graph work without claiming or deleting it. */
223
+ export function peekExtractionQueue(db, stashRoot, limit) {
224
+ try {
225
+ const rows = db
226
+ .prepare(`SELECT file_path, body_hash, priority
227
+ FROM graph_extraction_queue
228
+ WHERE stash_root = ?
229
+ ORDER BY priority DESC, queued_at ASC
230
+ LIMIT ?`)
231
+ .all(stashRoot, limit);
232
+ return rows.map((row) => ({ filePath: row.file_path, bodyHash: row.body_hash, priority: row.priority }));
233
+ }
234
+ catch (err) {
235
+ rethrowIfTestIsolationError(err);
236
+ return [];
237
+ }
238
+ }
239
+ /**
240
+ * Acknowledge the exact queued revision that was classified and handled.
241
+ * A concurrent re-enqueue with a new body hash therefore survives.
242
+ */
243
+ export function acknowledgeExtractionQueueEntry(db, stashRoot, filePath, bodyHash) {
244
+ try {
245
+ const result = db
246
+ .prepare("DELETE FROM graph_extraction_queue WHERE stash_root = ? AND file_path = ? AND body_hash = ?")
247
+ .run(stashRoot, filePath, bodyHash);
248
+ return result.changes > 0;
249
+ }
250
+ catch (err) {
251
+ rethrowIfTestIsolationError(err);
252
+ return false;
253
+ }
254
+ }
222
255
  /**
223
256
  * Scoped loader — graph_files rows without entities/relations. Used for
224
257
  * orphan detection and entity overview commands.
@@ -250,7 +250,7 @@ export function collectGraphRelatedHit(context, filePath) {
250
250
  * idx_graph_files_path guarantees one graph_files row per path).
251
251
  *
252
252
  * The returned `ref` field carries the canonical indexed `concept_id`, never a
253
- * value re-derived from presentation fields or `entry_key`. It is undefined
253
+ * value re-derived from presentation fields. It is undefined
254
254
  * when the graph row has no matching entry with current indexed provenance.
255
255
  */
256
256
  export function listRelatedPathsForFile(stashRoot, filePath, limit = 5, db) {
@@ -348,9 +348,8 @@ export function listRelatedPathsForFile(stashRoot, filePath, limit = 5, db) {
348
348
  try {
349
349
  const entryRows = db
350
350
  .prepare(`SELECT file_path, concept_id FROM entries
351
- WHERE file_path IN (${placeholders}) AND stash_dir = ?
352
- AND item_ref IS NOT NULL AND concept_id IS NOT NULL`)
353
- .all(...candidatePaths, stashRoot);
351
+ WHERE file_path IN (${placeholders})`)
352
+ .all(...candidatePaths);
354
353
  for (const row of entryRows) {
355
354
  refByPath.set(row.file_path, row.concept_id);
356
355
  }