@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,308 @@
|
|
|
1
|
+
import { CHILD_KILL_SCRIPT } from "@usine/agents/child-host";
|
|
2
|
+
import { ClaudeLoginLock } from "@usine/agents/runtime";
|
|
3
|
+
import { InfraFailure } from "@usine/core/attempt/failure";
|
|
4
|
+
import { RepositoryName, safeSegment } from "@usine/core/repository";
|
|
5
|
+
import { harvestFacts, harvestPostedComments, } from "@usine/core/step/harvest";
|
|
6
|
+
import { AttemptRuntime } from "@usine/durable/attempt-runtime";
|
|
7
|
+
import { Deferred, Effect, Exit, Option, Schema, Scope } from "effect";
|
|
8
|
+
import { durableSessionFor } from "../durable-session.js";
|
|
9
|
+
import { CheckoutRequest, Executor, ExecutorError, ExecutorOperationError, WorkerCapabilityError, } from "../executor.js";
|
|
10
|
+
import { verifyHarnessReadiness } from "../harness-preflight.js";
|
|
11
|
+
import { keyedLockFor } from "../keyed-lock.js";
|
|
12
|
+
import { withGitHooks } from "../pre-push-hook.js";
|
|
13
|
+
import { cacheDirectoryName, provisionWorktree, reattachWorktree, recoverWorktree, } from "../provision.js";
|
|
14
|
+
import { workerLeftoversFor } from "./leftovers.js";
|
|
15
|
+
import { workerWatchesFor } from "./liveness.js";
|
|
16
|
+
import { abandonedWorktreeSweepFor } from "./sweep.js";
|
|
17
|
+
const isExecutorError = Schema.is(ExecutorError);
|
|
18
|
+
const executorError = (message, cause) => new ExecutorOperationError({ operation: "prepare", message, cause });
|
|
19
|
+
/** A script that writes `$2` to the file `$1`, creating its directory, and makes it executable. */
|
|
20
|
+
const WRITE_EXECUTABLE_SCRIPT = String.raw `
|
|
21
|
+
set -e
|
|
22
|
+
mkdir -p "$(dirname "$1")"
|
|
23
|
+
printf '%s' "$2" > "$1"
|
|
24
|
+
chmod 755 "$1"
|
|
25
|
+
`.trim();
|
|
26
|
+
/**
|
|
27
|
+
* Returns the executor for Workers accessed over SSH. Each Attempt's Pi parent is a durable task
|
|
28
|
+
* in this process, and each child runs on the machine as one SSH command with a pid file next
|
|
29
|
+
* to the worktree. `worker` provides the machine, preflight, and repository access.
|
|
30
|
+
*/
|
|
31
|
+
export const remoteExecutorFor = (worker) => Effect.gen(function* () {
|
|
32
|
+
const { commands, label } = worker;
|
|
33
|
+
const span = (name) => `${worker.spanPrefix}.${name}`;
|
|
34
|
+
const fetches = yield* keyedLockFor();
|
|
35
|
+
const logins = yield* ClaudeLoginLock;
|
|
36
|
+
const sweepAbandonedWorktrees = yield* abandonedWorktreeSweepFor(commands);
|
|
37
|
+
const workerLeftovers = yield* workerLeftoversFor(commands, worker.machineFor, worker.reclaim);
|
|
38
|
+
const session = yield* durableSessionFor({ interruptGrace: worker.interruptGrace });
|
|
39
|
+
const runtime = yield* AttemptRuntime;
|
|
40
|
+
const workerWatches = yield* workerWatchesFor(commands);
|
|
41
|
+
const stopChildren = Effect.fn(span("stopChildren"))(function* (operation, machine, worktree) {
|
|
42
|
+
const host = machine.shell.destination;
|
|
43
|
+
yield* Effect.annotateCurrentSpan({ host, worktree });
|
|
44
|
+
const outcome = yield* commands.run(operation, machine.shell, "sh", [
|
|
45
|
+
"-c",
|
|
46
|
+
CHILD_KILL_SCRIPT,
|
|
47
|
+
"sh",
|
|
48
|
+
worktree,
|
|
49
|
+
]);
|
|
50
|
+
yield* Effect.logInfo("Confirmed no child of the Attempt runs on the Worker's machine", {
|
|
51
|
+
host,
|
|
52
|
+
worktree,
|
|
53
|
+
children: outcome.trim().split("\n"),
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
/** Runs git on the machine with the Attempt's repository access, refreshing the credential first if it's about to expire. */
|
|
57
|
+
const accessGit = (operation, access) => (args) => access.refresh.pipe(Effect.andThen(commands.run(operation, access.shell, "git", args, {
|
|
58
|
+
environment: access.gitEnvironment,
|
|
59
|
+
scrub: access.scrub,
|
|
60
|
+
})));
|
|
61
|
+
const harvestCommand = (operation, worktree, access) => (command, args) => access.refresh
|
|
62
|
+
.pipe(Effect.andThen(commands.run(operation, access.shell, command, args, {
|
|
63
|
+
cwd: worktree,
|
|
64
|
+
environment: access.environment,
|
|
65
|
+
scrub: access.scrub,
|
|
66
|
+
})))
|
|
67
|
+
.pipe(Effect.map((stdout) => (stdout === "" ? [] : stdout.replace(/\n$/u, "").split("\n"))));
|
|
68
|
+
const recover = Effect.fn(span("recover"))(function* (attempt, record) {
|
|
69
|
+
yield* Effect.annotateCurrentSpan({ ...attempt });
|
|
70
|
+
yield* session.stopForRecovery(attempt);
|
|
71
|
+
const { machine, checkouts } = yield* workerLeftovers(attempt.worker);
|
|
72
|
+
const worktree = `${machine.workerDirectory}/attempts/${safeSegment(attempt.attemptId)}`;
|
|
73
|
+
const inspectCheckout = Effect.gen(function* () {
|
|
74
|
+
const inspected = yield* commands.inspect("cleanup", machine.shell, "test", [
|
|
75
|
+
"-d",
|
|
76
|
+
worktree,
|
|
77
|
+
]);
|
|
78
|
+
if (inspected.exitCode === 1)
|
|
79
|
+
return false;
|
|
80
|
+
if (inspected.exitCode !== 0)
|
|
81
|
+
return yield* executorError("Can't inspect the recovery checkout", new Error(inspected.stderr));
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
// Checks the cached listing first to avoid an SSH round trip per persisted Attempt.
|
|
85
|
+
const present = checkouts.has(worktree) && (yield* inspectCheckout);
|
|
86
|
+
yield* session.recoverPostedComments(attempt, present
|
|
87
|
+
? Option.some((spec, windows) => Effect.scoped(Effect.gen(function* () {
|
|
88
|
+
const grant = yield* worker.grantFor(attempt.repository);
|
|
89
|
+
const access = yield* grant.acquire(attempt.attemptId, attempt.worker, attempt.permissions, machine, "cleanup");
|
|
90
|
+
return yield* harvestPostedComments(spec, harvestCommand("cleanup", worktree, access), windows);
|
|
91
|
+
})))
|
|
92
|
+
: Option.none(), record);
|
|
93
|
+
if (!present)
|
|
94
|
+
return;
|
|
95
|
+
const reconcile = (git) => recoverWorktree({
|
|
96
|
+
attempt,
|
|
97
|
+
host: machine.shell.destination,
|
|
98
|
+
worktree,
|
|
99
|
+
cache: `${machine.workerDirectory}/repos/${cacheDirectoryName(attempt.repository)}`,
|
|
100
|
+
git,
|
|
101
|
+
}, record.salvage);
|
|
102
|
+
if (attempt.succeeded || attempt.permissions === "read") {
|
|
103
|
+
yield* stopChildren("cleanup", machine, worktree);
|
|
104
|
+
yield* reconcile((args) => commands.run("cleanup", machine.shell, "git", args));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const grant = yield* worker.grantFor(attempt.repository);
|
|
108
|
+
yield* Effect.scoped(Effect.gen(function* () {
|
|
109
|
+
const access = yield* grant.acquire(attempt.attemptId, attempt.worker, attempt.permissions, machine, "cleanup");
|
|
110
|
+
yield* stopChildren("cleanup", machine, worktree);
|
|
111
|
+
yield* reconcile(accessGit("cleanup", access));
|
|
112
|
+
}));
|
|
113
|
+
});
|
|
114
|
+
const harvest = (workspace, access, windows) => harvestFacts(workspace.spec, harvestCommand("launch", workspace.worktree, access), windows).pipe(Effect.mapError((error) => new InfraFailure({
|
|
115
|
+
message: `Can't harvest the attempt's checkout: ${error.message}`,
|
|
116
|
+
cause: error,
|
|
117
|
+
})));
|
|
118
|
+
/**
|
|
119
|
+
* Checks that a reattached Attempt's parent task was created for this worktree and the
|
|
120
|
+
* worktree still exists, then stops children left from before the restart. Returns the
|
|
121
|
+
* parent's RunSpec.
|
|
122
|
+
*/
|
|
123
|
+
const takeOver = Effect.fn(span("takeOver"))(function* (request, machine, worktree) {
|
|
124
|
+
const { cwd, spec } = yield* session.storedRequest(request.attemptId);
|
|
125
|
+
if (cwd !== worktree)
|
|
126
|
+
return yield* executorError(`The reattached attempt's checkout isn't on the machine of this ${label} worker`, new Error(cwd));
|
|
127
|
+
const inspected = yield* commands.inspect("prepare", machine.shell, "test", ["-d", worktree]);
|
|
128
|
+
if (inspected.exitCode === 1)
|
|
129
|
+
return yield* executorError("The reattached attempt's checkout no longer exists", new Error(worktree));
|
|
130
|
+
if (inspected.exitCode !== 0)
|
|
131
|
+
return yield* executorError("Can't inspect the reattached attempt's checkout", new Error(inspected.stderr.trim()));
|
|
132
|
+
yield* stopChildren("prepare", machine, worktree);
|
|
133
|
+
return spec;
|
|
134
|
+
});
|
|
135
|
+
/** Returns the `WorkspaceOps` for the machine; git runs with the Attempt's repository access. */
|
|
136
|
+
const workspaceOps = (request, machine, access, layout) => ({
|
|
137
|
+
ensureRoots: Effect.asVoid(commands.run("prepare", machine.shell, "mkdir", [
|
|
138
|
+
"-p",
|
|
139
|
+
`${machine.workerDirectory}/repos`,
|
|
140
|
+
`${machine.workerDirectory}/attempts`,
|
|
141
|
+
])),
|
|
142
|
+
removePath: (operation, target) => Effect.asVoid(commands.run(operation, machine.shell, "rm", ["-rf", target])),
|
|
143
|
+
cacheExists: Effect.gen(function* () {
|
|
144
|
+
const inspected = yield* commands.inspect("prepare", machine.shell, "test", [
|
|
145
|
+
"-d",
|
|
146
|
+
layout.cache,
|
|
147
|
+
]);
|
|
148
|
+
if (inspected.exitCode === 0)
|
|
149
|
+
return true;
|
|
150
|
+
if (inspected.exitCode === 1)
|
|
151
|
+
return false;
|
|
152
|
+
return yield* executorError(`Can't inspect the cached clone on worker "${request.worker}"`, new Error(inspected.stderr.trim()));
|
|
153
|
+
}),
|
|
154
|
+
promoteStaging: Effect.asVoid(commands.run("prepare", machine.shell, "mv", [layout.staging, layout.cache])),
|
|
155
|
+
git: (operation, args) => accessGit(operation, access)(args),
|
|
156
|
+
writeExecutable: (target, content) => Effect.asVoid(commands.run("prepare", machine.shell, "sh", [
|
|
157
|
+
"-c",
|
|
158
|
+
WRITE_EXECUTABLE_SCRIPT,
|
|
159
|
+
"sh",
|
|
160
|
+
target,
|
|
161
|
+
content,
|
|
162
|
+
])),
|
|
163
|
+
});
|
|
164
|
+
const prepare = Effect.fn(span("prepare"))(function* (request) {
|
|
165
|
+
yield* Effect.annotateCurrentSpan({
|
|
166
|
+
attemptId: request.attemptId,
|
|
167
|
+
worker: request.worker,
|
|
168
|
+
repository: request.repository,
|
|
169
|
+
loop: request.loop,
|
|
170
|
+
permissions: request.permissions,
|
|
171
|
+
reattach: request.reattach,
|
|
172
|
+
});
|
|
173
|
+
if (request.permissions === "read" && Option.isSome(worker.readOnlyAccessGap)) {
|
|
174
|
+
const message = `${label} worker "${request.worker}" can't run loop "${request.loop}", which has permissions: read. ${worker.readOnlyAccessGap.value}.`;
|
|
175
|
+
yield* Effect.logWarning("Refused an Attempt that needs read-only repository access", {
|
|
176
|
+
attemptId: request.attemptId,
|
|
177
|
+
worker: request.worker,
|
|
178
|
+
loop: request.loop,
|
|
179
|
+
permissions: request.permissions,
|
|
180
|
+
message,
|
|
181
|
+
});
|
|
182
|
+
return yield* new WorkerCapabilityError({
|
|
183
|
+
worker: request.worker,
|
|
184
|
+
capability: "credentials",
|
|
185
|
+
message,
|
|
186
|
+
cause: new Error(worker.readOnlyAccessGap.value),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const grant = yield* worker.grantFor(request.repository);
|
|
190
|
+
const machine = yield* worker.machineFor(request.worker);
|
|
191
|
+
yield* verifyHarnessReadiness(request.worker, [request.agent.brain], worker.harnessProbe(machine), logins);
|
|
192
|
+
const host = machine.shell.destination;
|
|
193
|
+
const cache = `${machine.workerDirectory}/repos/${cacheDirectoryName(request.repository)}`;
|
|
194
|
+
const worktree = `${machine.workerDirectory}/attempts/${safeSegment(request.attemptId)}`;
|
|
195
|
+
const staging = `${cache}.cloning`;
|
|
196
|
+
yield* Effect.annotateCurrentSpan({ host });
|
|
197
|
+
yield* Effect.logInfo(request.reattach
|
|
198
|
+
? `Reattaching the Attempt to its ${label} checkout`
|
|
199
|
+
: `Preparing ${label} Attempt workspace`, {
|
|
200
|
+
attemptId: request.attemptId,
|
|
201
|
+
worker: request.worker,
|
|
202
|
+
host,
|
|
203
|
+
repository: request.repository,
|
|
204
|
+
loop: request.loop,
|
|
205
|
+
permissions: request.permissions,
|
|
206
|
+
worktree,
|
|
207
|
+
});
|
|
208
|
+
yield* sweepAbandonedWorktrees(request.attemptId, request.worker, machine.shell, machine.workerDirectory);
|
|
209
|
+
// A reattachment reuses its checkout before any credential is granted.
|
|
210
|
+
const reattached = request.reattach
|
|
211
|
+
? Option.some(yield* takeOver(request, machine, worktree))
|
|
212
|
+
: Option.none();
|
|
213
|
+
// A checkout kept after a failed remote stop never closes its scope, so its salvage result
|
|
214
|
+
// is completed here instead of by the checkout finalizer.
|
|
215
|
+
const salvaged = yield* Deferred.make();
|
|
216
|
+
const releaseWorkspace = Effect.fn(span("releaseWorkspace"))(function* (resource, exit) {
|
|
217
|
+
yield* Effect.annotateCurrentSpan({
|
|
218
|
+
attemptId: request.attemptId,
|
|
219
|
+
worker: request.worker,
|
|
220
|
+
host,
|
|
221
|
+
});
|
|
222
|
+
// Closes the checkout scope only if stopping the remote children succeeds.
|
|
223
|
+
yield* stopChildren("cleanup", machine, resource.provisioned.workspace.worktree);
|
|
224
|
+
yield* Scope.close(resource.scope, exit);
|
|
225
|
+
const salvage = yield* Effect.exit(resource.provisioned.salvaged);
|
|
226
|
+
yield* Deferred.done(salvaged, salvage);
|
|
227
|
+
}, (effect) => effect.pipe(Effect.tapError((error) => Effect.logError("Remote termination failed; Attempt checkout retained for recovery", {
|
|
228
|
+
attemptId: request.attemptId,
|
|
229
|
+
worker: request.worker,
|
|
230
|
+
host,
|
|
231
|
+
worktree,
|
|
232
|
+
message: error.message,
|
|
233
|
+
})), Effect.ignore, Effect.andThen(Deferred.succeed(salvaged, Option.none()))));
|
|
234
|
+
const acquire = Effect.gen(function* () {
|
|
235
|
+
// Credentials are scoped to the Attempt, not the checkout, so they are released exactly once
|
|
236
|
+
// even when checkout cleanup is skipped.
|
|
237
|
+
const access = yield* grant.acquire(request.attemptId, request.worker, request.permissions, machine, "prepare");
|
|
238
|
+
const ops = workspaceOps(request, machine, access, { cache, staging });
|
|
239
|
+
const checkout = Option.match(reattached, {
|
|
240
|
+
onNone: () => provisionWorktree({
|
|
241
|
+
request,
|
|
242
|
+
url: worker.repositoryUrl(machine, request.repository),
|
|
243
|
+
host,
|
|
244
|
+
layout: { cache, staging, worktree },
|
|
245
|
+
ops,
|
|
246
|
+
}),
|
|
247
|
+
onSome: (spec) => reattachWorktree({ request, host, layout: { cache, worktree }, ops, spec }),
|
|
248
|
+
});
|
|
249
|
+
const { provisioned } = yield* Effect.acquireRelease(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
250
|
+
const scope = yield* Scope.make();
|
|
251
|
+
// No child can exist before preparation succeeds, so a partial checkout is always rolled
|
|
252
|
+
// back; only a completed workspace uses the guarded release above.
|
|
253
|
+
const provisioned = yield* restore(checkout).pipe(Scope.provide(scope), Effect.onError((cause) => Scope.close(scope, Exit.failCause(cause))));
|
|
254
|
+
return { provisioned, scope };
|
|
255
|
+
})), releaseWorkspace, { interruptible: true });
|
|
256
|
+
return { provisioned, access };
|
|
257
|
+
});
|
|
258
|
+
const { provisioned, access } = yield* (request.reattach ? acquire : fetches.withLock(request.repository)(acquire)).pipe(Effect.mapError((cause) => isExecutorError(cause)
|
|
259
|
+
? cause
|
|
260
|
+
: executorError(`Can't prepare the ${label} attempt workspace`, cause)));
|
|
261
|
+
const prepared = provisioned.workspace;
|
|
262
|
+
yield* Effect.logInfo(`${label} Attempt workspace ready`, {
|
|
263
|
+
attemptId: request.attemptId,
|
|
264
|
+
worker: request.worker,
|
|
265
|
+
host,
|
|
266
|
+
repository: request.repository,
|
|
267
|
+
baseCommit: prepared.spec.baseCommit,
|
|
268
|
+
resume: Option.map(prepared.spec.resume, ({ ref }) => ref),
|
|
269
|
+
reattach: request.reattach,
|
|
270
|
+
worktree,
|
|
271
|
+
});
|
|
272
|
+
return {
|
|
273
|
+
workspace: prepared,
|
|
274
|
+
launch: (io) => Effect.scoped(Effect.gen(function* () {
|
|
275
|
+
// Uses the RunSpec's brain, including on reattachment. Each child reads the kind when it
|
|
276
|
+
// starts, so a preflight during the Attempt takes effect.
|
|
277
|
+
const gatewayCredential = worker.gatewayCredential(machine, prepared.spec.agent.brain.harness);
|
|
278
|
+
yield* workerWatches.watch({
|
|
279
|
+
attemptId: request.attemptId,
|
|
280
|
+
worker: request.worker,
|
|
281
|
+
shell: machine.shell,
|
|
282
|
+
report: (notice) => runtime.notify(request.attemptId, notice),
|
|
283
|
+
});
|
|
284
|
+
return yield* session.launch(prepared, io, {
|
|
285
|
+
host: access.shell,
|
|
286
|
+
environment: withGitHooks(access.environment, provisioned.gitHooks),
|
|
287
|
+
gatewayCredential,
|
|
288
|
+
harvest: (windows) => harvest(prepared, access, windows),
|
|
289
|
+
harvestComments: (windows) => harvestPostedComments(prepared.spec, harvestCommand("launch", prepared.worktree, access), windows),
|
|
290
|
+
keepForReattach: provisioned.keepForReattach,
|
|
291
|
+
});
|
|
292
|
+
})),
|
|
293
|
+
salvaged: Deferred.await(salvaged),
|
|
294
|
+
recordSalvage: provisioned.recordSalvage,
|
|
295
|
+
};
|
|
296
|
+
}, session.prepare);
|
|
297
|
+
return Executor.of({
|
|
298
|
+
kind: worker.kind,
|
|
299
|
+
recover,
|
|
300
|
+
cancel: session.cancel,
|
|
301
|
+
intervene: session.intervene,
|
|
302
|
+
isLive: session.isLive,
|
|
303
|
+
outcome: session.outcome,
|
|
304
|
+
preflight: worker.preflight,
|
|
305
|
+
prepare,
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/remote/remote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RemoteShell } from "@usine/agents/child-host";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { ExecutorOperationError } from "../executor.ts";
|
|
4
|
+
import type { RemoteCommands } from "./commands.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Lists paths directly under a Worker's `attempts` directory, creating it first so a new Worker
|
|
7
|
+
* lists as empty. Verifies that each path is a direct child of `attemptsRoot`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const attemptPathsOn: (commands: RemoteCommands, operation: "cancel" | "cleanup" | "launch" | "preflight" | "prepare", shell: RemoteShell, attemptsRoot: string) => Effect.Effect<readonly string[], ExecutorOperationError, never>;
|
|
10
|
+
/**
|
|
11
|
+
* Returns a sweep that prunes stale cache registrations once per Worker and keeps crash
|
|
12
|
+
* leftovers. Only durable Attempt recovery removes an existing checkout.
|
|
13
|
+
*/
|
|
14
|
+
export declare const abandonedWorktreeSweepFor: (commands: RemoteCommands) => Effect.Effect<(attemptId: string & import("effect/Brand").Brand<"AttemptId">, worker: string & import("effect/Brand").Brand<"WorkerName">, shell: RemoteShell, workerDirectory: string) => Effect.Effect<void, never, never>, never, never>;
|
|
15
|
+
//# sourceMappingURL=sweep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../../src/remote/sweep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAAE,MAAM,EAAe,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAA0B,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAyCpD;;;GAGG;AACH,eAAO,MAAM,cAAc,+MAiBzB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,2QA0GrC,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { AttemptId } from "@usine/core/attempt";
|
|
2
|
+
import { WorkerName } from "@usine/core/worker";
|
|
3
|
+
import { Effect, Ref, Schema } from "effect";
|
|
4
|
+
import { ExecutorOperationError } from "../executor.js";
|
|
5
|
+
import { keyedLockFor } from "../keyed-lock.js";
|
|
6
|
+
const SWEEP_CONCURRENCY = 4;
|
|
7
|
+
const directChildSchema = (parent) => {
|
|
8
|
+
const prefix = `${parent}/`;
|
|
9
|
+
return Schema.String.check(Schema.makeFilter((value) => {
|
|
10
|
+
const segment = value.slice(prefix.length);
|
|
11
|
+
return (value.startsWith(prefix) &&
|
|
12
|
+
segment.length > 0 &&
|
|
13
|
+
segment !== "." &&
|
|
14
|
+
segment !== ".." &&
|
|
15
|
+
!segment.includes("/"));
|
|
16
|
+
}, { message: `Expected a direct child of ${parent}` }));
|
|
17
|
+
};
|
|
18
|
+
const directChildren = (operation, parent, output) => Schema.decodeUnknownEffect(Schema.Array(directChildSchema(parent)))(output.split("\0").filter((value) => value.length > 0)).pipe(Effect.mapError((cause) => new ExecutorOperationError({
|
|
19
|
+
operation,
|
|
20
|
+
message: `Worker returned an invalid path while listing ${parent}`,
|
|
21
|
+
cause,
|
|
22
|
+
})));
|
|
23
|
+
/**
|
|
24
|
+
* Lists paths directly under a Worker's `attempts` directory, creating it first so a new Worker
|
|
25
|
+
* lists as empty. Verifies that each path is a direct child of `attemptsRoot`.
|
|
26
|
+
*/
|
|
27
|
+
export const attemptPathsOn = Effect.fn("RemoteExecutor.attemptPathsOn")(function* (commands, operation, shell, attemptsRoot) {
|
|
28
|
+
yield* Effect.annotateCurrentSpan({ host: shell.destination, operation, attemptsRoot });
|
|
29
|
+
yield* commands.run(operation, shell, "mkdir", ["-p", attemptsRoot]);
|
|
30
|
+
const output = yield* commands.run(operation, shell, "find", [
|
|
31
|
+
attemptsRoot,
|
|
32
|
+
"-mindepth",
|
|
33
|
+
"1",
|
|
34
|
+
"-maxdepth",
|
|
35
|
+
"1",
|
|
36
|
+
"-print0",
|
|
37
|
+
]);
|
|
38
|
+
return yield* directChildren(operation, attemptsRoot, output);
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Returns a sweep that prunes stale cache registrations once per Worker and keeps crash
|
|
42
|
+
* leftovers. Only durable Attempt recovery removes an existing checkout.
|
|
43
|
+
*/
|
|
44
|
+
export const abandonedWorktreeSweepFor = Effect.fn("RemoteExecutor.abandonedWorktreeSweepFor")(function* (commands) {
|
|
45
|
+
const locks = yield* keyedLockFor();
|
|
46
|
+
const swept = yield* Ref.make(new Set());
|
|
47
|
+
const sweep = Effect.fn("RemoteExecutor.sweepAbandonedWorktrees")(function* (attemptId, worker, shell, workerDirectory) {
|
|
48
|
+
const host = shell.destination;
|
|
49
|
+
yield* Effect.annotateCurrentSpan({ attemptId, worker, host });
|
|
50
|
+
yield* locks.withLock(worker)(Effect.gen(function* () {
|
|
51
|
+
if ((yield* Ref.get(swept)).has(worker)) {
|
|
52
|
+
yield* Effect.logDebug("Remote abandoned-worktree sweep was already complete", {
|
|
53
|
+
attemptId,
|
|
54
|
+
worker,
|
|
55
|
+
host,
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Marked done before running so a failed sweep is not retried before every prepare; the
|
|
60
|
+
// next process start retries it.
|
|
61
|
+
yield* Ref.update(swept, (current) => new Set(current).add(worker));
|
|
62
|
+
const attemptsRoot = `${workerDirectory}/attempts`;
|
|
63
|
+
const reposRoot = `${workerDirectory}/repos`;
|
|
64
|
+
yield* Effect.logInfo("Sweeping abandoned Attempt worktrees on the remote Worker", {
|
|
65
|
+
attemptId,
|
|
66
|
+
worker,
|
|
67
|
+
host,
|
|
68
|
+
});
|
|
69
|
+
yield* commands.run("prepare", shell, "mkdir", ["-p", reposRoot]);
|
|
70
|
+
const attempts = yield* attemptPathsOn(commands, "prepare", shell, attemptsRoot);
|
|
71
|
+
// An unrecognized path can contain unsalvaged work from a crash; only recovery from the
|
|
72
|
+
// durable Attempt record removes it.
|
|
73
|
+
yield* Effect.forEach(attempts, (worktree) => Effect.logWarning("Preserving abandoned remote path for salvage reconciliation", {
|
|
74
|
+
attemptId,
|
|
75
|
+
worker,
|
|
76
|
+
host,
|
|
77
|
+
worktree,
|
|
78
|
+
}), { discard: true });
|
|
79
|
+
const caches = yield* commands
|
|
80
|
+
.run("prepare", shell, "find", [
|
|
81
|
+
reposRoot,
|
|
82
|
+
"-mindepth",
|
|
83
|
+
"1",
|
|
84
|
+
"-maxdepth",
|
|
85
|
+
"1",
|
|
86
|
+
"-type",
|
|
87
|
+
"d",
|
|
88
|
+
"-name",
|
|
89
|
+
"*.git",
|
|
90
|
+
"-print0",
|
|
91
|
+
])
|
|
92
|
+
.pipe(Effect.flatMap((output) => directChildren("prepare", reposRoot, output)));
|
|
93
|
+
yield* Effect.forEach(caches, (cache) => commands.run("prepare", shell, "git", ["--git-dir", cache, "worktree", "prune"]).pipe(Effect.tapError((error) => Effect.logWarning("Could not prune a remote cache during the sweep", {
|
|
94
|
+
attemptId,
|
|
95
|
+
worker,
|
|
96
|
+
host,
|
|
97
|
+
cache,
|
|
98
|
+
message: error.message,
|
|
99
|
+
})), Effect.ignore), { concurrency: SWEEP_CONCURRENCY, discard: true });
|
|
100
|
+
yield* Effect.logInfo("Remote abandoned-worktree sweep completed", {
|
|
101
|
+
attemptId,
|
|
102
|
+
worker,
|
|
103
|
+
host,
|
|
104
|
+
retained: attempts.length,
|
|
105
|
+
caches: caches.length,
|
|
106
|
+
});
|
|
107
|
+
}).pipe(Effect.tapError((error) => Effect.logWarning("Remote abandoned-worktree sweep failed; continuing", {
|
|
108
|
+
attemptId,
|
|
109
|
+
worker,
|
|
110
|
+
host,
|
|
111
|
+
message: error.message,
|
|
112
|
+
})), Effect.ignore));
|
|
113
|
+
});
|
|
114
|
+
return sweep;
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=sweep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep.js","sourceRoot":"","sources":["../../src/remote/sweep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AttemptId } from "@usine/core/attempt";
|
|
2
|
+
import type { LoopPermissions } from "@usine/core/loop";
|
|
3
|
+
import type { RepositoryName } from "@usine/core/repository";
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
import type { CredentialUnavailableError, WorkerCredential } from "./executor.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Issues the Attempt's single-repository token with its Loop `permissions`, passes it to
|
|
8
|
+
* `publish`, and publishes a new one before each expiry until the caller's scope closes. Then
|
|
9
|
+
* wipes every issued token, so `Redacted.value` throws. Register cleanup for what `publish`
|
|
10
|
+
* writes before calling this, so the cleanup runs after renewal stops.
|
|
11
|
+
*/
|
|
12
|
+
export declare const renewableCredential: <A, E>(issue: (repository: RepositoryName, attemptId: AttemptId, permissions: LoopPermissions) => Effect.Effect<WorkerCredential, CredentialUnavailableError>, repository: string & import("effect/Brand").Brand<"RepositoryName">, attemptId: string & import("effect/Brand").Brand<"AttemptId">, permissions: "read" | "write", publish: (credential: WorkerCredential) => Effect.Effect<A, E>) => Effect.Effect<{
|
|
13
|
+
published: A;
|
|
14
|
+
refresh: () => Effect.Effect<void, E | CredentialUnavailableError, never>;
|
|
15
|
+
scrub: (text: string) => string;
|
|
16
|
+
}, E | CredentialUnavailableError, import("effect/Scope").Scope>;
|
|
17
|
+
//# sourceMappingURL=renewable-credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renewable-credential.d.ts","sourceRoot":"","sources":["../src/renewable-credential.ts"],"names":[],"mappings":"AAAA,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,EAAmB,MAAM,EAA6B,MAAM,QAAQ,CAAC;AAC5E,OAAO,KAAK,EAEV,0BAA0B,EAC1B,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAcvB;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAwD,CAAC,EAAE,CAAC,mVAKpE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;;kBAoD9C,MAAM,KAAG,MAAM;gEAK/B,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Clock, DateTime, Effect, Redacted, SynchronizedRef } from "effect";
|
|
2
|
+
/** The remaining lifetime, in milliseconds, below which a new token is issued. */
|
|
3
|
+
const RENEWAL_WINDOW_MILLIS = 5 * 60_000;
|
|
4
|
+
/**
|
|
5
|
+
* Issues the Attempt's single-repository token with its Loop `permissions`, passes it to
|
|
6
|
+
* `publish`, and publishes a new one before each expiry until the caller's scope closes. Then
|
|
7
|
+
* wipes every issued token, so `Redacted.value` throws. Register cleanup for what `publish`
|
|
8
|
+
* writes before calling this, so the cleanup runs after renewal stops.
|
|
9
|
+
*/
|
|
10
|
+
export const renewableCredential = Effect.fn("Executor.renewableCredential")(function* (issue, repository, attemptId, permissions, publish) {
|
|
11
|
+
yield* Effect.annotateCurrentSpan({ repository, attemptId, permissions });
|
|
12
|
+
const issued = new Set();
|
|
13
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => {
|
|
14
|
+
for (const token of issued)
|
|
15
|
+
Redacted.wipeUnsafe(token);
|
|
16
|
+
}));
|
|
17
|
+
const publishFresh = Effect.fn("Executor.publishCredential")(function* () {
|
|
18
|
+
yield* Effect.annotateCurrentSpan({ repository, attemptId, permissions });
|
|
19
|
+
const credential = yield* issue(repository, attemptId, permissions);
|
|
20
|
+
issued.add(credential.value);
|
|
21
|
+
const published = yield* publish(credential);
|
|
22
|
+
yield* Effect.logInfo("Published renewed Attempt repository credential", {
|
|
23
|
+
repository,
|
|
24
|
+
attemptId,
|
|
25
|
+
permissions,
|
|
26
|
+
expiresAt: DateTime.formatIso(credential.expiresAt),
|
|
27
|
+
});
|
|
28
|
+
return { expiresAt: credential.expiresAt, published };
|
|
29
|
+
});
|
|
30
|
+
const first = yield* publishFresh();
|
|
31
|
+
const expiry = yield* SynchronizedRef.make(first.expiresAt);
|
|
32
|
+
const refresh = Effect.fn("Executor.refreshCredential")(function* () {
|
|
33
|
+
yield* Effect.annotateCurrentSpan({ repository, attemptId });
|
|
34
|
+
yield* SynchronizedRef.updateEffect(expiry, (expiresAt) => Effect.gen(function* () {
|
|
35
|
+
const now = yield* Clock.currentTimeMillis;
|
|
36
|
+
if (DateTime.toEpochMillis(expiresAt) - now > RENEWAL_WINDOW_MILLIS)
|
|
37
|
+
return expiresAt;
|
|
38
|
+
return (yield* publishFresh()).expiresAt;
|
|
39
|
+
}));
|
|
40
|
+
});
|
|
41
|
+
// Forked in a scope opened before the checkout finalizers, so renewal continues through
|
|
42
|
+
// salvage and stops before the published credential is removed.
|
|
43
|
+
yield* Effect.forever(Effect.sleep("30 seconds").pipe(Effect.andThen(refresh()), Effect.tapError((error) => Effect.logWarning("Attempt credential renewal failed; will retry", {
|
|
44
|
+
repository,
|
|
45
|
+
attemptId,
|
|
46
|
+
message: String(error),
|
|
47
|
+
})), Effect.ignore)).pipe(Effect.forkScoped);
|
|
48
|
+
return {
|
|
49
|
+
published: first.published,
|
|
50
|
+
refresh,
|
|
51
|
+
scrub: (text) => {
|
|
52
|
+
for (const token of issued)
|
|
53
|
+
text = text.replaceAll(Redacted.value(token), "[REDACTED]");
|
|
54
|
+
return text;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=renewable-credential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renewable-credential.js","sourceRoot":"","sources":["../src/renewable-credential.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AttemptId } from "@usine/core/attempt";
|
|
2
|
+
import { type SalvageRef, SalvagePushed, SalvageRetained } from "@usine/core/attempt/salvage";
|
|
3
|
+
import { CommitSha } from "@usine/core/repository";
|
|
4
|
+
import type { WorkerName } from "@usine/core/worker";
|
|
5
|
+
import { Effect, Option } from "effect";
|
|
6
|
+
/** The git identity for commits usine creates in an Attempt's worktree. */
|
|
7
|
+
export declare const SALVAGE_GIT_CONFIG: string[];
|
|
8
|
+
export interface SalvageOptions<E extends Error> {
|
|
9
|
+
readonly attemptId: AttemptId;
|
|
10
|
+
readonly worker: WorkerName;
|
|
11
|
+
readonly host: string;
|
|
12
|
+
readonly worktree: string;
|
|
13
|
+
readonly baseCommit: Option.Option<CommitSha>;
|
|
14
|
+
readonly ref: SalvageRef;
|
|
15
|
+
/** Runs git with the Worker's repository credentials; `salvageWorktree` prepends `-C <worktree>`. */
|
|
16
|
+
readonly git: (args: ReadonlyArray<string>) => Effect.Effect<string, E>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Returns the operator-facing line for the run drawer: the failure's message followed by its
|
|
20
|
+
* cause's message. For a failed command, the cause is the stderr, which local and SSH executors
|
|
21
|
+
* scrub of the Attempt's token.
|
|
22
|
+
*/
|
|
23
|
+
export declare const failureMessage: (failure: Error) => string;
|
|
24
|
+
/**
|
|
25
|
+
* Commits everything in an unsuccessful Attempt's checkout and pushes HEAD to its salvage ref
|
|
26
|
+
* before the worktree is removed. Skips a clean checkout at its base commit. If the push fails,
|
|
27
|
+
* keeps the worktree and reports its path. Never fails; skipped and failed stages are logged.
|
|
28
|
+
*/
|
|
29
|
+
export declare const salvageWorktree: <E extends Error>(options: SalvageOptions<E>) => Effect.Effect<Option.Option<SalvagePushed | SalvageRetained>, never, never>;
|
|
30
|
+
//# sourceMappingURL=salvage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salvage.d.ts","sourceRoot":"","sources":["../src/salvage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAEL,KAAK,UAAU,EACf,aAAa,EACb,eAAe,EAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAGxD,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,UAO9B,CAAC;AAEF,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,KAAK;IAC7C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,qGAAqG;IACrG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACzE;AAID;;;;GAIG;AACH,eAAO,MAAM,cAAc,YAAa,KAAK,KAAG,MAG/C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAoD,CAAC,SAAS,KAAK,4GA8F7F,CAAC"}
|