@usine/executor 0.2.1 → 0.4.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 (250) hide show
  1. package/LICENSE +661 -21
  2. package/README.md +212 -37
  3. package/dist/child-command.d.ts +5 -8
  4. package/dist/child-command.d.ts.map +1 -1
  5. package/dist/child-command.js +10 -14
  6. package/dist/child-command.js.map +1 -1
  7. package/dist/child-environment.d.ts +19 -0
  8. package/dist/child-environment.d.ts.map +1 -0
  9. package/dist/child-environment.js +18 -0
  10. package/dist/child-environment.js.map +1 -0
  11. package/dist/claude-login-lock.d.ts +9 -0
  12. package/dist/claude-login-lock.d.ts.map +1 -0
  13. package/dist/claude-login-lock.js +15 -0
  14. package/dist/claude-login-lock.js.map +1 -0
  15. package/dist/cloudflare/client.d.ts +50 -0
  16. package/dist/cloudflare/client.d.ts.map +1 -0
  17. package/dist/cloudflare/client.js +108 -0
  18. package/dist/cloudflare/client.js.map +1 -0
  19. package/dist/cloudflare/cloudflare.d.ts +17 -0
  20. package/dist/cloudflare/cloudflare.d.ts.map +1 -0
  21. package/dist/cloudflare/cloudflare.js +704 -0
  22. package/dist/cloudflare/cloudflare.js.map +1 -0
  23. package/dist/cloudflare/model.d.ts +42 -0
  24. package/dist/cloudflare/model.d.ts.map +1 -0
  25. package/dist/cloudflare/model.js +2 -0
  26. package/dist/cloudflare/model.js.map +1 -0
  27. package/dist/cloudflare/shell/environment.d.ts +12 -0
  28. package/dist/cloudflare/shell/environment.d.ts.map +1 -0
  29. package/dist/cloudflare/shell/environment.js +12 -0
  30. package/dist/cloudflare/shell/environment.js.map +1 -0
  31. package/dist/cloudflare/shell/shell.d.ts +2 -0
  32. package/dist/cloudflare/shell/shell.d.ts.map +1 -0
  33. package/dist/cloudflare/shell/shell.js +155 -0
  34. package/dist/cloudflare/shell/shell.js.map +1 -0
  35. package/dist/credential-environment.d.ts +20 -0
  36. package/dist/credential-environment.d.ts.map +1 -0
  37. package/dist/credential-environment.js +20 -0
  38. package/dist/credential-environment.js.map +1 -0
  39. package/dist/durable-session.d.ts +81 -0
  40. package/dist/durable-session.d.ts.map +1 -0
  41. package/dist/durable-session.js +550 -0
  42. package/dist/durable-session.js.map +1 -0
  43. package/dist/exe-dev/commands.d.ts +23 -13
  44. package/dist/exe-dev/commands.d.ts.map +1 -1
  45. package/dist/exe-dev/commands.js +11 -57
  46. package/dist/exe-dev/commands.js.map +1 -1
  47. package/dist/exe-dev/exe-dev.d.ts +9 -3
  48. package/dist/exe-dev/exe-dev.d.ts.map +1 -1
  49. package/dist/exe-dev/exe-dev.js +61 -128
  50. package/dist/exe-dev/exe-dev.js.map +1 -1
  51. package/dist/exe-dev/grants.d.ts.map +1 -1
  52. package/dist/exe-dev/grants.js +35 -15
  53. package/dist/exe-dev/grants.js.map +1 -1
  54. package/dist/exe-dev/model.d.ts +15 -19
  55. package/dist/exe-dev/model.d.ts.map +1 -1
  56. package/dist/exe-dev/model.js +9 -12
  57. package/dist/exe-dev/model.js.map +1 -1
  58. package/dist/exe-dev/preflight.d.ts +8 -4
  59. package/dist/exe-dev/preflight.d.ts.map +1 -1
  60. package/dist/exe-dev/preflight.js +26 -35
  61. package/dist/exe-dev/preflight.js.map +1 -1
  62. package/dist/executor.d.ts +292 -44
  63. package/dist/executor.d.ts.map +1 -1
  64. package/dist/executor.js +187 -19
  65. package/dist/executor.js.map +1 -1
  66. package/dist/guard.d.ts +57 -7
  67. package/dist/guard.d.ts.map +1 -1
  68. package/dist/guard.js +274 -59
  69. package/dist/guard.js.map +1 -1
  70. package/dist/harness-preflight.d.ts +27 -5
  71. package/dist/harness-preflight.d.ts.map +1 -1
  72. package/dist/harness-preflight.js +32 -31
  73. package/dist/harness-preflight.js.map +1 -1
  74. package/dist/keyed-lock.d.ts +2 -3
  75. package/dist/keyed-lock.d.ts.map +1 -1
  76. package/dist/keyed-lock.js +2 -3
  77. package/dist/keyed-lock.js.map +1 -1
  78. package/dist/leftovers.d.ts +9 -0
  79. package/dist/leftovers.d.ts.map +1 -0
  80. package/dist/leftovers.js +14 -0
  81. package/dist/leftovers.js.map +1 -0
  82. package/dist/local/credentials.d.ts +21 -0
  83. package/dist/local/credentials.d.ts.map +1 -0
  84. package/dist/local/credentials.js +39 -0
  85. package/dist/local/credentials.js.map +1 -0
  86. package/dist/local/leftovers.d.ts +8 -0
  87. package/dist/local/leftovers.d.ts.map +1 -0
  88. package/dist/local/leftovers.js +23 -0
  89. package/dist/local/leftovers.js.map +1 -0
  90. package/dist/local/local.d.ts +17 -11
  91. package/dist/local/local.d.ts.map +1 -1
  92. package/dist/local/local.js +205 -132
  93. package/dist/local/local.js.map +1 -1
  94. package/dist/memory-preflight.d.ts +27 -0
  95. package/dist/memory-preflight.d.ts.map +1 -0
  96. package/dist/memory-preflight.js +83 -0
  97. package/dist/memory-preflight.js.map +1 -0
  98. package/dist/pre-push-hook.d.ts +20 -0
  99. package/dist/pre-push-hook.d.ts.map +1 -0
  100. package/dist/pre-push-hook.js +33 -0
  101. package/dist/pre-push-hook.js.map +1 -0
  102. package/dist/prepared-attempt.d.ts +41 -3
  103. package/dist/prepared-attempt.d.ts.map +1 -1
  104. package/dist/prepared-attempt.js +109 -31
  105. package/dist/prepared-attempt.js.map +1 -1
  106. package/dist/provision.d.ts +129 -15
  107. package/dist/provision.d.ts.map +1 -1
  108. package/dist/provision.js +428 -69
  109. package/dist/provision.js.map +1 -1
  110. package/dist/remote/commands.d.ts +51 -0
  111. package/dist/remote/commands.d.ts.map +1 -0
  112. package/dist/remote/commands.js +94 -0
  113. package/dist/remote/commands.js.map +1 -0
  114. package/dist/remote/container.d.ts +90 -0
  115. package/dist/remote/container.d.ts.map +1 -0
  116. package/dist/remote/container.js +480 -0
  117. package/dist/remote/container.js.map +1 -0
  118. package/dist/remote/leftovers.d.ts +14 -0
  119. package/dist/remote/leftovers.d.ts.map +1 -0
  120. package/dist/remote/leftovers.js +22 -0
  121. package/dist/remote/leftovers.js.map +1 -0
  122. package/dist/remote/liveness.d.ts +33 -0
  123. package/dist/remote/liveness.d.ts.map +1 -0
  124. package/dist/remote/liveness.js +196 -0
  125. package/dist/remote/liveness.js.map +1 -0
  126. package/dist/remote/machine.d.ts +110 -0
  127. package/dist/remote/machine.d.ts.map +1 -0
  128. package/dist/remote/machine.js +2 -0
  129. package/dist/remote/machine.js.map +1 -0
  130. package/dist/remote/remote.d.ts +28 -0
  131. package/dist/remote/remote.d.ts.map +1 -0
  132. package/dist/remote/remote.js +556 -0
  133. package/dist/remote/remote.js.map +1 -0
  134. package/dist/remote/sweep.d.ts +17 -0
  135. package/dist/remote/sweep.d.ts.map +1 -0
  136. package/dist/remote/sweep.js +117 -0
  137. package/dist/remote/sweep.js.map +1 -0
  138. package/dist/renewable-credential.d.ts +17 -0
  139. package/dist/renewable-credential.d.ts.map +1 -0
  140. package/dist/renewable-credential.js +58 -0
  141. package/dist/renewable-credential.js.map +1 -0
  142. package/dist/salvage.d.ts +38 -0
  143. package/dist/salvage.d.ts.map +1 -0
  144. package/dist/salvage.js +198 -0
  145. package/dist/salvage.js.map +1 -0
  146. package/dist/ssh/api-keys.d.ts +36 -0
  147. package/dist/ssh/api-keys.d.ts.map +1 -0
  148. package/dist/ssh/api-keys.js +72 -0
  149. package/dist/ssh/api-keys.js.map +1 -0
  150. package/dist/ssh/codex-homes.d.ts +21 -0
  151. package/dist/ssh/codex-homes.d.ts.map +1 -0
  152. package/dist/ssh/codex-homes.js +78 -0
  153. package/dist/ssh/codex-homes.js.map +1 -0
  154. package/dist/ssh/container.d.ts +32 -0
  155. package/dist/ssh/container.d.ts.map +1 -0
  156. package/dist/ssh/container.js +282 -0
  157. package/dist/ssh/container.js.map +1 -0
  158. package/dist/ssh/credentials.d.ts +43 -0
  159. package/dist/ssh/credentials.d.ts.map +1 -0
  160. package/dist/ssh/credentials.js +86 -0
  161. package/dist/ssh/credentials.js.map +1 -0
  162. package/dist/ssh/gateway/admin.d.ts +45 -0
  163. package/dist/ssh/gateway/admin.d.ts.map +1 -0
  164. package/dist/ssh/gateway/admin.js +129 -0
  165. package/dist/ssh/gateway/admin.js.map +1 -0
  166. package/dist/ssh/gateway/attachments.d.ts +31 -0
  167. package/dist/ssh/gateway/attachments.d.ts.map +1 -0
  168. package/dist/ssh/gateway/attachments.js +168 -0
  169. package/dist/ssh/gateway/attachments.js.map +1 -0
  170. package/dist/ssh/gateway/environment.d.ts +71 -0
  171. package/dist/ssh/gateway/environment.d.ts.map +1 -0
  172. package/dist/ssh/gateway/environment.js +148 -0
  173. package/dist/ssh/gateway/environment.js.map +1 -0
  174. package/dist/ssh/gateway/forward.d.ts +74 -0
  175. package/dist/ssh/gateway/forward.d.ts.map +1 -0
  176. package/dist/ssh/gateway/forward.js +247 -0
  177. package/dist/ssh/gateway/forward.js.map +1 -0
  178. package/dist/ssh/gateway/preflight.d.ts +67 -0
  179. package/dist/ssh/gateway/preflight.d.ts.map +1 -0
  180. package/dist/ssh/gateway/preflight.js +320 -0
  181. package/dist/ssh/gateway/preflight.js.map +1 -0
  182. package/dist/ssh/limits.d.ts +60 -0
  183. package/dist/ssh/limits.d.ts.map +1 -0
  184. package/dist/ssh/limits.js +84 -0
  185. package/dist/ssh/limits.js.map +1 -0
  186. package/dist/ssh/model.d.ts +153 -0
  187. package/dist/ssh/model.d.ts.map +1 -0
  188. package/dist/ssh/model.js +2 -0
  189. package/dist/ssh/model.js.map +1 -0
  190. package/dist/ssh/preflight.d.ts +35 -0
  191. package/dist/ssh/preflight.d.ts.map +1 -0
  192. package/dist/ssh/preflight.js +87 -0
  193. package/dist/ssh/preflight.js.map +1 -0
  194. package/dist/ssh/provisioner/boat.d.ts +33 -0
  195. package/dist/ssh/provisioner/boat.d.ts.map +1 -0
  196. package/dist/ssh/provisioner/boat.js +247 -0
  197. package/dist/ssh/provisioner/boat.js.map +1 -0
  198. package/dist/ssh/provisioner/hetzner.d.ts +32 -0
  199. package/dist/ssh/provisioner/hetzner.d.ts.map +1 -0
  200. package/dist/ssh/provisioner/hetzner.js +337 -0
  201. package/dist/ssh/provisioner/hetzner.js.map +1 -0
  202. package/dist/ssh/provisioner/host-key.d.ts +11 -0
  203. package/dist/ssh/provisioner/host-key.d.ts.map +1 -0
  204. package/dist/ssh/provisioner/host-key.js +57 -0
  205. package/dist/ssh/provisioner/host-key.js.map +1 -0
  206. package/dist/ssh/provisioner/http.d.ts +45 -0
  207. package/dist/ssh/provisioner/http.d.ts.map +1 -0
  208. package/dist/ssh/provisioner/http.js +72 -0
  209. package/dist/ssh/provisioner/http.js.map +1 -0
  210. package/dist/ssh/provisioner/machines.d.ts +48 -0
  211. package/dist/ssh/provisioner/machines.d.ts.map +1 -0
  212. package/dist/ssh/provisioner/machines.js +686 -0
  213. package/dist/ssh/provisioner/machines.js.map +1 -0
  214. package/dist/ssh/provisioner/model.d.ts +92 -0
  215. package/dist/ssh/provisioner/model.d.ts.map +1 -0
  216. package/dist/ssh/provisioner/model.js +37 -0
  217. package/dist/ssh/provisioner/model.js.map +1 -0
  218. package/dist/ssh/ssh.d.ts +23 -0
  219. package/dist/ssh/ssh.d.ts.map +1 -0
  220. package/dist/ssh/ssh.js +145 -0
  221. package/dist/ssh/ssh.js.map +1 -0
  222. package/dist/ssh/worker-records.d.ts +18 -0
  223. package/dist/ssh/worker-records.d.ts.map +1 -0
  224. package/dist/ssh/worker-records.js +100 -0
  225. package/dist/ssh/worker-records.js.map +1 -0
  226. package/dist/ssh/workers.d.ts +80 -0
  227. package/dist/ssh/workers.d.ts.map +1 -0
  228. package/dist/ssh/workers.js +247 -0
  229. package/dist/ssh/workers.js.map +1 -0
  230. package/package.json +25 -9
  231. package/dist/exe-dev/channel.d.ts +0 -12
  232. package/dist/exe-dev/channel.d.ts.map +0 -1
  233. package/dist/exe-dev/channel.js +0 -42
  234. package/dist/exe-dev/channel.js.map +0 -1
  235. package/dist/exe-dev/shell.d.ts +0 -12
  236. package/dist/exe-dev/shell.d.ts.map +0 -1
  237. package/dist/exe-dev/shell.js +0 -31
  238. package/dist/exe-dev/shell.js.map +0 -1
  239. package/dist/exe-dev/sweep.d.ts +0 -10
  240. package/dist/exe-dev/sweep.d.ts.map +0 -1
  241. package/dist/exe-dev/sweep.js +0 -117
  242. package/dist/exe-dev/sweep.js.map +0 -1
  243. package/dist/invalid-frame.d.ts +0 -17
  244. package/dist/invalid-frame.d.ts.map +0 -1
  245. package/dist/invalid-frame.js +0 -111
  246. package/dist/invalid-frame.js.map +0 -1
  247. package/dist/run-host-session.d.ts +0 -27
  248. package/dist/run-host-session.d.ts.map +0 -1
  249. package/dist/run-host-session.js +0 -303
  250. package/dist/run-host-session.js.map +0 -1
@@ -0,0 +1,196 @@
1
+ import { RemoteShell } from "@usine/agents/child-host";
2
+ import { WorkerResponsive, WorkerUnresponsive, } from "@usine/core/attempt/channel";
3
+ import { DateTime, Effect, Fiber, Match, Option, Ref, Semaphore } from "effect";
4
+ const PROBE_INTERVAL = "1 minute";
5
+ /** The SSH `ConnectTimeout` in seconds, covering the TCP connection, server banner, and key exchange. */
6
+ const CONNECT_TIMEOUT_SECONDS = 20;
7
+ /** The timeout for a whole probe, in seconds. A session that opens but never runs the command counts as unanswered. */
8
+ const PROBE_TIMEOUT_SECONDS = 45;
9
+ const reportTo = (notice, attemptIds) => attemptIds.length === 0 ? Option.none() : Option.some({ notice, attemptIds });
10
+ /**
11
+ * Returns the next liveness after a probe at `now`, with the notice for the `watching` Attempts.
12
+ * On the first unanswered probe, every Attempt not yet notified gets a "stopped responding"
13
+ * notice. When the Worker responds again, only notified Attempts get a "responding again"
14
+ * notice.
15
+ */
16
+ const observe = (worker, liveness, probe, now, watching) => {
17
+ if (probe._tag === "Answered")
18
+ return {
19
+ liveness: { _tag: "Answering", lastAnsweredAt: now },
20
+ report: liveness._tag === "Silent"
21
+ ? reportTo(new WorkerResponsive({ worker, lastAnsweredAt: liveness.lastAnsweredAt }), watching.filter((attemptId) => liveness.told.has(attemptId)))
22
+ : Option.none(),
23
+ };
24
+ const told = liveness._tag === "Silent" ? liveness.told : new Set();
25
+ return {
26
+ liveness: {
27
+ _tag: "Silent",
28
+ lastAnsweredAt: liveness.lastAnsweredAt,
29
+ unanswered: liveness._tag === "Silent" ? liveness.unanswered + 1 : 1,
30
+ reason: probe.reason,
31
+ told: new Set(watching),
32
+ },
33
+ report: reportTo(new WorkerUnresponsive({
34
+ worker,
35
+ lastAnsweredAt: liveness.lastAnsweredAt,
36
+ reason: probe.reason,
37
+ }), watching.filter((attemptId) => !told.has(attemptId))),
38
+ };
39
+ };
40
+ /**
41
+ * Returns the liveness after `attemptId` joins the watch. If the Worker is silent, an Attempt
42
+ * not yet notified gets a "stopped responding" notice with the last probe's failure.
43
+ */
44
+ const joinSilent = (worker, liveness, attemptId) => liveness._tag === "Answering" || liveness.told.has(attemptId)
45
+ ? { liveness, report: Option.none() }
46
+ : {
47
+ liveness: { ...liveness, told: new Set([...liveness.told, attemptId]) },
48
+ report: reportTo(new WorkerUnresponsive({
49
+ worker,
50
+ lastAnsweredAt: liveness.lastAnsweredAt,
51
+ reason: liveness.reason,
52
+ }), [attemptId]),
53
+ };
54
+ const lastLine = (text) => text
55
+ .split("\n")
56
+ .map((line) => line.trim())
57
+ .filter((line) => line !== "")
58
+ .at(-1) ?? "";
59
+ /**
60
+ * Probes one Worker every minute until interrupted, stores the result in `liveness`, and
61
+ * reports to the Attempts from `watchers`. Holds `lock` from reading `liveness` to the last
62
+ * report, so each Attempt gets its notices in order.
63
+ */
64
+ const watchWorker = (commands, worker, machineShell, lock, liveness, watchers) => Effect.gen(function* () {
65
+ const host = machineShell.destination;
66
+ const shell = new RemoteShell({
67
+ ssh: {
68
+ command: machineShell.ssh.command,
69
+ args: [...machineShell.ssh.args, "-o", `ConnectTimeout=${CONNECT_TIMEOUT_SECONDS}`],
70
+ },
71
+ sshEnvironment: machineShell.sshEnvironment,
72
+ destination: machineShell.destination,
73
+ });
74
+ const probe = commands.inspect("launch", shell, "true", []).pipe(Effect.timeoutOption(`${PROBE_TIMEOUT_SECONDS} seconds`), Effect.map(Option.match({
75
+ onNone: () => ({
76
+ _tag: "Unanswered",
77
+ reason: `No answer within ${PROBE_TIMEOUT_SECONDS} seconds`,
78
+ }),
79
+ onSome: (result) => result.exitCode === 0
80
+ ? { _tag: "Answered" }
81
+ : {
82
+ _tag: "Unanswered",
83
+ reason: [`ssh exited with code ${result.exitCode}`, lastLine(result.stderr)]
84
+ .filter((part) => part !== "")
85
+ .join(": "),
86
+ },
87
+ })), Effect.catch((error) => Effect.succeed({ _tag: "Unanswered", reason: error.message })));
88
+ const decide = (result) => Effect.gen(function* () {
89
+ const watching = watchers();
90
+ const attemptIds = watching.map(({ attemptId }) => attemptId);
91
+ const previous = yield* Ref.get(liveness);
92
+ const next = observe(worker, previous, result, yield* DateTime.now, attemptIds);
93
+ yield* Ref.set(liveness, next.liveness);
94
+ const fields = {
95
+ worker,
96
+ host,
97
+ attemptIds,
98
+ notifiedAttemptIds: Option.match(next.report, {
99
+ onNone: () => [],
100
+ onSome: ({ attemptIds }) => attemptIds,
101
+ }),
102
+ lastAnsweredAt: DateTime.formatIso(previous.lastAnsweredAt),
103
+ };
104
+ yield* Match.valueTags(result, {
105
+ Answered: () => previous._tag === "Silent"
106
+ ? Effect.logInfo("The Worker answers again", {
107
+ ...fields,
108
+ unansweredProbes: previous.unanswered,
109
+ })
110
+ : Effect.logDebug("The Worker answered its liveness probe", fields),
111
+ Unanswered: ({ reason }) => Effect.logWarning(previous._tag === "Silent"
112
+ ? "The Worker still does not answer"
113
+ : "The Worker stopped answering", {
114
+ ...fields,
115
+ unansweredProbes: previous._tag === "Silent" ? previous.unanswered + 1 : 1,
116
+ reason,
117
+ }),
118
+ });
119
+ if (Option.isSome(next.report)) {
120
+ const { notice, attemptIds: notified } = next.report.value;
121
+ yield* Effect.forEach(watching.filter(({ attemptId }) => notified.includes(attemptId)), ({ report }) => report(notice), { discard: true });
122
+ }
123
+ });
124
+ // Root span: the watch can run longer than the Attempt that started it.
125
+ const check = Effect.fn("RemoteExecutor.probeWorker", { root: true })(function* () {
126
+ yield* Effect.annotateCurrentSpan({ worker, host });
127
+ const result = yield* probe;
128
+ yield* Semaphore.withPermit(lock, decide(result));
129
+ });
130
+ return yield* Effect.sleep(PROBE_INTERVAL).pipe(Effect.andThen(check()), Effect.forever);
131
+ });
132
+ /**
133
+ * Returns the liveness watches that probe Workers' machines through `commands`. Each watch runs
134
+ * in the caller's scope and stops when that scope closes.
135
+ */
136
+ export const workerWatchesFor = (commands) => Effect.gen(function* () {
137
+ const scope = yield* Effect.scope;
138
+ const lock = yield* Semaphore.make(1);
139
+ // Keyed by Worker and destination, since a provisioned Worker has one machine per Attempt.
140
+ const watched = new Map();
141
+ const keyOf = (watch) => `${watch.worker} ${watch.shell.destination}`;
142
+ const join = (watch) => Semaphore.withPermit(lock, Effect.gen(function* () {
143
+ const fields = { attemptId: watch.attemptId, worker: watch.worker };
144
+ const existing = watched.get(keyOf(watch));
145
+ if (existing !== undefined) {
146
+ existing.watchers.set(watch.attemptId, watch);
147
+ const current = yield* Ref.get(existing.liveness);
148
+ const joined = { ...fields, attempts: existing.watchers.size };
149
+ if (current._tag === "Answering")
150
+ return yield* Effect.logDebug("The Attempt joins its Worker's liveness watch", joined);
151
+ const next = joinSilent(watch.worker, current, watch.attemptId);
152
+ yield* Ref.set(existing.liveness, next.liveness);
153
+ yield* Effect.logInfo(Option.isSome(next.report)
154
+ ? "The Attempt joins its Worker's liveness watch while the Worker does not answer, and is told so"
155
+ : "The Attempt joins its Worker's liveness watch while the Worker does not answer; it was told so already", {
156
+ ...joined,
157
+ lastAnsweredAt: DateTime.formatIso(current.lastAnsweredAt),
158
+ unansweredProbes: current.unanswered,
159
+ reason: current.reason,
160
+ });
161
+ if (Option.isSome(next.report))
162
+ yield* watch.report(next.report.value.notice);
163
+ return;
164
+ }
165
+ const liveness = yield* Ref.make({
166
+ _tag: "Answering",
167
+ lastAnsweredAt: yield* DateTime.now,
168
+ });
169
+ const watchers = new Map([[watch.attemptId, watch]]);
170
+ const fiber = yield* watchWorker(commands, watch.worker, watch.shell, lock, liveness, () => [...watchers.values()]).pipe(Effect.forkIn(scope));
171
+ watched.set(keyOf(watch), { liveness, watchers, fiber });
172
+ yield* Effect.logDebug("Watching the Worker while Attempts run on it", {
173
+ ...fields,
174
+ host: watch.shell.destination,
175
+ interval: PROBE_INTERVAL,
176
+ });
177
+ }));
178
+ const leave = (watch) => Semaphore.withPermit(lock, Effect.gen(function* () {
179
+ const existing = watched.get(keyOf(watch));
180
+ if (existing === undefined)
181
+ return;
182
+ existing.watchers.delete(watch.attemptId);
183
+ if (existing.watchers.size > 0)
184
+ return;
185
+ watched.delete(keyOf(watch));
186
+ yield* Fiber.interrupt(existing.fiber);
187
+ yield* Effect.logDebug("Stopped watching the Worker; no Attempt runs on it", {
188
+ attemptId: watch.attemptId,
189
+ worker: watch.worker,
190
+ });
191
+ }));
192
+ return {
193
+ watch: (watch) => Effect.acquireRelease(join(watch), () => leave(watch)),
194
+ };
195
+ });
196
+ //# sourceMappingURL=liveness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveness.js","sourceRoot":"","sources":["../../src/remote/liveness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import type { RemoteShell } from "@usine/agents/child-host";
2
+ import type { BrainSpec, Harness } from "@usine/core/agent/brain";
3
+ import type { AttemptId } from "@usine/core/attempt";
4
+ import type { AttemptRecovery } from "@usine/core/attempt/salvage";
5
+ import type { LoopPermissions } from "@usine/core/loop";
6
+ import type { RepositoryName } from "@usine/core/repository";
7
+ import type { GatewayCredentialKind, MachineId, WorkerKind, WorkerName } from "@usine/core/worker";
8
+ import type { Effect, Option, Redacted, Scope } from "effect";
9
+ import type { CredentialUnavailableError, ExecutorError, ExecutorOperation, PreflightReport } from "../executor.ts";
10
+ import type { HarnessProbe } from "../harness-preflight.ts";
11
+ import type { RemoteCommands } from "./commands.ts";
12
+ import type { AttemptIsolation } from "./container.ts";
13
+ /** A machine with checkouts left for reconciliation. */
14
+ interface RemoteLeftovers<M extends RemoteMachine> {
15
+ readonly machine: M;
16
+ /** The paths directly under the Worker's `attempts` directory. */
17
+ readonly checkouts: ReadonlySet<string>;
18
+ }
19
+ export interface RemoteMachine {
20
+ readonly shell: RemoteShell;
21
+ /** The Worker directory on the machine, with cached clones under `repos` and checkouts under `attempts`. */
22
+ readonly workerDirectory: string;
23
+ /** The provider's ID of a machine created for one Attempt, or `None` for a long-lived machine. */
24
+ readonly provisioned: Option.Option<MachineId>;
25
+ }
26
+ export interface RemoteAccess {
27
+ /**
28
+ * The shell for the Attempt's children, harvesting, and git commands: the machine's own, or one
29
+ * that sends `secrets` through the SSH connection (`sendingShell`). An Attempt container gets
30
+ * `secrets` when it starts instead.
31
+ */
32
+ readonly shell: RemoteShell;
33
+ /** The variables with the Attempt's secrets, which never appear in a command line. */
34
+ readonly secrets: Readonly<Record<string, Redacted.Redacted<string>>>;
35
+ /** The machine directories that the Attempt's container mounts read-only, such as its credential directory. */
36
+ readonly readOnlyPaths: ReadonlyArray<string>;
37
+ /** The machine directories of the Attempt that its container mounts read-write, such as a harness's home. */
38
+ readonly writablePaths: ReadonlyArray<string>;
39
+ /** The extra environment for the Attempt's children and harvesting commands. Values appear in the command line, so none can be secret. */
40
+ readonly environment: Readonly<Record<string, string>>;
41
+ /** The extra environment for the executor's git commands on the checkout. Values appear in the command line, so none can be secret. */
42
+ readonly gitEnvironment: Readonly<Record<string, string>>;
43
+ /** Renews the credential on the machine if it's about to expire. Run before each git and harvesting command. */
44
+ readonly refresh: Effect.Effect<void, ExecutorError>;
45
+ /** Removes every credential this process issued for the Attempt from a command's output. */
46
+ readonly scrub: (text: string) => string;
47
+ }
48
+ export interface RemoteGrant<M extends RemoteMachine> {
49
+ /**
50
+ * Grants the Attempt access to its repository on `machine` until the caller's scope closes,
51
+ * restricted to its Loop `permissions` if the Worker kind supports it.
52
+ */
53
+ readonly acquire: (attemptId: AttemptId, worker: WorkerName, permissions: LoopPermissions, machine: M, operation: ExecutorOperation) => Effect.Effect<RemoteAccess, ExecutorError, Scope.Scope>;
54
+ }
55
+ /** The Worker-kind implementation for the remote executor. */
56
+ export interface RemoteWorker<M extends RemoteMachine> {
57
+ /** Reported as `Executor.kind`; the scheduler rejects Workers of other kinds. */
58
+ readonly kind: WorkerKind;
59
+ /** The span name prefix, for example `ExeDevExecutor`. */
60
+ readonly spanPrefix: string;
61
+ readonly label: string;
62
+ readonly commands: RemoteCommands;
63
+ /** Returns a Worker's machine. Fails with a typed error if the machine is missing or doesn't respond. */
64
+ readonly machineFor: (worker: WorkerName) => Effect.Effect<M, ExecutorError>;
65
+ /**
66
+ * Returns the machine an Attempt runs on, if the Worker kind creates one per Attempt.
67
+ * Defaults to `machineFor`.
68
+ */
69
+ readonly attemptMachine?: (worker: WorkerName, attemptId: AttemptId) => Effect.Effect<M, ExecutorError>;
70
+ /**
71
+ * Returns the machine with `attempt`'s leftover checkout and the paths under its `attempts`
72
+ * directory, or `None` if the Attempt's machine is gone. `listed` is the Worker's machine and
73
+ * its listed checkouts, the default.
74
+ */
75
+ readonly leftovers?: (attempt: AttemptRecovery, listed: Effect.Effect<RemoteLeftovers<M>, ExecutorError>) => Effect.Effect<Option.Option<RemoteLeftovers<M>>, ExecutorError>;
76
+ /** Runs after `recover` reconciled `attempt`'s machine, with whether it succeeded. */
77
+ readonly recovered?: (attempt: AttemptRecovery, succeeded: boolean) => Effect.Effect<void>;
78
+ /**
79
+ * Records whether the machine of `attemptId` has the Attempt's checkout: from its preparation
80
+ * or a recovery that finds it, until its removal succeeds.
81
+ */
82
+ readonly checkoutHeld?: (attemptId: AttemptId, held: boolean) => Effect.Effect<void>;
83
+ /** See `Executor.preflight`. */
84
+ readonly preflight: (worker: WorkerName, brains: ReadonlyArray<BrainSpec>, maxConcurrentAttempts: number) => Effect.Effect<PreflightReport, ExecutorError>;
85
+ /** Returns the probe of a brain's binary and login through `shell`, on `machine` or in a container on it. */
86
+ readonly harnessProbe: (machine: M, shell: RemoteShell) => HarnessProbe;
87
+ /** Returns how new Attempts on `machine` run, as the Worker's last preflight found. */
88
+ readonly isolation: (machine: M) => Effect.Effect<AttemptIsolation, ExecutorError>;
89
+ /**
90
+ * Whether the Worker kind runs Attempt containers. If true, each existing checkout's container
91
+ * marker decides how a reattachment or recovery runs commands in it.
92
+ */
93
+ readonly runsContainers: boolean;
94
+ /** Returns the URL the cached clone on `machine` fetches `repository` from. */
95
+ readonly repositoryUrl: (machine: M, repository: RepositoryName) => string;
96
+ /** Returns the credential kind that the Gateway on `machine` injects for `harness`. Returns `None` if the machine has no Gateway or the harness uses its own login. */
97
+ readonly gatewayCredential: (machine: M, harness: Harness) => Effect.Effect<Option.Option<GatewayCredentialKind>>;
98
+ /** Returns the access grant for `repository`. Fails if none is configured. */
99
+ readonly grantFor: (repository: RepositoryName) => Effect.Effect<RemoteGrant<M>, CredentialUnavailableError>;
100
+ /** The reason this Worker kind can't grant read-only repository access, or `None` if it can. */
101
+ readonly readOnlyAccessGap: Option.Option<string>;
102
+ /** Removes leftovers of earlier processes that no Attempt can use. Runs before the Worker's checkouts are listed. */
103
+ readonly reclaim: (worker: WorkerName) => Effect.Effect<void>;
104
+ /** See `Executor.sweep`. Defaults to removing nothing. */
105
+ readonly sweep?: Effect.Effect<void>;
106
+ /** The timeout for the parent task's cancellation, then separately for the Attempt to finish. */
107
+ readonly interruptGrace: Parameters<typeof Effect.timeoutOption>[1];
108
+ }
109
+ export {};
110
+ //# sourceMappingURL=machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/remote/machine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=machine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machine.js","sourceRoot":"","sources":["../../src/remote/machine.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ import { ClaudeLoginLock } from "@usine/agents/runtime";
2
+ import type { AttemptId } from "@usine/core/attempt";
3
+ import { type AttemptFailure } from "@usine/core/attempt/failure";
4
+ import type { AttemptRecovery, RecoverySink } from "@usine/core/attempt/salvage";
5
+ import type * as AttemptChannel from "@usine/core/attempt/channel";
6
+ import type { BotAccount, WorkerName } from "@usine/core/worker";
7
+ import { AttemptRuntime } from "@usine/durable/attempt-runtime";
8
+ import { Effect, Option, Scope } from "effect";
9
+ import { CheckoutRequest, ExecutorError } from "../executor.ts";
10
+ import type { RemoteMachine, RemoteWorker } from "./machine.ts";
11
+ /**
12
+ * Returns the executor for Workers accessed over SSH. Each Attempt's Pi parent is a durable task
13
+ * in this process, and each child runs on the machine as one SSH command with a pid file next
14
+ * to the worktree, or inside the Attempt's container. `worker` provides the machine, preflight,
15
+ * isolation, and repository access.
16
+ */
17
+ export declare const remoteExecutorFor: <M extends RemoteMachine>(worker: RemoteWorker<M>) => Effect.Effect<{
18
+ readonly recover: <E, A>(attempt: AttemptRecovery, record: RecoverySink<E>, commitAuthor: Effect.Effect<BotAccount, A>) => Effect.Effect<void, E | A | ExecutorError>;
19
+ readonly kind: import("@usine/core/worker").WorkerKind;
20
+ readonly isLive: (attemptId: AttemptId) => Effect.Effect<boolean, AttemptFailure>;
21
+ readonly outcome: (attemptId: AttemptId) => Effect.Effect<Option.Option<import("effect/Result").Result<import("@usine/core/step/result").StepResult, AttemptFailure>>, AttemptFailure>;
22
+ readonly preflight: (worker: WorkerName, brains: ReadonlyArray<import("@usine/core/agent/brain").BrainSpec>, maxConcurrentAttempts: number) => Effect.Effect<import("../executor.ts").PreflightReport, ExecutorError>;
23
+ readonly prepare: (request: CheckoutRequest) => Effect.Effect<import("../executor.ts").PreparedAttempt, ExecutorError, Scope.Scope>;
24
+ readonly cancel: (attemptId: AttemptId, reason: import("@usine/core/attempt").StopReason) => Effect.Effect<void, ExecutorError>;
25
+ readonly intervene: (attemptId: AttemptId, intervention: AttemptChannel.Intervention) => Effect.Effect<void, AttemptFailure>;
26
+ readonly sweep: Effect.Effect<void>;
27
+ }, never, AttemptRuntime | ClaudeLoginLock | Scope.Scope>;
28
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/remote/remote.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,KAAK,cAAc,EAAgB,MAAM,6BAA6B,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAkB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AACjG,OAAO,KAAK,KAAK,cAAc,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAY,MAAM,EAAQ,MAAM,EAAU,KAAK,EAAmB,MAAM,QAAQ,CAAC;AAExF,OAAO,EAEL,eAAe,EAEf,aAAa,EAId,MAAM,gBAAgB,CAAC;AAyBxB,OAAO,KAAK,EAAgB,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkD9E;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,aAAa,UAAU,YAAY,CAAC,CAAC,CAAC;;;;;;;;;;yDA03B9E,CAAC"}