@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.
- package/README.md +115 -37
- package/dist/child-command.d.ts +4 -7
- package/dist/child-command.d.ts.map +1 -1
- package/dist/child-command.js +6 -12
- package/dist/child-command.js.map +1 -1
- package/dist/claude-login-lock.d.ts +8 -0
- package/dist/claude-login-lock.d.ts.map +1 -0
- package/dist/claude-login-lock.js +9 -0
- package/dist/claude-login-lock.js.map +1 -0
- package/dist/credential-environment.d.ts +20 -0
- package/dist/credential-environment.d.ts.map +1 -0
- package/dist/credential-environment.js +20 -0
- package/dist/credential-environment.js.map +1 -0
- package/dist/durable-session.d.ts +63 -0
- package/dist/durable-session.d.ts.map +1 -0
- package/dist/durable-session.js +491 -0
- package/dist/durable-session.js.map +1 -0
- package/dist/exe-dev/commands.d.ts +23 -13
- package/dist/exe-dev/commands.d.ts.map +1 -1
- package/dist/exe-dev/commands.js +11 -57
- package/dist/exe-dev/commands.js.map +1 -1
- package/dist/exe-dev/exe-dev.d.ts +9 -3
- package/dist/exe-dev/exe-dev.d.ts.map +1 -1
- package/dist/exe-dev/exe-dev.js +53 -128
- package/dist/exe-dev/exe-dev.js.map +1 -1
- package/dist/exe-dev/grants.d.ts.map +1 -1
- package/dist/exe-dev/grants.js +35 -15
- package/dist/exe-dev/grants.js.map +1 -1
- package/dist/exe-dev/model.d.ts +15 -19
- package/dist/exe-dev/model.d.ts.map +1 -1
- package/dist/exe-dev/model.js +9 -12
- package/dist/exe-dev/model.js.map +1 -1
- package/dist/exe-dev/preflight.d.ts +8 -4
- package/dist/exe-dev/preflight.d.ts.map +1 -1
- package/dist/exe-dev/preflight.js +23 -33
- package/dist/exe-dev/preflight.js.map +1 -1
- package/dist/executor.d.ts +140 -41
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +90 -19
- package/dist/executor.js.map +1 -1
- package/dist/guard.d.ts +57 -7
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +273 -59
- package/dist/guard.js.map +1 -1
- package/dist/harness-preflight.d.ts +25 -4
- package/dist/harness-preflight.d.ts.map +1 -1
- package/dist/harness-preflight.js +25 -29
- package/dist/harness-preflight.js.map +1 -1
- package/dist/keyed-lock.d.ts +2 -3
- package/dist/keyed-lock.d.ts.map +1 -1
- package/dist/keyed-lock.js +2 -3
- package/dist/keyed-lock.js.map +1 -1
- package/dist/leftovers.d.ts +9 -0
- package/dist/leftovers.d.ts.map +1 -0
- package/dist/leftovers.js +14 -0
- package/dist/leftovers.js.map +1 -0
- package/dist/local/credentials.d.ts +21 -0
- package/dist/local/credentials.d.ts.map +1 -0
- package/dist/local/credentials.js +39 -0
- package/dist/local/credentials.js.map +1 -0
- package/dist/local/leftovers.d.ts +8 -0
- package/dist/local/leftovers.d.ts.map +1 -0
- package/dist/local/leftovers.js +23 -0
- package/dist/local/leftovers.js.map +1 -0
- package/dist/local/local.d.ts +16 -10
- package/dist/local/local.d.ts.map +1 -1
- package/dist/local/local.js +163 -129
- package/dist/local/local.js.map +1 -1
- package/dist/memory-preflight.d.ts +25 -0
- package/dist/memory-preflight.d.ts.map +1 -0
- package/dist/memory-preflight.js +83 -0
- package/dist/memory-preflight.js.map +1 -0
- package/dist/pre-push-hook.d.ts +20 -0
- package/dist/pre-push-hook.d.ts.map +1 -0
- package/dist/pre-push-hook.js +33 -0
- package/dist/pre-push-hook.js.map +1 -0
- package/dist/prepared-attempt.d.ts +33 -3
- package/dist/prepared-attempt.d.ts.map +1 -1
- package/dist/prepared-attempt.js +109 -31
- package/dist/prepared-attempt.js.map +1 -1
- package/dist/provision.d.ts +77 -14
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +357 -55
- package/dist/provision.js.map +1 -1
- package/dist/remote/commands.d.ts +51 -0
- package/dist/remote/commands.d.ts.map +1 -0
- package/dist/remote/commands.js +94 -0
- package/dist/remote/commands.js.map +1 -0
- package/dist/remote/leftovers.d.ts +14 -0
- package/dist/remote/leftovers.d.ts.map +1 -0
- package/dist/remote/leftovers.js +22 -0
- package/dist/remote/leftovers.js.map +1 -0
- package/dist/remote/liveness.d.ts +33 -0
- package/dist/remote/liveness.d.ts.map +1 -0
- package/dist/remote/liveness.js +194 -0
- package/dist/remote/liveness.js.map +1 -0
- package/dist/remote/machine.d.ts +64 -0
- package/dist/remote/machine.d.ts.map +1 -0
- package/dist/remote/machine.js +2 -0
- package/dist/remote/machine.js.map +1 -0
- package/dist/remote/remote.d.ts +24 -0
- package/dist/remote/remote.d.ts.map +1 -0
- package/dist/remote/remote.js +308 -0
- package/dist/remote/remote.js.map +1 -0
- package/dist/remote/sweep.d.ts +15 -0
- package/dist/remote/sweep.d.ts.map +1 -0
- package/dist/remote/sweep.js +116 -0
- package/dist/remote/sweep.js.map +1 -0
- package/dist/renewable-credential.d.ts +17 -0
- package/dist/renewable-credential.d.ts.map +1 -0
- package/dist/renewable-credential.js +58 -0
- package/dist/renewable-credential.js.map +1 -0
- package/dist/salvage.d.ts +30 -0
- package/dist/salvage.d.ts.map +1 -0
- package/dist/salvage.js +104 -0
- package/dist/salvage.js.map +1 -0
- package/dist/ssh/credentials.d.ts +40 -0
- package/dist/ssh/credentials.d.ts.map +1 -0
- package/dist/ssh/credentials.js +83 -0
- package/dist/ssh/credentials.js.map +1 -0
- package/dist/ssh/gateway/admin.d.ts +45 -0
- package/dist/ssh/gateway/admin.d.ts.map +1 -0
- package/dist/ssh/gateway/admin.js +129 -0
- package/dist/ssh/gateway/admin.js.map +1 -0
- package/dist/ssh/gateway/attachments.d.ts +22 -0
- package/dist/ssh/gateway/attachments.d.ts.map +1 -0
- package/dist/ssh/gateway/attachments.js +154 -0
- package/dist/ssh/gateway/attachments.js.map +1 -0
- package/dist/ssh/gateway/environment.d.ts +52 -0
- package/dist/ssh/gateway/environment.d.ts.map +1 -0
- package/dist/ssh/gateway/environment.js +78 -0
- package/dist/ssh/gateway/environment.js.map +1 -0
- package/dist/ssh/gateway/forward.d.ts +74 -0
- package/dist/ssh/gateway/forward.d.ts.map +1 -0
- package/dist/ssh/gateway/forward.js +247 -0
- package/dist/ssh/gateway/forward.js.map +1 -0
- package/dist/ssh/gateway/preflight.d.ts +28 -0
- package/dist/ssh/gateway/preflight.d.ts.map +1 -0
- package/dist/ssh/gateway/preflight.js +234 -0
- package/dist/ssh/gateway/preflight.js.map +1 -0
- package/dist/ssh/model.d.ts +65 -0
- package/dist/ssh/model.d.ts.map +1 -0
- package/dist/ssh/model.js +2 -0
- package/dist/ssh/model.js.map +1 -0
- package/dist/ssh/preflight.d.ts +16 -0
- package/dist/ssh/preflight.d.ts.map +1 -0
- package/dist/ssh/preflight.js +47 -0
- package/dist/ssh/preflight.js.map +1 -0
- package/dist/ssh/ssh.d.ts +20 -0
- package/dist/ssh/ssh.d.ts.map +1 -0
- package/dist/ssh/ssh.js +78 -0
- package/dist/ssh/ssh.js.map +1 -0
- package/dist/ssh/workers.d.ts +53 -0
- package/dist/ssh/workers.d.ts.map +1 -0
- package/dist/ssh/workers.js +173 -0
- package/dist/ssh/workers.js.map +1 -0
- package/package.json +12 -4
- package/dist/exe-dev/channel.d.ts +0 -12
- package/dist/exe-dev/channel.d.ts.map +0 -1
- package/dist/exe-dev/channel.js +0 -42
- package/dist/exe-dev/channel.js.map +0 -1
- package/dist/exe-dev/shell.d.ts +0 -12
- package/dist/exe-dev/shell.d.ts.map +0 -1
- package/dist/exe-dev/shell.js +0 -31
- package/dist/exe-dev/shell.js.map +0 -1
- package/dist/exe-dev/sweep.d.ts +0 -10
- package/dist/exe-dev/sweep.d.ts.map +0 -1
- package/dist/exe-dev/sweep.js +0 -117
- package/dist/exe-dev/sweep.js.map +0 -1
- package/dist/invalid-frame.d.ts +0 -17
- package/dist/invalid-frame.d.ts.map +0 -1
- package/dist/invalid-frame.js +0 -111
- package/dist/invalid-frame.js.map +0 -1
- package/dist/run-host-session.d.ts +0 -27
- package/dist/run-host-session.d.ts.map +0 -1
- package/dist/run-host-session.js +0 -303
- package/dist/run-host-session.js.map +0 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { RemoteShell, sshArguments, } from "@usine/agents/child-host";
|
|
2
|
+
import { Effect, Redacted, Stream } from "effect";
|
|
3
|
+
import { ChildProcessSpawner } from "effect/unstable/process";
|
|
4
|
+
import { allowlistedEnvironment, collectCommand, requireSuccess, } from "../child-command.js";
|
|
5
|
+
/**
|
|
6
|
+
* The variables the local SSH client inherits. GitHub and factory credentials in the
|
|
7
|
+
* orchestrator environment aren't passed to the client or the machine.
|
|
8
|
+
*/
|
|
9
|
+
export const SSH_ENVIRONMENT_ALLOWLIST = [
|
|
10
|
+
"HOME",
|
|
11
|
+
"LANG",
|
|
12
|
+
"LC_ALL",
|
|
13
|
+
"PATH",
|
|
14
|
+
"SHELL",
|
|
15
|
+
"SSH_AGENT_PID",
|
|
16
|
+
"SSH_AUTH_SOCK",
|
|
17
|
+
"TMPDIR",
|
|
18
|
+
"USER",
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* The default SSH client for remote Workers. Its keepalive options make a dead TCP connection
|
|
22
|
+
* exit non-zero instead of hanging.
|
|
23
|
+
*/
|
|
24
|
+
export const DEFAULT_SSH = {
|
|
25
|
+
command: "ssh",
|
|
26
|
+
args: ["-o", "BatchMode=yes", "-o", "ServerAliveInterval=30", "-o", "ServerAliveCountMax=4"],
|
|
27
|
+
};
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
/**
|
|
30
|
+
* Returns `shell` with `variables` sent through OpenSSH `SendEnv` instead of the command line,
|
|
31
|
+
* so the values aren't in arguments, logs, or process listings. The remote sshd drops names
|
|
32
|
+
* not in its `AcceptEnv`.
|
|
33
|
+
*/
|
|
34
|
+
export const sendingShell = (shell, variables) => {
|
|
35
|
+
const entries = Object.entries(variables);
|
|
36
|
+
if (entries.length === 0)
|
|
37
|
+
return shell;
|
|
38
|
+
return new RemoteShell({
|
|
39
|
+
ssh: {
|
|
40
|
+
command: shell.ssh.command,
|
|
41
|
+
args: [...shell.ssh.args, "-o", `SendEnv=${entries.map(([name]) => name).join(" ")}`],
|
|
42
|
+
},
|
|
43
|
+
sshEnvironment: {
|
|
44
|
+
...shell.sshEnvironment,
|
|
45
|
+
...Object.fromEntries(entries.map(([name, value]) => [name, Redacted.value(value)])),
|
|
46
|
+
},
|
|
47
|
+
destination: shell.destination,
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
/** The `RemoteCommands` that use this process's spawner and the allowlisted SSH environment. */
|
|
51
|
+
export const remoteCommandsFor = Effect.gen(function* () {
|
|
52
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
53
|
+
const environment = yield* allowlistedEnvironment(SSH_ENVIRONMENT_ALLOWLIST);
|
|
54
|
+
const shellFor = (ssh, destination) => new RemoteShell({ ssh, sshEnvironment: environment, destination });
|
|
55
|
+
const executeRaw = Effect.fn("RemoteExecutor.executeRaw")(function* (operation, host, command, args, clientEnvironment) {
|
|
56
|
+
yield* Effect.annotateCurrentSpan({ host, operation });
|
|
57
|
+
return yield* collectCommand(spawner, operation, command, args, {
|
|
58
|
+
env: { ...clientEnvironment },
|
|
59
|
+
extendEnv: false,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
const local = Effect.fn("RemoteExecutor.local")(function* (operation, host, command, args) {
|
|
63
|
+
const result = yield* executeRaw(operation, host, command, args, environment);
|
|
64
|
+
return yield* requireSuccess(operation, host, command, args, result);
|
|
65
|
+
});
|
|
66
|
+
const inspect = (operation, shell, command, args) => executeRaw(operation, shell.destination, shell.ssh.command, sshArguments(shell, { command, args }), shell.sshEnvironment);
|
|
67
|
+
const run = Effect.fn("RemoteExecutor.run")(function* (operation, shell, command, args, context = {}) {
|
|
68
|
+
const sshArgs = sshArguments(shell, {
|
|
69
|
+
cwd: context.cwd,
|
|
70
|
+
environment: context.environment,
|
|
71
|
+
command,
|
|
72
|
+
args,
|
|
73
|
+
});
|
|
74
|
+
const result = yield* executeRaw(operation, shell.destination, shell.ssh.command, sshArgs, shell.sshEnvironment);
|
|
75
|
+
const scrub = context.scrub ?? ((text) => text);
|
|
76
|
+
return yield* requireSuccess(operation, shell.destination, shell.ssh.command, sshArgs, {
|
|
77
|
+
...result,
|
|
78
|
+
stdout: scrub(result.stdout),
|
|
79
|
+
stderr: scrub(result.stderr),
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
const runWithInput = Effect.fn("RemoteExecutor.runWithInput")(function* (operation, shell, command, args, input) {
|
|
83
|
+
yield* Effect.annotateCurrentSpan({ host: shell.destination, operation });
|
|
84
|
+
const sshArgs = sshArguments(shell, { command, args });
|
|
85
|
+
const result = yield* collectCommand(spawner, operation, shell.ssh.command, sshArgs, {
|
|
86
|
+
env: { ...shell.sshEnvironment },
|
|
87
|
+
extendEnv: false,
|
|
88
|
+
stdin: Stream.make(encoder.encode(Redacted.value(input))),
|
|
89
|
+
});
|
|
90
|
+
return yield* requireSuccess(operation, shell.destination, shell.ssh.command, sshArgs, result);
|
|
91
|
+
});
|
|
92
|
+
return { shellFor, local, inspect, run, runWithInput };
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/remote/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAEX,YAAY,GACb,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,cAAc,EAEd,cAAc,GACf,MAAM,qBAAqB,CAAC;AA+C7B;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,MAAM;IACN,MAAM;IACN,QAAQ;IACR,MAAM;IACN,OAAO;IACP,eAAe;IACf,eAAe;IACf,QAAQ;IACR,MAAM;CACE,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAe;IACrC,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,uBAAuB,CAAC;CAC7F,CAAC;AAEF,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,KAAkB,EAClB,SAA8D,EACjD,EAAE;IACf,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,IAAI,WAAW,CAAC;QACrB,GAAG,EAAE;YACH,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO;YAC1B,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;SACtF;QACD,cAAc,EAAE;YACd,GAAG,KAAK,CAAC,cAAc;YACvB,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACrF;QACD,WAAW,EAAE,KAAK,CAAC,WAAW;KAC/B,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,CAAC;IAC/D,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,sBAAsB,CAAC,yBAAyB,CAAC,CAAC;IAE7E,MAAM,QAAQ,GAAG,CAAC,GAAe,EAAE,WAA2B,EAAE,EAAE,CAChE,IAAI,WAAW,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;IAErE,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,2BAA2B,CAAC,CAAC,QAAQ,CAAC,EACjE,SAA4B,EAC5B,IAAY,EACZ,OAAe,EACf,IAA2B,EAC3B,iBAAmD;QAEnD,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;YAC9D,GAAG,EAAE,EAAE,GAAG,iBAAiB,EAAE;YAC7B,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,QAAQ,CAAC,EACvD,SAA4B,EAC5B,IAAY,EACZ,OAAe,EACf,IAA2B;QAE3B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAC9E,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,CACd,SAA4B,EAC5B,KAAkB,EAClB,OAAe,EACf,IAA2B,EAC2B,EAAE,CACxD,UAAU,CACR,SAAS,EACT,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,GAAG,CAAC,OAAO,EACjB,YAAY,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EACtC,KAAK,CAAC,cAAc,CACrB,CAAC;IAEJ,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EACnD,SAA4B,EAC5B,KAAkB,EAClB,OAAe,EACf,IAA2B,EAC3B,OAAO,GAAkB,EAAE;QAE3B,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,OAAO;YACP,IAAI;SACL,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAC9B,SAAS,EACT,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,GAAG,CAAC,OAAO,EACjB,OAAO,EACP,KAAK,CAAC,cAAc,CACrB,CAAC;QACF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE;YACrF,GAAG,MAAM;YACT,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAC5B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,EACrE,SAA4B,EAC5B,KAAkB,EAClB,OAAe,EACf,IAA2B,EAC3B,KAAgC;QAEhC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QAC1E,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE;YACnF,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC,cAAc,EAAE;YAChC,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;SAC1D,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAA2B,CAAC;AAClF,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorkerName } from "@usine/core/worker";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import type { RemoteCommands } from "./commands.ts";
|
|
4
|
+
import type { RemoteMachine } from "./machine.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Resolves a Worker's machine, runs `reclaim` on it, and lists its leftover checkouts, once per
|
|
7
|
+
* Worker per executor. A Worker that can't be resolved or listed isn't reconciled until the
|
|
8
|
+
* next start.
|
|
9
|
+
*/
|
|
10
|
+
export declare const workerLeftoversFor: <M extends RemoteMachine, E>(commands: RemoteCommands, machineFor: (worker: WorkerName) => Effect.Effect<M, E>, reclaim: (worker: WorkerName) => Effect.Effect<void>) => Effect.Effect<(worker: WorkerName) => Effect.Effect<{
|
|
11
|
+
machine: M;
|
|
12
|
+
checkouts: Set<string>;
|
|
13
|
+
}, E | import("../executor.ts").ExecutorOperationError, never>, never, never>;
|
|
14
|
+
//# sourceMappingURL=leftovers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leftovers.d.ts","sourceRoot":"","sources":["../../src/remote/leftovers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AASlD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,aAAa,EAAE,CAAC,YACjD,cAAc,cACZ,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,WAC9C,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;;;6EAuBnD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { listedOncePerWorker } from "../leftovers.js";
|
|
3
|
+
import { attemptPathsOn } from "./sweep.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a Worker's machine, runs `reclaim` on it, and lists its leftover checkouts, once per
|
|
6
|
+
* Worker per executor. A Worker that can't be resolved or listed isn't reconciled until the
|
|
7
|
+
* next start.
|
|
8
|
+
*/
|
|
9
|
+
export const workerLeftoversFor = (commands, machineFor, reclaim) => listedOncePerWorker(Effect.fn("RemoteExecutor.listWorkerLeftovers")(function* (worker) {
|
|
10
|
+
const machine = yield* machineFor(worker);
|
|
11
|
+
const host = machine.shell.destination;
|
|
12
|
+
yield* Effect.annotateCurrentSpan({ worker, host });
|
|
13
|
+
yield* reclaim(worker);
|
|
14
|
+
const checkouts = new Set(yield* attemptPathsOn(commands, "cleanup", machine.shell, `${machine.workerDirectory}/attempts`));
|
|
15
|
+
yield* Effect.logInfo("Listed remote checkouts left for reconciliation", {
|
|
16
|
+
worker,
|
|
17
|
+
host,
|
|
18
|
+
checkouts: checkouts.size,
|
|
19
|
+
});
|
|
20
|
+
return { machine, checkouts };
|
|
21
|
+
}));
|
|
22
|
+
//# sourceMappingURL=leftovers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leftovers.js","sourceRoot":"","sources":["../../src/remote/leftovers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,QAAwB,EACxB,UAAuD,EACvD,OAAoD,EACpD,EAAE,CACF,mBAAmB,CACjB,MAAM,CAAC,EAAE,CAAC,oCAAoC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAkB;IAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;IACvC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,KAAK,CAAC,CAAC,cAAc,CACnB,QAAQ,EACR,SAAS,EACT,OAAO,CAAC,KAAK,EACb,GAAG,OAAO,CAAC,eAAe,WAAW,CACtC,CACF,CAAC;IACF,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,iDAAiD,EAAE;QACvE,MAAM;QACN,IAAI;QACJ,SAAS,EAAE,SAAS,CAAC,IAAI;KAC1B,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,SAAS,EAA+B,CAAC;AAC7D,CAAC,CAAC,CACH,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { RemoteShell } from "@usine/agents/child-host";
|
|
2
|
+
import type { AttemptId } from "@usine/core/attempt";
|
|
3
|
+
import { type WorkerNotice } from "@usine/core/attempt/channel";
|
|
4
|
+
import type { WorkerName } from "@usine/core/worker";
|
|
5
|
+
import { Effect, type Scope } from "effect";
|
|
6
|
+
import type { RemoteCommands } from "./commands.ts";
|
|
7
|
+
interface WorkerWatcher {
|
|
8
|
+
readonly attemptId: AttemptId;
|
|
9
|
+
/** Records a notice in the Attempt's transcript. */
|
|
10
|
+
readonly report: (notice: WorkerNotice) => Effect.Effect<void>;
|
|
11
|
+
}
|
|
12
|
+
interface WorkerWatch extends WorkerWatcher {
|
|
13
|
+
readonly worker: WorkerName;
|
|
14
|
+
/** The machine's shell, without Attempt secrets. */
|
|
15
|
+
readonly shell: RemoteShell;
|
|
16
|
+
}
|
|
17
|
+
/** The liveness watches of one executor, one per Worker with a running Attempt. */
|
|
18
|
+
export interface WorkerWatches {
|
|
19
|
+
/**
|
|
20
|
+
* Adds the Attempt to its Worker's watch until the caller's scope closes. Every minute, the
|
|
21
|
+
* watch runs `true` on the machine over a new SSH connection; when the machine stops or resumes
|
|
22
|
+
* responding, it calls `report` for each Attempt and logs a line. Never stops or fails an
|
|
23
|
+
* Attempt (ADR 0013).
|
|
24
|
+
*/
|
|
25
|
+
readonly watch: (watch: WorkerWatch) => Effect.Effect<void, never, Scope.Scope>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns the liveness watches that probe Workers' machines through `commands`. Each watch runs
|
|
29
|
+
* in the caller's scope and stops when that scope closes.
|
|
30
|
+
*/
|
|
31
|
+
export declare const workerWatchesFor: (commands: RemoteCommands) => Effect.Effect<WorkerWatches, never, Scope.Scope>;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=liveness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveness.d.ts","sourceRoot":"","sources":["../../src/remote/liveness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAY,MAAM,EAA6B,KAAK,KAAK,EAAa,MAAM,QAAQ,CAAC;AAC5F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA+GpD,UAAU,aAAa;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CAChE;AAED,UAAU,WAAY,SAAQ,aAAa;IACzC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;CAC7B;AAED,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;CACjF;AA+GD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,aACjB,cAAc,KACvB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA+E9C,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
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
|
+
const watched = new Map();
|
|
140
|
+
const join = (watch) => Semaphore.withPermit(lock, Effect.gen(function* () {
|
|
141
|
+
const fields = { attemptId: watch.attemptId, worker: watch.worker };
|
|
142
|
+
const existing = watched.get(watch.worker);
|
|
143
|
+
if (existing !== undefined) {
|
|
144
|
+
existing.watchers.set(watch.attemptId, watch);
|
|
145
|
+
const current = yield* Ref.get(existing.liveness);
|
|
146
|
+
const joined = { ...fields, attempts: existing.watchers.size };
|
|
147
|
+
if (current._tag === "Answering")
|
|
148
|
+
return yield* Effect.logDebug("The Attempt joins its Worker's liveness watch", joined);
|
|
149
|
+
const next = joinSilent(watch.worker, current, watch.attemptId);
|
|
150
|
+
yield* Ref.set(existing.liveness, next.liveness);
|
|
151
|
+
yield* Effect.logInfo(Option.isSome(next.report)
|
|
152
|
+
? "The Attempt joins its Worker's liveness watch while the Worker does not answer, and is told so"
|
|
153
|
+
: "The Attempt joins its Worker's liveness watch while the Worker does not answer; it was told so already", {
|
|
154
|
+
...joined,
|
|
155
|
+
lastAnsweredAt: DateTime.formatIso(current.lastAnsweredAt),
|
|
156
|
+
unansweredProbes: current.unanswered,
|
|
157
|
+
reason: current.reason,
|
|
158
|
+
});
|
|
159
|
+
if (Option.isSome(next.report))
|
|
160
|
+
yield* watch.report(next.report.value.notice);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const liveness = yield* Ref.make({
|
|
164
|
+
_tag: "Answering",
|
|
165
|
+
lastAnsweredAt: yield* DateTime.now,
|
|
166
|
+
});
|
|
167
|
+
const watchers = new Map([[watch.attemptId, watch]]);
|
|
168
|
+
const fiber = yield* watchWorker(commands, watch.worker, watch.shell, lock, liveness, () => [...watchers.values()]).pipe(Effect.forkIn(scope));
|
|
169
|
+
watched.set(watch.worker, { liveness, watchers, fiber });
|
|
170
|
+
yield* Effect.logDebug("Watching the Worker while Attempts run on it", {
|
|
171
|
+
...fields,
|
|
172
|
+
host: watch.shell.destination,
|
|
173
|
+
interval: PROBE_INTERVAL,
|
|
174
|
+
});
|
|
175
|
+
}));
|
|
176
|
+
const leave = (watch) => Semaphore.withPermit(lock, Effect.gen(function* () {
|
|
177
|
+
const existing = watched.get(watch.worker);
|
|
178
|
+
if (existing === undefined)
|
|
179
|
+
return;
|
|
180
|
+
existing.watchers.delete(watch.attemptId);
|
|
181
|
+
if (existing.watchers.size > 0)
|
|
182
|
+
return;
|
|
183
|
+
watched.delete(watch.worker);
|
|
184
|
+
yield* Fiber.interrupt(existing.fiber);
|
|
185
|
+
yield* Effect.logDebug("Stopped watching the Worker; no Attempt runs on it", {
|
|
186
|
+
attemptId: watch.attemptId,
|
|
187
|
+
worker: watch.worker,
|
|
188
|
+
});
|
|
189
|
+
}));
|
|
190
|
+
return {
|
|
191
|
+
watch: (watch) => Effect.acquireRelease(join(watch), () => leave(watch)),
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
//# sourceMappingURL=liveness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveness.js","sourceRoot":"","sources":["../../src/remote/liveness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAEL,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAc,SAAS,EAAE,MAAM,QAAQ,CAAC;AAG5F,MAAM,cAAc,GAAG,UAAU,CAAC;AAClC,yGAAyG;AACzG,MAAM,uBAAuB,GAAG,EAAE,CAAC;AACnC,uHAAuH;AACvH,MAAM,qBAAqB,GAAG,EAAE,CAAC;AA6BjC,MAAM,QAAQ,GAAG,CACf,MAAoB,EACpB,UAAoC,EACb,EAAE,CACzB,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,OAAO,GAAG,CACd,MAAkB,EAClB,QAAkB,EAClB,KAAY,EACZ,GAAiB,EACjB,QAAkC,EACrB,EAAE;IACf,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAC3B,OAAO;YACL,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,EAAE;YACpD,MAAM,EACJ,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBACxB,CAAC,CAAC,QAAQ,CACN,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,EACzE,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAC7D;gBACH,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;SACpB,CAAC;IACJ,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAa,CAAC;IAC/E,OAAO;QACL,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,UAAU,EAAE,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC;SACxB;QACD,MAAM,EAAE,QAAQ,CACd,IAAI,kBAAkB,CAAC;YACrB,MAAM;YACN,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,EACF,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CACrD;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,GAAG,CAAC,MAAkB,EAAE,QAAkB,EAAE,SAAoB,EAAe,EAAE,CAC/F,QAAQ,CAAC,IAAI,KAAK,WAAW,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;IAC3D,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE;IACrC,CAAC,CAAC;QACE,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE;QACvE,MAAM,EAAE,QAAQ,CACd,IAAI,kBAAkB,CAAC;YACrB,MAAM;YACN,cAAc,EAAE,QAAQ,CAAC,cAAc;YACvC,MAAM,EAAE,QAAQ,CAAC,MAAM;SACxB,CAAC,EACF,CAAC,SAAS,CAAC,CACZ;KACF,CAAC;AAER,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE,CACxC,IAAI;KACD,KAAK,CAAC,IAAI,CAAC;KACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;KAC7B,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAyBlB;;;;GAIG;AACH,MAAM,WAAW,GAAG,CAClB,QAAwB,EACxB,MAAkB,EAClB,YAAyB,EACzB,IAAyB,EACzB,QAA2B,EAC3B,QAA4C,EACtB,EAAE,CACxB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC;QAC5B,GAAG,EAAE;YACH,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO;YACjC,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,uBAAuB,EAAE,CAAC;SACpF;QACD,cAAc,EAAE,YAAY,CAAC,cAAc;QAC3C,WAAW,EAAE,YAAY,CAAC,WAAW;KACtC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAyB,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,CACpF,MAAM,CAAC,aAAa,CAAC,GAAG,qBAAqB,UAAU,CAAC,EACxD,MAAM,CAAC,GAAG,CACR,MAAM,CAAC,KAAK,CAAC;QACX,MAAM,EAAE,GAAU,EAAE,CAAC,CAAC;YACpB,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,oBAAoB,qBAAqB,UAAU;SAC5D,CAAC;QACF,MAAM,EAAE,CAAC,MAAM,EAAS,EAAE,CACxB,MAAM,CAAC,QAAQ,KAAK,CAAC;YACnB,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE;YACtB,CAAC,CAAC;gBACE,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,CAAC,wBAAwB,MAAM,CAAC,QAAQ,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;qBACzE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;qBAC7B,IAAI,CAAC,IAAI,CAAC;aACd;KACR,CAAC,CACH,EACD,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAC9F,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,MAAa,EAAE,EAAE,CAC/B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAChF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG;YACb,MAAM;YACN,IAAI;YACJ,UAAU;YACV,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;gBAC5C,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE;gBAChB,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU;aACvC,CAAC;YACF,cAAc,EAAE,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC;SAC5D,CAAC;QACF,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE;YAC7B,QAAQ,EAAE,GAAG,EAAE,CACb,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBACxB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,0BAA0B,EAAE;oBACzC,GAAG,MAAM;oBACT,gBAAgB,EAAE,QAAQ,CAAC,UAAU;iBACtC,CAAC;gBACJ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,wCAAwC,EAAE,MAAM,CAAC;YACvE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CACzB,MAAM,CAAC,UAAU,CACf,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBACxB,CAAC,CAAC,kCAAkC;gBACpC,CAAC,CAAC,8BAA8B,EAClC;gBACE,GAAG,MAAM;gBACT,gBAAgB,EAAE,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1E,MAAM;aACP,CACF;SACJ,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAC3D,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAChE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAC9B,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,wEAAwE;IACxE,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC;QAC7E,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC;QAC5B,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;AAC3F,CAAC,CAAC,CAAC;AAQL;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAAwB,EAC0B,EAAE,CACpD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/C,MAAM,IAAI,GAAG,CAAC,KAAkB,EAAE,EAAE,CAClC,SAAS,CAAC,UAAU,CAClB,IAAI,EACJ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC/D,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;gBAC9B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAC3B,+CAA+C,EAC/C,MAAM,CACP,CAAC;YACJ,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YAChE,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjD,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CACnB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;gBACxB,CAAC,CAAC,gGAAgG;gBAClG,CAAC,CAAC,wGAAwG,EAC5G;gBACE,GAAG,MAAM;gBACT,cAAc,EAAE,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC;gBAC1D,gBAAgB,EAAE,OAAO,CAAC,UAAU;gBACpC,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CACF,CAAC;YACF,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAW;YACzC,IAAI,EAAE,WAAW;YACjB,cAAc,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG;SACpC,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAA2B,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,WAAW,CAC9B,QAAQ,EACR,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,KAAK,EACX,IAAI,EACJ,QAAQ,EACR,GAAG,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAC7B,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,8CAA8C,EAAE;YACrE,GAAG,MAAM;YACT,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW;YAC7B,QAAQ,EAAE,cAAc;SACzB,CAAC,CAAC;IACL,CAAC,CAAC,CACH,CAAC;IAEJ,MAAM,KAAK,GAAG,CAAC,KAAkB,EAAE,EAAE,CACnC,SAAS,CAAC,UAAU,CAClB,IAAI,EACJ,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO;QACnC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1C,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;YAAE,OAAO;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,oDAAoD,EAAE;YAC3E,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;IACL,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;KACjD,CAAC;AAC5B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { LoopPermissions } from "@usine/core/loop";
|
|
5
|
+
import type { RepositoryName } from "@usine/core/repository";
|
|
6
|
+
import type { GatewayCredentialKind, WorkerKind, WorkerName } from "@usine/core/worker";
|
|
7
|
+
import type { Effect, Option, Scope } from "effect";
|
|
8
|
+
import type { CredentialUnavailableError, ExecutorError, ExecutorOperation } from "../executor.ts";
|
|
9
|
+
import type { HarnessProbe } from "../harness-preflight.ts";
|
|
10
|
+
import type { RemoteCommands } from "./commands.ts";
|
|
11
|
+
export interface RemoteMachine {
|
|
12
|
+
readonly shell: RemoteShell;
|
|
13
|
+
/** The Worker directory on the machine, with cached clones under `repos` and checkouts under `attempts`. */
|
|
14
|
+
readonly workerDirectory: string;
|
|
15
|
+
}
|
|
16
|
+
export interface RemoteAccess {
|
|
17
|
+
/**
|
|
18
|
+
* The shell for the Attempt's children, harvesting, and git commands: the machine's own, or one
|
|
19
|
+
* that sends the Attempt's secrets through the SSH connection (`sendingShell`).
|
|
20
|
+
*/
|
|
21
|
+
readonly shell: RemoteShell;
|
|
22
|
+
/** The extra environment for the Attempt's children and harvesting commands. Values appear in the command line, so none can be secret. */
|
|
23
|
+
readonly environment: Readonly<Record<string, string>>;
|
|
24
|
+
/** The extra environment for the executor's git commands on the checkout. Values appear in the command line, so none can be secret. */
|
|
25
|
+
readonly gitEnvironment: Readonly<Record<string, string>>;
|
|
26
|
+
/** Renews the credential on the machine if it's about to expire. Run before each git and harvesting command. */
|
|
27
|
+
readonly refresh: Effect.Effect<void, ExecutorError>;
|
|
28
|
+
/** Removes every credential this process issued for the Attempt from a command's output. */
|
|
29
|
+
readonly scrub: (text: string) => string;
|
|
30
|
+
}
|
|
31
|
+
export interface RemoteGrant<M extends RemoteMachine> {
|
|
32
|
+
/**
|
|
33
|
+
* Grants the Attempt access to its repository on `machine` until the caller's scope closes,
|
|
34
|
+
* restricted to its Loop `permissions` if the Worker kind supports it.
|
|
35
|
+
*/
|
|
36
|
+
readonly acquire: (attemptId: AttemptId, worker: WorkerName, permissions: LoopPermissions, machine: M, operation: ExecutorOperation) => Effect.Effect<RemoteAccess, ExecutorError, Scope.Scope>;
|
|
37
|
+
}
|
|
38
|
+
/** The Worker-kind implementation for the remote executor. */
|
|
39
|
+
export interface RemoteWorker<M extends RemoteMachine> {
|
|
40
|
+
/** Reported as `Executor.kind`; the scheduler rejects Workers of other kinds. */
|
|
41
|
+
readonly kind: WorkerKind;
|
|
42
|
+
/** The span name prefix, for example `ExeDevExecutor`. */
|
|
43
|
+
readonly spanPrefix: string;
|
|
44
|
+
readonly label: string;
|
|
45
|
+
readonly commands: RemoteCommands;
|
|
46
|
+
/** Returns a Worker's machine. Fails with a typed error if the machine is missing or doesn't respond. */
|
|
47
|
+
readonly machineFor: (worker: WorkerName) => Effect.Effect<M, ExecutorError>;
|
|
48
|
+
/** See `Executor.preflight`. */
|
|
49
|
+
readonly preflight: (worker: WorkerName, brains: ReadonlyArray<BrainSpec>, maxConcurrentAttempts: number) => Effect.Effect<void, ExecutorError>;
|
|
50
|
+
readonly harnessProbe: (machine: M) => HarnessProbe;
|
|
51
|
+
/** Returns the URL the cached clone on `machine` fetches `repository` from. */
|
|
52
|
+
readonly repositoryUrl: (machine: M, repository: RepositoryName) => string;
|
|
53
|
+
/** 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. */
|
|
54
|
+
readonly gatewayCredential: (machine: M, harness: Harness) => Effect.Effect<Option.Option<GatewayCredentialKind>>;
|
|
55
|
+
/** Returns the access grant for `repository`. Fails if none is configured. */
|
|
56
|
+
readonly grantFor: (repository: RepositoryName) => Effect.Effect<RemoteGrant<M>, CredentialUnavailableError>;
|
|
57
|
+
/** The reason this Worker kind can't grant read-only repository access, or `None` if it can. */
|
|
58
|
+
readonly readOnlyAccessGap: Option.Option<string>;
|
|
59
|
+
/** Removes leftovers of earlier processes that no Attempt can use. Runs before the Worker's checkouts are listed. */
|
|
60
|
+
readonly reclaim: (worker: WorkerName) => Effect.Effect<void>;
|
|
61
|
+
/** The timeout for the parent task's cancellation, then separately for the Attempt to finish. */
|
|
62
|
+
readonly interruptGrace: Parameters<typeof Effect.timeoutOption>[1];
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/remote/machine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,4GAA4G;IAC5G,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,0IAA0I;IAC1I,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,uIAAuI;IACvI,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,gHAAgH;IAChH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACrD,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,aAAa;IAClD;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,CAChB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,eAAe,EAC5B,OAAO,EAAE,CAAC,EACV,SAAS,EAAE,iBAAiB,KACzB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;CAC9D;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,aAAa;IACnD,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,yGAAyG;IACzG,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAC7E,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,CAClB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,EAChC,qBAAqB,EAAE,MAAM,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACxC,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,YAAY,CAAC;IACpD,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,cAAc,KAAK,MAAM,CAAC;IAC3E,uKAAuK;IACvK,QAAQ,CAAC,iBAAiB,EAAE,CAC1B,OAAO,EAAE,CAAC,EACV,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACzD,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,CACjB,UAAU,EAAE,cAAc,KACvB,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;IAC/D,gGAAgG;IAChG,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,qHAAqH;IACrH,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9D,iGAAiG;IACjG,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;CACrE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.js","sourceRoot":"","sources":["../../src/remote/machine.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ClaudeLoginLock } from "@usine/agents/runtime";
|
|
2
|
+
import { type AttemptFailure } from "@usine/core/attempt/failure";
|
|
3
|
+
import type { AttemptRecovery, RecoverySink } from "@usine/core/attempt/salvage";
|
|
4
|
+
import type * as AttemptChannel from "@usine/core/attempt/channel";
|
|
5
|
+
import { AttemptRuntime } from "@usine/durable/attempt-runtime";
|
|
6
|
+
import { Effect, Option, Scope } from "effect";
|
|
7
|
+
import { CheckoutRequest, ExecutorError } from "../executor.ts";
|
|
8
|
+
import type { RemoteMachine, RemoteWorker } from "./machine.ts";
|
|
9
|
+
/**
|
|
10
|
+
* Returns the executor for Workers accessed over SSH. Each Attempt's Pi parent is a durable task
|
|
11
|
+
* in this process, and each child runs on the machine as one SSH command with a pid file next
|
|
12
|
+
* to the worktree. `worker` provides the machine, preflight, and repository access.
|
|
13
|
+
*/
|
|
14
|
+
export declare const remoteExecutorFor: <M extends RemoteMachine>(worker: RemoteWorker<M>) => Effect.Effect<{
|
|
15
|
+
readonly recover: <E>(attempt: AttemptRecovery, record: RecoverySink<E>) => Effect.Effect<void, E | ExecutorError>;
|
|
16
|
+
readonly kind: import("@usine/core/worker").WorkerKind;
|
|
17
|
+
readonly isLive: (attemptId: import("@usine/core/attempt").AttemptId) => Effect.Effect<boolean, AttemptFailure>;
|
|
18
|
+
readonly outcome: (attemptId: import("@usine/core/attempt").AttemptId) => Effect.Effect<Option.Option<import("effect/Result").Result<import("@usine/core/step/result").StepResult, AttemptFailure>>, AttemptFailure>;
|
|
19
|
+
readonly preflight: (worker: import("@usine/core/worker").WorkerName, brains: ReadonlyArray<import("@usine/core/agent/brain").BrainSpec>, maxConcurrentAttempts: number) => Effect.Effect<void, ExecutorError>;
|
|
20
|
+
readonly prepare: (request: CheckoutRequest) => Effect.Effect<import("../executor.ts").PreparedAttempt, ExecutorError, Scope.Scope>;
|
|
21
|
+
readonly cancel: (attemptId: import("@usine/core/attempt").AttemptId) => Effect.Effect<void, ExecutorError>;
|
|
22
|
+
readonly intervene: (attemptId: import("@usine/core/attempt").AttemptId, intervention: AttemptChannel.Intervention) => Effect.Effect<void, AttemptFailure>;
|
|
23
|
+
}, never, AttemptRuntime | ClaudeLoginLock | Scope.Scope>;
|
|
24
|
+
//# 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;AACxD,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;AAOnE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAY,MAAM,EAAQ,MAAM,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvE,OAAO,EAEL,eAAe,EAEf,aAAa,EAId,MAAM,gBAAgB,CAAC;AAcxB,OAAO,KAAK,EAAgB,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAgB9E;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,aAAa,UAAU,YAAY,CAAC,CAAC,CAAC;;;;;;;;;yDA6b9E,CAAC"}
|