@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,143 +1,268 @@
1
- import { createReadStream } from 'node:fs';
2
- import { access, mkdir, readFile, realpath, rename, stat, writeFile, } from 'node:fs/promises';
1
+ import { access, mkdir, readFile, readdir, realpath, rename, stat, writeFile, } from 'node:fs/promises';
3
2
  import { homedir, userInfo } from 'node:os';
4
3
  import { basename, dirname, join, resolve } from 'node:path';
5
- import { createInterface } from 'node:readline';
6
- import { ClaudeSessionAdapter } from './adapters/claude.js';
7
- import { CodexSessionAdapter } from './adapters/codex.js';
8
- import { CursorSessionAdapter } from './adapters/cursor.js';
9
- import { FactorySessionAdapter } from './adapters/factory.js';
10
- import { MuseSessionAdapter, museNativeSourceMatchesWorkspace } from './adapters/muse.js';
11
- import { OmpSessionAdapter, readOmpSessionHeader } from './adapters/omp.js';
4
+ import { inspectMuseNativeWorkspace } from './adapters/muse.js';
5
+ import { readOmpSessionHeader } from './adapters/omp.js';
6
+ import { grokbotConversationIdFromLocator } from './adapters/grokbot-locator.js';
12
7
  import { resolveOmpPaths } from '../providers/omp-paths.mjs';
13
- import { PiSessionAdapter } from './adapters/pi.js';
14
- import { DeepSeekHarnessSessionAdapter } from './adapters/deepseek-harness.js';
15
- import { SESSION_PROVIDER_IDS, sha256, } from './contracts.js';
8
+ import { SESSION_PROVIDER_IDS, SessionCoveragePreflightSchema, SessionContractError, sha256, } from './contracts.js';
16
9
  import { redactSourceLocator } from './discovery.js';
17
- import { fingerprintSourceFile } from './readers.js';
10
+ import { createSessionAdapterRegistry } from './adapter-registry.js';
11
+ import { coveragePreflight, expectedSessionProviders } from './coverage-preflight.js';
12
+ import { fingerprintSourceFile, streamJsonLines } from './readers.js';
13
+ import { matchSessionWorkspace } from './workspace-matching.js';
14
+ import { matchImportExclusion, nativeSessionIdFromLocator, resolveImportExclusions } from './import-exclusions.js';
18
15
  export const DISCOVERY_MANIFEST_VERSION = '1.0.0';
19
16
  const MANUAL_EXPORT_PROVIDERS = new Set([
20
- 'copilot', 'hermes', 'opencode', 'openclaw', 'openhuman', 'grokbot', 'grok-build',
17
+ 'copilot', 'hermes', 'opencode', 'openclaw', 'openhuman', 'grok-build',
21
18
  'warp', 'devin-desktop', 'generic',
22
19
  ]);
23
20
  export async function discoverWorkspaceHistories(options) {
21
+ const registry = options.registry ?? createSessionAdapterRegistry();
22
+ const exclusions = resolveImportExclusions(undefined, options.exclude);
23
+ const expectedProviders = expectedSessionProviders(options.expectedProviders ?? SESSION_PROVIDER_IDS);
24
+ const supportedProviders = new Set(registry.list().map((adapter) => adapter.provider));
24
25
  const workspacePath = await canonicalPath(options.workspace);
25
26
  const workspaceId = workspacePath;
27
+ const workspacePaths = [...new Set([workspacePath, resolve(options.workspace),
28
+ ...(options.workspaceAliases ?? []).map((alias) => resolve(alias))])];
29
+ for (const alias of workspacePaths) {
30
+ if (await canonicalPath(alias) !== workspacePath) {
31
+ throw new SessionContractError('INVALID_ARGUMENT', 'workspace alias resolves to a different workspace');
32
+ }
33
+ }
26
34
  const providerHomes = providerHomeCandidates(options.providerHome, options.operatorHome);
27
- const keyWithLeadingDash = workspaceKey(workspacePath, true);
28
- const keyWithoutLeadingDash = workspaceKey(workspacePath, false);
29
35
  const discoverable = [
30
- { provider: 'deepseek-harness', adapter: new DeepSeekHarnessSessionAdapter(), roots: options.dshRoot
36
+ { provider: 'deepseek-harness', roots: options.dshRoot
31
37
  ? [resolve(options.dshRoot)] : options.providerHome
32
38
  ? [join(resolve(options.providerHome), '.dsh', 'sessions')] : [] },
33
- { provider: 'omp', adapter: new OmpSessionAdapter(), roots: options.ompRoot
39
+ { provider: 'omp', roots: options.ompRoot
34
40
  ? [resolve(options.ompRoot)] : options.providerHome
35
41
  ? [resolveOmpPaths({ home: resolve(options.providerHome), cwd: workspacePath }).sessionsDir] : [] },
36
- { provider: 'muse', adapter: new MuseSessionAdapter(), roots: options.museRoot
42
+ { provider: 'muse', roots: options.museRoot
37
43
  ? [resolve(options.museRoot)] : [] },
44
+ // Grok Bot conversations carry no workspace/cwd field, so unlike
45
+ // claude/cursor/factory there is no per-workspace default path to derive
46
+ // from providerHome. Native discovery requires an explicit
47
+ // --grokbot-root (same shared-root authorization model as
48
+ // codex/omp/deepseek-harness/muse below), and every authorized
49
+ // conversation surfaces to whichever workspace runs discovery (same
50
+ // no-filtering behavior already used for `pi`/`deepseek-harness`).
51
+ { provider: 'grokbot', roots: options.grokbotRoot
52
+ ? [resolve(options.grokbotRoot)] : [] },
38
53
  {
39
54
  provider: 'claude',
40
- adapter: new ClaudeSessionAdapter(),
41
- roots: providerHomes.map((providerHome) => join(providerHome, '.claude', 'projects', keyWithLeadingDash)),
55
+ roots: providerHomes.flatMap((providerHome) => workspacePaths.map((workspace) => join(providerHome, '.claude', 'projects', claudeProjectKey(workspace)))),
42
56
  },
43
57
  {
44
58
  provider: 'codex',
45
- adapter: new CodexSessionAdapter(),
46
- roots: options.codexRoot
47
- ? [resolve(options.codexRoot)]
48
- : options.providerHome
49
- ? [join(resolve(options.providerHome), '.codex', 'sessions')]
50
- : [],
59
+ roots: options.authorizedRoots || !expectedProviders.includes('codex')
60
+ ? [] : await codexDiscoveryRoots(options),
51
61
  },
52
62
  {
53
63
  provider: 'cursor',
54
- adapter: new CursorSessionAdapter(),
55
- roots: providerHomes.map((providerHome) => join(providerHome, '.cursor', 'projects', keyWithoutLeadingDash, 'agent-transcripts')),
64
+ roots: providerHomes.flatMap((providerHome) => workspacePaths.map((workspace) => join(providerHome, '.cursor', 'projects', workspaceKey(workspace, false), 'agent-transcripts'))),
56
65
  },
57
66
  {
58
67
  provider: 'factory',
59
- adapter: new FactorySessionAdapter(),
60
- roots: providerHomes.flatMap((providerHome) => [
61
- join(providerHome, '.factory', 'projects', keyWithLeadingDash),
62
- join(providerHome, '.factory', 'sessions', keyWithLeadingDash),
63
- ]),
68
+ roots: providerHomes.flatMap((providerHome) => workspacePaths.flatMap((workspace) => [
69
+ join(providerHome, '.factory', 'projects', workspaceKey(workspace, true)),
70
+ join(providerHome, '.factory', 'sessions', workspaceKey(workspace, true)),
71
+ ])),
64
72
  },
65
73
  {
74
+ // Pi stores every working directory's sessions in its own
75
+ // subdirectory of the sessions root, named `--<path>--` where
76
+ // `<path>` has its leading separator removed and `/`, `\`, and `:`
77
+ // replaced with `-` (https://pi.dev/docs/latest/session-format,
78
+ // "File Location", verified 2026-10-12) — the same transform
79
+ // `workspaceKey(path, false)` already applies for Cursor below.
80
+ // Scanning the whole sessions root (as before) would import every
81
+ // other workspace's history into this one's catalog (#2656).
66
82
  provider: 'pi',
67
- adapter: new PiSessionAdapter(),
68
- roots: options.providerHome
69
- ? [process.env.PI_CODING_AGENT_SESSION_DIR
70
- ? resolve(process.env.PI_CODING_AGENT_SESSION_DIR)
71
- : join(resolve(options.providerHome), '.pi', 'agent', 'sessions')]
72
- : [],
83
+ roots: (process.env.PI_CODING_AGENT_SESSION_DIR
84
+ ? [resolve(process.env.PI_CODING_AGENT_SESSION_DIR)]
85
+ : providerHomes.map((providerHome) => join(providerHome, '.pi', 'agent', 'sessions'))).flatMap((sessionsRoot) => workspacePaths.map((workspace) => join(sessionsRoot, `--${workspaceKey(workspace, false)}--`))),
73
86
  },
74
87
  ];
88
+ const authorizedRoots = { ...options.authorizedRoots };
75
89
  const reports = new Map();
76
90
  const candidates = [];
77
91
  const seen = new Set();
78
92
  for (const entry of discoverable) {
93
+ if (!expectedProviders.includes(entry.provider) || !supportedProviders.has(entry.provider))
94
+ continue;
95
+ const adapter = registry.get(entry.provider);
96
+ if (adapter.disposition === 'unsupported' || !adapter.supportedOperations.includes('discover'))
97
+ continue;
79
98
  const availableRoots = [];
80
- for (const root of entry.roots) {
81
- if (await pathExists(root))
82
- availableRoots.push(await canonicalPath(root));
99
+ const rootCounts = new Map();
100
+ for (const root of options.authorizedRoots ? options.authorizedRoots[entry.provider] ?? [] : entry.roots) {
101
+ if (await pathExists(root)) {
102
+ const canonical = await canonicalPath(root);
103
+ if (options.authorizedRoots && canonical !== root) {
104
+ throw new SessionContractError('INVALID_ARGUMENT', 'previously authorized provider root changed; rediscover with explicit authorization');
105
+ }
106
+ if (!availableRoots.includes(canonical)) {
107
+ availableRoots.push(canonical);
108
+ rootCounts.set(canonical, {
109
+ root: redactSourceLocator(canonical), rootId: sha256(canonical),
110
+ status: 'checked', sourceCount: 0, duplicateCount: 0,
111
+ });
112
+ }
113
+ }
114
+ else {
115
+ rootCounts.set(root, {
116
+ root: redactSourceLocator(root), rootId: sha256(root),
117
+ status: 'unavailable', sourceCount: 0, duplicateCount: 0,
118
+ });
119
+ }
83
120
  }
84
121
  if (availableRoots.length === 0) {
85
122
  const codexNeedsAuthorization = (entry.provider === 'codex' || entry.provider === 'omp'
86
- || entry.provider === 'deepseek-harness' || entry.provider === 'muse')
123
+ || entry.provider === 'deepseek-harness' || entry.provider === 'muse'
124
+ || entry.provider === 'grokbot')
87
125
  && entry.roots.length === 0;
88
126
  reports.set(entry.provider, providerReport(entry.provider, codexNeedsAuthorization ? 'export-required' : 'unavailable', codexNeedsAuthorization ? 'manual-export' : 'discoverable', [], codexNeedsAuthorization
89
127
  ? 'SHARED_ROOT_AUTHORIZATION_REQUIRED'
90
128
  : 'PROVIDER_ROOT_UNAVAILABLE', codexNeedsAuthorization
91
- ? `Pass --${entry.provider}-root with an explicitly authorized sessions root.`
129
+ ? `Pass --${entry.provider === 'deepseek-harness' ? 'dsh' : entry.provider}-root with an explicitly authorized sessions root.`
92
130
  : `No authorized ${entry.provider} workspace history root was found.`));
131
+ if (entry.provider === 'codex')
132
+ reports.get(entry.provider).rootCounts = [...rootCounts.values()];
93
133
  continue;
94
134
  }
135
+ authorizedRoots[entry.provider] = availableRoots;
95
136
  const scope = {
96
137
  workspaceId,
97
138
  allowedRoots: availableRoots,
98
139
  };
99
140
  const providerSources = [];
100
- for await (const descriptor of entry.adapter.discover(scope)) {
101
- const locator = await canonicalPath(descriptor.locator);
102
- if (entry.provider === 'codex'
103
- && !await codexSourceMatchesWorkspace(locator, workspacePath))
141
+ let matchedBySubfolder = 0;
142
+ let matchedByWorktree = 0;
143
+ const museSourceInspections = [];
144
+ for await (const descriptor of adapter.discover(scope)) {
145
+ const known = options.knownSources?.find(source => source.provider === descriptor.provider && source.locator === descriptor.locator);
146
+ const nativeSessionId = known?.nativeSessionId ?? descriptor.nativeSessionId ?? nativeSessionIdFromLocator(descriptor);
147
+ const exclusion = matchImportExclusion({ ...descriptor, nativeSessionId }, exclusions);
148
+ if (exclusion) {
149
+ const locator = resolve(descriptor.locator);
150
+ const authorizedRoot = scope.allowedRoots.find(root => locator === root || locator.startsWith(`${root}/`));
151
+ if (!authorizedRoot)
152
+ continue;
153
+ const key = `excluded\0${entry.provider}\0${locator}`;
154
+ if (seen.has(key))
155
+ continue;
156
+ seen.add(key);
157
+ const source = {
158
+ sourceId: known?.sourceId ?? sha256(key), provider: entry.provider,
159
+ locator, redactedLocator: redactSourceLocator(locator), locatorClass: descriptor.locatorClass,
160
+ authorizedRoot, modifiedAt: '', sizeBytes: 0, digest: '', nativeSessionId,
161
+ status: 'excluded', exclusion,
162
+ };
163
+ rootCounts.get(authorizedRoot).sourceCount += 1;
164
+ providerSources.push(source);
165
+ candidates.push(source);
104
166
  continue;
105
- if (entry.provider === 'muse'
106
- && !await museNativeSourceMatchesWorkspace({
167
+ }
168
+ let workspaceMatch = null;
169
+ if (entry.provider === 'muse') {
170
+ const inspection = await inspectMuseNativeWorkspace({
107
171
  ...descriptor,
108
172
  sourceId: 'discovery',
109
173
  authorizedScope: scope,
110
- }, workspacePath))
111
- continue;
174
+ }, workspacePath);
175
+ museSourceInspections.push({
176
+ sourceKey: sha256(['muse-workspace-inspection-v1', descriptor.locator].join('\0')),
177
+ redactedLocator: redactSourceLocator(descriptor.locator),
178
+ nativeSessionId: basename(dirname(descriptor.locator)),
179
+ ...inspection,
180
+ });
181
+ if (inspection.outcome !== 'matched')
182
+ continue;
183
+ workspaceMatch = inspection.matchKind ?? null;
184
+ }
185
+ const locator = await canonicalPath(descriptor.locator);
186
+ if (entry.provider === 'codex') {
187
+ workspaceMatch = await codexSourceWorkspaceMatch(locator, workspacePath);
188
+ if (!workspaceMatch)
189
+ continue;
190
+ }
112
191
  const ompHeader = entry.provider === 'omp' ? await readOmpSessionHeader({ ...descriptor, sourceId: 'discovery', authorizedScope: scope }) : undefined;
113
- if (ompHeader && resolve(ompHeader.cwd) !== workspacePath)
114
- continue;
192
+ if (ompHeader) {
193
+ workspaceMatch = await matchSessionWorkspace(ompHeader.cwd, workspacePath);
194
+ if (!workspaceMatch)
195
+ continue;
196
+ }
115
197
  const details = await stat(locator);
116
198
  const authorizedRoot = scope.allowedRoots.find((root) => locator === root || locator.startsWith(`${root}/`));
117
199
  if (!authorizedRoot)
118
200
  continue;
201
+ if (entry.provider === 'claude'
202
+ && !await claudeSourceMatchesWorkspace(locator, workspacePath))
203
+ continue;
119
204
  const fingerprint = await fingerprintSourceFile({
120
205
  selectedPath: locator,
121
206
  allowedRoots: [authorizedRoot],
122
207
  });
123
- const dedupeKey = `${entry.provider}\0${fingerprint.digest}\0${fingerprint.size}`;
124
- if (seen.has(dedupeKey))
208
+ const rolloutId = entry.provider === 'codex' && descriptor.locatorClass === 'codex-rollout-jsonl'
209
+ ? await codexRolloutId(locator) : undefined;
210
+ const dedupeKey = rolloutId
211
+ ? `codex\0rollout\0${rolloutId}`
212
+ : `${entry.provider}\0${fingerprint.digest}\0${fingerprint.size}`;
213
+ const rootCount = rootCounts.get(authorizedRoot);
214
+ if (seen.has(dedupeKey)) {
215
+ rootCount.duplicateCount += 1;
125
216
  continue;
217
+ }
126
218
  seen.add(dedupeKey);
219
+ if (workspaceMatch === 'subfolder')
220
+ matchedBySubfolder += 1;
221
+ if (workspaceMatch === 'worktree')
222
+ matchedByWorktree += 1;
223
+ rootCount.sourceCount += 1;
127
224
  const source = sourceFromDescriptor(descriptor, locator, authorizedRoot, details, fingerprint.digest);
225
+ source.nativeSessionId = rolloutId ?? ompHeader?.id ?? nativeSessionId;
128
226
  if (ompHeader)
129
227
  source.sourceId = sha256(['omp-native-source-v1', workspaceId, ompHeader.id].join('\0'));
228
+ if (entry.provider === 'grokbot') {
229
+ // The replica is rewritten wholesale as its sliding window evicts
230
+ // old entries, so a content-digest sourceId (the default above)
231
+ // would churn every re-discovery and break checkpoint continuity.
232
+ // Key it on the conversation id instead, same rationale as the OMP
233
+ // override above.
234
+ const conversationId = grokbotConversationIdFromLocator(locator);
235
+ if (conversationId) {
236
+ source.sourceId = sha256(['grokbot-native-source-v1', workspaceId, conversationId].join('\0'));
237
+ }
238
+ }
130
239
  providerSources.push(source);
131
240
  candidates.push(source);
132
241
  }
133
- reports.set(entry.provider, providerReport(entry.provider, 'checked', 'discoverable', providerSources, providerSources.length === 0 ? 'NO_WORKSPACE_SOURCES' : null, providerSources.length === 0
134
- ? `The ${entry.provider} root was checked, but no source matched the authorized workspace.`
135
- : null));
242
+ const incompleteMuseInspection = museSourceInspections.some((inspection) => inspection.outcome === 'inconclusive');
243
+ const report = providerReport(entry.provider, incompleteMuseInspection ? 'not-checked' : 'checked', 'discoverable', providerSources, incompleteMuseInspection ? 'MUSE_SOURCE_INSPECTION_INCOMPLETE'
244
+ : providerSources.length === 0 ? 'NO_WORKSPACE_SOURCES' : null, incompleteMuseInspection
245
+ ? 'Review unattributed museSourceInspections and their limit name/value; authorize a supported Muse export for unresolved sources before claiming workspace coverage.'
246
+ : providerSources.length === 0
247
+ ? `The ${entry.provider} root was checked, but no source matched the authorized workspace.`
248
+ : null);
249
+ if (entry.provider === 'muse') {
250
+ report.museSourceInspections = museSourceInspections.sort((a, b) => a.sourceKey.localeCompare(b.sourceKey));
251
+ }
252
+ report.matchedBySubfolder = matchedBySubfolder;
253
+ report.matchedByWorktree = matchedByWorktree;
254
+ if (entry.provider === 'codex')
255
+ report.rootCounts = [...rootCounts.values()];
256
+ reports.set(entry.provider, report);
136
257
  }
137
- for (const provider of SESSION_PROVIDER_IDS) {
258
+ for (const provider of expectedProviders) {
138
259
  if (reports.has(provider))
139
260
  continue;
140
261
  const manual = MANUAL_EXPORT_PROVIDERS.has(provider);
262
+ if (!supportedProviders.has(provider)) {
263
+ reports.set(provider, providerReport(provider, 'not-checked', 'unsupported', [], 'MISSING_ADAPTER', 'Deliberately select a compatible runtime or an authorized supported export.'));
264
+ continue;
265
+ }
141
266
  const grokBuild = provider === 'grok-build';
142
267
  reports.set(provider, providerReport(provider, manual ? 'export-required' : 'not-checked', manual ? 'manual-export' : 'unsupported', [], grokBuild ? 'CLI_EXPORT_REQUIRED'
143
268
  : manual ? 'EXPLICIT_EXPORT_REQUIRED' : 'PROVIDER_NOT_CHECKED', grokBuild
@@ -148,9 +273,15 @@ export async function discoverWorkspaceHistories(options) {
148
273
  }
149
274
  const sources = candidates.sort(compareSources);
150
275
  const providers = [...reports.values()].sort((a, b) => a.provider.localeCompare(b.provider));
276
+ const preflight = coveragePreflight({
277
+ expectedProviders, expectedProviderBasis: options.expectedProviders ? 'explicit' : 'declared-default',
278
+ registry, runtime: options.runtime, reports: providers,
279
+ });
151
280
  const identity = {
152
281
  schemaVersion: DISCOVERY_MANIFEST_VERSION,
153
282
  workspaceId,
283
+ preflight,
284
+ authorizedRoots,
154
285
  sources: sources.map((source) => ({
155
286
  sourceId: source.sourceId,
156
287
  provider: source.provider,
@@ -159,11 +290,17 @@ export async function discoverWorkspaceHistories(options) {
159
290
  modifiedAt: source.modifiedAt,
160
291
  sizeBytes: source.sizeBytes,
161
292
  digest: source.digest,
293
+ ...(source.nativeSessionId ? { nativeSessionId: source.nativeSessionId } : {}),
294
+ ...(source.status ? { status: source.status, exclusion: source.exclusion } : {}),
162
295
  })),
163
296
  providers: providers.map((provider) => ({
164
297
  provider: provider.provider,
165
298
  status: provider.status,
166
299
  reasonCode: provider.reasonCode,
300
+ ...(provider.matchedBySubfolder !== undefined ? { matchedBySubfolder: provider.matchedBySubfolder } : {}),
301
+ ...(provider.matchedByWorktree !== undefined ? { matchedByWorktree: provider.matchedByWorktree } : {}),
302
+ ...(provider.rootCounts ? { rootCounts: provider.rootCounts } : {}),
303
+ ...(provider.museSourceInspections ? { museSourceInspections: provider.museSourceInspections } : {}),
167
304
  })),
168
305
  };
169
306
  return {
@@ -172,6 +309,8 @@ export async function discoverWorkspaceHistories(options) {
172
309
  createdAt: options.createdAt ?? new Date().toISOString(),
173
310
  workspaceId,
174
311
  workspacePath,
312
+ preflight,
313
+ authorizedRoots,
175
314
  providers,
176
315
  sources,
177
316
  };
@@ -194,6 +333,11 @@ export async function readDiscoveryManifest(path) {
194
333
  || !Array.isArray(value.sources)) {
195
334
  throw new Error('session discovery manifest is malformed or unsupported');
196
335
  }
336
+ if (value.preflight) {
337
+ const parsed = SessionCoveragePreflightSchema.safeParse(value.preflight);
338
+ if (!parsed.success)
339
+ throw new SessionContractError('INVALID_ARGUMENT', 'invalid discovery coverage preflight');
340
+ }
197
341
  const expected = await rediscoverManifestIdentity(value);
198
342
  if (expected !== value.manifestId) {
199
343
  throw new Error('session discovery manifest identity does not match its contents');
@@ -207,11 +351,15 @@ export function publicDiscoveryManifest(manifest) {
207
351
  createdAt: manifest.createdAt,
208
352
  workspaceId: manifest.workspaceId,
209
353
  workspacePath: manifest.workspacePath,
354
+ preflight: manifest.preflight,
210
355
  providers: manifest.providers,
211
356
  sources: manifest.sources.map(({ locator: _locator, authorizedRoot: _root, ...source }) => source),
212
357
  totals: {
213
358
  providers: manifest.providers.length,
214
359
  sources: manifest.sources.length,
360
+ excluded: manifest.sources.filter(source => source.status === 'excluded').length,
361
+ matchedBySubfolder: manifest.providers.reduce((sum, provider) => sum + (provider.matchedBySubfolder ?? 0), 0),
362
+ matchedByWorktree: manifest.providers.reduce((sum, provider) => sum + (provider.matchedByWorktree ?? 0), 0),
215
363
  },
216
364
  };
217
365
  }
@@ -231,12 +379,14 @@ function sourceFromDescriptor(descriptor, locator, authorizedRoot, details, dige
231
379
  };
232
380
  }
233
381
  function providerReport(provider, status, disposition, sources, reasonCode, remediation) {
234
- const timestamps = sources.map((source) => source.modifiedAt).sort();
382
+ const timestamps = sources.map((source) => source.modifiedAt).filter(Boolean).sort();
235
383
  return {
236
384
  provider,
237
385
  status,
238
386
  disposition,
239
387
  sourceCount: sources.length,
388
+ matchedBySubfolder: 0,
389
+ matchedByWorktree: 0,
240
390
  dateRange: {
241
391
  earliest: timestamps.at(0) ?? null,
242
392
  latest: timestamps.at(-1) ?? null,
@@ -250,6 +400,8 @@ async function rediscoverManifestIdentity(manifest) {
250
400
  const identity = {
251
401
  schemaVersion: manifest.schemaVersion,
252
402
  workspaceId: manifest.workspaceId,
403
+ ...(manifest.preflight ? { preflight: manifest.preflight } : {}),
404
+ ...(manifest.authorizedRoots ? { authorizedRoots: manifest.authorizedRoots } : {}),
253
405
  sources: manifest.sources.map((source) => ({
254
406
  sourceId: source.sourceId,
255
407
  provider: source.provider,
@@ -258,46 +410,84 @@ async function rediscoverManifestIdentity(manifest) {
258
410
  modifiedAt: source.modifiedAt,
259
411
  sizeBytes: source.sizeBytes,
260
412
  digest: source.digest,
413
+ ...(source.nativeSessionId ? { nativeSessionId: source.nativeSessionId } : {}),
414
+ ...(source.status ? { status: source.status, exclusion: source.exclusion } : {}),
261
415
  })),
262
416
  providers: manifest.providers.map((provider) => ({
263
417
  provider: provider.provider,
264
418
  status: provider.status,
265
419
  reasonCode: provider.reasonCode,
420
+ ...(provider.matchedBySubfolder !== undefined ? { matchedBySubfolder: provider.matchedBySubfolder } : {}),
421
+ ...(provider.matchedByWorktree !== undefined ? { matchedByWorktree: provider.matchedByWorktree } : {}),
422
+ ...(provider.rootCounts ? { rootCounts: provider.rootCounts } : {}),
423
+ ...(provider.museSourceInspections ? { museSourceInspections: provider.museSourceInspections } : {}),
266
424
  })),
267
425
  };
268
426
  return sha256(JSON.stringify(identity));
269
427
  }
270
- async function codexSourceMatchesWorkspace(locator, workspacePath) {
271
- const input = createReadStream(locator, { encoding: 'utf8' });
272
- const lines = createInterface({ input, crlfDelay: Infinity });
273
- let count = 0;
428
+ async function codexDiscoveryRoots(options) {
429
+ const explicit = [...(options.codexRoots ?? []), ...(options.codexRoot ? [options.codexRoot] : [])];
430
+ if (explicit.length > 0)
431
+ return [...new Set(explicit.map((root) => resolve(root)))];
432
+ // Shared stores require the same explicit provider-home authorization as the default root.
433
+ if (!options.providerHome)
434
+ return [];
435
+ const codexHome = join(resolve(options.providerHome), '.codex');
436
+ const roots = [join(codexHome, 'sessions')];
437
+ if (process.env.CODEX_HOME)
438
+ roots.push(resolve(process.env.CODEX_HOME, 'sessions'));
274
439
  try {
275
- for await (const line of lines) {
276
- if (++count > 50)
277
- break;
278
- let value;
279
- try {
280
- value = JSON.parse(line);
281
- }
282
- catch {
283
- continue;
284
- }
285
- const cwd = codexWorkspaceField(value);
286
- if (!cwd)
287
- continue;
288
- try {
289
- return await canonicalPath(cwd) === workspacePath;
290
- }
291
- catch {
292
- return resolve(cwd) === workspacePath;
440
+ const roles = await readdir(join(codexHome, 'roles-runtime'), { withFileTypes: true });
441
+ for (const role of roles.sort((a, b) => a.name.localeCompare(b.name))) {
442
+ if (role.isDirectory() || role.isSymbolicLink()) {
443
+ roots.push(join(codexHome, 'roles-runtime', role.name, '.codex', 'sessions'));
293
444
  }
294
445
  }
295
- return false;
296
446
  }
297
- finally {
298
- lines.close();
299
- input.destroy();
447
+ catch (error) {
448
+ if (!['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
449
+ throw error;
300
450
  }
451
+ return [...new Set(roots)];
452
+ }
453
+ async function codexRolloutId(locator) {
454
+ let count = 0;
455
+ for await (const { line } of streamJsonLines(locator)) {
456
+ if (++count > 50)
457
+ break;
458
+ let value;
459
+ try {
460
+ value = JSON.parse(line);
461
+ }
462
+ catch {
463
+ continue;
464
+ }
465
+ const record = asObject(value);
466
+ const id = asObject(record.payload).id;
467
+ if (record.type === 'session_meta' && typeof id === 'string' && id.length > 0)
468
+ return id;
469
+ }
470
+ return /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i
471
+ .exec(basename(locator))?.[1];
472
+ }
473
+ async function codexSourceWorkspaceMatch(locator, workspacePath) {
474
+ let count = 0;
475
+ for await (const { line } of streamJsonLines(locator)) {
476
+ if (++count > 50)
477
+ break;
478
+ let value;
479
+ try {
480
+ value = JSON.parse(line);
481
+ }
482
+ catch {
483
+ continue;
484
+ }
485
+ const cwd = codexWorkspaceField(value);
486
+ if (!cwd)
487
+ continue;
488
+ return await matchSessionWorkspace(cwd, workspacePath);
489
+ }
490
+ return null;
301
491
  }
302
492
  function codexWorkspaceField(value) {
303
493
  const root = asObject(value);
@@ -322,6 +512,43 @@ function asObject(value) {
322
512
  async function canonicalPath(path) {
323
513
  return realpath(resolve(path));
324
514
  }
515
+ async function claudeSourceMatchesWorkspace(locator, workspacePath) {
516
+ let count = 0;
517
+ for await (const { line } of streamJsonLines(locator, { end: 1024 * 1024 - 1 })) {
518
+ if (++count > 50)
519
+ break;
520
+ let value;
521
+ try {
522
+ value = JSON.parse(line);
523
+ }
524
+ catch {
525
+ continue;
526
+ }
527
+ const cwd = asObject(value).cwd;
528
+ if (typeof cwd !== 'string' || cwd.length === 0)
529
+ continue;
530
+ try {
531
+ return await canonicalPath(cwd) === workspacePath;
532
+ }
533
+ catch {
534
+ return resolve(cwd) === workspacePath;
535
+ }
536
+ }
537
+ // Older transcripts without cwd still use the selected project folder.
538
+ return true;
539
+ }
540
+ export function claudeProjectKey(path) {
541
+ // Claude Code 2.1.302 replaces each character, then caps keys at 200
542
+ // characters with a base-36 suffix from the original path's 32-bit hash.
543
+ const key = path.replace(/[^A-Za-z0-9-]/g, '-');
544
+ if (key.length <= 200)
545
+ return key;
546
+ let hash = 0;
547
+ for (let index = 0; index < path.length; index += 1) {
548
+ hash = ((hash << 5) - hash + path.charCodeAt(index)) | 0;
549
+ }
550
+ return `${key.slice(0, 200)}-${Math.abs(hash).toString(36)}`;
551
+ }
325
552
  function workspaceKey(path, retainLeadingSeparator) {
326
553
  const normalized = path.replace(/\\/g, '/');
327
554
  const input = retainLeadingSeparator ? normalized : normalized.replace(/^\/+/, '');