@skaile/workspaces 5.1.3 → 5.3.0

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 (379) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +1 -1
  3. package/dist/app-sdk/index.js +1 -1
  4. package/dist/{asset-feeds-C4X4RTZV.js → asset-feeds-VIZXYDAO.js} +13 -13
  5. package/dist/{asset-feeds-C4X4RTZV.js.map → asset-feeds-VIZXYDAO.js.map} +1 -1
  6. package/dist/asset-manager/catalog-deployer.js +10 -10
  7. package/dist/asset-manager/index.js +14 -14
  8. package/dist/asset-manager/installer.js +10 -10
  9. package/dist/asset-manager/src/index.d.ts +39 -4
  10. package/dist/asset-manager/src/index.d.ts.map +1 -1
  11. package/dist/asset-manager/src/installer.d.ts +2 -1
  12. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  13. package/dist/bridge/drivers/claude-sdk.js +16 -15
  14. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  15. package/dist/bridge/drivers/codex.js +13 -12
  16. package/dist/bridge/drivers/codex.js.map +1 -1
  17. package/dist/bridge/drivers/continue.js +13 -13
  18. package/dist/bridge/drivers/echo.js +3 -3
  19. package/dist/bridge/drivers/gemini.js +5 -5
  20. package/dist/bridge/drivers/goose.js +13 -13
  21. package/dist/bridge/drivers/omp.js +6 -5
  22. package/dist/bridge/drivers/omp.js.map +1 -1
  23. package/dist/bridge/drivers/opencode.js +13 -13
  24. package/dist/bridge/drivers/qwen.js +5 -5
  25. package/dist/bridge/index.js +15 -15
  26. package/dist/bridge/src/driver-capabilities.d.ts +66 -0
  27. package/dist/bridge/src/driver-capabilities.d.ts.map +1 -0
  28. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  29. package/dist/bridge/src/drivers/codex.d.ts.map +1 -1
  30. package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
  31. package/dist/bridge/src/index.d.ts +1 -0
  32. package/dist/bridge/src/index.d.ts.map +1 -1
  33. package/dist/bridge/src/registry.d.ts.map +1 -1
  34. package/dist/{chunk-7SAWDPUT.js → chunk-37GBJLF5.js} +5 -55
  35. package/dist/chunk-37GBJLF5.js.map +1 -0
  36. package/dist/{chunk-SP47UJKE.js → chunk-3ZVSINEV.js} +247 -118
  37. package/dist/chunk-3ZVSINEV.js.map +1 -0
  38. package/dist/{chunk-ZVKJNNME.js → chunk-4257Q2LH.js} +8 -8
  39. package/dist/{chunk-ZVKJNNME.js.map → chunk-4257Q2LH.js.map} +1 -1
  40. package/dist/{chunk-YDJZRLGN.js → chunk-4SSKKFDF.js} +4 -4
  41. package/dist/{chunk-YDJZRLGN.js.map → chunk-4SSKKFDF.js.map} +1 -1
  42. package/dist/{chunk-K5GBV4SA.js → chunk-5BEFNLOR.js} +6 -5
  43. package/dist/chunk-5BEFNLOR.js.map +1 -0
  44. package/dist/{chunk-IWCCZL7C.js → chunk-6GBQND2F.js} +99 -36
  45. package/dist/chunk-6GBQND2F.js.map +1 -0
  46. package/dist/{chunk-QU4J5YSJ.js → chunk-7L4WFH3Y.js} +4 -4
  47. package/dist/{chunk-QU4J5YSJ.js.map → chunk-7L4WFH3Y.js.map} +1 -1
  48. package/dist/{chunk-O4U7OL6D.js → chunk-A223FDDC.js} +6 -6
  49. package/dist/{chunk-O4U7OL6D.js.map → chunk-A223FDDC.js.map} +1 -1
  50. package/dist/{chunk-AZYIEK3F.js → chunk-AWGQVAC5.js} +3 -3
  51. package/dist/{chunk-AZYIEK3F.js.map → chunk-AWGQVAC5.js.map} +1 -1
  52. package/dist/{chunk-RDYI4MML.js → chunk-BNUZEYC3.js} +3 -3
  53. package/dist/{chunk-RDYI4MML.js.map → chunk-BNUZEYC3.js.map} +1 -1
  54. package/dist/{chunk-RNNUYFFD.js → chunk-BUZ3K2PT.js} +3 -3
  55. package/dist/{chunk-RNNUYFFD.js.map → chunk-BUZ3K2PT.js.map} +1 -1
  56. package/dist/{chunk-WKIOWDLQ.js → chunk-CZ35I4RK.js} +4 -4
  57. package/dist/{chunk-WKIOWDLQ.js.map → chunk-CZ35I4RK.js.map} +1 -1
  58. package/dist/{chunk-KWP4RVTJ.js → chunk-D63AJVBW.js} +761 -643
  59. package/dist/chunk-D63AJVBW.js.map +1 -0
  60. package/dist/{chunk-BJZHNSQO.js → chunk-DECPI7DN.js} +5 -5
  61. package/dist/{chunk-BJZHNSQO.js.map → chunk-DECPI7DN.js.map} +1 -1
  62. package/dist/{chunk-KVAI5DGL.js → chunk-ERCSHLTF.js} +3 -3
  63. package/dist/{chunk-KVAI5DGL.js.map → chunk-ERCSHLTF.js.map} +1 -1
  64. package/dist/{chunk-ZD7CX25M.js → chunk-FTYM4VRZ.js} +56 -7
  65. package/dist/chunk-FTYM4VRZ.js.map +1 -0
  66. package/dist/{chunk-DLLM4U6C.js → chunk-FXN4PLRO.js} +3 -3
  67. package/dist/{chunk-DLLM4U6C.js.map → chunk-FXN4PLRO.js.map} +1 -1
  68. package/dist/{chunk-KNC55536.js → chunk-FZGL7Z52.js} +5 -4
  69. package/dist/chunk-FZGL7Z52.js.map +1 -0
  70. package/dist/{chunk-WCQMXBO5.js → chunk-GCYD4EGY.js} +4 -4
  71. package/dist/{chunk-WCQMXBO5.js.map → chunk-GCYD4EGY.js.map} +1 -1
  72. package/dist/{chunk-EB6OPURC.js → chunk-HTKZ4AOW.js} +3 -3
  73. package/dist/{chunk-EB6OPURC.js.map → chunk-HTKZ4AOW.js.map} +1 -1
  74. package/dist/{chunk-YV4J7V53.js → chunk-JAJG4G5E.js} +3 -3
  75. package/dist/{chunk-YV4J7V53.js.map → chunk-JAJG4G5E.js.map} +1 -1
  76. package/dist/{chunk-TYUJB336.js → chunk-JELTQ4H7.js} +3 -3
  77. package/dist/{chunk-TYUJB336.js.map → chunk-JELTQ4H7.js.map} +1 -1
  78. package/dist/{chunk-VDJKWKH2.js → chunk-JKWU6ULI.js} +3 -3
  79. package/dist/{chunk-VDJKWKH2.js.map → chunk-JKWU6ULI.js.map} +1 -1
  80. package/dist/{chunk-AGWYBS2E.js → chunk-K2JVODQD.js} +18 -6
  81. package/dist/chunk-K2JVODQD.js.map +1 -0
  82. package/dist/{chunk-IDEA6CYI.js → chunk-K2K7OF4P.js} +95 -3
  83. package/dist/chunk-K2K7OF4P.js.map +1 -0
  84. package/dist/{chunk-MXXKTQXJ.js → chunk-KBAE7PU7.js} +18 -33
  85. package/dist/chunk-KBAE7PU7.js.map +1 -0
  86. package/dist/{chunk-ARUJBGAH.js → chunk-KXTO7HON.js} +3 -3
  87. package/dist/{chunk-ARUJBGAH.js.map → chunk-KXTO7HON.js.map} +1 -1
  88. package/dist/{chunk-TVOODIZE.js → chunk-LAI7X6I2.js} +3 -3
  89. package/dist/{chunk-TVOODIZE.js.map → chunk-LAI7X6I2.js.map} +1 -1
  90. package/dist/{chunk-DXUQCMVT.js → chunk-LFMX2UEF.js} +3 -3
  91. package/dist/{chunk-DXUQCMVT.js.map → chunk-LFMX2UEF.js.map} +1 -1
  92. package/dist/{chunk-UMSWQKCY.js → chunk-LM5XEFNS.js} +3 -3
  93. package/dist/{chunk-UMSWQKCY.js.map → chunk-LM5XEFNS.js.map} +1 -1
  94. package/dist/{chunk-TLKM4M47.js → chunk-MFHKHXDE.js} +6 -3
  95. package/dist/chunk-MFHKHXDE.js.map +1 -0
  96. package/dist/{chunk-5S4ZK75K.js → chunk-OMD4TAJX.js} +3 -3
  97. package/dist/{chunk-5S4ZK75K.js.map → chunk-OMD4TAJX.js.map} +1 -1
  98. package/dist/{chunk-M4ISBWXR.js → chunk-OOKFZW6H.js} +2472 -2265
  99. package/dist/chunk-OOKFZW6H.js.map +1 -0
  100. package/dist/{chunk-WPWJRDR3.js → chunk-QHIMMBJO.js} +8 -7
  101. package/dist/chunk-QHIMMBJO.js.map +1 -0
  102. package/dist/{chunk-KC3OF6B2.js → chunk-QMWMSZQ4.js} +3 -3
  103. package/dist/{chunk-KC3OF6B2.js.map → chunk-QMWMSZQ4.js.map} +1 -1
  104. package/dist/{chunk-AG44ZJ7W.js → chunk-SR4RFKHM.js} +35 -13
  105. package/dist/chunk-SR4RFKHM.js.map +1 -0
  106. package/dist/{chunk-RNOIDD3Y.js → chunk-TR7KFBIO.js} +7 -7
  107. package/dist/chunk-TR7KFBIO.js.map +1 -0
  108. package/dist/{chunk-YMOZC2D3.js → chunk-TVFSA5IQ.js} +4 -4
  109. package/dist/{chunk-YMOZC2D3.js.map → chunk-TVFSA5IQ.js.map} +1 -1
  110. package/dist/{chunk-H4EGUQ7M.js → chunk-VKSA2CDJ.js} +7 -8
  111. package/dist/chunk-VKSA2CDJ.js.map +1 -0
  112. package/dist/{chunk-I75CM2QF.js → chunk-VLEWVR44.js} +14 -15
  113. package/dist/chunk-VLEWVR44.js.map +1 -0
  114. package/dist/{chunk-RO4Z2CBP.js → chunk-WGN7Z36G.js} +21 -4
  115. package/dist/chunk-WGN7Z36G.js.map +1 -0
  116. package/dist/{chunk-BEOKEK3B.js → chunk-WGNFDLHT.js} +135 -64
  117. package/dist/chunk-WGNFDLHT.js.map +1 -0
  118. package/dist/{chunk-43ZBF3WH.js → chunk-WX74MVNA.js} +16 -3
  119. package/dist/chunk-WX74MVNA.js.map +1 -0
  120. package/dist/{chunk-U6K3I3AX.js → chunk-XGIS325V.js} +3 -3
  121. package/dist/{chunk-U6K3I3AX.js.map → chunk-XGIS325V.js.map} +1 -1
  122. package/dist/{chunk-UVOJSWD2.js → chunk-Y7UBRRKG.js} +107 -135
  123. package/dist/chunk-Y7UBRRKG.js.map +1 -0
  124. package/dist/{chunk-Y6V6NUEV.js → chunk-YTJZQ4HY.js} +3 -3
  125. package/dist/{chunk-Y6V6NUEV.js.map → chunk-YTJZQ4HY.js.map} +1 -1
  126. package/dist/{chunk-IAGCOAIW.js → chunk-YXNYBUQY.js} +5 -5
  127. package/dist/{chunk-IAGCOAIW.js.map → chunk-YXNYBUQY.js.map} +1 -1
  128. package/dist/chunk-ZCSFGGLG.js +15 -0
  129. package/dist/{chunk-XUQBVK4R.js.map → chunk-ZCSFGGLG.js.map} +1 -1
  130. package/dist/{chunk-2HR3RPWD.js → chunk-ZDMGMWK6.js} +13 -11
  131. package/dist/chunk-ZDMGMWK6.js.map +1 -0
  132. package/dist/cli/index.js +696 -552
  133. package/dist/cli/index.js.map +1 -1
  134. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  135. package/dist/cli/src/commands/catalog-cmd.d.ts.map +1 -1
  136. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  137. package/dist/cli/src/commands/config.d.ts.map +1 -1
  138. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  139. package/dist/cli/src/commands/library-index.d.ts +43 -1
  140. package/dist/cli/src/commands/library-index.d.ts.map +1 -1
  141. package/dist/cli/src/commands/library-publish.d.ts.map +1 -1
  142. package/dist/cli/src/commands/outdated.d.ts +3 -1
  143. package/dist/cli/src/commands/outdated.d.ts.map +1 -1
  144. package/dist/cli/src/commands/project.d.ts.map +1 -1
  145. package/dist/cli/src/commands/run.d.ts.map +1 -1
  146. package/dist/cli/src/commands/skailify-lib.d.ts +3 -47
  147. package/dist/cli/src/commands/skailify-lib.d.ts.map +1 -1
  148. package/dist/cli/src/commands/source.d.ts.map +1 -1
  149. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  150. package/dist/cli/src/flow-discovery.d.ts +9 -0
  151. package/dist/cli/src/flow-discovery.d.ts.map +1 -1
  152. package/dist/cli/src/helpers.d.ts +13 -0
  153. package/dist/cli/src/helpers.d.ts.map +1 -1
  154. package/dist/cli/src/setup.d.ts.map +1 -1
  155. package/dist/connectors/config.js +6 -6
  156. package/dist/connectors/index.js +19 -19
  157. package/dist/connectors/src/connector-manager.d.ts +8 -27
  158. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  159. package/dist/connectors/src/index.d.ts +1 -1
  160. package/dist/connectors/src/index.d.ts.map +1 -1
  161. package/dist/connectors/src/mount-ledger.d.ts +61 -0
  162. package/dist/connectors/src/mount-ledger.d.ts.map +1 -0
  163. package/dist/{connectors-BQXFKISC.js → connectors-Z2FUGAJU.js} +22 -22
  164. package/dist/{connectors-BQXFKISC.js.map → connectors-Z2FUGAJU.js.map} +1 -1
  165. package/dist/connectors-shared/index.js +2 -2
  166. package/dist/core/framework.js +1 -1
  167. package/dist/core/index.js +9 -9
  168. package/dist/core/manifest.js +2 -2
  169. package/dist/core/models.js +1 -1
  170. package/dist/core/publish-manifest.js +2 -2
  171. package/dist/core/ref.js +1 -1
  172. package/dist/core/runtime-assets.js +6 -6
  173. package/dist/core/src/asset-roots.d.ts +8 -0
  174. package/dist/core/src/asset-roots.d.ts.map +1 -1
  175. package/dist/core/src/cache-paths.d.ts +6 -0
  176. package/dist/core/src/cache-paths.d.ts.map +1 -1
  177. package/dist/core/src/framework.d.ts +7 -0
  178. package/dist/core/src/framework.d.ts.map +1 -1
  179. package/dist/core/src/index.d.ts +6 -6
  180. package/dist/core/src/index.d.ts.map +1 -1
  181. package/dist/core/src/lock.d.ts +12 -0
  182. package/dist/core/src/lock.d.ts.map +1 -1
  183. package/dist/core/src/manifest-yaml-editor.d.ts +14 -6
  184. package/dist/core/src/manifest-yaml-editor.d.ts.map +1 -1
  185. package/dist/core/src/models.d.ts +22 -0
  186. package/dist/core/src/models.d.ts.map +1 -1
  187. package/dist/core/src/publish-manifest.d.ts +28 -6
  188. package/dist/core/src/publish-manifest.d.ts.map +1 -1
  189. package/dist/core/src/settings.d.ts.map +1 -1
  190. package/dist/core/src/walker.d.ts.map +1 -1
  191. package/dist/core/store.js +2 -2
  192. package/dist/core/workspace-config.js +5 -5
  193. package/dist/deploy/index.js +9 -9
  194. package/dist/discovery/index.js +4 -4
  195. package/dist/discovery/src/discover-manifest.d.ts +5 -0
  196. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  197. package/dist/discovery/src/discover.d.ts.map +1 -1
  198. package/dist/discovery/src/hash.d.ts +45 -23
  199. package/dist/discovery/src/hash.d.ts.map +1 -1
  200. package/dist/discovery/src/index.d.ts +3 -1
  201. package/dist/discovery/src/index.d.ts.map +1 -1
  202. package/dist/discovery/src/parse-manifest.d.ts +27 -0
  203. package/dist/discovery/src/parse-manifest.d.ts.map +1 -0
  204. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  205. package/dist/{ensure-sources-CMHOTYFS.js → ensure-sources-3IH5XHAP.js} +17 -17
  206. package/dist/{ensure-sources-CMHOTYFS.js.map → ensure-sources-3IH5XHAP.js.map} +1 -1
  207. package/dist/factory-assets/connectors/box.js +19 -19
  208. package/dist/factory-assets/connectors/deploy.js +19 -19
  209. package/dist/factory-assets/connectors/devserver.js +19 -19
  210. package/dist/factory-assets/connectors/flow/adapter.d.ts +28 -4
  211. package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
  212. package/dist/factory-assets/connectors/flow/adapter.js +19 -19
  213. package/dist/factory-assets/connectors/flow/engine.js +10 -10
  214. package/dist/factory-assets/connectors/flow/index.d.ts +1 -1
  215. package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
  216. package/dist/factory-assets/connectors/flow/run-flow.js +21 -21
  217. package/dist/factory-assets/connectors/flow.js +19 -19
  218. package/dist/factory-assets/connectors/git/checkout.d.ts +161 -0
  219. package/dist/factory-assets/connectors/git/checkout.d.ts.map +1 -0
  220. package/dist/factory-assets/connectors/git/config.d.ts +78 -0
  221. package/dist/factory-assets/connectors/git/config.d.ts.map +1 -0
  222. package/dist/factory-assets/connectors/git/credentials.d.ts +93 -0
  223. package/dist/factory-assets/connectors/git/credentials.d.ts.map +1 -0
  224. package/dist/factory-assets/connectors/git/driver.d.ts +39 -598
  225. package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
  226. package/dist/factory-assets/connectors/git/exec.d.ts +177 -0
  227. package/dist/factory-assets/connectors/git/exec.d.ts.map +1 -0
  228. package/dist/factory-assets/connectors/git/inspect.d.ts +120 -0
  229. package/dist/factory-assets/connectors/git/inspect.d.ts.map +1 -0
  230. package/dist/factory-assets/connectors/git/lifecycle.d.ts +107 -0
  231. package/dist/factory-assets/connectors/git/lifecycle.d.ts.map +1 -0
  232. package/dist/factory-assets/connectors/git/repo.d.ts +496 -0
  233. package/dist/factory-assets/connectors/git/repo.d.ts.map +1 -0
  234. package/dist/factory-assets/connectors/git.js +19 -19
  235. package/dist/factory-assets/connectors/gmail.js +19 -19
  236. package/dist/factory-assets/connectors/googledrive.js +19 -19
  237. package/dist/factory-assets/connectors/local.js +19 -19
  238. package/dist/factory-assets/connectors/mattermost.js +19 -19
  239. package/dist/factory-assets/connectors/memory.js +19 -19
  240. package/dist/factory-assets/connectors/minio.js +19 -19
  241. package/dist/factory-assets/connectors/postgres.js +19 -19
  242. package/dist/factory-assets/connectors/s3.js +19 -19
  243. package/dist/factory-assets/connectors/sharepoint.js +19 -19
  244. package/dist/factory-assets/connectors/sqlite.js +19 -19
  245. package/dist/factory-assets/connectors/static-server.js +19 -19
  246. package/dist/factory-assets/connectors/tunnel.js +19 -19
  247. package/dist/factory-assets/connectors/webdav.js +19 -19
  248. package/dist/factory-assets/connectors/xstate-store.js +19 -19
  249. package/dist/factory-assets/connectors/xstate.js +19 -19
  250. package/dist/flows-64OAOYLP.js +26 -0
  251. package/dist/{flows-SVCCADGE.js.map → flows-64OAOYLP.js.map} +1 -1
  252. package/dist/{helpers-R3GLTAER.js → helpers-HV5Y57CY.js} +17 -17
  253. package/dist/{helpers-R3GLTAER.js.map → helpers-HV5Y57CY.js.map} +1 -1
  254. package/dist/library/index.js +12 -12
  255. package/dist/library/install.js +3 -2
  256. package/dist/library/src/config.d.ts +5 -4
  257. package/dist/library/src/config.d.ts.map +1 -1
  258. package/dist/library/src/index.d.ts +6 -3
  259. package/dist/library/src/index.d.ts.map +1 -1
  260. package/dist/library/src/install/install-from-manifest.d.ts +21 -0
  261. package/dist/library/src/install/install-from-manifest.d.ts.map +1 -1
  262. package/dist/library/src/local/install-library-asset.d.ts +64 -0
  263. package/dist/library/src/local/install-library-asset.d.ts.map +1 -0
  264. package/dist/library/src/local/library.d.ts.map +1 -1
  265. package/dist/library/src/local/local-catalog-source.d.ts +30 -0
  266. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  267. package/dist/library/src/local/store-paths.d.ts +6 -0
  268. package/dist/library/src/local/store-paths.d.ts.map +1 -1
  269. package/dist/library/src/manifest-writer.d.ts +79 -0
  270. package/dist/library/src/manifest-writer.d.ts.map +1 -0
  271. package/dist/library/src/sync/git-driver.d.ts +8 -0
  272. package/dist/library/src/sync/git-driver.d.ts.map +1 -1
  273. package/dist/library/src/sync/manifest-writeback.d.ts +2 -17
  274. package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
  275. package/dist/{library-publish-EL7VYICU.js → library-publish-TVS3WQ4C.js} +27 -25
  276. package/dist/library-publish-TVS3WQ4C.js.map +1 -0
  277. package/dist/{open-library-MTD34YX3.js → open-library-AT6RYQ5M.js} +20 -20
  278. package/dist/{open-library-MTD34YX3.js.map → open-library-AT6RYQ5M.js.map} +1 -1
  279. package/dist/open-registry-F2Z4OLXJ.js +32 -0
  280. package/dist/{open-registry-CHCWKV5W.js.map → open-registry-F2Z4OLXJ.js.map} +1 -1
  281. package/dist/paths-P7ZXMDCX.js +22 -0
  282. package/dist/{paths-MKSI52PF.js.map → paths-P7ZXMDCX.js.map} +1 -1
  283. package/dist/plugin-registry/src/targets.d.ts +3 -1
  284. package/dist/plugin-registry/src/targets.d.ts.map +1 -1
  285. package/dist/{plugin-store-SVYV7L4C.js → plugin-store-27KGLW4S.js} +11 -11
  286. package/dist/{plugin-store-SVYV7L4C.js.map → plugin-store-27KGLW4S.js.map} +1 -1
  287. package/dist/{project-HCNWJP7J.js → project-J2EROMBW.js} +18 -18
  288. package/dist/{project-HCNWJP7J.js.map → project-J2EROMBW.js.map} +1 -1
  289. package/dist/resolver/index.js +10 -10
  290. package/dist/runner/index.js +29 -29
  291. package/dist/runner/src/agent.d.ts +1 -1
  292. package/dist/runner/src/agent.d.ts.map +1 -1
  293. package/dist/runner/src/codex-init.d.ts.map +1 -1
  294. package/dist/runner/src/compaction-gate.d.ts +9 -33
  295. package/dist/runner/src/compaction-gate.d.ts.map +1 -1
  296. package/dist/runner/src/managed-codex-bootstrap.d.ts.map +1 -1
  297. package/dist/runner/src/pending-turns.d.ts +7 -2
  298. package/dist/runner/src/pending-turns.d.ts.map +1 -1
  299. package/dist/runner/src/resources.d.ts +2 -2
  300. package/dist/runner/src/resources.d.ts.map +1 -1
  301. package/dist/runner/src/serve-credentials.d.ts +2 -1
  302. package/dist/runner/src/serve-credentials.d.ts.map +1 -1
  303. package/dist/runner/src/serve.d.ts +19 -35
  304. package/dist/runner/src/serve.d.ts.map +1 -1
  305. package/dist/runner/src/session-builder.d.ts.map +1 -1
  306. package/dist/runner/src/turn-scheduler.d.ts +158 -0
  307. package/dist/runner/src/turn-scheduler.d.ts.map +1 -0
  308. package/dist/sdk/asset-manager.js +14 -14
  309. package/dist/sdk/bridge.js +15 -15
  310. package/dist/sdk/core.js +9 -9
  311. package/dist/sdk/flow.js +10 -10
  312. package/dist/sdk/index.js +29 -29
  313. package/dist/sdk/resolver.js +10 -10
  314. package/dist/sdk/runner.js +29 -29
  315. package/dist/sdk/session.js +2 -2
  316. package/dist/sdk/types.js +1 -1
  317. package/dist/secrets/index.js +2 -2
  318. package/dist/session/index.js +2 -2
  319. package/dist/session/src/dispatcher.d.ts.map +1 -1
  320. package/dist/{setup-HTXNR2CZ.js → setup-IFGA4NQA.js} +25 -25
  321. package/dist/setup-IFGA4NQA.js.map +1 -0
  322. package/dist/skills-3T55L4YT.js +26 -0
  323. package/dist/{skills-7K2YO3KN.js.map → skills-3T55L4YT.js.map} +1 -1
  324. package/dist/{source-UIFC2PFC.js → source-HEAE43IL.js} +21 -21
  325. package/dist/{source-UIFC2PFC.js.map → source-HEAE43IL.js.map} +1 -1
  326. package/dist/{source-manifest-publish-QKAKXDVH.js → source-manifest-publish-SCAHAYSQ.js} +23 -23
  327. package/dist/{source-manifest-publish-QKAKXDVH.js.map → source-manifest-publish-SCAHAYSQ.js.map} +1 -1
  328. package/dist/tui/index.js +30 -30
  329. package/dist/tui/index.js.map +1 -1
  330. package/dist/types/index.js +1 -1
  331. package/dist/types/src/delivery.d.ts +26 -0
  332. package/dist/types/src/delivery.d.ts.map +1 -0
  333. package/dist/types/src/index.d.ts +3 -1
  334. package/dist/types/src/index.d.ts.map +1 -1
  335. package/dist/types/src/runtime.d.ts +51 -0
  336. package/dist/types/src/runtime.d.ts.map +1 -1
  337. package/dist/workspace-plugin/adapters/mcp.js +26 -26
  338. package/dist/workspace-plugin/adapters/omp.js +18 -17
  339. package/dist/workspace-plugin/adapters/omp.js.map +1 -1
  340. package/dist/workspace-plugin/index.js +2 -1
  341. package/dist/workspace-plugin/src/adapters/mcp.d.ts.map +1 -1
  342. package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -1
  343. package/dist/workspace-plugin/src/plugin.d.ts.map +1 -1
  344. package/package.json +1 -1
  345. package/dist/chunk-2HR3RPWD.js.map +0 -1
  346. package/dist/chunk-43ZBF3WH.js.map +0 -1
  347. package/dist/chunk-7SAWDPUT.js.map +0 -1
  348. package/dist/chunk-AG44ZJ7W.js.map +0 -1
  349. package/dist/chunk-AGWYBS2E.js.map +0 -1
  350. package/dist/chunk-BEOKEK3B.js.map +0 -1
  351. package/dist/chunk-F7JHP7JV.js +0 -122
  352. package/dist/chunk-F7JHP7JV.js.map +0 -1
  353. package/dist/chunk-H4EGUQ7M.js.map +0 -1
  354. package/dist/chunk-I75CM2QF.js.map +0 -1
  355. package/dist/chunk-IDEA6CYI.js.map +0 -1
  356. package/dist/chunk-IWCCZL7C.js.map +0 -1
  357. package/dist/chunk-K5GBV4SA.js.map +0 -1
  358. package/dist/chunk-KNC55536.js.map +0 -1
  359. package/dist/chunk-KWP4RVTJ.js.map +0 -1
  360. package/dist/chunk-M4ISBWXR.js.map +0 -1
  361. package/dist/chunk-MXXKTQXJ.js.map +0 -1
  362. package/dist/chunk-RNOIDD3Y.js.map +0 -1
  363. package/dist/chunk-RO4Z2CBP.js.map +0 -1
  364. package/dist/chunk-SP47UJKE.js.map +0 -1
  365. package/dist/chunk-TLKM4M47.js.map +0 -1
  366. package/dist/chunk-UVOJSWD2.js.map +0 -1
  367. package/dist/chunk-WPWJRDR3.js.map +0 -1
  368. package/dist/chunk-XUQBVK4R.js +0 -15
  369. package/dist/chunk-ZD7CX25M.js.map +0 -1
  370. package/dist/flows-SVCCADGE.js +0 -26
  371. package/dist/library-publish-EL7VYICU.js.map +0 -1
  372. package/dist/open-registry-CHCWKV5W.js +0 -32
  373. package/dist/paths-MKSI52PF.js +0 -22
  374. package/dist/runner/src/flow-turn-dispatch.d.ts +0 -41
  375. package/dist/runner/src/flow-turn-dispatch.d.ts.map +0 -1
  376. package/dist/runner/src/reply-routing.d.ts +0 -54
  377. package/dist/runner/src/reply-routing.d.ts.map +0 -1
  378. package/dist/setup-HTXNR2CZ.js.map +0 -1
  379. package/dist/skills-7K2YO3KN.js +0 -26
@@ -1,32 +1,32 @@
1
- import { WorkspacePlugin } from './chunk-KNC55536.js';
2
- import { buildWorkspaceToolDefs } from './chunk-WPWJRDR3.js';
3
- import { findAiAssetsRoot } from './chunk-TYUJB336.js';
1
+ import { WorkspacePlugin } from './chunk-FZGL7Z52.js';
2
+ import { buildWorkspaceToolDefs } from './chunk-QHIMMBJO.js';
3
+ import { findAiAssetsRoot } from './chunk-JELTQ4H7.js';
4
4
  import { WebSocketServerTransport } from './chunk-5LKOAX7I.js';
5
5
  import { assembleSystemPrompt, buildCapabilitiesPromptSection } from './chunk-W3UDISS2.js';
6
6
  import { prepareNativePolicy, codexInstanceEnvironment, parseCodexCredential, parseCodexRefreshInput, parseCodexRefreshResult } from './chunk-HCYS7GFP.js';
7
- import { resolveFlowPath } from './chunk-ZVKJNNME.js';
8
- import { findAiAssetsRoot as findAiAssetsRoot$1, deployCatalogEntry, undeployCatalogEntry } from './chunk-VDJKWKH2.js';
9
- import { ConnectFailureCarryOver, registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, buildSdkConnectorTools, buildLazySdkFlowTools, describeFlowOperations, buildConnectorToolDefs, buildFlowToolDefs, SessionNodeExecutor, SessionSubpromptRunner, ClassifierSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn, buildSdkFlowTools } from './chunk-M4ISBWXR.js';
10
- import { loadYamlConnectorDeclarations, withMaterializedConnectorDeclarations, SecretProviderChain, ConnectorStartupError, isKnownSecretRef, EnvSecretProvider, PreMintedSecretProvider, InMemorySecretProvider, resolvedConfigToDeclarations, deriveSingleMaterializedConnectorDeclaration } from './chunk-WKIOWDLQ.js';
11
- import { EventNormalizer } from './chunk-QU4J5YSJ.js';
12
- import { probeResumeTranscript, transcriptStoreForRuntime } from './chunk-TVOODIZE.js';
7
+ import { resolveFlowPath } from './chunk-4257Q2LH.js';
8
+ import { findAiAssetsRoot as findAiAssetsRoot$1, deployCatalogEntry, undeployCatalogEntry } from './chunk-JKWU6ULI.js';
9
+ import { ConnectFailureCarryOver, registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, buildSdkConnectorTools, buildLazySdkFlowTools, describeFlowOperations, buildConnectorToolDefs, buildFlowToolDefs, SessionNodeExecutor, SessionSubpromptRunner, ClassifierSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn, buildSdkFlowTools } from './chunk-OOKFZW6H.js';
10
+ import { loadYamlConnectorDeclarations, withMaterializedConnectorDeclarations, SecretProviderChain, ConnectorStartupError, isKnownSecretRef, EnvSecretProvider, PreMintedSecretProvider, InMemorySecretProvider, resolvedConfigToDeclarations, deriveSingleMaterializedConnectorDeclaration } from './chunk-CZ35I4RK.js';
11
+ import { EventNormalizer } from './chunk-7L4WFH3Y.js';
12
+ import { probeResumeTranscript, transcriptStoreForRuntime } from './chunk-LAI7X6I2.js';
13
13
  import { scopeReconfigureModel } from './chunk-EINLFFP6.js';
14
14
  import { CodexNativeStateUnavailable } from './chunk-LOO5CB5M.js';
15
- import { dispatchCapability } from './chunk-RDYI4MML.js';
15
+ import { dispatchCapability } from './chunk-BNUZEYC3.js';
16
16
  import { classifyClaudeSdkError } from './chunk-XBSQ4KMC.js';
17
17
  import { agentExecRequested } from './chunk-YROR332M.js';
18
- import { toAgentEffort, createDriver, catalogLayer, providerCredentialEnvName, toMergedRegistry, registryCredentialEnv, AI_PROVIDER_PRESETS, AgentDriver } from './chunk-ZD7CX25M.js';
19
- import { loadFlow } from './chunk-UMSWQKCY.js';
18
+ import { driverCapabilities, toAgentEffort, createDriver, catalogLayer, providerCredentialEnvName, toMergedRegistry, registryCredentialEnv, AI_PROVIDER_PRESETS, supportsLiveToolUpdates, AgentDriver } from './chunk-FTYM4VRZ.js';
19
+ import { loadFlow } from './chunk-LM5XEFNS.js';
20
20
  import { parseFlowDefinition } from './chunk-QZLWJETK.js';
21
21
  import { renderStimulusPrompt } from './chunk-XUUYAS3Z.js';
22
- import { withActivityLabelJsonSchema, TOOL_ACTIVITY_PROMPT_SECTION, SESSION_ROOT_CONNECTOR_ID, PROTOCOL_VERSION } from './chunk-IDEA6CYI.js';
23
- import { resolveLibraryDir, resolveSettings, loadProviderRegistry } from './chunk-IWCCZL7C.js';
24
- import { resolveRuntimeAssets } from './chunk-YDJZRLGN.js';
25
- import { resolveDriverPaths } from './chunk-K5GBV4SA.js';
26
- import { resolveSkWorkspaceConfig, resolveAgentDir, loadMcpServerDeclarations, COMPACTION_DEFAULTS, resolveCompactionThresholdPercent, validateAssetRecipeAttr, deriveSingleMaterializedMcpDeclaration, stageMaterializedSkills, readSkillAllowList, isStagedSkillMarkerFor, unstageSkill, STAGED_SKILL_MARKER } from './chunk-MXXKTQXJ.js';
27
- import { globalSkaileDir } from './chunk-TLKM4M47.js';
28
- import { withFsDeadline, FsDeadlineError, fsDeadlineMs, parseFrontmatter, tryWithFsDeadline } from './chunk-DXUQCMVT.js';
29
- import { parseAssetRef } from './chunk-43ZBF3WH.js';
22
+ import { withActivityLabelJsonSchema, TOOL_ACTIVITY_PROMPT_SECTION, SESSION_ROOT_CONNECTOR_ID, PROTOCOL_VERSION, deliveryClassOf } from './chunk-K2K7OF4P.js';
23
+ import { resolveLibraryDir, resolveSettings, loadProviderRegistry } from './chunk-6GBQND2F.js';
24
+ import { resolveRuntimeAssets } from './chunk-4SSKKFDF.js';
25
+ import { DEFAULT_DRIVER_ID, resolveDriverPaths } from './chunk-5BEFNLOR.js';
26
+ import { resolveSkWorkspaceConfig, resolveAgentDir, loadMcpServerDeclarations, COMPACTION_DEFAULTS, resolveCompactionThresholdPercent, validateAssetRecipeAttr, deriveSingleMaterializedMcpDeclaration, stageMaterializedSkills, readSkillAllowList, isStagedSkillMarkerFor, unstageSkill, STAGED_SKILL_MARKER } from './chunk-KBAE7PU7.js';
27
+ import { globalSkaileDir } from './chunk-MFHKHXDE.js';
28
+ import { withFsDeadline, FsDeadlineError, fsDeadlineMs, parseFrontmatter, tryWithFsDeadline } from './chunk-LFMX2UEF.js';
29
+ import { parseAssetRef } from './chunk-WX74MVNA.js';
30
30
  import { resolveLogStoreConfig, createLogStoreFromConfig, OnLogBridgeSink, WsLogSink, resolveLogsRetention, enforceLogsRetention } from './chunk-JMKB7IB4.js';
31
31
  import { pickRegistryEntries, registryEntries, resolveEntryBaseUrl, parseModelRef, isEntryEnabled, parseCredentialRef } from './chunk-MJHSLODD.js';
32
32
  import { getLogStore, registerLogStore, createLogger, resetLogStore, isUnwritableStreamError, markStreamBroken, isBrokenPipeError, redactCredentials } from './chunk-BOFL7GIF.js';
@@ -2332,6 +2332,7 @@ function parsePresignResult(raw, op) {
2332
2332
  // runner/src/resources.ts
2333
2333
  async function buildAgentResources(projectDir, driverType, _onLog, watch, secretProvider, sessionMeta, tokenMediator, preMintedSecrets, deferFilesystemMounts, capabilityRegistry, fallbackConnectorDeclarations, extraMcpDeclarations, s3Presigner) {
2334
2334
  const managedProjectMcp = sessionMeta?.managedCodex ? await resolveExternalMcpDeclarations(projectDir, sessionMeta.sessionId, true) : void 0;
2335
+ const inProcessMcp = driverCapabilities(driverType).inProcessMcpServers;
2335
2336
  const resLog = createLogger({
2336
2337
  kind: "runner",
2337
2338
  subkind: "resources",
@@ -2415,7 +2416,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
2415
2416
  }
2416
2417
  return externalMcpManager;
2417
2418
  };
2418
- if (driverType === "claude-sdk") {
2419
+ if (inProcessMcp) {
2419
2420
  const inProcess = await buildInProcessMcpServers(
2420
2421
  resourceManager,
2421
2422
  projectDir,
@@ -2442,7 +2443,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
2442
2443
  mcpSecretChain,
2443
2444
  sessionMeta
2444
2445
  );
2445
- } else if (driverType === "claude-sdk") {
2446
+ } else if (inProcessMcp) {
2446
2447
  externalMcpDeclarations = await resolveExternalMcpDeclarations(
2447
2448
  projectDir,
2448
2449
  sessionMeta?.sessionId
@@ -2454,7 +2455,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
2454
2455
  sessionMeta
2455
2456
  );
2456
2457
  }
2457
- if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers() && !capabilityRegistry)
2458
+ if (!resourceManager && !inProcessMcp && !externalMcpManager?.hasServers() && !capabilityRegistry)
2458
2459
  return noopResult;
2459
2460
  let coalescer = null;
2460
2461
  const startWatching = () => {
@@ -2724,7 +2725,7 @@ function toSdkMcpServerConfig(decl, secrets) {
2724
2725
  // runner/src/session-builder.ts
2725
2726
  async function createAgentSession(config) {
2726
2727
  const managed = config.managedCodex;
2727
- if (managed && (config.driver !== "codex" || !config.model || !config.aiProviderConfigId || !config.capabilityRegistry || !config.capabilities))
2728
+ if (managed && (!driverCapabilities(config.driver).managedSession || !config.model || !config.aiProviderConfigId || !config.capabilityRegistry || !config.capabilities))
2728
2729
  throw new Error("AI_PROFILE_INVALID");
2729
2730
  const {
2730
2731
  projectDir,
@@ -2763,7 +2764,7 @@ async function createAgentSession(config) {
2763
2764
  driver: driverOverride,
2764
2765
  model: modelOverride
2765
2766
  });
2766
- const driverType = managed ? "codex" : settings.driver ?? "omp";
2767
+ const driverType = (managed ? config.driver : settings.driver) ?? DEFAULT_DRIVER_ID;
2767
2768
  const model = managed ? config.model : settings.model;
2768
2769
  const registry = loadSessionRegistry(projectDir, config.registry, config.providers, sessionLog);
2769
2770
  const modelRef = config.modelRef?.trim() || model?.trim() || void 0;
@@ -2867,7 +2868,7 @@ async function createAgentSession(config) {
2867
2868
  const maxTurns = maxTurnsOverride ?? manifest?.runtime?.max_turns;
2868
2869
  let driver;
2869
2870
  try {
2870
- const extraMcpServers = driverType === "claude-sdk" ? await config.extraInProcessMcpServers?.() : void 0;
2871
+ const extraMcpServers = driverCapabilities(driverType).inProcessMcpServers ? await config.extraInProcessMcpServers?.() : void 0;
2871
2872
  const driverMcpServers = extraMcpServers ? { ...mcpServers, ...extraMcpServers } : mcpServers;
2872
2873
  driver = await createSessionDriver({
2873
2874
  config,
@@ -4502,7 +4503,7 @@ function validateCodexInit(cmd, supported, previous) {
4502
4503
  if (requirements !== void 0 && (!Array.isArray(requirements) || requirements.some((item) => typeof item !== "string" || !supported.includes(item))))
4503
4504
  throw new Error("Unsupported runtime: required features are unavailable");
4504
4505
  const profile = cmd.resolvedConfig.agentConfig;
4505
- const managed = profile?.driver === "codex" && (profile.authMode !== void 0 || requirements?.includes("codex-app-server-v1"));
4506
+ const managed = profile !== void 0 && driverCapabilities(profile.driver).managedSession && (profile.authMode !== void 0 || requirements?.includes("codex-app-server-v1"));
4506
4507
  if ((managed || cmd.credentials.ai !== void 0) && !supported.includes("codex-app-server-v1"))
4507
4508
  throw new Error("Unsupported runtime: codex-app-server-v1 is unavailable");
4508
4509
  if (!managed && cmd.credentials.ai === void 0) return;
@@ -4605,7 +4606,7 @@ function loadManagedCodexHostConfig(file, projectDir) {
4605
4606
  function bindManagedCodexInit(host, cmd, refreshCredential) {
4606
4607
  const profile = cmd.resolvedConfig.agentConfig;
4607
4608
  const credential = parseCodexCredential(cmd.credentials.ai);
4608
- if (!profile?.authMode || !["subscription", "api-key"].includes(profile.authMode) || cmd.identity.sessionId !== host.sessionId || profile?.driver !== "codex" || !profile.model || !host.subpromptModels.available.includes(profile.model) || credential.configId !== cmd.resolvedConfig.aiProviderConfigId || profile.authMode === "subscription" !== (credential.kind === "codex-subscription"))
4609
+ if (!profile?.authMode || !["subscription", "api-key"].includes(profile.authMode) || cmd.identity.sessionId !== host.sessionId || !driverCapabilities(profile.driver).managedSession || !profile.model || !host.subpromptModels.available.includes(profile.model) || credential.configId !== cmd.resolvedConfig.aiProviderConfigId || profile.authMode === "subscription" !== (credential.kind === "codex-subscription"))
4609
4610
  throw refused();
4610
4611
  const reasoningEffort = profile.effort ?? host.reasoningEffort;
4611
4612
  if (!["minimal", "low", "medium", "high", "xhigh"].includes(reasoningEffort)) throw refused();
@@ -5012,6 +5013,309 @@ function planRuntimeSessionEmit(input) {
5012
5013
  return { type: "runtime_session", driverSessionId, model, capabilitySignature };
5013
5014
  }
5014
5015
 
5016
+ // runner/src/init-build-hold.ts
5017
+ var DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS = 1e4;
5018
+ function resolveConnectorMutateInitHoldMs(env = process.env) {
5019
+ const parsed = Number.parseInt(env.SKAILE_CONNECTOR_MUTATE_INIT_HOLD_MS ?? "", 10);
5020
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS;
5021
+ }
5022
+ function createInitBuildHold(now = Date.now) {
5023
+ let current = null;
5024
+ let tail = Promise.resolve();
5025
+ let held = 0;
5026
+ const building = () => current !== null && !current.done;
5027
+ async function awaitNewestBuild() {
5028
+ for (; ; ) {
5029
+ const build = current;
5030
+ if (!build) return null;
5031
+ if (!build.done) await build.settled;
5032
+ if (current === build) return build.error;
5033
+ }
5034
+ }
5035
+ return {
5036
+ beginBuild() {
5037
+ let resolve4;
5038
+ const build = {
5039
+ done: false,
5040
+ error: null,
5041
+ settled: new Promise((r) => {
5042
+ resolve4 = r;
5043
+ })
5044
+ };
5045
+ current = build;
5046
+ const settle = (error) => {
5047
+ if (build.done) return;
5048
+ build.done = true;
5049
+ build.error = error;
5050
+ resolve4();
5051
+ };
5052
+ return { succeed: () => settle(null), fail: (error) => settle(error) };
5053
+ },
5054
+ run(task, deadlineMs) {
5055
+ if (held === 0 && !building()) {
5056
+ if (current?.error) return task({ kind: "failed", error: current.error });
5057
+ return task({ kind: "ready", remainingMs: void 0 });
5058
+ }
5059
+ held++;
5060
+ const arrivedAt = now();
5061
+ const previous = tail;
5062
+ const turn = previous.then(awaitNewestBuild);
5063
+ let timer;
5064
+ const deadline = deadlineMs === void 0 ? null : new Promise((resolve4) => {
5065
+ timer = setTimeout(() => resolve4("timeout"), deadlineMs);
5066
+ timer.unref?.();
5067
+ });
5068
+ let markStarted;
5069
+ const started = new Promise((resolve4) => {
5070
+ markStarted = resolve4;
5071
+ });
5072
+ const result = (async () => {
5073
+ const first = deadline ? await Promise.race([turn, deadline]) : await turn;
5074
+ clearTimeout(timer);
5075
+ if (first === "timeout") {
5076
+ void turn.then(markStarted);
5077
+ return task({ kind: "timeout", waitedMs: now() - arrivedAt });
5078
+ }
5079
+ markStarted();
5080
+ if (first) return task({ kind: "failed", error: first });
5081
+ return task({
5082
+ kind: "ready",
5083
+ remainingMs: deadlineMs === void 0 ? void 0 : Math.max(0, deadlineMs - (now() - arrivedAt))
5084
+ });
5085
+ })();
5086
+ tail = started;
5087
+ void Promise.allSettled([turn, result]).then(() => {
5088
+ held--;
5089
+ });
5090
+ return result;
5091
+ },
5092
+ held: () => held
5093
+ };
5094
+ }
5095
+
5096
+ // runner/src/serial-lock.ts
5097
+ function createSerialLock() {
5098
+ let tail = Promise.resolve();
5099
+ return (fn) => {
5100
+ const run = tail.then(fn, fn);
5101
+ tail = run.catch(() => void 0);
5102
+ return run;
5103
+ };
5104
+ }
5105
+ function createCoalescedTask(lock, fn) {
5106
+ let waiting = null;
5107
+ return (...args) => {
5108
+ if (waiting) return waiting;
5109
+ const run = lock(() => {
5110
+ waiting = null;
5111
+ return fn(...args);
5112
+ });
5113
+ waiting = run;
5114
+ return run;
5115
+ };
5116
+ }
5117
+ async function recordStagedSkills(staged, projectDir, skillsDir, names, timeoutMs) {
5118
+ for (const name of names) {
5119
+ const path6 = join(projectDir, skillsDir, name);
5120
+ const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
5121
+ staged.set(
5122
+ name,
5123
+ st?.isDirectory() && st.birthtimeMs > 0 ? { path: path6, dev: st.dev, ino: st.ino, birthtimeMs: st.birthtimeMs } : null
5124
+ );
5125
+ }
5126
+ }
5127
+ async function isStillOurs(record2, path6, timeoutMs) {
5128
+ if (!record2 || record2.path !== path6) return false;
5129
+ const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
5130
+ return st?.isDirectory() === true && st.dev === record2.dev && st.ino === record2.ino && st.birthtimeMs === record2.birthtimeMs;
5131
+ }
5132
+ async function recordLoadedSkillDigests(loaded, projectDir, skillsDir, names, opts) {
5133
+ for (const name of names) {
5134
+ if (opts.driverUp && opts.previouslyStaged.has(name)) continue;
5135
+ const path6 = join(projectDir, skillsDir, name);
5136
+ loaded.set(name, { path: path6, digest: await stagedSkillDigest(path6) });
5137
+ }
5138
+ }
5139
+ var DIGEST_DEADLINE_FACTOR = 4;
5140
+ var DIGEST_MAX_BYTES = 64 * 1024 * 1024;
5141
+ var DIGEST_CHUNK_BYTES = 64 * 1024;
5142
+ var DIGEST_OPEN_FLAGS = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
5143
+ async function stagedSkillDigest(dir, timeoutMs) {
5144
+ return tryWithFsDeadline(
5145
+ `digest ${dir}`,
5146
+ async () => {
5147
+ const hash = createHash("sha256");
5148
+ let budget = DIGEST_MAX_BYTES;
5149
+ const hashFile = async (path6) => {
5150
+ const fh = await open(path6, DIGEST_OPEN_FLAGS);
5151
+ try {
5152
+ const st = await fh.stat();
5153
+ if (!st.isFile()) throw new Error(`not a regular file: ${path6}`);
5154
+ if (st.size > budget) throw new Error("skill too large to digest");
5155
+ const buf = Buffer.alloc(DIGEST_CHUNK_BYTES);
5156
+ let total = 0;
5157
+ for (; ; ) {
5158
+ const { bytesRead } = await fh.read(buf, 0, buf.length, null);
5159
+ if (bytesRead === 0) break;
5160
+ total += bytesRead;
5161
+ if (total > budget) throw new Error("skill too large to digest");
5162
+ hash.update(buf.subarray(0, bytesRead));
5163
+ }
5164
+ budget -= total;
5165
+ hash.update(`\0${total}\0`);
5166
+ } finally {
5167
+ await fh.close();
5168
+ }
5169
+ };
5170
+ const walk = async (rel) => {
5171
+ const here = rel ? join(dir, rel) : dir;
5172
+ if (rel && !(await lstat(here)).isDirectory()) throw new Error(`not a dir: ${here}`);
5173
+ const entries = await readdir(here, { withFileTypes: true });
5174
+ entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
5175
+ for (const entry of entries) {
5176
+ if (!rel && entry.name === STAGED_SKILL_MARKER) continue;
5177
+ const path6 = rel ? `${rel}/${entry.name}` : entry.name;
5178
+ if (entry.isDirectory()) {
5179
+ hash.update(`d\0${path6}\0`);
5180
+ await walk(path6);
5181
+ } else if (entry.isSymbolicLink()) {
5182
+ hash.update(`l\0${path6}\0${await readlink(join(dir, path6))}\0`);
5183
+ } else if (entry.isFile()) {
5184
+ hash.update(`f\0${path6}\0`);
5185
+ await hashFile(join(dir, path6));
5186
+ } else {
5187
+ hash.update(`o\0${path6}\0`);
5188
+ }
5189
+ }
5190
+ };
5191
+ await walk("");
5192
+ return hash.digest("hex");
5193
+ },
5194
+ null,
5195
+ fsDeadlineMs() * DIGEST_DEADLINE_FACTOR
5196
+ );
5197
+ }
5198
+ async function attachStagedSkill(deps, name) {
5199
+ try {
5200
+ const skillsDir = deps.skillsDir();
5201
+ const dirName = name.includes("/") ? name.split("/").pop() : name;
5202
+ const { staged, unchanged } = await deps.withSkillFsLock(async () => {
5203
+ const dest = join(deps.projectDir, skillsDir, dirName);
5204
+ const loaded = deps.stagedSkillDirs.has(dirName) ? deps.loadedSkillDigests.get(dirName) : void 0;
5205
+ const names = await stageMaterializedSkills(deps.projectDir, skillsDir, { declared: [name] });
5206
+ let same = false;
5207
+ if (names.includes(dirName)) {
5208
+ const digest = await stagedSkillDigest(dest);
5209
+ same = digest !== null && loaded?.path === dest && loaded.digest === digest;
5210
+ if (!same) deps.loadedSkillDigests.set(dirName, { path: dest, digest });
5211
+ }
5212
+ await recordStagedSkills(deps.stagedSkillDirs, deps.projectDir, skillsDir, names);
5213
+ return { staged: names, unchanged: same ? dirName : null };
5214
+ });
5215
+ if (staged.length === 0) {
5216
+ return {
5217
+ ok: false,
5218
+ code: "skill_not_materialized",
5219
+ message: `no materialized skill matching "${name}" under .skaile/assets/skill`
5220
+ };
5221
+ }
5222
+ const live = deps.driverStarted();
5223
+ const toRestart = staged.filter((s) => s !== unchanged);
5224
+ if (toRestart.length === 0) {
5225
+ deps.log(
5226
+ `[serve] runner.attach_instance: skill ${staged.join(", ")} already staged and unchanged \u2014 no driver restart`
5227
+ );
5228
+ return { ok: true, id: name, live, toolCount: 0 };
5229
+ }
5230
+ deps.log(`[serve] runner.attach_instance staged skill(s): ${toRestart.join(", ")}`);
5231
+ deps.scheduleSkillRestart(toRestart.map((s) => ({ name: s, action: "add" })));
5232
+ return { ok: true, id: name, live, toolCount: 0 };
5233
+ } catch (err) {
5234
+ return {
5235
+ ok: false,
5236
+ code: "skill_attach_failed",
5237
+ message: err instanceof Error ? err.message : String(err)
5238
+ };
5239
+ }
5240
+ }
5241
+ async function detachStagedSkill(deps, name) {
5242
+ try {
5243
+ const skillsDir = deps.skillsDir();
5244
+ const dirName = name.split("/").pop() ?? name;
5245
+ const result = await deps.withSkillFsLock(async () => {
5246
+ const knownStaged = await isStillOurs(
5247
+ deps.stagedSkillDirs.get(dirName),
5248
+ join(deps.projectDir, skillsDir, dirName)
5249
+ );
5250
+ return unstageSkill(deps.projectDir, skillsDir, name, { knownStaged });
5251
+ });
5252
+ const live = deps.driverStarted();
5253
+ if ("reason" in result) {
5254
+ deps.log(
5255
+ `[serve] runner.detach_instance: "${result.name}" exists but was not staged by the runner \u2014 left in place`
5256
+ );
5257
+ return { ok: true, id: result.name, removed: false, live, reason: result.reason };
5258
+ }
5259
+ const wasTracked = deps.stagedSkillDirs.delete(result.name);
5260
+ if (!result.removedStaged && !wasTracked) {
5261
+ deps.log(`[serve] runner.detach_instance: skill "${result.name}" was not staged`);
5262
+ return { ok: true, id: result.name, removed: result.removedAsset, live };
5263
+ }
5264
+ deps.log(`[serve] runner.detach_instance unstaged skill: ${result.name}`);
5265
+ deps.scheduleSkillRestart([{ name: result.name, action: "remove" }]);
5266
+ return { ok: true, id: result.name, removed: true, live };
5267
+ } catch (err) {
5268
+ return {
5269
+ ok: false,
5270
+ code: "skill_detach_failed",
5271
+ message: err instanceof Error ? err.message : String(err)
5272
+ };
5273
+ }
5274
+ }
5275
+ async function pathState(path6) {
5276
+ try {
5277
+ await withFsDeadline(`lstat ${path6}`, () => lstat(path6));
5278
+ return "present";
5279
+ } catch (err) {
5280
+ return err?.code === "ENOENT" ? "absent" : "unknown";
5281
+ }
5282
+ }
5283
+ async function removeUnlistedStagedSkills(deps, skillsDir) {
5284
+ const allowed = await readSkillAllowList(deps.projectDir);
5285
+ if (!allowed) return [];
5286
+ const root = join(deps.projectDir, skillsDir);
5287
+ const entries = await tryWithFsDeadline(
5288
+ `readdir ${root}`,
5289
+ () => readdir(root, { withFileTypes: true }),
5290
+ []
5291
+ );
5292
+ const removed = [];
5293
+ for (const entry of entries) {
5294
+ if (!entry.isDirectory() || allowed.has(entry.name)) continue;
5295
+ try {
5296
+ const dir = join(root, entry.name);
5297
+ if (await pathState(join(deps.projectDir, ".skaile/assets/skill", entry.name)) !== "absent") {
5298
+ continue;
5299
+ }
5300
+ const knownStaged = await isStillOurs(deps.stagedSkillDirs.get(entry.name), dir);
5301
+ if (!knownStaged && !await isStagedSkillMarkerFor(dir, entry.name).catch(() => false))
5302
+ continue;
5303
+ const result = await unstageSkill(deps.projectDir, skillsDir, entry.name, {
5304
+ knownStaged,
5305
+ keepAsset: true
5306
+ });
5307
+ if ("reason" in result || !result.removedStaged) continue;
5308
+ deps.stagedSkillDirs.delete(result.name);
5309
+ removed.push(result.name);
5310
+ } catch (err) {
5311
+ deps.log(
5312
+ `[serve] could not remove unlisted skill "${entry.name}" (left in place): ${err instanceof Error ? err.message : String(err)}`
5313
+ );
5314
+ }
5315
+ }
5316
+ return removed;
5317
+ }
5318
+
5015
5319
  // runner/src/compaction-gate.ts
5016
5320
  var CompactionGate = class {
5017
5321
  /**
@@ -5125,7 +5429,7 @@ async function claimDriverForCompaction(deps) {
5125
5429
  released = true;
5126
5430
  deps.gate.settle(hold);
5127
5431
  };
5128
- const timeoutMs = deps.timeoutMs ?? compactionTurnWaitMs();
5432
+ const { timeoutMs } = deps;
5129
5433
  if (await raceDeadline(deps.awaitClaimedTurns(), timeoutMs) !== "opened") {
5130
5434
  release2();
5131
5435
  deps.log(
@@ -5133,30 +5437,30 @@ async function claimDriverForCompaction(deps) {
5133
5437
  );
5134
5438
  return null;
5135
5439
  }
5136
- if (deps.isSwapping?.()) {
5440
+ if (deps.isDriverReplaced()) {
5137
5441
  release2();
5138
- deps.log("[serve] compaction skipped: a driver swap is pending");
5442
+ deps.log("[serve] compaction skipped: its driver is being or has been replaced");
5139
5443
  return null;
5140
5444
  }
5141
- const endTurn = deps.claimTurnSlot?.();
5445
+ const endTurn = deps.claimTurnSlot();
5142
5446
  return () => {
5143
- endTurn?.();
5447
+ endTurn();
5144
5448
  release2();
5145
5449
  };
5146
5450
  }
5147
5451
  var TURN_COMPACTION_YIELD_ATTEMPTS = 3;
5148
- async function beginTurnClearOfCompaction(deps, maxAttempts = TURN_COMPACTION_YIELD_ATTEMPTS) {
5149
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
5452
+ async function beginTurnClearOfCompaction(deps) {
5453
+ for (let attempt = 0; attempt < TURN_COMPACTION_YIELD_ATTEMPTS; attempt += 1) {
5150
5454
  if (!await deps.awaitIdle()) return null;
5151
5455
  const endTurn = await deps.claimTurn();
5152
5456
  if (deps.gate.isIdle()) return endTurn;
5153
5457
  endTurn();
5154
5458
  }
5155
- throw new Error(`turn overtaken by a compaction ${maxAttempts} times running`);
5459
+ throw new Error(`turn overtaken by a compaction ${TURN_COMPACTION_YIELD_ATTEMPTS} times running`);
5156
5460
  }
5157
5461
  var COMPACTION_GATE_TIMEOUT_MESSAGE = "The session is still compacting its history and could not take this message. Send it again in a moment.";
5158
5462
  async function guardTurnAgainstCompaction(deps) {
5159
- const outcome = await deps.gate.awaitIdle(deps.timeoutMs ?? compactionGateTimeoutMs());
5463
+ const outcome = await deps.gate.awaitIdle(compactionGateTimeoutMs());
5160
5464
  if (outcome === "waited") deps.log(`[serve] ${deps.what} released after compaction settled`);
5161
5465
  if (outcome !== "timeout") return true;
5162
5466
  deps.log(`[serve] ${deps.what} abandoned: a compaction has held the driver past its bound`);
@@ -5277,103 +5581,23 @@ var DriverSwapGate = class {
5277
5581
  beginSwap(recreate) {
5278
5582
  this.activeDriverSwap = recreate;
5279
5583
  const clear = () => {
5280
- if (this.activeDriverSwap === recreate) this.activeDriverSwap = null;
5281
- };
5282
- recreate.then(clear, clear);
5283
- }
5284
- /**
5285
- * Await the in-flight swap before reading the live driver. Re-checks in a loop
5286
- * so a second swap starting during the wait is also awaited.
5287
- */
5288
- async awaitSwap() {
5289
- while (this.activeDriverSwap) {
5290
- try {
5291
- await this.activeDriverSwap;
5292
- } catch {
5293
- }
5294
- }
5295
- }
5296
- };
5297
-
5298
- // runner/src/init-build-hold.ts
5299
- var DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS = 1e4;
5300
- function resolveConnectorMutateInitHoldMs(env = process.env) {
5301
- const parsed = Number.parseInt(env.SKAILE_CONNECTOR_MUTATE_INIT_HOLD_MS ?? "", 10);
5302
- return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS;
5303
- }
5304
- function createInitBuildHold(now = Date.now) {
5305
- let current = null;
5306
- let tail = Promise.resolve();
5307
- let held = 0;
5308
- const building = () => current !== null && !current.done;
5309
- async function awaitNewestBuild() {
5310
- for (; ; ) {
5311
- const build = current;
5312
- if (!build) return null;
5313
- if (!build.done) await build.settled;
5314
- if (current === build) return build.error;
5315
- }
5584
+ if (this.activeDriverSwap === recreate) this.activeDriverSwap = null;
5585
+ };
5586
+ recreate.then(clear, clear);
5316
5587
  }
5317
- return {
5318
- beginBuild() {
5319
- let resolve4;
5320
- const build = {
5321
- done: false,
5322
- error: null,
5323
- settled: new Promise((r) => {
5324
- resolve4 = r;
5325
- })
5326
- };
5327
- current = build;
5328
- const settle = (error) => {
5329
- if (build.done) return;
5330
- build.done = true;
5331
- build.error = error;
5332
- resolve4();
5333
- };
5334
- return { succeed: () => settle(null), fail: (error) => settle(error) };
5335
- },
5336
- run(task, deadlineMs) {
5337
- if (held === 0 && !building()) {
5338
- if (current?.error) return task({ kind: "failed", error: current.error });
5339
- return task({ kind: "ready", remainingMs: void 0 });
5588
+ /**
5589
+ * Await the in-flight swap before reading the live driver. Re-checks in a loop
5590
+ * so a second swap starting during the wait is also awaited.
5591
+ */
5592
+ async awaitSwap() {
5593
+ while (this.activeDriverSwap) {
5594
+ try {
5595
+ await this.activeDriverSwap;
5596
+ } catch {
5340
5597
  }
5341
- held++;
5342
- const arrivedAt = now();
5343
- const previous = tail;
5344
- const turn = previous.then(awaitNewestBuild);
5345
- let timer;
5346
- const deadline = deadlineMs === void 0 ? null : new Promise((resolve4) => {
5347
- timer = setTimeout(() => resolve4("timeout"), deadlineMs);
5348
- timer.unref?.();
5349
- });
5350
- let markStarted;
5351
- const started = new Promise((resolve4) => {
5352
- markStarted = resolve4;
5353
- });
5354
- const result = (async () => {
5355
- const first = deadline ? await Promise.race([turn, deadline]) : await turn;
5356
- clearTimeout(timer);
5357
- if (first === "timeout") {
5358
- void turn.then(markStarted);
5359
- return task({ kind: "timeout", waitedMs: now() - arrivedAt });
5360
- }
5361
- markStarted();
5362
- if (first) return task({ kind: "failed", error: first });
5363
- return task({
5364
- kind: "ready",
5365
- remainingMs: deadlineMs === void 0 ? void 0 : Math.max(0, deadlineMs - (now() - arrivedAt))
5366
- });
5367
- })();
5368
- tail = started;
5369
- void Promise.allSettled([turn, result]).then(() => {
5370
- held--;
5371
- });
5372
- return result;
5373
- },
5374
- held: () => held
5375
- };
5376
- }
5598
+ }
5599
+ }
5600
+ };
5377
5601
 
5378
5602
  // runner/src/pending-turns.ts
5379
5603
  var PendingTurns = class {
@@ -5397,9 +5621,15 @@ var PendingTurns = class {
5397
5621
  }
5398
5622
  };
5399
5623
  }
5400
- /** Call at a turn's end, while that turn is still counted: whether to report idle now. */
5401
- shouldReportIdle() {
5402
- if (this.count > 1) {
5624
+ /**
5625
+ * Whether to report idle now, at the end of something that ran on the driver.
5626
+ * A `"turn"` end belongs to a counted turn, which is still counted when it
5627
+ * fires. A `"compaction"` end (the compaction turn, or the snapshot turn after
5628
+ * it) is no counted turn, so every counted turn is waiting behind it.
5629
+ */
5630
+ shouldReportIdle(endedBy) {
5631
+ const own = endedBy === "turn" ? 1 : 0;
5632
+ if (this.count > own) {
5403
5633
  this.idleOwed = true;
5404
5634
  return false;
5405
5635
  }
@@ -5467,248 +5697,298 @@ var PromptTurnQueue = class {
5467
5697
  }
5468
5698
  };
5469
5699
 
5470
- // runner/src/serial-lock.ts
5471
- function createSerialLock() {
5472
- let tail = Promise.resolve();
5473
- return (fn) => {
5474
- const run = tail.then(fn, fn);
5475
- tail = run.catch(() => void 0);
5476
- return run;
5477
- };
5478
- }
5479
- function createCoalescedTask(lock, fn) {
5480
- let waiting = null;
5481
- return (...args) => {
5482
- if (waiting) return waiting;
5483
- const run = lock(() => {
5484
- waiting = null;
5485
- return fn(...args);
5700
+ // runner/src/turn-scheduler.ts
5701
+ var FLOW_TURN_COMPACTION_TIMEOUT = "Flow turn abandoned: a compaction held the driver";
5702
+ var TurnScheduler = class {
5703
+ constructor(deps) {
5704
+ this.deps = deps;
5705
+ }
5706
+ deps;
5707
+ swaps = new DriverSwapGate();
5708
+ compactions = new CompactionGate();
5709
+ pending = new PendingTurns(() => this.sendIdle());
5710
+ queue = new PromptTurnQueue();
5711
+ /** The compaction that armed the event suppression; null while none runs. */
5712
+ suppressedBy = null;
5713
+ /** Compactions past their end callback and not yet settled: a snapshot turn may still run. */
5714
+ snapshotTurns = /* @__PURE__ */ new Set();
5715
+ /** Counts {@link compactionHooks} calls; only the latest hooks may start a compaction. */
5716
+ hooksGeneration = 0;
5717
+ /** Run a chat prompt: queue it, wait out swaps and compactions, claim the driver, dispatch. */
5718
+ prompt(turn) {
5719
+ return this.counted(async () => {
5720
+ const place = this.queue.join(turn.owner);
5721
+ try {
5722
+ if (place.queued) {
5723
+ turn.onQueued?.();
5724
+ const queuedAt = Date.now();
5725
+ await place.ready;
5726
+ this.deps.logPhase("prompt_queue_wait", queuedAt, { dropped: place.dropped });
5727
+ if (place.dropped) return;
5728
+ }
5729
+ await this.runPrompt(turn, place.leave);
5730
+ } finally {
5731
+ place.leave();
5732
+ }
5486
5733
  });
5487
- waiting = run;
5488
- return run;
5489
- };
5490
- }
5491
- async function recordStagedSkills(staged, projectDir, skillsDir, names, timeoutMs) {
5492
- for (const name of names) {
5493
- const path6 = join(projectDir, skillsDir, name);
5494
- const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
5495
- staged.set(
5496
- name,
5497
- st?.isDirectory() && st.birthtimeMs > 0 ? { path: path6, dev: st.dev, ino: st.ino, birthtimeMs: st.birthtimeMs } : null
5498
- );
5499
5734
  }
5500
- }
5501
- async function isStillOurs(record2, path6, timeoutMs) {
5502
- if (!record2 || record2.path !== path6) return false;
5503
- const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
5504
- return st?.isDirectory() === true && st.dev === record2.dev && st.ino === record2.ino && st.birthtimeMs === record2.birthtimeMs;
5505
- }
5506
- async function recordLoadedSkillDigests(loaded, projectDir, skillsDir, names, opts) {
5507
- for (const name of names) {
5508
- if (opts.driverUp && opts.previouslyStaged.has(name)) continue;
5509
- const path6 = join(projectDir, skillsDir, name);
5510
- loaded.set(name, { path: path6, digest: await stagedSkillDigest(path6) });
5735
+ /**
5736
+ * Run a question reply. A paused question takes the answer at once, ahead of
5737
+ * every wait. A recreate waits for the paused turn, and that turn waits for
5738
+ * this answer, so gating the answer on the swap wedges the session for good.
5739
+ * Anything else is a fresh turn and queues like a prompt.
5740
+ */
5741
+ reply(turn) {
5742
+ return this.counted(async () => {
5743
+ if (!await turn.admit()) return;
5744
+ const paused = this.deps.getDriver();
5745
+ if (paused.hasPendingQuestion()) {
5746
+ if (paused.answerQuestion(turn.answer, turn.question, turn.requestId)) {
5747
+ turn.onAnswered?.();
5748
+ return;
5749
+ }
5750
+ } else {
5751
+ await this.swaps.awaitSwap();
5752
+ }
5753
+ if (!this.deps.getDriver().acceptsReplyAsPrompt) {
5754
+ if (!this.deps.getDriver().hasPendingQuestion()) {
5755
+ this.deps.log("[serve] reply: driver takes no reply as a prompt; answer not delivered");
5756
+ this.deps.sendEvent({
5757
+ type: "error",
5758
+ message: "This question is no longer open, so the agent did not get your answer. Send it as a new message.",
5759
+ fatal: false
5760
+ });
5761
+ }
5762
+ return;
5763
+ }
5764
+ let endTurn;
5765
+ try {
5766
+ endTurn = await this.claim("reply", () => this.deps.ensureDriverStarted());
5767
+ } catch (err) {
5768
+ this.deps.sendEvent(replyFailed(err));
5769
+ return;
5770
+ }
5771
+ if (!endTurn) return;
5772
+ try {
5773
+ await this.deps.getDriver().prompt(freshTurnReplyPrompt(turn.answer, turn.question));
5774
+ } catch (err) {
5775
+ this.deps.sendEvent(replyFailed(err));
5776
+ } finally {
5777
+ endTurn();
5778
+ }
5779
+ });
5511
5780
  }
5512
- }
5513
- var DIGEST_DEADLINE_FACTOR = 4;
5514
- var DIGEST_MAX_BYTES = 64 * 1024 * 1024;
5515
- var DIGEST_CHUNK_BYTES = 64 * 1024;
5516
- var DIGEST_OPEN_FLAGS = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
5517
- async function stagedSkillDigest(dir, timeoutMs) {
5518
- return tryWithFsDeadline(
5519
- `digest ${dir}`,
5520
- async () => {
5521
- const hash = createHash("sha256");
5522
- let budget = DIGEST_MAX_BYTES;
5523
- const hashFile = async (path6) => {
5524
- const fh = await open(path6, DIGEST_OPEN_FLAGS);
5781
+ /**
5782
+ * Run one flow turn and resolve on its `agent_end`.
5783
+ *
5784
+ * Waits out a pending swap, any compaction, and every turn already in flight.
5785
+ * The in-flight wait is what makes the `agent_end` listener safe: a flow
5786
+ * started from inside a chat turn would otherwise resolve on that turn's end.
5787
+ * The slot is held for the whole turn, never across a wait, which would stall
5788
+ * a swap behind a compaction.
5789
+ */
5790
+ flowTurn(prompt, timeoutMs) {
5791
+ return this.counted(async () => {
5792
+ for (; ; ) {
5793
+ await this.swaps.awaitSwap();
5794
+ if (!await this.awaitCompactionIdle("flow turn"))
5795
+ throw new Error(FLOW_TURN_COMPACTION_TIMEOUT);
5796
+ const endTurn = await this.swaps.beginQueuedTurn();
5797
+ if (this.swaps.isSwapping() || !this.compactions.isIdle()) {
5798
+ endTurn();
5799
+ continue;
5800
+ }
5525
5801
  try {
5526
- const st = await fh.stat();
5527
- if (!st.isFile()) throw new Error(`not a regular file: ${path6}`);
5528
- if (st.size > budget) throw new Error("skill too large to digest");
5529
- const buf = Buffer.alloc(DIGEST_CHUNK_BYTES);
5530
- let total = 0;
5531
- for (; ; ) {
5532
- const { bytesRead } = await fh.read(buf, 0, buf.length, null);
5533
- if (bytesRead === 0) break;
5534
- total += bytesRead;
5535
- if (total > budget) throw new Error("skill too large to digest");
5536
- hash.update(buf.subarray(0, bytesRead));
5537
- }
5538
- budget -= total;
5539
- hash.update(`\0${total}\0`);
5802
+ await this.deps.ensureDriverStarted();
5803
+ await awaitAgentEnd(this.deps.getDriver(), prompt, timeoutMs);
5804
+ return;
5540
5805
  } finally {
5541
- await fh.close();
5542
- }
5543
- };
5544
- const walk = async (rel) => {
5545
- const here = rel ? join(dir, rel) : dir;
5546
- if (rel && !(await lstat(here)).isDirectory()) throw new Error(`not a dir: ${here}`);
5547
- const entries = await readdir(here, { withFileTypes: true });
5548
- entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
5549
- for (const entry of entries) {
5550
- if (!rel && entry.name === STAGED_SKILL_MARKER) continue;
5551
- const path6 = rel ? `${rel}/${entry.name}` : entry.name;
5552
- if (entry.isDirectory()) {
5553
- hash.update(`d\0${path6}\0`);
5554
- await walk(path6);
5555
- } else if (entry.isSymbolicLink()) {
5556
- hash.update(`l\0${path6}\0${await readlink(join(dir, path6))}\0`);
5557
- } else if (entry.isFile()) {
5558
- hash.update(`f\0${path6}\0`);
5559
- await hashFile(join(dir, path6));
5560
- } else {
5561
- hash.update(`o\0${path6}\0`);
5562
- }
5806
+ endTurn();
5563
5807
  }
5564
- };
5565
- await walk("");
5566
- return hash.digest("hex");
5567
- },
5568
- null,
5569
- fsDeadlineMs() * DIGEST_DEADLINE_FACTOR
5570
- );
5571
- }
5572
- async function attachStagedSkill(deps, name) {
5573
- try {
5574
- const skillsDir = deps.skillsDir();
5575
- const dirName = name.includes("/") ? name.split("/").pop() : name;
5576
- const { staged, unchanged } = await deps.withSkillFsLock(async () => {
5577
- const dest = join(deps.projectDir, skillsDir, dirName);
5578
- const loaded = deps.stagedSkillDirs.has(dirName) ? deps.loadedSkillDigests.get(dirName) : void 0;
5579
- const names = await stageMaterializedSkills(deps.projectDir, skillsDir, { declared: [name] });
5580
- let same = false;
5581
- if (names.includes(dirName)) {
5582
- const digest = await stagedSkillDigest(dest);
5583
- same = digest !== null && loaded?.path === dest && loaded.digest === digest;
5584
- if (!same) deps.loadedSkillDigests.set(dirName, { path: dest, digest });
5585
5808
  }
5586
- await recordStagedSkills(deps.stagedSkillDirs, deps.projectDir, skillsDir, names);
5587
- return { staged: names, unchanged: same ? dirName : null };
5588
5809
  });
5589
- if (staged.length === 0) {
5590
- return {
5591
- ok: false,
5592
- code: "skill_not_materialized",
5593
- message: `no materialized skill matching "${name}" under .skaile/assets/skill`
5594
- };
5595
- }
5596
- const live = deps.driverStarted();
5597
- const toRestart = staged.filter((s) => s !== unchanged);
5598
- if (toRestart.length === 0) {
5599
- deps.log(
5600
- `[serve] runner.attach_instance: skill ${staged.join(", ")} already staged and unchanged \u2014 no driver restart`
5601
- );
5602
- return { ok: true, id: name, live, toolCount: 0 };
5603
- }
5604
- deps.log(`[serve] runner.attach_instance staged skill(s): ${toRestart.join(", ")}`);
5605
- deps.scheduleSkillRestart(toRestart.map((s) => ({ name: s, action: "add" })));
5606
- return { ok: true, id: name, live, toolCount: 0 };
5607
- } catch (err) {
5608
- return {
5609
- ok: false,
5610
- code: "skill_attach_failed",
5611
- message: err instanceof Error ? err.message : String(err)
5612
- };
5613
5810
  }
5614
- }
5615
- async function detachStagedSkill(deps, name) {
5616
- try {
5617
- const skillsDir = deps.skillsDir();
5618
- const dirName = name.split("/").pop() ?? name;
5619
- const result = await deps.withSkillFsLock(async () => {
5620
- const knownStaged = await isStillOurs(
5621
- deps.stagedSkillDirs.get(dirName),
5622
- join(deps.projectDir, skillsDir, dirName)
5623
- );
5624
- return unstageSkill(deps.projectDir, skillsDir, name, { knownStaged });
5625
- });
5626
- const live = deps.driverStarted();
5627
- if ("reason" in result) {
5628
- deps.log(
5629
- `[serve] runner.detach_instance: "${result.name}" exists but was not staged by the runner \u2014 left in place`
5630
- );
5631
- return { ok: true, id: result.name, removed: false, live, reason: result.reason };
5632
- }
5633
- const wasTracked = deps.stagedSkillDirs.delete(result.name);
5634
- if (!result.removedStaged && !wasTracked) {
5635
- deps.log(`[serve] runner.detach_instance: skill "${result.name}" was not staged`);
5636
- return { ok: true, id: result.name, removed: result.removedAsset, live };
5637
- }
5638
- deps.log(`[serve] runner.detach_instance unstaged skill: ${result.name}`);
5639
- deps.scheduleSkillRestart([{ name: result.name, action: "remove" }]);
5640
- return { ok: true, id: result.name, removed: true, live };
5641
- } catch (err) {
5811
+ /**
5812
+ * Run a driver swap (recreate): queued behind every earlier swap, then behind
5813
+ * every turn holding a slot. Prompts defer to it from the moment it is
5814
+ * registered. Never call from inside a swap: it would wait on itself.
5815
+ */
5816
+ runSwap(swap) {
5817
+ return this.swaps.runSwap(swap);
5818
+ }
5819
+ /**
5820
+ * The driver ended a turn. Reports idle unless a compaction suppresses it, or
5821
+ * more turns are queued behind this one, in which case it is owed and goes
5822
+ * out when the last of them settles.
5823
+ */
5824
+ reportTurnEnd() {
5825
+ this.reportIdleIfDrained(this.snapshotTurns.size > 0 ? "compaction" : "turn");
5826
+ }
5827
+ /**
5828
+ * Drop every prompt `senderId` has waiting, in queue order. The prompt whose
5829
+ * turn is running is not waiting, and a prompt with no sender is nobody's to drop.
5830
+ */
5831
+ dropQueuedPromptsFrom(senderId) {
5832
+ return this.queue.dropQueuedFrom(senderId);
5833
+ }
5834
+ /** Turns taken on and not yet settled, waiting ones included. */
5835
+ get pendingTurns() {
5836
+ return this.pending.size;
5837
+ }
5838
+ /**
5839
+ * Whether a compaction is running, from its start until its end callback: the
5840
+ * host must not see the compaction turn's events, `status: idle` included.
5841
+ */
5842
+ get isCompacting() {
5843
+ return this.suppressedBy !== null;
5844
+ }
5845
+ /**
5846
+ * The hooks one compaction orchestrator wires to take part in scheduling: it
5847
+ * claims the driver before it starts, holds user turns off from its start
5848
+ * until it has settled, and suppresses turn events from its start until its
5849
+ * end. Call once per orchestrator; a newer call retires the hooks before it,
5850
+ * so a stale orchestrator (its driver replaced by a swap) can no longer
5851
+ * start a compaction.
5852
+ */
5853
+ compactionHooks() {
5854
+ const generation = ++this.hooksGeneration;
5855
+ const superseded = () => generation !== this.hooksGeneration;
5856
+ let hold = null;
5642
5857
  return {
5643
- ok: false,
5644
- code: "skill_detach_failed",
5645
- message: err instanceof Error ? err.message : String(err)
5858
+ // A user turn that already holds a slot keeps the driver; the compaction
5859
+ // waits for it rather than prompting the driver under it. A platform call
5860
+ // waits briefly: a turn paused on a question can hold its slot for hours.
5861
+ claimDriver: async (trigger) => {
5862
+ if (superseded()) {
5863
+ this.deps.log("[serve] compaction skipped: its driver has been replaced");
5864
+ return null;
5865
+ }
5866
+ return claimDriverForCompaction({
5867
+ gate: this.compactions,
5868
+ awaitClaimedTurns: () => this.swaps.awaitActiveTurn(),
5869
+ isDriverReplaced: () => this.swaps.isSwapping() || superseded(),
5870
+ claimTurnSlot: () => this.swaps.beginTurn(),
5871
+ log: this.deps.log,
5872
+ timeoutMs: compactionTurnWaitFor(trigger)
5873
+ });
5874
+ },
5875
+ onCompactionStart: (trigger) => {
5876
+ hold = this.compactions.begin();
5877
+ this.suppressedBy = hold;
5878
+ this.deps.sendEvent({ type: "status", phase: "compacting" });
5879
+ this.deps.log(`[serve] compaction started (trigger=${trigger})`);
5880
+ },
5881
+ onCompactionEnd: () => {
5882
+ if (hold === null || this.suppressedBy !== hold) return;
5883
+ this.suppressedBy = null;
5884
+ this.snapshotTurns.add(hold);
5885
+ this.reportIdleIfDrained("compaction");
5886
+ },
5887
+ onCompactionSettled: () => {
5888
+ if (hold !== null && this.suppressedBy === hold) this.suppressedBy = null;
5889
+ if (hold !== null) this.snapshotTurns.delete(hold);
5890
+ this.compactions.settle(hold);
5891
+ hold = null;
5892
+ }
5646
5893
  };
5647
5894
  }
5648
- }
5649
- async function pathState(path6) {
5650
- try {
5651
- await withFsDeadline(`lstat ${path6}`, () => lstat(path6));
5652
- return "present";
5653
- } catch (err) {
5654
- return err?.code === "ENOENT" ? "absent" : "unknown";
5655
- }
5656
- }
5657
- async function removeUnlistedStagedSkills(deps, skillsDir) {
5658
- const allowed = await readSkillAllowList(deps.projectDir);
5659
- if (!allowed) return [];
5660
- const root = join(deps.projectDir, skillsDir);
5661
- const entries = await tryWithFsDeadline(
5662
- `readdir ${root}`,
5663
- () => readdir(root, { withFileTypes: true }),
5664
- []
5665
- );
5666
- const removed = [];
5667
- for (const entry of entries) {
5668
- if (!entry.isDirectory() || allowed.has(entry.name)) continue;
5669
- try {
5670
- const dir = join(root, entry.name);
5671
- if (await pathState(join(deps.projectDir, ".skaile/assets/skill", entry.name)) !== "absent") {
5672
- continue;
5895
+ async runPrompt(turn, leaveQueue) {
5896
+ if (!await turn.admit()) return;
5897
+ await this.swaps.awaitSwap();
5898
+ if (!await this.awaitCompactionIdle("prompt")) return;
5899
+ const handOff = await turn.route();
5900
+ if (handOff === false) return;
5901
+ if (handOff) {
5902
+ leaveQueue();
5903
+ try {
5904
+ await handOff();
5905
+ } finally {
5906
+ this.reportIdleIfDrained("turn");
5673
5907
  }
5674
- const knownStaged = await isStillOurs(deps.stagedSkillDirs.get(entry.name), dir);
5675
- if (!knownStaged && !await isStagedSkillMarkerFor(dir, entry.name).catch(() => false))
5676
- continue;
5677
- const result = await unstageSkill(deps.projectDir, skillsDir, entry.name, {
5678
- knownStaged,
5679
- keepAsset: true
5908
+ return;
5909
+ }
5910
+ const startedAt = Date.now();
5911
+ let ok = false;
5912
+ let attempts = 0;
5913
+ let endTurn;
5914
+ try {
5915
+ endTurn = await this.claim("prompt", () => {
5916
+ attempts += 1;
5917
+ return this.deps.ensureDriverStarted();
5680
5918
  });
5681
- if ("reason" in result || !result.removedStaged) continue;
5682
- deps.stagedSkillDirs.delete(result.name);
5683
- removed.push(result.name);
5919
+ ok = endTurn !== null;
5684
5920
  } catch (err) {
5685
- deps.log(
5686
- `[serve] could not remove unlisted skill "${entry.name}" (left in place): ${err instanceof Error ? err.message : String(err)}`
5687
- );
5921
+ const message = errorMessage2(err);
5922
+ this.deps.log(`[serve] driver start failed: ${message}`);
5923
+ this.deps.sendEvent({
5924
+ type: "error",
5925
+ message: `Driver start failed: ${message}`,
5926
+ fatal: true
5927
+ });
5928
+ return;
5929
+ } finally {
5930
+ this.deps.logPhase("driver_start", startedAt, { ok, attempts });
5688
5931
  }
5689
- }
5690
- return removed;
5691
- }
5692
-
5693
- // runner/src/flow-turn-dispatch.ts
5694
- var FLOW_TURN_COMPACTION_TIMEOUT = "Flow turn abandoned: a compaction held the driver";
5695
- async function dispatchFlowTurn(deps, prompt, timeoutMs) {
5696
- for (; ; ) {
5697
- await deps.gate.awaitSwap();
5698
- if (!await deps.awaitCompactionIdle()) throw new Error(FLOW_TURN_COMPACTION_TIMEOUT);
5699
- const endTurn = await deps.gate.beginQueuedTurn();
5700
- if (deps.gate.isSwapping() || deps.isCompacting()) {
5932
+ if (!endTurn) return;
5933
+ try {
5934
+ await turn.dispatch();
5935
+ } catch (err) {
5936
+ const message = errorMessage2(err);
5937
+ this.deps.log(`[serve] prompt failed: ${message}`);
5938
+ this.deps.sendEvent({ type: "error", message: `Prompt failed: ${message}`, fatal: true });
5939
+ } finally {
5701
5940
  endTurn();
5702
- continue;
5703
5941
  }
5942
+ }
5943
+ /** Claim a turn slot on a live driver no swap or compaction occupies. `null`: turn abandoned. */
5944
+ claim(what, prepare) {
5945
+ return beginTurnClearOfCompaction({
5946
+ gate: this.compactions,
5947
+ awaitIdle: () => this.awaitCompactionIdle(what),
5948
+ claimTurn: () => this.swaps.beginTurnOnLiveDriver(prepare)
5949
+ });
5950
+ }
5951
+ /** `false` when a compaction held the driver past its bound; the abandon is already reported. */
5952
+ awaitCompactionIdle(what) {
5953
+ return guardTurnAgainstCompaction({
5954
+ gate: this.compactions,
5955
+ what,
5956
+ log: this.deps.log,
5957
+ sendEvent: this.deps.sendEvent
5958
+ });
5959
+ }
5960
+ /** Count a turn from receipt until its handler settles, so waiting turns count as queued. */
5961
+ async counted(run) {
5962
+ const end = this.pending.begin();
5704
5963
  try {
5705
- await deps.ensureDriverStarted();
5706
- await awaitAgentEnd(deps.getDriver(), prompt, timeoutMs);
5707
- return;
5964
+ return await run();
5708
5965
  } finally {
5709
- endTurn();
5966
+ end();
5710
5967
  }
5711
5968
  }
5969
+ /** Idle unless a compaction suppresses events or more turns are queued, in which case it is owed. */
5970
+ reportIdleIfDrained(endedBy) {
5971
+ if (this.suppressedBy) return;
5972
+ if (this.pending.shouldReportIdle(endedBy)) this.sendIdle();
5973
+ }
5974
+ /** The only `status: idle` emit site. Silent while a compaction suppresses turn events. */
5975
+ sendIdle() {
5976
+ if (this.suppressedBy) return;
5977
+ this.deps.sendEvent({ type: "status", phase: "idle" });
5978
+ }
5979
+ };
5980
+ function errorMessage2(err) {
5981
+ return err instanceof Error ? err.message : String(err);
5982
+ }
5983
+ function replyFailed(err) {
5984
+ return { type: "error", message: `Reply failed: ${errorMessage2(err)}`, fatal: false };
5985
+ }
5986
+ function freshTurnReplyPrompt(answer, question) {
5987
+ const asked = question?.replace(/\s+/g, " ").trim();
5988
+ if (!asked) return answer;
5989
+ return `${answer}
5990
+
5991
+ (The answer above is to your question "${asked}")`;
5712
5992
  }
5713
5993
  function awaitAgentEnd(driver, prompt, timeoutMs) {
5714
5994
  return new Promise((resolve4, reject) => {
@@ -5737,25 +6017,6 @@ function awaitAgentEnd(driver, prompt, timeoutMs) {
5737
6017
  });
5738
6018
  }
5739
6019
 
5740
- // runner/src/reply-routing.ts
5741
- async function routeReply(deps) {
5742
- const current = deps.getDriver();
5743
- if (current.hasPendingQuestion()) {
5744
- if (!current.answerQuestion(deps.answer, deps.question, deps.requestId)) return "fresh-turn";
5745
- deps.onAnswered?.();
5746
- return "answered";
5747
- }
5748
- await deps.awaitSwap();
5749
- return "fresh-turn";
5750
- }
5751
- function freshTurnReplyPrompt(answer, question) {
5752
- const asked = question?.replace(/\s+/g, " ").trim();
5753
- if (!asked) return answer;
5754
- return `${answer}
5755
-
5756
- (The answer above is to your question "${asked}")`;
5757
- }
5758
-
5759
6020
  // runner/src/event-gap-buffer.ts
5760
6021
  var EVENT_GAP_BUFFER_MAX_EVENTS = 1e4;
5761
6022
  var EVENT_GAP_BUFFER_MAX_BYTES = 16 * 1024 * 1024;
@@ -6738,7 +6999,8 @@ function selectClaudeCodeCredentialsSecret(secrets, selection) {
6738
6999
  const legacy = secrets[CLAUDE_CODE_CREDENTIALS_KEY];
6739
7000
  if (legacy) return { key: CLAUDE_CODE_CREDENTIALS_KEY, value: legacy };
6740
7001
  if (!selection?.registry) return void 0;
6741
- if (selection.driver && selection.driver !== "claude-sdk") return void 0;
7002
+ if (selection.driver && !driverCapabilities(selection.driver).claudeCodeCredentials)
7003
+ return void 0;
6742
7004
  const entries = registryEntries(selection.registry).map(
6743
7005
  ([id, entry2]) => [id, { ...entry2, kind: entryKind(entry2) }]
6744
7006
  );
@@ -8480,9 +8742,6 @@ function pickRepointedManager(next, current, disposed) {
8480
8742
  if (current !== null && current === disposed) return null;
8481
8743
  return current;
8482
8744
  }
8483
- function supportsLiveToolUpdates(driverType, managedCodex = false) {
8484
- return driverType !== "claude-sdk" && !(driverType === "codex" && managedCodex);
8485
- }
8486
8745
  function buildResourcesAvailablePayload(manager, mcpManager, driverLive, bakedServerIds) {
8487
8746
  const { mounts, connectors } = splitConnectorsForWire(manager);
8488
8747
  const mcp_servers = (mcpManager?.listServers() ?? []).map((s) => ({
@@ -8491,19 +8750,16 @@ function buildResourcesAvailablePayload(manager, mcpManager, driverLive, bakedSe
8491
8750
  }));
8492
8751
  return { type: "resources_available", mounts, connectors, mcp_servers, sessionRoot: true };
8493
8752
  }
8494
- function isTerminalFlowStatus(status) {
8495
- return status === "complete" || status === "cancelled";
8496
- }
8497
8753
  function hasNonTerminalFlow(flows) {
8498
8754
  for (const f of flows) {
8499
- if (!isTerminalFlowStatus(f.adapter.getExecution(f.handle).status)) return true;
8755
+ if (!f.adapter.turnRule(f.handle).terminal) return true;
8500
8756
  }
8501
8757
  return false;
8502
8758
  }
8503
8759
  function registerActiveFlow(flows, runId, entry) {
8504
8760
  const removed = [];
8505
8761
  for (const [key, existing] of flows) {
8506
- if (isTerminalFlowStatus(existing.adapter.getExecution(existing.handle).status)) {
8762
+ if (existing.adapter.turnRule(existing.handle).terminal) {
8507
8763
  flows.delete(key);
8508
8764
  removed.push(key);
8509
8765
  }
@@ -8515,21 +8771,18 @@ function pickFlowToolTarget(flows, manager) {
8515
8771
  let latest;
8516
8772
  for (const entry of flows) latest = entry;
8517
8773
  if (!latest || !manager) return null;
8518
- if (isTerminalFlowStatus(latest.adapter.getExecution(latest.handle).status)) return null;
8774
+ if (latest.adapter.turnRule(latest.handle).terminal) return null;
8519
8775
  return { manager, connectorId: latest.connectorId };
8520
8776
  }
8521
- function flowRunDrivesTurns(execution) {
8522
- return !(execution.done || execution.status === "failed" || isTerminalFlowStatus(execution.status));
8523
- }
8524
8777
  function pickChatFlowTarget(flows) {
8525
8778
  let latest;
8526
8779
  for (const entry of flows) latest = entry;
8527
8780
  if (!latest) return null;
8528
- if (!flowRunDrivesTurns(latest.adapter.getExecution(latest.handle))) return null;
8781
+ if (!latest.adapter.turnRule(latest.handle).acceptsTurn) return null;
8529
8782
  return latest;
8530
8783
  }
8531
8784
  function flowStartNeedsDriverRestart(state) {
8532
- return state.driverStarted && state.driverType === "claude-sdk" && !state.flowToolsBaked;
8785
+ return state.driverStarted && driverCapabilities(state.driverType).inProcessMcpServers && !state.flowToolsBaked;
8533
8786
  }
8534
8787
  async function setUpFlowConnector(deps) {
8535
8788
  const recreated = await deps.recreateForFlowTools();
@@ -8540,8 +8793,8 @@ async function setUpFlowConnector(deps) {
8540
8793
  async function recreateKeepingLiveFlows(flows, deps) {
8541
8794
  const live = [];
8542
8795
  for (const { runId, connectorId, flowDef, adapter, handle } of flows) {
8796
+ if (adapter.turnRule(handle).terminal) continue;
8543
8797
  const execution = adapter.getExecution(handle);
8544
- if (isTerminalFlowStatus(execution.status)) continue;
8545
8798
  live.push({ runId, connectorId, flowDef, execution: structuredClone(execution) });
8546
8799
  }
8547
8800
  await deps.recreate();
@@ -8562,7 +8815,7 @@ async function recreateKeepingLiveFlows(flows, deps) {
8562
8815
  return reconnected;
8563
8816
  }
8564
8817
  function reconnectedRunNeedsAgentTurn(state) {
8565
- return state.cutDriverWork && state.wantsAgentTurn && !state.busHasTurn && !state.promptQueuedForRun;
8818
+ return state.cutDriverWork && state.restoreKick === "agent_work" && !state.busHasTurn && !state.promptQueuedForRun;
8566
8819
  }
8567
8820
  var DRIVER_ACTIVITY_EVENTS = /* @__PURE__ */ new Set([
8568
8821
  "message_start",
@@ -8965,11 +9218,11 @@ function toActiveFlowTarget(entry) {
8965
9218
  runId: entry.runId,
8966
9219
  connectorId: entry.connectorId,
8967
9220
  hydratedStateChanged: entry.hydratedStateChanged,
8968
- hasRuntimeWork: entry.adapter.hasRuntimeWork(entry.handle)
9221
+ restoreKick: entry.adapter.turnRule(entry.handle).restoreKick
8969
9222
  };
8970
9223
  }
8971
9224
  function restoredRunHasWorkToResume(target) {
8972
- return target.hydratedStateChanged === true || target.hasRuntimeWork === true;
9225
+ return target.hydratedStateChanged === true || target.restoreKick === "runtime_work";
8973
9226
  }
8974
9227
  async function executeConnectorMutate(cmd, deps) {
8975
9228
  let acked = false;
@@ -9158,7 +9411,7 @@ async function applyConnectorMutate(cmd, deps, respond, connectorWaitMs) {
9158
9411
  } else if (cmd.op === "hydrate") {
9159
9412
  const active = deps.flowState().activeFlow;
9160
9413
  const changed = typeof result === "string" && JSON.stringify(payload.state) !== result;
9161
- if (active && (changed || active.hasRuntimeWork === true)) {
9414
+ if (active && (changed || active.restoreKick === "runtime_work")) {
9162
9415
  deps.signalStimulus(active, { kind: "resumed_after_hibernation" });
9163
9416
  }
9164
9417
  }
@@ -9577,7 +9830,7 @@ async function startAgentServer(opts) {
9577
9830
  return {
9578
9831
  projectDir: opts.projectDir,
9579
9832
  agentDir,
9580
- driver: managedCodex ? "codex" : opts.driver ?? wireAgentConfig?.driver,
9833
+ driver: managedCodex ? wireAgentConfig?.driver : opts.driver ?? wireAgentConfig?.driver,
9581
9834
  model: managedCodex ? wireAgentConfig?.model : opts.model ?? wireAgentConfig?.model,
9582
9835
  // The control-plane registry layer, normalized to the bare `id → entry`
9583
9836
  // map the session builder layers `providers.yml` under.
@@ -9893,18 +10146,17 @@ async function startAgentServer(opts) {
9893
10146
  }
9894
10147
  const normalizer = new EventNormalizer();
9895
10148
  function forwardNormalizedEvent(event) {
9896
- if (compacting) return;
10149
+ if (turnScheduler.isCompacting) return;
9897
10150
  contextUsage.observeEvent(event);
9898
- const isTransient = event.type === "status" || event.type === "sync_status" || event.type === "resources_available" || event.type === "resource_response" || event.type === "commands_available";
9899
- if (!isTransient) {
10151
+ if (deliveryClassOf(event.type) === "persisted") {
9900
10152
  eventSeq++;
9901
10153
  compactionOrchestrator?.trackMessage(eventSeq);
9902
10154
  }
9903
10155
  if (event.type === "finished") {
9904
10156
  scheduleContextUsageEmit("turn-end");
9905
- if (!compacting && compactionOrchestrator?.shouldCompact()) {
10157
+ if (!turnScheduler.isCompacting && compactionOrchestrator?.shouldCompact()) {
9906
10158
  const compactionTimer = setTimeout(() => {
9907
- if (compacting || !compactionOrchestrator?.shouldCompact()) return;
10159
+ if (turnScheduler.isCompacting || !compactionOrchestrator?.shouldCompact()) return;
9908
10160
  compactionOrchestrator.compact("threshold").catch((err) => {
9909
10161
  log(
9910
10162
  `[serve] auto-compaction failed: ${err instanceof Error ? err.message : String(err)}`
@@ -9927,12 +10179,13 @@ async function startAgentServer(opts) {
9927
10179
  }
9928
10180
  let driverStarted = false;
9929
10181
  let driverStartInFlight = null;
9930
- const driverSwapGate = new DriverSwapGate();
9931
- const compactionGate = new CompactionGate();
9932
- const pendingTurns = new PendingTurns(() => {
9933
- if (!compacting) sendEvent({ type: "status", phase: "idle" });
10182
+ const turnScheduler = new TurnScheduler({
10183
+ ensureDriverStarted,
10184
+ getDriver: () => driver,
10185
+ sendEvent,
10186
+ log,
10187
+ logPhase
9934
10188
  });
9935
- const promptTurns = new PromptTurnQueue();
9936
10189
  let driverRestartChain = Promise.resolve();
9937
10190
  let liveDriverActiveAfterTurn = false;
9938
10191
  let driver = secretsMode === "env" ? agentSession.driver : void 0;
@@ -9975,8 +10228,6 @@ async function startAgentServer(opts) {
9975
10228
  };
9976
10229
  sendEvent(runtimeSessionEvent);
9977
10230
  }
9978
- let compacting = false;
9979
- let suppressedBy = null;
9980
10231
  let compactionOrchestrator = null;
9981
10232
  const compactionConfig = wsConfig.compaction;
9982
10233
  function scheduleContextUsageEmit(trigger) {
@@ -9991,18 +10242,13 @@ async function startAgentServer(opts) {
9991
10242
  }
9992
10243
  function rebuildCompactionOrchestrator() {
9993
10244
  if (!driver) return;
9994
- let gateHold = null;
9995
10245
  compactionOrchestrator = new CompactionOrchestrator({
9996
10246
  driver,
9997
10247
  config: compactionConfig,
9998
10248
  contextWindows,
9999
- onCompactionStart: (trigger) => {
10000
- compacting = true;
10001
- gateHold = compactionGate.begin();
10002
- suppressedBy = gateHold;
10003
- sendEvent({ type: "status", phase: "compacting" });
10004
- log(`[serve] compaction started (trigger=${trigger})`);
10005
- },
10249
+ // Start, end, settled and the driver claim: the scheduler owns the holds,
10250
+ // the event suppression and the `status` phases around a compaction.
10251
+ ...turnScheduler.compactionHooks(),
10006
10252
  onSnapshot: (snapshot) => {
10007
10253
  sendEvent(snapshot);
10008
10254
  contextUsage.onCompaction(snapshot.summary);
@@ -10011,27 +10257,6 @@ async function startAgentServer(opts) {
10011
10257
  onCompactionAttempt: (event) => {
10012
10258
  sendEvent(event);
10013
10259
  },
10014
- onCompactionEnd: () => {
10015
- if (suppressedBy !== gateHold) return;
10016
- compacting = false;
10017
- suppressedBy = null;
10018
- sendEvent({ type: "status", phase: "idle" });
10019
- },
10020
- onCompactionSettled: () => {
10021
- compactionGate.settle(gateHold);
10022
- gateHold = null;
10023
- },
10024
- // A user turn that already holds a slot keeps the driver; the compaction
10025
- // waits for it rather than prompting the driver under it. A platform call
10026
- // waits briefly: a turn paused on a question can hold its slot for hours.
10027
- claimDriver: (trigger) => claimDriverForCompaction({
10028
- gate: compactionGate,
10029
- awaitClaimedTurns: () => driverSwapGate.awaitActiveTurn(),
10030
- isSwapping: () => driverSwapGate.isSwapping(),
10031
- claimTurnSlot: () => driverSwapGate.beginTurn(),
10032
- log,
10033
- timeoutMs: compactionTurnWaitFor(trigger)
10034
- }),
10035
10260
  onLog: (line) => log(`[serve] ${line}`),
10036
10261
  // Phase 3: stamp every CompactionAttemptEvent with the registry's
10037
10262
  // current signature so wake-time tier-1 selection has the input it
@@ -10078,7 +10303,8 @@ async function startAgentServer(opts) {
10078
10303
  const normalized = normalizer.normalize(event);
10079
10304
  const turnEnded = event.type === "agent_end";
10080
10305
  for (const e of normalized) {
10081
- if (turnEnded && !compacting && e.type === "status" && e.phase === "idle" && !pendingTurns.shouldReportIdle()) {
10306
+ if (turnEnded && e.type === "status" && e.phase === "idle") {
10307
+ turnScheduler.reportTurnEnd();
10082
10308
  continue;
10083
10309
  }
10084
10310
  forwardNormalizedEvent(e);
@@ -10118,7 +10344,6 @@ async function startAgentServer(opts) {
10118
10344
  const stimulus = stimulusFromMetas(metas);
10119
10345
  await entry.adapter.drainRuntimeNodes(entry.handle);
10120
10346
  const execution = entry.adapter.getExecution(entry.handle);
10121
- if (!flowRunDrivesTurns(execution)) return;
10122
10347
  if (!entry.adapter.shouldDriveAgentTurn(entry.handle, stimulus)) return;
10123
10348
  await ensureFlowDriverStarted();
10124
10349
  await driveOrchestratorTurn({
@@ -10126,42 +10351,13 @@ async function startAgentServer(opts) {
10126
10351
  execution,
10127
10352
  stimulus,
10128
10353
  emit: sendEvent,
10129
- deliver: (prompt) => awaitFlowAgentEnd(prompt, FLOW_TURN_TIMEOUT_MS)
10354
+ deliver: (prompt) => turnScheduler.flowTurn(prompt, FLOW_TURN_TIMEOUT_MS)
10130
10355
  });
10131
10356
  },
10132
10357
  log: serverLog
10133
10358
  });
10134
10359
  return stimulusBus;
10135
10360
  }
10136
- function awaitFlowAgentEnd(prompt, timeoutMs) {
10137
- return countPendingTurn(
10138
- () => dispatchFlowTurn(
10139
- {
10140
- gate: driverSwapGate,
10141
- awaitCompactionIdle: () => awaitCompactionIdle("flow turn"),
10142
- isCompacting: () => !compactionGate.isIdle(),
10143
- ensureDriverStarted,
10144
- getDriver: () => driver
10145
- },
10146
- prompt,
10147
- timeoutMs
10148
- )
10149
- );
10150
- }
10151
- function activeFlowWantsAgentTurn(runId) {
10152
- const entry = activeFlows.get(runId);
10153
- if (!entry) return false;
10154
- if (!flowRunDrivesTurns(entry.adapter.getExecution(entry.handle))) return false;
10155
- return entry.adapter.shouldDriveAgentTurn(entry.handle, { kind: "resumed_after_hibernation" });
10156
- }
10157
- async function countPendingTurn(run) {
10158
- const end = pendingTurns.begin();
10159
- try {
10160
- return await run();
10161
- } finally {
10162
- end();
10163
- }
10164
- }
10165
10361
  function ensureResourceManagerForFlow() {
10166
10362
  if (!resourceManager) {
10167
10363
  registerBuiltinConnectors();
@@ -10259,7 +10455,7 @@ async function startAgentServer(opts) {
10259
10455
  execution,
10260
10456
  stimulus,
10261
10457
  emit: sendEvent,
10262
- deliver: (prompt) => awaitFlowAgentEnd(prompt, FLOW_TURN_TIMEOUT_MS)
10458
+ deliver: (prompt) => turnScheduler.flowTurn(prompt, FLOW_TURN_TIMEOUT_MS)
10263
10459
  });
10264
10460
  }
10265
10461
  });
@@ -10305,7 +10501,7 @@ async function startAgentServer(opts) {
10305
10501
  execute: (op, args) => adapter.executeOp(handle, op, args),
10306
10502
  mandatoryGates: () => adapter.getMandatoryAgentApprovalNodeIds(handle)
10307
10503
  };
10308
- if (agentSession?.driverType === "claude-sdk") {
10504
+ if (driverCapabilities(agentSession?.driverType).inProcessMcpServers) {
10309
10505
  try {
10310
10506
  const server = await buildSdkConnectorTools(manager, { z: z });
10311
10507
  const flowServer = flowToolsBaked ? null : await buildSdkFlowTools(manager, connectorId, { z: z });
@@ -10327,7 +10523,7 @@ async function startAgentServer(opts) {
10327
10523
  log(`[serve] failed to rebuild MCP tools for flow: ${errMsg}`);
10328
10524
  }
10329
10525
  }
10330
- if (agentSession?.driverType === "codex" && !driver.acceptsReplyAsPrompt) {
10526
+ if (driverCapabilities(agentSession?.driverType).managedSession && !driver.acceptsReplyAsPrompt) {
10331
10527
  removeCodexFlowTools?.();
10332
10528
  removeCodexFlowTools = registerCodexFlowTools(capabilityRegistry, manager, connectorId);
10333
10529
  }
@@ -10592,7 +10788,7 @@ async function startAgentServer(opts) {
10592
10788
  return { needsWireFallbackRecreate, needsWireAgentConfigRecreate };
10593
10789
  }
10594
10790
  async function recreateAgentSession(overrides) {
10595
- return driverSwapGate.runSwap(async () => {
10791
+ return turnScheduler.runSwap(async () => {
10596
10792
  const resolved = typeof overrides === "function" ? overrides() : overrides;
10597
10793
  if (!resolved) return false;
10598
10794
  await recreateAgentSessionInner(resolved);
@@ -10616,10 +10812,10 @@ async function startAgentServer(opts) {
10616
10812
  needsAgentTurn: (run) => {
10617
10813
  const needed = reconnectedRunNeedsAgentTurn({
10618
10814
  cutDriverWork,
10619
- wantsAgentTurn: activeFlowWantsAgentTurn(run.runId),
10815
+ restoreKick: run.restoreKick ?? null,
10620
10816
  busHasTurn: stimulusBus?.hasTurn(run.connectorId) ?? false,
10621
10817
  // Approximate: a waiting reply counts too. A prompt reaches one run only.
10622
- promptQueuedForRun: pendingTurns.size > 0 && pickChatFlowTarget(activeFlows.values())?.runId === run.runId
10818
+ promptQueuedForRun: turnScheduler.pendingTurns > 0 && pickChatFlowTarget(activeFlows.values())?.runId === run.runId
10623
10819
  });
10624
10820
  if (needed) redriven.push(run.runId);
10625
10821
  return needed;
@@ -10822,7 +11018,7 @@ async function startAgentServer(opts) {
10822
11018
  }
10823
11019
  }
10824
11020
  async function rebuildMcpToolsForNewStores(storesRegistered) {
10825
- if (!(storesRegistered > 0 && !driverStarted && agentSession?.driverType === "claude-sdk")) {
11021
+ if (!(storesRegistered > 0 && !driverStarted && driverCapabilities(agentSession?.driverType).inProcessMcpServers)) {
10826
11022
  return;
10827
11023
  }
10828
11024
  try {
@@ -10974,13 +11170,15 @@ async function startAgentServer(opts) {
10974
11170
  }
10975
11171
  try {
10976
11172
  validateCodexInit(cmd, supportedRuntimeFeatures, runtimeIdentity ?? void 0);
10977
- const wantsManaged = cmd.resolvedConfig.agentConfig?.driver === "codex";
11173
+ const wantsManaged = driverCapabilities(
11174
+ cmd.resolvedConfig.agentConfig?.driver
11175
+ ).managedSession;
10978
11176
  if (managedHost && !wantsManaged) throw new Error("AI_PROFILE_INVALID");
10979
11177
  if (managedHost && wantsManaged) {
10980
11178
  if (managedBootstrapClosed || agentSession && !managedInitFingerprint || cmd.secrets && CLAUDE_CODE_CREDENTIALS_KEY in cmd.secrets)
10981
11179
  throw new Error("AI_PROFILE_INVALID");
10982
11180
  const profile2 = cmd.resolvedConfig.agentConfig;
10983
- if (opts.driver && opts.driver !== "codex" || opts.provider && opts.provider !== "openai" || opts.model && opts.model !== profile2.model)
11181
+ if (opts.driver && opts.driver !== profile2.driver || opts.provider && opts.provider !== "openai" || opts.model && opts.model !== profile2.model)
10984
11182
  throw new Error("AI_PROFILE_INVALID");
10985
11183
  const initialCredential = parseCodexCredential(cmd.credentials.ai);
10986
11184
  const binding = bindManagedCodexInit(managedHost, cmd, async (input, signal) => {
@@ -11089,7 +11287,7 @@ async function startAgentServer(opts) {
11089
11287
  settings = { driver: driver2 ?? profile?.driver, model: model ?? profile?.model };
11090
11288
  }
11091
11289
  credentialsSelection = {
11092
- driver: settings.driver ?? "omp",
11290
+ driver: settings.driver ?? DEFAULT_DRIVER_ID,
11093
11291
  registry: wireAgentConfig?.registry,
11094
11292
  modelRef: wireAgentConfig?.modelRef?.trim() || settings.model?.trim() || void 0
11095
11293
  };
@@ -11138,7 +11336,7 @@ async function startAgentServer(opts) {
11138
11336
  let pendingResumeSessionId;
11139
11337
  const cfgResumeSessionId = cfg.resumeSessionId;
11140
11338
  const cfgExpectedSig = cfg.expectedCapabilitySignature;
11141
- const resumeTargetDriver = managedCodex ? "codex" : opts.driver ?? wireAgentConfig?.driver ?? agentSession?.driverType;
11339
+ const resumeTargetDriver = (managedCodex ? void 0 : opts.driver) ?? wireAgentConfig?.driver ?? agentSession?.driverType;
11142
11340
  if (cfgResumeSessionId) {
11143
11341
  const currentSig = computeCapabilitySignature(capabilityRegistry.list());
11144
11342
  if (cfgExpectedSig && cfgExpectedSig !== currentSig) {
@@ -11153,7 +11351,7 @@ async function startAgentServer(opts) {
11153
11351
  resumeSessionId: cfgResumeSessionId,
11154
11352
  reason: "signature_mismatch"
11155
11353
  });
11156
- } else if (resumeProbe === "jsonl_lost" && resumeTargetDriver === "claude-sdk") {
11354
+ } else if (resumeProbe === "jsonl_lost" && driverCapabilities(resumeTargetDriver).resumeNeedsTranscript) {
11157
11355
  log(`[serve] tier-1 resume skipped: no transcript for ${cfgResumeSessionId}`);
11158
11356
  sendEvent({
11159
11357
  type: "resume_failed",
@@ -11250,129 +11448,88 @@ async function startAgentServer(opts) {
11250
11448
  }
11251
11449
  });
11252
11450
  }
11253
- const awaitCompactionIdle = (what) => guardTurnAgainstCompaction({ gate: compactionGate, what, log, sendEvent });
11254
11451
  async function handlePrompt(cmd) {
11255
11452
  if (cmd.messageId) sendEvent({ type: "prompt_ack", messageId: cmd.messageId });
11256
- const place = promptTurns.join({ senderId: cmd.senderId, messageId: cmd.messageId });
11257
- try {
11258
- if (place.queued) {
11259
- driver?.supersedePendingQuestion?.();
11260
- const queuedAt = Date.now();
11261
- await place.ready;
11262
- logPhase("prompt_queue_wait", queuedAt, { dropped: place.dropped });
11263
- if (place.dropped) return;
11264
- }
11265
- await runPromptTurn(cmd, place.leave);
11266
- } finally {
11267
- place.leave();
11268
- }
11269
- }
11270
- async function runPromptTurn(cmd, leaveQueue) {
11271
- const promptReceivedAt = Date.now();
11272
- const sessionIsReady = await awaitSessionReadyOrFail();
11273
- logPhase("prompt_gate_wait", promptReceivedAt, { ready: sessionIsReady });
11274
- if (!sessionIsReady) return;
11275
- if (!secretsProvisioned) {
11276
- log("[serve] prompt received before secrets provisioned \u2014 rejecting");
11277
- sendEvent({
11278
- type: "error",
11279
- message: "Secrets not yet provisioned \u2014 send provision_secrets first",
11280
- fatal: false
11281
- });
11282
- return;
11283
- }
11284
- log(`[serve] prompt: ${cmd.prompt.slice(0, 80)}...`);
11285
- contextUsage.observeUserPrompt(cmd.prompt);
11286
- await driverSwapGate.awaitSwap();
11287
- if (!await awaitCompactionIdle("prompt")) return;
11288
- await restageMaterializedSkills(true);
11289
- try {
11290
- await rebuildForLateMcpDeclarations({
11291
- driverStarted: () => driverStarted,
11292
- unloadedMcpDeclarationIds: () => agentSession.unloadedMcpDeclarationIds(),
11293
- resumeSessionId: () => agentSession.resumeSessionId,
11294
- recreate: (overrides) => recreateAgentSession(overrides),
11295
- log,
11296
- warn: (line) => serverLog.warn(line)
11297
- });
11298
- } catch (err) {
11299
- const errMsg = err instanceof Error ? err.message : String(err);
11300
- serverLog.warn(`[serve] session rebuild for late MCP servers failed: ${errMsg}`);
11301
- sendEvent({ type: "error", message: `Session rebuild failed: ${errMsg}`, fatal: true });
11302
- return;
11303
- }
11304
- const activeFlow = pickChatFlowTarget(activeFlows.values());
11305
- if (activeFlow) {
11306
- leaveQueue();
11307
- sendEvent({ type: "status", phase: "thinking" });
11308
- try {
11309
- const bus = getOrCreateStimulusBus();
11310
- const userStimulus = {
11311
- kind: "user_message",
11312
- text: cmd.prompt,
11313
- senderId: "user"
11314
- };
11315
- await bus.signal(activeFlow.connectorId, {
11316
- promptFragment: renderStimulusPrompt(userStimulus),
11317
- meta: {
11318
- kind: "user_message",
11319
- runId: activeFlow.runId,
11320
- text: cmd.prompt,
11321
- senderId: "user"
11453
+ await turnScheduler.prompt({
11454
+ owner: { senderId: cmd.senderId, messageId: cmd.messageId },
11455
+ // The turn ahead may be paused on a question it can only leave through
11456
+ // this driver's rule for a new prompt; apply it now, not after that turn.
11457
+ onQueued: () => driver?.supersedePendingQuestion?.(),
11458
+ admit: async () => {
11459
+ const promptReceivedAt = Date.now();
11460
+ const sessionIsReady = await awaitSessionReadyOrFail();
11461
+ logPhase("prompt_gate_wait", promptReceivedAt, { ready: sessionIsReady });
11462
+ if (!sessionIsReady) return false;
11463
+ if (!secretsProvisioned) {
11464
+ log("[serve] prompt received before secrets provisioned \u2014 rejecting");
11465
+ sendEvent({
11466
+ type: "error",
11467
+ message: "Secrets not yet provisioned \u2014 send provision_secrets first",
11468
+ fatal: false
11469
+ });
11470
+ return false;
11471
+ }
11472
+ log(`[serve] prompt: ${cmd.prompt.slice(0, 80)}...`);
11473
+ contextUsage.observeUserPrompt(cmd.prompt);
11474
+ return true;
11475
+ },
11476
+ route: async () => {
11477
+ await restageMaterializedSkills(true);
11478
+ try {
11479
+ await rebuildForLateMcpDeclarations({
11480
+ driverStarted: () => driverStarted,
11481
+ unloadedMcpDeclarationIds: () => agentSession.unloadedMcpDeclarationIds(),
11482
+ resumeSessionId: () => agentSession.resumeSessionId,
11483
+ recreate: (overrides) => recreateAgentSession(overrides),
11484
+ log,
11485
+ warn: (line) => serverLog.warn(line)
11486
+ });
11487
+ } catch (err) {
11488
+ const errMsg = err instanceof Error ? err.message : String(err);
11489
+ serverLog.warn(`[serve] session rebuild for late MCP servers failed: ${errMsg}`);
11490
+ sendEvent({ type: "error", message: `Session rebuild failed: ${errMsg}`, fatal: true });
11491
+ return false;
11492
+ }
11493
+ const activeFlow = pickChatFlowTarget(activeFlows.values());
11494
+ if (!activeFlow) return null;
11495
+ return async () => {
11496
+ sendEvent({ type: "status", phase: "thinking" });
11497
+ try {
11498
+ const bus = getOrCreateStimulusBus();
11499
+ const userStimulus = {
11500
+ kind: "user_message",
11501
+ text: cmd.prompt,
11502
+ senderId: "user"
11503
+ };
11504
+ await bus.signal(activeFlow.connectorId, {
11505
+ promptFragment: renderStimulusPrompt(userStimulus),
11506
+ meta: {
11507
+ kind: "user_message",
11508
+ runId: activeFlow.runId,
11509
+ text: cmd.prompt,
11510
+ senderId: "user"
11511
+ }
11512
+ });
11513
+ } catch (err) {
11514
+ const errMsg = err instanceof Error ? err.message : String(err);
11515
+ log(`[serve] flow user-message turn failed: ${errMsg}`);
11516
+ sendEvent({ type: "error", message: `Flow turn failed: ${errMsg}`, fatal: false });
11322
11517
  }
11323
- });
11324
- } catch (err) {
11325
- const errMsg = err instanceof Error ? err.message : String(err);
11326
- log(`[serve] flow user-message turn failed: ${errMsg}`);
11327
- sendEvent({ type: "error", message: `Flow turn failed: ${errMsg}`, fatal: false });
11328
- } finally {
11329
- if (pendingTurns.shouldReportIdle()) sendEvent({ type: "status", phase: "idle" });
11518
+ };
11519
+ },
11520
+ dispatch: async () => {
11521
+ sendEvent({ type: "status", phase: "thinking" });
11522
+ await driver.promptInput({ text: cmd.prompt, attachments: cmd.attachments });
11330
11523
  }
11331
- return;
11332
- }
11333
- const driverStartStartedAt = Date.now();
11334
- let driverStartOk = false;
11335
- let driverStartAttempts = 0;
11336
- let endTurn;
11337
- try {
11338
- endTurn = await beginTurnClearOfCompaction({
11339
- gate: compactionGate,
11340
- awaitIdle: () => awaitCompactionIdle("prompt"),
11341
- claimTurn: () => driverSwapGate.beginTurnOnLiveDriver(() => {
11342
- driverStartAttempts += 1;
11343
- return ensureDriverStarted();
11344
- })
11345
- });
11346
- driverStartOk = endTurn !== null;
11347
- } catch (err) {
11348
- const errMsg = err instanceof Error ? err.message : String(err);
11349
- log(`[serve] driver start failed: ${errMsg}`);
11350
- sendEvent({ type: "error", message: `Driver start failed: ${errMsg}`, fatal: true });
11351
- return;
11352
- } finally {
11353
- logPhase("driver_start", driverStartStartedAt, {
11354
- ok: driverStartOk,
11355
- attempts: driverStartAttempts
11356
- });
11357
- }
11358
- if (!endTurn) return;
11359
- sendEvent({ type: "status", phase: "thinking" });
11360
- try {
11361
- await driver.promptInput({ text: cmd.prompt, attachments: cmd.attachments });
11362
- } catch (err) {
11363
- const errMsg = err instanceof Error ? err.message : String(err);
11364
- log(`[serve] prompt failed: ${errMsg}`);
11365
- sendEvent({ type: "error", message: `Prompt failed: ${errMsg}`, fatal: true });
11366
- } finally {
11367
- endTurn();
11368
- }
11524
+ });
11369
11525
  }
11370
11526
  async function handleReply(cmd) {
11371
- if (!await awaitSessionReadyOrFail()) return;
11372
- log(`[serve] reply: ${cmd.answer.slice(0, 80)}...`);
11373
- const routed = await routeReply({
11374
- getDriver: () => driver,
11375
- awaitSwap: () => driverSwapGate.awaitSwap(),
11527
+ await turnScheduler.reply({
11528
+ admit: async () => {
11529
+ if (!await awaitSessionReadyOrFail()) return false;
11530
+ log(`[serve] reply: ${cmd.answer.slice(0, 80)}...`);
11531
+ return true;
11532
+ },
11376
11533
  answer: cmd.answer,
11377
11534
  question: cmd.question,
11378
11535
  requestId: cmd.requestId,
@@ -11385,49 +11542,10 @@ async function startAgentServer(opts) {
11385
11542
  ...cmd.requestId !== void 0 ? { requestId: cmd.requestId } : {}
11386
11543
  })
11387
11544
  });
11388
- if (routed === "answered") return;
11389
- if (!driver.acceptsReplyAsPrompt) {
11390
- if (!driver.hasPendingQuestion()) {
11391
- log("[serve] reply: driver takes no reply as a prompt; answer not delivered");
11392
- sendEvent({
11393
- type: "error",
11394
- message: "This question is no longer open, so the agent did not get your answer. Send it as a new message.",
11395
- fatal: false
11396
- });
11397
- }
11398
- return;
11399
- }
11400
- let endTurn;
11401
- try {
11402
- endTurn = await beginTurnClearOfCompaction({
11403
- gate: compactionGate,
11404
- awaitIdle: () => awaitCompactionIdle("reply"),
11405
- claimTurn: () => driverSwapGate.beginTurnOnLiveDriver(ensureDriverStarted)
11406
- });
11407
- } catch (err) {
11408
- sendEvent({
11409
- type: "error",
11410
- message: `Reply failed: ${err instanceof Error ? err.message : String(err)}`,
11411
- fatal: false
11412
- });
11413
- return;
11414
- }
11415
- if (!endTurn) return;
11416
- try {
11417
- await driver.prompt(freshTurnReplyPrompt(cmd.answer, cmd.question));
11418
- } catch (err) {
11419
- sendEvent({
11420
- type: "error",
11421
- message: `Reply failed: ${err instanceof Error ? err.message : String(err)}`,
11422
- fatal: false
11423
- });
11424
- } finally {
11425
- endTurn();
11426
- }
11427
11545
  }
11428
11546
  async function handleCancel(cmd) {
11429
11547
  if (cmd.senderId) {
11430
- const dropped = promptTurns.dropQueuedFrom(cmd.senderId);
11548
+ const dropped = turnScheduler.dropQueuedPromptsFrom(cmd.senderId);
11431
11549
  if (dropped.length > 0) {
11432
11550
  log(`[serve] cancel dropped ${dropped.length} queued prompt(s) of the presser`);
11433
11551
  sendEvent({
@@ -11703,10 +11821,10 @@ async function startAgentServer(opts) {
11703
11821
  await handleSessionInit(cmd);
11704
11822
  break;
11705
11823
  case "prompt":
11706
- await countPendingTurn(() => handlePrompt(cmd));
11824
+ await handlePrompt(cmd);
11707
11825
  break;
11708
11826
  case "reply":
11709
- await countPendingTurn(() => handleReply(cmd));
11827
+ await handleReply(cmd);
11710
11828
  break;
11711
11829
  case "cancel":
11712
11830
  await handleCancel(cmd);
@@ -11815,7 +11933,7 @@ async function startAgentServer(opts) {
11815
11933
  }
11816
11934
  function emitAvailability() {
11817
11935
  if (resourceManager || agentSession?.getExternalMcpManager()) {
11818
- const driverLive = agentSession?.driverType !== "claude-sdk";
11936
+ const driverLive = driverCapabilities(agentSession?.driverType).liveToolUpdates;
11819
11937
  const payload = buildResourcesAvailablePayload(
11820
11938
  resourceManager,
11821
11939
  agentSession?.getExternalMcpManager() ?? null,
@@ -12015,6 +12133,6 @@ function touchSession(state) {
12015
12133
  return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
12016
12134
  }
12017
12135
 
12018
- export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CONNECTOR_MUTATE_NOT_READY, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, DEFAULT_FLOW_MUTATE_CONNECTOR_WAIT_MS, MOUNT_LIST_MAX_DEPTH, MOUNT_LIST_MAX_ENTRIES, MOUNT_READ_DEADLINE_FACTOR, MOUNT_READ_MAX_CHUNK_BYTES, MOUNT_STAT_BUDGET_MS, MOUNT_STAT_MAX_ENTRIES, MOUNT_TREE_OP_DEADLINE_FACTOR, MOUNT_WRITE_MAX_CHUNK_BYTES, MarkdownStreamer, PreInitRingSink, ResourceOperationError, SESSION_ROOT_WRITABLE_DIRS, SESSION_ROOT_WRITABLE_FILES, WRITE_RANGE_PARTIAL_TTL_MS, WS_AUTH_TOKEN_ENV, WS_AUTH_TOKEN_FILE_ENV, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildConnectorTokenMediator, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, buildStoreSnapshotReplay, builtinCapabilities, capabilityLogInstance, capabilitySignatureInputs, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, computeDirectoryTotals, connectorRefreshKind, createAgentSession, createFlowConnectorReadiness, createManagedCodexSubpromptDriver, createSessionStimulusBus, defineCapability, deleteSession, dispatchResourceRequest, dispatchRunnerCapabilityInvocation, driverActiveAfterTurnEnd, emitSystemPromptComposed, ensureClaudeSettingsDisablesConnectors, ensureGitConfigInclude, executeConnectorMutate, extractClaudeAiOauthExpiresAt, flowRunDrivesTurns, flowStartNeedsDriverRestart, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, handleSessionRootResourceRequest, hasNonTerminalFlow, hostOpResumeStimulus, installPreInitRingSink, isSessionRootPathAllowed, isTerminalFlowStatus, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadManagedCodexHostConfig, loadSession, loadSessionById, mcpAuthSecretKey, newSession, nulTailPaddingLength, pickChatFlowTarget, pickFlowToolTarget, pickRepointedManager, planFlowMutate, prepareCodexTools, reconcilePendingDecisions, reconnectedRunNeedsAgentTurn, recreateKeepingLiveFlows, registerActiveFlow, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, rejectPendingCapabilityCallsOnDisconnect, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveFlowMutateConnectorWaitMs, resolveMixin, restoredRunHasWorkToResume, runAgentChat, saveSession, setCurrentSession, setUpFlowConnector, startAgentServer, stimulusFromMetas, supportsLiveToolUpdates, takeRunnerWsAuthToken, toActiveFlowTarget, touchSession, validateInputResponse, writeClaudeCodeCredentialsFile, writeRangeChunk, writeRangePartialPath };
12019
- //# sourceMappingURL=chunk-KWP4RVTJ.js.map
12020
- //# sourceMappingURL=chunk-KWP4RVTJ.js.map
12136
+ export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CONNECTOR_MUTATE_NOT_READY, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, DEFAULT_FLOW_MUTATE_CONNECTOR_WAIT_MS, MOUNT_LIST_MAX_DEPTH, MOUNT_LIST_MAX_ENTRIES, MOUNT_READ_DEADLINE_FACTOR, MOUNT_READ_MAX_CHUNK_BYTES, MOUNT_STAT_BUDGET_MS, MOUNT_STAT_MAX_ENTRIES, MOUNT_TREE_OP_DEADLINE_FACTOR, MOUNT_WRITE_MAX_CHUNK_BYTES, MarkdownStreamer, PreInitRingSink, ResourceOperationError, SESSION_ROOT_WRITABLE_DIRS, SESSION_ROOT_WRITABLE_FILES, WRITE_RANGE_PARTIAL_TTL_MS, WS_AUTH_TOKEN_ENV, WS_AUTH_TOKEN_FILE_ENV, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildConnectorTokenMediator, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, buildStoreSnapshotReplay, builtinCapabilities, capabilityLogInstance, capabilitySignatureInputs, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, computeDirectoryTotals, connectorRefreshKind, createAgentSession, createFlowConnectorReadiness, createManagedCodexSubpromptDriver, createSessionStimulusBus, defineCapability, deleteSession, dispatchResourceRequest, dispatchRunnerCapabilityInvocation, driverActiveAfterTurnEnd, emitSystemPromptComposed, ensureClaudeSettingsDisablesConnectors, ensureGitConfigInclude, executeConnectorMutate, extractClaudeAiOauthExpiresAt, flowStartNeedsDriverRestart, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, handleSessionRootResourceRequest, hasNonTerminalFlow, hostOpResumeStimulus, installPreInitRingSink, isSessionRootPathAllowed, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadManagedCodexHostConfig, loadSession, loadSessionById, mcpAuthSecretKey, newSession, nulTailPaddingLength, pickChatFlowTarget, pickFlowToolTarget, pickRepointedManager, planFlowMutate, prepareCodexTools, reconcilePendingDecisions, reconnectedRunNeedsAgentTurn, recreateKeepingLiveFlows, registerActiveFlow, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, rejectPendingCapabilityCallsOnDisconnect, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveFlowMutateConnectorWaitMs, resolveMixin, restoredRunHasWorkToResume, runAgentChat, saveSession, setCurrentSession, setUpFlowConnector, startAgentServer, stimulusFromMetas, takeRunnerWsAuthToken, toActiveFlowTarget, touchSession, validateInputResponse, writeClaudeCodeCredentialsFile, writeRangeChunk, writeRangePartialPath };
12137
+ //# sourceMappingURL=chunk-D63AJVBW.js.map
12138
+ //# sourceMappingURL=chunk-D63AJVBW.js.map