@aiwg/cli 2026.10.3 → 2026.10.5

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 (279) hide show
  1. package/README.md +2 -2
  2. package/agentic/code/providers/model-capabilities.v1.json +96 -4
  3. package/bin/aiwg.mjs +50 -27
  4. package/dist/src/agents/grounding/knowledge-base.js +54 -6
  5. package/dist/src/artifacts/browser-export.js +6 -0
  6. package/dist/src/artifacts/checksum-manifest.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +173 -92
  8. package/dist/src/artifacts/citation-table-schema.js +59 -0
  9. package/dist/src/artifacts/cli.js +69 -18
  10. package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
  11. package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
  12. package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
  13. package/dist/src/artifacts/corpus-views/renderers.js +3 -3
  14. package/dist/src/artifacts/discovery-eval.js +6 -4
  15. package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
  16. package/dist/src/artifacts/fortemi-core-sync.js +166 -40
  17. package/dist/src/artifacts/framework-capabilities.js +171 -0
  18. package/dist/src/artifacts/framework-index-paths.js +73 -0
  19. package/dist/src/artifacts/framework-source-digest.js +75 -0
  20. package/dist/src/artifacts/index-builder.js +286 -131
  21. package/dist/src/artifacts/index-files.js +132 -18
  22. package/dist/src/artifacts/index-preparation.js +130 -0
  23. package/dist/src/artifacts/index-refresh.js +591 -0
  24. package/dist/src/artifacts/index-worker.mjs +11 -0
  25. package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
  26. package/dist/src/artifacts/prebuilt-deployment.js +46 -0
  27. package/dist/src/artifacts/prebuilt-relations.js +80 -0
  28. package/dist/src/artifacts/query-engine.js +410 -88
  29. package/dist/src/artifacts/relations-builder.js +168 -0
  30. package/dist/src/artifacts/relations.js +148 -0
  31. package/dist/src/artifacts/stats.js +5 -2
  32. package/dist/src/artifacts/types.js +30 -10
  33. package/dist/src/artifacts/watcher.js +1 -1
  34. package/dist/src/auth/credential-store.js +2 -1
  35. package/dist/src/catalog/cli.d.mts +5 -0
  36. package/dist/src/channel/manager.d.mts +20 -0
  37. package/dist/src/channel/manager.mjs +19 -2
  38. package/dist/src/cli/command-log.js +2 -3
  39. package/dist/src/cli/handlers/artifacts.js +3 -0
  40. package/dist/src/cli/handlers/auth.js +3 -0
  41. package/dist/src/cli/handlers/decision.js +19 -12
  42. package/dist/src/cli/handlers/diagnose.js +4 -3
  43. package/dist/src/cli/handlers/effect.js +4 -2
  44. package/dist/src/cli/handlers/evidence.js +3 -0
  45. package/dist/src/cli/handlers/help.js +1 -0
  46. package/dist/src/cli/handlers/index.js +3 -1
  47. package/dist/src/cli/handlers/init.js +4 -1
  48. package/dist/src/cli/handlers/lint.js +5 -0
  49. package/dist/src/cli/handlers/models.js +104 -8
  50. package/dist/src/cli/handlers/ralph-launcher.js +2 -0
  51. package/dist/src/cli/handlers/refresh.js +12 -0
  52. package/dist/src/cli/handlers/resource-versions.js +3 -0
  53. package/dist/src/cli/handlers/rules.js +195 -0
  54. package/dist/src/cli/handlers/run.js +4 -0
  55. package/dist/src/cli/handlers/runtime-info.js +1 -2
  56. package/dist/src/cli/handlers/script-runner.js +3 -2
  57. package/dist/src/cli/handlers/session.js +19 -9
  58. package/dist/src/cli/handlers/sessions.js +137 -43
  59. package/dist/src/cli/handlers/setup-manifest.js +39 -44
  60. package/dist/src/cli/handlers/setup.js +41 -0
  61. package/dist/src/cli/handlers/steward.js +11 -0
  62. package/dist/src/cli/handlers/subcommands.js +57 -2
  63. package/dist/src/cli/handlers/uhp.js +3 -0
  64. package/dist/src/cli/handlers/use.js +294 -55
  65. package/dist/src/cli/handlers/utilities.js +26 -10
  66. package/dist/src/cli/handlers/version.js +8 -0
  67. package/dist/src/cli/router.js +15 -1
  68. package/dist/src/cli/services/deployment-verification.js +19 -9
  69. package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
  70. package/dist/src/cli/skill-usage.js +2 -3
  71. package/dist/src/config/aiwg-config.js +87 -37
  72. package/dist/src/config/cli.js +111 -5
  73. package/dist/src/config/decision-config.js +106 -0
  74. package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
  75. package/dist/src/config/gitignore.js +50 -0
  76. package/dist/src/config/index-graph-overrides.js +36 -0
  77. package/dist/src/config/project-artifacts-health.d.mts +37 -0
  78. package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
  79. package/dist/src/config/user-config-dir.d.mts +9 -0
  80. package/dist/src/config/user-config.js +2 -1
  81. package/dist/src/config/user-registry.js +23 -15
  82. package/dist/src/config/user-state.js +7 -0
  83. package/dist/src/decision/ask.js +203 -43
  84. package/dist/src/decision/context-live-qualification.js +2 -2
  85. package/dist/src/decision/driver.js +13 -8
  86. package/dist/src/decision/ensemble/aggregate.js +23 -10
  87. package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
  88. package/dist/src/decision/entry.js +2 -15
  89. package/dist/src/decision/graph-live-qualification.js +1 -1
  90. package/dist/src/decision/graph-run.js +9 -0
  91. package/dist/src/decision/heldout/collector.js +5 -13
  92. package/dist/src/decision/heldout/contract.js +30 -7
  93. package/dist/src/decision/jev-credentials.js +15 -1
  94. package/dist/src/decision/ledger.js +131 -28
  95. package/dist/src/decision/offload-activation.js +137 -0
  96. package/dist/src/decision/offload.js +550 -0
  97. package/dist/src/decision/qualification/load.js +4 -6
  98. package/dist/src/decision/savings.js +28 -0
  99. package/dist/src/effects/types.js +5 -1
  100. package/dist/src/effects/verifiers/git.js +2 -1
  101. package/dist/src/effects/verifiers/tracker.js +26 -14
  102. package/dist/src/extensions/commands/definitions.js +19 -0
  103. package/dist/src/extensions/project-local-remove.js +36 -1
  104. package/dist/src/gates/providers/loader.js +61 -17
  105. package/dist/src/installation/manager-command.d.mts +18 -0
  106. package/dist/src/installation/manager-command.mjs +14 -2
  107. package/dist/src/installation/manager.d.mts +49 -0
  108. package/dist/src/installation/manager.mjs +78 -3
  109. package/dist/src/issues/cli.js +4 -4
  110. package/dist/src/issues/local.js +24 -5
  111. package/dist/src/jobs/runner.js +1 -1
  112. package/dist/src/lint/cli.js +27 -1
  113. package/dist/src/lint/loader.js +2 -1
  114. package/dist/src/lint/reporters.js +25 -1
  115. package/dist/src/lint/rule-activation.js +43 -0
  116. package/dist/src/lint/runner.js +137 -62
  117. package/dist/src/mcp/adapters/codex-runtime.js +7 -1
  118. package/dist/src/mcp/claude-install.d.mts +4 -0
  119. package/dist/src/mcp/claude-install.mjs +41 -0
  120. package/dist/src/mcp/cli.d.mts +1 -0
  121. package/dist/src/mcp/cli.mjs +36 -11
  122. package/dist/src/mcp/config-file.d.mts +28 -0
  123. package/dist/src/mcp/config-layers.d.mts +36 -0
  124. package/dist/src/mcp/credentials.d.mts +51 -0
  125. package/dist/src/mcp/grok-build-config.d.mts +6 -0
  126. package/dist/src/mcp/grok-build-config.mjs +1 -1
  127. package/dist/src/mcp/helpers.mjs +3 -2
  128. package/dist/src/mcp/muse-native-config.d.mts +13 -0
  129. package/dist/src/mcp/muse-native-config.mjs +1 -0
  130. package/dist/src/mcp/omp-config.d.mts +4 -0
  131. package/dist/src/mcp/registry.js +3 -93
  132. package/dist/src/mcp/registry.mjs +3 -87
  133. package/dist/src/mcp/server-config.d.mts +3 -0
  134. package/dist/src/mcp/server-config.mjs +89 -0
  135. package/dist/src/mcp/server.mjs +37 -375
  136. package/dist/src/mcp/test-simple.mjs +2 -1
  137. package/dist/src/mcp/toml-editor.d.mts +4 -0
  138. package/dist/src/mcp/toml-string.d.mts +1 -0
  139. package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
  140. package/dist/src/mcp/tool-filters.d.mts +46 -0
  141. package/dist/src/mcp/tools/decision.mjs +12 -11
  142. package/dist/src/mcp/tools/discovery.mjs +62 -55
  143. package/dist/src/mcp/tools/orchestration.mjs +12 -2
  144. package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
  145. package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
  146. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
  147. package/dist/src/mission-protocol/codecs.js +8 -0
  148. package/dist/src/models/config-loader.js +7 -2
  149. package/dist/src/models/model-capabilities.v1.json +96 -4
  150. package/dist/src/models/model-discovery.js +76 -11
  151. package/dist/src/models/provider-policy.js +101 -7
  152. package/dist/src/models/qualification-digest.d.mts +2 -0
  153. package/dist/src/models/resolver.js +12 -10
  154. package/dist/src/models/worker-direct-readiness.js +65 -44
  155. package/dist/src/models/worker-dispatch-offer.js +3 -3
  156. package/dist/src/models/worker-health-readiness.js +16 -3
  157. package/dist/src/models/worker-installation.d.mts +39 -0
  158. package/dist/src/models/worker-installation.mjs +135 -28
  159. package/dist/src/process/bounded-child-process.d.mts +84 -0
  160. package/dist/src/process/bounded-child-process.mjs +43 -0
  161. package/dist/src/process/cli-command.d.mts +16 -0
  162. package/dist/src/process/signal-child.d.mts +6 -0
  163. package/dist/src/process/signal-child.mjs +7 -0
  164. package/dist/src/providers/deployed-skill-roots.js +20 -0
  165. package/dist/src/providers/grok-build-acp.js +3 -2
  166. package/dist/src/providers/grok-build-headless.js +12 -4
  167. package/dist/src/providers/grok-build-inspect.js +1 -0
  168. package/dist/src/providers/omp-agent.d.mts +8 -0
  169. package/dist/src/providers/omp-diagnostics.d.mts +1 -0
  170. package/dist/src/providers/omp-paths.d.mts +13 -0
  171. package/dist/src/providers/skill-ownership.d.mts +9 -0
  172. package/dist/src/providers/skill-ownership.mjs +88 -0
  173. package/dist/src/rules/activation.d.mts +21 -0
  174. package/dist/src/rules/activation.mjs +62 -0
  175. package/dist/src/rules/inline-budget.d.mts +26 -0
  176. package/dist/src/rules/inline-budget.mjs +66 -0
  177. package/dist/src/rules/inventory.js +129 -0
  178. package/dist/src/rules/pin-state.js +73 -0
  179. package/dist/src/rules/pins.d.mts +14 -0
  180. package/dist/src/rules/pins.mjs +112 -0
  181. package/dist/src/rules/rule-frontmatter.schema.json +197 -0
  182. package/dist/src/serve/mission-conductor.js +38 -12
  183. package/dist/src/serve/worker-invocation.js +30 -10
  184. package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
  185. package/dist/src/sessions/adapter-registry.js +23 -19
  186. package/dist/src/sessions/adapters/claude.js +39 -54
  187. package/dist/src/sessions/adapters/codex.js +95 -67
  188. package/dist/src/sessions/adapters/copilot.js +4 -4
  189. package/dist/src/sessions/adapters/cursor.js +40 -57
  190. package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
  191. package/dist/src/sessions/adapters/factory.js +31 -27
  192. package/dist/src/sessions/adapters/generic.js +10 -10
  193. package/dist/src/sessions/adapters/grok-build.js +11 -11
  194. package/dist/src/sessions/adapters/grokbot.js +24 -13
  195. package/dist/src/sessions/adapters/hermes.js +27 -29
  196. package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
  197. package/dist/src/sessions/adapters/muse.js +150 -93
  198. package/dist/src/sessions/adapters/omp.js +28 -14
  199. package/dist/src/sessions/adapters/openclaw.js +89 -79
  200. package/dist/src/sessions/adapters/opencode.js +27 -24
  201. package/dist/src/sessions/adapters/openhuman.js +18 -60
  202. package/dist/src/sessions/adapters/pi.js +29 -14
  203. package/dist/src/sessions/adapters/warp.js +3 -3
  204. package/dist/src/sessions/adapters/windsurf.js +19 -48
  205. package/dist/src/sessions/batch-contracts.js +16 -8
  206. package/dist/src/sessions/batch-import.js +252 -12
  207. package/dist/src/sessions/contracts.js +50 -3
  208. package/dist/src/sessions/coverage-preflight.js +27 -2
  209. package/dist/src/sessions/export-plan.js +4 -3
  210. package/dist/src/sessions/import-exclusions.js +72 -0
  211. package/dist/src/sessions/import-lease.js +34 -18
  212. package/dist/src/sessions/import-limits.js +37 -0
  213. package/dist/src/sessions/importer.js +60 -38
  214. package/dist/src/sessions/lifecycle.js +45 -0
  215. package/dist/src/sessions/policy.js +145 -26
  216. package/dist/src/sessions/readers.js +106 -53
  217. package/dist/src/sessions/refresh.js +105 -0
  218. package/dist/src/sessions/repository.js +151 -54
  219. package/dist/src/sessions/workspace-discovery.js +292 -60
  220. package/dist/src/sessions/workspace-matching.js +107 -0
  221. package/dist/src/skills/importer.js +1 -0
  222. package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
  223. package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
  224. package/dist/src/smiths/context-pipeline/finalization.js +6 -5
  225. package/dist/src/smiths/context-pipeline/generator.js +21 -4
  226. package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
  227. package/dist/src/smiths/mcpsmith/generator.js +1 -1
  228. package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
  229. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
  230. package/dist/src/storage/backends/fs.js +18 -76
  231. package/dist/src/storage/backends/obsidian.js +1 -0
  232. package/dist/src/tracker/forge-http.js +2 -1
  233. package/dist/src/update/checker.d.mts +2 -0
  234. package/dist/src/update/service.d.mts +22 -0
  235. package/dist/src/utils/contained-filesystem.d.mts +37 -0
  236. package/dist/src/utils/contained-filesystem.mjs +683 -0
  237. package/dist/src/utils/temporary-directory.js +36 -0
  238. package/dist/src/writing/example-generator.js +1 -1
  239. package/package.json +15 -2
  240. package/schemas/models/model-catalog.v1.schema.json +1 -1
  241. package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
  242. package/tools/_resolve-impl.mjs +13 -15
  243. package/tools/agents/deploy-agents.mjs +49 -21
  244. package/tools/agents/providers/base.mjs +104 -134
  245. package/tools/agents/providers/claude.mjs +8 -24
  246. package/tools/agents/providers/codex.mjs +18 -11
  247. package/tools/agents/providers/cursor.mjs +19 -18
  248. package/tools/agents/providers/grok-build.mjs +3 -1
  249. package/tools/agents/providers/hermes.mjs +57 -47
  250. package/tools/agents/providers/openclaw.mjs +9 -4
  251. package/tools/agents/providers/pi.mjs +5 -0
  252. package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
  253. package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
  254. package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
  255. package/tools/agents/providers/rule-delivery.mjs +1270 -0
  256. package/tools/agents/providers/warp.mjs +20 -26
  257. package/tools/cli/decision-offload-report.mjs +40 -0
  258. package/tools/cli/workspace-status.mjs +862 -0
  259. package/tools/plugin/package-plugins.mjs +186 -8
  260. package/tools/plugin/plugin-links.mjs +114 -0
  261. package/tools/providers/antigravity-transport.mjs +3 -1
  262. package/tools/providers/deepseek-harness-transport.mjs +6 -4
  263. package/tools/providers/omp-transport.mjs +4 -2
  264. package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
  265. package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
  266. package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
  267. package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
  268. package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
  269. package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
  270. package/tools/ralph-external/lib/session-environment.mjs +28 -0
  271. package/tools/ralph-external/lib/systemd-client.mjs +49 -0
  272. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  273. package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
  274. package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
  275. package/tools/ralph-external/process-monitor.mjs +1017 -0
  276. package/tools/ralph-external/session-launcher.mjs +5057 -0
  277. package/tools/scripts/resource-preflight.mjs +541 -0
  278. package/tools/skills/deploy-skills-codex.mjs +2 -1
  279. package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
@@ -0,0 +1,197 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://aiwg.io/schemas/rules/rule-frontmatter.v1.schema.json",
4
+ "title": "Rule activation frontmatter",
5
+ "description": "ADR rule activation contract. Other existing discovery metadata is preserved. Missing activation is permitted only by the migration parser, which warns and infers tier delivery.",
6
+ "type": "object",
7
+ "required": [
8
+ "activation"
9
+ ],
10
+ "additionalProperties": true,
11
+ "properties": {
12
+ "activation": {
13
+ "type": "string",
14
+ "enum": [
15
+ "kernel",
16
+ "summary",
17
+ "bound",
18
+ "paths",
19
+ "on-demand"
20
+ ]
21
+ },
22
+ "summary": {
23
+ "type": "string",
24
+ "pattern": "^[^\\r\\n\\u0085\\u2028\\u2029]*\\S[^\\r\\n\\u0085\\u2028\\u2029]*$",
25
+ "description": "A nonempty single-line imperative, <=240 Unicode code points after trimming. Imperative mood is reviewed by authors.",
26
+ "allOf": [
27
+ {
28
+ "pattern": "^\\s*\\S(?:[^\\r\\n\\u0085\\u2028\\u2029]{0,238}\\S)?\\s*$"
29
+ }
30
+ ]
31
+ },
32
+ "bound_to": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "properties": {
36
+ "skills": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "string",
40
+ "pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
41
+ }
42
+ },
43
+ "agents": {
44
+ "type": "array",
45
+ "items": {
46
+ "type": "string",
47
+ "pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
48
+ }
49
+ },
50
+ "flows": {
51
+ "type": "array",
52
+ "items": {
53
+ "type": "string",
54
+ "pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
55
+ }
56
+ }
57
+ }
58
+ },
59
+ "paths": {
60
+ "type": "array",
61
+ "minItems": 1,
62
+ "items": {
63
+ "type": "string",
64
+ "pattern": "^(?![A-Za-z]:)(?!/)(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$))(?=.*\\S)[^\\r\\n]+$"
65
+ }
66
+ },
67
+ "enforcedBy": {
68
+ "description": "Opaque reserved metadata for #2839. Has no activation or runtime enforcement effect."
69
+ }
70
+ },
71
+ "allOf": [
72
+ {
73
+ "if": {
74
+ "properties": {
75
+ "activation": {
76
+ "enum": [
77
+ "summary",
78
+ "bound",
79
+ "paths"
80
+ ]
81
+ }
82
+ }
83
+ },
84
+ "then": {
85
+ "required": [
86
+ "summary"
87
+ ],
88
+ "properties": {
89
+ "summary": {}
90
+ }
91
+ }
92
+ },
93
+ {
94
+ "if": {
95
+ "properties": {
96
+ "activation": {
97
+ "enum": [
98
+ "kernel",
99
+ "on-demand"
100
+ ]
101
+ }
102
+ }
103
+ },
104
+ "then": {
105
+ "not": {
106
+ "required": [
107
+ "bound_to"
108
+ ],
109
+ "properties": {
110
+ "bound_to": {}
111
+ }
112
+ }
113
+ }
114
+ },
115
+ {
116
+ "if": {
117
+ "properties": {
118
+ "activation": {
119
+ "const": "paths"
120
+ }
121
+ }
122
+ },
123
+ "then": {
124
+ "required": [
125
+ "paths"
126
+ ],
127
+ "properties": {
128
+ "paths": {}
129
+ }
130
+ },
131
+ "else": {
132
+ "not": {
133
+ "required": [
134
+ "paths"
135
+ ],
136
+ "properties": {
137
+ "paths": {}
138
+ }
139
+ }
140
+ }
141
+ },
142
+ {
143
+ "if": {
144
+ "properties": {
145
+ "activation": {
146
+ "const": "bound"
147
+ }
148
+ }
149
+ },
150
+ "then": {
151
+ "required": [
152
+ "bound_to"
153
+ ],
154
+ "properties": {
155
+ "bound_to": {
156
+ "type": "object",
157
+ "anyOf": [
158
+ {
159
+ "required": [
160
+ "skills"
161
+ ],
162
+ "properties": {
163
+ "skills": {
164
+ "type": "array",
165
+ "minItems": 1
166
+ }
167
+ }
168
+ },
169
+ {
170
+ "required": [
171
+ "agents"
172
+ ],
173
+ "properties": {
174
+ "agents": {
175
+ "type": "array",
176
+ "minItems": 1
177
+ }
178
+ }
179
+ },
180
+ {
181
+ "required": [
182
+ "flows"
183
+ ],
184
+ "properties": {
185
+ "flows": {
186
+ "type": "array",
187
+ "minItems": 1
188
+ }
189
+ }
190
+ }
191
+ ]
192
+ }
193
+ }
194
+ }
195
+ }
196
+ ]
197
+ }
@@ -25,8 +25,6 @@
25
25
  import { routeMission } from './agent-router.js';
26
26
  import { StackAdapterRegistry } from './stack-adapters.js';
27
27
  import { assertMissionWorkerHandoff } from '../mission-protocol/codecs.js';
28
- const defaultRunWorker = () => ({ output: undefined, cost: 0 });
29
- const defaultScore = (r) => (r.output ? r.output.length : 0);
30
28
  /**
31
29
  * The cross-stack Mission conductor. Decomposes a Mission into worker cycles,
32
30
  * dispatches each to an executor of the chosen runtime via `routeMission`, and
@@ -36,10 +34,12 @@ export class MissionConductor {
36
34
  adapters;
37
35
  runWorker;
38
36
  scoreOutput;
37
+ scorerId;
39
38
  constructor(opts = {}) {
40
39
  this.adapters = opts.adapters ?? new StackAdapterRegistry();
41
- this.runWorker = opts.runWorker ?? defaultRunWorker;
42
- this.scoreOutput = opts.scoreOutput ?? defaultScore;
40
+ this.runWorker = opts.runWorker;
41
+ this.scoreOutput = opts.scoreOutput;
42
+ this.scorerId = opts.scoreOutput ? (opts.scorerId ?? 'custom') : null;
43
43
  }
44
44
  /**
45
45
  * Conduct a Mission across the given executor pool. Returns the ledger.
@@ -69,6 +69,8 @@ export class MissionConductor {
69
69
  missionId: plan.missionId,
70
70
  goal: plan.goal,
71
71
  completionCriterion: plan.completionCriterion,
72
+ executionMode: this.runWorker ? 'executed' : 'plan-only',
73
+ scorerId: this.scorerId,
72
74
  activityLog: [],
73
75
  cycles: [],
74
76
  totalCost: 0,
@@ -77,6 +79,7 @@ export class MissionConductor {
77
79
  ...(plan.graph ? { graph: structuredClone(plan.graph) } : {}),
78
80
  };
79
81
  ledger.activityLog.push(`mission ${plan.missionId} start — goal: ${plan.goal} — ${plan.cycles.length} cycle(s)` +
82
+ ` — mode: ${ledger.executionMode}, scorer: ${ledger.scorerId ?? '(none)'}` +
80
83
  (resumeFrom ? ` (resume: ${carried.size} carried)` : ''));
81
84
  for (const cycle of plan.cycles) {
82
85
  const graph = plan.graph && cycle.graph ? {
@@ -134,6 +137,20 @@ export class MissionConductor {
134
137
  const executor = routing.selected.executor;
135
138
  const invocation = adapter.invoke(cycle.prompt, graph);
136
139
  ledger.activityLog.push(`cycle ${cycle.id} → executor ${executor.name} (${executor.executorId}) on ${cycle.runtime}: ${invocation.describe}`);
140
+ if (!this.runWorker) {
141
+ ledger.cycles.push({
142
+ cycleId: cycle.id,
143
+ runtime: cycle.runtime,
144
+ primitive: adapter.primitive,
145
+ executorId: executor.executorId,
146
+ routed: true,
147
+ reason: 'plan-only: worker not configured; execution pending',
148
+ cost: 0,
149
+ ...(graph ? { graph } : {}),
150
+ });
151
+ ledger.activityLog.push(`cycle ${cycle.id} PLANNED on ${cycle.runtime} — execution pending`);
152
+ continue;
153
+ }
137
154
  let output;
138
155
  let cost = 0;
139
156
  try {
@@ -173,23 +190,32 @@ export class MissionConductor {
173
190
  ledger.totalCost += cost;
174
191
  ledger.activityLog.push(`cycle ${cycle.id} done on ${cycle.runtime} (cost ${cost})`);
175
192
  }
176
- // Pending = cycles neither completed nor failed (none, here — full pass).
193
+ // Planned cycles remain pending until a worker executes them.
177
194
  const accounted = new Set([...ledger.checkpoint.completed, ...ledger.checkpoint.failed]);
178
195
  ledger.checkpoint.pending = plan.cycles.map((c) => c.id).filter((id) => !accounted.has(id));
179
196
  // Cross-stack aggregation: distinct runtimes that actually ran a worker.
180
197
  ledger.runtimesUsed = [
181
- ...new Set(ledger.cycles.filter((c) => c.routed).map((c) => c.runtime)),
198
+ ...new Set(ledger.cycles.filter((c) => c.routed && accounted.has(c.cycleId)).map((c) => c.runtime)),
182
199
  ];
183
200
  // Best-output selection (REF-015) — conductor-side, across stacks.
184
201
  let best;
185
- for (const c of ledger.cycles) {
186
- if (!c.output)
187
- continue;
188
- const score = this.scoreOutput(c);
189
- if (!best || score > best.score) {
190
- best = { cycleId: c.cycleId, runtime: c.runtime, output: c.output, score };
202
+ if (this.scoreOutput) {
203
+ for (const c of ledger.cycles) {
204
+ if (c.output === undefined)
205
+ continue;
206
+ const score = this.scoreOutput(c);
207
+ if (!Number.isFinite(score)) {
208
+ ledger.activityLog.push(`cycle ${c.cycleId} UNSCORED — scorer ${this.scorerId} returned a non-finite score`);
209
+ continue;
210
+ }
211
+ if (!best || score > best.score) {
212
+ best = { cycleId: c.cycleId, runtime: c.runtime, output: c.output, score };
213
+ }
191
214
  }
192
215
  }
216
+ else {
217
+ ledger.activityLog.push('best-output unavailable: no scorer configured');
218
+ }
193
219
  ledger.bestOutput = best;
194
220
  ledger.activityLog.push(`mission ${plan.missionId} end — completed ${ledger.checkpoint.completed.length}, ` +
195
221
  `failed ${ledger.checkpoint.failed.length}, runtimes [${ledger.runtimesUsed.join(', ')}], ` +
@@ -8,7 +8,7 @@ import { resolveWorkerPlan } from '../models/resolver.js';
8
8
  import { workerConfigDigest, validateWorkerHealthConfig } from '../config/aiwg-config.js';
9
9
  import { assertValidWorkerPayload } from '../mission-protocol/codecs.js';
10
10
  import { qualificationDigest } from '../models/qualification-digest.mjs';
11
- import { qualifyWorkerInvocationProfile, assertWorkerSelectionAllowed, requiredWorkerControls, requiresWorkerExternalBoundary, isCanonicalWorkerModelKey, assertWorkerHealthQualification, WorkerPolicyError, DEFAULT_WORKER_SELECTION } from '../models/provider-policy.js';
11
+ import { qualifyWorkerInvocationProfile, isOperatorQualifiedWorkerAdapter, assertOperatorWorkerNativeArgv, assertWorkerSelectionAllowed, requiredWorkerControls, requiresWorkerExternalBoundary, isCanonicalWorkerModelKey, assertWorkerHealthQualification, WorkerPolicyError, DEFAULT_WORKER_SELECTION } from '../models/provider-policy.js';
12
12
  /** Frozen per-attempt windows; parent/transport ceilings include time already spent. */
13
13
  export function resolveWorkerEffectiveHealth(config, input) {
14
14
  const roleDefaults = { efficiency: 1, coding: 1, reasoning: 2 };
@@ -149,6 +149,7 @@ export async function prepareWorkerInvocation(invocation, qualification) {
149
149
  throw new Error('Worker invocation input/output paths must be distinct');
150
150
  }
151
151
  if (result.transport === 'shell') {
152
+ assertOperatorWorkerNativeArgv(qualification.adapter, result.argv, result.selected, qualification.permissions);
152
153
  if (!absolute(result.argv[0]) || result.argv[0].includes('=') || result.argv.some(value => value.includes('\0'))) {
153
154
  throw new WorkerPolicyError('OG_CONFIG_REFERENCE', 'Worker invocation requires an absolute binary without equals and NUL-free argv');
154
155
  }
@@ -230,8 +231,15 @@ export function parseWorkerCommandArgs(args) {
230
231
  workdir: 'workdir', 'final-output': 'final_output', transport: 'transport', format: 'format' };
231
232
  const result = {};
232
233
  let json = false;
234
+ let premiumAuthorized = false;
233
235
  for (let i = 0; i < args.length; i++) {
234
236
  const token = args[i];
237
+ if (token === '--authorize-premium') {
238
+ if (premiumAuthorized)
239
+ throw new Error('Duplicate --authorize-premium');
240
+ premiumAuthorized = true;
241
+ continue;
242
+ }
235
243
  if (token === '--json') {
236
244
  if (json)
237
245
  throw new Error('Duplicate --json');
@@ -266,7 +274,7 @@ export function parseWorkerCommandArgs(args) {
266
274
  throw new Error('Unsupported transport');
267
275
  if (result.format && !['shell', 'json'].includes(result.format))
268
276
  throw new Error('Unsupported renderer; use POSIX shell or JSON');
269
- return result;
277
+ return { ...result, ...(premiumAuthorized ? { authority: { premiumAuthorized: true, maxAutoTier: 3 } } : {}) };
270
278
  }
271
279
  const bytesDigest = (bytes) => `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
272
280
  export async function inspectWorkerPath(filename, kind) {
@@ -324,6 +332,14 @@ async function readBrief(filename) {
324
332
  await handle.close();
325
333
  }
326
334
  }
335
+ /** Structured root-check failure; only these explicit path details are public. */
336
+ export class WorkerPathScopeError extends WorkerPolicyError {
337
+ pointer;
338
+ constructor(key, filename, roots) {
339
+ super('OG_CONFIG_REFERENCE', `${filename} must be inside the worker-writable ${roots.length === 1 ? 'root' : 'roots'} ${roots.join(', ')}.`);
340
+ this.pointer = key === 'briefPath' ? '/request/brief' : '/request/finalOutput';
341
+ }
342
+ }
327
343
  /** Re-resolve saved JSON through the same trusted owners; saved argv is never authority. */
328
344
  export async function revalidateWorkerInvocationPlan(saved, snapshot, drivers, now = new Date().toISOString()) {
329
345
  if (!saved.request || saved.mode !== 'direct' || saved.status !== 'eligible'
@@ -350,6 +366,8 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
350
366
  let failureCode = 'OG_CONFIG_REFERENCE';
351
367
  let plan;
352
368
  try {
369
+ if (!path.isAbsolute(request.brief))
370
+ throw new WorkerPolicyError('OG_CONFIG_REFERENCE', '--brief must be an absolute path; relative paths are not resolved against cwd or --workdir.');
353
371
  const bytes = await readBrief(request.brief);
354
372
  const briefDigest = bytes === null ? null : bytesDigest(bytes);
355
373
  if (expected && expected.briefDigest !== briefDigest)
@@ -364,7 +382,7 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
364
382
  }
365
383
  }
366
384
  plan = resolveWorkerPlan(snapshot, { role: request.role, taskClass: request.task, group: request.group,
367
- transport: request.transport, now, expectedDigests: expected?.digests,
385
+ transport: request.transport, authority: request.authority, now, expectedDigests: expected?.digests,
368
386
  ...(brief ? { dataClass: brief.intent.dataClass, member: brief.intent.pins.member,
369
387
  model: brief.intent.pins.model, effort: brief.intent.pins.effort?.value, ceilings: {
370
388
  ...brief.intent.limits, costUsd: brief.intent.limits.costUsd ?? undefined
@@ -442,7 +460,7 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
442
460
  throw new Error('MCP server/tool is not registered and allowed by the current MCP profile');
443
461
  }
444
462
  }
445
- const controls = requiredWorkerControls({ policy: plan.policy, permissions: tuple.permissions, effort: tuple.effort,
463
+ const controls = isOperatorQualifiedWorkerAdapter(adapter) ? (healthConfig?.requireStepCap ? ['stepCap'] : []) : requiredWorkerControls({ policy: plan.policy, permissions: tuple.permissions, effort: tuple.effort,
446
464
  requiredControls: healthConfig?.requireStepCap ? ['stepCap'] : [] });
447
465
  pointer = `/parallelism/clis/${tuple.cli}/invocationProfile`;
448
466
  failureCode = 'OG_ADAPTER_UNQUALIFIED';
@@ -469,9 +487,8 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
469
487
  readiness: bytes !== null && workspaceExists && outputParentsExist ? 'launchable' : 'preparatory', briefDigest,
470
488
  limits, maxOutputBytes: adapter.invocation.maxOutputBytes ?? 10485760,
471
489
  effectiveCaps: tuple.effectiveMaxParallel === null ? {} : { parallel: tuple.effectiveMaxParallel },
472
- controlEvidence: controls.map(name => profile.controls[name].evidence),
473
- health: effectiveHealth,
474
- };
490
+ controlEvidence: isOperatorQualifiedWorkerAdapter(adapter) ? [adapter.qualification.evidenceRef, ...controls.map(name => profile.controls[name].evidence)] : controls.map(name => profile.controls[name].evidence),
491
+ health: effectiveHealth, };
475
492
  const invocationQualification = { ...qualification, now: Date.parse(now),
476
493
  policy: plan.policy, permissions: tuple.permissions, role: request.role, modelObservation: observation,
477
494
  expectedDigests: { policyDigest, catalogDigest: plan.digests.catalogDigest, profileDigest: plan.digests.profileDigest, briefDigest },
@@ -520,8 +537,10 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
520
537
  return plan;
521
538
  }
522
539
  }
523
- /** Public diagnostics contain fixed summaries, never filesystem/probe/provider error text. */
540
+ /** Public diagnostics contain fixed summaries or explicit typed request-path details. */
524
541
  export function workerInvocationDiagnostic(error, pointer, fallback = 'OG_CONFIG_REFERENCE') {
542
+ if (error instanceof WorkerPathScopeError)
543
+ return { code: error.code, pointer: error.pointer, message: error.message };
525
544
  const code = error instanceof WorkerPolicyError ? error.code : fallback;
526
545
  const messages = {
527
546
  OG_CONFIG_REFERENCE: 'Invalid request or configuration reference; check the paths and settings.',
@@ -529,10 +548,11 @@ export function workerInvocationDiagnostic(error, pointer, fallback = 'OG_CONFIG
529
548
  OG_MODEL_UNAPPROVED: 'The selected model lacks current approved observation evidence.',
530
549
  OG_EFFORT_DENIED: 'The selected effort is denied by the resolved worker policy.',
531
550
  OG_DATA_POLICY: 'The selected model does not satisfy the resolved data policy.',
532
- OG_ADAPTER_UNQUALIFIED: 'The installation or invocation could not be revalidated. Use inspectWorkerInstallation, qualifyWorkerInstallation and recordWorkerInstallation from the trusted installation owner to qualify this workspace.',
551
+ OG_ADAPTER_UNQUALIFIED: 'The installation or invocation could not be revalidated. Run aiwg doctor --probe-workers --qualify to qualify this workspace.',
533
552
  OG_POLICY_RELAXATION: 'The request would relax the resolved worker policy.',
534
553
  OG_BUDGET_UNMEASURABLE: 'The requested worker budget cannot be enforced.',
535
554
  };
536
- return { code, pointer, message: messages[code] };
555
+ return { code, pointer, message: error instanceof WorkerPolicyError && error.message === '--brief must be an absolute path; relative paths are not resolved against cwd or --workdir.'
556
+ ? error.message : messages[code] };
537
557
  }
538
558
  //# sourceMappingURL=worker-invocation.js.map
@@ -0,0 +1,10 @@
1
+ /** Conductor-side stdin framing shared by the shell renderer and the one-shot launcher. */
2
+ export const WORKER_STDIN_FRAME_MAX_BRIEF_BYTES: number;
3
+ export const WORKER_STDIN_FRAME_MAX_BYTES: number;
4
+ export function recordedWorkerStdinBytes(input: {
5
+ filename: string; workspace: string; cli: string; adapterId: string; scopeDigest: string; briefDigest: string;
6
+ storePath: string; storeDigest: string; policy?: import('../models/types.js').WorkerSelectionPolicy;
7
+ }): Promise<Buffer | null>;
8
+ export function workerStdinDocument(input: { brief: string | Buffer; model: string; cwd: string }): string;
9
+ export function workerStdinBytes(invocation: { stdin: 'closed' | 'brief-text' | 'brief-json' | 'adapter-frame'; cwd?: string;
10
+ selected?: { model?: string } }, brief: string | Buffer, adapter?: { buildWorkerStdinFrame?(brief: string | Buffer): string | Uint8Array }): Buffer | null;
@@ -1,3 +1,4 @@
1
+ import { resolveImportLimits } from './import-limits.js';
1
2
  import { ClaudeSessionAdapter } from './adapters/claude.js';
2
3
  import { CodexSessionAdapter } from './adapters/codex.js';
3
4
  import { CopilotSessionAdapter } from './adapters/copilot.js';
@@ -17,27 +18,30 @@ import { WarpSessionAdapter } from './adapters/warp.js';
17
18
  import { DevinDesktopSessionAdapter } from './adapters/windsurf.js';
18
19
  import { GenericSessionInterchangeAdapter } from './adapters/generic.js';
19
20
  import { SessionSourceAdapterRegistry } from './discovery.js';
20
- export function createSessionAdapterRegistry() {
21
+ export function createSessionAdapterRegistry(limits) {
22
+ limits = { ...resolveImportLimits(undefined, {
23
+ maxRecordBytes: limits?.maxRecordBytes, maxSourceBytes: limits?.maxTotalBytes,
24
+ }), ...limits };
21
25
  const registry = new SessionSourceAdapterRegistry();
22
26
  for (const adapter of [
23
- new ClaudeSessionAdapter(),
24
- new CodexSessionAdapter(),
25
- new CopilotSessionAdapter(),
26
- new CursorSessionAdapter(),
27
- new FactorySessionAdapter(),
28
- new HermesSessionAdapter(),
29
- new OpenCodeSessionAdapter(),
30
- new OpenClawSessionAdapter(),
31
- new OpenHumanSessionAdapter(),
32
- new GrokbotSessionAdapter(),
33
- new GrokBuildSessionAdapter(),
34
- new MuseSessionAdapter(),
35
- new PiSessionAdapter(),
36
- new OmpSessionAdapter(),
37
- new DeepSeekHarnessSessionAdapter(),
38
- new WarpSessionAdapter(),
39
- new DevinDesktopSessionAdapter(),
40
- new GenericSessionInterchangeAdapter(),
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),
41
45
  ])
42
46
  registry.register(adapter);
43
47
  return registry;
@@ -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) {