@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
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Conductor-side stdin framing for resolved worker invocations (#2911).
3
+ *
4
+ * `stdin: 'brief-json'` means the worker reads one JSON params document on
5
+ * stdin, built by the conductor from the brief file and closed at EOF. The
6
+ * brief stays the source of truth and is never copied into argv, so prompt
7
+ * text cannot surface in /proc/<pid>/cmdline, unit properties or argv logs.
8
+ * The document is the OpenHuman agent.chat params shape (`message`,
9
+ * `model_override`, `cwd`; tinyhumansai/openhuman@216ea32
10
+ * crates/openhuman-core/src/agent/schemas.rs:97-105), consumed by
11
+ * `call --params-stdin`, which reads stdin to EOF (core/cli.rs:445-468).
12
+ *
13
+ * Shared by the #2887 shell renderer (as a pipeline stage) and the attached
14
+ * one-shot launcher (written to the child's stdin pipe).
15
+ */
16
+ import { open } from 'node:fs/promises';
17
+ import { createHash } from 'node:crypto';
18
+ import { pathToFileURL } from 'node:url';
19
+
20
+ export const WORKER_STDIN_FRAME_MAX_BRIEF_BYTES = 262144;
21
+ export const WORKER_STDIN_FRAME_MAX_BYTES = 1048576;
22
+
23
+ /** @returns {string} the exact JSON document delivered on stdin. */
24
+ export function workerStdinDocument({ brief, model, cwd }) {
25
+ const text = Buffer.isBuffer(brief) ? new TextDecoder('utf-8', { fatal: true }).decode(brief) : brief;
26
+ if (typeof text !== 'string') throw new Error('brief-json framing requires brief text');
27
+ if (typeof model !== 'string' || !model || model.includes('\0')) throw new Error('brief-json framing requires an explicit model');
28
+ if (typeof cwd !== 'string' || !cwd.startsWith('/') || cwd.includes('\0')) throw new Error('brief-json framing requires an absolute workspace');
29
+ return JSON.stringify({ message: text, model_override: model, cwd });
30
+ }
31
+
32
+ /** Stdin bytes for a resolved invocation: null (closed), the raw brief, or the framed document. */
33
+ export function workerStdinBytes(invocation, brief, adapter) {
34
+ if (invocation.stdin === 'closed') return null;
35
+ if (invocation.stdin === 'brief-text') return Buffer.isBuffer(brief) ? brief : Buffer.from(brief);
36
+ if (invocation.stdin === 'brief-json') {
37
+ return Buffer.from(workerStdinDocument({ brief, model: invocation.selected?.model, cwd: invocation.cwd }));
38
+ }
39
+ if (invocation.stdin === 'adapter-frame') {
40
+ if (typeof adapter?.buildWorkerStdinFrame !== 'function') throw new Error('Installed adapter stdin framer is required');
41
+ if (Buffer.byteLength(brief) > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief exceeds the framing bound');
42
+ const frame = adapter.buildWorkerStdinFrame(brief);
43
+ if (typeof frame !== 'string' && !(frame instanceof Uint8Array)) throw new Error('Adapter stdin frame must be bytes or text');
44
+ if (Buffer.byteLength(frame) === 0) throw new Error('Adapter stdin frame must not be empty');
45
+ if (Buffer.byteLength(frame) > WORKER_STDIN_FRAME_MAX_BYTES) throw new Error('Adapter stdin frame exceeds byte bound');
46
+ return Buffer.from(frame);
47
+ }
48
+ throw new Error(`Unsupported worker stdin mode: ${invocation.stdin}`);
49
+ }
50
+
51
+ async function readBounded(filename) {
52
+ const handle = await open(filename, 'r');
53
+ try {
54
+ const stat = await handle.stat();
55
+ if (!stat.isFile() || stat.size > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief must be a bounded regular file');
56
+ const bytes = Buffer.alloc(WORKER_STDIN_FRAME_MAX_BRIEF_BYTES + 1);
57
+ let length = 0;
58
+ while (length < bytes.length) {
59
+ const { bytesRead } = await handle.read(bytes, length, bytes.length - length, null);
60
+ if (!bytesRead) break;
61
+ length += bytesRead;
62
+ }
63
+ if (length > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief exceeds the framing bound');
64
+ return bytes.subarray(0, length);
65
+ } finally { await handle.close(); }
66
+ }
67
+
68
+ /** Bound host authority only; workspace is an execution scope, never a config source. */
69
+ export async function recordedWorkerStdinBytes({ filename, workspace, cli, adapterId, scopeDigest, briefDigest,
70
+ storePath, storeDigest, policy }) {
71
+ if (!filename?.startsWith('/') || !storePath?.startsWith('/')
72
+ || !/^sha256:[a-f0-9]{64}$/.test(storeDigest ?? '')) throw new Error('Invalid adapter stdin framing request');
73
+ const { loadRecordedWorkerInstallations } = await import('../models/worker-installation.mjs');
74
+ const { loadProviderModelCapabilities } = await import('../models/provider-policy.js');
75
+ const { drivers } = await loadRecordedWorkerInstallations({ registry: loadProviderModelCapabilities(),
76
+ cwd: workspace, policy, storePath, storeDigest });
77
+ const driver = drivers[cli];
78
+ if (!driver || driver.qualification.adapterId !== adapterId
79
+ || driver.qualification.adapter.invocation.stdin !== 'adapter-frame'
80
+ || driver.qualification.installation?.evidence?.scopeDigest !== scopeDigest) throw new Error('Adapter stdin binding changed');
81
+ const brief = await readBounded(filename);
82
+ if (`sha256:${createHash('sha256').update(brief).digest('hex')}` !== briefDigest) throw new Error('Adapter stdin brief changed');
83
+ return workerStdinBytes({ stdin: 'adapter-frame' }, brief, driver);
84
+ }
85
+
86
+ // Pipeline stage: `worker-stdin-frame.mjs BRIEF_PATH MODEL CWD`. Only the
87
+ // brief path, never its content, appears on this command line.
88
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
89
+ const [briefPath, model, cwd] = process.argv.slice(2);
90
+ try {
91
+ if (briefPath === '--adapter-frame') {
92
+ const [filename, workspace, cli, adapterId, scopeDigest, briefDigest, storePath, storeDigest, policyJson] = process.argv.slice(3);
93
+ if (process.argv.length !== 12) throw new Error('Invalid adapter stdin framing request');
94
+ // Reuse the recorded-installation loader; no module path or code supplied
95
+ // by a brief is ever imported. The conductor binds store bytes and policy;
96
+ // never resolve configuration from the worker-writable workspace.
97
+ process.stdout.write(await recordedWorkerStdinBytes({ filename, workspace, cli, adapterId, scopeDigest, briefDigest,
98
+ storePath, storeDigest, policy: JSON.parse(policyJson) ?? undefined }));
99
+ } else {
100
+ if (process.argv.length !== 5 || !briefPath?.startsWith('/')) throw new Error('usage: worker-stdin-frame.mjs BRIEF_PATH MODEL CWD');
101
+ process.stdout.write(workerStdinDocument({ brief: await readBounded(briefPath), model, cwd }));
102
+ }
103
+ } catch (error) {
104
+ process.stderr.write(`worker-stdin-frame: ${error?.message ?? error}\n`);
105
+ process.exitCode = 2;
106
+ }
107
+ }
@@ -0,0 +1,49 @@
1
+ import { resolveImportLimits } from './import-limits.js';
2
+ import { ClaudeSessionAdapter } from './adapters/claude.js';
3
+ import { CodexSessionAdapter } from './adapters/codex.js';
4
+ import { CopilotSessionAdapter } from './adapters/copilot.js';
5
+ import { CursorSessionAdapter } from './adapters/cursor.js';
6
+ import { FactorySessionAdapter } from './adapters/factory.js';
7
+ import { HermesSessionAdapter } from './adapters/hermes.js';
8
+ import { OpenCodeSessionAdapter } from './adapters/opencode.js';
9
+ import { OpenClawSessionAdapter } from './adapters/openclaw.js';
10
+ import { OpenHumanSessionAdapter } from './adapters/openhuman.js';
11
+ import { GrokbotSessionAdapter } from './adapters/grokbot.js';
12
+ import { GrokBuildSessionAdapter } from './adapters/grok-build.js';
13
+ import { MuseSessionAdapter } from './adapters/muse.js';
14
+ import { PiSessionAdapter } from './adapters/pi.js';
15
+ import { OmpSessionAdapter } from './adapters/omp.js';
16
+ import { DeepSeekHarnessSessionAdapter } from './adapters/deepseek-harness.js';
17
+ import { WarpSessionAdapter } from './adapters/warp.js';
18
+ import { DevinDesktopSessionAdapter } from './adapters/windsurf.js';
19
+ import { GenericSessionInterchangeAdapter } from './adapters/generic.js';
20
+ import { SessionSourceAdapterRegistry } from './discovery.js';
21
+ export function createSessionAdapterRegistry(limits) {
22
+ limits = { ...resolveImportLimits(undefined, {
23
+ maxRecordBytes: limits?.maxRecordBytes, maxSourceBytes: limits?.maxTotalBytes,
24
+ }), ...limits };
25
+ const registry = new SessionSourceAdapterRegistry();
26
+ for (const adapter of [
27
+ new ClaudeSessionAdapter(limits),
28
+ new CodexSessionAdapter(limits),
29
+ new CopilotSessionAdapter(limits),
30
+ new CursorSessionAdapter(limits),
31
+ new FactorySessionAdapter(limits),
32
+ new HermesSessionAdapter(limits),
33
+ new OpenCodeSessionAdapter(limits),
34
+ new OpenClawSessionAdapter(limits),
35
+ new OpenHumanSessionAdapter(limits),
36
+ new GrokbotSessionAdapter(limits),
37
+ new GrokBuildSessionAdapter(limits),
38
+ new MuseSessionAdapter(limits),
39
+ new PiSessionAdapter(limits),
40
+ new OmpSessionAdapter(limits),
41
+ new DeepSeekHarnessSessionAdapter(limits),
42
+ new WarpSessionAdapter(limits),
43
+ new DevinDesktopSessionAdapter(limits),
44
+ new GenericSessionInterchangeAdapter(limits),
45
+ ])
46
+ registry.register(adapter);
47
+ return registry;
48
+ }
49
+ //# sourceMappingURL=adapter-registry.js.map
@@ -1,9 +1,9 @@
1
1
  import { opendir } from 'node:fs/promises';
2
2
  import { basename, extname, resolve } from 'node:path';
3
3
  import { z } from 'zod';
4
- import { SessionContractError, assertSupportedSchemaMajor, sha256, } from '../contracts.js';
4
+ import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, sha256, } from '../contracts.js';
5
5
  import { redactSourceLocator } from '../discovery.js';
6
- import { readBoundedJson, readBoundedJsonLines, streamBoundedJsonLines, } from '../readers.js';
6
+ import { readBoundedJson, streamBoundedJsonLines, } from '../readers.js';
7
7
  export const CLAUDE_ADAPTER_VERSION = '1.1.0';
8
8
  export const CLAUDE_TRANSCRIPT_SCHEMA_VERSION = '1.0.0';
9
9
  /** AIWG's own understanding of the layout it supports; Claude web/account
@@ -101,7 +101,7 @@ export class ClaudeSessionAdapter {
101
101
  for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
102
102
  emitted += 1;
103
103
  if (emitted > this.discoveryLimits.maxFiles) {
104
- throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Claude source discovery exceeded the authorized file limit');
104
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Claude source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
105
105
  }
106
106
  yield {
107
107
  provider: 'claude',
@@ -112,12 +112,19 @@ export class ClaudeSessionAdapter {
112
112
  }
113
113
  }
114
114
  async inspect(source) {
115
- const parsed = await this.readSource(source);
116
- return {
117
- sourceSchemaVersion: parsed.schemaVersion,
118
- consistency: parsed.consistency,
119
- operationalState: 'available',
120
- };
115
+ if (source.locatorClass === 'claude-web-export-json') {
116
+ const parsed = await this.readWebExportSource(source);
117
+ return {
118
+ sourceSchemaVersion: parsed.schemaVersion,
119
+ consistency: parsed.consistency,
120
+ operationalState: 'available',
121
+ };
122
+ }
123
+ const records = this.readSource(source);
124
+ let result = await records.next();
125
+ while (!result.done)
126
+ result = await records.next();
127
+ return result.value;
121
128
  }
122
129
  async *stream(source, cursor) {
123
130
  if (source.locatorClass === 'claude-web-export-json') {
@@ -127,69 +134,57 @@ export class ClaudeSessionAdapter {
127
134
  yield record;
128
135
  return;
129
136
  }
137
+ yield* this.readSource(source, cursor);
138
+ }
139
+ async *readSource(source, cursor) {
130
140
  const start = parseRecordCursor(cursor?.value);
131
141
  const input = await streamBoundedJsonLines({
132
142
  selectedPath: source.locator,
133
143
  allowedRoots: source.authorizedScope.allowedRoots,
134
144
  }, { consistency: 'provisional', limits: this.limits });
135
- const hookSource = isHookLocator(source.locator);
145
+ let hookSource = isHookLocator(source.locator) ? true : undefined;
136
146
  let outputIndex = 0;
137
147
  let sawRecord = false;
148
+ let complete = false;
138
149
  let schemaVersion = null;
139
150
  for await (const line of input) {
140
151
  sawRecord = true;
141
- const value = line.value;
152
+ const value = line.value && typeof line.value === 'object'
153
+ ? line.value : {};
142
154
  const currentSchema = typeof value.schemaVersion === 'string'
143
155
  ? value.schemaVersion : CLAUDE_TRANSCRIPT_SCHEMA_VERSION;
144
156
  if (schemaVersion && currentSchema !== schemaVersion) {
145
- throw new SessionContractError('SCHEMA_DRIFT', 'Claude source declares mixed schema versions');
157
+ throw new SessionContractError('SCHEMA_DRIFT', 'Claude source declares mixed schema versions', schemaIssueDetail('schemaVersion'));
146
158
  }
147
159
  schemaVersion = currentSchema;
148
160
  assertSupportedSchemaMajor(schemaVersion);
149
- const normalized = hookSource || isHookRecord(line.value)
150
- ? normalizeHooks([line]).records
151
- : normalizeTranscript([line], source.locator).records;
152
- for (const record of normalized) {
161
+ hookSource ??= isHookRecord(line.value);
162
+ const normalized = hookSource
163
+ ? normalizeHooks([line])
164
+ : normalizeTranscript([line], source.locator);
165
+ complete ||= normalized.complete;
166
+ for (const record of normalized.records) {
153
167
  if (outputIndex++ >= start)
154
168
  yield record;
155
169
  }
156
170
  }
157
171
  if (!sawRecord && !input.incompleteTail) {
158
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty');
172
+ throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty', schemaIssueDetail('<root>'));
159
173
  }
160
- }
161
- async readSource(source) {
162
- if (source.locatorClass === 'claude-web-export-json') {
163
- return this.readWebExportSource(source);
164
- }
165
- const result = await readBoundedJsonLines({
166
- selectedPath: source.locator,
167
- allowedRoots: source.authorizedScope.allowedRoots,
168
- }, { consistency: 'provisional', limits: this.limits });
169
- if (result.records.length === 0 && !result.incompleteTail) {
170
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty');
171
- }
172
- const hookSource = isHookLocator(source.locator)
173
- || result.records.some((record) => isHookRecord(record.value));
174
- const normalized = hookSource
175
- ? normalizeHooks(result.records)
176
- : normalizeTranscript(result.records, source.locator);
177
- const schemaVersion = declaredSchemaVersion(result.records);
178
- assertSupportedSchemaMajor(schemaVersion);
179
174
  return {
180
- records: normalized.records,
181
- schemaVersion,
182
- consistency: normalized.complete ? 'complete' : 'provisional',
175
+ sourceSchemaVersion: schemaVersion ?? CLAUDE_TRANSCRIPT_SCHEMA_VERSION,
176
+ consistency: complete ? 'complete' : 'provisional',
177
+ operationalState: 'available',
183
178
  };
184
179
  }
185
180
  async readWebExportSource(source) {
186
181
  const { value } = await readBoundedJson({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, this.limits);
187
182
  const parsed = ClaudeWebExportSchema.safeParse(value);
188
183
  if (!parsed.success) {
189
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is not a recognized conversations.json layout');
184
+ throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is not a recognized conversations.json layout', schemaRejectionDetail(parsed.error));
190
185
  }
191
186
  if (parsed.data.length === 0) {
192
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is empty');
187
+ throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is empty', schemaIssueDetail('<root>'));
193
188
  }
194
189
  return {
195
190
  records: normalizeWebExport(parsed.data),
@@ -263,7 +258,7 @@ function normalizeTranscript(records, locator) {
263
258
  for (const record of records) {
264
259
  const parsed = ClaudeRecordSchema.safeParse(record.value);
265
260
  if (!parsed.success) {
266
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude transcript record is malformed');
261
+ throw new SessionContractError('MALFORMED_SOURCE', 'Claude transcript record is malformed', schemaRejectionDetail(parsed.error));
267
262
  }
268
263
  const value = parsed.data;
269
264
  const embeddedSessionId = value.sessionId ?? value.session_id;
@@ -297,7 +292,7 @@ function normalizeHooks(records) {
297
292
  for (const record of records) {
298
293
  const parsed = ClaudeHookSchema.safeParse(record.value);
299
294
  if (!parsed.success) {
300
- throw new SessionContractError('MALFORMED_SOURCE', 'Claude lifecycle hook record is malformed');
295
+ throw new SessionContractError('MALFORMED_SOURCE', 'Claude lifecycle hook record is malformed', schemaRejectionDetail(parsed.error));
301
296
  }
302
297
  const hook = parsed.data;
303
298
  complete ||= hook.hook_event_name === 'SessionEnd';
@@ -464,21 +459,11 @@ async function* discoverJsonl(root, maxDepth) {
464
459
  pending.push({ path, depth: current.depth + 1 });
465
460
  }
466
461
  }
467
- function declaredSchemaVersion(records) {
468
- const declared = records
469
- .map((record) => {
470
- if (!record.value || typeof record.value !== 'object' || Array.isArray(record.value))
471
- return undefined;
472
- return record.value.schemaVersion;
473
- })
474
- .find((value) => typeof value === 'string');
475
- return declared ?? CLAUDE_TRANSCRIPT_SCHEMA_VERSION;
476
- }
477
462
  function parseRecordCursor(value) {
478
463
  if (value === undefined || value === '')
479
464
  return 0;
480
465
  if (!/^\d+$/.test(value))
481
- throw new SessionContractError('SCHEMA_DRIFT', 'Claude record cursor is invalid');
466
+ throw new SessionContractError('SCHEMA_DRIFT', 'Claude record cursor is invalid', schemaIssueDetail('cursor'));
482
467
  return Number(value);
483
468
  }
484
469
  function hookNativeId(hook, sequence) {
@@ -1,8 +1,8 @@
1
1
  import { opendir } from 'node:fs/promises';
2
2
  import { basename, resolve } from 'node:path';
3
3
  import { z } from 'zod';
4
- import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
5
- import { readBoundedJsonLines, streamBoundedJsonLines, } from '../readers.js';
4
+ import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
5
+ import { streamBoundedJsonLines, } from '../readers.js';
6
6
  export const CODEX_ADAPTER_VERSION = '1.0.0';
7
7
  export const CODEX_SOURCE_SCHEMA_VERSION = '1.0.0';
8
8
  const AppServerEnvelopeSchema = z.object({
@@ -57,7 +57,7 @@ export class CodexSessionAdapter {
57
57
  for (const root of [...scope.allowedRoots].sort()) {
58
58
  for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
59
59
  if (++emitted > this.discoveryLimits.maxFiles) {
60
- throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Codex source discovery exceeded the authorized file limit');
60
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Codex source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
61
61
  }
62
62
  yield {
63
63
  provider: 'codex',
@@ -70,30 +70,34 @@ export class CodexSessionAdapter {
70
70
  }
71
71
  }
72
72
  async inspect(source) {
73
- const parsed = await this.readSource(source);
74
- return {
75
- sourceSchemaVersion: parsed.schemaVersion,
76
- consistency: parsed.consistency,
77
- operationalState: 'available',
78
- };
73
+ const records = this.readSource(source);
74
+ let result = await records.next();
75
+ while (!result.done)
76
+ result = await records.next();
77
+ return result.value;
79
78
  }
80
79
  async *stream(source, cursor) {
80
+ yield* this.readSource(source, cursor);
81
+ }
82
+ async *readSource(source, cursor) {
81
83
  const start = parseCursor(cursor?.value);
82
84
  const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
83
85
  let mode = isAppServerLocator(source.locator)
84
86
  ? 'app-server' : null;
85
87
  let schemaVersion = null;
86
88
  const sourceArtifactSessionId = rolloutIdFromFilename(source.locator);
87
- let nativeSessionId = sourceArtifactSessionId;
89
+ const rolloutState = { nativeSessionId: sourceArtifactSessionId };
88
90
  const identities = new Map();
89
91
  let outputIndex = 0;
90
92
  let sawRecord = false;
93
+ let complete = false;
94
+ let sawActive = false;
91
95
  for await (const line of input) {
92
96
  sawRecord = true;
93
97
  mode ??= isAppServerRecord(line.value) ? 'app-server' : 'rollout';
94
98
  const currentSchema = declaredSchemaVersion([line]);
95
99
  if (schemaVersion && schemaVersion !== currentSchema) {
96
- throw new SessionContractError('SCHEMA_DRIFT', 'Codex source declares mixed schema versions');
100
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex source declares mixed schema versions', schemaIssueDetail('schemaVersion'));
97
101
  }
98
102
  schemaVersion = currentSchema;
99
103
  assertSupportedSchemaMajor(schemaVersion);
@@ -101,30 +105,22 @@ export class CodexSessionAdapter {
101
105
  if (mode === 'app-server') {
102
106
  const parsed = AppServerEnvelopeSchema.safeParse(line.value);
103
107
  if (!parsed.success) {
104
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
108
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed', schemaRejectionDetail(parsed.error));
105
109
  }
106
110
  for (const thread of extractThreads(parsed.data)) {
107
111
  validateThreadIdentity(thread, identities);
112
+ sawActive ||= statusType(thread.status) === 'active';
108
113
  }
109
- normalized = normalizeAppServer([line]).records;
114
+ const appServer = normalizeAppServer([line]);
115
+ complete ||= appServer.complete;
116
+ normalized = appServer.records;
110
117
  }
111
118
  else {
112
119
  const parsed = RolloutEnvelopeSchema.safeParse(line.value);
113
120
  if (!parsed.success) {
114
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
115
- }
116
- const payload = asObject(parsed.data.payload);
117
- if (parsed.data.type === 'session_meta') {
118
- const declaredId = stringValue(payload.id);
119
- if (!declaredId) {
120
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id');
121
- }
122
- nativeSessionId = declaredId;
121
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed', schemaRejectionDetail(parsed.error));
123
122
  }
124
- if (!nativeSessionId) {
125
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records');
126
- }
127
- normalized = [rolloutRecord(nativeSessionId, parsed.data, payload, line, sourceArtifactSessionId)];
123
+ normalized = [normalizeRolloutRecord(rolloutState, parsed.data, line, sourceArtifactSessionId)];
128
124
  }
129
125
  for (const record of normalized) {
130
126
  if (outputIndex++ >= start)
@@ -132,25 +128,12 @@ export class CodexSessionAdapter {
132
128
  }
133
129
  }
134
130
  if (!sawRecord && !input.incompleteTail) {
135
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
136
- }
137
- }
138
- async readSource(source) {
139
- const input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
140
- if (input.records.length === 0 && !input.incompleteTail) {
141
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
131
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty', schemaIssueDetail('<root>'));
142
132
  }
143
- const appServer = isAppServerLocator(source.locator)
144
- || input.records.some((record) => isAppServerRecord(record.value));
145
- const schemaVersion = declaredSchemaVersion(input.records);
146
- assertSupportedSchemaMajor(schemaVersion);
147
- const normalized = appServer
148
- ? normalizeAppServer(input.records)
149
- : normalizeRollout(input.records, source.locator);
150
133
  return {
151
- records: normalized.records,
152
- schemaVersion,
153
- consistency: normalized.complete ? 'complete' : 'provisional',
134
+ sourceSchemaVersion: schemaVersion ?? CODEX_SOURCE_SCHEMA_VERSION,
135
+ consistency: complete && !sawActive ? 'complete' : 'provisional',
136
+ operationalState: 'available',
154
137
  };
155
138
  }
156
139
  }
@@ -162,7 +145,7 @@ function normalizeAppServer(input) {
162
145
  for (const line of input) {
163
146
  const parsed = AppServerEnvelopeSchema.safeParse(line.value);
164
147
  if (!parsed.success) {
165
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
148
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed', schemaRejectionDetail(parsed.error));
166
149
  }
167
150
  const envelope = parsed.data;
168
151
  const threads = extractThreads(envelope);
@@ -207,30 +190,62 @@ function normalizeAppServer(input) {
207
190
  }
208
191
  return { records, complete: complete && !sawActive };
209
192
  }
210
- function normalizeRollout(input, locator) {
211
- const sourceArtifactSessionId = rolloutIdFromFilename(locator);
212
- let nativeSessionId = sourceArtifactSessionId;
213
- const records = [];
214
- for (const line of input) {
215
- const parsed = RolloutEnvelopeSchema.safeParse(line.value);
216
- if (!parsed.success) {
217
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
193
+ function normalizeRolloutRecord(state, envelope, line, sourceArtifactSessionId) {
194
+ const payload = asObject(envelope.payload);
195
+ let firstMetadata = false;
196
+ if (envelope.type === 'session_meta') {
197
+ const declaredId = stringValue(payload.id);
198
+ if (!declaredId) {
199
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id', schemaIssueDetail('payload.id'));
218
200
  }
219
- const envelope = parsed.data;
220
- const payload = asObject(envelope.payload);
221
- if (envelope.type === 'session_meta') {
222
- const declaredId = stringValue(payload.id);
223
- if (!declaredId) {
224
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id');
225
- }
226
- nativeSessionId = declaredId;
201
+ if (!state.metadataId) {
202
+ firstMetadata = true;
203
+ state.metadataId = declaredId;
204
+ state.nativeSessionId = declaredId;
205
+ const spawn = asObject(asObject(asObject(payload.source).subagent).thread_spawn);
206
+ const lineage = Object.fromEntries(Object.entries({
207
+ forkedFromId: stringValue(payload.forked_from_id),
208
+ parentThreadId: stringValue(spawn.parent_thread_id),
209
+ depth: nonnegativeInteger(spawn.depth ?? payload.depth),
210
+ agentPath: stringValue(payload.agent_path ?? spawn.agent_path),
211
+ agentNickname: stringValue(payload.agent_nickname ?? spawn.agent_nickname),
212
+ subagentHistoryStartOrdinal: nonnegativeInteger(payload.subagent_history_start_ordinal),
213
+ threadSource: stringValue(payload.thread_source),
214
+ }).filter(([, value]) => value !== undefined));
215
+ if (Object.keys(lineage).length > 0)
216
+ state.lineage = lineage;
227
217
  }
228
- if (!nativeSessionId) {
229
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records');
218
+ else if (declaredId !== state.metadataId) {
219
+ state.replayParentId ??= declaredId;
230
220
  }
231
- records.push(rolloutRecord(nativeSessionId, envelope, payload, line, sourceArtifactSessionId));
232
221
  }
233
- return { records, complete: false };
222
+ if (!state.nativeSessionId) {
223
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records', schemaIssueDetail('payload.id'));
224
+ }
225
+ const historyStart = state.lineage?.subagentHistoryStartOrdinal;
226
+ // Legacy rollouts have no ordinal boundary; a new turn ends the replay prefix.
227
+ if (historyStart === undefined && (envelope.type === 'turn_context'
228
+ || (envelope.type === 'event_msg' && payload.type === 'task_started'))) {
229
+ state.replayParentId = undefined;
230
+ }
231
+ const parentId = stringValue(state.lineage?.parentThreadId)
232
+ ?? stringValue(state.lineage?.forkedFromId)
233
+ ?? state.replayParentId;
234
+ const inherited = !firstMetadata && parentId && (typeof historyStart === 'number'
235
+ ? (nonnegativeInteger(envelope.ordinal) ?? line.sequence) < historyStart
236
+ : state.replayParentId !== undefined);
237
+ const record = rolloutRecord(state.nativeSessionId, envelope, payload, line, sourceArtifactSessionId);
238
+ if (state.lineage)
239
+ record.extensions.lineage = state.lineage;
240
+ if (inherited) {
241
+ record.extensions.inheritedFromId = parentId;
242
+ record.extensions.replayed = true;
243
+ }
244
+ return record;
245
+ }
246
+ function nonnegativeInteger(value) {
247
+ return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0
248
+ ? value : undefined;
234
249
  }
235
250
  function threadEvidence(thread, envelope, line) {
236
251
  const status = statusType(thread.status);
@@ -350,7 +365,7 @@ function extractThreads(envelope) {
350
365
  return candidates.map((candidate) => {
351
366
  const parsed = ThreadSchema.safeParse(candidate);
352
367
  if (!parsed.success) {
353
- throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server thread is malformed');
368
+ throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server thread is malformed', schemaRejectionDetail(parsed.error));
354
369
  }
355
370
  return parsed.data;
356
371
  });
@@ -359,7 +374,7 @@ function validateThreadIdentity(thread, identities) {
359
374
  const sessionTree = thread.sessionId ?? thread.id;
360
375
  const previous = identities.get(thread.id);
361
376
  if (previous && previous !== sessionTree) {
362
- throw new SessionContractError('SCHEMA_DRIFT', 'Codex thread session-tree identity changed');
377
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex thread session-tree identity changed', schemaIssueDetail('sessionId'));
363
378
  }
364
379
  identities.set(thread.id, sessionTree);
365
380
  }
@@ -514,7 +529,7 @@ function parseCursor(value) {
514
529
  if (value === undefined || value === '')
515
530
  return 0;
516
531
  if (!/^\d+$/.test(value))
517
- throw new SessionContractError('SCHEMA_DRIFT', 'Codex record cursor is invalid');
532
+ throw new SessionContractError('SCHEMA_DRIFT', 'Codex record cursor is invalid', schemaIssueDetail('cursor'));
518
533
  return Number(value);
519
534
  }
520
535
  function unixTimestamp(value) {
@@ -1,6 +1,6 @@
1
1
  import { basename, extname } from 'node:path';
2
2
  import { z } from 'zod';
3
- import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
3
+ import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
4
4
  import { readBoundedJson } from '../readers.js';
5
5
  export const COPILOT_ADAPTER_VERSION = '1.0.0';
6
6
  export const COPILOT_EXPORT_SCHEMA_VERSION = '1.0.0';
@@ -76,7 +76,7 @@ export class CopilotSessionAdapter {
76
76
  }, this.limits);
77
77
  const parsed = ExportSchema.safeParse(value);
78
78
  if (!parsed.success) {
79
- throw new SessionContractError('MALFORMED_SOURCE', 'Copilot chat export is malformed');
79
+ throw new SessionContractError('MALFORMED_SOURCE', 'Copilot chat export is malformed', schemaRejectionDetail(parsed.error));
80
80
  }
81
81
  const schemaVersion = declaredSchemaVersion(parsed.data);
82
82
  assertSupportedSchemaMajor(schemaVersion);
@@ -193,7 +193,7 @@ function declaredSchemaVersion(value) {
193
193
  ? value.version
194
194
  : Number(String(value.version).split('.')[0]);
195
195
  if (!Number.isInteger(major) || major < 1) {
196
- throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot export version');
196
+ throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot export version', schemaIssueDetail('version'));
197
197
  }
198
198
  return `${major}.0.0`;
199
199
  }
@@ -210,7 +210,7 @@ function parseCursor(value) {
210
210
  if (!value)
211
211
  return 0;
212
212
  if (!/^\d+$/.test(value)) {
213
- throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot record cursor');
213
+ throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot record cursor', schemaIssueDetail('cursor'));
214
214
  }
215
215
  return Number(value);
216
216
  }