@coool/opencode-adaptive 0.0.0-stage → 1.0.1

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 (334) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -2
  3. package/dist/adapters/codex-capacity/index.d.ts +4 -0
  4. package/dist/adapters/codex-capacity/index.js +5 -0
  5. package/dist/adapters/codex-capacity/index.js.map +1 -0
  6. package/dist/adapters/codex-capacity/parse.d.ts +28 -0
  7. package/dist/adapters/codex-capacity/parse.js +146 -0
  8. package/dist/adapters/codex-capacity/parse.js.map +1 -0
  9. package/dist/adapters/codex-capacity/reading.d.ts +9 -0
  10. package/dist/adapters/codex-capacity/reading.js +45 -0
  11. package/dist/adapters/codex-capacity/reading.js.map +1 -0
  12. package/dist/adapters/codex-capacity/sensor.d.ts +23 -0
  13. package/dist/adapters/codex-capacity/sensor.js +30 -0
  14. package/dist/adapters/codex-capacity/sensor.js.map +1 -0
  15. package/dist/adapters/codex-capacity/types.d.ts +31 -0
  16. package/dist/adapters/codex-capacity/types.js +18 -0
  17. package/dist/adapters/codex-capacity/types.js.map +1 -0
  18. package/dist/adapters/opencode/escalation-tool.d.ts +51 -0
  19. package/dist/adapters/opencode/escalation-tool.js +61 -0
  20. package/dist/adapters/opencode/escalation-tool.js.map +1 -0
  21. package/dist/adapters/opencode/events.d.ts +23 -0
  22. package/dist/adapters/opencode/events.js +68 -0
  23. package/dist/adapters/opencode/events.js.map +1 -0
  24. package/dist/adapters/opencode/hooks.d.ts +34 -0
  25. package/dist/adapters/opencode/hooks.js +29 -0
  26. package/dist/adapters/opencode/hooks.js.map +1 -0
  27. package/dist/adapters/opencode/index.d.ts +16 -0
  28. package/dist/adapters/opencode/index.js +9 -0
  29. package/dist/adapters/opencode/index.js.map +1 -0
  30. package/dist/adapters/opencode/inventory.d.ts +30 -0
  31. package/dist/adapters/opencode/inventory.js +53 -0
  32. package/dist/adapters/opencode/inventory.js.map +1 -0
  33. package/dist/adapters/opencode/report.d.ts +91 -0
  34. package/dist/adapters/opencode/report.js +145 -0
  35. package/dist/adapters/opencode/report.js.map +1 -0
  36. package/dist/adapters/opencode/session-ops.d.ts +39 -0
  37. package/dist/adapters/opencode/session-ops.js +32 -0
  38. package/dist/adapters/opencode/session-ops.js.map +1 -0
  39. package/dist/adapters/opencode/storage.d.ts +15 -0
  40. package/dist/adapters/opencode/storage.js +8 -0
  41. package/dist/adapters/opencode/storage.js.map +1 -0
  42. package/dist/adapters/opencode/tier-tool.d.ts +37 -0
  43. package/dist/adapters/opencode/tier-tool.js +72 -0
  44. package/dist/adapters/opencode/tier-tool.js.map +1 -0
  45. package/dist/adapters/opencode/types.d.ts +101 -0
  46. package/dist/adapters/opencode/types.js +2 -0
  47. package/dist/adapters/opencode/types.js.map +1 -0
  48. package/dist/core/compatibility/gate.d.ts +7 -0
  49. package/dist/core/compatibility/gate.js +51 -0
  50. package/dist/core/compatibility/gate.js.map +1 -0
  51. package/dist/core/compatibility/index.d.ts +2 -0
  52. package/dist/core/compatibility/index.js +3 -0
  53. package/dist/core/compatibility/index.js.map +1 -0
  54. package/dist/core/compatibility/types.d.ts +53 -0
  55. package/dist/core/compatibility/types.js +27 -0
  56. package/dist/core/compatibility/types.js.map +1 -0
  57. package/dist/core/scheduler/admit.d.ts +6 -0
  58. package/dist/core/scheduler/admit.js +154 -0
  59. package/dist/core/scheduler/admit.js.map +1 -0
  60. package/dist/core/scheduler/escalate.d.ts +6 -0
  61. package/dist/core/scheduler/escalate.js +45 -0
  62. package/dist/core/scheduler/escalate.js.map +1 -0
  63. package/dist/core/scheduler/index.d.ts +4 -0
  64. package/dist/core/scheduler/index.js +5 -0
  65. package/dist/core/scheduler/index.js.map +1 -0
  66. package/dist/core/scheduler/mode.d.ts +8 -0
  67. package/dist/core/scheduler/mode.js +10 -0
  68. package/dist/core/scheduler/mode.js.map +1 -0
  69. package/dist/core/scheduler/types.d.ts +136 -0
  70. package/dist/core/scheduler/types.js +75 -0
  71. package/dist/core/scheduler/types.js.map +1 -0
  72. package/dist/core/tier-policy/index.d.ts +3 -0
  73. package/dist/core/tier-policy/index.js +4 -0
  74. package/dist/core/tier-policy/index.js.map +1 -0
  75. package/dist/core/tier-policy/resolve.d.ts +18 -0
  76. package/dist/core/tier-policy/resolve.js +52 -0
  77. package/dist/core/tier-policy/resolve.js.map +1 -0
  78. package/dist/core/tier-policy/tier-list.d.ts +10 -0
  79. package/dist/core/tier-policy/tier-list.js +23 -0
  80. package/dist/core/tier-policy/tier-list.js.map +1 -0
  81. package/dist/core/tier-policy/types.d.ts +86 -0
  82. package/dist/core/tier-policy/types.js +49 -0
  83. package/dist/core/tier-policy/types.js.map +1 -0
  84. package/dist/core/work-unit/index.d.ts +3 -0
  85. package/dist/core/work-unit/index.js +4 -0
  86. package/dist/core/work-unit/index.js.map +1 -0
  87. package/dist/core/work-unit/interruption.d.ts +7 -0
  88. package/dist/core/work-unit/interruption.js +12 -0
  89. package/dist/core/work-unit/interruption.js.map +1 -0
  90. package/dist/core/work-unit/tracker.d.ts +53 -0
  91. package/dist/core/work-unit/tracker.js +156 -0
  92. package/dist/core/work-unit/tracker.js.map +1 -0
  93. package/dist/core/work-unit/types.d.ts +151 -0
  94. package/dist/core/work-unit/types.js +23 -0
  95. package/dist/core/work-unit/types.js.map +1 -0
  96. package/dist/execution/continuation/execute.d.ts +18 -0
  97. package/dist/execution/continuation/execute.js +31 -0
  98. package/dist/execution/continuation/execute.js.map +1 -0
  99. package/dist/execution/continuation/index.d.ts +4 -0
  100. package/dist/execution/continuation/index.js +4 -0
  101. package/dist/execution/continuation/index.js.map +1 -0
  102. package/dist/execution/continuation/plan.d.ts +12 -0
  103. package/dist/execution/continuation/plan.js +18 -0
  104. package/dist/execution/continuation/plan.js.map +1 -0
  105. package/dist/execution/continuation/prompts.d.ts +7 -0
  106. package/dist/execution/continuation/prompts.js +8 -0
  107. package/dist/execution/continuation/prompts.js.map +1 -0
  108. package/dist/execution/continuation/types.d.ts +68 -0
  109. package/dist/execution/continuation/types.js +15 -0
  110. package/dist/execution/continuation/types.js.map +1 -0
  111. package/dist/execution/escalation/index.d.ts +1 -0
  112. package/dist/execution/escalation/index.js +2 -0
  113. package/dist/execution/escalation/index.js.map +1 -0
  114. package/dist/execution/escalation/types.d.ts +30 -0
  115. package/dist/execution/escalation/types.js +49 -0
  116. package/dist/execution/escalation/types.js.map +1 -0
  117. package/dist/execution/index.d.ts +4 -0
  118. package/dist/execution/index.js +5 -0
  119. package/dist/execution/index.js.map +1 -0
  120. package/dist/execution/parking/index.d.ts +2 -0
  121. package/dist/execution/parking/index.js +2 -0
  122. package/dist/execution/parking/index.js.map +1 -0
  123. package/dist/execution/parking/plan.d.ts +39 -0
  124. package/dist/execution/parking/plan.js +34 -0
  125. package/dist/execution/parking/plan.js.map +1 -0
  126. package/dist/execution/retry/decide.d.ts +29 -0
  127. package/dist/execution/retry/decide.js +75 -0
  128. package/dist/execution/retry/decide.js.map +1 -0
  129. package/dist/execution/retry/index.d.ts +2 -0
  130. package/dist/execution/retry/index.js +3 -0
  131. package/dist/execution/retry/index.js.map +1 -0
  132. package/dist/execution/retry/types.d.ts +64 -0
  133. package/dist/execution/retry/types.js +9 -0
  134. package/dist/execution/retry/types.js.map +1 -0
  135. package/dist/gui-experimental.cjs +1 -0
  136. package/dist/gui.d.ts +16 -0
  137. package/dist/gui.js +73 -0
  138. package/dist/gui.js.map +1 -0
  139. package/dist/health/capacity/index.d.ts +3 -0
  140. package/dist/health/capacity/index.js +4 -0
  141. package/dist/health/capacity/index.js.map +1 -0
  142. package/dist/health/capacity/merge.d.ts +57 -0
  143. package/dist/health/capacity/merge.js +154 -0
  144. package/dist/health/capacity/merge.js.map +1 -0
  145. package/dist/health/capacity/registry.d.ts +40 -0
  146. package/dist/health/capacity/registry.js +106 -0
  147. package/dist/health/capacity/registry.js.map +1 -0
  148. package/dist/health/capacity/types.d.ts +73 -0
  149. package/dist/health/capacity/types.js +6 -0
  150. package/dist/health/capacity/types.js.map +1 -0
  151. package/dist/health/circuit-breaker/breaker.d.ts +91 -0
  152. package/dist/health/circuit-breaker/breaker.js +150 -0
  153. package/dist/health/circuit-breaker/breaker.js.map +1 -0
  154. package/dist/health/circuit-breaker/index.d.ts +2 -0
  155. package/dist/health/circuit-breaker/index.js +3 -0
  156. package/dist/health/circuit-breaker/index.js.map +1 -0
  157. package/dist/health/circuit-breaker/types.d.ts +52 -0
  158. package/dist/health/circuit-breaker/types.js +13 -0
  159. package/dist/health/circuit-breaker/types.js.map +1 -0
  160. package/dist/health/classifier/classify.d.ts +8 -0
  161. package/dist/health/classifier/classify.js +245 -0
  162. package/dist/health/classifier/classify.js.map +1 -0
  163. package/dist/health/classifier/index.d.ts +2 -0
  164. package/dist/health/classifier/index.js +3 -0
  165. package/dist/health/classifier/index.js.map +1 -0
  166. package/dist/health/classifier/types.d.ts +71 -0
  167. package/dist/health/classifier/types.js +27 -0
  168. package/dist/health/classifier/types.js.map +1 -0
  169. package/dist/health/index.d.ts +4 -0
  170. package/dist/health/index.js +5 -0
  171. package/dist/health/index.js.map +1 -0
  172. package/dist/health/resource-health/index.d.ts +4 -0
  173. package/dist/health/resource-health/index.js +5 -0
  174. package/dist/health/resource-health/index.js.map +1 -0
  175. package/dist/health/resource-health/key.d.ts +18 -0
  176. package/dist/health/resource-health/key.js +54 -0
  177. package/dist/health/resource-health/key.js.map +1 -0
  178. package/dist/health/resource-health/registry.d.ts +46 -0
  179. package/dist/health/resource-health/registry.js +276 -0
  180. package/dist/health/resource-health/registry.js.map +1 -0
  181. package/dist/health/resource-health/transitions.d.ts +9 -0
  182. package/dist/health/resource-health/transitions.js +157 -0
  183. package/dist/health/resource-health/transitions.js.map +1 -0
  184. package/dist/health/resource-health/types.d.ts +122 -0
  185. package/dist/health/resource-health/types.js +44 -0
  186. package/dist/health/resource-health/types.js.map +1 -0
  187. package/dist/index.d.ts +11 -0
  188. package/dist/index.js +105 -0
  189. package/dist/index.js.map +1 -0
  190. package/dist/plugin-id.d.ts +2 -0
  191. package/dist/plugin-id.js +3 -0
  192. package/dist/plugin-id.js.map +1 -0
  193. package/dist/rpc/definition.d.ts +123 -0
  194. package/dist/rpc/definition.js +130 -0
  195. package/dist/rpc/definition.js.map +1 -0
  196. package/dist/rpc/handlers.d.ts +53 -0
  197. package/dist/rpc/handlers.js +125 -0
  198. package/dist/rpc/handlers.js.map +1 -0
  199. package/dist/rpc/status.d.ts +42 -0
  200. package/dist/rpc/status.js +45 -0
  201. package/dist/rpc/status.js.map +1 -0
  202. package/dist/rpc.d.ts +10 -0
  203. package/dist/rpc.js +8 -0
  204. package/dist/rpc.js.map +1 -0
  205. package/dist/state/capacity/index.d.ts +3 -0
  206. package/dist/state/capacity/index.js +4 -0
  207. package/dist/state/capacity/index.js.map +1 -0
  208. package/dist/state/capacity/parse.d.ts +2 -0
  209. package/dist/state/capacity/parse.js +122 -0
  210. package/dist/state/capacity/parse.js.map +1 -0
  211. package/dist/state/capacity/store.d.ts +18 -0
  212. package/dist/state/capacity/store.js +78 -0
  213. package/dist/state/capacity/store.js.map +1 -0
  214. package/dist/state/capacity/types.d.ts +37 -0
  215. package/dist/state/capacity/types.js +11 -0
  216. package/dist/state/capacity/types.js.map +1 -0
  217. package/dist/state/health/index.d.ts +4 -0
  218. package/dist/state/health/index.js +4 -0
  219. package/dist/state/health/index.js.map +1 -0
  220. package/dist/state/health/parse.d.ts +2 -0
  221. package/dist/state/health/parse.js +137 -0
  222. package/dist/state/health/parse.js.map +1 -0
  223. package/dist/state/health/store.d.ts +17 -0
  224. package/dist/state/health/store.js +69 -0
  225. package/dist/state/health/store.js.map +1 -0
  226. package/dist/state/health/types.d.ts +23 -0
  227. package/dist/state/health/types.js +5 -0
  228. package/dist/state/health/types.js.map +1 -0
  229. package/dist/state/parked-work/index.d.ts +4 -0
  230. package/dist/state/parked-work/index.js +4 -0
  231. package/dist/state/parked-work/index.js.map +1 -0
  232. package/dist/state/parked-work/parse.d.ts +6 -0
  233. package/dist/state/parked-work/parse.js +83 -0
  234. package/dist/state/parked-work/parse.js.map +1 -0
  235. package/dist/state/parked-work/store.d.ts +17 -0
  236. package/dist/state/parked-work/store.js +98 -0
  237. package/dist/state/parked-work/store.js.map +1 -0
  238. package/dist/state/parked-work/types.d.ts +41 -0
  239. package/dist/state/parked-work/types.js +7 -0
  240. package/dist/state/parked-work/types.js.map +1 -0
  241. package/dist/state/receipts/bound.d.ts +14 -0
  242. package/dist/state/receipts/bound.js +77 -0
  243. package/dist/state/receipts/bound.js.map +1 -0
  244. package/dist/state/receipts/index.d.ts +6 -0
  245. package/dist/state/receipts/index.js +5 -0
  246. package/dist/state/receipts/index.js.map +1 -0
  247. package/dist/state/receipts/parse.d.ts +6 -0
  248. package/dist/state/receipts/parse.js +226 -0
  249. package/dist/state/receipts/parse.js.map +1 -0
  250. package/dist/state/receipts/store.d.ts +34 -0
  251. package/dist/state/receipts/store.js +148 -0
  252. package/dist/state/receipts/store.js.map +1 -0
  253. package/dist/state/receipts/types.d.ts +61 -0
  254. package/dist/state/receipts/types.js +12 -0
  255. package/dist/state/receipts/types.js.map +1 -0
  256. package/dist/state/session-modes/index.d.ts +4 -0
  257. package/dist/state/session-modes/index.js +4 -0
  258. package/dist/state/session-modes/index.js.map +1 -0
  259. package/dist/state/session-modes/parse.d.ts +8 -0
  260. package/dist/state/session-modes/parse.js +62 -0
  261. package/dist/state/session-modes/parse.js.map +1 -0
  262. package/dist/state/session-modes/store.d.ts +20 -0
  263. package/dist/state/session-modes/store.js +87 -0
  264. package/dist/state/session-modes/store.js.map +1 -0
  265. package/dist/state/session-modes/types.d.ts +41 -0
  266. package/dist/state/session-modes/types.js +7 -0
  267. package/dist/state/session-modes/types.js.map +1 -0
  268. package/dist/state/settings/index.d.ts +4 -0
  269. package/dist/state/settings/index.js +4 -0
  270. package/dist/state/settings/index.js.map +1 -0
  271. package/dist/state/settings/parse.d.ts +33 -0
  272. package/dist/state/settings/parse.js +261 -0
  273. package/dist/state/settings/parse.js.map +1 -0
  274. package/dist/state/settings/store.d.ts +21 -0
  275. package/dist/state/settings/store.js +65 -0
  276. package/dist/state/settings/store.js.map +1 -0
  277. package/dist/state/settings/types.d.ts +62 -0
  278. package/dist/state/settings/types.js +12 -0
  279. package/dist/state/settings/types.js.map +1 -0
  280. package/dist/state/tier-requests/index.d.ts +4 -0
  281. package/dist/state/tier-requests/index.js +4 -0
  282. package/dist/state/tier-requests/index.js.map +1 -0
  283. package/dist/state/tier-requests/parse.d.ts +3 -0
  284. package/dist/state/tier-requests/parse.js +53 -0
  285. package/dist/state/tier-requests/parse.js.map +1 -0
  286. package/dist/state/tier-requests/store.d.ts +27 -0
  287. package/dist/state/tier-requests/store.js +96 -0
  288. package/dist/state/tier-requests/store.js.map +1 -0
  289. package/dist/state/tier-requests/types.d.ts +30 -0
  290. package/dist/state/tier-requests/types.js +7 -0
  291. package/dist/state/tier-requests/types.js.map +1 -0
  292. package/dist/supervisor/index.d.ts +4 -0
  293. package/dist/supervisor/index.js +4 -0
  294. package/dist/supervisor/index.js.map +1 -0
  295. package/dist/supervisor/log.d.ts +10 -0
  296. package/dist/supervisor/log.js +14 -0
  297. package/dist/supervisor/log.js.map +1 -0
  298. package/dist/supervisor/supervisor.d.ts +86 -0
  299. package/dist/supervisor/supervisor.js +1629 -0
  300. package/dist/supervisor/supervisor.js.map +1 -0
  301. package/dist/supervisor/types.d.ts +49 -0
  302. package/dist/supervisor/types.js +3 -0
  303. package/dist/supervisor/types.js.map +1 -0
  304. package/dist/supervisor/view.d.ts +3 -0
  305. package/dist/supervisor/view.js +4 -0
  306. package/dist/supervisor/view.js.map +1 -0
  307. package/dist/tui.d.ts +15 -0
  308. package/dist/tui.js +256 -0
  309. package/dist/tui.js.map +1 -0
  310. package/dist/ui/gui/api.d.ts +17 -0
  311. package/dist/ui/gui/api.js +21 -0
  312. package/dist/ui/gui/api.js.map +1 -0
  313. package/dist/ui/gui/view.d.ts +26 -0
  314. package/dist/ui/gui/view.js +49 -0
  315. package/dist/ui/gui/view.js.map +1 -0
  316. package/dist/ui/tui/controller.d.ts +97 -0
  317. package/dist/ui/tui/controller.js +415 -0
  318. package/dist/ui/tui/controller.js.map +1 -0
  319. package/dist/ui/tui/menu.d.ts +55 -0
  320. package/dist/ui/tui/menu.js +176 -0
  321. package/dist/ui/tui/menu.js.map +1 -0
  322. package/dist/ui/tui/options.d.ts +19 -0
  323. package/dist/ui/tui/options.js +17 -0
  324. package/dist/ui/tui/options.js.map +1 -0
  325. package/dist/ui/tui/receipts.d.ts +21 -0
  326. package/dist/ui/tui/receipts.js +112 -0
  327. package/dist/ui/tui/receipts.js.map +1 -0
  328. package/dist/ui/tui/status.d.ts +22 -0
  329. package/dist/ui/tui/status.js +92 -0
  330. package/dist/ui/tui/status.js.map +1 -0
  331. package/dist/ui/tui/tiers.d.ts +51 -0
  332. package/dist/ui/tui/tiers.js +108 -0
  333. package/dist/ui/tui/tiers.js.map +1 -0
  334. package/package.json +85 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escalation-tool.js","sourceRoot":"","sources":["../../../src/adapters/opencode/escalation-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AAElG,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAK/B,MAAM,gBAAgB,GACpB,0FAA0F;IAC1F,sFAAsF;IACtF,2FAA2F;IAC3F,wFAAwF;IACxF,0FAA0F;IAC1F,0BAA0B,CAAA;AAE5B,sEAAsE;AACtE,MAAM,qBAAqB,GAAG;IAC5B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,mEAAmE;SACjF;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,sEAAsE;SACpF;KACF;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IAChC,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,6EAA6E;AAC7E,MAAM,qBAAqB,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAW,CAAA;AAE1D,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,MAA0B;IAOvD,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE,gBAAgB;QAC7B,KAAK,EAAE,qBAAqB;QAC5B,OAAO,EAAE,qBAAqB;QAC9B,OAAO,EAAE,CAAC,KAAc,EAAE,OAA8B,EAAE,EAAE;YAC1D,MAAM,OAAO,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAA;YAC7C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,oDAAoD,EAAE,CAAC,CAAA;YAC3F,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;YAC5E,OAAO,OAAO,CAAC,OAAO,CACpB,QAAQ;gBACN,CAAC,CAAC,EAAE,OAAO,EAAE,uDAAuD,EAAE;gBACtE,CAAC,CAAC,EAAE,OAAO,EAAE,mDAAmD,EAAE,CACrE,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["/**\n * The typed escalation tool (T-18, ADP-015): the smallest Adaptive-owned\n * mechanism for an agent to request stronger capability. The input schema is\n * a plain JSON Schema — the host builds the model-facing tool definition by\n * converting the schema, and a Standard Schema implementation is silently\n * dropped (\"Schema vendor does not support JSON Schema conversion\", observed\n * on 2.2.5). The tool also opts out of the host's code-mode bundling: with\n * code mode enabled the host routes codemode-bundled tools through the\n * `execute` tool only, and a direct call fails with \"No tool named ... is\n * currently available\" (observed on 2.2.5). `execute` still re-validates\n * defensively: model-produced JSON is untrusted. The tool is deliberately\n * not a planning or task-management API.\n */\nimport { ESCALATION_TOOL_NAME, parseEscalationRequest } from \"../../execution/escalation/index.js\"\n\nexport { ESCALATION_TOOL_NAME }\n\n/** Records the request against the session's current work unit. */\nexport type EscalationRecorder = (sessionID: string, reason: string, evidence: string) => boolean\n\nconst TOOL_DESCRIPTION =\n \"Request stronger model capability for the current work unit. Provide a short reason and \" +\n \"the concrete evidence (what failed or was blocked). Adaptive records the request as \" +\n \"structured evidence and weighs it when a failure on this unit is already classified as a \" +\n \"capability gap (for example context overflow or a content-policy rejection), within a \" +\n \"finite budget; recording alone does not force a tier escalation. This is not a planning \" +\n \"or task-management tool.\"\n\n/** The tool's input schema in JSON Schema form (host-convertible). */\nconst escalationInputSchema = {\n type: \"object\",\n properties: {\n reason: {\n type: \"string\",\n minLength: 1,\n description: \"Short reason why the current work unit needs stronger capability.\",\n },\n evidence: {\n type: \"string\",\n minLength: 1,\n description: \"Concrete evidence of the capability gap: what failed or was blocked.\",\n },\n },\n required: [\"reason\", \"evidence\"],\n additionalProperties: false,\n}\n\n/** Keeps the tool directly callable when the host's code mode is enabled. */\nconst escalationToolOptions = { codemode: false } as const\n\n/** Build the plugin tool registration for the escalation request surface. */\nexport function escalationTool(record: EscalationRecorder): {\n name: typeof ESCALATION_TOOL_NAME\n description: string\n input: typeof escalationInputSchema\n options: typeof escalationToolOptions\n execute: (input: unknown, context: { sessionID: string }) => Promise<{ content: string }>\n} {\n return {\n name: ESCALATION_TOOL_NAME,\n description: TOOL_DESCRIPTION,\n input: escalationInputSchema,\n options: escalationToolOptions,\n execute: (input: unknown, context: { sessionID: string }) => {\n const request = parseEscalationRequest(input)\n if (request === undefined) {\n return Promise.resolve({ content: \"reason and evidence are required non-empty strings\" })\n }\n const recorded = record(context.sessionID, request.reason, request.evidence)\n return Promise.resolve(\n recorded\n ? { content: \"escalation request recorded for the current work unit\" }\n : { content: \"no active work unit; the request was not recorded\" },\n )\n },\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Session event subscription (ADP-001). Subscribes to the lifecycle/
3
+ * selection events, maps them into reports, and pumps them to the supervisor.
4
+ * The pump runs until disposed. A stream error (SSE hiccup, host reconnect)
5
+ * must not permanently silence observation — the pump resubscribes with a
6
+ * bounded backoff and reports each failure to `onError` (wiring decides
7
+ * fail-open behavior — ADP-031). Abort-induced termination is quiet.
8
+ */
9
+ import type { EventDomain } from "@opencode/plugin/promise/event";
10
+ /** The event surface the subscription actually uses (structural — fixture-friendly). */
11
+ export type EventSource = Pick<EventDomain, "subscribe">;
12
+ import type { ExecutionReport } from "./types.js";
13
+ export declare const SESSION_EVENT_TYPES: readonly ["session.execution.started", "session.execution.succeeded", "session.execution.failed", "session.execution.interrupted", "session.model.selected"];
14
+ export interface SessionSubscription {
15
+ /** Abort the stream; the pump settles quietly. */
16
+ dispose(): void;
17
+ /** Settles when the pump ends (disposed or errored). */
18
+ done: Promise<void>;
19
+ }
20
+ /** Subscribe and pump session lifecycle reports to `onReport`, resubscribing after stream errors. */
21
+ export declare function subscribeSessions(events: EventSource, onReport: (report: ExecutionReport) => void, onError: (error: unknown) => void,
22
+ /** Injectable so tests never wait on real timers. */
23
+ pause?: (ms: number) => Promise<void>): SessionSubscription;
@@ -0,0 +1,68 @@
1
+ import { mapSessionEvent } from "./report.js";
2
+ export const SESSION_EVENT_TYPES = [
3
+ "session.execution.started",
4
+ "session.execution.succeeded",
5
+ "session.execution.failed",
6
+ "session.execution.interrupted",
7
+ "session.model.selected",
8
+ ];
9
+ const RETRY_BASE_MS = 1_000;
10
+ const RETRY_MAX_MS = 30_000;
11
+ const defaultPause = (ms) => new Promise((resolve) => {
12
+ setTimeout(resolve, ms);
13
+ });
14
+ /** Subscribe and pump session lifecycle reports to `onReport`, resubscribing after stream errors. */
15
+ export function subscribeSessions(events, onReport, onError,
16
+ /** Injectable so tests never wait on real timers. */
17
+ pause = defaultPause) {
18
+ const controller = new AbortController();
19
+ // Checked through a function on purpose: TS narrows the `controller.signal`
20
+ // property after the first guard, but `dispose()` flips `aborted` from
21
+ // another context mid-pump, so every re-check below is load-bearing.
22
+ const aborted = () => controller.signal.aborted;
23
+ const done = (async () => {
24
+ let backoff = RETRY_BASE_MS;
25
+ for (;;) {
26
+ if (aborted())
27
+ return;
28
+ // Events delivered since the last failure prove the stream itself
29
+ // works; a fresh failure then starts the backoff climb again.
30
+ let delivered = 0;
31
+ try {
32
+ const stream = events.subscribe({
33
+ types: [...SESSION_EVENT_TYPES],
34
+ signal: controller.signal,
35
+ });
36
+ for await (const event of stream) {
37
+ const report = mapSessionEvent(event);
38
+ if (report !== null) {
39
+ delivered += 1;
40
+ onReport(report);
41
+ }
42
+ }
43
+ // A clean stream end is still an observation outage: the host closed
44
+ // the subscription, so fall through to the resubscribe path.
45
+ if (!aborted())
46
+ onError(new Error("session event stream ended"));
47
+ }
48
+ catch (error) {
49
+ if (aborted())
50
+ return;
51
+ onError(error);
52
+ }
53
+ if (aborted())
54
+ return;
55
+ if (delivered > 0)
56
+ backoff = RETRY_BASE_MS;
57
+ await pause(backoff);
58
+ backoff = Math.min(backoff * 2, RETRY_MAX_MS);
59
+ }
60
+ })();
61
+ return {
62
+ dispose: () => {
63
+ controller.abort();
64
+ },
65
+ done,
66
+ };
67
+ }
68
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/adapters/opencode/events.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAqB,MAAM,aAAa,CAAA;AAGhE,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,2BAA2B;IAC3B,6BAA6B;IAC7B,0BAA0B;IAC1B,+BAA+B;IAC/B,wBAAwB;CACY,CAAA;AAStC,MAAM,aAAa,GAAG,KAAK,CAAA;AAC3B,MAAM,YAAY,GAAG,MAAM,CAAA;AAE3B,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;IAC5B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA;AAEJ,qGAAqG;AACrG,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,QAA2C,EAC3C,OAAiC;AACjC,qDAAqD;AACrD,QAAuC,YAAY;IAEnD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,4EAA4E;IAC5E,uEAAuE;IACvE,qEAAqE;IACrE,MAAM,OAAO,GAAG,GAAY,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAA;IACxD,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QACvB,IAAI,OAAO,GAAG,aAAa,CAAA;QAC3B,SAAS,CAAC;YACR,IAAI,OAAO,EAAE;gBAAE,OAAM;YACrB,kEAAkE;YAClE,8DAA8D;YAC9D,IAAI,SAAS,GAAG,CAAC,CAAA;YACjB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;oBAC9B,KAAK,EAAE,CAAC,GAAG,mBAAmB,CAAC;oBAC/B,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAA;gBACF,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAqC,EAAE,CAAC;oBAChE,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;oBACrC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;wBACpB,SAAS,IAAI,CAAC,CAAA;wBACd,QAAQ,CAAC,MAAM,CAAC,CAAA;oBAClB,CAAC;gBACH,CAAC;gBACD,qEAAqE;gBACrE,6DAA6D;gBAC7D,IAAI,CAAC,OAAO,EAAE;oBAAE,OAAO,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAA;YAClE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,OAAO,EAAE;oBAAE,OAAM;gBACrB,OAAO,CAAC,KAAK,CAAC,CAAA;YAChB,CAAC;YACD,IAAI,OAAO,EAAE;gBAAE,OAAM;YACrB,IAAI,SAAS,GAAG,CAAC;gBAAE,OAAO,GAAG,aAAa,CAAA;YAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,CAAA;YACpB,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,YAAY,CAAC,CAAA;QAC/C,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;IACJ,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,UAAU,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC;QACD,IAAI;KACL,CAAA;AACH,CAAC","sourcesContent":["/**\n * Session event subscription (ADP-001). Subscribes to the lifecycle/\n * selection events, maps them into reports, and pumps them to the supervisor.\n * The pump runs until disposed. A stream error (SSE hiccup, host reconnect)\n * must not permanently silence observation — the pump resubscribes with a\n * bounded backoff and reports each failure to `onError` (wiring decides\n * fail-open behavior — ADP-031). Abort-induced termination is quiet.\n */\nimport type { EventDomain } from \"@opencode/plugin/promise/event\"\n\n/** The event surface the subscription actually uses (structural — fixture-friendly). */\nexport type EventSource = Pick<EventDomain, \"subscribe\">\nimport { mapSessionEvent, type SessionEvent } from \"./report.js\"\nimport type { ExecutionReport } from \"./types.js\"\n\nexport const SESSION_EVENT_TYPES = [\n \"session.execution.started\",\n \"session.execution.succeeded\",\n \"session.execution.failed\",\n \"session.execution.interrupted\",\n \"session.model.selected\",\n] as const satisfies readonly string[]\n\nexport interface SessionSubscription {\n /** Abort the stream; the pump settles quietly. */\n dispose(): void\n /** Settles when the pump ends (disposed or errored). */\n done: Promise<void>\n}\n\nconst RETRY_BASE_MS = 1_000\nconst RETRY_MAX_MS = 30_000\n\nconst defaultPause = (ms: number): Promise<void> =>\n new Promise<void>((resolve) => {\n setTimeout(resolve, ms)\n })\n\n/** Subscribe and pump session lifecycle reports to `onReport`, resubscribing after stream errors. */\nexport function subscribeSessions(\n events: EventSource,\n onReport: (report: ExecutionReport) => void,\n onError: (error: unknown) => void,\n /** Injectable so tests never wait on real timers. */\n pause: (ms: number) => Promise<void> = defaultPause,\n): SessionSubscription {\n const controller = new AbortController()\n // Checked through a function on purpose: TS narrows the `controller.signal`\n // property after the first guard, but `dispose()` flips `aborted` from\n // another context mid-pump, so every re-check below is load-bearing.\n const aborted = (): boolean => controller.signal.aborted\n const done = (async () => {\n let backoff = RETRY_BASE_MS\n for (;;) {\n if (aborted()) return\n // Events delivered since the last failure prove the stream itself\n // works; a fresh failure then starts the backoff climb again.\n let delivered = 0\n try {\n const stream = events.subscribe({\n types: [...SESSION_EVENT_TYPES],\n signal: controller.signal,\n })\n for await (const event of stream as AsyncIterable<SessionEvent>) {\n const report = mapSessionEvent(event)\n if (report !== null) {\n delivered += 1\n onReport(report)\n }\n }\n // A clean stream end is still an observation outage: the host closed\n // the subscription, so fall through to the resubscribe path.\n if (!aborted()) onError(new Error(\"session event stream ended\"))\n } catch (error) {\n if (aborted()) return\n onError(error)\n }\n if (aborted()) return\n if (delivered > 0) backoff = RETRY_BASE_MS\n await pause(backoff)\n backoff = Math.min(backoff * 2, RETRY_MAX_MS)\n }\n })()\n return {\n dispose: () => {\n controller.abort()\n },\n done,\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Session hook registration (ADP-012/ADP-013/ADP-027). Registers the hooks the
3
+ * supervisor needs on the host session domain and returns their registrations
4
+ * for cleanup. Hooks MUTATE their inputs on the host — the retry handler owns
5
+ * `input.decision`; the adapter passes the raw input through so wiring can
6
+ * veto (`{ retry: false }`) or leave OpenCode's native retry untouched.
7
+ *
8
+ * Fail-open behavior (ADP-031) is applied by the wiring around these handlers;
9
+ * the adapter itself never swallows errors, so wiring sees every failure.
10
+ */
11
+ import type { Registration } from "@opencode/plugin/promise/registration";
12
+ import type { SessionDomain, SessionRetry } from "@opencode/plugin/promise/session";
13
+ /** The session surface the hooks actually use (structural — fixture-friendly). */
14
+ export type SessionHookSource = Pick<SessionDomain, "hook">;
15
+ import type { HttpResponseReport, IdleReport, ModelRequestReport, PromptReport } from "./types.js";
16
+ export interface SessionHookHandlers {
17
+ /** Raw retry hook input; wiring decides and mutates `input.decision`. */
18
+ readonly onRetry: (input: SessionRetry) => Promise<void> | void;
19
+ readonly onModelRequest: (report: ModelRequestReport) => Promise<void> | void;
20
+ readonly onHttpResponse: (report: HttpResponseReport) => Promise<void> | void;
21
+ readonly onIdle: (report: IdleReport) => Promise<void> | void;
22
+ /** Awaited before the turn's model resolution — the admission boundary. */
23
+ readonly onPrompt: (report: PromptReport) => Promise<void> | void;
24
+ }
25
+ /** Optional hook behavior supplied by the wiring. */
26
+ export interface SessionHookOptions {
27
+ /**
28
+ * Allowlist predicate over lowercase response header names selecting the
29
+ * quota telemetry to capture (no other header ever leaves the response).
30
+ */
31
+ readonly capture?: (lowercaseName: string) => boolean;
32
+ }
33
+ /** Register supervisor hooks; resolves to all registrations (dispose in order). */
34
+ export declare function registerSessionHooks(session: SessionHookSource, handlers: SessionHookHandlers, options?: SessionHookOptions): Promise<Registration[]>;
@@ -0,0 +1,29 @@
1
+ import { contextModelRequest, hookModelRequest, mapHttpResponse } from "./report.js";
2
+ /** Register supervisor hooks; resolves to all registrations (dispose in order). */
3
+ export async function registerSessionHooks(session, handlers, options) {
4
+ const acquired = [];
5
+ try {
6
+ acquired.push(await session.hook("retry", (input) => handlers.onRetry(input)));
7
+ acquired.push(await session.hook("context", (input) => handlers.onModelRequest(contextModelRequest(input))));
8
+ acquired.push(await session.hook("model.request", (input) => handlers.onModelRequest(hookModelRequest(input))));
9
+ acquired.push(await session.hook("http.response", async (input) => handlers.onHttpResponse(await mapHttpResponse(input, options))));
10
+ acquired.push(await session.hook("experimental.idle", (input) => handlers.onIdle({ kind: "idle", sessionID: input.sessionID })));
11
+ acquired.push(await session.hook("prompt", (input) => handlers.onPrompt({ kind: "prompt", sessionID: input.sessionID })));
12
+ return acquired;
13
+ }
14
+ catch (error) {
15
+ // Partial-failure rollback: every hook already registered on the host must
16
+ // be disposed so a failed setup leaves no half-wired supervisor behind.
17
+ // Disposal failures are swallowed — the registration failure is the cause.
18
+ for (const registration of acquired) {
19
+ try {
20
+ await registration.dispose();
21
+ }
22
+ catch {
23
+ // Disposal failure must not mask the original registration error.
24
+ }
25
+ }
26
+ throw error;
27
+ }
28
+ }
29
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/adapters/opencode/hooks.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAsBpF,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAA0B,EAC1B,QAA6B,EAC7B,OAA4B;IAE5B,MAAM,QAAQ,GAAmB,EAAE,CAAA;IACnC,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC9E,QAAQ,CAAC,IAAI,CACX,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAC9F,CAAA;QACD,QAAQ,CAAC,IAAI,CACX,MAAM,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE,CAC5C,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CACjD,CACF,CAAA;QACD,QAAQ,CAAC,IAAI,CACX,MAAM,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAClD,QAAQ,CAAC,cAAc,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAC/D,CACF,CAAA;QACD,QAAQ,CAAC,IAAI,CACX,MAAM,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE,CAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAC9D,CACF,CAAA;QACD,QAAQ,CAAC,IAAI,CACX,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAClE,CACF,CAAA;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2EAA2E;QAC3E,wEAAwE;QACxE,2EAA2E;QAC3E,KAAK,MAAM,YAAY,IAAI,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,MAAM,YAAY,CAAC,OAAO,EAAE,CAAA;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACP,kEAAkE;YACpE,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC","sourcesContent":["/**\n * Session hook registration (ADP-012/ADP-013/ADP-027). Registers the hooks the\n * supervisor needs on the host session domain and returns their registrations\n * for cleanup. Hooks MUTATE their inputs on the host — the retry handler owns\n * `input.decision`; the adapter passes the raw input through so wiring can\n * veto (`{ retry: false }`) or leave OpenCode's native retry untouched.\n *\n * Fail-open behavior (ADP-031) is applied by the wiring around these handlers;\n * the adapter itself never swallows errors, so wiring sees every failure.\n */\nimport type { Registration } from \"@opencode/plugin/promise/registration\"\nimport type { SessionDomain, SessionRetry } from \"@opencode/plugin/promise/session\"\n\n/** The session surface the hooks actually use (structural — fixture-friendly). */\nexport type SessionHookSource = Pick<SessionDomain, \"hook\">\nimport { contextModelRequest, hookModelRequest, mapHttpResponse } from \"./report.js\"\nimport type { HttpResponseReport, IdleReport, ModelRequestReport, PromptReport } from \"./types.js\"\n\nexport interface SessionHookHandlers {\n /** Raw retry hook input; wiring decides and mutates `input.decision`. */\n readonly onRetry: (input: SessionRetry) => Promise<void> | void\n readonly onModelRequest: (report: ModelRequestReport) => Promise<void> | void\n readonly onHttpResponse: (report: HttpResponseReport) => Promise<void> | void\n readonly onIdle: (report: IdleReport) => Promise<void> | void\n /** Awaited before the turn's model resolution — the admission boundary. */\n readonly onPrompt: (report: PromptReport) => Promise<void> | void\n}\n\n/** Optional hook behavior supplied by the wiring. */\nexport interface SessionHookOptions {\n /**\n * Allowlist predicate over lowercase response header names selecting the\n * quota telemetry to capture (no other header ever leaves the response).\n */\n readonly capture?: (lowercaseName: string) => boolean\n}\n\n/** Register supervisor hooks; resolves to all registrations (dispose in order). */\nexport async function registerSessionHooks(\n session: SessionHookSource,\n handlers: SessionHookHandlers,\n options?: SessionHookOptions,\n): Promise<Registration[]> {\n const acquired: Registration[] = []\n try {\n acquired.push(await session.hook(\"retry\", (input) => handlers.onRetry(input)))\n acquired.push(\n await session.hook(\"context\", (input) => handlers.onModelRequest(contextModelRequest(input))),\n )\n acquired.push(\n await session.hook(\"model.request\", (input) =>\n handlers.onModelRequest(hookModelRequest(input)),\n ),\n )\n acquired.push(\n await session.hook(\"http.response\", async (input) =>\n handlers.onHttpResponse(await mapHttpResponse(input, options)),\n ),\n )\n acquired.push(\n await session.hook(\"experimental.idle\", (input) =>\n handlers.onIdle({ kind: \"idle\", sessionID: input.sessionID }),\n ),\n )\n acquired.push(\n await session.hook(\"prompt\", (input) =>\n handlers.onPrompt({ kind: \"prompt\", sessionID: input.sessionID }),\n ),\n )\n return acquired\n } catch (error) {\n // Partial-failure rollback: every hook already registered on the host must\n // be disposed so a failed setup leaves no half-wired supervisor behind.\n // Disposal failures are swallowed — the registration failure is the cause.\n for (const registration of acquired) {\n try {\n await registration.dispose()\n } catch {\n // Disposal failure must not mask the original registration error.\n }\n }\n throw error\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export { BODY_EXCERPT_LENGTH, mapHttpResponse, mapSessionEvent, modelRefOf } from "./report.js";
2
+ export type { SessionEvent } from "./report.js";
3
+ export type { AdapterStructuredError, EventReport, ExecutionReport, HttpResponseReport, IdleReport, ModelRequestReport, } from "./types.js";
4
+ export { candidateFor, listCandidates, mapModelInfo } from "./inventory.js";
5
+ export type { ModelSource } from "./inventory.js";
6
+ export { sessionOps } from "./session-ops.js";
7
+ export type { SessionOpsHooks, SessionOpsSource } from "./session-ops.js";
8
+ export { storageSeam } from "./storage.js";
9
+ export type { JsonSeam, StorageSource } from "./storage.js";
10
+ export { SESSION_EVENT_TYPES, subscribeSessions } from "./events.js";
11
+ export type { EventSource, SessionSubscription } from "./events.js";
12
+ export { registerSessionHooks } from "./hooks.js";
13
+ export type { SessionHookHandlers, SessionHookSource } from "./hooks.js";
14
+ export { ESCALATION_TOOL_NAME, escalationTool } from "./escalation-tool.js";
15
+ export { tierTool } from "./tier-tool.js";
16
+ export type { EscalationRecorder } from "./escalation-tool.js";
@@ -0,0 +1,9 @@
1
+ export { BODY_EXCERPT_LENGTH, mapHttpResponse, mapSessionEvent, modelRefOf } from "./report.js";
2
+ export { candidateFor, listCandidates, mapModelInfo } from "./inventory.js";
3
+ export { sessionOps } from "./session-ops.js";
4
+ export { storageSeam } from "./storage.js";
5
+ export { SESSION_EVENT_TYPES, subscribeSessions } from "./events.js";
6
+ export { registerSessionHooks } from "./hooks.js";
7
+ export { ESCALATION_TOOL_NAME, escalationTool } from "./escalation-tool.js";
8
+ export { tierTool } from "./tier-tool.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/opencode/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAU/F,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA","sourcesContent":["export { BODY_EXCERPT_LENGTH, mapHttpResponse, mapSessionEvent, modelRefOf } from \"./report.js\"\nexport type { SessionEvent } from \"./report.js\"\nexport type {\n AdapterStructuredError,\n EventReport,\n ExecutionReport,\n HttpResponseReport,\n IdleReport,\n ModelRequestReport,\n} from \"./types.js\"\nexport { candidateFor, listCandidates, mapModelInfo } from \"./inventory.js\"\nexport type { ModelSource } from \"./inventory.js\"\nexport { sessionOps } from \"./session-ops.js\"\nexport type { SessionOpsHooks, SessionOpsSource } from \"./session-ops.js\"\nexport { storageSeam } from \"./storage.js\"\nexport type { JsonSeam, StorageSource } from \"./storage.js\"\nexport { SESSION_EVENT_TYPES, subscribeSessions } from \"./events.js\"\nexport type { EventSource, SessionSubscription } from \"./events.js\"\nexport { registerSessionHooks } from \"./hooks.js\"\nexport type { SessionHookHandlers, SessionHookSource } from \"./hooks.js\"\nexport { ESCALATION_TOOL_NAME, escalationTool } from \"./escalation-tool.js\"\nexport { tierTool } from \"./tier-tool.js\"\nexport type { EscalationRecorder } from \"./escalation-tool.js\"\n"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Model inventory mapping (ADP-005/ADP-006/ADP-017). Host `Model.Info` records
3
+ * become supervisor `CandidateModel` views for the compatibility gate.
4
+ *
5
+ * `providerEnabled: true` is honest for `editor.list()` output: the verified
6
+ * host contract is that `list()` returns candidates "from available providers"
7
+ * (including models disabled by earlier transforms — the per-model `enabled`
8
+ * flag distinguishes those). Pins are verified against the same editor via
9
+ * `candidateFor`, which additionally checks variant existence (a variant the
10
+ * model does not offer must not be switchable-to).
11
+ */
12
+ import type { Model } from "@opencode/plugin";
13
+ import type { ModelDomain } from "@opencode/plugin/promise/model";
14
+ import type { CandidateModel } from "../../core/compatibility/types.js";
15
+ import type { ModelRef } from "../../core/work-unit/types.js";
16
+ /** The model surface the inventory actually uses (structural — fixture-friendly). */
17
+ export type ModelSource = Pick<ModelDomain, "transform">;
18
+ /** Map one host model record into a candidate view. */
19
+ export declare function mapModelInfo(info: Model.Info): CandidateModel;
20
+ /** All inventory candidates, in host order. Each offered variant is an
21
+ * additional explicit candidate so tier resources pinned to a variant
22
+ * (`provider/model@variant`) are matchable by the scheduler. */
23
+ export declare function listCandidates(model: ModelSource): Promise<CandidateModel[]>;
24
+ /**
25
+ * Resolve one exact resource reference (a pin) to its candidate, or `undefined`
26
+ * when the model is not in the host inventory or the requested variant does
27
+ * not exist. A resolved variant is reported as available so the compatibility
28
+ * gate does not reject the very resource the user pinned.
29
+ */
30
+ export declare function candidateFor(model: ModelSource, ref: ModelRef): Promise<CandidateModel | undefined>;
@@ -0,0 +1,53 @@
1
+ /** Map one host model record into a candidate view. */
2
+ export function mapModelInfo(info) {
3
+ return {
4
+ providerID: info.providerID,
5
+ modelID: info.id,
6
+ enabled: info.enabled,
7
+ providerEnabled: true,
8
+ capabilities: {
9
+ tools: info.capabilities.tools,
10
+ input: [...info.capabilities.input],
11
+ output: [...info.capabilities.output],
12
+ },
13
+ limit: { context: info.limit.context },
14
+ };
15
+ }
16
+ /** All inventory candidates, in host order. Each offered variant is an
17
+ * additional explicit candidate so tier resources pinned to a variant
18
+ * (`provider/model@variant`) are matchable by the scheduler. */
19
+ export async function listCandidates(model) {
20
+ const out = [];
21
+ await model.transform((editor) => {
22
+ for (const info of editor.list()) {
23
+ out.push(mapModelInfo(info));
24
+ for (const variant of info.variants) {
25
+ out.push({ ...mapModelInfo(info), variant: variant.id, variantAvailable: true });
26
+ }
27
+ }
28
+ });
29
+ return out;
30
+ }
31
+ /**
32
+ * Resolve one exact resource reference (a pin) to its candidate, or `undefined`
33
+ * when the model is not in the host inventory or the requested variant does
34
+ * not exist. A resolved variant is reported as available so the compatibility
35
+ * gate does not reject the very resource the user pinned.
36
+ */
37
+ export async function candidateFor(model, ref) {
38
+ let found;
39
+ await model.transform((editor) => {
40
+ const info = editor.get(ref.providerID, ref.id);
41
+ if (info === undefined) {
42
+ return;
43
+ }
44
+ if (ref.variant !== undefined && !info.variants.some((variant) => variant.id === ref.variant)) {
45
+ return;
46
+ }
47
+ const base = mapModelInfo(info);
48
+ found =
49
+ ref.variant !== undefined ? { ...base, variant: ref.variant, variantAvailable: true } : base;
50
+ });
51
+ return found;
52
+ }
53
+ //# sourceMappingURL=inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inventory.js","sourceRoot":"","sources":["../../../src/adapters/opencode/inventory.ts"],"names":[],"mappings":"AAmBA,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,OAAO,EAAE,IAAI,CAAC,EAAE;QAChB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,eAAe,EAAE,IAAI;QACrB,YAAY,EAAE;YACZ,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK;YAC9B,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YACnC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;SACtC;QACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;KACvC,CAAA;AACH,CAAC;AAED;;gEAEgE;AAChE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAkB;IACrD,MAAM,GAAG,GAAqB,EAAE,CAAA;IAChC,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;QAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;YAC5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACpC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAA;YAClF,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAkB,EAClB,GAAa;IAEb,IAAI,KAAiC,CAAA;IACrC,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QAC/C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAM;QACR,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9F,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QAC/B,KAAK;YACH,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAChG,CAAC,CAAC,CAAA;IACF,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["/**\n * Model inventory mapping (ADP-005/ADP-006/ADP-017). Host `Model.Info` records\n * become supervisor `CandidateModel` views for the compatibility gate.\n *\n * `providerEnabled: true` is honest for `editor.list()` output: the verified\n * host contract is that `list()` returns candidates \"from available providers\"\n * (including models disabled by earlier transforms — the per-model `enabled`\n * flag distinguishes those). Pins are verified against the same editor via\n * `candidateFor`, which additionally checks variant existence (a variant the\n * model does not offer must not be switchable-to).\n */\nimport type { Model } from \"@opencode/plugin\"\nimport type { ModelDomain } from \"@opencode/plugin/promise/model\"\nimport type { CandidateModel } from \"../../core/compatibility/types.js\"\nimport type { ModelRef } from \"../../core/work-unit/types.js\"\n\n/** The model surface the inventory actually uses (structural — fixture-friendly). */\nexport type ModelSource = Pick<ModelDomain, \"transform\">\n\n/** Map one host model record into a candidate view. */\nexport function mapModelInfo(info: Model.Info): CandidateModel {\n return {\n providerID: info.providerID,\n modelID: info.id,\n enabled: info.enabled,\n providerEnabled: true,\n capabilities: {\n tools: info.capabilities.tools,\n input: [...info.capabilities.input],\n output: [...info.capabilities.output],\n },\n limit: { context: info.limit.context },\n }\n}\n\n/** All inventory candidates, in host order. Each offered variant is an\n * additional explicit candidate so tier resources pinned to a variant\n * (`provider/model@variant`) are matchable by the scheduler. */\nexport async function listCandidates(model: ModelSource): Promise<CandidateModel[]> {\n const out: CandidateModel[] = []\n await model.transform((editor) => {\n for (const info of editor.list()) {\n out.push(mapModelInfo(info))\n for (const variant of info.variants) {\n out.push({ ...mapModelInfo(info), variant: variant.id, variantAvailable: true })\n }\n }\n })\n return out\n}\n\n/**\n * Resolve one exact resource reference (a pin) to its candidate, or `undefined`\n * when the model is not in the host inventory or the requested variant does\n * not exist. A resolved variant is reported as available so the compatibility\n * gate does not reject the very resource the user pinned.\n */\nexport async function candidateFor(\n model: ModelSource,\n ref: ModelRef,\n): Promise<CandidateModel | undefined> {\n let found: CandidateModel | undefined\n await model.transform((editor) => {\n const info = editor.get(ref.providerID, ref.id)\n if (info === undefined) {\n return\n }\n if (ref.variant !== undefined && !info.variants.some((variant) => variant.id === ref.variant)) {\n return\n }\n const base = mapModelInfo(info)\n found =\n ref.variant !== undefined ? { ...base, variant: ref.variant, variantAvailable: true } : base\n })\n return found\n}\n"]}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Event/hook → report mappers. Pure observation, no policy: the adapter
3
+ * normalizes verified host payloads into `EventReport` shapes the supervisor
4
+ * consumes. Timestamps come from the host event envelope (`created`, epoch
5
+ * milliseconds) — work units are clock-free.
6
+ */
7
+ import type { Model } from "@opencode/plugin";
8
+ import type { SessionHttpResponse } from "@opencode/plugin/promise/session";
9
+ import type { ModelRef } from "../../core/work-unit/types.js";
10
+ import type { AdapterStructuredError, ExecutionReport, HttpResponseReport, ModelRequestReport } from "./types.js";
11
+ /**
12
+ * Response bodies are bounded here (and bounded again by the classifier) so a
13
+ * hostile provider payload can never inflate memory or receipts. The excerpt
14
+ * is read with a streaming reader and the stream is cancelled once the cap is
15
+ * reached — a multi-megabyte body never materializes in memory.
16
+ */
17
+ export declare const BODY_EXCERPT_LENGTH = 512;
18
+ /** Capture bounds for wiring-selected telemetry headers. */
19
+ export declare const MAX_CAPTURED_HEADERS = 16;
20
+ export declare const MAX_CAPTURED_VALUE_LENGTH = 64;
21
+ /** Convert a host `Model.Ref` into the supervisor's `ModelRef` shape. */
22
+ export declare function modelRefOf(ref: Model.Ref): ModelRef;
23
+ /** Structural session event the mapper accepts (host payloads are assignable). */
24
+ export type SessionEvent = {
25
+ type: "session.execution.started";
26
+ created: number;
27
+ data: {
28
+ sessionID: string;
29
+ };
30
+ } | {
31
+ type: "session.execution.succeeded";
32
+ created: number;
33
+ data: {
34
+ sessionID: string;
35
+ };
36
+ } | {
37
+ type: "session.execution.failed";
38
+ created: number;
39
+ data: {
40
+ sessionID: string;
41
+ error: AdapterStructuredError;
42
+ };
43
+ } | {
44
+ type: "session.execution.interrupted";
45
+ created: number;
46
+ data: {
47
+ sessionID: string;
48
+ reason: string;
49
+ };
50
+ } | {
51
+ type: "session.model.selected";
52
+ created: number;
53
+ data: {
54
+ sessionID: string;
55
+ model: Model.Ref;
56
+ };
57
+ };
58
+ /**
59
+ * Map one subscribed session event into its report. Returns `null` for event
60
+ * types the supervisor does not consume (defensive — the subscription filters
61
+ * types, so this branch only fires if the host ever widens the stream).
62
+ */
63
+ export declare function mapSessionEvent(event: SessionEvent): ExecutionReport | null;
64
+ /** Model request report from the `context` hook — the agent loop is `primary`. */
65
+ export declare function contextModelRequest(input: {
66
+ sessionID: string;
67
+ model: Model.Ref;
68
+ agent?: string;
69
+ }): ModelRequestReport;
70
+ /** Model request report from the `model.request` hook (carries the request kind). */
71
+ export declare function hookModelRequest(input: {
72
+ sessionID: string;
73
+ model: Model.Ref;
74
+ kind: "primary" | "compaction" | "title" | "generate";
75
+ agent?: string;
76
+ }): ModelRequestReport;
77
+ /**
78
+ * Map an `http.response` hook input. The response body is cloned EXACTLY ONCE
79
+ * and only the bounded excerpt of the clone is read — the original body stays
80
+ * untouched for the host (verified one-shot body limitation). If the body
81
+ * cannot be cloned (already consumed, streaming error), the report degrades
82
+ * to status/header evidence.
83
+ *
84
+ * `capture` is an optional allowlist predicate over lowercase header names
85
+ * (quota telemetry only — never `authorization`, cookies, or any other
86
+ * credential-bearing header). Captured entries are bounded in count and value
87
+ * length; capture never throws.
88
+ */
89
+ export declare function mapHttpResponse(input: SessionHttpResponse, options?: {
90
+ capture?: (lowercaseName: string) => boolean;
91
+ }): Promise<HttpResponseReport>;
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Response bodies are bounded here (and bounded again by the classifier) so a
3
+ * hostile provider payload can never inflate memory or receipts. The excerpt
4
+ * is read with a streaming reader and the stream is cancelled once the cap is
5
+ * reached — a multi-megabyte body never materializes in memory.
6
+ */
7
+ export const BODY_EXCERPT_LENGTH = 512;
8
+ /**
9
+ * Reads at most `BODY_EXCERPT_LENGTH` characters from the response body via a
10
+ * streaming reader, cancelling the underlying stream when the cap is reached.
11
+ * Returns `undefined` for missing or empty bodies.
12
+ */
13
+ async function readBodyExcerpt(response) {
14
+ const reader = response.body?.getReader();
15
+ if (reader === undefined)
16
+ return undefined;
17
+ const decoder = new TextDecoder();
18
+ let text = "";
19
+ for (;;) {
20
+ const { done, value } = await reader.read();
21
+ if (done)
22
+ break;
23
+ text += decoder.decode(value, { stream: true });
24
+ if (text.length >= BODY_EXCERPT_LENGTH) {
25
+ // Fire-and-forget: cancellation failure must not fail the observation.
26
+ void reader.cancel().catch(() => undefined);
27
+ break;
28
+ }
29
+ }
30
+ text = text.slice(0, BODY_EXCERPT_LENGTH);
31
+ return text === "" ? undefined : text;
32
+ }
33
+ /** Capture bounds for wiring-selected telemetry headers. */
34
+ export const MAX_CAPTURED_HEADERS = 16;
35
+ export const MAX_CAPTURED_VALUE_LENGTH = 64;
36
+ /** Convert a host `Model.Ref` into the supervisor's `ModelRef` shape. */
37
+ export function modelRefOf(ref) {
38
+ return {
39
+ providerID: ref.providerID,
40
+ id: ref.id,
41
+ ...(ref.variant !== undefined ? { variant: ref.variant } : {}),
42
+ };
43
+ }
44
+ /**
45
+ * Map one subscribed session event into its report. Returns `null` for event
46
+ * types the supervisor does not consume (defensive — the subscription filters
47
+ * types, so this branch only fires if the host ever widens the stream).
48
+ */
49
+ export function mapSessionEvent(event) {
50
+ switch (event.type) {
51
+ case "session.execution.started":
52
+ return { kind: "execution-started", sessionID: event.data.sessionID, at: event.created };
53
+ case "session.execution.succeeded":
54
+ return { kind: "execution-succeeded", sessionID: event.data.sessionID, at: event.created };
55
+ case "session.execution.failed":
56
+ return {
57
+ kind: "execution-failed",
58
+ sessionID: event.data.sessionID,
59
+ at: event.created,
60
+ error: event.data.error,
61
+ };
62
+ case "session.execution.interrupted":
63
+ return {
64
+ kind: "execution-interrupted",
65
+ sessionID: event.data.sessionID,
66
+ at: event.created,
67
+ reason: event.data.reason,
68
+ };
69
+ case "session.model.selected":
70
+ return {
71
+ kind: "model-selected",
72
+ sessionID: event.data.sessionID,
73
+ at: event.created,
74
+ model: modelRefOf(event.data.model),
75
+ };
76
+ default:
77
+ return null;
78
+ }
79
+ }
80
+ /** Model request report from the `context` hook — the agent loop is `primary`. */
81
+ export function contextModelRequest(input) {
82
+ return {
83
+ kind: "model-request",
84
+ sessionID: input.sessionID,
85
+ model: modelRefOf(input.model),
86
+ requestKind: "primary",
87
+ ...(input.agent !== undefined ? { agent: input.agent } : {}),
88
+ };
89
+ }
90
+ /** Model request report from the `model.request` hook (carries the request kind). */
91
+ export function hookModelRequest(input) {
92
+ return {
93
+ kind: "model-request",
94
+ sessionID: input.sessionID,
95
+ model: modelRefOf(input.model),
96
+ requestKind: input.kind,
97
+ ...(input.agent !== undefined ? { agent: input.agent } : {}),
98
+ };
99
+ }
100
+ /**
101
+ * Map an `http.response` hook input. The response body is cloned EXACTLY ONCE
102
+ * and only the bounded excerpt of the clone is read — the original body stays
103
+ * untouched for the host (verified one-shot body limitation). If the body
104
+ * cannot be cloned (already consumed, streaming error), the report degrades
105
+ * to status/header evidence.
106
+ *
107
+ * `capture` is an optional allowlist predicate over lowercase header names
108
+ * (quota telemetry only — never `authorization`, cookies, or any other
109
+ * credential-bearing header). Captured entries are bounded in count and value
110
+ * length; capture never throws.
111
+ */
112
+ export async function mapHttpResponse(input, options) {
113
+ const retryAfterHeader = input.response.headers.get("retry-after");
114
+ let bodyExcerpt;
115
+ try {
116
+ bodyExcerpt = await readBodyExcerpt(input.response.clone());
117
+ }
118
+ catch {
119
+ // Body unreadable — status + headers evidence remains available.
120
+ }
121
+ let capturedHeaders;
122
+ if (options?.capture !== undefined) {
123
+ const captured = {};
124
+ for (const [name, value] of input.response.headers) {
125
+ if (Object.keys(captured).length >= MAX_CAPTURED_HEADERS) {
126
+ break;
127
+ }
128
+ if (options.capture(name.toLowerCase())) {
129
+ captured[name] = value.slice(0, MAX_CAPTURED_VALUE_LENGTH);
130
+ }
131
+ }
132
+ if (Object.keys(captured).length > 0) {
133
+ capturedHeaders = captured;
134
+ }
135
+ }
136
+ return {
137
+ kind: "http-response",
138
+ sessionID: input.sessionID,
139
+ status: input.response.status,
140
+ ...(retryAfterHeader !== null ? { retryAfterHeader } : {}),
141
+ ...(bodyExcerpt !== undefined ? { bodyExcerpt } : {}),
142
+ ...(capturedHeaders !== undefined ? { capturedHeaders } : {}),
143
+ };
144
+ }
145
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/adapters/opencode/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Event/hook → report mappers. Pure observation, no policy: the adapter\n * normalizes verified host payloads into `EventReport` shapes the supervisor\n * consumes. Timestamps come from the host event envelope (`created`, epoch\n * milliseconds) — work units are clock-free.\n */\nimport type { Model } from \"@opencode/plugin\"\nimport type { SessionHttpResponse } from \"@opencode/plugin/promise/session\"\nimport type { ModelRef } from \"../../core/work-unit/types.js\"\nimport type {\n AdapterStructuredError,\n ExecutionReport,\n HttpResponseReport,\n ModelRequestReport,\n} from \"./types.js\"\n\n/**\n * Response bodies are bounded here (and bounded again by the classifier) so a\n * hostile provider payload can never inflate memory or receipts. The excerpt\n * is read with a streaming reader and the stream is cancelled once the cap is\n * reached — a multi-megabyte body never materializes in memory.\n */\nexport const BODY_EXCERPT_LENGTH = 512\n\n/**\n * Reads at most `BODY_EXCERPT_LENGTH` characters from the response body via a\n * streaming reader, cancelling the underlying stream when the cap is reached.\n * Returns `undefined` for missing or empty bodies.\n */\nasync function readBodyExcerpt(response: Response): Promise<string | undefined> {\n const reader = response.body?.getReader()\n if (reader === undefined) return undefined\n const decoder = new TextDecoder()\n let text = \"\"\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n text += decoder.decode(value, { stream: true })\n if (text.length >= BODY_EXCERPT_LENGTH) {\n // Fire-and-forget: cancellation failure must not fail the observation.\n void reader.cancel().catch(() => undefined)\n break\n }\n }\n text = text.slice(0, BODY_EXCERPT_LENGTH)\n return text === \"\" ? undefined : text\n}\n\n/** Capture bounds for wiring-selected telemetry headers. */\nexport const MAX_CAPTURED_HEADERS = 16\nexport const MAX_CAPTURED_VALUE_LENGTH = 64\n\n/** Convert a host `Model.Ref` into the supervisor's `ModelRef` shape. */\nexport function modelRefOf(ref: Model.Ref): ModelRef {\n return {\n providerID: ref.providerID,\n id: ref.id,\n ...(ref.variant !== undefined ? { variant: ref.variant } : {}),\n }\n}\n\n/** Structural session event the mapper accepts (host payloads are assignable). */\nexport type SessionEvent =\n | { type: \"session.execution.started\"; created: number; data: { sessionID: string } }\n | { type: \"session.execution.succeeded\"; created: number; data: { sessionID: string } }\n | {\n type: \"session.execution.failed\"\n created: number\n data: { sessionID: string; error: AdapterStructuredError }\n }\n | {\n type: \"session.execution.interrupted\"\n created: number\n data: { sessionID: string; reason: string }\n }\n | {\n type: \"session.model.selected\"\n created: number\n data: { sessionID: string; model: Model.Ref }\n }\n\n/**\n * Map one subscribed session event into its report. Returns `null` for event\n * types the supervisor does not consume (defensive — the subscription filters\n * types, so this branch only fires if the host ever widens the stream).\n */\nexport function mapSessionEvent(event: SessionEvent): ExecutionReport | null {\n switch (event.type) {\n case \"session.execution.started\":\n return { kind: \"execution-started\", sessionID: event.data.sessionID, at: event.created }\n case \"session.execution.succeeded\":\n return { kind: \"execution-succeeded\", sessionID: event.data.sessionID, at: event.created }\n case \"session.execution.failed\":\n return {\n kind: \"execution-failed\",\n sessionID: event.data.sessionID,\n at: event.created,\n error: event.data.error,\n }\n case \"session.execution.interrupted\":\n return {\n kind: \"execution-interrupted\",\n sessionID: event.data.sessionID,\n at: event.created,\n reason: event.data.reason,\n }\n case \"session.model.selected\":\n return {\n kind: \"model-selected\",\n sessionID: event.data.sessionID,\n at: event.created,\n model: modelRefOf(event.data.model),\n }\n default:\n return null\n }\n}\n\n/** Model request report from the `context` hook — the agent loop is `primary`. */\nexport function contextModelRequest(input: {\n sessionID: string\n model: Model.Ref\n agent?: string\n}): ModelRequestReport {\n return {\n kind: \"model-request\",\n sessionID: input.sessionID,\n model: modelRefOf(input.model),\n requestKind: \"primary\",\n ...(input.agent !== undefined ? { agent: input.agent } : {}),\n }\n}\n\n/** Model request report from the `model.request` hook (carries the request kind). */\nexport function hookModelRequest(input: {\n sessionID: string\n model: Model.Ref\n kind: \"primary\" | \"compaction\" | \"title\" | \"generate\"\n agent?: string\n}): ModelRequestReport {\n return {\n kind: \"model-request\",\n sessionID: input.sessionID,\n model: modelRefOf(input.model),\n requestKind: input.kind,\n ...(input.agent !== undefined ? { agent: input.agent } : {}),\n }\n}\n\n/**\n * Map an `http.response` hook input. The response body is cloned EXACTLY ONCE\n * and only the bounded excerpt of the clone is read — the original body stays\n * untouched for the host (verified one-shot body limitation). If the body\n * cannot be cloned (already consumed, streaming error), the report degrades\n * to status/header evidence.\n *\n * `capture` is an optional allowlist predicate over lowercase header names\n * (quota telemetry only — never `authorization`, cookies, or any other\n * credential-bearing header). Captured entries are bounded in count and value\n * length; capture never throws.\n */\nexport async function mapHttpResponse(\n input: SessionHttpResponse,\n options?: { capture?: (lowercaseName: string) => boolean },\n): Promise<HttpResponseReport> {\n const retryAfterHeader = input.response.headers.get(\"retry-after\")\n let bodyExcerpt: string | undefined\n try {\n bodyExcerpt = await readBodyExcerpt(input.response.clone())\n } catch {\n // Body unreadable — status + headers evidence remains available.\n }\n let capturedHeaders: Record<string, string> | undefined\n if (options?.capture !== undefined) {\n const captured: Record<string, string> = {}\n for (const [name, value] of input.response.headers) {\n if (Object.keys(captured).length >= MAX_CAPTURED_HEADERS) {\n break\n }\n if (options.capture(name.toLowerCase())) {\n captured[name] = value.slice(0, MAX_CAPTURED_VALUE_LENGTH)\n }\n }\n if (Object.keys(captured).length > 0) {\n capturedHeaders = captured\n }\n }\n return {\n kind: \"http-response\",\n sessionID: input.sessionID,\n status: input.response.status,\n ...(retryAfterHeader !== null ? { retryAfterHeader } : {}),\n ...(bodyExcerpt !== undefined ? { bodyExcerpt } : {}),\n ...(capturedHeaders !== undefined ? { capturedHeaders } : {}),\n }\n}\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Session operations seam (ADP-013/ADP-014/ADP-023/ADP-028). Implements the
3
+ * supervisor's `ContinuationOps` on the host session domain: settle on the
4
+ * host's experimental wait, switch model, deliver a prompt. Never replays a
5
+ * failed request — prompting after a failure starts a NEW execution that
6
+ * continues from session state (prompt strategy chosen by the supervisor).
7
+ *
8
+ * Switch self-tagging (verified limitation: `session.model.selected` fires for
9
+ * manual AND plugin switches): `beforeSwitch` is invoked BEFORE the host
10
+ * switch so the supervisor can record its own pending attribution note; the
11
+ * resulting selection event is then attributed to Adaptive, never to the user.
12
+ */
13
+ import type { SessionDomain } from "@opencode/plugin/promise/session";
14
+ /** The session surface the ops actually use (structural — fixture-friendly). */
15
+ export type SessionOpsSource = Pick<SessionDomain, "wait" | "switchModel" | "prompt">;
16
+ import type { ContinuationOps } from "../../execution/continuation/types.js";
17
+ import type { ModelRef } from "../../core/work-unit/types.js";
18
+ export interface SessionOpsHooks {
19
+ /**
20
+ * Called before every host `switchModel` this adapter performs, so wiring
21
+ * can tag the switch as Adaptive's own (`noteOwnSwitch`).
22
+ */
23
+ readonly beforeSwitch?: (sessionID: string, model: ModelRef) => void;
24
+ /**
25
+ * Called before the adapter prompts a continuation, so wiring can mark the
26
+ * upcoming prompt-hook admission as owned (the continuation belongs to the
27
+ * active unit and must not re-admit).
28
+ */
29
+ readonly beforePrompt?: (sessionID: string) => void;
30
+ /**
31
+ * Called when the prompted call settles (success or failure), whether or
32
+ * not the prompt hook fired — the counterpart that bounds the ownership
33
+ * mark's lifetime. `delivered` is false exactly when the host prompt
34
+ * rejected, so the hook can never fire for it.
35
+ */
36
+ readonly afterPrompt?: (sessionID: string, delivered: boolean) => void;
37
+ }
38
+ /** Build the supervisor's continuation ops on top of the host session domain. */
39
+ export declare function sessionOps(session: SessionOpsSource, hooks?: SessionOpsHooks): ContinuationOps;