@skaile/workspaces 1.16.0 → 2.1.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 (291) hide show
  1. package/CHANGELOG.md +309 -0
  2. package/dist/{asset-feeds-WIBEP37F.js → asset-feeds-FBGBQEYD.js} +25 -24
  3. package/dist/asset-feeds-FBGBQEYD.js.map +1 -0
  4. package/dist/asset-manager/catalog-deployer.js +13 -1
  5. package/dist/asset-manager/index.js +10 -9
  6. package/dist/asset-manager/installer.js +7 -6
  7. package/dist/asset-manager/src/catalog-deployer.d.ts +70 -5
  8. package/dist/asset-manager/src/catalog-deployer.d.ts.map +1 -1
  9. package/dist/asset-manager/src/index.d.ts +41 -17
  10. package/dist/asset-manager/src/index.d.ts.map +1 -1
  11. package/dist/asset-manager/src/mcp-config.d.ts +58 -0
  12. package/dist/asset-manager/src/mcp-config.d.ts.map +1 -0
  13. package/dist/bridge/drivers/claude-sdk.js +108 -56
  14. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  15. package/dist/bridge/drivers/codex.js +3 -2
  16. package/dist/bridge/drivers/codex.js.map +1 -1
  17. package/dist/bridge/drivers/continue.js +4 -3
  18. package/dist/bridge/drivers/continue.js.map +1 -1
  19. package/dist/bridge/drivers/echo.js +3 -2
  20. package/dist/bridge/drivers/echo.js.map +1 -1
  21. package/dist/bridge/drivers/gemini.js +5 -4
  22. package/dist/bridge/drivers/goose.js +4 -3
  23. package/dist/bridge/drivers/goose.js.map +1 -1
  24. package/dist/bridge/drivers/omp.js +3 -2
  25. package/dist/bridge/drivers/omp.js.map +1 -1
  26. package/dist/bridge/drivers/opencode.js +4 -3
  27. package/dist/bridge/drivers/opencode.js.map +1 -1
  28. package/dist/bridge/drivers/qwen.js +5 -4
  29. package/dist/bridge/drivers/qwen.js.map +1 -1
  30. package/dist/bridge/index.js +4 -3
  31. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  32. package/dist/bridge/src/drivers/scrub-transcript.d.ts +21 -1
  33. package/dist/bridge/src/drivers/scrub-transcript.d.ts.map +1 -1
  34. package/dist/{chunk-MO43URUI.js → chunk-2BSXXTUP.js} +7 -7
  35. package/dist/{chunk-MO43URUI.js.map → chunk-2BSXXTUP.js.map} +1 -1
  36. package/dist/{chunk-FIUGSIKC.js → chunk-43TAGQ3Z.js} +19 -11
  37. package/dist/chunk-43TAGQ3Z.js.map +1 -0
  38. package/dist/{chunk-7J7LQP6T.js → chunk-5BGEYZ7I.js} +31 -19
  39. package/dist/chunk-5BGEYZ7I.js.map +1 -0
  40. package/dist/chunk-7GOCNYUV.js +300 -0
  41. package/dist/chunk-7GOCNYUV.js.map +1 -0
  42. package/dist/{chunk-KY5NY7LB.js → chunk-BCTU4TN7.js} +11 -11
  43. package/dist/chunk-BCTU4TN7.js.map +1 -0
  44. package/dist/chunk-BEAIJRVF.js +159 -0
  45. package/dist/chunk-BEAIJRVF.js.map +1 -0
  46. package/dist/{chunk-2TSSCHCQ.js → chunk-BHLNQ4L5.js} +5 -5
  47. package/dist/{chunk-2TSSCHCQ.js.map → chunk-BHLNQ4L5.js.map} +1 -1
  48. package/dist/chunk-BK3WL3QK.js +10 -0
  49. package/dist/chunk-BK3WL3QK.js.map +1 -0
  50. package/dist/{chunk-TFIFNDT2.js → chunk-BTR3ZJ7S.js} +4 -4
  51. package/dist/{chunk-TFIFNDT2.js.map → chunk-BTR3ZJ7S.js.map} +1 -1
  52. package/dist/{chunk-BI2NKPA4.js → chunk-CA5CWLGN.js} +3 -2
  53. package/dist/chunk-CA5CWLGN.js.map +1 -0
  54. package/dist/{chunk-STQOPWPS.js → chunk-CTWE7I7Z.js} +4 -4
  55. package/dist/{chunk-STQOPWPS.js.map → chunk-CTWE7I7Z.js.map} +1 -1
  56. package/dist/{chunk-GXC3TYMQ.js → chunk-CZZRDYT4.js} +70 -32
  57. package/dist/chunk-CZZRDYT4.js.map +1 -0
  58. package/dist/chunk-DYMWJAL4.js +552 -0
  59. package/dist/chunk-DYMWJAL4.js.map +1 -0
  60. package/dist/{chunk-ACXLKNIM.js → chunk-E7HKNQTH.js} +10 -4
  61. package/dist/chunk-E7HKNQTH.js.map +1 -0
  62. package/dist/{chunk-2BQBWWFX.js → chunk-GUKMNUQK.js} +6 -6
  63. package/dist/chunk-GUKMNUQK.js.map +1 -0
  64. package/dist/{chunk-6POODADP.js → chunk-HOL5KD7U.js} +453 -250
  65. package/dist/chunk-HOL5KD7U.js.map +1 -0
  66. package/dist/{chunk-C4KVFALU.js → chunk-L26NGI43.js} +3 -3
  67. package/dist/{chunk-C4KVFALU.js.map → chunk-L26NGI43.js.map} +1 -1
  68. package/dist/{chunk-MZV6WCF3.js → chunk-MAN7AGQJ.js} +3 -3
  69. package/dist/{chunk-MZV6WCF3.js.map → chunk-MAN7AGQJ.js.map} +1 -1
  70. package/dist/{chunk-YULV7UTU.js → chunk-MLYV6WEM.js} +10 -10
  71. package/dist/{chunk-YULV7UTU.js.map → chunk-MLYV6WEM.js.map} +1 -1
  72. package/dist/{chunk-O5VCUU6D.js → chunk-N6TYW6EB.js} +4 -4
  73. package/dist/{chunk-O5VCUU6D.js.map → chunk-N6TYW6EB.js.map} +1 -1
  74. package/dist/{chunk-EPWY2ABE.js → chunk-PSVF3LDU.js} +5 -5
  75. package/dist/{chunk-EPWY2ABE.js.map → chunk-PSVF3LDU.js.map} +1 -1
  76. package/dist/{chunk-M5GJT3D7.js → chunk-PYYL5XMA.js} +3 -3
  77. package/dist/{chunk-M5GJT3D7.js.map → chunk-PYYL5XMA.js.map} +1 -1
  78. package/dist/{chunk-BG4XVMG2.js → chunk-RBOPTTTK.js} +286 -151
  79. package/dist/chunk-RBOPTTTK.js.map +1 -0
  80. package/dist/{chunk-2IJFUAZB.js → chunk-RK3HU3H3.js} +123 -18
  81. package/dist/chunk-RK3HU3H3.js.map +1 -0
  82. package/dist/{chunk-5NZ56R63.js → chunk-RTLQAZAE.js} +18 -6
  83. package/dist/chunk-RTLQAZAE.js.map +1 -0
  84. package/dist/{chunk-MNKUZUN2.js → chunk-SGLGA2AZ.js} +3 -3
  85. package/dist/{chunk-MNKUZUN2.js.map → chunk-SGLGA2AZ.js.map} +1 -1
  86. package/dist/{chunk-JB35MVBN.js → chunk-U5POE4BA.js} +4 -298
  87. package/dist/chunk-U5POE4BA.js.map +1 -0
  88. package/dist/{chunk-A22KZ7GZ.js → chunk-VPXBAEWE.js} +274 -40
  89. package/dist/chunk-VPXBAEWE.js.map +1 -0
  90. package/dist/{chunk-ACWCVB5Q.js → chunk-WVPL4OGD.js} +3 -3
  91. package/dist/{chunk-ACWCVB5Q.js.map → chunk-WVPL4OGD.js.map} +1 -1
  92. package/dist/{chunk-MB6563TL.js → chunk-XQVP6XWR.js} +3 -3
  93. package/dist/{chunk-MB6563TL.js.map → chunk-XQVP6XWR.js.map} +1 -1
  94. package/dist/{chunk-344DEXZS.js → chunk-XSIXGVH6.js} +4 -4
  95. package/dist/{chunk-344DEXZS.js.map → chunk-XSIXGVH6.js.map} +1 -1
  96. package/dist/{chunk-BYS6JDZB.js → chunk-Y6VSFX2A.js} +3 -3
  97. package/dist/{chunk-BYS6JDZB.js.map → chunk-Y6VSFX2A.js.map} +1 -1
  98. package/dist/{chunk-ISA7R7PK.js → chunk-YODP3STD.js} +90 -40
  99. package/dist/chunk-YODP3STD.js.map +1 -0
  100. package/dist/{chunk-WSTY3AWY.js → chunk-ZWFLEMI4.js} +4 -4
  101. package/dist/{chunk-WSTY3AWY.js.map → chunk-ZWFLEMI4.js.map} +1 -1
  102. package/dist/cli/index.js +347 -127
  103. package/dist/cli/index.js.map +1 -1
  104. package/dist/cli/src/asset-feeds.d.ts +2 -2
  105. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  106. package/dist/cli/src/commands/catalog.d.ts +51 -2
  107. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  108. package/dist/cli/src/commands/connector.d.ts +1 -1
  109. package/dist/cli/src/commands/connector.d.ts.map +1 -1
  110. package/dist/cli/src/commands/logs.d.ts.map +1 -1
  111. package/dist/cli/src/commands/manage.d.ts +30 -3
  112. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  113. package/dist/cli/src/commands/project.d.ts +5 -2
  114. package/dist/cli/src/commands/project.d.ts.map +1 -1
  115. package/dist/connectors/config.js +7 -6
  116. package/dist/connectors/index.js +8 -7
  117. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  118. package/dist/connectors/src/watcher.d.ts.map +1 -1
  119. package/dist/connectors/src/worktree.d.ts +20 -2
  120. package/dist/connectors/src/worktree.d.ts.map +1 -1
  121. package/dist/core/index.js +6 -5
  122. package/dist/core/logging.js +2 -1
  123. package/dist/core/manifest.js +2 -1
  124. package/dist/core/runtime-assets.js +4 -3
  125. package/dist/core/src/fs-deadline.d.ts +84 -0
  126. package/dist/core/src/fs-deadline.d.ts.map +1 -0
  127. package/dist/core/src/index.d.ts +4 -3
  128. package/dist/core/src/index.d.ts.map +1 -1
  129. package/dist/core/src/manifest.d.ts +142 -18
  130. package/dist/core/src/manifest.d.ts.map +1 -1
  131. package/dist/core/src/repo-manager.d.ts +2 -2
  132. package/dist/core/src/repo-manager.d.ts.map +1 -1
  133. package/dist/core/src/runtime-assets.d.ts.map +1 -1
  134. package/dist/core/src/subprocess.d.ts +33 -1
  135. package/dist/core/src/subprocess.d.ts.map +1 -1
  136. package/dist/core/src/walker.d.ts +1 -1
  137. package/dist/core/src/walker.d.ts.map +1 -1
  138. package/dist/core/src/workspace-config.d.ts +19 -2
  139. package/dist/core/src/workspace-config.d.ts.map +1 -1
  140. package/dist/core/workspace-config.js +3 -2
  141. package/dist/deploy/index.js +12 -7
  142. package/dist/deploy/index.js.map +1 -1
  143. package/dist/deploy/src/targets/container-runtime.d.ts.map +1 -1
  144. package/dist/discovery/index.js +3 -2
  145. package/dist/{ensure-sources-RSTZONIE.js → ensure-sources-AVCVX7CV.js} +13 -12
  146. package/dist/ensure-sources-AVCVX7CV.js.map +1 -0
  147. package/dist/factory-assets/connectors/box.js +8 -7
  148. package/dist/factory-assets/connectors/deploy/CONNECTOR.md +19 -0
  149. package/dist/factory-assets/connectors/deploy/adapter.d.ts.map +1 -1
  150. package/dist/factory-assets/connectors/deploy.js +8 -7
  151. package/dist/factory-assets/connectors/devserver/adapter.d.ts.map +1 -1
  152. package/dist/factory-assets/connectors/devserver.js +8 -7
  153. package/dist/factory-assets/connectors/flow/adapter.js +8 -7
  154. package/dist/factory-assets/connectors/flow/engine.js +6 -5
  155. package/dist/factory-assets/connectors/flow/run-flow.js +10 -9
  156. package/dist/factory-assets/connectors/flow.js +8 -7
  157. package/dist/factory-assets/connectors/git/driver.d.ts +12 -1
  158. package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
  159. package/dist/factory-assets/connectors/git.js +8 -7
  160. package/dist/factory-assets/connectors/gmail.js +8 -7
  161. package/dist/factory-assets/connectors/googledrive.js +8 -7
  162. package/dist/factory-assets/connectors/local/driver.d.ts +25 -1
  163. package/dist/factory-assets/connectors/local/driver.d.ts.map +1 -1
  164. package/dist/factory-assets/connectors/local.js +8 -7
  165. package/dist/factory-assets/connectors/mattermost.js +8 -7
  166. package/dist/factory-assets/connectors/memory.js +8 -7
  167. package/dist/factory-assets/connectors/minio.js +8 -7
  168. package/dist/factory-assets/connectors/postgres.js +8 -7
  169. package/dist/factory-assets/connectors/s3/driver.d.ts +15 -0
  170. package/dist/factory-assets/connectors/s3/driver.d.ts.map +1 -1
  171. package/dist/factory-assets/connectors/s3.js +8 -7
  172. package/dist/factory-assets/connectors/sharepoint.js +8 -7
  173. package/dist/factory-assets/connectors/sqlite/adapter.d.ts +8 -1
  174. package/dist/factory-assets/connectors/sqlite/adapter.d.ts.map +1 -1
  175. package/dist/factory-assets/connectors/sqlite.js +8 -7
  176. package/dist/factory-assets/connectors/static-server/adapter.d.ts.map +1 -1
  177. package/dist/factory-assets/connectors/static-server.js +8 -7
  178. package/dist/factory-assets/connectors/tunnel.js +8 -7
  179. package/dist/factory-assets/connectors/webdav.js +8 -7
  180. package/dist/factory-assets/connectors/xstate/adapter.d.ts +6 -0
  181. package/dist/factory-assets/connectors/xstate/adapter.d.ts.map +1 -1
  182. package/dist/factory-assets/connectors/xstate-store.js +8 -7
  183. package/dist/factory-assets/connectors/xstate.js +8 -7
  184. package/dist/flows-CXVFGR27.js +20 -0
  185. package/dist/{flows-FHWBCLXF.js.map → flows-CXVFGR27.js.map} +1 -1
  186. package/dist/{helpers-GUUWPPAX.js → helpers-M5SXB4LL.js} +13 -12
  187. package/dist/{helpers-GUUWPPAX.js.map → helpers-M5SXB4LL.js.map} +1 -1
  188. package/dist/library/index.js +8 -7
  189. package/dist/library/install.js +6 -5
  190. package/dist/{library-publish-UKKSJP7V.js → library-publish-HVIIQMI6.js} +16 -15
  191. package/dist/library-publish-HVIIQMI6.js.map +1 -0
  192. package/dist/{open-library-VALRYGFV.js → open-library-EJQISBWV.js} +14 -13
  193. package/dist/{open-library-VALRYGFV.js.map → open-library-EJQISBWV.js.map} +1 -1
  194. package/dist/{paths-5QJJBAND.js → paths-2HMHL25W.js} +11 -10
  195. package/dist/{paths-5QJJBAND.js.map → paths-2HMHL25W.js.map} +1 -1
  196. package/dist/plugin-registry/src/deploy-helpers.d.ts +1 -1
  197. package/dist/{plugin-store-ZBJZ7F6D.js → plugin-store-TLBQ5XRS.js} +8 -7
  198. package/dist/plugin-store-TLBQ5XRS.js.map +1 -0
  199. package/dist/{project-IRUJLIVX.js → project-M2COJFPZ.js} +14 -13
  200. package/dist/{project-IRUJLIVX.js.map → project-M2COJFPZ.js.map} +1 -1
  201. package/dist/resolver/index.js +13 -1
  202. package/dist/resolver/src/types.d.ts +7 -0
  203. package/dist/resolver/src/types.d.ts.map +1 -1
  204. package/dist/resolver/src/validator.d.ts +8 -1
  205. package/dist/resolver/src/validator.d.ts.map +1 -1
  206. package/dist/runner/index.js +13 -12
  207. package/dist/runner/src/external-mcp.d.ts +1 -1
  208. package/dist/runner/src/external-mcp.d.ts.map +1 -1
  209. package/dist/runner/src/mcp-prompt.d.ts +7 -3
  210. package/dist/runner/src/mcp-prompt.d.ts.map +1 -1
  211. package/dist/runner/src/mcp-runtime-handlers.d.ts +12 -0
  212. package/dist/runner/src/mcp-runtime-handlers.d.ts.map +1 -1
  213. package/dist/runner/src/mixin-resolver.d.ts.map +1 -1
  214. package/dist/runner/src/recipe-resolver.d.ts +20 -6
  215. package/dist/runner/src/recipe-resolver.d.ts.map +1 -1
  216. package/dist/runner/src/resource-handler.d.ts +43 -0
  217. package/dist/runner/src/resource-handler.d.ts.map +1 -1
  218. package/dist/runner/src/resources.d.ts +12 -5
  219. package/dist/runner/src/resources.d.ts.map +1 -1
  220. package/dist/runner/src/serve.d.ts +31 -5
  221. package/dist/runner/src/serve.d.ts.map +1 -1
  222. package/dist/runner/src/session-builder.d.ts +9 -0
  223. package/dist/runner/src/session-builder.d.ts.map +1 -1
  224. package/dist/runner/src/session-capability-wiring.d.ts +5 -0
  225. package/dist/runner/src/session-capability-wiring.d.ts.map +1 -1
  226. package/dist/runner/src/workspace-migration.d.ts +37 -3
  227. package/dist/runner/src/workspace-migration.d.ts.map +1 -1
  228. package/dist/sdk/asset-manager.js +10 -9
  229. package/dist/sdk/bridge.js +4 -3
  230. package/dist/sdk/core.js +6 -5
  231. package/dist/sdk/flow.js +6 -5
  232. package/dist/sdk/index.js +13 -12
  233. package/dist/sdk/index.js.map +1 -1
  234. package/dist/sdk/resolver.js +13 -1
  235. package/dist/sdk/runner.js +13 -12
  236. package/dist/sdk/session.js +1 -1
  237. package/dist/sdk/store.js +1 -1
  238. package/dist/session/index.js +1 -1
  239. package/dist/session/src/dispatcher.d.ts.map +1 -1
  240. package/dist/{setup-WJPNUE32.js → setup-GWXEG3G2.js} +10 -9
  241. package/dist/setup-GWXEG3G2.js.map +1 -0
  242. package/dist/skills-YTMGG23D.js +20 -0
  243. package/dist/{skills-BMI6H7HI.js.map → skills-YTMGG23D.js.map} +1 -1
  244. package/dist/{source-5KDURFBS.js → source-WMXH2OBW.js} +15 -14
  245. package/dist/{source-5KDURFBS.js.map → source-WMXH2OBW.js.map} +1 -1
  246. package/dist/{source-manifest-publish-DPQI44D3.js → source-manifest-publish-MTHUGBAY.js} +17 -16
  247. package/dist/source-manifest-publish-MTHUGBAY.js.map +1 -0
  248. package/dist/store/index.js +1 -1
  249. package/dist/store/src/store.d.ts +9 -0
  250. package/dist/store/src/store.d.ts.map +1 -1
  251. package/dist/tui/index.js +13 -12
  252. package/dist/tui/index.js.map +1 -1
  253. package/dist/validator-RN64BKFW.js +5 -0
  254. package/dist/{validator-VF5M764T.js.map → validator-RN64BKFW.js.map} +1 -1
  255. package/dist/workspace-plugin/adapters/mcp.js +18 -5
  256. package/dist/workspace-plugin/adapters/mcp.js.map +1 -1
  257. package/dist/workspace-plugin/adapters/omp.js +10 -10
  258. package/dist/workspace-plugin/index.js +3 -2
  259. package/dist/workspace-plugin/src/tools/validator.d.ts.map +1 -1
  260. package/dist/workspace-plugin/src/utils/ai-assets.d.ts +11 -6
  261. package/dist/workspace-plugin/src/utils/ai-assets.d.ts.map +1 -1
  262. package/package.json +1 -1
  263. package/dist/asset-feeds-WIBEP37F.js.map +0 -1
  264. package/dist/chunk-2BQBWWFX.js.map +0 -1
  265. package/dist/chunk-2IJFUAZB.js.map +0 -1
  266. package/dist/chunk-5NZ56R63.js.map +0 -1
  267. package/dist/chunk-6POODADP.js.map +0 -1
  268. package/dist/chunk-7J7LQP6T.js.map +0 -1
  269. package/dist/chunk-A22KZ7GZ.js.map +0 -1
  270. package/dist/chunk-ACXLKNIM.js.map +0 -1
  271. package/dist/chunk-BG4XVMG2.js.map +0 -1
  272. package/dist/chunk-BI2NKPA4.js.map +0 -1
  273. package/dist/chunk-BQCGFPHW.js +0 -345
  274. package/dist/chunk-BQCGFPHW.js.map +0 -1
  275. package/dist/chunk-FIUGSIKC.js.map +0 -1
  276. package/dist/chunk-GXC3TYMQ.js.map +0 -1
  277. package/dist/chunk-ISA7R7PK.js.map +0 -1
  278. package/dist/chunk-JB35MVBN.js.map +0 -1
  279. package/dist/chunk-KY5NY7LB.js.map +0 -1
  280. package/dist/chunk-LV2HPH3C.js +0 -73
  281. package/dist/chunk-LV2HPH3C.js.map +0 -1
  282. package/dist/chunk-XCBG2KDC.js +0 -23
  283. package/dist/chunk-XCBG2KDC.js.map +0 -1
  284. package/dist/ensure-sources-RSTZONIE.js.map +0 -1
  285. package/dist/flows-FHWBCLXF.js +0 -7
  286. package/dist/library-publish-UKKSJP7V.js.map +0 -1
  287. package/dist/plugin-store-ZBJZ7F6D.js.map +0 -1
  288. package/dist/setup-WJPNUE32.js.map +0 -1
  289. package/dist/skills-BMI6H7HI.js +0 -7
  290. package/dist/source-manifest-publish-DPQI44D3.js.map +0 -1
  291. package/dist/validator-VF5M764T.js +0 -5
@@ -1,17 +1,19 @@
1
- import { resolveAuthRef } from './chunk-2TSSCHCQ.js';
1
+ import { resolveAuthRef } from './chunk-BHLNQ4L5.js';
2
2
  import { pluginRegistry } from './chunk-6E6PKKAD.js';
3
3
  import { computeFlowStateFromSnapshots } from './chunk-HPGV54O4.js';
4
4
  import { renderStimulusPrompt } from './chunk-Y662DNQQ.js';
5
5
  import { computeStimulus } from './chunk-IFGTRL2I.js';
6
- import { portableSpawn } from './chunk-5NZ56R63.js';
7
- import { createLogger } from './chunk-JB35MVBN.js';
8
- import { existsSync, mkdirSync, renameSync, writeFileSync, readFileSync, cpSync, statSync, createReadStream, readdirSync, openSync, writeSync, closeSync, chmodSync } from 'fs';
6
+ import { portableSpawn } from './chunk-RTLQAZAE.js';
7
+ import { withFsDeadline, tryWithFsDeadline, FsDeadlineError, fsDeadlineMs } from './chunk-DYMWJAL4.js';
8
+ import { createLogger } from './chunk-7GOCNYUV.js';
9
+ import { mkdir, rename, writeFile, readFile, stat, cp, readdir, chmod, realpath } from 'fs/promises';
9
10
  import { join, dirname, resolve, sep, relative } from 'path';
10
11
  import * as zNS from 'zod';
11
- import { execSync } from 'child_process';
12
+ import { execFile } from 'child_process';
13
+ import { promisify } from 'util';
14
+ import { createReadStream, readFileSync, existsSync, mkdirSync, openSync, writeSync, closeSync, chmodSync, renameSync } from 'fs';
12
15
  import { createServer } from 'http';
13
16
  import mime from 'mime';
14
- import { stat, readdir, mkdir, chmod, readFile, realpath } from 'fs/promises';
15
17
  import { createRequire } from 'module';
16
18
  import { pathToFileURL } from 'url';
17
19
  import { createConnection } from 'net';
@@ -51,6 +53,8 @@ var AbstractConnector = class {
51
53
  };
52
54
  }
53
55
  };
56
+ var execFileAsync = promisify(execFile);
57
+ var GIT_REV_PARSE_TIMEOUT_MS = 15e3;
54
58
  var DeployConnector = class extends AbstractConnector {
55
59
  name = "deploy";
56
60
  tools;
@@ -69,12 +73,16 @@ var DeployConnector = class extends AbstractConnector {
69
73
  for (const [k, v] of Object.entries(declaration.options ?? {})) {
70
74
  if (k !== "provider" && typeof v === "string") defaults[k] = v;
71
75
  }
76
+ const repoDir = String(declaration.options?.repo_root ?? process.cwd());
72
77
  let repoRoot = null;
73
78
  try {
74
- repoRoot = execSync("git rev-parse --show-toplevel", {
79
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
80
+ cwd: repoDir,
75
81
  encoding: "utf-8",
76
- stdio: ["pipe", "pipe", "pipe"]
77
- }).trim();
82
+ timeout: GIT_REV_PARSE_TIMEOUT_MS,
83
+ killSignal: "SIGKILL"
84
+ });
85
+ repoRoot = stdout.trim();
78
86
  } catch {
79
87
  }
80
88
  return this.makeHandle(declaration, {
@@ -82,7 +90,7 @@ var DeployConnector = class extends AbstractConnector {
82
90
  defaults,
83
91
  deployments: /* @__PURE__ */ new Map(),
84
92
  repoRoot,
85
- worktreeDir: process.cwd()
93
+ worktreeDir: repoDir
86
94
  });
87
95
  }
88
96
  async disconnect(handle) {
@@ -317,7 +325,7 @@ var DevServerConnector = class extends AbstractConnector {
317
325
  const portRange = opts.port_range ?? [3e3, 3099];
318
326
  let repoRoot = null;
319
327
  try {
320
- repoRoot = findGitRoot(process.cwd());
328
+ repoRoot = await findGitRoot(process.cwd());
321
329
  } catch {
322
330
  }
323
331
  const state = {
@@ -546,8 +554,8 @@ var DevServerConnector = class extends AbstractConnector {
546
554
  detached: true
547
555
  });
548
556
  const logBuffer = new LogBuffer(state.logBufferSize);
549
- pipeToBuffer(proc.stdout, logBuffer);
550
- pipeToBuffer(proc.stderr, logBuffer);
557
+ void pipeToBuffer(proc.stdout, logBuffer);
558
+ void pipeToBuffer(proc.stderr, logBuffer);
551
559
  const instance = {
552
560
  id: label,
553
561
  pid: proc.pid,
@@ -838,24 +846,29 @@ function resolveGitConfig(args) {
838
846
  };
839
847
  }
840
848
  var modeLog = createLogger({ kind: "connector", subkind: "git" });
841
- function shellQuote(value) {
842
- return `'${value.replace(/'/g, "'\\''")}'`;
843
- }
844
- function gitCommand(cwd) {
845
- return `git -c safe.directory=${shellQuote(cwd)}`;
849
+ var execFileAsync2 = promisify(execFile);
850
+ function gitPrefix(cwd) {
851
+ return ["-c", `safe.directory=${cwd}`];
846
852
  }
847
- function git(cmd, cwd, timeout = 3e4) {
848
- return execSync(`${gitCommand(cwd)} ${cmd}`, {
849
- cwd,
853
+ async function runGit(args, options) {
854
+ const { stdout } = await execFileAsync2("git", args, {
850
855
  encoding: "utf-8",
851
- timeout,
852
- stdio: "pipe"
853
- }).trim();
856
+ timeout: options.timeout,
857
+ killSignal: "SIGKILL",
858
+ ...options.cwd === void 0 ? {} : { cwd: options.cwd }
859
+ });
860
+ return stdout.trim();
854
861
  }
855
- function syncSubmodules(cwd) {
856
- if (!existsSync(join(cwd, ".gitmodules"))) return;
862
+ function git(args, cwd, timeout = 3e4) {
863
+ return runGit([...gitPrefix(cwd), ...args], { cwd, timeout });
864
+ }
865
+ function pathExists(path) {
866
+ return tryWithFsDeadline(`stat ${path}`, () => stat(path).then(() => true), false);
867
+ }
868
+ async function syncSubmodules(cwd) {
869
+ if (!await pathExists(join(cwd, ".gitmodules"))) return;
857
870
  try {
858
- git("submodule update --init --recursive", cwd, 12e4);
871
+ await git(["submodule", "update", "--init", "--recursive"], cwd, 12e4);
859
872
  } catch {
860
873
  }
861
874
  }
@@ -867,19 +880,19 @@ function isValidGitRefOrSha(ref) {
867
880
  if (ref.includes("..") || ref.includes("@{")) return false;
868
881
  return true;
869
882
  }
870
- function hasChanges(cwd) {
871
- const status = git("status --porcelain", cwd);
883
+ async function hasChanges(cwd) {
884
+ const status = await git(["status", "--porcelain"], cwd);
872
885
  return status.length > 0;
873
886
  }
874
- function gitOrNull(cmd, cwd) {
887
+ async function gitOrNull(args, cwd) {
875
888
  try {
876
- return git(cmd, cwd);
889
+ return await git(args, cwd);
877
890
  } catch {
878
891
  return null;
879
892
  }
880
893
  }
881
- function countAheadBehind(cwd, remoteRef) {
882
- const out = gitOrNull(`rev-list --left-right --count ${remoteRef}...HEAD`, cwd);
894
+ async function countAheadBehind(cwd, remoteRef) {
895
+ const out = await gitOrNull(["rev-list", "--left-right", "--count", `${remoteRef}...HEAD`], cwd);
883
896
  if (!out) {
884
897
  return { ahead: 0, behind: 0 };
885
898
  }
@@ -891,15 +904,15 @@ function countAheadBehind(cwd, remoteRef) {
891
904
  behind: Number.isFinite(behind) ? behind : 0
892
905
  };
893
906
  }
894
- function readGitSyncStatus(cwd, baseBranch) {
895
- const branchRaw = gitOrNull("rev-parse --abbrev-ref HEAD", cwd);
907
+ async function readGitSyncStatus(cwd, baseBranch) {
908
+ const branchRaw = await gitOrNull(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
896
909
  const branch = branchRaw && branchRaw !== "HEAD" ? branchRaw : null;
897
- const dirty = (gitOrNull("status --porcelain", cwd) ?? "") !== "";
898
- const hasUpstream = branch !== null && gitOrNull("rev-parse --abbrev-ref @{upstream}", cwd) !== null;
899
- const upstream = countAheadBehind(cwd, "@{upstream}");
910
+ const dirty = (await gitOrNull(["status", "--porcelain"], cwd) ?? "") !== "";
911
+ const hasUpstream = branch !== null && await gitOrNull(["rev-parse", "--abbrev-ref", "@{upstream}"], cwd) !== null;
912
+ const upstream = await countAheadBehind(cwd, "@{upstream}");
900
913
  const baseRef = isValidGitRefOrSha(baseBranch) ? `origin/${baseBranch}` : "origin/main";
901
- const base = countAheadBehind(cwd, baseRef);
902
- const commitSha = gitOrNull("rev-parse HEAD", cwd);
914
+ const base = await countAheadBehind(cwd, baseRef);
915
+ const commitSha = await gitOrNull(["rev-parse", "HEAD"], cwd);
903
916
  return {
904
917
  branch,
905
918
  dirty,
@@ -911,25 +924,22 @@ function readGitSyncStatus(cwd, baseBranch) {
911
924
  commitSha
912
925
  };
913
926
  }
914
- function localBranchExists(branch, cwd) {
927
+ async function localBranchExists(branch, cwd) {
915
928
  try {
916
- git(`rev-parse --verify --quiet refs/heads/${branch}`, cwd);
929
+ await git(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`], cwd);
917
930
  return true;
918
931
  } catch {
919
932
  return false;
920
933
  }
921
934
  }
922
- function isDirEmpty(dir) {
923
- try {
924
- return readdirSync(dir).length === 0;
925
- } catch {
926
- return true;
927
- }
935
+ async function isDirEmpty(dir) {
936
+ const entries = await tryWithFsDeadline(`readdir ${dir}`, () => readdir(dir), []);
937
+ return entries.length === 0;
928
938
  }
929
- function commitAll(cwd, message) {
930
- if (!hasChanges(cwd)) return null;
931
- git("add -A", cwd);
932
- return git(`commit -m ${JSON.stringify(message)}`, cwd);
939
+ async function commitAll(cwd, message) {
940
+ if (!await hasChanges(cwd)) return null;
941
+ await git(["add", "-A"], cwd);
942
+ return git(["commit", "-m", message], cwd);
933
943
  }
934
944
  var TokenMediatorError = class extends Error {
935
945
  code;
@@ -969,7 +979,7 @@ var GitConnector = class extends AbstractConnector {
969
979
  throw new Error("git sync_status: mount path unavailable");
970
980
  }
971
981
  const state = handle.state;
972
- return JSON.stringify(readGitSyncStatus(cwd, state.branch));
982
+ return JSON.stringify(await readGitSyncStatus(cwd, state.branch));
973
983
  }
974
984
  default:
975
985
  throw new Error(`GitConnector has no operation: ${operation}`);
@@ -1014,9 +1024,9 @@ var GitConnector = class extends AbstractConnector {
1014
1024
  tokenMediator: initial.authRef?.kind === "backend" ? tokenMediator : void 0
1015
1025
  };
1016
1026
  const authUrl = this.authUrl(state);
1017
- this.prepareCheckout(targetDir, url, branch, authUrl, started);
1027
+ await this.prepareCheckout(targetDir, url, branch, authUrl, started);
1018
1028
  if (session.enabled && !session.isMain && session.slug) {
1019
- this.checkoutSessionBranch(state, session, targetDir);
1029
+ await this.checkoutSessionBranch(state, session, targetDir);
1020
1030
  }
1021
1031
  if (sync.fetchIntervalSec > 0) {
1022
1032
  this.startPeriodicFetch(state, targetDir);
@@ -1030,9 +1040,9 @@ var GitConnector = class extends AbstractConnector {
1030
1040
  }
1031
1041
  }
1032
1042
  if (state.managedGitconfig) {
1033
- this.stripRemoteInlineToken(targetDir);
1043
+ await this.stripRemoteInlineToken(targetDir);
1034
1044
  } else {
1035
- this.rebakeRemoteAuth(targetDir, state);
1045
+ await this.rebakeRemoteAuth(targetDir, state);
1036
1046
  if (initial.authRef?.kind === "backend" && initial.expiresAt && state.tokenMediator) {
1037
1047
  this.scheduleRefresh(declaration.id, state, initial.expiresAt);
1038
1048
  }
@@ -1061,31 +1071,37 @@ var GitConnector = class extends AbstractConnector {
1061
1071
  * reset, no clean. Existing files become uncommitted-on-init; the
1062
1072
  * agent or `pushAfterCommit` reconciles with remote later.
1063
1073
  */
1064
- prepareCheckout(targetDir, url, branch, authUrl, started) {
1074
+ async prepareCheckout(targetDir, url, branch, authUrl, started) {
1065
1075
  try {
1066
- if (existsSync(join(targetDir, ".git"))) {
1067
- if (this.isInitialisedCheckout(targetDir)) {
1076
+ if (await pathExists(join(targetDir, ".git"))) {
1077
+ if (await this.isInitialisedCheckout(targetDir)) {
1068
1078
  this.log.info("found existing checkout \u2014 using as-is", { branch, targetDir });
1069
1079
  } else {
1070
1080
  this.log.info("found empty .git \u2014 bootstrapping from origin", { branch });
1071
- this.bootstrapFromOrigin(targetDir, branch, authUrl);
1081
+ await this.bootstrapFromOrigin(targetDir, branch, authUrl);
1072
1082
  this.log.info("bootstrap ok", { branch, durationMs: Date.now() - started });
1073
1083
  }
1074
1084
  } else {
1075
- mkdirSync(targetDir, { recursive: true });
1076
- if (isDirEmpty(targetDir)) {
1085
+ await withFsDeadline(`mkdir ${targetDir}`, () => mkdir(targetDir, { recursive: true }));
1086
+ if (await isDirEmpty(targetDir)) {
1077
1087
  this.log.info("clone start", { url, branch });
1078
- execSync(
1079
- `${gitCommand(targetDir)} clone --branch ${branch} --single-branch --recurse-submodules ${authUrl} ${targetDir}`,
1080
- {
1081
- timeout: 12e4,
1082
- stdio: "pipe"
1083
- }
1088
+ await runGit(
1089
+ [
1090
+ ...gitPrefix(targetDir),
1091
+ "clone",
1092
+ "--branch",
1093
+ branch,
1094
+ "--single-branch",
1095
+ "--recurse-submodules",
1096
+ authUrl,
1097
+ targetDir
1098
+ ],
1099
+ { timeout: 12e4 }
1084
1100
  );
1085
1101
  this.log.info("clone ok", { branch, durationMs: Date.now() - started });
1086
1102
  } else {
1087
1103
  this.log.warn("target non-empty without .git \u2014 initialising in place", { targetDir });
1088
- this.initInPlace(targetDir, authUrl);
1104
+ await this.initInPlace(targetDir, authUrl);
1089
1105
  this.log.info("init in place ok", { durationMs: Date.now() - started });
1090
1106
  }
1091
1107
  }
@@ -1101,37 +1117,37 @@ var GitConnector = class extends AbstractConnector {
1101
1117
  * fork flow) when supplied and valid, else off the currently-checked-out
1102
1118
  * HEAD (== base branch).
1103
1119
  */
1104
- checkoutSessionBranch(state, session, targetDir) {
1120
+ async checkoutSessionBranch(state, session, targetDir) {
1105
1121
  const sessionBranch = `${session.branchPrefix}${session.slug}`;
1106
1122
  if (!isValidGitRefOrSha(sessionBranch)) {
1107
1123
  throw new Error(`Git connector: invalid session branch name "${sessionBranch}"`);
1108
1124
  }
1109
1125
  let created = false;
1110
- if (localBranchExists(sessionBranch, targetDir)) {
1111
- git(`checkout ${sessionBranch}`, targetDir);
1126
+ if (await localBranchExists(sessionBranch, targetDir)) {
1127
+ await git(["checkout", sessionBranch], targetDir);
1112
1128
  this.log.info("reusing existing local session branch", { sessionBranch });
1113
1129
  } else {
1114
1130
  let originHasBranch = false;
1115
1131
  try {
1116
- git(`rev-parse --verify origin/${sessionBranch}`, targetDir);
1132
+ await git(["rev-parse", "--verify", `origin/${sessionBranch}`], targetDir);
1117
1133
  originHasBranch = true;
1118
1134
  } catch {
1119
1135
  }
1120
1136
  if (originHasBranch) {
1121
- git(`checkout -B ${sessionBranch} origin/${sessionBranch}`, targetDir);
1122
- } else if (!this.branchFromRef(session, sessionBranch, targetDir)) {
1123
- git(`checkout -b ${sessionBranch}`, targetDir);
1137
+ await git(["checkout", "-B", sessionBranch, `origin/${sessionBranch}`], targetDir);
1138
+ } else if (!await this.branchFromRef(session, sessionBranch, targetDir)) {
1139
+ await git(["checkout", "-b", sessionBranch], targetDir);
1124
1140
  created = true;
1125
1141
  } else {
1126
1142
  created = true;
1127
1143
  }
1128
1144
  }
1129
- syncSubmodules(targetDir);
1145
+ await syncSubmodules(targetDir);
1130
1146
  state.activeBranch = sessionBranch;
1131
1147
  this.log.info("session branch checked out", { sessionBranch });
1132
1148
  if (created && state.lifecycle.publishOnCreate) {
1133
1149
  try {
1134
- git(`push -u origin ${sessionBranch}`, targetDir, 6e4);
1150
+ await git(["push", "-u", "origin", sessionBranch], targetDir, 6e4);
1135
1151
  this.log.info("published new session branch", { sessionBranch });
1136
1152
  } catch (err) {
1137
1153
  this.log.warn("publish-on-create push failed; deferring to lifecycle push", {
@@ -1146,7 +1162,7 @@ var GitConnector = class extends AbstractConnector {
1146
1162
  * true when the branch was created from the anchor; false when no valid
1147
1163
  * `fromRef` was supplied or the fetch failed (caller falls back to base).
1148
1164
  */
1149
- branchFromRef(session, sessionBranch, targetDir) {
1165
+ async branchFromRef(session, sessionBranch, targetDir) {
1150
1166
  if (!session.fromRef) return false;
1151
1167
  if (!isValidGitRefOrSha(session.fromRef)) {
1152
1168
  this.log.warn("fromRef rejected by refname validation, falling back to base branch", {
@@ -1156,8 +1172,8 @@ var GitConnector = class extends AbstractConnector {
1156
1172
  return false;
1157
1173
  }
1158
1174
  try {
1159
- git(`fetch origin ${session.fromRef}`, targetDir);
1160
- git(`checkout -b ${sessionBranch} FETCH_HEAD`, targetDir);
1175
+ await git(["fetch", "origin", session.fromRef], targetDir);
1176
+ await git(["checkout", "-b", sessionBranch, "FETCH_HEAD"], targetDir);
1161
1177
  this.log.info("session branch created from fromRef", {
1162
1178
  sessionBranch,
1163
1179
  fromRef: session.fromRef
@@ -1189,7 +1205,7 @@ var GitConnector = class extends AbstractConnector {
1189
1205
  await ensureFleetMounted(targetDir, this.log);
1190
1206
  let activeBranch = "unknown";
1191
1207
  try {
1192
- activeBranch = git("rev-parse --abbrev-ref HEAD", targetDir, 5e3);
1208
+ activeBranch = await git(["rev-parse", "--abbrev-ref", "HEAD"], targetDir, 5e3);
1193
1209
  } catch {
1194
1210
  }
1195
1211
  const fleetConfig = resolveGitConfig({
@@ -1265,6 +1281,7 @@ var GitConnector = class extends AbstractConnector {
1265
1281
  async disconnect(handle) {
1266
1282
  this.log.info("unmount");
1267
1283
  const s = handle.state;
1284
+ s.disposed = true;
1268
1285
  if (s.fleetManaged) {
1269
1286
  await s.fleetWatcher?.close();
1270
1287
  s.fleetWatcher = void 0;
@@ -1289,8 +1306,8 @@ var GitConnector = class extends AbstractConnector {
1289
1306
  }
1290
1307
  this.log.debug("sync (pull) start", { branch: s.activeBranch });
1291
1308
  try {
1292
- git(`pull origin ${s.activeBranch}`, handle.mountPath, 6e4);
1293
- syncSubmodules(handle.mountPath);
1309
+ await git(["pull", "origin", s.activeBranch], handle.mountPath, 6e4);
1310
+ await syncSubmodules(handle.mountPath);
1294
1311
  this.log.debug("sync ok");
1295
1312
  } catch (err) {
1296
1313
  this.log.error("sync failed", err, { branch: s.activeBranch });
@@ -1341,12 +1358,12 @@ var GitConnector = class extends AbstractConnector {
1341
1358
  }
1342
1359
  const lc = s.lifecycle;
1343
1360
  if (!lc.commitOnHibernate) return;
1344
- const result = commitAll(handle.mountPath, `skaile: hibernate snapshot`);
1361
+ const result = await commitAll(handle.mountPath, `skaile: hibernate snapshot`);
1345
1362
  if (!result) return "Nothing to commit.";
1346
- const sha = git("rev-parse --short HEAD", handle.mountPath);
1363
+ const sha = await git(["rev-parse", "--short", "HEAD"], handle.mountPath);
1347
1364
  if (lc.pushOnHibernate) {
1348
1365
  try {
1349
- git(`push origin ${s.activeBranch}`, handle.mountPath, 6e4);
1366
+ await git(["push", "origin", s.activeBranch], handle.mountPath, 6e4);
1350
1367
  this.log.info("push ok", { branch: s.activeBranch });
1351
1368
  } catch (err) {
1352
1369
  this.log.error("push failed", err, { branch: s.activeBranch });
@@ -1363,29 +1380,29 @@ var GitConnector = class extends AbstractConnector {
1363
1380
  }
1364
1381
  const lc = s.lifecycle;
1365
1382
  const details = [];
1366
- const commitResult = commitAll(handle.mountPath, `skaile: session close`);
1383
+ const commitResult = await commitAll(handle.mountPath, `skaile: session close`);
1367
1384
  if (commitResult) {
1368
- const sha = git("rev-parse --short HEAD", handle.mountPath);
1385
+ const sha = await git(["rev-parse", "--short", "HEAD"], handle.mountPath);
1369
1386
  details.push(`Committed ${sha}`);
1370
1387
  }
1371
1388
  if (lc.pushOnClose || lc.mergeOnClose) {
1372
- git(`push origin ${s.activeBranch}`, handle.mountPath, 6e4);
1389
+ await git(["push", "origin", s.activeBranch], handle.mountPath, 6e4);
1373
1390
  details.push(`Pushed ${s.activeBranch}`);
1374
1391
  }
1375
1392
  if (lc.mergeOnClose && s.activeBranch !== s.branch) {
1376
- git(`checkout ${s.branch}`, handle.mountPath);
1377
- git(`pull origin ${s.branch}`, handle.mountPath, 6e4);
1378
- syncSubmodules(handle.mountPath);
1393
+ await git(["checkout", s.branch], handle.mountPath);
1394
+ await git(["pull", "origin", s.branch], handle.mountPath, 6e4);
1395
+ await syncSubmodules(handle.mountPath);
1379
1396
  try {
1380
- git(`merge ${s.activeBranch}`, handle.mountPath);
1397
+ await git(["merge", s.activeBranch], handle.mountPath);
1381
1398
  } catch {
1382
- const resolved = this.resolveConflictsOrAbort(s, handle.mountPath, "merge");
1399
+ const resolved = await this.resolveConflictsOrAbort(s, handle.mountPath, "merge");
1383
1400
  if (resolved) {
1384
1401
  details.push("Resolved merge conflicts (created .conflict files)");
1385
1402
  }
1386
1403
  }
1387
1404
  if (lc.pushOnClose) {
1388
- git(`push origin ${s.branch}`, handle.mountPath, 6e4);
1405
+ await git(["push", "origin", s.branch], handle.mountPath, 6e4);
1389
1406
  }
1390
1407
  details.push(`Merged ${s.activeBranch} into ${s.branch}`);
1391
1408
  }
@@ -1592,7 +1609,7 @@ var GitConnector = class extends AbstractConnector {
1592
1609
  credentialsPath: state.managedGitconfig.credentialsPath
1593
1610
  });
1594
1611
  } else if (state.targetDir) {
1595
- this.rebakeRemoteAuth(state.targetDir, state);
1612
+ await this.rebakeRemoteAuth(state.targetDir, state);
1596
1613
  }
1597
1614
  this.log.info("refresh", {
1598
1615
  event: "refresh",
@@ -1662,18 +1679,13 @@ var GitConnector = class extends AbstractConnector {
1662
1679
  * handling is external to this method (managed-gitconfig credential
1663
1680
  * helper refresh in Tier-2 connectors).
1664
1681
  */
1665
- initInPlace(targetDir, authUrl) {
1666
- git("init", targetDir, 1e4);
1682
+ async initInPlace(targetDir, authUrl) {
1683
+ await git(["init"], targetDir, 1e4);
1667
1684
  try {
1668
- git("remote remove origin", targetDir, 5e3);
1685
+ await git(["remote", "remove", "origin"], targetDir, 5e3);
1669
1686
  } catch {
1670
1687
  }
1671
- execSync(`${gitCommand(targetDir)} remote add origin ${authUrl}`, {
1672
- cwd: targetDir,
1673
- encoding: "utf-8",
1674
- timeout: 5e3,
1675
- stdio: "pipe"
1676
- });
1688
+ await git(["remote", "add", "origin", authUrl], targetDir, 5e3);
1677
1689
  }
1678
1690
  /**
1679
1691
  * True when `<targetDir>/.git` contains at least one resolvable commit
@@ -1684,9 +1696,9 @@ var GitConnector = class extends AbstractConnector {
1684
1696
  * checkout (preserve, don't touch) and a half-initialised one
1685
1697
  * (bootstrap by fetching from origin).
1686
1698
  */
1687
- isInitialisedCheckout(targetDir) {
1699
+ async isInitialisedCheckout(targetDir) {
1688
1700
  try {
1689
- git("rev-parse HEAD", targetDir, 5e3);
1701
+ await git(["rev-parse", "HEAD"], targetDir, 5e3);
1690
1702
  return true;
1691
1703
  } catch {
1692
1704
  return false;
@@ -1712,23 +1724,18 @@ var GitConnector = class extends AbstractConnector {
1712
1724
  * the same way `git clone <authUrl>` does — token-rotation handling
1713
1725
  * is external to this connector method.
1714
1726
  */
1715
- bootstrapFromOrigin(targetDir, branch, authUrl) {
1727
+ async bootstrapFromOrigin(targetDir, branch, authUrl) {
1716
1728
  try {
1717
- git("remote remove origin", targetDir, 5e3);
1729
+ await git(["remote", "remove", "origin"], targetDir, 5e3);
1718
1730
  } catch {
1719
1731
  }
1720
- execSync(`${gitCommand(targetDir)} remote add origin ${authUrl}`, {
1721
- cwd: targetDir,
1722
- encoding: "utf-8",
1723
- timeout: 5e3,
1724
- stdio: "pipe"
1725
- });
1726
- git(`fetch --depth=1 origin ${branch}`, targetDir, 12e4);
1727
- this.preserveConflictingUntracked(targetDir, branch);
1728
- git(`checkout -B ${branch} origin/${branch}`, targetDir, 3e4);
1729
- syncSubmodules(targetDir);
1732
+ await git(["remote", "add", "origin", authUrl], targetDir, 5e3);
1733
+ await git(["fetch", "--depth=1", "origin", branch], targetDir, 12e4);
1734
+ await this.preserveConflictingUntracked(targetDir, branch);
1735
+ await git(["checkout", "-B", branch, `origin/${branch}`], targetDir, 3e4);
1736
+ await syncSubmodules(targetDir);
1730
1737
  try {
1731
- git(`branch --set-upstream-to=origin/${branch} ${branch}`, targetDir, 5e3);
1738
+ await git(["branch", `--set-upstream-to=origin/${branch}`, branch], targetDir, 5e3);
1732
1739
  } catch {
1733
1740
  }
1734
1741
  }
@@ -1747,10 +1754,10 @@ var GitConnector = class extends AbstractConnector {
1747
1754
  * left untouched — they are pure local additions and survive the
1748
1755
  * bootstrap.
1749
1756
  */
1750
- preserveConflictingUntracked(targetDir, branch) {
1757
+ async preserveConflictingUntracked(targetDir, branch) {
1751
1758
  let remoteFiles = [];
1752
1759
  try {
1753
- remoteFiles = git(`ls-tree -r origin/${branch} --name-only`, targetDir, 3e4).split("\n").filter(Boolean);
1760
+ remoteFiles = (await git(["ls-tree", "-r", `origin/${branch}`, "--name-only"], targetDir, 3e4)).split("\n").filter(Boolean);
1754
1761
  } catch (err) {
1755
1762
  this.log.warn("ls-tree failed \u2014 skipping untracked preservation", {
1756
1763
  branch,
@@ -1760,13 +1767,13 @@ var GitConnector = class extends AbstractConnector {
1760
1767
  }
1761
1768
  for (const relPath of remoteFiles) {
1762
1769
  const fullPath = join(targetDir, relPath);
1763
- if (!existsSync(fullPath)) continue;
1770
+ if (!await pathExists(fullPath)) continue;
1764
1771
  let dest = `${fullPath}.local`;
1765
- if (existsSync(dest)) {
1772
+ if (await pathExists(dest)) {
1766
1773
  dest = `${fullPath}.local.${Date.now()}`;
1767
1774
  }
1768
1775
  try {
1769
- renameSync(fullPath, dest);
1776
+ await withFsDeadline(`rename ${fullPath}`, () => rename(fullPath, dest));
1770
1777
  this.log.info("preserved local file as .local", { path: relPath, dest });
1771
1778
  } catch (err) {
1772
1779
  this.log.warn("failed to preserve local file \u2014 checkout may fail", {
@@ -1793,15 +1800,15 @@ var GitConnector = class extends AbstractConnector {
1793
1800
  * carries creds — so the baked-in token must go. Best-effort: a missing
1794
1801
  * origin or a non-http(s) remote (e.g. file:// in tests) is left untouched.
1795
1802
  */
1796
- stripRemoteInlineToken(targetDir) {
1803
+ async stripRemoteInlineToken(targetDir) {
1797
1804
  try {
1798
- const current = git("remote get-url origin", targetDir, 5e3);
1805
+ const current = await git(["remote", "get-url", "origin"], targetDir, 5e3);
1799
1806
  if (!current.startsWith("https://") && !current.startsWith("http://")) return;
1800
1807
  const u = new URL(current);
1801
1808
  if (!u.username && !u.password) return;
1802
1809
  u.username = "";
1803
1810
  u.password = "";
1804
- git(`remote set-url origin ${u.toString()}`, targetDir, 5e3);
1811
+ await git(["remote", "set-url", "origin", u.toString()], targetDir, 5e3);
1805
1812
  } catch (err) {
1806
1813
  this.log.warn("managed-gitconfig: failed to strip inline token from origin", {
1807
1814
  error: err instanceof Error ? err.message : String(err)
@@ -1815,10 +1822,10 @@ var GitConnector = class extends AbstractConnector {
1815
1822
  * a Tier-2 helper this URL token is the sole credential, so it must be
1816
1823
  * refreshed here. No-op for anonymous (no token) or non-https remotes.
1817
1824
  */
1818
- rebakeRemoteAuth(targetDir, state) {
1825
+ async rebakeRemoteAuth(targetDir, state) {
1819
1826
  if (!state.token || !state.url.startsWith("https://")) return;
1820
1827
  try {
1821
- git(`remote set-url origin ${this.authUrl(state)}`, targetDir, 5e3);
1828
+ await git(["remote", "set-url", "origin", this.authUrl(state)], targetDir, 5e3);
1822
1829
  } catch (err) {
1823
1830
  this.log.warn("failed to refresh inline token on origin", {
1824
1831
  error: err instanceof Error ? err.message : String(err)
@@ -1830,22 +1837,41 @@ var GitConnector = class extends AbstractConnector {
1830
1837
  if (s.fetchTimer) clearInterval(s.fetchTimer);
1831
1838
  const intervalMs = s.sync.fetchIntervalSec * 1e3;
1832
1839
  s.fetchTimer = setInterval(() => {
1840
+ if (s.fetchInFlight) {
1841
+ this.log.warn("periodic fetch skipped \u2014 previous tick still running", {
1842
+ branch: s.activeBranch,
1843
+ intervalMs
1844
+ });
1845
+ return;
1846
+ }
1847
+ if (s.disposed) return;
1848
+ s.fetchInFlight = true;
1849
+ void this.runPeriodicFetch(s, mountPath).catch((err) => {
1850
+ this.log.debug("periodic fetch failed", {
1851
+ error: err instanceof Error ? err.message : String(err)
1852
+ });
1853
+ }).finally(() => {
1854
+ s.fetchInFlight = false;
1855
+ });
1856
+ }, intervalMs);
1857
+ }
1858
+ /** One periodic-fetch tick. Bails out at each resumption point once disconnected. */
1859
+ async runPeriodicFetch(s, mountPath) {
1860
+ await git(["fetch", "origin"], mountPath, 6e4);
1861
+ if (s.disposed) return;
1862
+ if (s.sync.autoRebase && s.activeBranch !== s.branch) {
1833
1863
  try {
1834
- git("fetch origin", mountPath, 6e4);
1835
- if (s.sync.autoRebase && s.activeBranch !== s.branch) {
1836
- try {
1837
- git(`rebase origin/${s.branch}`, mountPath, 6e4);
1838
- } catch {
1839
- this.resolveConflictsOrAbort(s, mountPath, "rebase");
1840
- }
1841
- syncSubmodules(mountPath);
1842
- } else if (s.sync.autoPull) {
1843
- git(`pull origin ${s.activeBranch}`, mountPath, 6e4);
1844
- syncSubmodules(mountPath);
1845
- }
1864
+ await git(["rebase", `origin/${s.branch}`], mountPath, 6e4);
1846
1865
  } catch {
1866
+ await this.resolveConflictsOrAbort(s, mountPath, "rebase");
1847
1867
  }
1848
- }, intervalMs);
1868
+ if (s.disposed) return;
1869
+ await syncSubmodules(mountPath);
1870
+ } else if (s.sync.autoPull) {
1871
+ await git(["pull", "origin", s.activeBranch], mountPath, 6e4);
1872
+ if (s.disposed) return;
1873
+ await syncSubmodules(mountPath);
1874
+ }
1849
1875
  }
1850
1876
  // ── Conflict resolution ──────────────────────────────────────────────────
1851
1877
  /**
@@ -1853,17 +1879,17 @@ var GitConnector = class extends AbstractConnector {
1853
1879
  * "theirs" to a .conflict file. If resolution fails entirely, abort.
1854
1880
  * Returns true if conflicts were resolved, false if aborted.
1855
1881
  */
1856
- resolveConflictsOrAbort(s, mountPath, mode) {
1882
+ async resolveConflictsOrAbort(s, mountPath, mode) {
1857
1883
  try {
1858
- const conflicted = git("diff --name-only --diff-filter=U", mountPath).split("\n").filter(Boolean);
1884
+ const conflicted = (await git(["diff", "--name-only", "--diff-filter=U"], mountPath)).split("\n").filter(Boolean);
1859
1885
  if (conflicted.length === 0) return false;
1860
1886
  for (const file of conflicted) {
1861
- this.resolveFileConflict(mountPath, file);
1887
+ await this.resolveFileConflict(mountPath, file);
1862
1888
  }
1863
1889
  if (mode === "rebase") {
1864
- git("-c core.editor=true rebase --continue", mountPath, 3e4);
1890
+ await git(["-c", "core.editor=true", "rebase", "--continue"], mountPath, 3e4);
1865
1891
  } else {
1866
- git(`commit --no-edit`, mountPath);
1892
+ await git(["commit", "--no-edit"], mountPath);
1867
1893
  }
1868
1894
  for (const file of conflicted) {
1869
1895
  const ext = file.includes(".") ? file.slice(file.lastIndexOf(".")) : "";
@@ -1878,9 +1904,9 @@ var GitConnector = class extends AbstractConnector {
1878
1904
  } catch {
1879
1905
  try {
1880
1906
  if (mode === "rebase") {
1881
- git("rebase --abort", mountPath);
1907
+ await git(["rebase", "--abort"], mountPath);
1882
1908
  } else {
1883
- git("merge --abort", mountPath);
1909
+ await git(["merge", "--abort"], mountPath);
1884
1910
  }
1885
1911
  } catch {
1886
1912
  }
@@ -1890,31 +1916,48 @@ var GitConnector = class extends AbstractConnector {
1890
1916
  /**
1891
1917
  * For a single conflicted file: keep "ours", save "theirs" as .conflict file.
1892
1918
  */
1893
- resolveFileConflict(root, file) {
1919
+ async resolveFileConflict(root, file) {
1894
1920
  const ext = file.includes(".") ? file.slice(file.lastIndexOf(".")) : "";
1895
1921
  const base = file.includes(".") ? file.slice(0, file.lastIndexOf(".")) : file;
1896
1922
  const conflictPath = `${base}.conflict${ext}`;
1897
1923
  try {
1898
- const theirs = git(`show :3:${file}`, root);
1899
- writeFileSync(join(root, conflictPath), theirs);
1924
+ const theirs = await git(["show", `:3:${file}`], root);
1925
+ await withFsDeadline(
1926
+ `write ${conflictPath}`,
1927
+ () => writeFile(join(root, conflictPath), theirs)
1928
+ );
1900
1929
  } catch {
1901
1930
  const fullPath = join(root, file);
1902
- if (existsSync(fullPath)) {
1903
- const content = readFileSync(fullPath, "utf-8");
1904
- writeFileSync(join(root, conflictPath), content);
1931
+ const content = await tryWithFsDeadline(
1932
+ `read ${file}`,
1933
+ () => readFile(fullPath, "utf-8"),
1934
+ null
1935
+ );
1936
+ if (content !== null) {
1937
+ await withFsDeadline(
1938
+ `write ${conflictPath}`,
1939
+ () => writeFile(join(root, conflictPath), content)
1940
+ );
1905
1941
  }
1906
1942
  }
1907
1943
  try {
1908
- const ours = git(`show :2:${file}`, root);
1909
- writeFileSync(join(root, file), ours);
1944
+ const ours = await git(["show", `:2:${file}`], root);
1945
+ await withFsDeadline(`write ${file}`, () => writeFile(join(root, file), ours));
1910
1946
  } catch {
1911
1947
  const fullPath = join(root, file);
1912
- if (existsSync(fullPath)) {
1913
- const content = readFileSync(fullPath, "utf-8");
1914
- writeFileSync(fullPath, this.stripConflictKeepOurs(content));
1948
+ const content = await tryWithFsDeadline(
1949
+ `read ${file}`,
1950
+ () => readFile(fullPath, "utf-8"),
1951
+ null
1952
+ );
1953
+ if (content !== null) {
1954
+ await withFsDeadline(
1955
+ `write ${file}`,
1956
+ () => writeFile(fullPath, this.stripConflictKeepOurs(content))
1957
+ );
1915
1958
  }
1916
1959
  }
1917
- git(`add ${file} ${conflictPath}`, root);
1960
+ await git(["add", file, conflictPath], root);
1918
1961
  }
1919
1962
  stripConflictKeepOurs(content) {
1920
1963
  return content.replace(/<<<<<<< .*\n/g, "").replace(/=======\n[\s\S]*?>>>>>>> .*\n/g, "");
@@ -1922,30 +1965,48 @@ var GitConnector = class extends AbstractConnector {
1922
1965
  // ── Auto-commit on idle ────────────────────────────────────────────────────
1923
1966
  resetAutoCommitTimer(s, mountPath) {
1924
1967
  if (s.lifecycle.autoCommitIdleMs <= 0) return;
1968
+ if (s.disposed) return;
1925
1969
  if (s.autoCommitTimer) clearTimeout(s.autoCommitTimer);
1926
1970
  s.autoCommitTimer = setTimeout(() => {
1927
- this.performAutoCommit(s, mountPath);
1971
+ s.autoCommitTimer = void 0;
1972
+ if (s.disposed) return;
1973
+ if (s.autoCommitInFlight) {
1974
+ this.log.warn("auto-commit skipped \u2014 previous run still in flight", {
1975
+ branch: s.activeBranch
1976
+ });
1977
+ this.resetAutoCommitTimer(s, mountPath);
1978
+ return;
1979
+ }
1980
+ s.autoCommitInFlight = true;
1981
+ void this.performAutoCommit(s, mountPath).catch((err) => {
1982
+ this.log.debug("auto-commit failed", {
1983
+ error: err instanceof Error ? err.message : String(err)
1984
+ });
1985
+ }).finally(() => {
1986
+ s.autoCommitInFlight = false;
1987
+ });
1928
1988
  }, s.lifecycle.autoCommitIdleMs);
1929
1989
  }
1930
- performAutoCommit(s, mountPath) {
1990
+ async performAutoCommit(s, mountPath) {
1931
1991
  try {
1932
- const message = this.generateCommitMessage(mountPath);
1933
- const result = commitAll(mountPath, message);
1934
- if (!result) return;
1992
+ const message = await this.generateCommitMessage(mountPath);
1993
+ if (s.disposed) return;
1994
+ const result = await commitAll(mountPath, message);
1995
+ if (!result || s.disposed) return;
1935
1996
  if (s.lifecycle.pushAfterCommit) {
1936
1997
  try {
1937
- git(`push origin ${s.activeBranch}`, mountPath, 6e4);
1998
+ await git(["push", "origin", s.activeBranch], mountPath, 6e4);
1938
1999
  } catch {
1939
2000
  }
1940
2001
  }
1941
2002
  } catch {
1942
2003
  }
1943
2004
  }
1944
- generateCommitMessage(mountPath) {
2005
+ async generateCommitMessage(mountPath) {
1945
2006
  try {
1946
- git("add -A", mountPath);
1947
- const stat2 = git("diff --cached --stat", mountPath);
1948
- const lines = stat2.split("\n").filter((l) => l.includes("|"));
2007
+ await git(["add", "-A"], mountPath);
2008
+ const stat5 = await git(["diff", "--cached", "--stat"], mountPath);
2009
+ const lines = stat5.split("\n").filter((l) => l.includes("|"));
1949
2010
  if (lines.length === 0) return "skaile: auto-save";
1950
2011
  const files = lines.map((l) => l.split("|")[0].trim());
1951
2012
  if (files.length === 1) return `Update ${files[0]}`;
@@ -2217,6 +2278,7 @@ function syncFleetManaged2(options) {
2217
2278
  });
2218
2279
  return Promise.resolve({ filesWritten: 0, filesDeleted: 0, bytesTransferred: 0 });
2219
2280
  }
2281
+ var COPY_DEADLINE_FACTOR = 20;
2220
2282
  var LocalConnector = class extends AbstractConnector {
2221
2283
  name = "local";
2222
2284
  filesystem = {
@@ -2231,20 +2293,24 @@ var LocalConnector = class extends AbstractConnector {
2231
2293
  }
2232
2294
  const started = Date.now();
2233
2295
  const source = declaration.mount?.source ?? "";
2234
- this.log.info("mount start", { source, targetDir });
2235
2296
  const sourceDir = resolve(String(source));
2236
- if (!existsSync(sourceDir)) {
2237
- this.log.error("connect failed: source path does not exist", void 0, {
2238
- sourceDir
2297
+ if (isFleetManaged(declaration.id)) {
2298
+ this.log.info("mount handled by host fleet \u2014 skipping local copy", {
2299
+ connectorId: declaration.id,
2300
+ targetDir
2239
2301
  });
2240
- throw new Error(`Local source path does not exist: ${sourceDir}`);
2241
- }
2242
- mkdirSync(targetDir, { recursive: true });
2243
- const src = resolve(sourceDir);
2244
- const tgt = resolve(targetDir);
2245
- if (src !== tgt && !tgt.startsWith(`${src}/`)) {
2246
- cpSync(src, tgt, { recursive: true });
2302
+ await ensureFleetMounted(targetDir, this.log);
2303
+ this.log.info("mount ok", { targetDir, durationMs: Date.now() - started });
2304
+ return this.makeHandle(
2305
+ declaration,
2306
+ { sourceDir, fleetManaged: true },
2307
+ targetDir
2308
+ );
2247
2309
  }
2310
+ this.log.info("mount start", { source, targetDir });
2311
+ await this.assertSourceExists(sourceDir);
2312
+ await withFsDeadline(`mkdir ${targetDir}`, () => mkdir(targetDir, { recursive: true }));
2313
+ await this.copyTree(sourceDir, targetDir);
2248
2314
  this.log.info("mount ok", { targetDir, durationMs: Date.now() - started });
2249
2315
  return this.makeHandle(declaration, { sourceDir }, targetDir);
2250
2316
  }
@@ -2253,18 +2319,58 @@ var LocalConnector = class extends AbstractConnector {
2253
2319
  }
2254
2320
  async _sync(handle, _options) {
2255
2321
  this.log.debug("sync start");
2256
- const { sourceDir } = handle.state;
2257
- const src = resolve(sourceDir);
2322
+ const state = handle.state;
2323
+ if (state.fleetManaged) {
2324
+ this.log.debug("sync skipped \u2014 fleet-managed");
2325
+ return { filesWritten: 0, filesDeleted: 0, bytesTransferred: 0 };
2326
+ }
2327
+ const src = resolve(state.sourceDir);
2258
2328
  const tgt = resolve(handle.mountPath);
2259
2329
  if (src === tgt || tgt.startsWith(`${src}/`)) {
2260
2330
  this.log.debug("sync ok (no-op: source equals target)");
2261
2331
  return { filesWritten: 0, filesDeleted: 0, bytesTransferred: 0 };
2262
2332
  }
2263
- mkdirSync(handle.mountPath, { recursive: true });
2264
- cpSync(src, handle.mountPath, { recursive: true });
2333
+ await withFsDeadline(`mkdir ${tgt}`, () => mkdir(tgt, { recursive: true }));
2334
+ await this.copyTree(src, tgt);
2265
2335
  this.log.debug("sync ok");
2266
2336
  return { filesWritten: 0, filesDeleted: 0, bytesTransferred: 0 };
2267
2337
  }
2338
+ /**
2339
+ * Fail with the historical message when the source directory is missing,
2340
+ * while letting a wedged-mount deadline surface as itself.
2341
+ *
2342
+ * The old `existsSync` probe could not tell those apart — and on a hung
2343
+ * mount it never returned at all.
2344
+ */
2345
+ async assertSourceExists(sourceDir) {
2346
+ try {
2347
+ await withFsDeadline(`stat ${sourceDir}`, () => stat(sourceDir));
2348
+ } catch (err) {
2349
+ if (err instanceof FsDeadlineError) {
2350
+ this.log.error("connect failed: source path unreadable (deadline)", err, { sourceDir });
2351
+ throw err;
2352
+ }
2353
+ this.log.error("connect failed: source path does not exist", void 0, { sourceDir });
2354
+ throw new Error(`Local source path does not exist: ${sourceDir}`);
2355
+ }
2356
+ }
2357
+ /**
2358
+ * Recursively copy `src` into `tgt`, skipping the copy when the two overlap.
2359
+ *
2360
+ * The string-overlap guard is a second line of defence behind the
2361
+ * fleet-managed refusal in `connect`: it is a *textual* comparison, so a
2362
+ * source that differs textually while overlapping physically (symlink, bind
2363
+ * mount, `..` segments already normalised away) still slips past it. It stays
2364
+ * because it is free and catches the common container layout.
2365
+ */
2366
+ async copyTree(src, tgt) {
2367
+ if (src === tgt || tgt.startsWith(`${src}/`)) return;
2368
+ await withFsDeadline(
2369
+ `cp -r ${src} -> ${tgt}`,
2370
+ () => cp(src, tgt, { recursive: true }),
2371
+ fsDeadlineMs() * COPY_DEADLINE_FACTOR
2372
+ );
2373
+ }
2268
2374
  watch(handle, callback, options) {
2269
2375
  let fsWatcher = null;
2270
2376
  let closed = false;
@@ -3373,6 +3479,7 @@ function createConnector12() {
3373
3479
  return new PostgresConnector();
3374
3480
  }
3375
3481
  var s3Pkg = "@aws-sdk/client-s3";
3482
+ var DOWNLOAD_DEADLINE_FACTOR = 20;
3376
3483
  var S3Connector = class extends AbstractConnector {
3377
3484
  name = "s3";
3378
3485
  /** Optional SDK module override — used in tests to avoid importing the real AWS SDK. */
@@ -3420,7 +3527,7 @@ var S3Connector = class extends AbstractConnector {
3420
3527
  }
3421
3528
  const client = new S3Client(clientConfig);
3422
3529
  const state = { client, bucket, prefix, region };
3423
- mkdirSync(targetDir, { recursive: true });
3530
+ await withFsDeadline(`mkdir ${targetDir}`, () => mkdir(targetDir, { recursive: true }));
3424
3531
  try {
3425
3532
  const result = await this.downloadAll(state, targetDir);
3426
3533
  this.log.info("mount ok", {
@@ -3451,6 +3558,28 @@ var S3Connector = class extends AbstractConnector {
3451
3558
  throw err;
3452
3559
  }
3453
3560
  }
3561
+ /**
3562
+ * Fetch one object's bytes, or `null` when it yields none.
3563
+ *
3564
+ * S3-side failures are contained here — a single `GetObject` miss is
3565
+ * survivable and must not abort the whole sync. Local filesystem failures are
3566
+ * deliberately *not* in scope: see the write path in {@link downloadAll}.
3567
+ */
3568
+ async fetchObject(s3Mod, state, key) {
3569
+ try {
3570
+ const resp = await state.client.send(
3571
+ new s3Mod.GetObjectCommand({ Bucket: state.bucket, Key: key })
3572
+ );
3573
+ const bytes = await resp.Body?.transformToByteArray();
3574
+ return bytes == null ? null : Buffer.from(bytes);
3575
+ } catch (err) {
3576
+ this.log.warn("object download failed", {
3577
+ key,
3578
+ error: err instanceof Error ? err.message : String(err)
3579
+ });
3580
+ return null;
3581
+ }
3582
+ }
3454
3583
  async downloadAll(state, targetDir) {
3455
3584
  const s3Mod = await this._loadSdk();
3456
3585
  const { client, bucket, prefix } = state;
@@ -3474,23 +3603,32 @@ var S3Connector = class extends AbstractConnector {
3474
3603
  } while (continuationToken);
3475
3604
  let filesWritten = 0;
3476
3605
  let bytesTransferred = 0;
3606
+ const budgetMs = fsDeadlineMs() * DOWNLOAD_DEADLINE_FACTOR;
3607
+ const deadlineAt = Date.now() + budgetMs;
3608
+ const created = /* @__PURE__ */ new Set();
3477
3609
  for (const { key, relPath } of entries) {
3478
- try {
3479
- const resp = await client.send(new s3Mod.GetObjectCommand({ Bucket: bucket, Key: key }));
3480
- const bytes = await resp.Body?.transformToByteArray();
3481
- if (bytes == null) continue;
3482
- const body = Buffer.from(bytes);
3483
- const localPath = join(targetDir, relPath);
3484
- mkdirSync(dirname(localPath), { recursive: true });
3485
- writeFileSync(localPath, body);
3486
- filesWritten++;
3487
- bytesTransferred += body.byteLength;
3488
- } catch (err) {
3489
- this.log.warn("object download failed", {
3490
- key,
3491
- error: err instanceof Error ? err.message : String(err)
3492
- });
3610
+ if (deadlineAt - Date.now() <= 0) {
3611
+ throw new FsDeadlineError(`downloadAll ${targetDir}`, budgetMs);
3612
+ }
3613
+ const body = await this.fetchObject(s3Mod, state, key);
3614
+ if (body == null) continue;
3615
+ const localPath = join(targetDir, relPath);
3616
+ const parent = dirname(localPath);
3617
+ if (!created.has(parent)) {
3618
+ await withFsDeadline(
3619
+ `mkdir ${parent}`,
3620
+ () => mkdir(parent, { recursive: true }),
3621
+ deadlineAt - Date.now()
3622
+ );
3623
+ created.add(parent);
3493
3624
  }
3625
+ await withFsDeadline(
3626
+ `writeFile ${localPath}`,
3627
+ () => writeFile(localPath, body),
3628
+ deadlineAt - Date.now()
3629
+ );
3630
+ filesWritten++;
3631
+ bytesTransferred += body.byteLength;
3494
3632
  }
3495
3633
  return { filesWritten, filesDeleted: 0, bytesTransferred };
3496
3634
  }
@@ -3583,14 +3721,21 @@ var SQLiteConnector = class extends AbstractConnector {
3583
3721
  let db;
3584
3722
  if (dbPath === ":memory:") {
3585
3723
  db = new SQL.Database();
3586
- } else if (existsSync(dbPath)) {
3587
- const buffer = readFileSync(dbPath);
3588
- db = new SQL.Database(buffer);
3589
- } else if (!isReadonly) {
3590
- db = new SQL.Database();
3591
3724
  } else {
3592
- this.log.error("connect failed: db file not found", void 0, { dbPath });
3593
- throw new Error(`SQLite database not found: ${dbPath}`);
3725
+ let buffer;
3726
+ try {
3727
+ buffer = await withFsDeadline(`readFile ${dbPath}`, () => readFile(dbPath));
3728
+ } catch (err) {
3729
+ if (err.code !== "ENOENT") {
3730
+ this.log.error("connect failed: db path unreadable", err, { dbPath });
3731
+ throw err;
3732
+ }
3733
+ if (isReadonly) {
3734
+ this.log.error("connect failed: db file not found", void 0, { dbPath });
3735
+ throw new Error(`SQLite database not found: ${dbPath}`);
3736
+ }
3737
+ }
3738
+ db = buffer ? new SQL.Database(buffer) : new SQL.Database();
3594
3739
  }
3595
3740
  this.log.info("connect ok", { dbPath, durationMs: Date.now() - started });
3596
3741
  if (!isReadonly && dbPath !== ":memory:") {
@@ -3605,7 +3750,7 @@ var SQLiteConnector = class extends AbstractConnector {
3605
3750
  this.log.info("disconnect");
3606
3751
  const { db, dbPath, readonly: isReadonly } = handle.state;
3607
3752
  if (!isReadonly && dbPath !== ":memory:") {
3608
- this.saveToDisk(db, dbPath);
3753
+ await this.saveToDisk(db, dbPath);
3609
3754
  }
3610
3755
  db.close();
3611
3756
  handle.status = "disconnected";
@@ -3613,13 +3758,18 @@ var SQLiteConnector = class extends AbstractConnector {
3613
3758
  db(handle) {
3614
3759
  return handle.state.db;
3615
3760
  }
3616
- /** sql.js operates in-memory — flush to disk explicitly. */
3617
- saveToDisk(db, dbPath) {
3761
+ /** sql.js operates in-memory — flush to disk explicitly. Best-effort, but no
3762
+ * longer silent: a dropped flush on a wedged mount is lost data, so it warns. */
3763
+ async saveToDisk(db, dbPath) {
3618
3764
  try {
3619
3765
  const data = db.export();
3620
3766
  const buffer = Buffer.from(data);
3621
- writeFileSync(dbPath, buffer);
3622
- } catch {
3767
+ await withFsDeadline(`writeFile ${dbPath}`, () => writeFile(dbPath, buffer));
3768
+ } catch (err) {
3769
+ this.log.warn("db flush failed \u2014 changes not persisted", {
3770
+ dbPath,
3771
+ error: err instanceof Error ? err.message : String(err)
3772
+ });
3623
3773
  }
3624
3774
  }
3625
3775
  /** Run a query that returns rows. sql.js uses stmt.getAsObject() pattern. */
@@ -3790,7 +3940,7 @@ var SQLiteConnector = class extends AbstractConnector {
3790
3940
  if (!sql) return "Error: sql argument is required";
3791
3941
  const changes = this.runStmt(db, sql);
3792
3942
  if (!state.readonly && state.dbPath !== ":memory:") {
3793
- this.saveToDisk(db, state.dbPath);
3943
+ await this.saveToDisk(db, state.dbPath);
3794
3944
  }
3795
3945
  return JSON.stringify({ changes });
3796
3946
  }
@@ -3821,7 +3971,7 @@ var StaticServerConnector = class extends AbstractConnector {
3821
3971
  const worktreeDir = String(declaration.options?.worktree_dir ?? DEFAULT_WORKTREE_DIR);
3822
3972
  let repoRoot = null;
3823
3973
  try {
3824
- repoRoot = findGitRoot(process.cwd());
3974
+ repoRoot = await findGitRoot(process.cwd());
3825
3975
  } catch {
3826
3976
  }
3827
3977
  return this.makeHandle(declaration, {
@@ -3945,7 +4095,10 @@ var StaticServerConnector = class extends AbstractConnector {
3945
4095
  }
3946
4096
  const serveDir = dir;
3947
4097
  const server = createServer((req, res) => {
3948
- serveStaticFile(serveDir, req.url ?? "/", res);
4098
+ void serveStaticFile(serveDir, req.url ?? "/", res).catch(() => {
4099
+ if (!res.headersSent) res.writeHead(500, { "content-type": "text/plain" });
4100
+ res.end();
4101
+ });
3949
4102
  });
3950
4103
  server.listen(port);
3951
4104
  state.instances.set(label, {
@@ -4014,7 +4167,14 @@ var StaticServerConnector = class extends AbstractConnector {
4014
4167
  };
4015
4168
  }
4016
4169
  };
4017
- function serveStaticFile(rootDir, reqUrl, res) {
4170
+ async function statOrNull(filePath) {
4171
+ try {
4172
+ return await withFsDeadline(`stat ${filePath}`, () => stat(filePath));
4173
+ } catch {
4174
+ return void 0;
4175
+ }
4176
+ }
4177
+ async function serveStaticFile(rootDir, reqUrl, res) {
4018
4178
  const root = resolve(rootDir);
4019
4179
  const pathname = decodeURIComponent(new URL(reqUrl, "http://localhost").pathname);
4020
4180
  let filePath = resolve(root, `.${pathname}`);
@@ -4023,10 +4183,18 @@ function serveStaticFile(rootDir, reqUrl, res) {
4023
4183
  res.end("Forbidden");
4024
4184
  return;
4025
4185
  }
4026
- if (pathname.endsWith("/") || existsSync(filePath) && statSync(filePath).isDirectory()) {
4186
+ let stats;
4187
+ if (pathname.endsWith("/")) {
4027
4188
  filePath = join(filePath, "index.html");
4189
+ stats = await statOrNull(filePath);
4190
+ } else {
4191
+ stats = await statOrNull(filePath);
4192
+ if (stats?.isDirectory()) {
4193
+ filePath = join(filePath, "index.html");
4194
+ stats = await statOrNull(filePath);
4195
+ }
4028
4196
  }
4029
- if (!existsSync(filePath) || !statSync(filePath).isFile()) {
4197
+ if (!stats?.isFile()) {
4030
4198
  res.writeHead(404, { "content-type": "text/plain" });
4031
4199
  res.end("Not Found");
4032
4200
  return;
@@ -4361,8 +4529,13 @@ var XStateConnector = class extends AbstractConnector {
4361
4529
  let definition = declaration.options?.machine;
4362
4530
  if (!definition && declaration.options?.definitionPath) {
4363
4531
  const defPath = String(declaration.options.definitionPath);
4364
- if (!existsSync(defPath)) throw new Error(`Machine definition not found: ${defPath}`);
4365
- const raw = readFileSync(defPath, "utf-8");
4532
+ let raw;
4533
+ try {
4534
+ raw = await withFsDeadline(`readFile ${defPath}`, () => readFile(defPath, "utf-8"));
4535
+ } catch (err) {
4536
+ if (err instanceof FsDeadlineError) throw err;
4537
+ throw new Error(`Machine definition not found: ${defPath}`);
4538
+ }
4366
4539
  if (defPath.endsWith(".json")) {
4367
4540
  definition = JSON.parse(raw);
4368
4541
  } else {
@@ -5317,7 +5490,7 @@ var ConnectorManager = class {
5317
5490
  if (connector.filesystem != null) {
5318
5491
  const absPath = this.resolveMountTarget(declaration);
5319
5492
  this.reserveMountTarget(declaration.id, absPath);
5320
- if (!existsSync(absPath)) mkdirSync(absPath, { recursive: true });
5493
+ await withFsDeadline(`mkdir ${absPath}`, () => mkdir(absPath, { recursive: true }));
5321
5494
  ctx.mountTarget = absPath;
5322
5495
  }
5323
5496
  return ctx;
@@ -5370,8 +5543,18 @@ var ConnectorManager = class {
5370
5543
  */
5371
5544
  async connectAll(declarations, options) {
5372
5545
  this.mgrLog.info("connectAll start", { count: declarations.length });
5373
- for (const decl of declarations) {
5374
- if (decl.mount != null) this.reserveMountTarget(decl.id, this.resolveMountTarget(decl));
5546
+ const claimed = [];
5547
+ try {
5548
+ for (const decl of declarations) {
5549
+ if (decl.mount == null) continue;
5550
+ const absPath = this.resolveMountTarget(decl);
5551
+ const isNew = !this.mountTargets.has(absPath);
5552
+ this.reserveMountTarget(decl.id, absPath);
5553
+ if (isNew) claimed.push(absPath);
5554
+ }
5555
+ } catch (err) {
5556
+ for (const path of claimed) this.mountTargets.delete(path);
5557
+ throw err;
5375
5558
  }
5376
5559
  const results = [];
5377
5560
  for (const decl of declarations) {
@@ -5447,6 +5630,7 @@ var ConnectorManager = class {
5447
5630
  access: decl.access
5448
5631
  };
5449
5632
  } catch (err) {
5633
+ if (!this.active.has(decl.id)) this.releaseMountTarget(decl.id);
5450
5634
  const msg = err instanceof Error ? err.message : String(err);
5451
5635
  this.mgrLog.error("connect failed", err, { id: decl.id, driver: decl.driver });
5452
5636
  this.opts.onStatusChange?.({
@@ -5514,8 +5698,8 @@ var ConnectorManager = class {
5514
5698
  instance: declaration.id
5515
5699
  });
5516
5700
  connector.setLogger?.(connectorLog);
5517
- const ctx = await this.buildConnectContext(declaration, connector);
5518
5701
  try {
5702
+ const ctx = await this.buildConnectContext(declaration, connector);
5519
5703
  const handle = await this.withSpan(
5520
5704
  "connector.connect",
5521
5705
  {
@@ -6796,11 +6980,15 @@ var DEFAULT_IGNORED = [
6796
6980
  (p) => p.endsWith("~")
6797
6981
  ];
6798
6982
  var DEFAULT_DEBOUNCE_MS = 150;
6799
- function parseGitignore(rootDir) {
6983
+ async function parseGitignore(rootDir) {
6800
6984
  const gitignorePath = join(rootDir, ".gitignore");
6801
- if (!existsSync(gitignorePath)) return [];
6985
+ const content = await tryWithFsDeadline(
6986
+ `read ${gitignorePath}`,
6987
+ () => readFile(gitignorePath, "utf-8"),
6988
+ null
6989
+ );
6990
+ if (content === null) return [];
6802
6991
  try {
6803
- const content = readFileSync(gitignorePath, "utf-8");
6804
6992
  const matchers = [];
6805
6993
  for (const raw of content.split("\n")) {
6806
6994
  const line = raw.trim();
@@ -6834,7 +7022,7 @@ var CHOKIDAR_EVENT_MAP = {
6834
7022
  };
6835
7023
  async function createFsWatcher(rootDir, callback, options) {
6836
7024
  const log = createLogger({ kind: "connector", subkind: "watcher", instance: rootDir });
6837
- const gitignorePatterns = parseGitignore(rootDir);
7025
+ const gitignorePatterns = await parseGitignore(rootDir);
6838
7026
  const optionsIgnored = (options?.ignored ?? []).map(
6839
7027
  (entry) => typeof entry === "string" ? globToMatcher(entry) : entry
6840
7028
  );
@@ -6865,6 +7053,7 @@ async function createFsWatcher(rootDir, callback, options) {
6865
7053
  close: () => watcher.close()
6866
7054
  };
6867
7055
  }
7056
+ var execFileAsync3 = promisify(execFile);
6868
7057
  var WorktreeRegistryImpl = class {
6869
7058
  entries = /* @__PURE__ */ new Map();
6870
7059
  register(path, owner) {
@@ -6889,27 +7078,37 @@ var WorktreeRegistryImpl = class {
6889
7078
  }
6890
7079
  };
6891
7080
  var worktreeRegistry = new WorktreeRegistryImpl();
6892
- function git2(args, cwd) {
6893
- return execSync(`git ${args}`, { cwd, encoding: "utf-8" }).trim();
7081
+ var GIT_QUERY_TIMEOUT_MS = 15e3;
7082
+ var GIT_WORKTREE_TIMEOUT_MS = 12e4;
7083
+ async function git2(args, cwd, timeoutMs) {
7084
+ const { stdout } = await execFileAsync3("git", args, {
7085
+ cwd,
7086
+ encoding: "utf-8",
7087
+ timeout: timeoutMs,
7088
+ killSignal: "SIGKILL"
7089
+ });
7090
+ return stdout.trim();
6894
7091
  }
6895
- function resolveRef(repoRoot, ref) {
6896
- return git2(`rev-parse --verify ${ref}`, repoRoot);
7092
+ async function resolveRef(repoRoot, ref) {
7093
+ return git2(["rev-parse", "--verify", ref], repoRoot, GIT_QUERY_TIMEOUT_MS);
6897
7094
  }
6898
- function findGitRoot(fromDir) {
6899
- return git2("rev-parse --show-toplevel", fromDir);
7095
+ async function findGitRoot(fromDir) {
7096
+ return git2(["rev-parse", "--show-toplevel"], fromDir, GIT_QUERY_TIMEOUT_MS);
6900
7097
  }
6901
7098
  async function createWorktree(opts) {
6902
- const sha = resolveRef(opts.repoRoot, opts.ref);
7099
+ const sha = await resolveRef(opts.repoRoot, opts.ref);
6903
7100
  const label = opts.label ?? sha.slice(0, 8);
6904
7101
  const wtPath = resolve(opts.baseDir, label);
6905
- if (!existsSync(opts.baseDir)) {
6906
- mkdirSync(opts.baseDir, { recursive: true });
6907
- }
6908
- git2(`worktree add "${wtPath}" ${sha} --detach`, opts.repoRoot);
7102
+ await withFsDeadline(`mkdir ${opts.baseDir}`, () => mkdir(opts.baseDir, { recursive: true }));
7103
+ await git2(["worktree", "add", wtPath, sha, "--detach"], opts.repoRoot, GIT_WORKTREE_TIMEOUT_MS);
6909
7104
  worktreeRegistry.register(wtPath, opts.owner);
6910
7105
  let branch;
6911
7106
  try {
6912
- const refName = git2(`rev-parse --abbrev-ref ${opts.ref}`, opts.repoRoot);
7107
+ const refName = await git2(
7108
+ ["rev-parse", "--abbrev-ref", opts.ref],
7109
+ opts.repoRoot,
7110
+ GIT_QUERY_TIMEOUT_MS
7111
+ );
6913
7112
  if (refName !== "HEAD" && refName !== sha) branch = refName;
6914
7113
  } catch {
6915
7114
  }
@@ -6924,15 +7123,19 @@ async function createWorktree(opts) {
6924
7123
  throw new Error(`worktree in use by: ${remaining.join(", ")}`);
6925
7124
  }
6926
7125
  try {
6927
- git2(`worktree remove "${wtPath}" --force`, opts.repoRoot);
7126
+ await git2(
7127
+ ["worktree", "remove", wtPath, "--force"],
7128
+ opts.repoRoot,
7129
+ GIT_WORKTREE_TIMEOUT_MS
7130
+ );
6928
7131
  } catch {
6929
7132
  }
6930
- git2("worktree prune", opts.repoRoot);
7133
+ await git2(["worktree", "prune"], opts.repoRoot, GIT_WORKTREE_TIMEOUT_MS);
6931
7134
  }
6932
7135
  };
6933
7136
  }
6934
7137
  async function listWorktrees(repoRoot) {
6935
- const raw = git2("worktree list --porcelain", repoRoot);
7138
+ const raw = await git2(["worktree", "list", "--porcelain"], repoRoot, GIT_QUERY_TIMEOUT_MS);
6936
7139
  const trees = [];
6937
7140
  let current = {};
6938
7141
  for (const line of raw.split("\n")) {
@@ -7907,5 +8110,5 @@ function createConnector() {
7907
8110
  }
7908
8111
 
7909
8112
  export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, BoxConnector, ConnectorFieldMissingError, ConnectorManager, ConnectorStartupError, DeployConnector, DevServerConnector, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, PortPool, PostgresConnector, S3Connector, SQLiteConnector, SharePointConnector, StaticServerConnector, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, __test, atomicReplaceCredential, buildConnectorPromptSection, buildSdkConnectorTools, buildSdkFlowTools, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector20, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createFsWatcher, createWorktree, defaultSpawn, ensureDirMode, ensureFleetMounted, findGitRoot, findMissingPackages, getConnector, installNpmPackages, isFleetManaged, isPackageResolvable, listConnectors, listWorktrees, readGitSyncStatus, registerBuiltinConnectors, removeMountBlock, renderCredentialHelperScript, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock };
7910
- //# sourceMappingURL=chunk-6POODADP.js.map
7911
- //# sourceMappingURL=chunk-6POODADP.js.map
8113
+ //# sourceMappingURL=chunk-HOL5KD7U.js.map
8114
+ //# sourceMappingURL=chunk-HOL5KD7U.js.map