@aiwg/cli 2026.10.1 → 2026.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/capability-matrix.yaml +270 -0
  3. package/agentic/code/providers/model-capabilities.v1.json +3183 -24
  4. package/bin/aiwg.mjs +135 -47
  5. package/dist/src/a2a/codecs.js +9 -0
  6. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  7. package/dist/src/artifacts/browser-export.js +6 -0
  8. package/dist/src/artifacts/checksum-manifest.js +1 -0
  9. package/dist/src/artifacts/citation-parser.js +173 -92
  10. package/dist/src/artifacts/citation-table-schema.js +59 -0
  11. package/dist/src/artifacts/cli.js +57 -18
  12. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  13. package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
  14. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  15. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  16. package/dist/src/artifacts/discovery-eval.js +6 -4
  17. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  18. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  19. package/dist/src/artifacts/framework-capabilities.js +171 -0
  20. package/dist/src/artifacts/framework-index-paths.js +73 -0
  21. package/dist/src/artifacts/framework-source-digest.js +75 -0
  22. package/dist/src/artifacts/index-builder.js +285 -131
  23. package/dist/src/artifacts/index-files.js +132 -18
  24. package/dist/src/artifacts/index-preparation.js +65 -0
  25. package/dist/src/artifacts/index-refresh.js +576 -0
  26. package/dist/src/artifacts/index-worker.mjs +9 -0
  27. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  28. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  29. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  30. package/dist/src/artifacts/query-engine.js +410 -88
  31. package/dist/src/artifacts/relations-builder.js +168 -0
  32. package/dist/src/artifacts/relations.js +148 -0
  33. package/dist/src/artifacts/repair.js +9 -4
  34. package/dist/src/artifacts/stats.js +5 -2
  35. package/dist/src/artifacts/types.js +30 -10
  36. package/dist/src/artifacts/watcher.js +1 -1
  37. package/dist/src/auth/credential-store.js +2 -1
  38. package/dist/src/catalog/cli.d.mts +5 -0
  39. package/dist/src/channel/manager.d.mts +20 -0
  40. package/dist/src/channel/manager.mjs +78 -12
  41. package/dist/src/cli/child-process-result.js +40 -0
  42. package/dist/src/cli/command-log.js +2 -3
  43. package/dist/src/cli/env.js +38 -16
  44. package/dist/src/cli/flag-parsing.js +236 -0
  45. package/dist/src/cli/handlers/artifacts.js +3 -0
  46. package/dist/src/cli/handlers/auth.js +3 -0
  47. package/dist/src/cli/handlers/decision.js +218 -5
  48. package/dist/src/cli/handlers/diagnose.js +13 -5
  49. package/dist/src/cli/handlers/effect.js +4 -2
  50. package/dist/src/cli/handlers/evidence.js +3 -0
  51. package/dist/src/cli/handlers/feedback.js +14 -5
  52. package/dist/src/cli/handlers/help.js +1 -0
  53. package/dist/src/cli/handlers/index.js +3 -1
  54. package/dist/src/cli/handlers/init.js +248 -30
  55. package/dist/src/cli/handlers/lint.js +5 -0
  56. package/dist/src/cli/handlers/mc.js +23 -0
  57. package/dist/src/cli/handlers/models.js +169 -10
  58. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  59. package/dist/src/cli/handlers/ralph.js +3 -0
  60. package/dist/src/cli/handlers/refresh.js +28 -0
  61. package/dist/src/cli/handlers/regenerate.js +14 -0
  62. package/dist/src/cli/handlers/resource-versions.js +3 -0
  63. package/dist/src/cli/handlers/rules.js +195 -0
  64. package/dist/src/cli/handlers/run.js +4 -0
  65. package/dist/src/cli/handlers/runtime-info.js +25 -11
  66. package/dist/src/cli/handlers/script-runner.js +19 -8
  67. package/dist/src/cli/handlers/session.js +406 -62
  68. package/dist/src/cli/handlers/sessions.js +243 -76
  69. package/dist/src/cli/handlers/setup-manifest.js +474 -79
  70. package/dist/src/cli/handlers/setup.js +180 -39
  71. package/dist/src/cli/handlers/steward.js +11 -0
  72. package/dist/src/cli/handlers/subcommands.js +60 -3
  73. package/dist/src/cli/handlers/team.js +18 -8
  74. package/dist/src/cli/handlers/uhp.js +3 -0
  75. package/dist/src/cli/handlers/use.js +307 -55
  76. package/dist/src/cli/handlers/utilities.js +125 -26
  77. package/dist/src/cli/handlers/version.js +8 -0
  78. package/dist/src/cli/prompt-utils.js +72 -0
  79. package/dist/src/cli/provider-resolution.js +11 -0
  80. package/dist/src/cli/router.js +15 -1
  81. package/dist/src/cli/services/deployment-verification.js +19 -9
  82. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  83. package/dist/src/cli/skill-usage.js +2 -3
  84. package/dist/src/config/aiwg-config.js +349 -35
  85. package/dist/src/config/cli.js +256 -23
  86. package/dist/src/config/decision-config.js +106 -0
  87. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  88. package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
  89. package/dist/src/config/gitignore.js +50 -0
  90. package/dist/src/config/index-graph-overrides.js +36 -0
  91. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  92. package/dist/src/config/project-artifacts-health.mjs +14 -3
  93. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  94. package/dist/src/config/user-config-dir.d.mts +9 -0
  95. package/dist/src/config/user-config.js +38 -11
  96. package/dist/src/config/user-registry.js +23 -15
  97. package/dist/src/config/user-state.js +7 -0
  98. package/dist/src/decision/adapters/jev.js +75 -27
  99. package/dist/src/decision/ask.js +203 -43
  100. package/dist/src/decision/context-live-qualification.js +2 -2
  101. package/dist/src/decision/driver.js +14 -7
  102. package/dist/src/decision/ensemble/aggregate.js +23 -10
  103. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  104. package/dist/src/decision/entry.js +25 -6
  105. package/dist/src/decision/graph-live-qualification.js +1 -1
  106. package/dist/src/decision/graph-run.js +9 -0
  107. package/dist/src/decision/heldout/collector.js +15 -14
  108. package/dist/src/decision/heldout/contract.js +30 -7
  109. package/dist/src/decision/index.js +1 -0
  110. package/dist/src/decision/interop.js +60 -8
  111. package/dist/src/decision/jev-credentials.js +15 -1
  112. package/dist/src/decision/ledger.js +942 -0
  113. package/dist/src/decision/offload-activation.js +137 -0
  114. package/dist/src/decision/offload.js +550 -0
  115. package/dist/src/decision/qualification/load.js +4 -6
  116. package/dist/src/decision/savings.js +28 -0
  117. package/dist/src/decision/validate.js +6 -3
  118. package/dist/src/effects/dispatch-verifier.js +252 -0
  119. package/dist/src/effects/index.js +1 -0
  120. package/dist/src/effects/types.js +5 -1
  121. package/dist/src/effects/verifiers/git.js +2 -1
  122. package/dist/src/effects/verifiers/tracker.js +26 -14
  123. package/dist/src/extensions/commands/definitions.js +19 -0
  124. package/dist/src/extensions/project-local-remove.js +36 -1
  125. package/dist/src/features/installer.js +2 -2
  126. package/dist/src/flow/graph-metadata.js +5 -0
  127. package/dist/src/gates/providers/loader.js +64 -18
  128. package/dist/src/installation/manager-command.d.mts +18 -0
  129. package/dist/src/installation/manager-command.mjs +15 -3
  130. package/dist/src/installation/manager.d.mts +49 -0
  131. package/dist/src/installation/manager.mjs +95 -5
  132. package/dist/src/issues/cli.js +4 -4
  133. package/dist/src/issues/local.js +24 -5
  134. package/dist/src/jobs/runner.js +1 -1
  135. package/dist/src/lint/cli.js +27 -1
  136. package/dist/src/lint/loader.js +2 -1
  137. package/dist/src/lint/reporters.js +25 -1
  138. package/dist/src/lint/rule-activation.js +43 -0
  139. package/dist/src/lint/runner.js +137 -62
  140. package/dist/src/mcp/adapters/codex-runtime.js +366 -56
  141. package/dist/src/mcp/claude-install.d.mts +4 -0
  142. package/dist/src/mcp/claude-install.mjs +41 -0
  143. package/dist/src/mcp/cli.d.mts +1 -0
  144. package/dist/src/mcp/cli.mjs +620 -85
  145. package/dist/src/mcp/config-file.d.mts +28 -0
  146. package/dist/src/mcp/config-file.mjs +279 -0
  147. package/dist/src/mcp/config-layers.d.mts +36 -0
  148. package/dist/src/mcp/config-layers.mjs +348 -0
  149. package/dist/src/mcp/credentials.d.mts +51 -0
  150. package/dist/src/mcp/credentials.mjs +484 -0
  151. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  152. package/dist/src/mcp/grok-build-config.mjs +17 -27
  153. package/dist/src/mcp/helpers.mjs +109 -4
  154. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  155. package/dist/src/mcp/muse-native-config.mjs +1 -0
  156. package/dist/src/mcp/omp-config.d.mts +4 -0
  157. package/dist/src/mcp/omp-config.mjs +50 -29
  158. package/dist/src/mcp/profiles.js +97 -23
  159. package/dist/src/mcp/profiles.mjs +99 -27
  160. package/dist/src/mcp/registry.js +248 -131
  161. package/dist/src/mcp/registry.mjs +169 -100
  162. package/dist/src/mcp/server-config.d.mts +3 -0
  163. package/dist/src/mcp/server-config.mjs +89 -0
  164. package/dist/src/mcp/server.mjs +127 -82
  165. package/dist/src/mcp/test-simple.mjs +2 -1
  166. package/dist/src/mcp/toml-editor.d.mts +4 -0
  167. package/dist/src/mcp/toml-string.d.mts +1 -0
  168. package/dist/src/mcp/toml-string.mjs +9 -0
  169. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  170. package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
  171. package/dist/src/mcp/tool-filters.d.mts +46 -0
  172. package/dist/src/mcp/tool-filters.mjs +357 -0
  173. package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
  174. package/dist/src/mcp/tools/decision.mjs +22 -3
  175. package/dist/src/mcp/tools/discovery.mjs +62 -55
  176. package/dist/src/mcp/tools/orchestration.mjs +50 -2
  177. package/dist/src/mcp/tools/subsystems.mjs +39 -8
  178. package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
  179. package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
  180. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
  181. package/dist/src/memory/project-registry.js +2 -2
  182. package/dist/src/mission-protocol/codecs.js +647 -1
  183. package/dist/src/mission-protocol/types.js +110 -0
  184. package/dist/src/mission-protocol/worker-status.js +2 -0
  185. package/dist/src/models/config-loader.js +76 -14
  186. package/dist/src/models/grok-build-models.js +93 -41
  187. package/dist/src/models/model-capabilities.v1.json +3183 -24
  188. package/dist/src/models/model-discovery.js +931 -67
  189. package/dist/src/models/provider-policy.js +719 -11
  190. package/dist/src/models/qualification-digest.d.mts +2 -0
  191. package/dist/src/models/qualification-digest.mjs +17 -0
  192. package/dist/src/models/resolver.js +261 -0
  193. package/dist/src/models/worker-direct-readiness.js +550 -0
  194. package/dist/src/models/worker-dispatch-offer.js +169 -0
  195. package/dist/src/models/worker-health-readiness.js +144 -0
  196. package/dist/src/models/worker-installation.d.mts +39 -0
  197. package/dist/src/models/worker-installation.mjs +986 -0
  198. package/dist/src/models/wrapper-route.js +18 -0
  199. package/dist/src/ops/registry.js +9 -14
  200. package/dist/src/plugins/standalone-packager.js +4 -3
  201. package/dist/src/process/bounded-child-process.d.mts +84 -0
  202. package/dist/src/process/bounded-child-process.mjs +430 -0
  203. package/dist/src/process/cli-command.d.mts +16 -0
  204. package/dist/src/process/cli-command.mjs +75 -0
  205. package/dist/src/process/signal-child.d.mts +6 -0
  206. package/dist/src/process/signal-child.mjs +7 -0
  207. package/dist/src/providers/capability-matrix.js +8 -0
  208. package/dist/src/providers/capability-matrix.yaml +270 -0
  209. package/dist/src/providers/deployed-skill-roots.js +20 -0
  210. package/dist/src/providers/grok-build-acp.js +3 -2
  211. package/dist/src/providers/grok-build-headless.js +53 -23
  212. package/dist/src/providers/grok-build-inspect.js +1 -0
  213. package/dist/src/providers/omp-agent.d.mts +8 -0
  214. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  215. package/dist/src/providers/omp-paths.d.mts +13 -0
  216. package/dist/src/providers/provider-definitions.js +9 -1
  217. package/dist/src/providers/provider-definitions.mjs +9 -2
  218. package/dist/src/providers/skill-ownership.d.mts +9 -0
  219. package/dist/src/providers/skill-ownership.mjs +88 -0
  220. package/dist/src/rules/activation.d.mts +21 -0
  221. package/dist/src/rules/activation.mjs +62 -0
  222. package/dist/src/rules/inline-budget.d.mts +26 -0
  223. package/dist/src/rules/inline-budget.mjs +66 -0
  224. package/dist/src/rules/inventory.js +129 -0
  225. package/dist/src/rules/pin-state.js +73 -0
  226. package/dist/src/rules/pins.d.mts +14 -0
  227. package/dist/src/rules/pins.mjs +112 -0
  228. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  229. package/dist/src/serve/executor-registry.js +16 -24
  230. package/dist/src/serve/fleet-mission-conductor.js +9 -0
  231. package/dist/src/serve/mission-conductor.js +47 -12
  232. package/dist/src/serve/shared-host-scheduler.js +2 -0
  233. package/dist/src/serve/worker-invocation.js +558 -0
  234. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  235. package/dist/src/serve/worker-stdin-frame.mjs +107 -0
  236. package/dist/src/sessions/adapter-registry.js +49 -0
  237. package/dist/src/sessions/adapters/claude.js +39 -54
  238. package/dist/src/sessions/adapters/codex.js +82 -67
  239. package/dist/src/sessions/adapters/copilot.js +4 -4
  240. package/dist/src/sessions/adapters/cursor.js +40 -57
  241. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  242. package/dist/src/sessions/adapters/factory.js +31 -27
  243. package/dist/src/sessions/adapters/generic.js +43 -9
  244. package/dist/src/sessions/adapters/grok-build.js +11 -11
  245. package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
  246. package/dist/src/sessions/adapters/grokbot.js +434 -24
  247. package/dist/src/sessions/adapters/hermes.js +27 -29
  248. package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
  249. package/dist/src/sessions/adapters/muse.js +200 -104
  250. package/dist/src/sessions/adapters/omp.js +28 -14
  251. package/dist/src/sessions/adapters/openclaw.js +89 -79
  252. package/dist/src/sessions/adapters/opencode.js +27 -24
  253. package/dist/src/sessions/adapters/openhuman.js +18 -60
  254. package/dist/src/sessions/adapters/pi.js +30 -14
  255. package/dist/src/sessions/adapters/warp.js +3 -3
  256. package/dist/src/sessions/adapters/windsurf.js +19 -48
  257. package/dist/src/sessions/batch-contracts.js +25 -5
  258. package/dist/src/sessions/batch-import.js +72 -51
  259. package/dist/src/sessions/candidates.js +47 -11
  260. package/dist/src/sessions/contracts.js +75 -2
  261. package/dist/src/sessions/coverage-preflight.js +134 -0
  262. package/dist/src/sessions/discovery.js +3 -0
  263. package/dist/src/sessions/export-plan.js +4 -3
  264. package/dist/src/sessions/grok-build-cli.js +67 -5
  265. package/dist/src/sessions/import-exclusions.js +72 -0
  266. package/dist/src/sessions/import-lease.js +34 -18
  267. package/dist/src/sessions/import-limits.js +37 -0
  268. package/dist/src/sessions/importer.js +84 -46
  269. package/dist/src/sessions/index.js +2 -0
  270. package/dist/src/sessions/lifecycle.js +45 -0
  271. package/dist/src/sessions/policy.js +133 -25
  272. package/dist/src/sessions/readers.js +106 -53
  273. package/dist/src/sessions/refresh.js +106 -0
  274. package/dist/src/sessions/repository.js +199 -63
  275. package/dist/src/sessions/workspace-discovery.js +315 -88
  276. package/dist/src/sessions/workspace-matching.js +107 -0
  277. package/dist/src/skills/adapters/clawhub.js +10 -8
  278. package/dist/src/skills/adapters/openclaw.js +10 -7
  279. package/dist/src/skills/importer.js +1 -0
  280. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  281. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  282. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  283. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  284. package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
  285. package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
  286. package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
  287. package/dist/src/smiths/mcpsmith/example.js +1 -1
  288. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  289. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  290. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
  291. package/dist/src/storage/backends/fs.js +18 -76
  292. package/dist/src/storage/backends/logseq.js +68 -7
  293. package/dist/src/storage/backends/obsidian.js +1 -0
  294. package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
  295. package/dist/src/testing/generators/test-code-generator.js +57 -30
  296. package/dist/src/tracker/forge-http.js +2 -1
  297. package/dist/src/uhp/client.js +11 -1
  298. package/dist/src/uhp/mission.js +5 -0
  299. package/dist/src/update/checker.d.mts +2 -0
  300. package/dist/src/update/checker.mjs +5 -5
  301. package/dist/src/update/notifier.mjs +54 -2
  302. package/dist/src/update/service.d.mts +22 -0
  303. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  304. package/dist/src/utils/contained-filesystem.mjs +683 -0
  305. package/dist/src/utils/temporary-directory.js +36 -0
  306. package/dist/src/writing/example-generator.js +1 -1
  307. package/dist/src/writing/fidelity.js +18 -1
  308. package/package.json +32 -2
  309. package/schemas/mission-v1.schema.json +2429 -0
  310. package/schemas/models/model-catalog.v1.schema.json +301 -0
  311. package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
  312. package/schemas/models/model-policy.v1.schema.json +14 -0
  313. package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
  314. package/tools/_resolve-impl.mjs +39 -2
  315. package/tools/agents/deploy-agents.mjs +64 -23
  316. package/tools/agents/providers/base.mjs +153 -166
  317. package/tools/agents/providers/claude.mjs +8 -24
  318. package/tools/agents/providers/codex.mjs +18 -11
  319. package/tools/agents/providers/cursor.mjs +19 -18
  320. package/tools/agents/providers/grok-build.mjs +3 -1
  321. package/tools/agents/providers/grokbot.mjs +11 -12
  322. package/tools/agents/providers/hermes.mjs +62 -49
  323. package/tools/agents/providers/omp.mjs +5 -2
  324. package/tools/agents/providers/openclaw-translator.mjs +19 -5
  325. package/tools/agents/providers/openclaw.mjs +9 -4
  326. package/tools/agents/providers/pi.mjs +5 -0
  327. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  328. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  329. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  330. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  331. package/tools/agents/providers/warp.mjs +20 -26
  332. package/tools/cli/decision-offload-report.mjs +40 -0
  333. package/tools/cli/workspace-status.mjs +862 -0
  334. package/tools/plugin/package-plugins.mjs +186 -8
  335. package/tools/plugin/plugin-links.mjs +114 -0
  336. package/tools/providers/antigravity-transport.mjs +3 -1
  337. package/tools/providers/deepseek-harness-transport.mjs +360 -0
  338. package/tools/providers/omp-transport.mjs +194 -0
  339. package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
  340. package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
  341. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  342. package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
  343. package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
  344. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  345. package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
  346. package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
  347. package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
  348. package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
  349. package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
  350. package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
  351. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  352. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  353. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  354. package/tools/ralph-external/lib/worker-health.mjs +439 -0
  355. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  356. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  357. package/tools/ralph-external/process-monitor.mjs +1017 -0
  358. package/tools/ralph-external/session-launcher.mjs +5057 -0
  359. package/tools/scripts/resource-preflight.mjs +541 -0
  360. package/tools/skills/deploy-skills-codex.mjs +2 -1
  361. package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
@@ -1,10 +1,16 @@
1
1
  import { requireFeaturePackage } from '../features/runtime.js';
2
2
  import { CandidateReviewReceiptSchema, DeletionReceiptSchema, IntelligenceCandidateSchema, PromotionDependencyDecisionSchema, PromotionReceiptSchema, SessionContractError, sha256, } from './contracts.js';
3
3
  import { coverageFromBatchRun, } from './batch-contracts.js';
4
- import { redactSessionText, sanitizeNativeExtensions } from './policy.js';
4
+ import { redactSessionText, redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
5
+ import { effectiveSessionLifecycle } from './lifecycle.js';
5
6
  import { deriveSessionAnalytics, } from './analytics.js';
6
7
  const POLICY_PROVIDER_MIGRATION = 'policy-provider-identity:v2';
7
8
  const EVENT_ORIGIN_INTENT_MIGRATION = 'event-origin-intent:v1';
9
+ const VISIBLE_SESSION_PREDICATE = `s.lifecycle != 'tombstoned' AND EXISTS (
10
+ SELECT 1 FROM session_events e
11
+ JOIN import_runs r ON r.import_run_id=e.import_run_id
12
+ WHERE e.session_id=s.session_id AND r.status='committed'
13
+ )`;
8
14
  export class SessionRepository {
9
15
  db;
10
16
  constructor(path = ':memory:') {
@@ -119,6 +125,12 @@ export class SessionRepository {
119
125
  ON sessions(workspace_id, source_id, lifecycle);
120
126
  CREATE INDEX IF NOT EXISTS idx_event_session_sequence
121
127
  ON session_events(session_id, sequence_no);
128
+ CREATE INDEX IF NOT EXISTS idx_event_source_run
129
+ ON session_events(source_id, import_run_id);
130
+ CREATE INDEX IF NOT EXISTS idx_event_import_run_session
131
+ ON session_events(import_run_id, session_id);
132
+ CREATE INDEX IF NOT EXISTS idx_session_analytics_session
133
+ ON session_analytics_facts(session_id);
122
134
  CREATE INDEX IF NOT EXISTS idx_session_analytics_scope
123
135
  ON session_analytics_facts(
124
136
  workspace_id, category, provider, status, occurred_at, fact_id
@@ -126,6 +138,9 @@ export class SessionRepository {
126
138
  CREATE VIRTUAL TABLE IF NOT EXISTS session_event_fts USING fts5(
127
139
  event_id UNINDEXED, searchable_text, tokenize='unicode61'
128
140
  );
141
+ -- FTS5 stores event_id in c0. A covering index checks identity/rowid
142
+ -- alignment without reading searchable text or event JSON.
143
+ CREATE INDEX IF NOT EXISTS idx_fts_event_id ON session_event_fts_content(c0);
129
144
  `);
130
145
  const deletionReceiptColumns = this.db.prepare('PRAGMA table_info(deletion_receipts)').all().map((row) => String(row.name));
131
146
  if (!deletionReceiptColumns.includes('workspace_id')) {
@@ -149,48 +164,79 @@ export class SessionRepository {
149
164
  CREATE INDEX IF NOT EXISTS idx_mutation_audit_workspace
150
165
  ON mutation_audit(workspace_id, occurred_at, operation_id)
151
166
  ;
167
+ CREATE INDEX IF NOT EXISTS idx_import_runs_batch
168
+ ON import_runs(batch_run_id);
152
169
  CREATE INDEX IF NOT EXISTS idx_batch_import_workspace
153
170
  ON batch_import_runs(workspace_id, updated_at, batch_run_id)
154
171
  `);
172
+ this.initializeAnalyticsVerification();
155
173
  this.alignSessionFtsRowids();
156
174
  this.migrateSessionPolicyAndProviderIdentity();
157
175
  this.migrateEventOriginAndIntent();
158
176
  this.alignSessionAnalytics();
159
177
  }
178
+ initializeAnalyticsVerification() {
179
+ // Invalidate verification even for writes from another connection. Ordinary
180
+ // repository mutations maintain analytics in the same transaction below.
181
+ this.db.transaction(() => {
182
+ this.db.prepare('INSERT OR IGNORE INTO session_catalog_meta(key, value) VALUES (?, ?)').run('consistency:analytics:v1', 'dirty');
183
+ for (const table of [
184
+ 'session_events', 'session_analytics_facts', 'sessions', 'session_sources', 'import_runs',
185
+ ]) {
186
+ for (const operation of ['INSERT', 'UPDATE', 'DELETE']) {
187
+ this.db.exec(`
188
+ CREATE TRIGGER IF NOT EXISTS consistency_${table}_${operation.toLowerCase()}
189
+ AFTER ${operation} ON ${table}
190
+ BEGIN
191
+ UPDATE session_catalog_meta SET value='dirty'
192
+ WHERE key='consistency:analytics:v1' AND value!='dirty';
193
+ END;
194
+ `);
195
+ }
196
+ }
197
+ })();
198
+ }
199
+ analyticsVerified() {
200
+ return this.db.prepare('SELECT value FROM session_catalog_meta WHERE key=?').get('consistency:analytics:v1')?.value === 'verified';
201
+ }
202
+ markAnalyticsVerified() {
203
+ this.db.prepare('UPDATE session_catalog_meta SET value=? WHERE key=?').run('verified', 'consistency:analytics:v1');
204
+ }
205
+ maintainedAnalyticsTransaction(mutate) {
206
+ return this.db.transaction(() => {
207
+ const verified = this.analyticsVerified();
208
+ const result = mutate();
209
+ // A scoped mutation must not hide pre-existing damage elsewhere.
210
+ if (verified)
211
+ this.markAnalyticsVerified();
212
+ return result;
213
+ });
214
+ }
160
215
  alignSessionAnalytics() {
161
- const eventCount = Number(this.db.prepare(`SELECT COUNT(*) AS count
162
- FROM session_events e
163
- JOIN import_runs r ON r.import_run_id=e.import_run_id
164
- JOIN sessions s ON s.session_id=e.session_id
165
- WHERE r.status='committed' AND s.lifecycle!='tombstoned'`).get()?.count ?? 0);
166
- const factSessions = Number(this.db.prepare('SELECT COUNT(DISTINCT session_id) AS count FROM session_analytics_facts').get()?.count ?? 0);
167
- const sourceSessions = Number(this.db.prepare(`SELECT COUNT(DISTINCT e.session_id) AS count
168
- FROM session_events e
169
- JOIN import_runs r ON r.import_run_id=e.import_run_id
170
- JOIN sessions s ON s.session_id=e.session_id
171
- WHERE r.status='committed' AND s.lifecycle!='tombstoned'`).get()?.count ?? 0);
172
- if (eventCount === 0 || factSessions === sourceSessions)
173
- return;
174
- this.rebuildAnalytics();
216
+ this.db.transaction(() => {
217
+ if (this.analyticsVerified())
218
+ return;
219
+ this.rebuildAnalytics();
220
+ })();
175
221
  }
176
222
  alignSessionFtsRowids() {
177
- const eventCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_events').get()?.count ?? 0);
178
- const ftsCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_event_fts').get()?.count ?? 0);
179
- const mismatches = Number(this.db.prepare(`SELECT COUNT(*) AS count
180
- FROM session_event_fts f
181
- LEFT JOIN session_events e ON e.rowid=f.rowid
182
- WHERE e.rowid IS NULL OR e.event_id!=f.event_id`).get()?.count ?? 0);
183
- if (eventCount === ftsCount && mismatches === 0)
184
- return;
185
- const rebuild = this.db.transaction(() => {
223
+ this.db.transaction(() => {
224
+ const eventCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_events').get()?.count ?? 0);
225
+ const ftsCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_event_fts_content').get()?.count ?? 0);
226
+ const mismatch = this.db.prepare(`SELECT 1 AS mismatch
227
+ FROM session_event_fts_content f
228
+ LEFT JOIN session_events e ON e.event_id=f.c0
229
+ WHERE e.rowid IS NULL OR e.rowid!=f.id
230
+ LIMIT 1`).get();
231
+ if (eventCount === ftsCount && !mismatch)
232
+ return;
186
233
  this.db.exec('DELETE FROM session_event_fts');
187
234
  this.db.exec(`
188
235
  INSERT INTO session_event_fts(rowid, event_id, searchable_text)
189
236
  SELECT rowid, event_id, json_extract(data, '$.searchableText')
190
237
  FROM session_events
191
238
  `);
192
- });
193
- rebuild();
239
+ })();
194
240
  }
195
241
  migrateSessionPolicyAndProviderIdentity() {
196
242
  this.runCatalogMigration(POLICY_PROVIDER_MIGRATION, () => {
@@ -326,6 +372,7 @@ export class SessionRepository {
326
372
  transaction();
327
373
  }
328
374
  emitMutation(input) {
375
+ input = redactSessionValue(input).value;
329
376
  const unsigned = {
330
377
  contractVersion: '1.0.0',
331
378
  ...input,
@@ -430,7 +477,17 @@ export class SessionRepository {
430
477
  };
431
478
  }
432
479
  applyImport(batch, checkpoint, publish = true) {
433
- const apply = this.db.transaction(() => {
480
+ // Guard callers that submit normalized batches directly as well as adapters.
481
+ batch = redactSessionValue({
482
+ ...batch,
483
+ source: { ...batch.source, extensions: sanitizeNativeExtensions(batch.source.extensions).value },
484
+ sessions: batch.sessions.map((session) => ({
485
+ ...session, extensions: sanitizeSessionExtensions(session.extensions, session.provider),
486
+ })),
487
+ events: batch.events.map(sanitizeSessionEvent),
488
+ }).value;
489
+ checkpoint = redactSessionValue(checkpoint).value;
490
+ const apply = this.maintainedAnalyticsTransaction(() => {
434
491
  const existing = this.db.prepare('SELECT outcome, counts, checkpoint FROM import_receipts WHERE import_run_id = ?').get(batch.run.importRunId);
435
492
  if (existing) {
436
493
  const counts = JSON.parse(String(existing.counts));
@@ -536,7 +593,7 @@ export class SessionRepository {
536
593
  return apply();
537
594
  }
538
595
  commitStagedImports(sourceId, parserVersion) {
539
- const commit = this.db.transaction(() => {
596
+ const commit = this.maintainedAnalyticsTransaction(() => {
540
597
  const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
541
598
  WHERE source_id=? AND parser_version=? AND status='staged'`).all(sourceId, parserVersion).map((row) => String(row.import_run_id));
542
599
  const result = this.db.prepare(`UPDATE import_runs SET status='committed'
@@ -564,7 +621,7 @@ export class SessionRepository {
564
621
  WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
565
622
  }
566
623
  if (result.changes > 0)
567
- this.rebuildAnalytics();
624
+ this.rebuildImportAnalytics(staged);
568
625
  return result.changes;
569
626
  });
570
627
  return commit();
@@ -573,7 +630,7 @@ export class SessionRepository {
573
630
  if (sourceIds.length === 0)
574
631
  return 0;
575
632
  const placeholders = sourceIds.map(() => '?').join(', ');
576
- const commit = this.db.transaction(() => {
633
+ const commit = this.maintainedAnalyticsTransaction(() => {
577
634
  const params = [batchRunId, ...sourceIds];
578
635
  const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
579
636
  WHERE batch_run_id=? AND source_id IN (${placeholders}) AND status='staged'`).all(...params).map((row) => String(row.import_run_id));
@@ -602,33 +659,84 @@ export class SessionRepository {
602
659
  WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
603
660
  }
604
661
  if (result.changes > 0)
605
- this.rebuildAnalytics();
662
+ this.rebuildImportAnalytics(staged);
606
663
  return result.changes;
607
664
  });
608
665
  return commit();
609
666
  }
610
- sourceImportTotals(sourceId, batchRunId) {
611
- const events = Number(this.db.prepare(`SELECT COUNT(*) AS count
667
+ rebuildImportAnalytics(importRunIds) {
668
+ const affected = this.db.prepare(`SELECT DISTINCT s.workspace_id, s.session_id
612
669
  FROM session_events e
613
- JOIN import_runs r ON r.import_run_id=e.import_run_id
614
- WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId)?.count ?? 0);
615
- const sessions = Number(this.db.prepare(`SELECT COUNT(DISTINCT e.session_id) AS count
670
+ JOIN sessions s ON s.session_id=e.session_id
671
+ WHERE e.import_run_id=?`);
672
+ const sessions = new Map();
673
+ for (const importRunId of importRunIds) {
674
+ for (const row of affected.all(importRunId)) {
675
+ sessions.set(String(row.session_id), String(row.workspace_id));
676
+ }
677
+ }
678
+ for (const [sessionId, workspaceId] of sessions) {
679
+ this.rebuildAnalytics(workspaceId, sessionId);
680
+ }
681
+ }
682
+ sourceImportTotals(sourceId, batchRunId) {
683
+ const totals = this.db.prepare(`SELECT COUNT(*) AS events, COUNT(DISTINCT e.session_id) AS sessions
616
684
  FROM session_events e
617
685
  JOIN import_runs r ON r.import_run_id=e.import_run_id
618
- WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId)?.count ?? 0);
619
- return { sessions, events };
686
+ WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId);
687
+ return { sessions: Number(totals?.sessions ?? 0), events: Number(totals?.events ?? 0) };
620
688
  }
621
689
  getSession(id, workspaceId) {
622
690
  const row = this.db.prepare(`SELECT s.data FROM sessions s
623
- WHERE s.session_id=? AND s.lifecycle != ?
624
- ${workspaceId ? 'AND s.workspace_id=?' : ''}
625
- AND EXISTS (
626
- SELECT 1 FROM session_events e
627
- JOIN import_runs r ON r.import_run_id=e.import_run_id
628
- WHERE e.session_id=s.session_id AND r.status='committed'
629
- )`)
630
- .get(...(workspaceId ? [id, 'tombstoned', workspaceId] : [id, 'tombstoned']));
631
- return row ? JSON.parse(String(row.data)) : null;
691
+ WHERE s.session_id=? AND ${VISIBLE_SESSION_PREDICATE}
692
+ ${workspaceId ? 'AND s.workspace_id=?' : ''}`)
693
+ .get(...(workspaceId ? [id, workspaceId] : [id]));
694
+ return row ? effectiveSessionLifecycle(JSON.parse(String(row.data))) : null;
695
+ }
696
+ findSessionsByReference(reference, workspaceId) {
697
+ const internal = this.getSession(reference, workspaceId);
698
+ if (internal)
699
+ return [internal];
700
+ const query = (predicate) => this.db.prepare(`SELECT s.data FROM sessions s
701
+ WHERE ${workspaceId ? 's.workspace_id=? AND' : ''} ${VISIBLE_SESSION_PREDICATE} AND (${predicate})
702
+ ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference] : [reference]))
703
+ .map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
704
+ const exact = query('s.native_session_id=?');
705
+ if (exact.length === 1)
706
+ return exact;
707
+ if (exact.length > 1) {
708
+ // Artifact IDs are redacted by native-extension sanitization. The
709
+ // adapter's boolean subagent flag survives. Only prefer a parent when
710
+ // every other match is a proven Claude subagent in the same workspace.
711
+ if (exact.every((session) => session.provider === 'claude'
712
+ && session.workspaceId === exact[0].workspaceId)) {
713
+ const classified = exact.map((session) => {
714
+ const flags = this.db.prepare(`SELECT
715
+ MAX(json_extract(e.data, '$.extensions."native.claude".transcriptFamily.subagent')=0) AS parent,
716
+ MAX(json_extract(e.data, '$.extensions."native.claude".transcriptFamily.subagent')=1) AS subagent
717
+ FROM session_events e JOIN import_runs r ON r.import_run_id=e.import_run_id
718
+ WHERE e.session_id=? AND r.status='committed'`).get(session.sessionId);
719
+ return { session, parent: flags.parent === 1, subagent: flags.subagent === 1 };
720
+ });
721
+ const parents = classified.filter((item) => item.parent && !item.subagent);
722
+ if (parents.length === 1 && classified.every((item) => item === parents[0]
723
+ || (item.subagent && !item.parent)))
724
+ return [parents[0].session];
725
+ }
726
+ return exact;
727
+ }
728
+ // substr treats %, _ and other characters literally rather than as LIKE patterns.
729
+ return this.db.prepare(`SELECT s.data FROM sessions s
730
+ WHERE ${workspaceId ? 's.workspace_id=? AND' : ''} ${VISIBLE_SESSION_PREDICATE}
731
+ AND (substr(s.native_session_id, 1, length(?))=?
732
+ OR substr(s.session_id, 1, length(?))=?)
733
+ ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference, reference, reference, reference]
734
+ : [reference, reference, reference, reference]))
735
+ .map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
736
+ }
737
+ listWorkspaceSessionCounts() {
738
+ return this.db.prepare(`SELECT s.workspace_id, COUNT(*) AS count FROM sessions s
739
+ WHERE ${VISIBLE_SESSION_PREDICATE} GROUP BY s.workspace_id ORDER BY s.workspace_id`).all().map((row) => ({ workspaceId: String(row.workspace_id), count: Number(row.count) }));
632
740
  }
633
741
  listSources() {
634
742
  return this.db.prepare('SELECT data FROM session_sources ORDER BY provider, source_id').all().map((row) => JSON.parse(String(row.data)));
@@ -637,6 +745,7 @@ export class SessionRepository {
637
745
  return this.db.prepare('SELECT DISTINCT workspace_id FROM sessions ORDER BY workspace_id').all().map((row) => String(row.workspace_id));
638
746
  }
639
747
  saveBatchImportRun(run) {
748
+ run = redactSessionValue(run).value;
640
749
  const save = this.db.transaction(() => {
641
750
  const prior = this.db.prepare('SELECT manifest_id, workspace_id FROM batch_import_runs WHERE batch_run_id=?').get(run.runId);
642
751
  if (prior && (String(prior.manifest_id) !== run.manifestId
@@ -655,6 +764,22 @@ export class SessionRepository {
655
764
  const row = this.db.prepare('SELECT data FROM batch_import_runs WHERE batch_run_id=?').get(runId);
656
765
  return row ? JSON.parse(String(row.data)) : null;
657
766
  }
767
+ /** Call only while holding the catalog import lease, before starting a new import. */
768
+ interruptRunningBatchImports(now = new Date()) {
769
+ const interruptedAt = now.toISOString();
770
+ return this.db.transaction(() => {
771
+ const rows = this.db.prepare("SELECT data FROM batch_import_runs WHERE status='running'").all();
772
+ return rows.map((row) => {
773
+ const run = JSON.parse(String(row.data));
774
+ run.status = 'interrupted';
775
+ run.interruptedAt = interruptedAt;
776
+ run.updatedAt = interruptedAt;
777
+ run.completedAt = null;
778
+ this.saveBatchImportRun(run);
779
+ return { runId: run.runId, interruptedAt };
780
+ });
781
+ })();
782
+ }
658
783
  getBatchImportRunForManifest(manifestId, workspaceId) {
659
784
  const row = this.db.prepare(`SELECT data FROM batch_import_runs
660
785
  WHERE manifest_id=? AND workspace_id=?`).get(manifestId, workspaceId);
@@ -670,11 +795,7 @@ export class SessionRepository {
670
795
  : coverage;
671
796
  }
672
797
  listSessions(options) {
673
- const where = [`s.lifecycle != 'tombstoned'`, `EXISTS (
674
- SELECT 1 FROM session_events e
675
- JOIN import_runs r ON r.import_run_id=e.import_run_id
676
- WHERE e.session_id=s.session_id AND r.status='committed'
677
- )`];
798
+ const where = [VISIBLE_SESSION_PREDICATE];
678
799
  const scopeDigest = sessionListScopeDigest(options);
679
800
  const cursor = decodeSessionListCursor(options.cursor);
680
801
  if (cursor && cursor.scopeDigest !== scopeDigest) {
@@ -702,18 +823,18 @@ export class SessionRepository {
702
823
  const pageParams = [...params];
703
824
  if (cursor) {
704
825
  pageWhere.push(`(
705
- COALESCE(json_extract(s.data, '$.updatedAt'), '') > ?
826
+ COALESCE(json_extract(s.data, '$.updatedAt'), '') < ?
706
827
  OR (
707
828
  COALESCE(json_extract(s.data, '$.updatedAt'), '') = ?
708
- AND s.session_id > ?
829
+ AND s.session_id < ?
709
830
  )
710
831
  )`);
711
832
  pageParams.push(cursor.updatedAt, cursor.updatedAt, cursor.sessionId);
712
833
  }
713
834
  const items = this.db.prepare(`SELECT s.data FROM sessions s WHERE ${pageWhere.join(' AND ')}
714
- ORDER BY COALESCE(json_extract(s.data, '$.updatedAt'), ''), s.session_id
835
+ ORDER BY COALESCE(json_extract(s.data, '$.updatedAt'), '') DESC, s.session_id DESC
715
836
  LIMIT ?${options.offset ? ' OFFSET ?' : ''}`).all(...pageParams, options.limit + 1, ...(options.offset ? [options.offset] : []))
716
- .map((row) => JSON.parse(String(row.data)));
837
+ .map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
717
838
  const page = items.slice(0, options.limit);
718
839
  const last = page.at(-1);
719
840
  return {
@@ -738,6 +859,7 @@ export class SessionRepository {
738
859
  .map((row) => String(row.tag));
739
860
  }
740
861
  tagSession(sessionId, tag, workspaceId) {
862
+ tag = redactSessionText(tag).text;
741
863
  const mutate = this.db.transaction(() => {
742
864
  if (!this.getSession(sessionId, workspaceId))
743
865
  return false;
@@ -778,7 +900,7 @@ export class SessionRepository {
778
900
  e.session_id,
779
901
  e.sequence_no,
780
902
  e.event_id`).all(workspaceId).map((row) => ({
781
- session: JSON.parse(String(row.session_data)),
903
+ session: effectiveSessionLifecycle(JSON.parse(String(row.session_data))),
782
904
  event: JSON.parse(String(row.event_data)),
783
905
  }));
784
906
  }
@@ -919,6 +1041,14 @@ export class SessionRepository {
919
1041
  };
920
1042
  }
921
1043
  rebuildAnalytics(workspaceId, sessionId) {
1044
+ return this.maintainedAnalyticsTransaction(() => {
1045
+ const inserted = this.rebuildAnalyticsFacts(workspaceId, sessionId);
1046
+ if (!workspaceId && !sessionId)
1047
+ this.markAnalyticsVerified();
1048
+ return inserted;
1049
+ })();
1050
+ }
1051
+ rebuildAnalyticsFacts(workspaceId, sessionId) {
922
1052
  const where = [
923
1053
  `r.status='committed'`,
924
1054
  `s.lifecycle!='tombstoned'`,
@@ -1087,7 +1217,10 @@ export class SessionRepository {
1087
1217
  }
1088
1218
  }
1089
1219
  const saved = candidates.map((input) => {
1090
- const parsed = IntelligenceCandidateSchema.parse(input);
1220
+ const redacted = redactSessionValue(input);
1221
+ const parsed = IntelligenceCandidateSchema.parse(redacted.value);
1222
+ if (redacted.classes.length)
1223
+ parsed.sensitivity = 'sensitive';
1091
1224
  this.assertCandidateEvidence(parsed);
1092
1225
  const priorRow = this.db.prepare(`SELECT data FROM intelligence_candidates
1093
1226
  WHERE candidate_id=? ORDER BY version DESC LIMIT 1`).get(parsed.candidateId);
@@ -1155,6 +1288,7 @@ export class SessionRepository {
1155
1288
  return rows.map((row) => IntelligenceCandidateSchema.parse(JSON.parse(String(row.data))));
1156
1289
  }
1157
1290
  reviewCandidate(input) {
1291
+ input = redactSessionValue(input).value;
1158
1292
  const review = this.db.transaction(() => {
1159
1293
  const candidate = this.getCandidate(input.candidateId, input.version, input.workspaceId);
1160
1294
  if (!candidate) {
@@ -1216,7 +1350,7 @@ export class SessionRepository {
1216
1350
  }
1217
1351
  recordPromotion(receiptInput) {
1218
1352
  const record = this.db.transaction(() => {
1219
- const receipt = PromotionReceiptSchema.parse(receiptInput);
1353
+ const receipt = PromotionReceiptSchema.parse(redactSessionValue(receiptInput).value);
1220
1354
  const existing = this.getPromotionReceipt(receipt.candidateId, receipt.candidateVersion, receipt.consumer);
1221
1355
  if (existing)
1222
1356
  return { ...existing, duplicate: true };
@@ -1283,6 +1417,7 @@ export class SessionRepository {
1283
1417
  return row ? JSON.parse(String(row.checkpoint)) : null;
1284
1418
  }
1285
1419
  relocateSource(sourceId, redactedLocator, workspaceId) {
1420
+ redactedLocator = redactSessionText(redactedLocator).text;
1286
1421
  const relocate = this.db.transaction(() => {
1287
1422
  const row = this.db.prepare(`SELECT src.data FROM session_sources src
1288
1423
  WHERE src.source_id=? ${workspaceId ? `AND EXISTS (
@@ -1340,7 +1475,7 @@ export class SessionRepository {
1340
1475
  };
1341
1476
  }
1342
1477
  tombstoneSession(sessionId, workspaceId) {
1343
- const tombstone = this.db.transaction(() => {
1478
+ const tombstone = this.maintainedAnalyticsTransaction(() => {
1344
1479
  const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
1345
1480
  WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
1346
1481
  if (!row)
@@ -1369,7 +1504,7 @@ export class SessionRepository {
1369
1504
  return tombstone();
1370
1505
  }
1371
1506
  restoreSession(sessionId, workspaceId) {
1372
- const restore = this.db.transaction(() => {
1507
+ const restore = this.maintainedAnalyticsTransaction(() => {
1373
1508
  const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
1374
1509
  WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
1375
1510
  if (!row)
@@ -1483,6 +1618,7 @@ export class SessionRepository {
1483
1618
  return rows.map((row) => JSON.parse(String(row.data)));
1484
1619
  }
1485
1620
  purgeSession(input) {
1621
+ input = redactSessionValue(input).value;
1486
1622
  const existing = this.db.prepare('SELECT data FROM deletion_receipts WHERE operation_id=?').get(input.preview.operationId);
1487
1623
  if (existing)
1488
1624
  return JSON.parse(String(existing.data));
@@ -1502,7 +1638,7 @@ export class SessionRepository {
1502
1638
  if (!mutationWorkspaceId) {
1503
1639
  throw new SessionContractError('OPERATION_NOT_AUTHORIZED', 'purge mutation lacks an authorized workspace');
1504
1640
  }
1505
- const apply = this.db.transaction(() => {
1641
+ const apply = this.maintainedAnalyticsTransaction(() => {
1506
1642
  for (const decision of validatedDecisions) {
1507
1643
  this.db.prepare(`INSERT INTO promotion_dependency_decisions
1508
1644
  (operation_id, dependent_id, action, basis) VALUES (?, ?, ?, ?)`).run(input.preview.operationId, decision.dependentId, decision.action, decision.basis);
@@ -1596,7 +1732,7 @@ export class SessionRepository {
1596
1732
  return apply();
1597
1733
  }
1598
1734
  reindex(workspaceId) {
1599
- const rebuild = this.db.transaction(() => {
1735
+ const rebuild = this.maintainedAnalyticsTransaction(() => {
1600
1736
  let indexed = 0;
1601
1737
  if (!workspaceId) {
1602
1738
  this.db.exec('REINDEX');