@skaile/workspaces 6.1.0 → 6.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 (406) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/ai-sdk.d.ts +2 -0
  3. package/dist/ai-sdk.js +111 -0
  4. package/dist/ai-sdk.js.map +1 -0
  5. package/dist/{asset-feeds-HJFV7UPW.js → asset-feeds-3YO2352Y.js} +26 -26
  6. package/dist/{asset-feeds-HJFV7UPW.js.map → asset-feeds-3YO2352Y.js.map} +1 -1
  7. package/dist/asset-manager/catalog-deployer.js +10 -10
  8. package/dist/asset-manager/fragments.js +1 -1
  9. package/dist/asset-manager/index.js +18 -18
  10. package/dist/asset-manager/installer.js +13 -13
  11. package/dist/asset-manager/renderers.js +11 -11
  12. package/dist/asset-manager/src/index.d.ts +149 -16
  13. package/dist/asset-manager/src/index.d.ts.map +1 -1
  14. package/dist/asset-manager/src/installer.d.ts +9 -0
  15. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  16. package/dist/asset-manager/src/renderers.d.ts +7 -0
  17. package/dist/asset-manager/src/renderers.d.ts.map +1 -1
  18. package/dist/bridge/harnesses/claude-sdk.js +16 -15
  19. package/dist/bridge/harnesses/claude-sdk.js.map +1 -1
  20. package/dist/bridge/harnesses/codex.js +25 -17
  21. package/dist/bridge/harnesses/codex.js.map +1 -1
  22. package/dist/bridge/harnesses/continue.js +15 -14
  23. package/dist/bridge/harnesses/continue.js.map +1 -1
  24. package/dist/bridge/harnesses/echo.js +5 -4
  25. package/dist/bridge/harnesses/echo.js.map +1 -1
  26. package/dist/bridge/harnesses/gemini.js +11 -10
  27. package/dist/bridge/harnesses/goose.js +15 -14
  28. package/dist/bridge/harnesses/goose.js.map +1 -1
  29. package/dist/bridge/harnesses/omp.js +16 -8
  30. package/dist/bridge/harnesses/omp.js.map +1 -1
  31. package/dist/bridge/harnesses/opencode.js +15 -14
  32. package/dist/bridge/harnesses/opencode.js.map +1 -1
  33. package/dist/bridge/harnesses/qwen.js +11 -10
  34. package/dist/bridge/harnesses/qwen.js.map +1 -1
  35. package/dist/bridge/index.js +21 -19
  36. package/dist/bridge/src/ai-sdk.d.ts +46 -0
  37. package/dist/bridge/src/ai-sdk.d.ts.map +1 -0
  38. package/dist/bridge/src/harness-model-check.d.ts +15 -0
  39. package/dist/bridge/src/harness-model-check.d.ts.map +1 -1
  40. package/dist/bridge/src/harnesses/_subprocess-cli.d.ts.map +1 -1
  41. package/dist/bridge/src/harnesses/codex.d.ts.map +1 -1
  42. package/dist/bridge/src/harnesses/omp.d.ts.map +1 -1
  43. package/dist/bridge/src/index.d.ts +2 -1
  44. package/dist/bridge/src/index.d.ts.map +1 -1
  45. package/dist/bridge/src/provider-registry-load.d.ts +30 -0
  46. package/dist/bridge/src/provider-registry-load.d.ts.map +1 -0
  47. package/dist/bridge/src/runner-private-env.d.ts +7 -0
  48. package/dist/bridge/src/runner-private-env.d.ts.map +1 -1
  49. package/dist/{chunk-SVTMNSPI.js → chunk-2TFKXSB5.js} +5 -5
  50. package/dist/{chunk-SVTMNSPI.js.map → chunk-2TFKXSB5.js.map} +1 -1
  51. package/dist/{chunk-NB7SYQYP.js → chunk-32FYVSSW.js} +9 -28
  52. package/dist/chunk-32FYVSSW.js.map +1 -0
  53. package/dist/{chunk-QAKUD6QN.js → chunk-4QRJBY2P.js} +3 -3
  54. package/dist/{chunk-QAKUD6QN.js.map → chunk-4QRJBY2P.js.map} +1 -1
  55. package/dist/{chunk-XFIEVEU7.js → chunk-6OHZUUR7.js} +5 -4
  56. package/dist/chunk-6OHZUUR7.js.map +1 -0
  57. package/dist/{chunk-ILLTBKDJ.js → chunk-6UP2EDFN.js} +4 -313
  58. package/dist/chunk-6UP2EDFN.js.map +1 -0
  59. package/dist/{chunk-ZDLUQLI6.js → chunk-6WH2WE4B.js} +15 -5
  60. package/dist/chunk-6WH2WE4B.js.map +1 -0
  61. package/dist/{chunk-HPMQRAIF.js → chunk-72NT2TJU.js} +8 -7
  62. package/dist/chunk-72NT2TJU.js.map +1 -0
  63. package/dist/{chunk-E572OHGY.js → chunk-76FLBODK.js} +4 -3
  64. package/dist/chunk-76FLBODK.js.map +1 -0
  65. package/dist/{chunk-5Y2KGB4H.js → chunk-7MV3NHPT.js} +35 -9
  66. package/dist/chunk-7MV3NHPT.js.map +1 -0
  67. package/dist/{chunk-QEULL4Q3.js → chunk-7QG2WRSN.js} +77 -18
  68. package/dist/chunk-7QG2WRSN.js.map +1 -0
  69. package/dist/{chunk-6YR4ALVX.js → chunk-7RH6E332.js} +7 -7
  70. package/dist/{chunk-6YR4ALVX.js.map → chunk-7RH6E332.js.map} +1 -1
  71. package/dist/{chunk-BBBCJSSU.js → chunk-7TSNR5H5.js} +4 -4
  72. package/dist/{chunk-BBBCJSSU.js.map → chunk-7TSNR5H5.js.map} +1 -1
  73. package/dist/{chunk-3GMOPFWH.js → chunk-AMJ6KEV7.js} +4 -4
  74. package/dist/{chunk-3GMOPFWH.js.map → chunk-AMJ6KEV7.js.map} +1 -1
  75. package/dist/{chunk-X3YGUKCG.js → chunk-BPTWWKGF.js} +3 -3
  76. package/dist/{chunk-X3YGUKCG.js.map → chunk-BPTWWKGF.js.map} +1 -1
  77. package/dist/{chunk-Z7ZEZZB6.js → chunk-C5HFK34M.js} +3 -3
  78. package/dist/chunk-C5HFK34M.js.map +1 -0
  79. package/dist/{chunk-EJPMNDTP.js → chunk-COUJOTAJ.js} +3 -3
  80. package/dist/{chunk-EJPMNDTP.js.map → chunk-COUJOTAJ.js.map} +1 -1
  81. package/dist/{chunk-J72MO2WA.js → chunk-DU26AVK2.js} +10 -9
  82. package/dist/chunk-DU26AVK2.js.map +1 -0
  83. package/dist/{chunk-YLLVSR2U.js → chunk-E5NQRHEB.js} +30 -7
  84. package/dist/chunk-E5NQRHEB.js.map +1 -0
  85. package/dist/{chunk-XGULGQA3.js → chunk-ELSGFI3I.js} +5 -4
  86. package/dist/chunk-ELSGFI3I.js.map +1 -0
  87. package/dist/{chunk-IHFGPHCT.js → chunk-EQNIBBB6.js} +49 -25
  88. package/dist/chunk-EQNIBBB6.js.map +1 -0
  89. package/dist/{chunk-BFMYYNDT.js → chunk-F3D25RGM.js} +11 -3
  90. package/dist/chunk-F3D25RGM.js.map +1 -0
  91. package/dist/{chunk-GNZBFSRB.js → chunk-H622YULS.js} +5 -4
  92. package/dist/chunk-H622YULS.js.map +1 -0
  93. package/dist/{chunk-FKQNBCDW.js → chunk-HDVLBEEX.js} +4 -4
  94. package/dist/{chunk-FKQNBCDW.js.map → chunk-HDVLBEEX.js.map} +1 -1
  95. package/dist/{chunk-AATHJRKL.js → chunk-HGOJEVHY.js} +4 -4
  96. package/dist/{chunk-AATHJRKL.js.map → chunk-HGOJEVHY.js.map} +1 -1
  97. package/dist/{chunk-CEKW3KXP.js → chunk-HH2H2ZV7.js} +18 -15
  98. package/dist/chunk-HH2H2ZV7.js.map +1 -0
  99. package/dist/{chunk-ZFUZ5AKM.js → chunk-HTGTNN2B.js} +3 -3
  100. package/dist/{chunk-ZFUZ5AKM.js.map → chunk-HTGTNN2B.js.map} +1 -1
  101. package/dist/{chunk-LSSYC5IC.js → chunk-IZQOO6MN.js} +2 -2
  102. package/dist/{chunk-LSSYC5IC.js.map → chunk-IZQOO6MN.js.map} +1 -1
  103. package/dist/{chunk-VMVDAZLA.js → chunk-J5JRGBKK.js} +108 -19
  104. package/dist/chunk-J5JRGBKK.js.map +1 -0
  105. package/dist/{chunk-7LP7RCZI.js → chunk-JGH7NB47.js} +5 -5
  106. package/dist/{chunk-7LP7RCZI.js.map → chunk-JGH7NB47.js.map} +1 -1
  107. package/dist/{chunk-RHN5MRQO.js → chunk-JMIKGAUA.js} +27 -5
  108. package/dist/chunk-JMIKGAUA.js.map +1 -0
  109. package/dist/{chunk-HWNK3F3X.js → chunk-KGHYXXXV.js} +588 -76
  110. package/dist/chunk-KGHYXXXV.js.map +1 -0
  111. package/dist/{chunk-7HX6FNKL.js → chunk-KIPCBIFJ.js} +41 -56
  112. package/dist/chunk-KIPCBIFJ.js.map +1 -0
  113. package/dist/{chunk-ZBHZLWV3.js → chunk-KPKGWXUJ.js} +4 -4
  114. package/dist/{chunk-ZBHZLWV3.js.map → chunk-KPKGWXUJ.js.map} +1 -1
  115. package/dist/{chunk-ABFPSVIS.js → chunk-LD6O6QKU.js} +31 -7
  116. package/dist/chunk-LD6O6QKU.js.map +1 -0
  117. package/dist/{chunk-AZ2H6R5I.js → chunk-LEJQAX7G.js} +74 -39
  118. package/dist/chunk-LEJQAX7G.js.map +1 -0
  119. package/dist/{chunk-ZAELRYKS.js → chunk-MD3FUZS3.js} +3 -3
  120. package/dist/{chunk-ZAELRYKS.js.map → chunk-MD3FUZS3.js.map} +1 -1
  121. package/dist/{chunk-NUA33BYO.js → chunk-MYXFR27L.js} +42 -15
  122. package/dist/chunk-MYXFR27L.js.map +1 -0
  123. package/dist/{chunk-KUQAJVYT.js → chunk-PHAMYCZH.js} +142 -28
  124. package/dist/chunk-PHAMYCZH.js.map +1 -0
  125. package/dist/{chunk-NOA6EJXE.js → chunk-PKE3PXOK.js} +3 -3
  126. package/dist/{chunk-NOA6EJXE.js.map → chunk-PKE3PXOK.js.map} +1 -1
  127. package/dist/{chunk-RDTLPOPD.js → chunk-PL52CI4U.js} +4 -4
  128. package/dist/{chunk-RDTLPOPD.js.map → chunk-PL52CI4U.js.map} +1 -1
  129. package/dist/{chunk-VYVTEMAW.js → chunk-PNUM7GUY.js} +3 -3
  130. package/dist/{chunk-VYVTEMAW.js.map → chunk-PNUM7GUY.js.map} +1 -1
  131. package/dist/{chunk-DIGFA7Z5.js → chunk-Q7CU5GQO.js} +13 -5
  132. package/dist/chunk-Q7CU5GQO.js.map +1 -0
  133. package/dist/chunk-QFFMFZIR.js +32 -0
  134. package/dist/chunk-QFFMFZIR.js.map +1 -0
  135. package/dist/{chunk-HMISULVD.js → chunk-QK7AG5AV.js} +4 -4
  136. package/dist/{chunk-HMISULVD.js.map → chunk-QK7AG5AV.js.map} +1 -1
  137. package/dist/{chunk-2LAPHLDH.js → chunk-QTLUZUF2.js} +45 -35
  138. package/dist/chunk-QTLUZUF2.js.map +1 -0
  139. package/dist/{chunk-4MUDQCBP.js → chunk-RFQONXET.js} +3 -3
  140. package/dist/{chunk-4MUDQCBP.js.map → chunk-RFQONXET.js.map} +1 -1
  141. package/dist/{chunk-AITJ7ELM.js → chunk-ROVZCGTN.js} +59 -23
  142. package/dist/chunk-ROVZCGTN.js.map +1 -0
  143. package/dist/{chunk-LSI2IVFT.js → chunk-RXGPFAMN.js} +4 -3
  144. package/dist/chunk-RXGPFAMN.js.map +1 -0
  145. package/dist/chunk-S6KZHPR4.js +315 -0
  146. package/dist/chunk-S6KZHPR4.js.map +1 -0
  147. package/dist/{chunk-EX3GLAL6.js → chunk-TGV2EWGL.js} +5 -5
  148. package/dist/{chunk-EX3GLAL6.js.map → chunk-TGV2EWGL.js.map} +1 -1
  149. package/dist/{chunk-QSYQOTWN.js → chunk-TO5SSMRI.js} +58 -5
  150. package/dist/chunk-TO5SSMRI.js.map +1 -0
  151. package/dist/{chunk-Z3VKUWAX.js → chunk-TSTRH4SM.js} +3 -3
  152. package/dist/{chunk-Z3VKUWAX.js.map → chunk-TSTRH4SM.js.map} +1 -1
  153. package/dist/{chunk-5J4NPGFM.js → chunk-U3SXCVR7.js} +5 -5
  154. package/dist/{chunk-5J4NPGFM.js.map → chunk-U3SXCVR7.js.map} +1 -1
  155. package/dist/{chunk-IRYKRKVQ.js → chunk-URCJIV7T.js} +3 -3
  156. package/dist/{chunk-IRYKRKVQ.js.map → chunk-URCJIV7T.js.map} +1 -1
  157. package/dist/{chunk-ASWTQQ7E.js → chunk-V5BPDB4J.js} +3 -3
  158. package/dist/{chunk-ASWTQQ7E.js.map → chunk-V5BPDB4J.js.map} +1 -1
  159. package/dist/{chunk-ADPM6AYF.js → chunk-VSX2G7LA.js} +3 -3
  160. package/dist/{chunk-ADPM6AYF.js.map → chunk-VSX2G7LA.js.map} +1 -1
  161. package/dist/{chunk-4FVIT5DI.js → chunk-VUWRGMT6.js} +3 -3
  162. package/dist/{chunk-4FVIT5DI.js.map → chunk-VUWRGMT6.js.map} +1 -1
  163. package/dist/{chunk-ZHGKAZJ7.js → chunk-XBQTXGY4.js} +56 -8
  164. package/dist/chunk-XBQTXGY4.js.map +1 -0
  165. package/dist/{chunk-UI745XC3.js → chunk-XEVFSDIF.js} +13 -7
  166. package/dist/chunk-XEVFSDIF.js.map +1 -0
  167. package/dist/{chunk-S2XHGWQC.js → chunk-Y3I4KGLX.js} +44 -15
  168. package/dist/chunk-Y3I4KGLX.js.map +1 -0
  169. package/dist/{chunk-COYF6IG2.js → chunk-YW4ASEUP.js} +5 -5
  170. package/dist/{chunk-COYF6IG2.js.map → chunk-YW4ASEUP.js.map} +1 -1
  171. package/dist/{chunk-DGTI65OC.js → chunk-ZEH4WFEG.js} +17 -11
  172. package/dist/chunk-ZEH4WFEG.js.map +1 -0
  173. package/dist/{claude-code-RE46FJXI.js → claude-code-EUKDGOOO.js} +5 -5
  174. package/dist/{claude-code-RE46FJXI.js.map → claude-code-EUKDGOOO.js.map} +1 -1
  175. package/dist/cli/index.js +350 -141
  176. package/dist/cli/index.js.map +1 -1
  177. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  178. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  179. package/dist/cli/src/commands/config.d.ts.map +1 -1
  180. package/dist/cli/src/commands/diff.d.ts.map +1 -1
  181. package/dist/cli/src/commands/harness.d.ts.map +1 -1
  182. package/dist/cli/src/commands/integration.d.ts.map +1 -1
  183. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  184. package/dist/cli/src/commands/library-index.d.ts +8 -1
  185. package/dist/cli/src/commands/library-index.d.ts.map +1 -1
  186. package/dist/cli/src/commands/migrate-assets.d.ts.map +1 -1
  187. package/dist/cli/src/commands/outdated.d.ts.map +1 -1
  188. package/dist/cli/src/commands/plugin-registry-cmd.d.ts.map +1 -1
  189. package/dist/cli/src/commands/project.d.ts.map +1 -1
  190. package/dist/cli/src/commands/providers.d.ts.map +1 -1
  191. package/dist/cli/src/commands/rebuild.d.ts.map +1 -1
  192. package/dist/cli/src/commands/run.d.ts.map +1 -1
  193. package/dist/cli/src/commands/serve-preflight.d.ts +31 -1
  194. package/dist/cli/src/commands/serve-preflight.d.ts.map +1 -1
  195. package/dist/cli/src/commands/serve.d.ts +10 -0
  196. package/dist/cli/src/commands/serve.d.ts.map +1 -1
  197. package/dist/cli/src/commands/source-manifest-publish.d.ts.map +1 -1
  198. package/dist/cli/src/commands/source-manifest.d.ts +19 -7
  199. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
  200. package/dist/cli/src/commands/validate-instances.d.ts.map +1 -1
  201. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  202. package/dist/cli/src/commands/why.d.ts.map +1 -1
  203. package/dist/cli/src/config-checks.d.ts +23 -5
  204. package/dist/cli/src/config-checks.d.ts.map +1 -1
  205. package/dist/cli/src/harness-error.d.ts +12 -1
  206. package/dist/cli/src/harness-error.d.ts.map +1 -1
  207. package/dist/cli/src/helpers.d.ts +18 -8
  208. package/dist/cli/src/helpers.d.ts.map +1 -1
  209. package/dist/cli/src/plugin-store/index.d.ts +10 -1
  210. package/dist/cli/src/plugin-store/index.d.ts.map +1 -1
  211. package/dist/cli/src/plugin-store/spec.d.ts +8 -0
  212. package/dist/cli/src/plugin-store/spec.d.ts.map +1 -1
  213. package/dist/cli/src/skill-checks.d.ts +2 -2
  214. package/dist/cli/src/skill-checks.d.ts.map +1 -1
  215. package/dist/connectors/config.js +5 -5
  216. package/dist/connectors/index.js +24 -22
  217. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  218. package/dist/connectors-XYPE2DCQ.js +50 -0
  219. package/dist/{connectors-7THEF7YA.js.map → connectors-XYPE2DCQ.js.map} +1 -1
  220. package/dist/core/framework.js +1 -1
  221. package/dist/core/index.js +9 -9
  222. package/dist/core/manifest.js +2 -2
  223. package/dist/core/models.js +1 -1
  224. package/dist/core/provider-registry-credentials.js +2 -2
  225. package/dist/core/provider-registry.js +1 -1
  226. package/dist/core/publish-manifest.js +3 -3
  227. package/dist/core/ref.js +1 -1
  228. package/dist/core/runtime-assets.js +5 -5
  229. package/dist/core/src/framework.d.ts +5 -3
  230. package/dist/core/src/framework.d.ts.map +1 -1
  231. package/dist/core/src/index.d.ts +2 -1
  232. package/dist/core/src/index.d.ts.map +1 -1
  233. package/dist/core/src/lock.d.ts +12 -0
  234. package/dist/core/src/lock.d.ts.map +1 -1
  235. package/dist/core/src/manifest.d.ts +15 -0
  236. package/dist/core/src/manifest.d.ts.map +1 -1
  237. package/dist/core/src/models.d.ts +7 -0
  238. package/dist/core/src/models.d.ts.map +1 -1
  239. package/dist/core/src/provider-registry.d.ts +6 -0
  240. package/dist/core/src/provider-registry.d.ts.map +1 -1
  241. package/dist/core/src/workspace-config.d.ts +10 -1
  242. package/dist/core/src/workspace-config.d.ts.map +1 -1
  243. package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -1
  244. package/dist/core/workspace-config.js +4 -4
  245. package/dist/deploy/index.js +9 -9
  246. package/dist/discovery/index.js +5 -5
  247. package/dist/discovery/src/parse-manifest.d.ts.map +1 -1
  248. package/dist/{ensure-sources-IH7CHSJF.js → ensure-sources-IN3VKHUA.js} +37 -21
  249. package/dist/ensure-sources-IN3VKHUA.js.map +1 -0
  250. package/dist/factory-assets/connectors/box.js +24 -22
  251. package/dist/factory-assets/connectors/deploy.js +24 -22
  252. package/dist/factory-assets/connectors/devserver.js +24 -22
  253. package/dist/factory-assets/connectors/flow/adapter.js +24 -22
  254. package/dist/factory-assets/connectors/flow/engine.js +10 -10
  255. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  256. package/dist/factory-assets/connectors/flow/run-flow.js +26 -24
  257. package/dist/factory-assets/connectors/flow.js +24 -22
  258. package/dist/factory-assets/connectors/git.js +24 -22
  259. package/dist/factory-assets/connectors/gmail.js +24 -22
  260. package/dist/factory-assets/connectors/googledrive.js +24 -22
  261. package/dist/factory-assets/connectors/local.js +24 -22
  262. package/dist/factory-assets/connectors/mattermost.js +24 -22
  263. package/dist/factory-assets/connectors/memory.js +24 -22
  264. package/dist/factory-assets/connectors/minio.js +24 -22
  265. package/dist/factory-assets/connectors/postgres.js +24 -22
  266. package/dist/factory-assets/connectors/s3.js +24 -22
  267. package/dist/factory-assets/connectors/sharepoint.js +24 -22
  268. package/dist/factory-assets/connectors/sqlite.js +24 -22
  269. package/dist/factory-assets/connectors/static-server.js +24 -22
  270. package/dist/factory-assets/connectors/tunnel.js +24 -22
  271. package/dist/factory-assets/connectors/webdav.js +24 -22
  272. package/dist/factory-assets/connectors/xstate-store.js +24 -22
  273. package/dist/factory-assets/connectors/xstate.js +24 -22
  274. package/dist/flows-QAO63TDV.js +26 -0
  275. package/dist/{flows-4JZQ3XFK.js.map → flows-QAO63TDV.js.map} +1 -1
  276. package/dist/helpers-HDVGCF3M.js +54 -0
  277. package/dist/{helpers-JNMK3FC2.js.map → helpers-HDVGCF3M.js.map} +1 -1
  278. package/dist/library/index.js +14 -14
  279. package/dist/library/install.js +5 -5
  280. package/dist/library/src/index.d.ts +1 -1
  281. package/dist/library/src/index.d.ts.map +1 -1
  282. package/dist/library/src/install/index.d.ts +1 -1
  283. package/dist/library/src/install/index.d.ts.map +1 -1
  284. package/dist/library/src/install/install-from-manifest.d.ts +13 -0
  285. package/dist/library/src/install/install-from-manifest.d.ts.map +1 -1
  286. package/dist/library/src/install/source-fetch-github.d.ts.map +1 -1
  287. package/dist/library/src/manifest-writer.d.ts.map +1 -1
  288. package/dist/library/src/remote/remote-catalog-source.d.ts +3 -1
  289. package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
  290. package/dist/library/src/remote/rest-catalog-source.d.ts +3 -2
  291. package/dist/library/src/remote/rest-catalog-source.d.ts.map +1 -1
  292. package/dist/{library-publish-I3UWXAHI.js → library-publish-62OWCNB5.js} +56 -55
  293. package/dist/library-publish-62OWCNB5.js.map +1 -0
  294. package/dist/model-endpoint/index.js +13 -12
  295. package/dist/model-endpoint/src/openai-chat.d.ts +7 -2
  296. package/dist/model-endpoint/src/openai-chat.d.ts.map +1 -1
  297. package/dist/model-endpoint/src/openai-shared.d.ts +8 -0
  298. package/dist/model-endpoint/src/openai-shared.d.ts.map +1 -1
  299. package/dist/model-endpoint/src/server.d.ts.map +1 -1
  300. package/dist/model-endpoint/src/types.d.ts +1 -1
  301. package/dist/model-endpoint/src/types.d.ts.map +1 -1
  302. package/dist/model-endpoint/src/usage-cost.d.ts +23 -0
  303. package/dist/model-endpoint/src/usage-cost.d.ts.map +1 -0
  304. package/dist/open-library-TZ7OSDEJ.js +58 -0
  305. package/dist/{open-library-NKKUJLWA.js.map → open-library-TZ7OSDEJ.js.map} +1 -1
  306. package/dist/open-registry-RLZKTJG3.js +32 -0
  307. package/dist/{open-registry-BYAXSHUI.js.map → open-registry-RLZKTJG3.js.map} +1 -1
  308. package/dist/paths-D6LBQETQ.js +22 -0
  309. package/dist/{paths-UKWE35XS.js.map → paths-D6LBQETQ.js.map} +1 -1
  310. package/dist/plugin-store-A5J4TLCH.js +23 -0
  311. package/dist/{plugin-store-ABE35NRX.js.map → plugin-store-A5J4TLCH.js.map} +1 -1
  312. package/dist/project-4AVRES3M.js +88 -0
  313. package/dist/{project-BIPK47JK.js.map → project-4AVRES3M.js.map} +1 -1
  314. package/dist/resolver/index.js +10 -10
  315. package/dist/runner/index.js +41 -39
  316. package/dist/runner/src/capability-roundtrip.d.ts +7 -6
  317. package/dist/runner/src/capability-roundtrip.d.ts.map +1 -1
  318. package/dist/runner/src/serve.d.ts +6 -5
  319. package/dist/runner/src/serve.d.ts.map +1 -1
  320. package/dist/sdk/asset-manager.js +18 -18
  321. package/dist/sdk/bridge.js +21 -19
  322. package/dist/sdk/core.js +9 -9
  323. package/dist/sdk/flow.js +10 -10
  324. package/dist/sdk/index.js +41 -39
  325. package/dist/sdk/index.js.map +1 -1
  326. package/dist/sdk/resolver.js +10 -10
  327. package/dist/sdk/runner.js +41 -39
  328. package/dist/sdk/transport/ws/server.js +10 -10
  329. package/dist/sdk/transport/ws.js +10 -10
  330. package/dist/sdk/transport.js +10 -10
  331. package/dist/{serve-preflight-FLTIBTEX.js → serve-preflight-H2AYMGJ6.js} +65 -35
  332. package/dist/serve-preflight-H2AYMGJ6.js.map +1 -0
  333. package/dist/{setup-AG6NFHSN.js → setup-NSPQD4V4.js} +33 -31
  334. package/dist/setup-NSPQD4V4.js.map +1 -0
  335. package/dist/skills-B533SRVZ.js +26 -0
  336. package/dist/{skills-UQYUHVKO.js.map → skills-B533SRVZ.js.map} +1 -1
  337. package/dist/source-VTECABUO.js +87 -0
  338. package/dist/{source-ASEHI2XS.js.map → source-VTECABUO.js.map} +1 -1
  339. package/dist/source-fetch-github-RWHV4I5Z.js +4 -0
  340. package/dist/{source-fetch-github-ST4MFL3D.js.map → source-fetch-github-RWHV4I5Z.js.map} +1 -1
  341. package/dist/{source-manifest-publish-IEVV3W6J.js → source-manifest-publish-YORI42MN.js} +56 -56
  342. package/dist/source-manifest-publish-YORI42MN.js.map +1 -0
  343. package/dist/transport/index.js +10 -10
  344. package/dist/transport/ws/server.js +10 -10
  345. package/dist/transport/ws.js +10 -10
  346. package/dist/tui/index.js +49 -40
  347. package/dist/tui/index.js.map +1 -1
  348. package/dist/tui/src/repl.d.ts.map +1 -1
  349. package/dist/types/manifests.js +1 -1
  350. package/dist/types/src/manifests/index.d.ts +1 -1
  351. package/dist/types/src/manifests/index.d.ts.map +1 -1
  352. package/dist/types/src/manifests/scaffold-body.d.ts +2 -0
  353. package/dist/types/src/manifests/scaffold-body.d.ts.map +1 -1
  354. package/dist/workspace-plugin/adapters/mcp.js +31 -29
  355. package/dist/workspace-plugin/adapters/omp.js +15 -15
  356. package/dist/workspace-plugin/index.js +2 -2
  357. package/package.json +27 -1
  358. package/dist/chunk-2LAPHLDH.js.map +0 -1
  359. package/dist/chunk-5Y2KGB4H.js.map +0 -1
  360. package/dist/chunk-7HX6FNKL.js.map +0 -1
  361. package/dist/chunk-ABFPSVIS.js.map +0 -1
  362. package/dist/chunk-AITJ7ELM.js.map +0 -1
  363. package/dist/chunk-AZ2H6R5I.js.map +0 -1
  364. package/dist/chunk-BFMYYNDT.js.map +0 -1
  365. package/dist/chunk-CEKW3KXP.js.map +0 -1
  366. package/dist/chunk-DGTI65OC.js.map +0 -1
  367. package/dist/chunk-DIGFA7Z5.js.map +0 -1
  368. package/dist/chunk-E572OHGY.js.map +0 -1
  369. package/dist/chunk-GNZBFSRB.js.map +0 -1
  370. package/dist/chunk-HPMQRAIF.js.map +0 -1
  371. package/dist/chunk-HWNK3F3X.js.map +0 -1
  372. package/dist/chunk-IHFGPHCT.js.map +0 -1
  373. package/dist/chunk-ILLTBKDJ.js.map +0 -1
  374. package/dist/chunk-J72MO2WA.js.map +0 -1
  375. package/dist/chunk-KUQAJVYT.js.map +0 -1
  376. package/dist/chunk-LSI2IVFT.js.map +0 -1
  377. package/dist/chunk-NB7SYQYP.js.map +0 -1
  378. package/dist/chunk-NUA33BYO.js.map +0 -1
  379. package/dist/chunk-QEULL4Q3.js.map +0 -1
  380. package/dist/chunk-QSYQOTWN.js.map +0 -1
  381. package/dist/chunk-RHN5MRQO.js.map +0 -1
  382. package/dist/chunk-S2XHGWQC.js.map +0 -1
  383. package/dist/chunk-UI745XC3.js.map +0 -1
  384. package/dist/chunk-VMVDAZLA.js.map +0 -1
  385. package/dist/chunk-XFIEVEU7.js.map +0 -1
  386. package/dist/chunk-XGULGQA3.js.map +0 -1
  387. package/dist/chunk-YLLVSR2U.js.map +0 -1
  388. package/dist/chunk-Z7ZEZZB6.js.map +0 -1
  389. package/dist/chunk-ZDLUQLI6.js.map +0 -1
  390. package/dist/chunk-ZHGKAZJ7.js.map +0 -1
  391. package/dist/connectors-7THEF7YA.js +0 -48
  392. package/dist/ensure-sources-IH7CHSJF.js.map +0 -1
  393. package/dist/flows-4JZQ3XFK.js +0 -26
  394. package/dist/helpers-JNMK3FC2.js +0 -38
  395. package/dist/library-publish-I3UWXAHI.js.map +0 -1
  396. package/dist/open-library-NKKUJLWA.js +0 -42
  397. package/dist/open-registry-BYAXSHUI.js +0 -32
  398. package/dist/paths-UKWE35XS.js +0 -22
  399. package/dist/plugin-store-ABE35NRX.js +0 -23
  400. package/dist/project-BIPK47JK.js +0 -86
  401. package/dist/serve-preflight-FLTIBTEX.js.map +0 -1
  402. package/dist/setup-AG6NFHSN.js.map +0 -1
  403. package/dist/skills-UQYUHVKO.js +0 -26
  404. package/dist/source-ASEHI2XS.js +0 -85
  405. package/dist/source-fetch-github-ST4MFL3D.js +0 -4
  406. package/dist/source-manifest-publish-IEVV3W6J.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../workspace-plugin/src/tools/flows.ts"],"names":[],"mappings":"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","file":"chunk-X3YGUKCG.js","sourcesContent":["// src/tools/flows.ts\n\nimport type { ToolResult } from \"../types.js\";\nimport { err, okJson } from \"../types.js\";\nimport { findAiAssetsRoot } from \"../utils/ai-assets.js\";\nimport { readAllSessions } from \"./sessions.js\";\n\n// ── Flow tools ────────────────────────────────────────────────────────────────\n\n/**\n * List all flow definitions available in the project's `ai-assets` directory.\n *\n * Returns a JSON array of summary objects `{ id, name, nodeCount }`.\n * Returns an empty array when no `ai-assets` root is found.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowList(projectDir: string): Promise<ToolResult> {\n try {\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return okJson([]);\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const summary = flows.map((f: any) => ({\n id: f.id,\n name: f.name ?? f.id,\n nodeCount: f.nodes?.length ?? 0,\n }));\n return okJson(summary);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Show the full flow definition (nodes, edges, metadata) for a specific flow.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param flowId - Flow ID as returned by {@link flowList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowShow(projectDir: string, flowId: string): Promise<ToolResult> {\n try {\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return err(`Flow not found: ${flowId}`);\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const flow = flows.find((f: any) => f.id === flowId);\n if (!flow) return err(`Flow not found: ${flowId}`);\n return okJson(flow);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * List all past and active flow run sessions for the workspace.\n *\n * Delegates to {@link readAllSessions} (reads `.skaile/sessions/*.json`),\n * sorted newest-first by `updatedAt`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowListSessions(projectDir: string): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n return okJson(sessions);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Get harness metadata for a specific flow run session.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param runId - Run ID from {@link flowListSessions}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowGetSession(projectDir: string, runId: string): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n const session = sessions.find((s) => s.runId === runId);\n if (!session) return err(`Session not found: ${runId}`);\n return okJson(session);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Resolve and return the flow definition that was used in a past session.\n *\n * Looks up the session by `runId`, reads its `flowId`, then returns the full\n * flow definition from `ai-assets`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param runId - Run ID from {@link flowListSessions}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowFindFlowForSession(\n projectDir: string,\n runId: string,\n): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n const session = sessions.find((s) => s.runId === runId);\n if (!session) return err(`Session not found: ${runId}`);\n\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return err(`Flow not found for session: ${runId} (no ai-assets root)`);\n\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const flow = flows.find((f: any) => f.id === session.flowId);\n if (!flow) return err(`Flow not found: ${session.flowId}`);\n return okJson(flow);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n"]}
1
+ {"version":3,"sources":["../workspace-plugin/src/tools/flows.ts"],"names":[],"mappings":"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","file":"chunk-BPTWWKGF.js","sourcesContent":["// src/tools/flows.ts\n\nimport type { ToolResult } from \"../types.js\";\nimport { err, okJson } from \"../types.js\";\nimport { findAiAssetsRoot } from \"../utils/ai-assets.js\";\nimport { readAllSessions } from \"./sessions.js\";\n\n// ── Flow tools ────────────────────────────────────────────────────────────────\n\n/**\n * List all flow definitions available in the project's `ai-assets` directory.\n *\n * Returns a JSON array of summary objects `{ id, name, nodeCount }`.\n * Returns an empty array when no `ai-assets` root is found.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowList(projectDir: string): Promise<ToolResult> {\n try {\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return okJson([]);\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const summary = flows.map((f: any) => ({\n id: f.id,\n name: f.name ?? f.id,\n nodeCount: f.nodes?.length ?? 0,\n }));\n return okJson(summary);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Show the full flow definition (nodes, edges, metadata) for a specific flow.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param flowId - Flow ID as returned by {@link flowList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowShow(projectDir: string, flowId: string): Promise<ToolResult> {\n try {\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return err(`Flow not found: ${flowId}`);\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const flow = flows.find((f: any) => f.id === flowId);\n if (!flow) return err(`Flow not found: ${flowId}`);\n return okJson(flow);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * List all past and active flow run sessions for the workspace.\n *\n * Delegates to {@link readAllSessions} (reads `.skaile/sessions/*.json`),\n * sorted newest-first by `updatedAt`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowListSessions(projectDir: string): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n return okJson(sessions);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Get harness metadata for a specific flow run session.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param runId - Run ID from {@link flowListSessions}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowGetSession(projectDir: string, runId: string): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n const session = sessions.find((s) => s.runId === runId);\n if (!session) return err(`Session not found: ${runId}`);\n return okJson(session);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Resolve and return the flow definition that was used in a past session.\n *\n * Looks up the session by `runId`, reads its `flowId`, then returns the full\n * flow definition from `ai-assets`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param runId - Run ID from {@link flowListSessions}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function flowFindFlowForSession(\n projectDir: string,\n runId: string,\n): Promise<ToolResult> {\n try {\n const sessions = await readAllSessions(projectDir);\n const session = sessions.find((s) => s.runId === runId);\n if (!session) return err(`Session not found: ${runId}`);\n\n const assetsRoot = await findAiAssetsRoot(projectDir);\n if (!assetsRoot) return err(`Flow not found for session: ${runId} (no ai-assets root)`);\n\n const { loadAllFlows } = await import(\n \"@skaile/workspaces/factory-assets/connectors/flow/engine\"\n );\n const flows = loadAllFlows(assetsRoot);\n const flow = flows.find((f: any) => f.id === session.flowId);\n if (!flow) return err(`Flow not found: ${session.flowId}`);\n return okJson(flow);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  // core/src/framework.ts
2
- var DEFAULT_HARNESS_ID = "omp";
2
+ var DEFAULT_HARNESS_ID = "claude-sdk";
3
3
  var HARNESS_DEFAULTS = {
4
4
  "claude-sdk": {
5
5
  skillsDir: ".claude/skills",
@@ -28,5 +28,5 @@ function resolveHarnessPaths(settings) {
28
28
  }
29
29
 
30
30
  export { DEFAULT_HARNESS_ID, HARNESS_DEFAULTS, resolveHarnessPaths };
31
- //# sourceMappingURL=chunk-Z7ZEZZB6.js.map
32
- //# sourceMappingURL=chunk-Z7ZEZZB6.js.map
31
+ //# sourceMappingURL=chunk-C5HFK34M.js.map
32
+ //# sourceMappingURL=chunk-C5HFK34M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../core/src/framework.ts"],"names":[],"mappings":";AA8BO,IAAM,kBAAA,GAAqB;AAO3B,IAAM,gBAAA,GAAiD;AAAA,EAC5D,YAAA,EAAc;AAAA,IACZ,SAAA,EAAW,gBAAA;AAAA,IACX,SAAA,EAAW,gBAAA;AAAA,IACX,UAAA,EAAY;AAAA,GACd;AAAA,EACA,KAAA,EAAO;AAAA,IACL,SAAA,EAAW,eAAA;AAAA,IACX,SAAA,EAAW,eAAA;AAAA,IACX,UAAA,EAAY;AAAA,GACd;AAAA,EACA,GAAA,EAAK;AAAA,IACH,SAAA,EAAW,aAAA;AAAA,IACX,SAAA,EAAW,aAAA;AAAA,IACX,UAAA,EAAY;AAAA;AAEhB;AA0BO,SAAS,oBAAoB,QAAA,EAAsC;AACxE,EAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,kBAAA;AACpC,EAAA,MAAM,QAAA,GAAW,gBAAA,CAAiB,OAAO,CAAA,IAAK,iBAAiB,kBAAkB,CAAA;AACjF,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,QAAA,CAAS,SAAA,IAAa,QAAA,CAAU,SAAA;AAAA,IAC3C,SAAA,EAAW,QAAA,CAAS,SAAA,IAAa,QAAA,CAAU,SAAA;AAAA,IAC3C,UAAA,EAAY,QAAA,CAAS,UAAA,IAAc,QAAA,CAAU;AAAA,GAC/C;AACF","file":"chunk-C5HFK34M.js","sourcesContent":["/**\n * Harness path resolution — maps execution harness names to their runtime paths.\n */\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/**\n * Resolved runtime path structure for a bridge harness.\n * All three directories are relative to the project root.\n * @docLink packages/core/concepts#harness-paths\n */\nexport interface HarnessPaths {\n /** Where skills (SKILL.md dirs) are installed relative to projectDir */\n skillsDir: string;\n /** Where agent definitions are installed relative to projectDir */\n agentsDir: string;\n /** Where prompt files are installed relative to projectDir */\n promptsDir: string;\n}\n\n// ── Harness defaults ───────────────────────────────────────────────────────────\n\n/**\n * The harness a session runs on when no settings layer, flag or profile names\n * one: the Claude Agent SDK, which deploys to `.claude/` like the `claude-code`\n * target `add` and `install` use for a project without `agent-config` (p1670).\n * The single definition: settings defaults, path resolution and the runner's\n * session build all import it.\n * @docLink packages/core/concepts#harness-defaults\n */\nexport const DEFAULT_HARNESS_ID = \"claude-sdk\";\n\n/**\n * Built-in per-harness runtime path conventions (relative to project root).\n * Covers `claude-sdk`, `codex`, and `omp`. Used as defaults by `resolveHarnessPaths`.\n * @docLink packages/core/concepts#harness-defaults\n */\nexport const HARNESS_DEFAULTS: Record<string, HarnessPaths> = {\n \"claude-sdk\": {\n skillsDir: \".claude/skills\",\n agentsDir: \".claude/agents\",\n promptsDir: \".claude/commands\",\n },\n codex: {\n skillsDir: \".codex/skills\",\n agentsDir: \".codex/agents\",\n promptsDir: \".codex/rules\",\n },\n omp: {\n skillsDir: \".omp/skills\",\n agentsDir: \".omp/agents\",\n promptsDir: \".omp/prompts\",\n },\n};\n\n// ── Harness resolution ─────────────────────────────────────────────────────────\n\n/** Settings interface — minimal subset needed for harness path resolution. */\ninterface SettingsLike {\n skillsDir?: string;\n agentsDir?: string;\n promptsDir?: string;\n harness?: string;\n}\n\n/**\n * Resolve the effective runtime paths for a bridge harness.\n *\n * Looks up `HARNESS_DEFAULTS[settings.harness]`, then overlays any per-field\n * overrides from `settings.skillsDir`, `settings.agentsDir`, `settings.promptsDir`.\n * Falls back to the `omp` defaults for unknown harness values.\n *\n * To look up file install paths for a specific IDE/tool target, use\n * `HARNESS_TARGETS[harnessName]` from `harness-targets.ts` directly.\n *\n * @param settings - Minimal settings object providing `harness` and optional path overrides\n * @returns `HarnessPaths` with resolved relative paths for skills, agents, and prompts\n * @docLink packages/core/concepts#resolve-harness-paths\n */\nexport function resolveHarnessPaths(settings: SettingsLike): HarnessPaths {\n const harness = settings.harness ?? DEFAULT_HARNESS_ID;\n const defaults = HARNESS_DEFAULTS[harness] ?? HARNESS_DEFAULTS[DEFAULT_HARNESS_ID];\n return {\n skillsDir: settings.skillsDir ?? defaults!.skillsDir,\n agentsDir: settings.agentsDir ?? defaults!.agentsDir,\n promptsDir: settings.promptsDir ?? defaults!.promptsDir,\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { decodeBearerFromHeader, tokensEqual } from './chunk-32NA4TVC.js';
2
- import { listenWithProbe } from './chunk-VMVDAZLA.js';
2
+ import { listenWithProbe } from './chunk-J5JRGBKK.js';
3
3
  import { createServer } from 'http';
4
4
  import { WebSocketServer } from 'ws';
5
5
 
@@ -256,5 +256,5 @@ var WebSocketServerTransport = class {
256
256
  };
257
257
 
258
258
  export { WebSocketServerTransport };
259
- //# sourceMappingURL=chunk-EJPMNDTP.js.map
260
- //# sourceMappingURL=chunk-EJPMNDTP.js.map
259
+ //# sourceMappingURL=chunk-COUJOTAJ.js.map
260
+ //# sourceMappingURL=chunk-COUJOTAJ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../transport/src/ws/server.ts"],"names":[],"mappings":"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","file":"chunk-EJPMNDTP.js","sourcesContent":["/**\n * WebSocketServerTransport — `ws`-based WebSocket server.\n *\n * Accepts one client at a time. Implements ServerTransport from @skaile/workspaces/types.\n * Built on the `ws` package + `node:http`, both of which run under Node and Bun.\n */\n\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { listenWithProbe } from \"@skaile/workspaces/core\";\nimport type { AgentCommand, AgentEvent, ServerTransport } from \"@skaile/workspaces/types\";\nimport { type WebSocket, WebSocketServer } from \"ws\";\nimport { decodeBearerFromHeader, tokensEqual } from \"./auth.js\";\n\n/** @deprecated Moved to `@skaile/workspaces/core`, where `portIsHeld` replaces it. */\nexport { needsWildcardProbe } from \"@skaile/workspaces/core\";\n\n/**\n * Options for {@link WebSocketServerTransport}.\n *\n * @param port - TCP port to bind to; `0` picks a free port (read it back via `boundPort`).\n * @param onLog - Optional callback for internal log lines (client connect/disconnect events).\n * @param host - Address to bind. Default: every interface (Node's unspecified address).\n * `127.0.0.1` accepts local clients only.\n * @param authToken - When set, every upgrade must present this token via the\n * `skaile-bearer.<base64url>` subprotocol or the handshake is rejected with\n * HTTP 401. When unset, no auth is enforced (back-compatible default).\n * @param onListening - Called once the socket is bound, with the address a client\n * connects to (`url`) and whether it needs a token. For a plain-text ready line\n * (the `onLog` record carries the port only inside a log sentence).\n * @param heartbeatMs - Interval in milliseconds between pings to the active\n * client. Default: 30 000.\n * @param maxMissedPongs - Heartbeat ticks the client may go without a pong (or\n * any inbound frame) before its socket is terminated, so a client lost behind a\n * dead path (no FIN) fires `onDisconnect` instead of swallowing every event\n * sent to it. Default: 2, i.e. detection within 3 x `heartbeatMs`. `0` turns\n * the heartbeat off. Every WebSocket client answers pings on its own.\n *\n * @docLink packages/transport/dev-guide#websocket-server-transport\n */\nexport interface WebSocketServerOptions {\n port: number;\n host?: string;\n onLog?: (line: string) => void;\n authToken?: string;\n onListening?: (info: { url: string; port: number; tokenRequired: boolean }) => void;\n heartbeatMs?: number;\n maxMissedPongs?: number;\n}\n\nconst DEFAULT_HEARTBEAT_MS = 30_000;\nconst DEFAULT_MAX_MISSED_PONGS = 2;\n\n/**\n * Shape-validate a `session_init` frame at ingress before forwarding to the\n * runner. Protocol v3 requires the deterministic bootstrap envelope to carry\n * an identity tuple, a semver-shaped `protocolVersion`, a resolved config\n * object, and a `credentials` map keyed by `mounts` / `connectors`. Frames\n * that fail the guard are rejected on the wire so the runner never sees a\n * malformed boot envelope.\n *\n * Returns `null` when the frame is well-formed, or a human-readable reason\n * when it should be rejected.\n *\n * Spec: `_devlog/specs/2026-05-10-deterministic-session-bootstrap.md`\n * § \"SessionInitCommand schema\".\n *\n * @internal\n */\nfunction validateSessionInitShape(cmd: Record<string, unknown>): string | null {\n if (cmd.type !== \"session_init\") return \"type must be 'session_init'\";\n\n const identity = cmd.identity as Record<string, unknown> | undefined;\n if (!identity || typeof identity !== \"object\" || Array.isArray(identity)) {\n return \"identity must be an object\";\n }\n if (typeof identity.containerId !== \"string\") return \"identity.containerId must be a string\";\n if (typeof identity.sessionId !== \"string\") return \"identity.sessionId must be a string\";\n if (typeof identity.projectId !== \"string\") return \"identity.projectId must be a string\";\n\n const protocolVersion = cmd.protocolVersion as Record<string, unknown> | undefined;\n if (!protocolVersion || typeof protocolVersion !== \"object\" || Array.isArray(protocolVersion)) {\n return \"protocolVersion must be an object\";\n }\n if (typeof protocolVersion.major !== \"number\") return \"protocolVersion.major must be a number\";\n if (typeof protocolVersion.minor !== \"number\") return \"protocolVersion.minor must be a number\";\n if (typeof protocolVersion.patch !== \"number\") return \"protocolVersion.patch must be a number\";\n\n if (\n !cmd.resolvedConfig ||\n typeof cmd.resolvedConfig !== \"object\" ||\n Array.isArray(cmd.resolvedConfig)\n ) {\n return \"resolvedConfig must be an object\";\n }\n\n if (!cmd.credentials || typeof cmd.credentials !== \"object\" || Array.isArray(cmd.credentials)) {\n return \"credentials must be an object\";\n }\n\n return null;\n}\n\n/**\n * `ServerTransport` implementation backed by the `ws` package on top of a\n * `node:http` server.\n *\n * Enforces a single-client policy: if a new connection arrives while a client is\n * already connected, the stale connection is closed with code 4001 and replaced.\n * Incoming frames are parsed as JSON `AgentCommand` messages and fanned out to\n * registered `onCommand` handlers; outgoing `AgentEvent` objects are JSON-serialised\n * before sending. Call `listen()` to start accepting connections and `close()` to\n * shut down cleanly — `close()` terminates the active socket immediately rather\n * than keeping the event loop alive.\n *\n * @example\n * ```ts\n * const server = new WebSocketServerTransport({ port: 8080 });\n * await server.listen();\n * server.onCommand((cmd) => console.log(cmd));\n * server.send({ type: 'agent_end' });\n * await server.close();\n * ```\n *\n * @docLink packages/transport/dev-guide#websocket-server-transport\n */\nexport class WebSocketServerTransport implements ServerTransport {\n private httpServer: HttpServer | null = null;\n private wss: WebSocketServer | null = null;\n private activeClient: WebSocket | null = null;\n private readonly port: number;\n private readonly log: (line: string) => void;\n private readonly host?: string;\n private readonly authToken?: string;\n private readonly heartbeatMs: number;\n private readonly maxMissedPongs: number;\n\n private readonly onListening: WebSocketServerOptions[\"onListening\"];\n private readonly commandHandlers = new Set<(command: AgentCommand) => void>();\n private readonly connectHandlers = new Set<() => void>();\n private readonly disconnectHandlers = new Set<() => void>();\n\n constructor(options: WebSocketServerOptions) {\n this.port = options.port;\n this.log = options.onLog ?? console.log;\n this.host = options.host;\n this.authToken = options.authToken;\n this.onListening = options.onListening;\n this.heartbeatMs = options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;\n this.maxMissedPongs = options.maxMissedPongs ?? DEFAULT_MAX_MISSED_PONGS;\n }\n\n /** Start the server and accept connections. */\n async listen(): Promise<void> {\n const httpServer = createServer((_req, res) => {\n res.writeHead(200, { \"content-type\": \"text/plain\" });\n res.end(\"skaile agent server\");\n });\n // When an auth token is configured, reject the upgrade at handshake time\n // (HTTP 401) unless the client presents the matching bearer subprotocol.\n // Rejecting here — before `connection` — keeps unauthenticated sockets from\n // ever reaching the command handlers.\n const expected = this.authToken;\n const wss = new WebSocketServer({\n server: httpServer,\n verifyClient: expected\n ? (info, cb) => {\n const presented = decodeBearerFromHeader(info.req.headers[\"sec-websocket-protocol\"]);\n if (presented !== null && tokensEqual(presented, expected)) {\n cb(true);\n } else {\n this.log(\"[ws-server] rejecting unauthenticated upgrade\");\n cb(false, 401, \"Unauthorized\");\n }\n }\n : undefined,\n });\n wss.on(\"connection\", (ws) => this.handleConnection(ws));\n // `ws` re-emits the http server's errors on `wss`; unhandled during the bind,\n // that throws before the reject below runs and `listen()` hangs. Scoped to the\n // bind so a post-startup server error still surfaces loudly.\n const swallowBindError = () => {};\n wss.on(\"error\", swallowBindError);\n this.httpServer = httpServer;\n this.wss = wss;\n\n try {\n await listenWithProbe(httpServer, this.port, this.host);\n } catch (err) {\n wss.close();\n this.wss = null;\n this.httpServer = null;\n if (err instanceof Error && \"code\" in err && err.code === \"EADDRINUSE\") {\n const where = this.host ? `${this.host}:${this.port}` : `port ${this.port}`;\n throw Object.assign(\n new Error(\n `${where} is already in use: another process listens there. Pick another port.`,\n ),\n { code: \"EADDRINUSE\" },\n );\n }\n throw err;\n } finally {\n wss.off(\"error\", swallowBindError);\n }\n\n const addr = httpServer.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : this.port;\n const bind = this.host ?? \"all interfaces\";\n this.log(\n `[ws-server] listening on port ${boundPort} (${bind}; ${this.authToken ? \"token required\" : \"no authentication\"})`,\n );\n // A wildcard bind is reachable on loopback; that is the URL worth printing.\n const urlHost =\n !this.host || this.host === \"0.0.0.0\" || this.host === \"::\"\n ? \"127.0.0.1\"\n : this.host.includes(\":\") && !this.host.startsWith(\"[\")\n ? `[${this.host}]`\n : this.host;\n this.onListening?.({\n url: `ws://${urlHost}:${boundPort}`,\n port: boundPort,\n tokenRequired: this.authToken !== undefined,\n });\n }\n\n private handleConnection(ws: WebSocket): void {\n if (this.activeClient) {\n // Close the stale connection instead of rejecting the new one.\n // This handles the race where waitForWsReady's probe hasn't\n // fully disconnected before the real gateway client connects.\n this.log(\"[ws-server] replacing previous connection\");\n try {\n this.activeClient.close(4001, \"Replaced by new connection\");\n } catch {\n // already closed\n }\n }\n this.log(\"[ws-server] client connected\");\n this.activeClient = ws;\n for (const handler of this.connectHandlers) {\n handler();\n }\n\n const stopHeartbeat = this.startHeartbeat(ws);\n\n ws.on(\"message\", (data) => {\n try {\n const parsed = JSON.parse(String(data)) as Record<string, unknown>;\n // Protocol v3: shape-validate `session_init` at ingress so the\n // runner never receives a malformed boot envelope. Other command\n // shapes pass through unchanged — invalid `AgentCommand`s surface\n // through the existing per-command handlers in serve.ts.\n if (parsed && typeof parsed === \"object\" && parsed.type === \"session_init\") {\n const reason = validateSessionInitShape(parsed);\n if (reason !== null) {\n this.log(`[ws-server] rejecting invalid session_init: ${reason}`);\n this.sendRaw({\n type: \"error\",\n message: `Invalid session_init: ${reason}`,\n fatal: false,\n });\n return;\n }\n }\n const cmd = parsed as unknown as AgentCommand;\n for (const handler of this.commandHandlers) {\n handler(cmd);\n }\n } catch (err) {\n this.sendRaw({\n type: \"error\",\n message: `Invalid message: ${err instanceof Error ? err.message : String(err)}`,\n fatal: false,\n });\n }\n });\n\n ws.on(\"close\", () => {\n stopHeartbeat();\n this.log(\"[ws-server] client disconnected\");\n if (this.activeClient === ws) {\n this.activeClient = null;\n for (const handler of this.disconnectHandlers) {\n handler();\n }\n }\n });\n }\n\n /**\n * Ping `ws` every {@link heartbeatMs}; terminate it after\n * {@link maxMissedPongs} unanswered ticks. `terminate()` makes `ws` emit\n * `close`, which runs the normal disconnect path. Returns the stop function.\n */\n private startHeartbeat(ws: WebSocket): () => void {\n if (this.maxMissedPongs <= 0) return () => {};\n let missed = 0;\n const markAlive = () => {\n missed = 0;\n };\n ws.on(\"pong\", markAlive);\n ws.on(\"message\", markAlive);\n const timer = setInterval(() => {\n if (ws.readyState !== ws.OPEN) return;\n if (missed >= this.maxMissedPongs) {\n this.log(\n `[ws-server] no pong for ${missed} heartbeats of ${this.heartbeatMs}ms; terminating client`,\n );\n clearInterval(timer);\n ws.terminate();\n return;\n }\n missed++;\n try {\n ws.ping();\n } catch {\n // socket closing underneath us; the close event cleans up\n }\n }, this.heartbeatMs);\n timer.unref?.();\n return () => clearInterval(timer);\n }\n\n /**\n * Stop the server.\n *\n * Terminates the active socket immediately — otherwise a still-connected\n * client would keep the event loop alive and block process shutdown.\n */\n async close(): Promise<void> {\n try {\n this.activeClient?.terminate();\n } catch {\n // already closed\n }\n this.activeClient = null;\n this.wss?.close();\n this.wss = null;\n const httpServer = this.httpServer;\n this.httpServer = null;\n if (httpServer) {\n httpServer.closeAllConnections();\n await new Promise<void>((resolve) => httpServer.close(() => resolve()));\n }\n }\n\n send(event: AgentEvent): void {\n this.sendRaw(event);\n }\n\n onCommand(handler: (command: AgentCommand) => void): () => void {\n this.commandHandlers.add(handler);\n return () => {\n this.commandHandlers.delete(handler);\n };\n }\n\n onConnect(handler: () => void): () => void {\n this.connectHandlers.add(handler);\n return () => {\n this.connectHandlers.delete(handler);\n };\n }\n\n onDisconnect(handler: () => void): () => void {\n this.disconnectHandlers.add(handler);\n return () => {\n this.disconnectHandlers.delete(handler);\n };\n }\n\n get connected(): boolean {\n return this.activeClient !== null;\n }\n\n /** The port actually bound by `listen()` (resolves `port: 0`); `undefined` when not listening. */\n get boundPort(): number | undefined {\n const addr = this.httpServer?.address();\n return typeof addr === \"object\" && addr ? addr.port : undefined;\n }\n\n private sendRaw(data: unknown): void {\n try {\n const client = this.activeClient;\n if (client && client.readyState === 1) {\n client.send(JSON.stringify(data));\n }\n } catch {\n // Silently ignore send failures\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../transport/src/ws/server.ts"],"names":[],"mappings":"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","file":"chunk-COUJOTAJ.js","sourcesContent":["/**\n * WebSocketServerTransport — `ws`-based WebSocket server.\n *\n * Accepts one client at a time. Implements ServerTransport from @skaile/workspaces/types.\n * Built on the `ws` package + `node:http`, both of which run under Node and Bun.\n */\n\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { listenWithProbe } from \"@skaile/workspaces/core\";\nimport type { AgentCommand, AgentEvent, ServerTransport } from \"@skaile/workspaces/types\";\nimport { type WebSocket, WebSocketServer } from \"ws\";\nimport { decodeBearerFromHeader, tokensEqual } from \"./auth.js\";\n\n/** @deprecated Moved to `@skaile/workspaces/core`, where `portIsHeld` replaces it. */\nexport { needsWildcardProbe } from \"@skaile/workspaces/core\";\n\n/**\n * Options for {@link WebSocketServerTransport}.\n *\n * @param port - TCP port to bind to; `0` picks a free port (read it back via `boundPort`).\n * @param onLog - Optional callback for internal log lines (client connect/disconnect events).\n * @param host - Address to bind. Default: every interface (Node's unspecified address).\n * `127.0.0.1` accepts local clients only.\n * @param authToken - When set, every upgrade must present this token via the\n * `skaile-bearer.<base64url>` subprotocol or the handshake is rejected with\n * HTTP 401. When unset, no auth is enforced (back-compatible default).\n * @param onListening - Called once the socket is bound, with the address a client\n * connects to (`url`) and whether it needs a token. For a plain-text ready line\n * (the `onLog` record carries the port only inside a log sentence).\n * @param heartbeatMs - Interval in milliseconds between pings to the active\n * client. Default: 30 000.\n * @param maxMissedPongs - Heartbeat ticks the client may go without a pong (or\n * any inbound frame) before its socket is terminated, so a client lost behind a\n * dead path (no FIN) fires `onDisconnect` instead of swallowing every event\n * sent to it. Default: 2, i.e. detection within 3 x `heartbeatMs`. `0` turns\n * the heartbeat off. Every WebSocket client answers pings on its own.\n *\n * @docLink packages/transport/dev-guide#websocket-server-transport\n */\nexport interface WebSocketServerOptions {\n port: number;\n host?: string;\n onLog?: (line: string) => void;\n authToken?: string;\n onListening?: (info: { url: string; port: number; tokenRequired: boolean }) => void;\n heartbeatMs?: number;\n maxMissedPongs?: number;\n}\n\nconst DEFAULT_HEARTBEAT_MS = 30_000;\nconst DEFAULT_MAX_MISSED_PONGS = 2;\n\n/**\n * Shape-validate a `session_init` frame at ingress before forwarding to the\n * runner. Protocol v3 requires the deterministic bootstrap envelope to carry\n * an identity tuple, a semver-shaped `protocolVersion`, a resolved config\n * object, and a `credentials` map keyed by `mounts` / `connectors`. Frames\n * that fail the guard are rejected on the wire so the runner never sees a\n * malformed boot envelope.\n *\n * Returns `null` when the frame is well-formed, or a human-readable reason\n * when it should be rejected.\n *\n * Spec: `_devlog/specs/2026-05-10-deterministic-session-bootstrap.md`\n * § \"SessionInitCommand schema\".\n *\n * @internal\n */\nfunction validateSessionInitShape(cmd: Record<string, unknown>): string | null {\n if (cmd.type !== \"session_init\") return \"type must be 'session_init'\";\n\n const identity = cmd.identity as Record<string, unknown> | undefined;\n if (!identity || typeof identity !== \"object\" || Array.isArray(identity)) {\n return \"identity must be an object\";\n }\n if (typeof identity.containerId !== \"string\") return \"identity.containerId must be a string\";\n if (typeof identity.sessionId !== \"string\") return \"identity.sessionId must be a string\";\n if (typeof identity.projectId !== \"string\") return \"identity.projectId must be a string\";\n\n const protocolVersion = cmd.protocolVersion as Record<string, unknown> | undefined;\n if (!protocolVersion || typeof protocolVersion !== \"object\" || Array.isArray(protocolVersion)) {\n return \"protocolVersion must be an object\";\n }\n if (typeof protocolVersion.major !== \"number\") return \"protocolVersion.major must be a number\";\n if (typeof protocolVersion.minor !== \"number\") return \"protocolVersion.minor must be a number\";\n if (typeof protocolVersion.patch !== \"number\") return \"protocolVersion.patch must be a number\";\n\n if (\n !cmd.resolvedConfig ||\n typeof cmd.resolvedConfig !== \"object\" ||\n Array.isArray(cmd.resolvedConfig)\n ) {\n return \"resolvedConfig must be an object\";\n }\n\n if (!cmd.credentials || typeof cmd.credentials !== \"object\" || Array.isArray(cmd.credentials)) {\n return \"credentials must be an object\";\n }\n\n return null;\n}\n\n/**\n * `ServerTransport` implementation backed by the `ws` package on top of a\n * `node:http` server.\n *\n * Enforces a single-client policy: if a new connection arrives while a client is\n * already connected, the stale connection is closed with code 4001 and replaced.\n * Incoming frames are parsed as JSON `AgentCommand` messages and fanned out to\n * registered `onCommand` handlers; outgoing `AgentEvent` objects are JSON-serialised\n * before sending. Call `listen()` to start accepting connections and `close()` to\n * shut down cleanly — `close()` terminates the active socket immediately rather\n * than keeping the event loop alive.\n *\n * @example\n * ```ts\n * const server = new WebSocketServerTransport({ port: 8080 });\n * await server.listen();\n * server.onCommand((cmd) => console.log(cmd));\n * server.send({ type: 'agent_end' });\n * await server.close();\n * ```\n *\n * @docLink packages/transport/dev-guide#websocket-server-transport\n */\nexport class WebSocketServerTransport implements ServerTransport {\n private httpServer: HttpServer | null = null;\n private wss: WebSocketServer | null = null;\n private activeClient: WebSocket | null = null;\n private readonly port: number;\n private readonly log: (line: string) => void;\n private readonly host?: string;\n private readonly authToken?: string;\n private readonly heartbeatMs: number;\n private readonly maxMissedPongs: number;\n\n private readonly onListening: WebSocketServerOptions[\"onListening\"];\n private readonly commandHandlers = new Set<(command: AgentCommand) => void>();\n private readonly connectHandlers = new Set<() => void>();\n private readonly disconnectHandlers = new Set<() => void>();\n\n constructor(options: WebSocketServerOptions) {\n this.port = options.port;\n this.log = options.onLog ?? console.log;\n this.host = options.host;\n this.authToken = options.authToken;\n this.onListening = options.onListening;\n this.heartbeatMs = options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;\n this.maxMissedPongs = options.maxMissedPongs ?? DEFAULT_MAX_MISSED_PONGS;\n }\n\n /** Start the server and accept connections. */\n async listen(): Promise<void> {\n const httpServer = createServer((_req, res) => {\n res.writeHead(200, { \"content-type\": \"text/plain\" });\n res.end(\"skaile agent server\");\n });\n // When an auth token is configured, reject the upgrade at handshake time\n // (HTTP 401) unless the client presents the matching bearer subprotocol.\n // Rejecting here — before `connection` — keeps unauthenticated sockets from\n // ever reaching the command handlers.\n const expected = this.authToken;\n const wss = new WebSocketServer({\n server: httpServer,\n verifyClient: expected\n ? (info, cb) => {\n const presented = decodeBearerFromHeader(info.req.headers[\"sec-websocket-protocol\"]);\n if (presented !== null && tokensEqual(presented, expected)) {\n cb(true);\n } else {\n this.log(\"[ws-server] rejecting unauthenticated upgrade\");\n cb(false, 401, \"Unauthorized\");\n }\n }\n : undefined,\n });\n wss.on(\"connection\", (ws) => this.handleConnection(ws));\n // `ws` re-emits the http server's errors on `wss`; unhandled during the bind,\n // that throws before the reject below runs and `listen()` hangs. Scoped to the\n // bind so a post-startup server error still surfaces loudly.\n const swallowBindError = () => {};\n wss.on(\"error\", swallowBindError);\n this.httpServer = httpServer;\n this.wss = wss;\n\n try {\n await listenWithProbe(httpServer, this.port, this.host);\n } catch (err) {\n wss.close();\n this.wss = null;\n this.httpServer = null;\n if (err instanceof Error && \"code\" in err && err.code === \"EADDRINUSE\") {\n const where = this.host ? `${this.host}:${this.port}` : `port ${this.port}`;\n throw Object.assign(\n new Error(\n `${where} is already in use: another process listens there. Pick another port.`,\n ),\n { code: \"EADDRINUSE\" },\n );\n }\n throw err;\n } finally {\n wss.off(\"error\", swallowBindError);\n }\n\n const addr = httpServer.address();\n const boundPort = typeof addr === \"object\" && addr ? addr.port : this.port;\n const bind = this.host ?? \"all interfaces\";\n this.log(\n `[ws-server] listening on port ${boundPort} (${bind}; ${this.authToken ? \"token required\" : \"no authentication\"})`,\n );\n // A wildcard bind is reachable on loopback; that is the URL worth printing.\n const urlHost =\n !this.host || this.host === \"0.0.0.0\" || this.host === \"::\"\n ? \"127.0.0.1\"\n : this.host.includes(\":\") && !this.host.startsWith(\"[\")\n ? `[${this.host}]`\n : this.host;\n this.onListening?.({\n url: `ws://${urlHost}:${boundPort}`,\n port: boundPort,\n tokenRequired: this.authToken !== undefined,\n });\n }\n\n private handleConnection(ws: WebSocket): void {\n if (this.activeClient) {\n // Close the stale connection instead of rejecting the new one.\n // This handles the race where waitForWsReady's probe hasn't\n // fully disconnected before the real gateway client connects.\n this.log(\"[ws-server] replacing previous connection\");\n try {\n this.activeClient.close(4001, \"Replaced by new connection\");\n } catch {\n // already closed\n }\n }\n this.log(\"[ws-server] client connected\");\n this.activeClient = ws;\n for (const handler of this.connectHandlers) {\n handler();\n }\n\n const stopHeartbeat = this.startHeartbeat(ws);\n\n ws.on(\"message\", (data) => {\n try {\n const parsed = JSON.parse(String(data)) as Record<string, unknown>;\n // Protocol v3: shape-validate `session_init` at ingress so the\n // runner never receives a malformed boot envelope. Other command\n // shapes pass through unchanged — invalid `AgentCommand`s surface\n // through the existing per-command handlers in serve.ts.\n if (parsed && typeof parsed === \"object\" && parsed.type === \"session_init\") {\n const reason = validateSessionInitShape(parsed);\n if (reason !== null) {\n this.log(`[ws-server] rejecting invalid session_init: ${reason}`);\n this.sendRaw({\n type: \"error\",\n message: `Invalid session_init: ${reason}`,\n fatal: false,\n });\n return;\n }\n }\n const cmd = parsed as unknown as AgentCommand;\n for (const handler of this.commandHandlers) {\n handler(cmd);\n }\n } catch (err) {\n this.sendRaw({\n type: \"error\",\n message: `Invalid message: ${err instanceof Error ? err.message : String(err)}`,\n fatal: false,\n });\n }\n });\n\n ws.on(\"close\", () => {\n stopHeartbeat();\n this.log(\"[ws-server] client disconnected\");\n if (this.activeClient === ws) {\n this.activeClient = null;\n for (const handler of this.disconnectHandlers) {\n handler();\n }\n }\n });\n }\n\n /**\n * Ping `ws` every {@link heartbeatMs}; terminate it after\n * {@link maxMissedPongs} unanswered ticks. `terminate()` makes `ws` emit\n * `close`, which runs the normal disconnect path. Returns the stop function.\n */\n private startHeartbeat(ws: WebSocket): () => void {\n if (this.maxMissedPongs <= 0) return () => {};\n let missed = 0;\n const markAlive = () => {\n missed = 0;\n };\n ws.on(\"pong\", markAlive);\n ws.on(\"message\", markAlive);\n const timer = setInterval(() => {\n if (ws.readyState !== ws.OPEN) return;\n if (missed >= this.maxMissedPongs) {\n this.log(\n `[ws-server] no pong for ${missed} heartbeats of ${this.heartbeatMs}ms; terminating client`,\n );\n clearInterval(timer);\n ws.terminate();\n return;\n }\n missed++;\n try {\n ws.ping();\n } catch {\n // socket closing underneath us; the close event cleans up\n }\n }, this.heartbeatMs);\n timer.unref?.();\n return () => clearInterval(timer);\n }\n\n /**\n * Stop the server.\n *\n * Terminates the active socket immediately — otherwise a still-connected\n * client would keep the event loop alive and block process shutdown.\n */\n async close(): Promise<void> {\n try {\n this.activeClient?.terminate();\n } catch {\n // already closed\n }\n this.activeClient = null;\n this.wss?.close();\n this.wss = null;\n const httpServer = this.httpServer;\n this.httpServer = null;\n if (httpServer) {\n httpServer.closeAllConnections();\n await new Promise<void>((resolve) => httpServer.close(() => resolve()));\n }\n }\n\n send(event: AgentEvent): void {\n this.sendRaw(event);\n }\n\n onCommand(handler: (command: AgentCommand) => void): () => void {\n this.commandHandlers.add(handler);\n return () => {\n this.commandHandlers.delete(handler);\n };\n }\n\n onConnect(handler: () => void): () => void {\n this.connectHandlers.add(handler);\n return () => {\n this.connectHandlers.delete(handler);\n };\n }\n\n onDisconnect(handler: () => void): () => void {\n this.disconnectHandlers.add(handler);\n return () => {\n this.disconnectHandlers.delete(handler);\n };\n }\n\n get connected(): boolean {\n return this.activeClient !== null;\n }\n\n /** The port actually bound by `listen()` (resolves `port: 0`); `undefined` when not listening. */\n get boundPort(): number | undefined {\n const addr = this.httpServer?.address();\n return typeof addr === \"object\" && addr ? addr.port : undefined;\n }\n\n private sendRaw(data: unknown): void {\n try {\n const client = this.activeClient;\n if (client && client.readyState === 1) {\n client.send(JSON.stringify(data));\n }\n } catch {\n // Silently ignore send failures\n }\n }\n}\n"]}
@@ -1,13 +1,14 @@
1
1
  import { initTelemetry } from './chunk-4R6DROGN.js';
2
- import { parseSkillFrontmatter, validateFlowVersions } from './chunk-IRYKRKVQ.js';
3
- import { FlowAdapter, SessionNodeExecutor, SessionSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn } from './chunk-DGTI65OC.js';
4
- import { loadFlow, flowLookupRoots, findFlowFileInRoots, FLOW_FILE_EXTENSIONS } from './chunk-4MUDQCBP.js';
2
+ import { parseSkillFrontmatter, validateFlowVersions } from './chunk-URCJIV7T.js';
3
+ import { FlowAdapter, SessionNodeExecutor, SessionSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn } from './chunk-ZEH4WFEG.js';
4
+ import { loadFlow, flowLookupRoots, findFlowFileInRoots, FLOW_FILE_EXTENSIONS } from './chunk-RFQONXET.js';
5
5
  import { renderStimulusPrompt } from './chunk-WD3L5QSU.js';
6
6
  import { flowSkillVersionPins } from './chunk-7RGTAEG6.js';
7
- import { resolveSettings } from './chunk-VMVDAZLA.js';
7
+ import { resolveSettings } from './chunk-J5JRGBKK.js';
8
+ import { DEFAULT_HARNESS_ID } from './chunk-C5HFK34M.js';
8
9
  import { findKindDirs } from './chunk-MWXYN6NY.js';
9
- import { resolveAgentDir, resolveSkWorkspaceConfig } from './chunk-ZHGKAZJ7.js';
10
- import { isValidAssetName } from './chunk-LSSYC5IC.js';
10
+ import { resolveAgentDir, resolveSkWorkspaceConfig } from './chunk-XBQTXGY4.js';
11
+ import { isValidAssetName } from './chunk-IZQOO6MN.js';
11
12
  import { createLogger } from './chunk-BOFL7GIF.js';
12
13
  import fs from 'fs';
13
14
  import path from 'path';
@@ -60,7 +61,7 @@ async function runFlow(opts) {
60
61
  flowId: flow.id,
61
62
  projectDir: opts.projectDir,
62
63
  agentDir,
63
- harness: settings.harness ?? "omp",
64
+ harness: settings.harness ?? DEFAULT_HARNESS_ID,
64
65
  model: settings.model,
65
66
  label: opts.sessionLabel
66
67
  });
@@ -536,5 +537,5 @@ function walkForSkill(dir, skillId) {
536
537
  }
537
538
 
538
539
  export { awaitAgentEnd, resolveFlowPath, resumeFlow, runFlow };
539
- //# sourceMappingURL=chunk-J72MO2WA.js.map
540
- //# sourceMappingURL=chunk-J72MO2WA.js.map
540
+ //# sourceMappingURL=chunk-DU26AVK2.js.map
541
+ //# sourceMappingURL=chunk-DU26AVK2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../factory-assets/connectors/flow/run-flow.ts"],"names":["c"],"mappings":"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","file":"chunk-DU26AVK2.js","sourcesContent":["/**\n * runFlow / resumeFlow — CLI entry helpers for the flow connector.\n *\n * Moved from `runner/src/runner.ts` to `factory-assets/connectors/flow/run-flow.ts`\n * in Phase 3 of the flow-connector extraction (2026-05-08). Behaviour is\n * byte-identical to the previous runner-side implementation; only the log\n * source changes from `runner:flow:<runId>` to `flow-connector:run:<runId>`.\n *\n * The runner re-exports these symbols with a deprecation warning for one\n * release. CLI consumers should switch to\n * `import { runFlow, resumeFlow } from \"@skaile/workspaces/factory-assets/connectors/flow/run-flow\"`.\n *\n * Internal runner helpers (FlowOrchestrator, bootstrapRunnerLogStore,\n * createAgentSession, resolveHarnessPaths, session helpers) are loaded lazily\n * via dynamic `await import(\"@skaile/workspaces/runner\")` inside\n * `loadRunnerModule()` below. The lazy load avoids a static package-level\n * cycle (runner → connectors → factory-assets → runner) — the cycle exists at\n * the workspace level but never resolves at module-load time because\n * factory-assets only ever calls `import` from inside an async function body.\n * The string-literal specifier preserves `bun --compile` and tsup static\n * analysis.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { AgentEvent } from \"@skaile/workspaces/bridge\";\nimport {\n DEFAULT_HARNESS_ID,\n findKindDirs,\n isValidAssetName,\n resolveAgentDir,\n resolveSettings,\n resolveSkWorkspaceConfig,\n} from \"@skaile/workspaces/core\";\nimport { createLogger } from \"@skaile/workspaces/core/logging\";\nimport { parseSkillFrontmatter, validateFlowVersions } from \"@skaile/workspaces/resolver\";\nimport { initTelemetry } from \"@skaile/workspaces/telemetry\";\nimport type { FlowExecution, FlowPromptEvent } from \"@skaile/workspaces/types\";\nimport * as z from \"zod\";\nimport { FlowAdapter } from \"./adapter.js\";\nimport {\n findFlowFileInRoots,\n FLOW_FILE_EXTENSIONS,\n type FlowLookupMiss,\n flowLookupRoots,\n loadFlow,\n} from \"./engine/index.js\";\nimport { flowSkillVersionPins } from \"./engine/node-shape.js\";\nimport { SessionInlineSubFlowRunner } from \"./inline-sub-flow-host.js\";\nimport { SessionNodeExecutor } from \"./node-executor.js\";\nimport { driveOrchestratorTurn } from \"./orchestrator-turn.js\";\nimport { renderStimulusPrompt, type TurnStimulus } from \"./prompt-fragments.js\";\nimport { SessionSubpromptRunner } from \"./subprompt-runner.js\";\n\n/**\n * Lazy `import(\"@skaile/workspaces/runner\")` accessor. Cached on first call so\n * subsequent `runFlow` invocations don't re-evaluate the runner module.\n *\n * Dynamic ESM import is used (not `require`) so vitest and other ESM\n * bundlers honour their alias resolution — `require` would side-step the\n * configured aliases and pick up two distinct module instances when run\n * under vitest. The string-literal specifier ensures bun --compile keeps\n * the dependency (per the static-import-or-die rule in\n * connectors/CLAUDE.md).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _runnerModule: any | undefined;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nasync function loadRunnerModule(): Promise<any> {\n if (_runnerModule) return _runnerModule;\n _runnerModule = await import(\"@skaile/workspaces/runner\");\n return _runnerModule;\n}\n\n/** Type-only re-export of SessionState so the runner tombstone shim still works. */\nexport type SessionState = import(\"@skaile/workspaces/runner\").SessionState;\n\n/** Maximum agent session duration (4 hours). Configurable via {@link RunOptions.sessionTimeoutMs}. */\nconst DEFAULT_SESSION_TIMEOUT_MS = 4 * 60 * 60 * 1000; // 4 hours\n\nconst FLOW_AGENT_OPERATION_NAMES = new Set([\n \"get_available\",\n \"get_state\",\n \"get_globals\",\n \"build_handoff\",\n \"validate_node\",\n \"start_node\",\n \"request_approval\",\n \"request_input\",\n \"complete_node\",\n \"skip_node\",\n \"fail_node\",\n]);\n\n/**\n * Options for {@link runFlow}.\n *\n * Wraps `FlowOrchestrator` with autonomous mode turned on by default. First-class\n * gate nodes remain mandatory human decisions in every mode.\n *\n * @docLink packages/factory-assets/flow#run-flow\n */\nexport interface RunOptions {\n /** The working directory for the project being orchestrated. */\n projectDir: string;\n /** Absolute path to the `.flow.yaml` or `.flow.json` definition file. */\n flowPath: string;\n /**\n * Directory containing `agent.yaml`, `SOUL.md`, `RULES.md`, `knowledge/`.\n * Resolved from `skaile.yaml` via `resolveAgentDir` when absent.\n */\n agentDir?: string;\n /**\n * Agent harness. Defaults to `settings.harness` (`\"omp\"` or `\"claude-sdk\"`).\n */\n harness?: string;\n /**\n */\n /**\n * Model name override. Falls back to `settings.model` when absent.\n */\n model?: string;\n /**\n * Path to a specific `settings.json` to load instead of the default\n * layered resolution chain (project → parent → global → built-in defaults).\n */\n settingsFile?: string;\n /**\n * When `true`, prints the initial flow state without starting the agent\n * and returns immediately.\n */\n dryRun?: boolean;\n /**\n * Per-session timeout in milliseconds. Defaults to\n * {@link DEFAULT_SESSION_TIMEOUT_MS} (4 hours).\n */\n sessionTimeoutMs?: number;\n /** Optional human-readable label shown in the session list. */\n sessionLabel?: string;\n /**\n * The session `skaile resume` continues. Its run id is kept and its harness thread resumed,\n * instead of starting a second session. Set by {@link resumeFlow}; not for other callers.\n */\n resumeSession?: SessionState;\n /** Autonomous mode for CLI runs. Defaults to true; first-class gate nodes are never bypassed. */\n autonomousMode?: boolean;\n /**\n * Called for each {@link AgentEvent} emitted during the run\n * (e.g. `text`, `tool_call`, `state_changed`).\n */\n onEvent?: (event: AgentEvent) => void;\n /**\n * Called for each diagnostic log line. Defaults to `process.stdout`.\n */\n onLog?: (line: string) => void;\n}\n\n/**\n * Options for resuming an existing CLI session.\n *\n * Reconnects the harness's conversation thread (conversation history is\n * preserved via the stored `harnessSessionId`) but restarts flow execution\n * from scratch — flow state is not persisted in CLI mode. For governed,\n * resumable flow runs use a host that persists flow state (e.g. the Skaile\n * platform).\n *\n * @docLink packages/factory-assets/flow#resume-flow\n */\nexport interface ResumeOptions {\n /** The working directory for the project being orchestrated. */\n projectDir: string;\n /**\n * Specific run ID to resume. When absent, the current session pointer\n * at `<projectDir>/.skaile/current` is used.\n */\n sessionId?: string;\n /**\n * Agent definition directory override. Defaults to the directory stored\n * in the session file.\n */\n agentDir?: string;\n /**\n * When `true`, prints the initial flow state without starting the agent\n * and returns immediately.\n */\n dryRun?: boolean;\n /**\n * Per-session timeout in milliseconds. Defaults to\n * {@link DEFAULT_SESSION_TIMEOUT_MS} (4 hours).\n */\n sessionTimeoutMs?: number;\n /**\n * Called for each {@link AgentEvent} emitted during the run.\n */\n onEvent?: RunOptions[\"onEvent\"];\n /**\n * Called for each diagnostic log line. Defaults to `process.stdout`.\n */\n onLog?: RunOptions[\"onLog\"];\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Start a new flow session from the CLI.\n *\n * Wraps `FlowOrchestrator` with autonomous mode turned on by default. The\n * runner remains idle between turns; first-class gates always park for a human\n * decision, including in autonomous mode. Non-CLI hosts (Skaile platform,\n * Pichi) use the orchestrator directly via the serve command surface and drive\n * gates through user actions.\n *\n * @docLink packages/factory-assets/flow#run-flow\n */\nexport async function runFlow(opts: RunOptions): Promise<void> {\n const runner = await loadRunnerModule();\n const {\n bootstrapRunnerLogStore,\n bootstrapCapabilityRegistry,\n CapabilityRegistry,\n createAgentSession,\n createSessionStimulusBus,\n defineCapability,\n registerCompositionCapabilities,\n resolveHarnessPaths,\n newSession,\n saveSession,\n touchSession,\n } = runner;\n\n const flow = loadFlow(opts.flowPath);\n const agentDir = opts.agentDir ?? resolveAgentDir(opts.projectDir);\n const settings = await resolveSettings(opts.projectDir, {\n harness: opts.harness,\n model: opts.model,\n });\n\n // `skaile resume` continues the session it was given: same run id, so the harness thread\n // (`harnessSessionId`) resumes and `session list` shows one run, not a second one (p850).\n const session = opts.resumeSession\n ? (({ error: _prior, ...kept }) => touchSession({ ...kept, status: \"running\" }))(\n opts.resumeSession,\n )\n : newSession({\n flowId: flow.id,\n projectDir: opts.projectDir,\n agentDir,\n harness: settings.harness ?? DEFAULT_HARNESS_ID,\n model: settings.model,\n label: opts.sessionLabel,\n });\n\n // A dry run only prints the plan: it must not leave a `running` session behind.\n if (!opts.dryRun) await saveSession(opts.projectDir, session);\n\n // Bootstrap structured logging — registers a process-singleton LogStore.\n // OnLogBridgeSink mirrors entries to opts.onLog when caller provides one,\n // preserving back-compat with CLI hosts that consume plain text lines.\n const wsConfigEarly = resolveSkWorkspaceConfig(opts.projectDir);\n const { dispose: disposeLogStore } = bootstrapRunnerLogStore({\n sessionId: session.runId,\n projectDir: opts.projectDir,\n yamlBlock: wsConfigEarly.logging,\n onLog: opts.onLog,\n // A host that takes lines through `onLog` prints them itself; the stdout\n // sink would add every record again as a raw JSON line.\n stdout: opts.onLog === undefined,\n });\n const flowLog = createLogger({\n kind: \"flow-connector\",\n subkind: \"run\",\n instance: session.runId,\n });\n const log = (line: string) => flowLog.info(line);\n const capabilityRegistry = new CapabilityRegistry();\n bootstrapCapabilityRegistry(capabilityRegistry);\n const capabilityHooks = {\n sessionId: session.runId,\n composeTools: () => capabilityRegistry.composeLLMTools(),\n resolve: (name: string) =>\n capabilityRegistry.list().find((cap: { name: string }) => cap.name === name) ?? null,\n invoke: (name: string, input: unknown, _signal?: AbortSignal, callId?: string) =>\n capabilityRegistry.invoke(name, input, { sessionId: session.runId, callId }),\n };\n\n try {\n // ── Dry run ────────────────────────────────────────────────────────────\n if (opts.dryRun) {\n const adapter = new FlowAdapter();\n const handle = await adapter.connect(\n {\n id: \"flow\",\n driver: \"flow\",\n access: \"read-only\" as const,\n options: { flow, seed: { runId: session.runId, startedBy: \"cli\" } },\n },\n {}, // flow needs no connect context\n );\n const state = adapter.getExecution(handle);\n const available = Object.values(state.nodes)\n .filter((n) => n.status === \"available\")\n .map((n) => n.id);\n // The plan is the command's output, not a log event: print it as plain lines\n // (no `[info] [flow-connector:run:…]` prefix from the log formatter).\n const printPlan = opts.onLog ?? ((line: string) => console.log(line));\n printPlan(`[dry-run] Flow: ${flow.name} (${flow.id})`);\n printPlan(`[dry-run] Available: ${available.join(\", \") || \"(none)\"}`);\n await adapter.disconnect(handle);\n return;\n }\n\n await validatePinnedVersions(flow, opts.projectDir, log);\n\n // ── Telemetry initialization ────────────────────────────────────────────\n const wsConfig = wsConfigEarly;\n const telemetry = await initTelemetry(wsConfig.telemetry);\n const flowTrace = telemetry.startTrace({\n name: `flow:${flow.id}`,\n kind: \"flow_run\",\n attributes: {\n \"skaile.flow.id\": flow.id,\n \"skaile.flow.run_id\": session.runId,\n },\n });\n\n // ── Agent session setup ─────────────────────────────────────────────────\n const harnessPaths = resolveHarnessPaths(settings);\n const agentSession = await createAgentSession({\n projectDir: opts.projectDir,\n agentDir: session.agentDir,\n harness: session.harness,\n model: session.model,\n resumeSessionId: session.harnessSessionId,\n projectClaudeMd: path.join(opts.projectDir, \"CLAUDE.md\"),\n promptsDir: path.join(opts.projectDir, harnessPaths.promptsDir),\n sessionId: session.runId,\n onLog: log,\n telemetry,\n trace: flowTrace,\n wsConfig,\n capabilities: capabilityHooks,\n capabilityRegistry,\n // A flow step has no one to answer an approval card: with `permission_mode: interactive`\n // a tool call that needs approval is refused instead of hanging the step.\n unattended: true,\n });\n if (agentSession.composition?.discoverableEntries.length) {\n registerCompositionCapabilities(\n capabilityRegistry,\n agentSession.composition.discoverableEntries,\n );\n }\n const { harness } = agentSession;\n const nodeExecutor = new SessionNodeExecutor({ workspaceDir: opts.projectDir });\n // Same endpoints and credentials the session harness used: the registry\n // and the credential env `createAgentSession` already resolved — not a\n // new resolution, not a new secret channel.\n const subpromptRunner = new SessionSubpromptRunner({\n harnessType: agentSession.harnessType,\n sessionModel: agentSession.model,\n workspaceDir: opts.projectDir,\n registry: agentSession.registry,\n credentialEnv: agentSession.credentialEnv,\n ...(agentSession.modelRef ? { modelRef: agentSession.modelRef } : {}),\n });\n let harnessStarted = false;\n const updatedSession = { ...session };\n\n // Track harness session ID so future resumes can reconnect the SDK thread.\n harness.on(\"agent-event\", () => {\n const runtimeSessionId = harness.runtimeSessionId;\n if (!runtimeSessionId || runtimeSessionId === updatedSession.harnessSessionId) return;\n updatedSession.harnessSessionId = runtimeSessionId;\n void saveSession(opts.projectDir, updatedSession).catch(() => {});\n });\n\n // ── FlowAdapter + stimulus bus ─────────────────────────────────────────\n //\n // Phase 4 of the flow-connector extraction: SessionStimulusBus is the sole\n // turn driver. The legacy FlowOrchestrator + onStateChange subscription\n // are gone — every turn is initiated either by the bus (after an adapter\n // mutation observed via `useBusForStimulus: true`) or by an explicit\n // `bus.signal()` call from this function (the initial flow_started turn).\n //\n // The bus's `driveTurn` callback receives the stimulus paragraph the\n // adapter rendered (not the full orchestrator prompt). It hands the turn to\n // `driveOrchestratorTurn`, which rebuilds the five-section prompt so the\n // agent sees the same flow context the legacy orchestrator produced — and\n // announces it, so a CLI consumer's `onEvent` stream carries the prompt too.\n const flowConnectorId = \"flow\";\n const turnTimeoutMs = opts.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;\n\n const ensureHarnessStarted = async (): Promise<void> => {\n if (harnessStarted) return;\n await harness.start();\n harnessStarted = true;\n };\n\n // Same widening the `state_changed` forwarder below performs: `onEvent` is\n // typed against the bridge's harness-level union, which has no case for a\n // runtime-level event.\n const emitFlowPrompt = (event: FlowPromptEvent): void => {\n opts.onEvent?.(event as unknown as AgentEvent);\n };\n\n const inlineSubFlowRunner = new SessionInlineSubFlowRunner({\n resolveFlow: (flowId) => loadFlow(resolveFlowPath(flowId, opts.projectDir)),\n nodeExecutor,\n subpromptRunner,\n driveAgentTurn: async ({ flow: childFlow, execution, stimulus }) => {\n await ensureHarnessStarted();\n await driveOrchestratorTurn({\n flow: childFlow,\n execution,\n stimulus,\n emit: emitFlowPrompt,\n deliver: (prompt) => awaitAgentEnd(harness, prompt, opts.onEvent, turnTimeoutMs),\n });\n },\n });\n\n // Forward declaration so `driveTurn` can read the live execution\n // snapshot. Assigned just below, before the bus can fire.\n let flowAdapterRef: FlowAdapter | null = null;\n let flowHandleRef: import(\"@skaile/workspaces/connectors\").ConnectorHandle | null = null;\n\n const stimulusBus = createSessionStimulusBus({\n driveTurn: async (\n promptFragment: string,\n metas: Array<Record<string, unknown>>,\n ): Promise<void> => {\n // The adapter signal carries `meta.kind` per stimulus. Use that to\n // reconstruct the typed `TurnStimulus`; for compound batches, fall\n // back to `state_changed` (the union element that means \"look at\n // current state and continue\").\n const lastKind = metas[metas.length - 1]?.kind;\n let stimulus: TurnStimulus;\n if (lastKind === \"flow_started\") {\n stimulus = { kind: \"flow_started\" };\n } else if (\n lastKind === \"user_message\" &&\n typeof metas[metas.length - 1]?.text === \"string\"\n ) {\n const meta = metas[metas.length - 1] as Record<string, unknown>;\n stimulus = {\n kind: \"user_message\",\n text: String(meta.text ?? \"\"),\n senderId: String(meta.senderId ?? \"user\"),\n };\n } else {\n stimulus = { kind: \"state_changed\" };\n }\n // The fragment passed in by the bus is the adapter's\n // `renderStimulusPrompt(stim)` joined across coalesced signals. It is\n // discarded in favour of the structured stimulus, which\n // `driveOrchestratorTurn` rebuilds the full prompt from; that keeps the\n // prompt shape stable and the structured form already contains\n // everything the fragment encoded.\n void promptFragment;\n if (!flowAdapterRef || !flowHandleRef) {\n throw new Error(\"driveTurn fired before FlowAdapter was wired\");\n }\n await flowAdapterRef.drainRuntimeNodes(flowHandleRef);\n const execution = flowAdapterRef.getExecution(flowHandleRef);\n if (execution.done || execution.status === \"failed\" || execution.status === \"cancelled\") {\n return;\n }\n if (!flowAdapterRef.shouldDriveAgentTurn(flowHandleRef, stimulus)) return;\n await ensureHarnessStarted();\n await driveOrchestratorTurn({\n flow,\n execution,\n stimulus,\n emit: emitFlowPrompt,\n deliver: (prompt) => awaitAgentEnd(harness, prompt, opts.onEvent, turnTimeoutMs),\n });\n },\n log: flowLog,\n });\n\n const flowAdapter = new FlowAdapter();\n const flowHandle = await flowAdapter.connect(\n {\n id: flowConnectorId,\n driver: \"flow\",\n access: \"read-write\" as const,\n options: {\n flow,\n seed: {\n runId: session.runId,\n startedBy: \"cli\",\n autonomousMode: opts.autonomousMode ?? true,\n },\n stimulusBus,\n useBusForStimulus: true,\n nodeExecutor,\n subpromptRunner,\n inlineSubFlowRunner,\n },\n },\n {}, // flow needs no connect context\n );\n flowAdapterRef = flowAdapter;\n flowHandleRef = flowHandle;\n\n // Flow operations retain the connector's published bare protocol names;\n // this is the intentional exception to generic capability namespaces.\n for (const operation of flowAdapter.tools\n .describeOperations(flowHandle)\n .filter(({ name }) => FLOW_AGENT_OPERATION_NAMES.has(name))) {\n const shape: Record<string, z.ZodType> = {};\n for (const arg of operation.args) {\n let schema: z.ZodType;\n switch (arg.type) {\n case \"boolean\":\n schema = z.boolean();\n break;\n case \"number\":\n schema = z.number();\n break;\n case \"json\":\n schema = z.json();\n break;\n default:\n schema = z.string();\n }\n shape[arg.name] = arg.required ? schema : schema.optional();\n }\n capabilityRegistry.register(\n defineCapability({\n name: operation.name,\n displayName: operation.name,\n description: operation.description,\n input: z.object(shape),\n side: \"agent\",\n origin: { kind: \"flow\", flowId: flow.id },\n scope: \"session\",\n audience: [\"llm\"],\n kind: operation.accessLevel === \"read\" ? \"query\" : \"effect\",\n handler: async (args: Record<string, unknown>) =>\n flowAdapter.executeOp(flowHandle, operation.name, args),\n }),\n \"agent\",\n );\n }\n\n // Forward state_changed events to the caller. The bus computes a\n // turn-kicking stimulus on each adapter mutation; the host-facing\n // event stream still observes the full snapshot via onChange.\n flowAdapter.onStateChange(flowHandle, (state: FlowExecution) => {\n opts.onEvent?.({\n type: \"state_changed\",\n store: `flow:${state.runId}`,\n state: state as unknown as Record<string, unknown>,\n } as unknown as AgentEvent);\n });\n\n // ── Execute ────────────────────────────────────────────────────────────\n flowLog.info(\"starting flow\", {\n flowId: flow.id,\n flowName: flow.name,\n runId: session.runId,\n });\n\n let runError: unknown;\n try {\n // Kick the initial flow_started turn explicitly. Subsequent turns are\n // driven by the bus signaling whenever the adapter mutates.\n const initialStimulus: TurnStimulus = { kind: \"flow_started\" };\n await stimulusBus.signal(flowConnectorId, {\n promptFragment: renderStimulusPrompt(initialStimulus),\n meta: { kind: initialStimulus.kind },\n });\n\n const finalState = flowAdapter.getExecution(flowHandle);\n if (finalState.done) {\n flowLog.info(\"flow complete\", { flowId: flow.id, flowName: flow.name });\n } else if (finalState.status === \"failed\") {\n flowLog.error(\"flow failed\", undefined, { flowId: flow.id, flowName: flow.name });\n } else {\n flowLog.warn(\"flow paused awaiting further stimulus\", {\n flowId: flow.id,\n status: finalState.status,\n note: \"CLI mode does not supply human approval/input decisions\",\n });\n }\n } catch (err) {\n // The harness could not start (SDK missing, bad credentials, …): no node ran, so the\n // session is `failed` with the cause, not a `paused` run that `resume` would pick up.\n runError = err;\n throw err;\n } finally {\n harness.kill();\n const lastState = flowAdapter.getExecution(flowHandle);\n const failed = runError !== undefined;\n let status: \"complete\" | \"failed\" | \"paused\" = \"paused\";\n if (failed) status = \"failed\";\n else if (lastState.status === \"complete\") status = \"complete\";\n await saveSession(\n opts.projectDir,\n touchSession({\n ...updatedSession,\n harnessSessionId: harness.runtimeSessionId ?? updatedSession.harnessSessionId,\n status,\n ...(failed\n ? { error: runError instanceof Error ? runError.message : String(runError) }\n : {}),\n }),\n ).catch(() => {});\n await flowAdapter.disconnect(flowHandle).catch(() => {});\n await agentSession.dispose();\n telemetry.endTrace(flowTrace, {\n status: flowAdapter.getExecution(flowHandle).status === \"complete\" ? \"ok\" : \"error\",\n });\n await telemetry.flush().catch(() => {});\n }\n } finally {\n disposeLogStore();\n }\n}\n\n/**\n * Resume an existing session from the CLI.\n *\n * With the Phase 2 turn-based model, flow state is NOT persisted to\n * local session files — only the harness session ID is kept. The CLI\n * can resume the agent's conversation thread, but the flow execution\n * itself starts from scratch because the runner has no durable store\n * for per-run state.\n *\n * For a governed, resumable flow run, use a host that persists flow\n * state (e.g. the Skaile platform). CLI resume is retained as a\n * harness-level convenience only: we load the session, restart the\n * flow, and the SDK will reconnect to the prior conversation thread.\n *\n * @docLink packages/factory-assets/flow#resume-flow\n */\nexport async function resumeFlow(opts: ResumeOptions): Promise<void> {\n const runner = await loadRunnerModule();\n const { loadSession, loadSessionById, bootstrapRunnerLogStore } = runner;\n\n const session = opts.sessionId\n ? await loadSessionById(opts.projectDir, opts.sessionId)\n : await loadSession(opts.projectDir);\n\n if (!session) {\n const hint = opts.sessionId\n ? `session ${opts.sessionId}`\n : `current session in ${opts.projectDir}/.skaile`;\n throw new Error(`No session found (${hint}) — run 'start' first`);\n }\n\n const flowPath = resolveFlowPath(session.flowId, opts.projectDir);\n\n // Bootstrap a transient logger for the resume diagnostics. The inner\n // runFlow() call will register its own LogStore for the new run. Keep\n // OnLogBridgeSink wiring so callers passing onLog still see this line.\n const wsConfigEarly = resolveSkWorkspaceConfig(opts.projectDir);\n const { dispose: disposeLogStore } = bootstrapRunnerLogStore({\n sessionId: session.runId,\n projectDir: opts.projectDir,\n yamlBlock: wsConfigEarly.logging,\n onLog: opts.onLog,\n stdout: opts.onLog === undefined,\n });\n const flowLog = createLogger({\n kind: \"flow-connector\",\n subkind: \"run\",\n instance: session.runId,\n });\n flowLog.info(\"resuming session\", {\n runId: session.runId,\n flowId: session.flowId,\n note: \"CLI mode does not persist flow state — flow restarts from scratch; harness thread resumes\",\n });\n\n try {\n await runFlow({\n projectDir: opts.projectDir,\n flowPath,\n agentDir: opts.agentDir ?? session.agentDir,\n harness: session.harness,\n model: session.model,\n sessionLabel: session.label,\n resumeSession: session,\n dryRun: opts.dryRun,\n sessionTimeoutMs: opts.sessionTimeoutMs,\n onEvent: opts.onEvent,\n onLog: opts.onLog,\n });\n } finally {\n disposeLogStore();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function validatePinnedVersions(\n flow: Awaited<ReturnType<typeof loadFlow>>,\n projectDir: string,\n log: (line: string) => void,\n): Promise<void> {\n const pinnedNodes = flowSkillVersionPins(flow);\n if (pinnedNodes.length === 0) return;\n\n const skillVersions = new Map<string, string>();\n const aiResourcesDir = findAiResourcesDir(projectDir);\n if (aiResourcesDir) {\n for (const node of pinnedNodes) {\n const skillId = node.skillId;\n if (skillVersions.has(skillId)) continue;\n const skillPath = findSkillMd(aiResourcesDir, skillId);\n if (skillPath) {\n const content = fs.readFileSync(skillPath, \"utf-8\");\n const fm = parseSkillFrontmatter(content);\n skillVersions.set(skillId, fm.metadata?.version ?? fm.version ?? \"\");\n }\n }\n }\n\n const checks = validateFlowVersions(pinnedNodes, skillVersions);\n const failures = checks.filter((c) => !c.satisfied);\n if (failures.length > 0) {\n const lines = failures.map(\n (f) => ` ${f.nodeId}: wants ${f.requested}, found ${f.actual || \"(none)\"}`,\n );\n throw new Error(`Skill version mismatch:\\n${lines.join(\"\\n\")}`);\n }\n for (const c of checks.filter((c) => c.satisfied)) {\n log(` Version OK: ${c.skillId} ${c.actual} satisfies ${c.requested}`);\n }\n}\n\n/**\n * Assert `found` sits inside one of `roots`.\n *\n * A backstop, not the primary control: `isValidAssetName` already rejects every\n * id containing a separator, and `findFlowFileInRoots` skips any candidate that\n * escapes its search dir. So on today's code this cannot fire — it is here to\n * fail loudly rather than silently if a future lookup stops enforcing\n * containment itself. Widening the accepted extensions must never widen which\n * paths are reachable, and this is the line that keeps that honest.\n */\nfunction assertContainedInAnyRoot(found: string, roots: string[], flowId: string): void {\n const resolved = path.resolve(found);\n const inside = roots.some((root) => {\n const relative = path.relative(path.resolve(root), resolved);\n return !relative.startsWith(\"..\") && !path.isAbsolute(relative);\n });\n if (!inside) {\n throw new Error(`Flow path escapes its lookup root: ${JSON.stringify(flowId)}`);\n }\n}\n\n/** One line per near-miss: a file that is right there but was still rejected. */\nfunction describeMisses(misses: FlowLookupMiss[], heading: string): string {\n const seen = new Set<string>();\n const lines: string[] = [];\n for (const miss of misses) {\n if (seen.has(miss.path)) continue;\n seen.add(miss.path);\n lines.push(\n miss.reason === \"id-mismatch\"\n ? ` ${miss.path}: declares id ${JSON.stringify(miss.declaredId ?? \"\")}`\n : ` ${miss.path}: could not be parsed (${miss.error ?? \"unknown error\"})`,\n );\n }\n return lines.length > 0 ? `\\n${heading}\\n${lines.join(\"\\n\")}` : \"\";\n}\n\n/**\n * Resolve one flow identity through the CLI/serve host's normal lookup order —\n * the same roots and filenames `skaile run` and `flow list` use, via\n * {@link flowLookupRoots} / {@link findFlowFileInRoots}. Resolution is by the\n * **declared** `id`, not by filename.\n *\n * @throws {Error} When `flowId` is not a canonical asset name, when no file\n * declares it, or when a match somehow resolves outside every lookup root.\n */\nexport function resolveFlowPath(flowId: string, projectDir: string): string {\n // Sub-flow targets and resumed session records are the two callers, so an\n // identity that is not canonical is a bug in the caller, not a missing file.\n if (!isValidAssetName(flowId)) {\n throw new Error(`Invalid canonical flow identity: ${JSON.stringify(flowId)}`);\n }\n\n const roots = flowLookupRoots(projectDir);\n const misses: FlowLookupMiss[] = [];\n const found = findFlowFileInRoots(flowId, roots, { onMiss: (m) => misses.push(m) });\n if (found) {\n assertContainedInAnyRoot(found, roots, flowId);\n return found;\n }\n\n // A file that is present but unparseable is a different problem from a missing\n // one, and \"not found\" is the wrong headline for it — that exact misdirection\n // is what this change exists to remove, so don't reintroduce it here.\n if (misses.length > 0 && misses.every((m) => m.reason === \"unparseable\")) {\n throw new Error(\n `Flow ${flowId} was found but could not be loaded.` + describeMisses(misses, \"Candidates:\"),\n );\n }\n\n const shown = roots.slice(0, 3).join(\", \");\n const more = roots.length > 3 ? \", …\" : \"\";\n // Spelled from FLOW_FILE_EXTENSIONS so the message cannot drift from the\n // candidate list the lookup actually probes.\n const accepted = FLOW_FILE_EXTENSIONS.map((ext) => `${flowId}${ext}`).join(\" | \");\n throw new Error(\n `Flow not found: ${flowId}. Searched ${roots.length} root(s) (${shown || \"none\"}${more}) ` +\n `for ${accepted} — flat, or inside a ${flowId}/ directory. ` +\n `Only the flows of this project are found: run \\`skaile add flow:@<publisher>/<name>\\` first for a flow that lives in a library or source.` +\n describeMisses(misses, \"Near misses:\"),\n );\n}\n\n/** Walk up from projectDir to find ai-assets/ */\nfunction findAiResourcesDir(projectDir: string): string | null {\n let dir = projectDir;\n for (let i = 0; i < 6; i++) {\n const candidate = path.join(dir, \"ai-assets\");\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/** Find SKILL.md for a given skill ID in any `skills/` directory under ai-assets */\nfunction findSkillMd(aiResourcesDir: string, skillId: string): string | null {\n for (const skillsDir of findKindDirs(aiResourcesDir, \"skills\")) {\n const found = walkForSkill(skillsDir, skillId);\n if (found) return found;\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Turn-wait helper\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal harness surface needed by the bus's `driveTurn` callback. Mirrors\n * the slice the legacy `FlowOrchestrator` consumed (`prompt` + `on` +\n * `removeAllListeners`) so we can keep the wait helper private to this\n * module without pulling in a runtime dep on `@skaile/workspaces/bridge`.\n */\ninterface TurnHarnessSurface {\n prompt(message: string): Promise<void>;\n on(event: \"agent-event\", handler: (event: AgentEvent) => void): void;\n removeAllListeners(event: \"agent-event\"): void;\n}\n\n/**\n * Send a prompt to the harness and resolve when the agent emits\n * `agent_end` (or reject on an `error` that is not an in-place retry).\n * Identical contract to the legacy `awaitAgentEnd` helper from\n * `flow-orchestrator.ts`. Phase 4 lifts the helper into `run-flow.ts` because\n * the bus now owns turn driving. Exported for tests only.\n */\nexport function awaitAgentEnd(\n harness: TurnHarnessSurface,\n prompt: string,\n onEvent: ((event: AgentEvent) => void) | undefined,\n timeoutMs: number,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const done = (err?: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n harness.removeAllListeners(\"agent-event\");\n if (err) reject(err);\n else resolve();\n };\n\n const timer = setTimeout(\n () => done(new Error(`Flow turn timed out after ${timeoutMs / 1000}s`)),\n timeoutMs,\n );\n\n harness.on(\"agent-event\", (event: AgentEvent) => {\n onEvent?.(event);\n if (event.type === \"agent_end\") done();\n // An in-place retry replays this same turn; its own end settles it.\n else if (event.type === \"error\" && event.retrying !== true) {\n const msg =\n (event as { error?: string; message?: string }).error ??\n (event as { message?: string }).message ??\n \"Agent error\";\n done(new Error(msg));\n }\n });\n\n harness.prompt(prompt).catch(done);\n });\n}\n\nfunction walkForSkill(dir: string, skillId: string): string | null {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const full = path.join(dir, entry.name);\n const skillMd = path.join(full, \"SKILL.md\");\n if (fs.existsSync(skillMd)) {\n if (entry.name === skillId) return skillMd;\n } else {\n const found = walkForSkill(full, skillId);\n if (found) return found;\n }\n }\n return null;\n}\n"]}
@@ -1,7 +1,8 @@
1
- import { compositeSha256 } from './chunk-ZBHZLWV3.js';
2
- import { parseAssetRef } from './chunk-LSSYC5IC.js';
1
+ import { compositeSha256 } from './chunk-KPKGWXUJ.js';
2
+ import { parseAssetRef } from './chunk-IZQOO6MN.js';
3
3
  import { createHash } from 'crypto';
4
- import { rm, mkdir, writeFile } from 'fs/promises';
4
+ import { openSync, fstatSync, readSync, chmodSync, closeSync } from 'fs';
5
+ import { rm, mkdir, writeFile, chmod } from 'fs/promises';
5
6
  import { isAbsolute, resolve, sep, join, dirname } from 'path';
6
7
 
7
8
  function assertSafeManifestPath(installPath, p) {
@@ -33,9 +34,29 @@ function longestCommonDirPrefix(paths) {
33
34
  }
34
35
  return common.join("/");
35
36
  }
37
+ function isScriptBytes(bytes) {
38
+ return bytes.length >= 2 && bytes[0] === 35 && bytes[1] === 33;
39
+ }
40
+ var EXECUTABLE_MODE = 493;
41
+ function restoreScriptModes(root, relPaths) {
42
+ for (const rel of relPaths) {
43
+ let fd;
44
+ try {
45
+ fd = openSync(join(root, rel), "r");
46
+ if ((fstatSync(fd).mode & 73) !== 0) continue;
47
+ const head = Buffer.alloc(2);
48
+ if (readSync(fd, head, 0, 2, 0) === 2 && isScriptBytes(head)) {
49
+ chmodSync(join(root, rel), EXECUTABLE_MODE);
50
+ }
51
+ } catch {
52
+ } finally {
53
+ if (fd !== void 0) closeSync(fd);
54
+ }
55
+ }
56
+ }
36
57
  async function installFromManifest(opts) {
37
58
  const { manifest, libraryRoot } = opts;
38
- const fetcher = opts.fetcher ?? (await import('./source-fetch-github-ST4MFL3D.js')).fetchAssetFilesFromGitHub;
59
+ const fetcher = opts.fetcher ?? (await import('./source-fetch-github-RWHV4I5Z.js')).fetchAssetFilesFromGitHub;
39
60
  if (opts.targetDir !== void 0) {
40
61
  return installFlat(manifest, opts.targetDir, fetcher);
41
62
  }
@@ -86,6 +107,7 @@ async function installFromManifest(opts) {
86
107
  const target = join(installPath, f.path);
87
108
  await mkdir(dirname(target), { recursive: true });
88
109
  await writeFile(target, bytes[f.path]);
110
+ if (isScriptBytes(bytes[f.path])) await chmod(target, EXECUTABLE_MODE);
89
111
  }
90
112
  } catch (e) {
91
113
  await rm(installPath, { recursive: true, force: true }).catch(() => {
@@ -118,10 +140,11 @@ async function installFlat(manifest, targetDir, fetcher) {
118
140
  const dest = join(target, relPath);
119
141
  await mkdir(dirname(dest), { recursive: true });
120
142
  await writeFile(dest, buf);
143
+ if (isScriptBytes(buf)) await chmod(dest, EXECUTABLE_MODE);
121
144
  }
122
145
  return { installPath: target };
123
146
  }
124
147
 
125
- export { assertSafeManifestPath, installFromManifest, longestCommonDirPrefix };
126
- //# sourceMappingURL=chunk-YLLVSR2U.js.map
127
- //# sourceMappingURL=chunk-YLLVSR2U.js.map
148
+ export { assertSafeManifestPath, installFromManifest, isScriptBytes, longestCommonDirPrefix, restoreScriptModes };
149
+ //# sourceMappingURL=chunk-E5NQRHEB.js.map
150
+ //# sourceMappingURL=chunk-E5NQRHEB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../library/src/install/install-from-manifest.ts"],"names":[],"mappings":"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","file":"chunk-E5NQRHEB.js","sourcesContent":["/**\n * Pointer-only install path.\n *\n * Given an {@link InstallManifest} (the Pointer Triple the Catalog hands\n * clients), this:\n *\n * 1. fetches the asset bytes directly from the upstream repo at the pinned\n * commit (via an injectable fetcher, default {@link fetchAssetFilesFromGitHub});\n * 2. verifies EVERY per-file SHA256 against `manifest.files[].sha256`;\n * 3. verifies the composite SHA256 rollup over the sorted\n * `<path>:<sha256>\\n` lines against `manifest.sha256`;\n * 4. writes the verified bytes under `<libraryRoot>/@<publisher>/<name>/<version>`.\n *\n * Any hash mismatch is a hard failure — bytes are not written if per-file\n * verification fails, and the composite check is the second gate.\n *\n * @docLink packages/library/concepts#install\n */\n\nimport { createHash } from \"node:crypto\";\nimport { chmodSync, closeSync, fstatSync, openSync, readSync } from \"node:fs\";\nimport { chmod, mkdir, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport type { InstallManifest } from \"@skaile/workspaces/types\";\n// Narrow module, not the `core` barrel: the barrel's chunks carry `import.meta`,\n// which breaks consumers that transpile this entry to CommonJS.\nimport { parseAssetRef } from \"../../../core/src/models.js\";\nimport { compositeSha256 } from \"../../../core/src/publish-manifest.js\";\n\n/**\n * Validate a single manifest-supplied file path against path traversal.\n *\n * `manifest.files[].path` comes off the network — the attacker controls the\n * entire manifest (and therefore every hash in it), so hash verification can\n * NEVER mitigate a malicious *destination*. A path like\n * `../../../../home/user/.bashrc` or an absolute path would escape\n * `installPath` and yield an arbitrary file write. Every path is checked\n * BEFORE any fetch or write happens; the first bad path aborts the entire\n * install with a hard throw.\n *\n * A path is rejected if ANY of:\n * - it is empty;\n * - it is absolute (`path.isAbsolute`) or has a leading slash;\n * - it contains a `..` segment;\n * - `path.resolve(installPath, p)` is not `installPath` itself and does not\n * start with `installPath + path.sep` (escapes the install dir).\n *\n * @throws An error matching `/unsafe path in manifest/` on the first bad path.\n */\nexport function assertSafeManifestPath(installPath: string, p: string): void {\n const bad = (): never => {\n throw new Error(`unsafe path in manifest: ${p}`);\n };\n if (!p || p.length === 0) bad();\n if (isAbsolute(p) || p.startsWith(\"/\") || p.startsWith(\"\\\\\")) bad();\n const segments = p.split(/[/\\\\]/);\n if (segments.some((s) => s === \"..\")) bad();\n const resolved = resolve(installPath, p);\n if (resolved !== installPath && !resolved.startsWith(installPath + sep)) bad();\n}\n\n/**\n * Validate one component (publisher / name / version) of the attacker-controlled\n * `manifest.ref`.\n *\n * `installPath` is built by joining these components onto `libraryRoot`. A\n * component containing a path separator or a `..` / leading-dot segment would\n * let `installPath` itself escape `libraryRoot` — yielding an arbitrary file\n * write AND, via the pre-write `rm(installPath, { recursive })`, an arbitrary\n * recursive delete. The per-file `assertSafeManifestPath` guard cannot catch\n * this: it only validates each `f.path` *relative to* `installPath`, never\n * `installPath` itself. Components must be plain identifier-like strings.\n *\n * @throws An error matching `/unsafe ref/` on a bad component.\n */\nfunction assertSafeRefComponent(kind: string, value: string): void {\n // Reject empty, leading-dot (covers `.` and `..`), path separators, and\n // ASCII control characters (NUL et al.) — fails a malformed segment fast\n // with a domain-specific error rather than a raw EINVAL deeper in.\n const hasControlChar = [...value].some((c) => c.charCodeAt(0) < 0x20);\n if (!value || value.startsWith(\".\") || /[/\\\\]/.test(value) || hasControlChar) {\n throw new Error(`unsafe ref ${kind} component in manifest: '${value}'`);\n }\n}\n\n/**\n * Longest common **directory** prefix across manifest paths, compared by whole\n * slash-delimited segments (never raw-string — so `app/` and `app-data/` never\n * collide). Each path's basename is excluded, so the result is always a\n * directory prefix and every path keeps a non-empty remainder after stripping.\n *\n * Used by flat mode to reproduce the platform pointer-installer's asset-rooting:\n * the store persists repo-root-relative paths (e.g. `skaile-platform/mcpo/xls/MCP.md`)\n * but the runner scans `.skaile/assets/<kind>/<name>/` for immediate-child files,\n * so this prefix is stripped from the WRITE path while the fetch keeps the full\n * repo path. Returns `''` when there is no common directory (a no-op strip).\n */\nexport function longestCommonDirPrefix(paths: readonly string[]): string {\n if (paths.length === 0) return \"\";\n const dirSegments = paths.map((p) => p.split(\"/\").slice(0, -1));\n let common = dirSegments[0]!;\n for (let i = 1; i < dirSegments.length && common.length > 0; i++) {\n const segs = dirSegments[i]!;\n let n = 0;\n while (n < common.length && n < segs.length && common[n] === segs[n]) n++;\n common = common.slice(0, n);\n }\n return common.join(\"/\");\n}\n\n/**\n * Whether `bytes` start a script (`#!`). A pointer manifest and GitHub's raw host carry no file\n * modes, while the library or clone the same asset comes from keeps its script executable, so a\n * shebang is what marks a file executable here (p1657).\n */\nexport function isScriptBytes(bytes: Uint8Array): boolean {\n return bytes.length >= 2 && bytes[0] === 0x23 && bytes[1] === 0x21;\n}\n\n/** The mode of an executable file written from store bytes. */\nconst EXECUTABLE_MODE = 0o755;\n\n/**\n * Make every file of `relPaths` under `root` that starts with `#!` executable. For bytes an\n * earlier install already wrote (a project store cache from before exec bits were kept), so a\n * restore from them deploys the same modes as a fresh fetch. A missing or unreadable file is\n * skipped.\n */\nexport function restoreScriptModes(root: string, relPaths: readonly string[]): void {\n for (const rel of relPaths) {\n let fd: number | undefined;\n try {\n fd = openSync(join(root, rel), \"r\");\n if ((fstatSync(fd).mode & 0o111) !== 0) continue;\n const head = Buffer.alloc(2);\n if (readSync(fd, head, 0, 2, 0) === 2 && isScriptBytes(head)) {\n chmodSync(join(root, rel), EXECUTABLE_MODE);\n }\n } catch {\n // Not readable or not a file: nothing to fix.\n } finally {\n if (fd !== undefined) closeSync(fd);\n }\n }\n}\n\n/**\n * Fetcher signature — fetches `{ path → Buffer }` for the requested paths at\n * a pinned upstream commit. {@link fetchAssetFilesFromGitHub} is the default\n * production implementation; tests inject a mock.\n */\nexport type AssetFetcher = (opts: {\n url: string;\n commitSha: string;\n paths: string[];\n}) => Promise<Record<string, Buffer>>;\n\n/**\n * Options for {@link installFromManifest}.\n */\nexport interface InstallOpts {\n /** The pointer-only install manifest from the Catalog. */\n manifest: InstallManifest;\n /** Filesystem root the asset is installed under (ref-derived mode). */\n libraryRoot: string;\n /**\n * Pluggable fetcher so tests can inject mock data. Defaults to\n * {@link fetchAssetFilesFromGitHub} in production.\n */\n fetcher?: AssetFetcher;\n /**\n * Flat-layout mode. When set, install-core reproduces the platform\n * pointer-installer's behavior: it ignores `libraryRoot`/ref-derivation, does\n * NOT parse `manifest.ref` and does NOT verify the composite sha256, strips\n * the longest-common-dir prefix from each path, per-file sha256-verifies, and\n * writes the stripped paths as immediate children of `targetDir` (what the\n * runner's `.skaile/assets/<kind>/<name>/` scan requires). `installPath` is\n * `targetDir`. Absent → unchanged ref-derived `@<pub>/name/version/<path>`\n * layout with composite verify.\n */\n targetDir?: string;\n}\n\n/**\n * Result of a successful {@link installFromManifest} call.\n */\nexport interface InstallResult {\n /** Absolute path the asset files were written to. */\n installPath: string;\n}\n\n/**\n * Fetch, verify, and write an asset's files per its {@link InstallManifest}.\n *\n * @throws An error matching `/hash mismatch/i` if any per-file SHA256 differs.\n * @throws An error matching `/composite hash mismatch/i` if the rollup differs.\n * @throws An error if the ref is malformed or the fetcher omits a file.\n */\nexport async function installFromManifest(opts: InstallOpts): Promise<InstallResult> {\n const { manifest, libraryRoot } = opts;\n const fetcher =\n opts.fetcher ?? (await import(\"./source-fetch-github.js\")).fetchAssetFilesFromGitHub;\n\n // Flat mode: reproduce the platform pointer-installer's asset-rooted layout.\n // No ref parse, no composite verify — the platform store may not satisfy a\n // ref-grammar or composite, and the runner only needs immediate-child files.\n if (opts.targetDir !== undefined) {\n return installFlat(manifest, opts.targetDir, fetcher);\n }\n\n // 1. Parse ref into install path: `skill:@x/git#1.0.0` → `<root>/@x/git/1.0.0`.\n // Done first so the C1 path-traversal guard can resolve against installPath\n // BEFORE any network fetch happens. The ref is attacker-controlled, so each\n // segment is further validated as a safe path component (H1) after parsing.\n // `parseAssetRef` is the single canonical grammar (`kind:@publisher/name#version`);\n // the legacy trailing-`@version` shape was removed in core and is rejected here.\n let parsed: ReturnType<typeof parseAssetRef>;\n try {\n parsed = parseAssetRef(manifest.ref);\n } catch (e) {\n throw new Error(`invalid ref: ${manifest.ref}: ${e instanceof Error ? e.message : String(e)}`);\n }\n const publisher = parsed.publisher;\n const name = parsed.name;\n const version = parsed.pin;\n if (!publisher) throw new Error(`invalid ref: ${manifest.ref} (missing publisher)`);\n if (!version) throw new Error(`invalid ref: ${manifest.ref} (missing version pin)`);\n assertSafeRefComponent(\"publisher\", publisher);\n assertSafeRefComponent(\"name\", name);\n assertSafeRefComponent(\"version\", version);\n const root = resolve(libraryRoot);\n const installPath = resolve(join(root, `@${publisher}`, name, version));\n // Defense in depth: even with the segment guards above, assert the built\n // installPath stays strictly inside libraryRoot before any write or `rm`.\n if (installPath !== root && !installPath.startsWith(root + sep)) {\n throw new Error(`unsafe install path: ref '${manifest.ref}' resolves outside the library root`);\n }\n\n // 2. [C1] Validate EVERY manifest path against traversal BEFORE fetching.\n // The attacker controls the manifest (and thus all hashes) — hashes verify\n // content, never destination. Reject the whole install on the first bad path.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n }\n\n // 3. Fetch all files at the pinned commit.\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // 4. Verify per-file SHA256 — hard fail before writing anything. The path\n // key used to read from the fetcher result is re-guarded as defense in depth.\n for (const f of manifest.files) {\n assertSafeManifestPath(installPath, f.path);\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n }\n\n // 5. Verify composite SHA256 over the sorted `<path>:<sha256>\\n` lines.\n const actualComposite = compositeSha256(manifest.files);\n if (actualComposite !== manifest.sha256) {\n throw new Error(`composite hash mismatch: expected ${manifest.sha256}, got ${actualComposite}`);\n }\n\n // 6. [M1] Write all verified files. A failed install must leave NO partial\n // directory: any prior `installPath` is removed first (clean overwrite), and\n // a mid-loop write failure removes the partially-written tree before\n // rethrowing.\n await rm(installPath, { recursive: true, force: true });\n try {\n for (const f of manifest.files) {\n const target = join(installPath, f.path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, bytes[f.path]!);\n if (isScriptBytes(bytes[f.path]!)) await chmod(target, EXECUTABLE_MODE);\n }\n } catch (e) {\n await rm(installPath, { recursive: true, force: true }).catch(() => {});\n throw e;\n }\n\n return { installPath };\n}\n\n/**\n * Flat-layout install — the platform pointer-installer's behavior, made canonical\n * in install-core. Validates every path, fetches with the FULL repo paths, per-file\n * sha256-verifies, then strips the longest-common-dir prefix and writes each file\n * as `join(targetDir, path.slice(assetRoot.length + 1))` — immediate children of\n * `targetDir`. No ref parse, no composite check.\n */\nasync function installFlat(\n manifest: InstallManifest,\n targetDir: string,\n fetcher: AssetFetcher,\n): Promise<InstallResult> {\n const target = resolve(targetDir);\n\n // Gate every path before any fetch — the attacker controls the whole manifest.\n for (const f of manifest.files) {\n assertSafeManifestPath(target, f.path);\n }\n\n // Fetch keys off the FULL repo path (matches the upstream tree).\n const paths = manifest.files.map((f) => f.path);\n const bytes = await fetcher({\n url: manifest.source.url,\n commitSha: manifest.source.commitSha,\n paths,\n });\n\n // Strip the asset-root dir prefix from the WRITE path only — the fetch above\n // still keyed off the full repo path. Stripping removes leading whole segments\n // (never the basename), so a non-empty remainder always survives.\n const assetRoot = longestCommonDirPrefix(paths);\n\n for (const f of manifest.files) {\n const buf = bytes[f.path];\n if (!buf) throw new Error(`fetcher returned no bytes for ${f.path}`);\n const actual = createHash(\"sha256\").update(buf).digest(\"hex\");\n if (actual !== f.sha256) {\n throw new Error(`hash mismatch for ${f.path}: expected ${f.sha256}, got ${actual}`);\n }\n const relPath = assetRoot ? f.path.slice(assetRoot.length + 1) : f.path;\n // Re-guard the post-strip destination — it is what we actually write.\n assertSafeManifestPath(target, relPath);\n const dest = join(target, relPath);\n await mkdir(dirname(dest), { recursive: true });\n await writeFile(dest, buf);\n if (isScriptBytes(buf)) await chmod(dest, EXECUTABLE_MODE);\n }\n\n return { installPath: target };\n}\n"]}
@@ -1,6 +1,7 @@
1
- import { getProviderPreset, providerCredentialEnvName } from './chunk-ILLTBKDJ.js';
1
+ import { providerCredentialEnvName } from './chunk-S6KZHPR4.js';
2
+ import { getProviderPreset } from './chunk-6UP2EDFN.js';
2
3
  import { globalSkaileDir } from './chunk-L5VSIPQD.js';
3
- import { registryEntries, parseModelRef, isEntryEnabled, resolveEntryBaseUrl } from './chunk-LSI2IVFT.js';
4
+ import { registryEntries, parseModelRef, isEntryEnabled, resolveEntryBaseUrl } from './chunk-RXGPFAMN.js';
4
5
  import { createHash } from 'crypto';
5
6
  import { mkdirSync, rmSync, writeFileSync, renameSync } from 'fs';
6
7
  import { join } from 'path';
@@ -121,5 +122,5 @@ function writeCodexConfigToml(home, document) {
121
122
  }
122
123
 
123
124
  export { buildCodexConfigDocument, codexProviderTableId, codexSessionHome, writeCodexConfigToml };
124
- //# sourceMappingURL=chunk-XGULGQA3.js.map
125
- //# sourceMappingURL=chunk-XGULGQA3.js.map
125
+ //# sourceMappingURL=chunk-ELSGFI3I.js.map
126
+ //# sourceMappingURL=chunk-ELSGFI3I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../bridge/src/codex/config-toml.ts"],"names":["stringifyToml"],"mappings":"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","file":"chunk-ELSGFI3I.js","sourcesContent":["/**\n * Codex's `config.toml` adapter — the AI provider registry materialized into\n * the only provider surface the Codex CLI reads (plan §2.3, codex rows).\n *\n * Codex is a **file-shaped** harness: it takes its endpoints from\n * `$CODEX_HOME/config.toml`, never from per-request options. Both codex modes\n * therefore get a session-private `CODEX_HOME` holding a rendered document:\n *\n * - every addressable registry entry becomes `[model_providers.<id>]` with\n * `base_url`, `env_key`, `wire_api`, `query_params` and `http_headers`\n * mapping 1:1 onto the entry's `base_url`, `credential`, `surface`,\n * `query_params` and `headers`;\n * - `model_provider` and `model` at the top level name the selected entry.\n *\n * The rendered file never contains a credential **value** — `env_key` holds\n * the *name* of the per-entry variable (`SKAILE_AIP_<ID>_KEY`, minted by\n * {@link providerCredentialEnvName}), and the value rides in the child\n * environment. An `oauth` entry has no env carrier at all: it gets\n * `requires_openai_auth`, which routes codex to its own auth manager.\n *\n * **Surface coverage.** Codex names the wire protocol `wire_api` and, as of\n * codex-cli 0.154, accepts exactly one value: `responses`. `chat` was removed\n * (\"`wire_api = \\\"chat\\\"` is no longer supported\", openai/codex#7782), and an\n * unknown value fails the *whole* document at load time — one unaddressable\n * entry would take the rest of the registry down with it. Entries whose\n * surface codex cannot speak (`openai-completions`, `anthropic-messages`,\n * `bedrock-converse-stream`, `google-*`) are therefore left out and reported\n * in {@link CodexConfigBuild.skipped} for the harness to log.\n *\n * @docLink packages/bridge/harnesses#codex-harness\n */\n\nimport { createHash } from \"node:crypto\";\nimport { mkdirSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { globalSkaileDir } from \"@skaile/workspaces/core\";\nimport {\n type AIProviderEntry,\n type AIProviderLlmEntry,\n type AIProviderRegistry,\n type AIProviderSurface,\n isEntryEnabled,\n type MergedAIProviderRegistry,\n parseModelRef,\n registryEntries,\n type ResolvedModelRef,\n resolveEntryBaseUrl,\n} from \"@skaile/workspaces/core/provider-registry\";\nimport { stringify as stringifyToml } from \"smol-toml\";\nimport { getProviderPreset } from \"../provider-catalog.js\";\nimport { providerCredentialEnvName } from \"../provider-materialize/credential-env.js\";\n\n/**\n * `surface` → codex `wire_api`. Only the responses-flavoured surfaces have a\n * codex spelling; see the module docstring for why `openai-completions` is\n * absent rather than mapped to the removed `chat` value.\n */\nconst CODEX_WIRE_API: Partial<Record<AIProviderSurface, string>> = {\n \"openai-codex-responses\": \"responses\",\n \"openai-responses\": \"responses\",\n \"azure-openai-responses\": \"responses\",\n};\n\n/**\n * Provider ids codex reserves for its own built-ins. A `[model_providers.<id>]`\n * table under one of them fails the whole document (\"model_providers contains\n * reserved built-in provider IDs\"), so such an entry is rendered under\n * {@link codexProviderTableId}.\n */\nconst CODEX_RESERVED_PROVIDER_IDS: ReadonlySet<string> = new Set([\"openai\", \"ollama\", \"lmstudio\"]);\n\n/**\n * The `[model_providers.<id>]` table name for a registry entry: the entry id,\n * or `skaile-<id>` when codex reserves that id (the `openai` preset).\n */\nexport function codexProviderTableId(id: string): string {\n return CODEX_RESERVED_PROVIDER_IDS.has(id) ? `skaile-${id}` : id;\n}\n\n/** Credential kinds whose value the adapter hands over in an env var. */\nconst ENV_DELIVERED_CREDENTIALS: Record<string, true> = {\n api_key_header: true,\n bearer: true,\n command: true,\n};\n\n/** One `[model_providers.<id>]` table, in codex's own vocabulary. */\nexport interface CodexModelProviderTable {\n /** Display name. Codex rejects a provider table without one. */\n name: string;\n base_url?: string;\n /** Name of the variable carrying the credential — never the credential. */\n env_key?: string;\n wire_api?: string;\n /** Routes codex to its own auth manager (ChatGPT subscription / stored key). */\n requires_openai_auth?: boolean;\n query_params?: Record<string, string>;\n http_headers?: Record<string, string>;\n}\n\n/** The subset of codex's `config.toml` this adapter owns. */\nexport interface CodexConfigDocument {\n /** Table id the session addresses (see {@link codexProviderTableId}); absent when nothing rendered. */\n model_provider?: string;\n /** Provider-side model id. */\n model?: string;\n model_providers: Record<string, CodexModelProviderTable>;\n}\n\n/** An entry codex cannot address, and why. */\nexport interface CodexSkippedEntry {\n id: string;\n reason: string;\n}\n\n/** Result of {@link buildCodexConfigDocument}. */\nexport interface CodexConfigBuild {\n document: CodexConfigDocument;\n /** Selected registry entry id (not the table id), when it rendered. */\n providerId?: string;\n /** Provider-side model id of the selection, when the selector named one. */\n model?: string;\n /**\n * Entries left out of the document. Non-fatal: codex keeps its built-in\n * providers, so a session whose selection was skipped behaves exactly as it\n * did before the registry existed.\n */\n skipped: CodexSkippedEntry[];\n /** Notes from `modelRef` resolution (dangling role, disabled provider, …). */\n warnings: string[];\n /**\n * Set when the selector named an entry codex cannot address: the session\n * must stop with `reason`, not fall back to codex's built-in providers.\n */\n unaddressable?: { id: string; reason: string };\n}\n\n/**\n * Whether the session's selector named the entry `selected` resolved to, rather\n * than reaching it by registry order alone.\n */\nfunction selectionNamesEntry(\n input: CodexConfigInput,\n selected: ResolvedModelRef,\n registry: AIProviderRegistry | MergedAIProviderRegistry,\n): boolean {\n if (selected.role && selected.modelId !== undefined) return true;\n const selector = input.modelRef?.trim() || input.model?.trim() || \"\";\n if (selector.startsWith(`${selected.providerId}/`)) return true;\n const entry = registryEntries(registry).find(([id]) => id === selected.providerId)?.[1] as\n | AIProviderLlmEntry\n | undefined;\n const modelId = selected.modelId;\n return (\n modelId !== undefined &&\n (entry?.model_map?.[modelId] !== undefined || entry?.capabilities?.[modelId] !== undefined)\n );\n}\n\n/** Inputs {@link buildCodexConfigDocument} reads off an `AgentConfig`. */\nexport interface CodexConfigInput {\n registry?: AIProviderRegistry | MergedAIProviderRegistry;\n /** `\"<providerId>/<modelId>\"`, a bare model id, or `\"@role\"`. */\n modelRef?: string;\n /** Legacy model field, used as the selector when `modelRef` is absent. */\n model?: string;\n /** Roles table (`skaile.yaml`), consulted for an `@role` selector. */\n roles?: Record<string, string>;\n}\n\n/**\n * Render one entry as a codex provider table, or explain why codex cannot\n * address it.\n */\nexport function renderCodexProviderTable(\n id: string,\n entry: AIProviderEntry,\n): { table: CodexModelProviderTable } | { skipped: string } {\n if (!isEntryEnabled(entry)) return { skipped: \"entry is disabled\" };\n if (entry.kind !== \"llm\" && entry.kind !== \"embed\")\n return { skipped: `kind '${entry.kind}' is not a model endpoint` };\n const llm = entry as AIProviderLlmEntry;\n // `surface` and `base_url` may live on the catalog preset the entry names —\n // the catalog layer fills them during a merge, but an entry handed straight\n // to a harness has not necessarily been through one.\n const preset = entry.preset ? getProviderPreset(entry.preset) : undefined;\n const surface = llm.surface ?? preset?.surface;\n const wireApi = surface ? CODEX_WIRE_API[surface] : undefined;\n if (!wireApi)\n return {\n skipped: surface\n ? `codex has no wire_api for surface '${surface}'`\n : \"entry declares no surface\",\n };\n const credentialKind = entry.credential?.kind;\n const table: CodexModelProviderTable = { name: entry.label ?? id };\n const baseUrl = resolveEntryBaseUrl(entry) ?? preset?.base_url;\n if (baseUrl) table.base_url = baseUrl;\n if (credentialKind && ENV_DELIVERED_CREDENTIALS[credentialKind])\n table.env_key = providerCredentialEnvName(id);\n table.wire_api = wireApi;\n if (credentialKind === \"oauth\") table.requires_openai_auth = true;\n if (llm.query_params && Object.keys(llm.query_params).length > 0)\n table.query_params = { ...llm.query_params };\n if (entry.headers && Object.keys(entry.headers).length > 0)\n table.http_headers = { ...entry.headers };\n return { table };\n}\n\n/**\n * Build the document for a session: every addressable entry, plus the\n * selection when it resolved to one of them.\n */\nexport function buildCodexConfigDocument(input: CodexConfigInput): CodexConfigBuild {\n const document: CodexConfigDocument = { model_providers: {} };\n const skipped: CodexSkippedEntry[] = [];\n const entries = input.registry ? registryEntries(input.registry) : [];\n for (const [id, entry] of entries) {\n const rendered = renderCodexProviderTable(id, entry);\n if (\"skipped\" in rendered) skipped.push({ id, reason: rendered.skipped });\n else document.model_providers[codexProviderTableId(id)] = rendered.table;\n }\n\n if (!input.registry) return { document, skipped, warnings: [] };\n // An empty selector resolves the same way a bare one does — first entry in\n // registry order. A session that configured an endpoint and named no model\n // still means that endpoint, not codex's built-in default.\n const selected = parseModelRef(\n input.modelRef?.trim() || input.model?.trim() || \"\",\n input.registry,\n input.roles,\n );\n if (!selected) return { document, skipped, warnings: [] };\n const warnings = selected.warnings;\n const tableId = codexProviderTableId(selected.providerId);\n if (!document.model_providers[tableId]) {\n // A selector that names the entry (`ollama/llama3`, a role or a model its\n // `model_map` lists) and cannot be rendered must not fall through to\n // codex's built-in OpenAI: the prompt would go to a provider the user did\n // not pick. A bare model id that matched no entry only landed on the first\n // entry by registry order, so codex's own providers stay the right answer.\n const reason = skipped.find((s) => s.id === selected.providerId)?.reason;\n if (reason && selectionNamesEntry(input, selected, input.registry)) {\n return {\n document,\n skipped,\n warnings,\n unaddressable: { id: selected.providerId, reason },\n };\n }\n return { document, skipped, warnings };\n }\n document.model_provider = tableId;\n if (selected.providerModelId) document.model = selected.providerModelId;\n return {\n document,\n providerId: selected.providerId,\n ...(selected.providerModelId ? { model: selected.providerModelId } : {}),\n skipped,\n warnings,\n };\n}\n\n/** Serialize a document to TOML. Deterministic: registry order throughout. */\nexport function renderCodexConfigToml(document: CodexConfigDocument): string {\n const ordered: Record<string, unknown> = {};\n if (document.model_provider) ordered.model_provider = document.model_provider;\n if (document.model) ordered.model = document.model;\n ordered.model_providers = document.model_providers;\n return `${stringifyToml(ordered)}\\n`;\n}\n\n/**\n * The session-private codex home.\n *\n * Deliberately outside `cwd`: codex's `workspace-write` sandbox makes the\n * working tree writable by the model, and a config home inside it would let a\n * turn rewrite its own `base_url`. `$SKAILE_HOME` (honoured by\n * {@link globalSkaileDir}) relocates the whole tree, which is also the test\n * seam.\n */\nexport function codexSessionHome(config: { cwd: string; sessionId?: string }): string {\n const key =\n config.sessionId && /^[A-Za-z0-9._-]{1,128}$/.test(config.sessionId)\n ? config.sessionId\n : createHash(\"sha256\")\n .update(config.sessionId ?? config.cwd)\n .digest(\"hex\")\n .slice(0, 32);\n return join(globalSkaileDir(), \"codex\", key);\n}\n\n/**\n * Write `<home>/config.toml`, creating the home always. Atomic: a\n * partially written document would fail codex's config load for the whole\n * session.\n *\n * A document with no provider tables says nothing codex does not already\n * know, so nothing is written and a file left by an earlier render is\n * removed — a session that no longer carries a registry must not keep\n * answering to the one it used to have.\n *\n * @returns the absolute path written, or `undefined` when there was nothing\n * to render.\n */\nexport function writeCodexConfigToml(\n home: string,\n document: CodexConfigDocument,\n): string | undefined {\n const path = join(home, \"config.toml\");\n // codex exits when CODEX_HOME names a directory that does not exist, so the\n // home exists before the early return too.\n mkdirSync(home, { recursive: true, mode: 0o700 });\n if (Object.keys(document.model_providers).length === 0) {\n rmSync(path, { force: true });\n return undefined;\n }\n const temporary = join(home, \"config.toml.new\");\n rmSync(temporary, { force: true });\n writeFileSync(temporary, renderCodexConfigToml(document), { mode: 0o600, flag: \"wx\" });\n renameSync(temporary, path);\n return path;\n}\n"]}