@usine/executor 0.2.1 → 0.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 (177) hide show
  1. package/README.md +115 -37
  2. package/dist/child-command.d.ts +4 -7
  3. package/dist/child-command.d.ts.map +1 -1
  4. package/dist/child-command.js +6 -12
  5. package/dist/child-command.js.map +1 -1
  6. package/dist/claude-login-lock.d.ts +8 -0
  7. package/dist/claude-login-lock.d.ts.map +1 -0
  8. package/dist/claude-login-lock.js +9 -0
  9. package/dist/claude-login-lock.js.map +1 -0
  10. package/dist/credential-environment.d.ts +20 -0
  11. package/dist/credential-environment.d.ts.map +1 -0
  12. package/dist/credential-environment.js +20 -0
  13. package/dist/credential-environment.js.map +1 -0
  14. package/dist/durable-session.d.ts +63 -0
  15. package/dist/durable-session.d.ts.map +1 -0
  16. package/dist/durable-session.js +491 -0
  17. package/dist/durable-session.js.map +1 -0
  18. package/dist/exe-dev/commands.d.ts +23 -13
  19. package/dist/exe-dev/commands.d.ts.map +1 -1
  20. package/dist/exe-dev/commands.js +11 -57
  21. package/dist/exe-dev/commands.js.map +1 -1
  22. package/dist/exe-dev/exe-dev.d.ts +9 -3
  23. package/dist/exe-dev/exe-dev.d.ts.map +1 -1
  24. package/dist/exe-dev/exe-dev.js +53 -128
  25. package/dist/exe-dev/exe-dev.js.map +1 -1
  26. package/dist/exe-dev/grants.d.ts.map +1 -1
  27. package/dist/exe-dev/grants.js +35 -15
  28. package/dist/exe-dev/grants.js.map +1 -1
  29. package/dist/exe-dev/model.d.ts +15 -19
  30. package/dist/exe-dev/model.d.ts.map +1 -1
  31. package/dist/exe-dev/model.js +9 -12
  32. package/dist/exe-dev/model.js.map +1 -1
  33. package/dist/exe-dev/preflight.d.ts +8 -4
  34. package/dist/exe-dev/preflight.d.ts.map +1 -1
  35. package/dist/exe-dev/preflight.js +23 -33
  36. package/dist/exe-dev/preflight.js.map +1 -1
  37. package/dist/executor.d.ts +140 -41
  38. package/dist/executor.d.ts.map +1 -1
  39. package/dist/executor.js +90 -19
  40. package/dist/executor.js.map +1 -1
  41. package/dist/guard.d.ts +57 -7
  42. package/dist/guard.d.ts.map +1 -1
  43. package/dist/guard.js +273 -59
  44. package/dist/guard.js.map +1 -1
  45. package/dist/harness-preflight.d.ts +25 -4
  46. package/dist/harness-preflight.d.ts.map +1 -1
  47. package/dist/harness-preflight.js +25 -29
  48. package/dist/harness-preflight.js.map +1 -1
  49. package/dist/keyed-lock.d.ts +2 -3
  50. package/dist/keyed-lock.d.ts.map +1 -1
  51. package/dist/keyed-lock.js +2 -3
  52. package/dist/keyed-lock.js.map +1 -1
  53. package/dist/leftovers.d.ts +9 -0
  54. package/dist/leftovers.d.ts.map +1 -0
  55. package/dist/leftovers.js +14 -0
  56. package/dist/leftovers.js.map +1 -0
  57. package/dist/local/credentials.d.ts +21 -0
  58. package/dist/local/credentials.d.ts.map +1 -0
  59. package/dist/local/credentials.js +39 -0
  60. package/dist/local/credentials.js.map +1 -0
  61. package/dist/local/leftovers.d.ts +8 -0
  62. package/dist/local/leftovers.d.ts.map +1 -0
  63. package/dist/local/leftovers.js +23 -0
  64. package/dist/local/leftovers.js.map +1 -0
  65. package/dist/local/local.d.ts +16 -10
  66. package/dist/local/local.d.ts.map +1 -1
  67. package/dist/local/local.js +163 -129
  68. package/dist/local/local.js.map +1 -1
  69. package/dist/memory-preflight.d.ts +25 -0
  70. package/dist/memory-preflight.d.ts.map +1 -0
  71. package/dist/memory-preflight.js +83 -0
  72. package/dist/memory-preflight.js.map +1 -0
  73. package/dist/pre-push-hook.d.ts +20 -0
  74. package/dist/pre-push-hook.d.ts.map +1 -0
  75. package/dist/pre-push-hook.js +33 -0
  76. package/dist/pre-push-hook.js.map +1 -0
  77. package/dist/prepared-attempt.d.ts +33 -3
  78. package/dist/prepared-attempt.d.ts.map +1 -1
  79. package/dist/prepared-attempt.js +109 -31
  80. package/dist/prepared-attempt.js.map +1 -1
  81. package/dist/provision.d.ts +77 -14
  82. package/dist/provision.d.ts.map +1 -1
  83. package/dist/provision.js +357 -55
  84. package/dist/provision.js.map +1 -1
  85. package/dist/remote/commands.d.ts +51 -0
  86. package/dist/remote/commands.d.ts.map +1 -0
  87. package/dist/remote/commands.js +94 -0
  88. package/dist/remote/commands.js.map +1 -0
  89. package/dist/remote/leftovers.d.ts +14 -0
  90. package/dist/remote/leftovers.d.ts.map +1 -0
  91. package/dist/remote/leftovers.js +22 -0
  92. package/dist/remote/leftovers.js.map +1 -0
  93. package/dist/remote/liveness.d.ts +33 -0
  94. package/dist/remote/liveness.d.ts.map +1 -0
  95. package/dist/remote/liveness.js +194 -0
  96. package/dist/remote/liveness.js.map +1 -0
  97. package/dist/remote/machine.d.ts +64 -0
  98. package/dist/remote/machine.d.ts.map +1 -0
  99. package/dist/remote/machine.js +2 -0
  100. package/dist/remote/machine.js.map +1 -0
  101. package/dist/remote/remote.d.ts +24 -0
  102. package/dist/remote/remote.d.ts.map +1 -0
  103. package/dist/remote/remote.js +308 -0
  104. package/dist/remote/remote.js.map +1 -0
  105. package/dist/remote/sweep.d.ts +15 -0
  106. package/dist/remote/sweep.d.ts.map +1 -0
  107. package/dist/remote/sweep.js +116 -0
  108. package/dist/remote/sweep.js.map +1 -0
  109. package/dist/renewable-credential.d.ts +17 -0
  110. package/dist/renewable-credential.d.ts.map +1 -0
  111. package/dist/renewable-credential.js +58 -0
  112. package/dist/renewable-credential.js.map +1 -0
  113. package/dist/salvage.d.ts +30 -0
  114. package/dist/salvage.d.ts.map +1 -0
  115. package/dist/salvage.js +104 -0
  116. package/dist/salvage.js.map +1 -0
  117. package/dist/ssh/credentials.d.ts +40 -0
  118. package/dist/ssh/credentials.d.ts.map +1 -0
  119. package/dist/ssh/credentials.js +83 -0
  120. package/dist/ssh/credentials.js.map +1 -0
  121. package/dist/ssh/gateway/admin.d.ts +45 -0
  122. package/dist/ssh/gateway/admin.d.ts.map +1 -0
  123. package/dist/ssh/gateway/admin.js +129 -0
  124. package/dist/ssh/gateway/admin.js.map +1 -0
  125. package/dist/ssh/gateway/attachments.d.ts +22 -0
  126. package/dist/ssh/gateway/attachments.d.ts.map +1 -0
  127. package/dist/ssh/gateway/attachments.js +154 -0
  128. package/dist/ssh/gateway/attachments.js.map +1 -0
  129. package/dist/ssh/gateway/environment.d.ts +52 -0
  130. package/dist/ssh/gateway/environment.d.ts.map +1 -0
  131. package/dist/ssh/gateway/environment.js +78 -0
  132. package/dist/ssh/gateway/environment.js.map +1 -0
  133. package/dist/ssh/gateway/forward.d.ts +74 -0
  134. package/dist/ssh/gateway/forward.d.ts.map +1 -0
  135. package/dist/ssh/gateway/forward.js +247 -0
  136. package/dist/ssh/gateway/forward.js.map +1 -0
  137. package/dist/ssh/gateway/preflight.d.ts +28 -0
  138. package/dist/ssh/gateway/preflight.d.ts.map +1 -0
  139. package/dist/ssh/gateway/preflight.js +234 -0
  140. package/dist/ssh/gateway/preflight.js.map +1 -0
  141. package/dist/ssh/model.d.ts +65 -0
  142. package/dist/ssh/model.d.ts.map +1 -0
  143. package/dist/ssh/model.js +2 -0
  144. package/dist/ssh/model.js.map +1 -0
  145. package/dist/ssh/preflight.d.ts +16 -0
  146. package/dist/ssh/preflight.d.ts.map +1 -0
  147. package/dist/ssh/preflight.js +47 -0
  148. package/dist/ssh/preflight.js.map +1 -0
  149. package/dist/ssh/ssh.d.ts +20 -0
  150. package/dist/ssh/ssh.d.ts.map +1 -0
  151. package/dist/ssh/ssh.js +78 -0
  152. package/dist/ssh/ssh.js.map +1 -0
  153. package/dist/ssh/workers.d.ts +53 -0
  154. package/dist/ssh/workers.d.ts.map +1 -0
  155. package/dist/ssh/workers.js +173 -0
  156. package/dist/ssh/workers.js.map +1 -0
  157. package/package.json +12 -4
  158. package/dist/exe-dev/channel.d.ts +0 -12
  159. package/dist/exe-dev/channel.d.ts.map +0 -1
  160. package/dist/exe-dev/channel.js +0 -42
  161. package/dist/exe-dev/channel.js.map +0 -1
  162. package/dist/exe-dev/shell.d.ts +0 -12
  163. package/dist/exe-dev/shell.d.ts.map +0 -1
  164. package/dist/exe-dev/shell.js +0 -31
  165. package/dist/exe-dev/shell.js.map +0 -1
  166. package/dist/exe-dev/sweep.d.ts +0 -10
  167. package/dist/exe-dev/sweep.d.ts.map +0 -1
  168. package/dist/exe-dev/sweep.js +0 -117
  169. package/dist/exe-dev/sweep.js.map +0 -1
  170. package/dist/invalid-frame.d.ts +0 -17
  171. package/dist/invalid-frame.d.ts.map +0 -1
  172. package/dist/invalid-frame.js +0 -111
  173. package/dist/invalid-frame.js.map +0 -1
  174. package/dist/run-host-session.d.ts +0 -27
  175. package/dist/run-host-session.d.ts.map +0 -1
  176. package/dist/run-host-session.js +0 -303
  177. package/dist/run-host-session.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../../src/ssh/gateway/attachments.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAqB,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAChG,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnF,OAAO,EACL,kBAAkB,EAClB,0BAA0B,GAI3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAuB,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvE;;;GAGG;AACH,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;CAOxC,CAAC,IAAI,EAAE,CAAC;AAET,gHAAgH;AAChH,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAOrC,0GAA0G;AAC1G,MAAM,iBAAiB,GAAG,CAAC,OAAmB,EAAU,EAAE,CAAC,GAAG,OAAO,CAAC,eAAe,KAAK,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC,QAAQ,CAAC,EAC3F,QAAwB,EACxB,UAA4E;IAE5E,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,kBAAkB,CAAC;IAE3C,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,uCAAuC,CAAC,CAAC,QAAQ,CAAC,EAClF,MAAkB;QAElB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC1C,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;YAChC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,oDAAoD,EAAE;gBAClF,MAAM;aACP,CAAC,CAAC;QACL,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QAClD,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1C,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACnF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YACxB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,6DAA6D,EAAE;gBAC3F,MAAM;gBACN,MAAM,EAAE,QAAQ,CAAC,MAAM;aACxB,CAAC,CAAC;QACL,4EAA4E;QAC5E,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,SAAS,EACT,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CACrB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CACnB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC1B,MAAM,CAAC,OAAO,CAAC,uDAAuD,EAAE;YACtE,MAAM;YACN,UAAU;YACV,UAAU,EAAE,EAAE;YACd,QAAQ;SACT,CAAC,CACH,EACD,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CACf,0FAA0F,EAC1F,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAC/D,CACF,EACD,MAAM,CAAC,MAAM,CACd,EACH,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,6FAA6F;IAC7F,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAClC,QAAQ,EAAE,MAAM,CAAC,iBAAiB;QAClC,MAAM,EAAE,CAAC,MAAkB,EAAE,EAAE,CAC7B,eAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAC1B,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CACf,+FAA+F,EAC/F,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CACnC,CACF,EACD,MAAM,CAAC,MAAM,CACd;KACJ,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,MAAkB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAErE,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,EAChE,SAAoB,EACpB,MAAkB,EAClB,UAA0B,EAC1B,WAA4B,EAC5B,OAAmB,EACnB,OAAuB,EACvB,SAA4B;QAE5B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QACpC,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;QACvF,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChD,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE;YAClD,IAAI;YACJ,sBAAsB;YACtB,IAAI;YACJ,iBAAiB,CAAC,OAAO,CAAC;YAC1B,MAAM,CAAC,YAAY,CAAC;YACpB,MAAM,CAAC,WAAW,CAAC;SACpB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAqB,CAAC,CAAC;QACnE,2EAA2E;QAC3E,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAC9B,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CACpB,MAAM,CAAC,OAAO,CACZ,MAAM,CAAC,KAAK,CAAC;YACX,MAAM,EAAE,GAAG,EAAE,CACX,MAAM,CAAC,QAAQ,CAAC,iDAAiD,EAAE,MAAM,CAAC;YAC5E,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CACjB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CACnB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC1B,MAAM,CAAC,OAAO,CAAC,+CAA+C,EAAE;gBAC9D,GAAG,MAAM;gBACT,UAAU,EAAE,EAAE;gBACd,QAAQ;aACT,CAAC,CACH,EACD,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CACf,8FAA8F,EAC9F,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CACtD,CACF,EACD,MAAM,CAAC,MAAM,CACd;SACJ,CAAC,CACH,CACF,CACF,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,UAA4B,EAAE,EAAE,CAClD,IAAI,aAAa,CAAC;YAChB,MAAM;YACN,UAAU;YACV,UAAU,EAAE,IAAI,sBAAsB,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;YACnE,SAAS,EAAE,UAAU,CAAC,SAAS;SAChC,CAAC,CAAC;QAEL,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CACxD,QAAQ,CAAC,EAAE,UAA4B;YACrC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;gBAC1C,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;gBAClD,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;aAC5D,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CACb,CAAC,KAAK,EAAE,EAAE,CACR,IAAI,0BAA0B,CAAC;gBAC7B,UAAU;gBACV,MAAM,EAAE,aAAa;gBACrB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK;aACN,CAAC,CACL,CACF,CAAC;YACF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YAChF,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;YACxE,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;gBACpB,CAAC,CAAC,6CAA6C;gBAC/C,CAAC,CAAC,iDAAiD,EACrD;gBACE,GAAG,MAAM;gBACT,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE;gBAChC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC;aAC3D,CACF,CAAC;YACF,OAAO,MAAM,CAAC,WAAW,CAAC;QAC5B,CAAC;QACD,oFAAoF;QACpF,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EACnB,MAAM,CAAC,eAAe,CACvB,CAAC;QAEF,4FAA4F;QAC5F,qCAAqC;QACrC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,+BAA+B,CAAC,CACxD,QAAQ,CAAC;YACP,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;gBAAE,OAAO;YACnC,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;YACzC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;YACtD,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;YAC/C,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,mDAAmD,EAAE;gBAC1E,GAAG,MAAM;gBACT,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC,EACD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EACnB,MAAM,CAAC,eAAe,CACvB,CAAC;QAEF,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAC3C,QAAQ,CAAC,KAAK,EACd,UAAU,EACV,SAAS,EACT,WAAW,EACX,OAAO,CACR,CAAC;QACF,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC;QACzC,yFAAyF;QACzF,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CACjC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EACzB,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,UAAU,CACf,uEAAuE,EACvE;YACE,GAAG,MAAM;YACT,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CACF,CACF,EACD,MAAM,CAAC,MAAM,CACd,CACF,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1B,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC;YAC5C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,YAAY,EAAE,QAAQ,CAAC,YAAY;YACnC,iBAAiB,EAAE,iBAAiB,CAAC,OAAO,CAAC;YAC7C,WAAW;SACZ,CAAC,CAAC;QACH,OAAO;YACL,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;YACxC,WAAW,EAAE,QAAQ;YACrB,cAAc,EAAE,QAAQ;YACxB,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE;YAC7B,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC;SACvE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC,CAAC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { RepositoryName } from "@usine/core/repository";
2
+ import type { GatewayDomain, GatewayLlmProvider } from "@usine/core/worker";
3
+ import { type CallerToken } from "@usine/gateway/admin";
4
+ import { Redacted } from "effect";
5
+ /** The variables sent through the SSH connection because they contain the caller token. The Worker's sshd must accept each in `AcceptEnv`. */
6
+ export declare const GATEWAY_SENT_VARIABLES: readonly ["GIT_CONFIG_VALUE_0", "GH_ENTERPRISE_TOKEN", "GH_TOKEN", "ANTHROPIC_AUTH_TOKEN"];
7
+ /** Returns the Gateway's forward proxy URL from a Worker; children receive it as `HTTPS_PROXY`. */
8
+ export declare const forwardProxyUrl: (domain: GatewayDomain) => string;
9
+ /** Returns the URL a Worker behind the Gateway clones and fetches `repository` from. */
10
+ export declare const gatewayRepositoryUrl: (domain: GatewayDomain, repository: RepositoryName) => string;
11
+ /**
12
+ * Returns gh's configuration files for the Gateway at `domain`. Neither file contains a token;
13
+ * gh reads the caller token from `GH_ENTERPRISE_TOKEN` and `GH_TOKEN`.
14
+ */
15
+ export declare const ghGatewayConfig: (domain: GatewayDomain) => {
16
+ readonly "config.yml": "version: \"1\"\nhttp_unix_socket: /run/usine-gateway/http.sock\n";
17
+ readonly "hosts.yml": `git.${string & import("effect/Brand").Brand<"GatewayDomain">}:
18
+ git_protocol: https
19
+ `;
20
+ };
21
+ export interface GatewayEnvironmentOptions {
22
+ readonly domain: GatewayDomain;
23
+ readonly llmProviders: ReadonlyArray<GatewayLlmProvider>;
24
+ /** The machine directory that contains the `ghGatewayConfig` files. */
25
+ readonly ghConfigDirectory: string;
26
+ readonly callerToken: CallerToken;
27
+ }
28
+ /**
29
+ * An Attempt's environment behind a Gateway. `exported` has no secrets and goes in each command
30
+ * line; `sent` contains the caller token and goes only through the SSH connection.
31
+ */
32
+ export interface GatewayEnvironment {
33
+ readonly exported: Readonly<Record<string, string>>;
34
+ readonly sent: Readonly<Record<string, Redacted.Redacted<string>>>;
35
+ }
36
+ /**
37
+ * Returns the environment that points git, gh, package managers, and Claude Code at the
38
+ * Gateway at `domain`.
39
+ *
40
+ * - git sends the caller token in `x-usine-gateway-token` to `git.<domain>` only, and rewrites
41
+ * `https://github.com/` and `https://git.<domain>/` to the Gateway. The header value is
42
+ * config entry 0 (`GIT_CONFIG_VALUE_0`).
43
+ * - gh uses `git.<domain>` through the Gateway socket, with the caller token as both its
44
+ * enterprise and GitHub token, so absolute pagination links also authenticate.
45
+ * - Package managers use the forward proxy at `<domain>:3128`; local addresses and the
46
+ * Gateway's own names bypass it.
47
+ * - Claude Code calls `llm.<domain>/anthropic` with the caller token if the Gateway has the
48
+ * Anthropic credential. Otherwise, and for Codex, the harness uses its own login through the
49
+ * forward proxy, whose allowlist must include the login's hosts.
50
+ */
51
+ export declare const gatewayEnvironment: (options: GatewayEnvironmentOptions) => GatewayEnvironment;
52
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../src/ssh/gateway/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAWlC,8IAA8I;AAC9I,eAAO,MAAM,sBAAsB,YACjC,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,sBAAsB,CACd,CAAC;AAEX,mGAAmG;AACnG,eAAO,MAAM,eAAe,WAAY,aAAa,KAAG,MACd,CAAC;AAE3C,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,WAAY,aAAa,cAAc,cAAc,KAAG,MAC/C,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,eAAe,WAAY,aAAa;aAEjD,YAAY;aACZ,WAAW;;;CACF,CAAC;AAEd,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACzD,uEAAuE;IACvE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CACpE;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,YAAa,yBAAyB,KAAG,kBAgCvE,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { GATEWAY_TOKEN_HEADER } from "@usine/gateway/admin";
2
+ import { Redacted } from "effect";
3
+ /**
4
+ * The Unix socket that systemd forwards to the Gateway's port 80
5
+ * (`infra/hetzner/gateway/worker-cloud-init.yaml`). gh sends plain HTTP over it, and only HTTPS
6
+ * to `GH_HOST` directly.
7
+ */
8
+ const GH_GATEWAY_SOCKET = "/run/usine-gateway/http.sock";
9
+ const FORWARD_PROXY_PORT = 3128;
10
+ /** The variables sent through the SSH connection because they contain the caller token. The Worker's sshd must accept each in `AcceptEnv`. */
11
+ export const GATEWAY_SENT_VARIABLES = [
12
+ "GIT_CONFIG_VALUE_0",
13
+ "GH_ENTERPRISE_TOKEN",
14
+ "GH_TOKEN",
15
+ "ANTHROPIC_AUTH_TOKEN",
16
+ ];
17
+ /** Returns the Gateway's forward proxy URL from a Worker; children receive it as `HTTPS_PROXY`. */
18
+ export const forwardProxyUrl = (domain) => `http://${domain}:${FORWARD_PROXY_PORT}`;
19
+ /** Returns the URL a Worker behind the Gateway clones and fetches `repository` from. */
20
+ export const gatewayRepositoryUrl = (domain, repository) => `http://git.${domain}/${repository}.git`;
21
+ /**
22
+ * Returns gh's configuration files for the Gateway at `domain`. Neither file contains a token;
23
+ * gh reads the caller token from `GH_ENTERPRISE_TOKEN` and `GH_TOKEN`.
24
+ */
25
+ export const ghGatewayConfig = (domain) => ({
26
+ "config.yml": `version: "1"\nhttp_unix_socket: ${GH_GATEWAY_SOCKET}\n`,
27
+ "hosts.yml": `git.${domain}:\n git_protocol: https\n`,
28
+ });
29
+ /**
30
+ * Returns the environment that points git, gh, package managers, and Claude Code at the
31
+ * Gateway at `domain`.
32
+ *
33
+ * - git sends the caller token in `x-usine-gateway-token` to `git.<domain>` only, and rewrites
34
+ * `https://github.com/` and `https://git.<domain>/` to the Gateway. The header value is
35
+ * config entry 0 (`GIT_CONFIG_VALUE_0`).
36
+ * - gh uses `git.<domain>` through the Gateway socket, with the caller token as both its
37
+ * enterprise and GitHub token, so absolute pagination links also authenticate.
38
+ * - Package managers use the forward proxy at `<domain>:3128`; local addresses and the
39
+ * Gateway's own names bypass it.
40
+ * - Claude Code calls `llm.<domain>/anthropic` with the caller token if the Gateway has the
41
+ * Anthropic credential. Otherwise, and for Codex, the harness uses its own login through the
42
+ * forward proxy, whose allowlist must include the login's hosts.
43
+ */
44
+ export const gatewayEnvironment = (options) => {
45
+ const { domain, callerToken } = options;
46
+ const gitBase = `http://git.${domain}/`;
47
+ const proxy = forwardProxyUrl(domain);
48
+ const direct = `localhost,127.0.0.1,::1,${domain}`;
49
+ const exported = {
50
+ GIT_CONFIG_COUNT: "3",
51
+ GIT_CONFIG_KEY_0: `http.${gitBase}.extraHeader`,
52
+ GIT_CONFIG_KEY_1: `url.${gitBase}.insteadOf`,
53
+ GIT_CONFIG_VALUE_1: "https://github.com/",
54
+ GIT_CONFIG_KEY_2: `url.${gitBase}.insteadOf`,
55
+ GIT_CONFIG_VALUE_2: `https://git.${domain}/`,
56
+ GH_HOST: `git.${domain}`,
57
+ GH_CONFIG_DIR: options.ghConfigDirectory,
58
+ GH_PROMPT_DISABLED: "1",
59
+ HTTPS_PROXY: proxy,
60
+ HTTP_PROXY: proxy,
61
+ https_proxy: proxy,
62
+ http_proxy: proxy,
63
+ NO_PROXY: direct,
64
+ no_proxy: direct,
65
+ };
66
+ const sent = {
67
+ GIT_CONFIG_VALUE_0: Redacted.make(`${GATEWAY_TOKEN_HEADER}: ${Redacted.value(callerToken)}`),
68
+ GH_ENTERPRISE_TOKEN: callerToken,
69
+ GH_TOKEN: callerToken,
70
+ };
71
+ if (!options.llmProviders.includes("anthropic"))
72
+ return { exported, sent };
73
+ return {
74
+ exported: { ...exported, ANTHROPIC_BASE_URL: `http://llm.${domain}/anthropic` },
75
+ sent: { ...sent, ANTHROPIC_AUTH_TOKEN: callerToken },
76
+ };
77
+ };
78
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../../src/ssh/gateway/environment.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,8BAA8B,CAAC;AAEzD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,8IAA8I;AAC9I,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,oBAAoB;IACpB,qBAAqB;IACrB,UAAU;IACV,sBAAsB;CACd,CAAC;AAEX,mGAAmG;AACnG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAqB,EAAU,EAAE,CAC/D,UAAU,MAAM,IAAI,kBAAkB,EAAE,CAAC;AAE3C,wFAAwF;AACxF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAqB,EAAE,UAA0B,EAAU,EAAE,CAChG,cAAc,MAAM,IAAI,UAAU,MAAM,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAqB,EAAE,EAAE,CACvD,CAAC;IACC,YAAY,EAAE,mCAAmC,iBAAiB,IAAI;IACtE,WAAW,EAAE,OAAO,MAAM,8BAA8B;CACzD,CAAU,CAAC;AAmBd;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAkC,EAAsB,EAAE;IAC3F,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IACxC,MAAM,OAAO,GAAG,cAAc,MAAM,GAAG,CAAC;IACxC,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,2BAA2B,MAAM,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG;QACf,gBAAgB,EAAE,GAAG;QACrB,gBAAgB,EAAE,QAAQ,OAAO,cAAc;QAC/C,gBAAgB,EAAE,OAAO,OAAO,YAAY;QAC5C,kBAAkB,EAAE,qBAAqB;QACzC,gBAAgB,EAAE,OAAO,OAAO,YAAY;QAC5C,kBAAkB,EAAE,eAAe,MAAM,GAAG;QAC5C,OAAO,EAAE,OAAO,MAAM,EAAE;QACxB,aAAa,EAAE,OAAO,CAAC,iBAAiB;QACxC,kBAAkB,EAAE,GAAG;QACvB,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,MAAM,IAAI,GAAG;QACX,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,oBAAoB,KAAK,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5F,mBAAmB,EAAE,WAAW;QAChC,QAAQ,EAAE,WAAW;KACtB,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC3E,OAAO;QACL,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,kBAAkB,EAAE,cAAc,MAAM,YAAY,EAAE;QAC/E,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,oBAAoB,EAAE,WAAW,EAAE;KACrD,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { RemoteShell } from "@usine/agents/child-host";
2
+ import { SshDestination } from "@usine/core/worker";
3
+ import { DateTime, Effect, Schema, Stream } from "effect";
4
+ import { ChildProcess, type ChildProcessSpawner } from "effect/unstable/process";
5
+ export interface OpenForward {
6
+ /** The SSH client number, starting at 1. `reopen` replaces only this generation. */
7
+ readonly generation: number;
8
+ readonly url: URL;
9
+ }
10
+ declare const GatewayForwardClosed_base: Schema.Class<GatewayForwardClosed, Schema.TaggedStruct<"GatewayForwardClosed", {
11
+ readonly gateway: Schema.brand<Schema.String, "SshDestination">;
12
+ readonly generation: Schema.Int;
13
+ readonly since: Schema.DateTimeUtc;
14
+ readonly reason: Schema.NonEmptyString;
15
+ }>, import("effect/Cause").YieldableError>;
16
+ /**
17
+ * The error for a closed admin API forward, whose SSH client didn't open or exited. `since` is
18
+ * when the Gateway became unreachable, and `reason` is the SSH client's error.
19
+ */
20
+ export declare class GatewayForwardClosed extends GatewayForwardClosed_base {
21
+ }
22
+ /**
23
+ * An SSH forward from a local port to a Gateway's admin API (ADR 0027, amendment of
24
+ * 2026-10-19). It opens with the first Worker behind the Gateway, reopens after a pause when
25
+ * its client exits, and closes with the last Worker or the executor.
26
+ */
27
+ export interface GatewayForward {
28
+ /** The Gateway's SSH destination, used to identify it in logs and messages. */
29
+ readonly gateway: SshDestination;
30
+ /** The SSH command an operator can run to open the same forward manually. */
31
+ readonly command: string;
32
+ /** Returns the open forward, waiting while a client is opening. Fails immediately while the forward is closed. */
33
+ readonly current: Effect.Effect<OpenForward, GatewayForwardClosed>;
34
+ /**
35
+ * Replaces SSH client `generation`, or ends the pause after it closed, and waits for the next
36
+ * client. If another request already replaced it, waits for the current forward.
37
+ */
38
+ readonly reopen: (generation: number) => Effect.Effect<OpenForward, GatewayForwardClosed>;
39
+ /** Records an unanswered request sent at `sentAt`, and returns when the first unanswered request since the last response was sent. */
40
+ readonly unanswered: (sentAt: DateTime.Utc) => Effect.Effect<DateTime.Utc>;
41
+ /** Records a response from the admin API, so the next unanswered request starts a new outage. */
42
+ readonly answered: Effect.Effect<void>;
43
+ }
44
+ /**
45
+ * Opens a forward to the admin API at `adminPort` on `gateway`, using the SSH client and
46
+ * environment of `shell`, and keeps it open until the caller's scope closes. Each client
47
+ * listens on a kernel-picked port of 127.0.0.1, so it never conflicts with an operator's
48
+ * forward.
49
+ */
50
+ export declare const gatewayForwardFor: (spawner: {
51
+ spawn(command: ChildProcess.Command): Effect.Effect<ChildProcessSpawner.ChildProcessHandle, import("effect/PlatformError").PlatformError, import("effect/Scope").Scope>;
52
+ exitCode(command: ChildProcess.Command): Effect.Effect<ChildProcessSpawner.ExitCode, import("effect/PlatformError").PlatformError>;
53
+ streamString(command: ChildProcess.Command, options?: {
54
+ readonly includeStderr?: boolean | undefined;
55
+ }): Stream.Stream<string, import("effect/PlatformError").PlatformError>;
56
+ streamLines(command: ChildProcess.Command, options?: {
57
+ readonly includeStderr?: boolean | undefined;
58
+ }): Stream.Stream<string, import("effect/PlatformError").PlatformError>;
59
+ lines(command: ChildProcess.Command, options?: {
60
+ readonly includeStderr?: boolean | undefined;
61
+ }): Effect.Effect<Array<string>, import("effect/PlatformError").PlatformError>;
62
+ string(command: ChildProcess.Command, options?: {
63
+ readonly includeStderr?: boolean | undefined;
64
+ }): Effect.Effect<string, import("effect/PlatformError").PlatformError>;
65
+ }, shell: Pick<RemoteShell, "ssh" | "sshEnvironment">, gateway: string & import("effect/Brand").Brand<"SshDestination">, adminPort: number & import("effect/Brand").Brand<"GatewayAdminPort">) => Effect.Effect<{
66
+ gateway: string & import("effect/Brand").Brand<"SshDestination">;
67
+ command: string;
68
+ current: Effect.Effect<OpenForward, GatewayForwardClosed, never>;
69
+ reopen: (generation: number) => Effect.Effect<OpenForward, GatewayForwardClosed, never>;
70
+ unanswered: (sentAt: DateTime.Utc) => Effect.Effect<DateTime.Utc, never, never>;
71
+ answered: Effect.Effect<void, never, never>;
72
+ }, never, import("effect/Scope").Scope>;
73
+ export {};
74
+ //# sourceMappingURL=forward.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward.d.ts","sourceRoot":"","sources":["../../../src/ssh/gateway/forward.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAyB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAY,MAAM,EAA8B,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAcjF,MAAM,WAAW,WAAW;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;CACnB;;;;;;;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,yBAOxC;CAAG;AAEL;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IACnE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IAC1F,sIAAsI;IACtI,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3E,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACxC;AA6DD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;yBAyQA,QAAQ,CAAC,GAAG;;uCAWxC,CAAC"}
@@ -0,0 +1,247 @@
1
+ import { createServer } from "node:net";
2
+ import { SshDestination } from "@usine/core/worker";
3
+ import { DateTime, Deferred, Effect, Fiber, Option, Ref, Result, Schema, Stream } from "effect";
4
+ import { ChildProcess } from "effect/unstable/process";
5
+ /** The line the SSH client prints through `LocalCommand` when its local port is listening. */
6
+ const OPEN_LINE = "usine-gateway-forward-open";
7
+ /** The time an SSH client has to connect and listen before it's replaced. */
8
+ const OPEN_TIMEOUT = "30 seconds";
9
+ /** The time a request waits for the forward to open. */
10
+ const OPEN_WAIT = "1 minute";
11
+ /** The maximum pause between SSH clients, in milliseconds. The pause doubles from one second after each failure. */
12
+ const MAX_PAUSE_MILLIS = 60_000;
13
+ /**
14
+ * The error for a closed admin API forward, whose SSH client didn't open or exited. `since` is
15
+ * when the Gateway became unreachable, and `reason` is the SSH client's error.
16
+ */
17
+ export class GatewayForwardClosed extends Schema.TaggedError("@usine/executor/GatewayForwardClosed")("GatewayForwardClosed", {
18
+ gateway: SshDestination,
19
+ generation: Schema.Int,
20
+ since: Schema.DateTimeUtc,
21
+ reason: Schema.NonEmptyString,
22
+ }) {
23
+ }
24
+ const notOpened = (reason) => ({ _tag: "NotOpened", reason });
25
+ const exited = (reason) => ({ _tag: "Exited", reason });
26
+ const REPLACED = { _tag: "Replaced" };
27
+ const ListenerAddress = Schema.Struct({ port: Schema.Int });
28
+ /** Returns a free port on 127.0.0.1 picked by the kernel, released for the SSH client to listen on. */
29
+ const freeLocalPort = Effect.callback((resume) => {
30
+ const server = createServer();
31
+ server.once("error", (cause) => resume(Effect.fail(cause)));
32
+ server.listen(0, "127.0.0.1", () => {
33
+ const address = Schema.decodeUnknownOption(ListenerAddress)(server.address());
34
+ server.close(() => resume(Option.match(address, {
35
+ onNone: () => Effect.fail(new Error("the listener reported no port")),
36
+ onSome: ({ port }) => Effect.succeed(port),
37
+ })));
38
+ });
39
+ });
40
+ /** Returns the SSH client's stderr on one line, or its exit code if stderr is empty. */
41
+ const complaint = (stderr, exitCode) => {
42
+ const lines = stderr
43
+ .split("\n")
44
+ .map((line) => line.trim())
45
+ .filter((line) => line !== "");
46
+ return lines.length > 0 ? lines.join("; ") : `ssh exited with code ${String(exitCode)}`;
47
+ };
48
+ const pauseAfter = (failures) => Math.min(1000 * 2 ** Math.max(failures - 1, 0), MAX_PAUSE_MILLIS);
49
+ /**
50
+ * Opens a forward to the admin API at `adminPort` on `gateway`, using the SSH client and
51
+ * environment of `shell`, and keeps it open until the caller's scope closes. Each client
52
+ * listens on a kernel-picked port of 127.0.0.1, so it never conflicts with an operator's
53
+ * forward.
54
+ */
55
+ export const gatewayForwardFor = Effect.fn("SshExecutor.gatewayForwardFor")(function* (spawner, shell, gateway, adminPort) {
56
+ const fields = { gateway, adminPort };
57
+ yield* Effect.annotateCurrentSpan(fields);
58
+ const forwardSpec = (port) => `127.0.0.1:${String(port)}:127.0.0.1:${String(adminPort)}`;
59
+ const command = [
60
+ shell.ssh.command,
61
+ ...shell.ssh.args,
62
+ "-N",
63
+ "-o",
64
+ "ExitOnForwardFailure=yes",
65
+ "-L",
66
+ forwardSpec(adminPort),
67
+ gateway,
68
+ ].join(" ");
69
+ const argumentsFor = (port) => [
70
+ ...shell.ssh.args,
71
+ "-N",
72
+ // LocalCommand runs when all listeners are up, ExitOnForwardFailure exits if a listener fails, and ControlPath=none avoids the operator's shared connections.
73
+ "-o",
74
+ "ExitOnForwardFailure=yes",
75
+ "-o",
76
+ "ControlPath=none",
77
+ "-o",
78
+ "PermitLocalCommand=yes",
79
+ "-o",
80
+ `LocalCommand=echo ${OPEN_LINE}`,
81
+ "-L",
82
+ forwardSpec(port),
83
+ gateway,
84
+ ];
85
+ const generationNumbered = (number) => Effect.all({
86
+ opened: Deferred.make(),
87
+ replace: Deferred.make(),
88
+ next: Deferred.make(),
89
+ }).pipe(Effect.map((signals) => ({ number, ...signals })));
90
+ const first = yield* generationNumbered(1);
91
+ const state = yield* Ref.make({ _tag: "Opening", generation: first });
92
+ const runClient = Effect.fn("SshExecutor.runGatewayForward")(function* (generation, closedSince) {
93
+ yield* Effect.annotateCurrentSpan({ ...fields, generation: generation.number });
94
+ const picked = yield* Effect.result(freeLocalPort);
95
+ if (Result.isFailure(picked))
96
+ return notOpened(`no free port on 127.0.0.1: ${picked.failure.message}`);
97
+ const port = picked.success;
98
+ yield* Effect.annotateCurrentSpan({ port });
99
+ yield* Effect.logDebug("Starting an SSH client for the forward to the Gateway's admin API", {
100
+ ...fields,
101
+ generation: generation.number,
102
+ port,
103
+ });
104
+ return yield* Effect.scoped(Effect.gen(function* () {
105
+ const handle = yield* spawner.spawn(ChildProcess.make(shell.ssh.command, argumentsFor(port), {
106
+ env: { ...shell.sshEnvironment },
107
+ extendEnv: false,
108
+ detached: false,
109
+ forceKillAfter: "5 seconds",
110
+ stdin: "ignore",
111
+ }));
112
+ const stderr = yield* handle.stderr.pipe(Stream.decodeText(), Stream.mkString, Effect.forkScoped);
113
+ const reported = (exitCode) => Fiber.join(stderr).pipe(Effect.map((text) => complaint(text, exitCode)));
114
+ const listening = yield* handle.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.filter((line) => line.trim() === OPEN_LINE), Stream.runHead, Effect.timeoutOption(OPEN_TIMEOUT));
115
+ if (Option.isNone(listening))
116
+ return notOpened(`ssh didn't open the forward within ${OPEN_TIMEOUT}`);
117
+ if (Option.isNone(listening.value))
118
+ return notOpened(yield* reported(Number(yield* handle.exitCode)));
119
+ const open = {
120
+ generation: generation.number,
121
+ url: new URL(`http://127.0.0.1:${String(port)}`),
122
+ };
123
+ yield* Ref.set(state, { _tag: "Open", generation, open });
124
+ yield* Deferred.succeed(generation.opened, open);
125
+ yield* Option.match(closedSince, {
126
+ onNone: () => Effect.logInfo("Opened the forward to the Gateway's admin API", {
127
+ ...fields,
128
+ generation: generation.number,
129
+ port,
130
+ }),
131
+ onSome: (since) => Effect.logInfo("Reopened the forward to the Gateway's admin API", {
132
+ ...fields,
133
+ generation: generation.number,
134
+ port,
135
+ closedSince: DateTime.formatIso(since),
136
+ }),
137
+ });
138
+ // Sets the state to closed first, so no request uses a port the client no longer listens on.
139
+ const closedNow = (reason) => DateTime.now.pipe(Effect.flatMap((since) => Ref.set(state, {
140
+ _tag: "Closed",
141
+ generation,
142
+ closed: new GatewayForwardClosed({
143
+ gateway,
144
+ generation: generation.number,
145
+ since,
146
+ reason,
147
+ }),
148
+ })));
149
+ return yield* Effect.raceFirst(handle.exitCode.pipe(Effect.flatMap((code) => reported(Number(code))), Effect.catch((error) => Effect.succeed(`can't read the SSH client's exit code: ${error.message}`)), Effect.tap(closedNow), Effect.map(exited)), Deferred.await(generation.replace).pipe(Effect.andThen(closedNow("replaced after a request got no response")), Effect.as(REPLACED)));
150
+ })).pipe(Effect.catch((error) => Effect.succeed(notOpened(`can't run ${shell.ssh.command}: ${error.message}`))));
151
+ });
152
+ // Runs until the caller's scope closes, with one span per SSH client.
153
+ const supervise = Effect.gen(function* () {
154
+ let generation = first;
155
+ let failures = 0;
156
+ let closedSince = Option.none();
157
+ while (true) {
158
+ const end = yield* runClient(generation, closedSince);
159
+ const now = yield* DateTime.now;
160
+ if (end._tag === "Replaced") {
161
+ failures = 0;
162
+ closedSince = Option.some(now);
163
+ yield* Effect.logInfo("Replacing the forward to the Gateway's admin API, which a request found unanswered", { ...fields, generation: generation.number });
164
+ }
165
+ else {
166
+ failures = end._tag === "Exited" ? 1 : failures + 1;
167
+ const since = end._tag === "Exited" ? now : Option.getOrElse(closedSince, () => now);
168
+ closedSince = Option.some(since);
169
+ const pause = pauseAfter(failures);
170
+ const closed = new GatewayForwardClosed({
171
+ gateway,
172
+ generation: generation.number,
173
+ since,
174
+ reason: end.reason,
175
+ });
176
+ yield* Ref.set(state, { _tag: "Closed", generation, closed });
177
+ yield* Deferred.fail(generation.opened, closed);
178
+ yield* Effect.logWarning(end._tag === "Exited"
179
+ ? "The forward to the Gateway's admin API exited; reopening it after a pause"
180
+ : "Could not open the forward to the Gateway's admin API; trying again after a pause", {
181
+ ...fields,
182
+ generation: generation.number,
183
+ closedSince: DateTime.formatIso(since),
184
+ failures,
185
+ pauseSeconds: pause / 1000,
186
+ reason: end.reason,
187
+ });
188
+ const trigger = yield* Effect.raceFirst(Effect.sleep(pause).pipe(Effect.as("pause elapsed")), Deferred.await(generation.replace).pipe(Effect.as("request")));
189
+ yield* Effect.logInfo("Reopening the forward to the Gateway's admin API", {
190
+ ...fields,
191
+ generation: generation.number + 1,
192
+ closedSince: DateTime.formatIso(since),
193
+ trigger,
194
+ });
195
+ }
196
+ const next = yield* generationNumbered(generation.number + 1);
197
+ yield* Ref.set(state, { _tag: "Opening", generation: next });
198
+ yield* Deferred.succeed(generation.next, next);
199
+ generation = next;
200
+ }
201
+ });
202
+ yield* supervise.pipe(Effect.onInterrupt(() => Effect.logInfo("Closed the forward to the Gateway's admin API", fields)), Effect.forkScoped);
203
+ const notOpenedWithin = (generation) => DateTime.now.pipe(Effect.flatMap((since) => new GatewayForwardClosed({
204
+ gateway,
205
+ generation,
206
+ since,
207
+ reason: `the forward didn't open within ${OPEN_WAIT}`,
208
+ })));
209
+ const current = Effect.gen(function* () {
210
+ const now = yield* Ref.get(state);
211
+ switch (now._tag) {
212
+ case "Open":
213
+ return now.open;
214
+ case "Closed":
215
+ return yield* now.closed;
216
+ case "Opening":
217
+ return yield* Deferred.await(now.generation.opened).pipe(Effect.timeoutOrElse({
218
+ duration: OPEN_WAIT,
219
+ orElse: () => notOpenedWithin(now.generation.number),
220
+ }));
221
+ }
222
+ });
223
+ const reopen = Effect.fn("SshExecutor.reopenGatewayForward")(function* (generation) {
224
+ yield* Effect.annotateCurrentSpan({ ...fields, generation });
225
+ const now = yield* Ref.get(state);
226
+ if (now.generation.number !== generation) {
227
+ yield* Effect.logDebug("Another request replaced the forward to the Gateway's admin API already", { ...fields, generation, current: now.generation.number });
228
+ return yield* current;
229
+ }
230
+ yield* Deferred.succeed(now.generation.replace, undefined);
231
+ return yield* Deferred.await(now.generation.next).pipe(Effect.flatMap((next) => Deferred.await(next.opened)), Effect.timeoutOrElse({
232
+ duration: OPEN_WAIT,
233
+ orElse: () => notOpenedWithin(generation + 1),
234
+ }));
235
+ });
236
+ const silentSince = yield* Ref.make(Option.none());
237
+ const unanswered = (sentAt) => Ref.modify(silentSince, (since) => {
238
+ const first = Option.match(since, {
239
+ onNone: () => sentAt,
240
+ onSome: (earlier) => DateTime.min(earlier, sentAt),
241
+ });
242
+ return [first, Option.some(first)];
243
+ });
244
+ const answered = Ref.set(silentSince, Option.none());
245
+ return { gateway, command, current, reopen, unanswered, answered };
246
+ });
247
+ //# sourceMappingURL=forward.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forward.js","sourceRoot":"","sources":["../../../src/ssh/gateway/forward.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Harness } from "@usine/core/agent/brain";
2
+ import type { GatewayCredentialKind } from "@usine/core/worker";
3
+ import { Effect, Option } from "effect";
4
+ import { ExecutorOperationError, WorkerCapabilityError } from "../../executor.ts";
5
+ import type { HarnessProbe } from "../../harness-preflight.ts";
6
+ import { type RemoteCommands } from "../../remote/commands.ts";
7
+ import type { MachineGateway, SshMachine } from "../model.ts";
8
+ /**
9
+ * Returns the credential kind the Gateway injects for `harness`, as recorded by the last
10
+ * preflight. Only Claude Code uses a Gateway credential; Codex and Pi use their own logins.
11
+ */
12
+ export declare const gatewayCredentialFor: (gateway: MachineGateway, harness: Harness) => Effect.Effect<Option.Option<GatewayCredentialKind>>;
13
+ /**
14
+ * Verifies the Gateway in front of an SSH Worker without attaching anything: the admin API
15
+ * forward opens and accepts the admin token, the machine's sshd accepts the caller-token
16
+ * variables, and the machine can connect to `git.<domain>`, which rejects a request without a caller
17
+ * token. If the Gateway has the Anthropic credential, records its kind for the Worker.
18
+ */
19
+ export declare const verifyGateway: (commands: RemoteCommands, worker: string & import("effect/Brand").Brand<"WorkerName">, machine: SshMachine, gateway: MachineGateway) => Effect.Effect<undefined, ExecutorOperationError | WorkerCapabilityError, never>;
20
+ /**
21
+ * Probes a brain on a Worker behind a Gateway (ADR 0027). If the Gateway has the Anthropic
22
+ * credential, checks only the Claude Code binary. Otherwise, Claude Code and Codex use the
23
+ * operator's login (ADR 0026): `probe` checks the login, then the machine must connect to the
24
+ * login's hosts through the forward proxy. Pi goes to `probe`, which rejects it on any remote
25
+ * machine.
26
+ */
27
+ export declare const gatewayHarnessProbe: (commands: RemoteCommands, machine: SshMachine, gateway: MachineGateway, probe: HarnessProbe) => HarnessProbe;
28
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../../src/ssh/gateway/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElE,OAAO,KAAK,EAAE,qBAAqB,EAAc,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAiB,MAAM,QAAQ,CAAC;AAEvD,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAwF9D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,YACtB,cAAc,WACd,OAAO,KACf,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAQpD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,0NAgFxB,CAAC;AAmCH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,aACpB,cAAc,WACf,UAAU,WACV,cAAc,SAChB,YAAY,KAClB,YA2FF,CAAC"}