@outerlayer/cli 0.23.0 → 0.25.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/CHANGELOG.md +26 -0
- package/README.md +13 -0
- package/dist/{agent-setup-SNDCEHG2.js → agent-setup-PDIIGMKE.js} +7 -7
- package/dist/{bridge-QFN3KJP6.js → bridge-5KZ36YDG.js} +3 -3
- package/dist/build-Q2OBF77R.js +12 -0
- package/dist/build-info.json +1 -1
- package/dist/{builder-7FBQAWQZ.js → builder-PRSCX5AH.js} +7 -7
- package/dist/{check-3CGLWMHM.js → check-EPYRTE3R.js} +40 -37
- package/dist/{chunk-URWYRAIC.js → chunk-2K3TCQHW.js} +1 -3
- package/dist/{chunk-Z42JY3LQ.js → chunk-2N72GPS2.js} +3 -3
- package/dist/{chunk-WY7HFY62.js → chunk-34ANPNVB.js} +3 -3
- package/dist/{chunk-QSEPKZXR.js → chunk-3I44PQ26.js} +206 -57
- package/dist/{chunk-ZKWKQIJU.js → chunk-4S4VBDSO.js} +1 -1
- package/dist/chunk-5222PA6S.js +66 -0
- package/dist/{chunk-GXV73IIS.js → chunk-6CNHXHI2.js} +17 -5
- package/dist/{chunk-NYTZ7HVN.js → chunk-7OWPLRJR.js} +1 -1
- package/dist/{chunk-EFB3FGLC.js → chunk-ATGHVEU4.js} +1 -1
- package/dist/{chunk-QILR6TZP.js → chunk-AXPCGD46.js} +5 -5
- package/dist/{chunk-CBCKD6DO.js → chunk-D4AMAEZ7.js} +12 -11
- package/dist/{chunk-XACXXKQ5.js → chunk-DEBOL6ON.js} +1 -1
- package/dist/{chunk-XGPC3IOR.js → chunk-FXUVXSY2.js} +2 -2
- package/dist/{chunk-6AOZD3LY.js → chunk-HBLLZLOH.js} +3 -3
- package/dist/{chunk-ZLZ3XVPI.js → chunk-HWEIFHSW.js} +3 -3
- package/dist/{chunk-D64E222W.js → chunk-IDJIWKTY.js} +3 -3
- package/dist/{chunk-OBCFK4QD.js → chunk-IGRRD7PX.js} +11 -7
- package/dist/{chunk-GISNHSYL.js → chunk-JGD5TWQ2.js} +4 -2
- package/dist/{chunk-2TT7DEMZ.js → chunk-JKILLWZF.js} +11 -9
- package/dist/{chunk-V5CG75NX.js → chunk-JWRX5ZTT.js} +6 -2
- package/dist/{chunk-XOEV4FVK.js → chunk-K5WVK7IC.js} +1 -1
- package/dist/{chunk-TFGXOHF6.js → chunk-L2FZLBF7.js} +278 -40
- package/dist/{chunk-QS43O4DR.js → chunk-M4B6QKNZ.js} +1 -1
- package/dist/{chunk-UF5L4BAI.js → chunk-O2WYUIK7.js} +1 -1
- package/dist/{chunk-276D7BJ7.js → chunk-QMQC6JCO.js} +1 -1
- package/dist/{chunk-OGMZJWWD.js → chunk-QUGYGO6L.js} +6 -6
- package/dist/{chunk-JV4YGAAW.js → chunk-QXNJWSTM.js} +5 -5
- package/dist/{chunk-3W333NFO.js → chunk-RGW7ERF3.js} +15 -4
- package/dist/{chunk-I2UOAV7X.js → chunk-TQMI335S.js} +4 -1
- package/dist/{chunk-WXJXHZVB.js → chunk-UNF7MWEL.js} +1 -1
- package/dist/{chunk-FX6IHR5C.js → chunk-VMF5LK3D.js} +8 -8
- package/dist/{chunk-C2XZBNHY.js → chunk-VNGENFOG.js} +19 -6
- package/dist/{chunk-G3LHWUBK.js → chunk-VPUNOGXO.js} +6 -6
- package/dist/{chunk-C64D7HR3.js → chunk-X5LNCIZT.js} +19 -10
- package/dist/{chunk-2Q3PZ42G.js → chunk-XGJUNNXL.js} +1 -1
- package/dist/{chunk-BOG4ENP7.js → chunk-XHXDCYSK.js} +185 -38
- package/dist/{chunk-CQAEV3Z5.js → chunk-XRYUJTAT.js} +8 -1
- package/dist/{chunk-KGKFEONR.js → chunk-YMKQVCKC.js} +5 -5
- package/dist/{chunk-DJYOCD65.js → chunk-YTTHDPWF.js} +5 -5
- package/dist/{chunk-4AVDD7VX.js → chunk-ZGMQQWCV.js} +2 -2
- package/dist/{chunk-IHNQWF6F.js → chunk-ZI2ZVWKT.js} +1 -1
- package/dist/{chunk-OW52QLK3.js → chunk-ZODVSFI4.js} +1 -1
- package/dist/chunk-ZVB57WI6.js +19 -0
- package/dist/{claude-launcher-KEESTJHO.js → claude-launcher-WGOCLTG6.js} +1 -1
- package/dist/{cli-44WGGICQ.js → cli-2LGSPAYZ.js} +131 -97
- package/dist/command-ITLPJ5XU.js +533 -0
- package/dist/{config-H4QS332G.js → config-JJ3EO7SB.js} +3 -3
- package/dist/connect-cmd-JFDZKPND.js +25 -0
- package/dist/container-start-X22OXY6E.js +179 -0
- package/dist/{control-plane-launch-SEYCOZFH.js → control-plane-launch-ZFT6SI4N.js} +6 -6
- package/dist/{dist-SOH3O24Y.js → dist-2APO44JG.js} +1 -1
- package/dist/{docker-KMK4LOET.js → docker-PQHWAY5J.js} +7 -7
- package/dist/{doctor-4H77CEB7.js → doctor-73GNT4VV.js} +90 -31
- package/dist/{emit-artifact-cmd-XCZ3ALLV.js → emit-artifact-cmd-AIOTX6YT.js} +14 -11
- package/dist/{emit-criteria-cmd-JE72JHKJ.js → emit-criteria-cmd-7PJINOHA.js} +11 -8
- package/dist/{emit-finding-cmd-ILIDRMYN.js → emit-finding-cmd-JRDSZ4DR.js} +11 -8
- package/dist/{emit-result-cmd-WPKG5YAS.js → emit-result-cmd-ZGF6Q6OP.js} +14 -11
- package/dist/{emit-step-cmd-OVMLQSL6.js → emit-step-cmd-DUR34STQ.js} +12 -9
- package/dist/{exec-client-ATPF2DDB.js → exec-client-S5IA7JRG.js} +4 -4
- package/dist/{governing-source-EQBKPME7.js → governing-source-DKJABQAT.js} +12 -11
- package/dist/{guest-init-HWSE7W6L.js → guest-init-TOSKPGPF.js} +5 -5
- package/dist/{hook-fast-27SHD72I.js → hook-fast-NEELST6G.js} +1 -1
- package/dist/host-key-ICJEQBWH.js +9 -0
- package/dist/image-tag-6KJOGBQK.js +10 -0
- package/dist/index.js +4 -4
- package/dist/{init-HAAHIQFN.js → init-NE3VR3EY.js} +26 -23
- package/dist/{init-WQ62BXDN.js → init-SKOXNJND.js} +26 -23
- package/dist/{init-cmd-VPFIDY64.js → init-cmd-UEDOJ7LG.js} +12 -12
- package/dist/{init-update-UZIJ2FMU.js → init-update-VKZ4S6HH.js} +36 -10
- package/dist/{install-SFACZU7E.js → install-MPEJJ7X6.js} +5 -5
- package/dist/install-cmd-SE6NCTJK.js +12 -0
- package/dist/job-state-format-WJQGQB6F.js +6 -0
- package/dist/{logs-N3ZX7HFV.js → logs-T4ERSOQ4.js} +3 -3
- package/dist/loop-BPVEA5OC.js +78 -0
- package/dist/{machine-PGDRWPI2.js → machine-G3GICXQN.js} +22 -19
- package/dist/{mcp-serve-cmd-CNRC5AL5.js → mcp-serve-cmd-7M4VLNI4.js} +5 -5
- package/dist/{paths-AKX2OOLF.js → paths-2KGM2LZV.js} +3 -3
- package/dist/pending-BGLMTB5Q.js +9 -0
- package/dist/{pidfile-G2J5WBQS.js → pidfile-VYBH3IMN.js} +4 -4
- package/dist/{record-Q4IEYIVV.js → record-GNOHDJ2O.js} +4 -4
- package/dist/{relay-PSZ4LGMW.js → relay-GFPPD6GF.js} +1 -1
- package/dist/relay-protocol-HELO5SNH.js +6 -0
- package/dist/{runner-env-GZHXM27A.js → runner-env-GUFV544G.js} +6 -6
- package/dist/{runner-identity-IIZ3RK7M.js → runner-identity-J6DXJ6MF.js} +7 -7
- package/dist/{runner-key-BPP5XRYR.js → runner-key-L55O7Y7W.js} +26 -23
- package/dist/{session-sender-EKKZ5DEU.js → session-sender-LXTASWBY.js} +15 -12
- package/dist/{spec-cmd-JDHGNFVJ.js → spec-cmd-G2JNXKD7.js} +12 -9
- package/dist/{status-UCQDEMFX.js → status-U6DXOR6C.js} +43 -28
- package/dist/{sync-cmd-NSVXOYFJ.js → sync-cmd-VPNS5ITY.js} +14 -11
- package/dist/{watch-NQVZWPBJ.js → watch-ZOCYD2NE.js} +14 -11
- package/dist/{work-claim-cmd-FPJXQAXP.js → work-claim-cmd-BUMIPJNF.js} +15 -12
- package/dist/{work-cmd-FMPDXPU6.js → work-cmd-LRAXUOJV.js} +12 -9
- package/dist/{work-comment-cmd-ZVUE2IUN.js → work-comment-cmd-4RDIBUYO.js} +12 -9
- package/dist/{work-logs-cmd-CQH2SYT4.js → work-logs-cmd-YYN2CPJQ.js} +12 -9
- package/dist/{work-open-pr-cmd-YY2OGJOI.js → work-open-pr-cmd-3MCND2LZ.js} +13 -10
- package/dist/{work-pr-cmd-EHFTEVJO.js → work-pr-cmd-BODEZAXN.js} +12 -9
- package/dist/{work-stop-cmd-LGWSBSBT.js → work-stop-cmd-P7HXVKEG.js} +12 -9
- package/package.json +2 -2
- package/skill-pack/maintained/outerlayer-build/SKILL.md +1 -1
- package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +3 -2
- package/skill-pack/maintained/outerlayer-build/references/review-briefs.md +3 -1
- package/dist/build-WHHFA7KM.js +0 -12
- package/dist/command-4FAP2D3P.js +0 -207
- package/dist/connect-cmd-6DUTUK63.js +0 -22
- package/dist/host-key-ATB23GI3.js +0 -9
- package/dist/install-cmd-6HTP7I43.js +0 -12
- package/dist/loop-JPW2QJ64.js +0 -75
- package/dist/pending-7SGWZCEH.js +0 -9
- package/dist/relay-protocol-K7KP2SPI.js +0 -6
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, commandLogOffset, execCommandLine, startSender, startHostServices, finishJob, isContainerTracked, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, AttemptLogBook, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, ALREADY_RELEASED } from './chunk-
|
|
4
|
-
import { writePendingUpdate } from './chunk-
|
|
5
|
-
import {
|
|
3
|
+
import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, commandLogOffset, execCommandLine, startSender, startHostServices, finishJob, isContainerTracked, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, AttemptLogBook, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, ALREADY_RELEASED, inTeardown } from './chunk-3I44PQ26.js';
|
|
4
|
+
import { writePendingUpdate } from './chunk-XRYUJTAT.js';
|
|
5
|
+
import { JOB_STATE_FORMAT, readsJobState, jobStateFormatOf } from './chunk-ZVB57WI6.js';
|
|
6
|
+
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-O2WYUIK7.js';
|
|
6
7
|
import { decideInstalledSwitch } from './chunk-3JVYMD4G.js';
|
|
7
8
|
import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-YETTWTAY.js';
|
|
8
|
-
import { compareVersions, satisfiesRange } from './chunk-I2UOAV7X.js';
|
|
9
9
|
import { RUNNER_PROTOCOL } from './chunk-TPKYTORP.js';
|
|
10
|
-
import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-
|
|
10
|
+
import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-VPUNOGXO.js';
|
|
11
|
+
import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, isInLayout, cleanVersions, stagingDir } from './chunk-QMQC6JCO.js';
|
|
11
12
|
import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
|
|
12
|
-
import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, cleanVersions, isInLayout, stagingDir } from './chunk-276D7BJ7.js';
|
|
13
13
|
import { RepoFilter } from './chunk-TBT347UY.js';
|
|
14
|
-
import { LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec, measureDisk, setUpRunnerCgroup, createContainerRuntime, parseCpuList, ensureTunnel, keepGhConfigCurrent, filesAreCopied } from './chunk-
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
14
|
+
import { LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec, measureDisk, setUpRunnerCgroup, createContainerRuntime, parseCpuList, ensureTunnel, keepGhConfigCurrent, filesAreCopied } from './chunk-XHXDCYSK.js';
|
|
15
|
+
import { tagToPull, pullInstruction, imageTag, writeUpdateStatus } from './chunk-5222PA6S.js';
|
|
16
|
+
import { isVersion, compareVersions, satisfiesRange } from './chunk-TQMI335S.js';
|
|
17
|
+
import { checkFit } from './chunk-IGRRD7PX.js';
|
|
18
|
+
import { claimPidFile, readPidFile, releasePidFile } from './chunk-DEBOL6ON.js';
|
|
17
19
|
import { startTimeOf, isSameProcess } from './chunk-JBJTC3UU.js';
|
|
18
|
-
import { writeJobFile, ensureRunnerIdentity, readJobFile, builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, spawnRun, BUILD_LABEL, RUNNER_LABEL, readJobFileChecked } from './chunk-
|
|
19
|
-
import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, BuildTokens, classifyRefusal, refusalCode, createRunnerLog, formatClock } from './chunk-
|
|
20
|
-
import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-
|
|
21
|
-
import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind, DEFAULT_UPDATE_MAX_WAIT_HOURS } from './chunk-
|
|
20
|
+
import { writeJobFile, ensureRunnerIdentity, readJobFile, builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, spawnRun, BUILD_LABEL, RUNNER_LABEL, readJobFileChecked } from './chunk-QUGYGO6L.js';
|
|
21
|
+
import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, BuildTokens, classifyRefusal, refusalCode, createRunnerLog, formatClock } from './chunk-YMKQVCKC.js';
|
|
22
|
+
import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-X5LNCIZT.js';
|
|
23
|
+
import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind, DEFAULT_UPDATE_MAX_WAIT_HOURS } from './chunk-JWRX5ZTT.js';
|
|
22
24
|
import { exceedsDisk } from './chunk-7RQ73DLO.js';
|
|
23
25
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
24
|
-
import { loadHostKey, ensureHostKey, signerFor } from './chunk-
|
|
25
|
-
import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, RUNNER_FILE_MODE, jobsDir, pidFilePath, spoolDir, rootfsDir } from './chunk-
|
|
26
|
-
import { parseClaimIdentity, parseClaimedRepositories, parseUnreachable, repositoriesOf, primaryOf, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-
|
|
27
|
-
import { COMMAND_LOST_REASON, CONTAINER_STOPPED_REASON } from './chunk-
|
|
26
|
+
import { loadHostKey, ensureHostKey, signerFor } from './chunk-ZODVSFI4.js';
|
|
27
|
+
import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, RUNNER_FILE_MODE, jobsDir, pidFilePath, spoolDir, rootfsDir } from './chunk-ZI2ZVWKT.js';
|
|
28
|
+
import { parseClaimIdentity, parseClaimedRepositories, parseUnreachable, repositoriesOf, primaryOf, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-2K3TCQHW.js';
|
|
29
|
+
import { COMMAND_LOST_REASON, CONTAINER_STOPPED_REASON } from './chunk-JGD5TWQ2.js';
|
|
28
30
|
import { randomBytes } from 'crypto';
|
|
29
31
|
import { mkdirSync, existsSync, chmodSync, writeFileSync, renameSync, statSync, readdirSync, readFileSync, rmSync, closeSync, openSync, constants, lstatSync } from 'fs';
|
|
30
32
|
import { join, dirname } from 'path';
|
|
@@ -237,6 +239,61 @@ function writeLastUpdate(configPath, update) {
|
|
|
237
239
|
`, { mode: RUNNER_FILE_MODE });
|
|
238
240
|
renameSync(temporary, path);
|
|
239
241
|
}
|
|
242
|
+
|
|
243
|
+
// src/runner/update/ask-formats.ts
|
|
244
|
+
async function askJobStateFormats(runNode, entry, cwd) {
|
|
245
|
+
let result;
|
|
246
|
+
try {
|
|
247
|
+
result = await runNode([entry, "runner", "job-state-formats"], cwd);
|
|
248
|
+
} catch {
|
|
249
|
+
return void 0;
|
|
250
|
+
}
|
|
251
|
+
if (result.status !== 0) return void 0;
|
|
252
|
+
try {
|
|
253
|
+
const body = JSON.parse(result.stdout);
|
|
254
|
+
if (!Array.isArray(body.reads) || !body.reads.every((n) => Number.isInteger(n))) return void 0;
|
|
255
|
+
return body.reads;
|
|
256
|
+
} catch {
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/runner/update/survives-restart.ts
|
|
262
|
+
function stageReason(job) {
|
|
263
|
+
if (job.stage === "command") return void 0;
|
|
264
|
+
if (!inTeardown(job)) return "is still in setup";
|
|
265
|
+
switch (job.stage) {
|
|
266
|
+
case "judge":
|
|
267
|
+
return "is running the criteria judge";
|
|
268
|
+
case "checks":
|
|
269
|
+
return "is running its checks";
|
|
270
|
+
default:
|
|
271
|
+
return `is finishing (${job.stage})`;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function ownReason({ job, ending }) {
|
|
275
|
+
if (job.microvm !== void 0) return "runs in a microVM, which does not carry on through a restart";
|
|
276
|
+
if (!isContainerTracked(job)) return "is not a container build tracked inside its container";
|
|
277
|
+
if (ending) return "is being ended";
|
|
278
|
+
return stageReason(job);
|
|
279
|
+
}
|
|
280
|
+
function buildBlockers(builds) {
|
|
281
|
+
return builds.flatMap((build) => {
|
|
282
|
+
const reason = ownReason(build);
|
|
283
|
+
return reason === void 0 ? [] : [{ item: build.job.item, reason }];
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function restartBlockers(builds, reads) {
|
|
287
|
+
return builds.flatMap((build) => {
|
|
288
|
+
const reason = ownReason(build);
|
|
289
|
+
if (reason !== void 0) return [{ item: build.job.item, reason }];
|
|
290
|
+
if (reads === void 0) return [{ item: build.job.item, reason: "has job state the new version may not read: it did not say which formats it reads" }];
|
|
291
|
+
if (!readsJobState(build.job, reads)) {
|
|
292
|
+
return [{ item: build.job.item, reason: `has job-state format ${jobStateFormatOf(build.job)}, which the new version does not read` }];
|
|
293
|
+
}
|
|
294
|
+
return [];
|
|
295
|
+
});
|
|
296
|
+
}
|
|
240
297
|
var RELEASE_REPOSITORY = "https://github.com/outerlayerai/outerlayer";
|
|
241
298
|
var RELEASE_WORKFLOW_PATH = ".github/workflows/outerlayer-release.yml";
|
|
242
299
|
var UpdateStepError = class extends Error {
|
|
@@ -410,8 +467,8 @@ async function preflightUpdate(args) {
|
|
|
410
467
|
const failure2 = await earlyFailure(args);
|
|
411
468
|
return failure2 === void 0 ? void 0 : finish(args, failure2);
|
|
412
469
|
}
|
|
413
|
-
async function
|
|
414
|
-
const { configPath,
|
|
470
|
+
async function prepareUpdate(args) {
|
|
471
|
+
const { configPath, version, deps } = args;
|
|
415
472
|
const early = await earlyFailure(args);
|
|
416
473
|
if (early !== void 0) return finish(args, early);
|
|
417
474
|
let verified;
|
|
@@ -423,24 +480,31 @@ async function performUpdate(args) {
|
|
|
423
480
|
if (!verified.ok) return finish(args, { outcome: verified.outcome, reason: verified.reason });
|
|
424
481
|
const staged = await deps.runNode([entryIn(verified.dir), "runner", "check", "--config", configPath], verified.dir);
|
|
425
482
|
if (staged.status !== 0) {
|
|
426
|
-
|
|
427
|
-
rmSync(verified.dir, { recursive: true, force: true });
|
|
428
|
-
} catch {
|
|
429
|
-
}
|
|
483
|
+
removeStaging(verified.dir);
|
|
430
484
|
return finish(args, {
|
|
431
485
|
outcome: "retrying",
|
|
432
486
|
reason: `${version} failed \`runner check\` on this host (exit ${staged.status})`,
|
|
433
487
|
detail: `${version} failed \`runner check\` on this host: ${(staged.stderr.trim() || staged.stdout.trim()).slice(0, 500)}`
|
|
434
488
|
});
|
|
435
489
|
}
|
|
490
|
+
return { kind: "prepared", dir: verified.dir };
|
|
491
|
+
}
|
|
492
|
+
function removeStaging(dir) {
|
|
493
|
+
try {
|
|
494
|
+
rmSync(dir, { recursive: true });
|
|
495
|
+
} catch {
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function installPrepared(args, stagedDir) {
|
|
499
|
+
const { configPath, own, version } = args;
|
|
436
500
|
try {
|
|
437
501
|
if (version !== own) rmSync(versionDir(configPath, version), { recursive: true, force: true });
|
|
438
|
-
renameSync(
|
|
502
|
+
renameSync(stagedDir, versionDir(configPath, version));
|
|
439
503
|
writeMarker(configPath, { from: own, to: version, starts: 0 });
|
|
440
504
|
switchCurrent(configPath, version);
|
|
441
505
|
} catch (err) {
|
|
442
506
|
try {
|
|
443
|
-
rmSync(
|
|
507
|
+
rmSync(stagedDir, { recursive: true, force: true });
|
|
444
508
|
if (currentVersion(configPath) !== version) removeMarker(configPath);
|
|
445
509
|
} catch {
|
|
446
510
|
}
|
|
@@ -454,6 +518,10 @@ async function performUpdate(args) {
|
|
|
454
518
|
args.log.line(`updating ${own} -> ${version} \xB7 restarting`);
|
|
455
519
|
return { kind: "switched" };
|
|
456
520
|
}
|
|
521
|
+
async function performUpdate(args) {
|
|
522
|
+
const prepared = await prepareUpdate(args);
|
|
523
|
+
return prepared.kind === "prepared" ? installPrepared(args, prepared.dir) : prepared;
|
|
524
|
+
}
|
|
457
525
|
function rollBack(configPath, marker, reason, detail, now, log) {
|
|
458
526
|
try {
|
|
459
527
|
writeLastUpdate(configPath, { from: marker.from, to: marker.to, outcome: "rolled_back", reason, at: isoAt(now) });
|
|
@@ -1165,6 +1233,10 @@ function selfUpdateBlocker(configPath, entryPath, own) {
|
|
|
1165
1233
|
return void 0;
|
|
1166
1234
|
}
|
|
1167
1235
|
function considerNamedVersion(state, named) {
|
|
1236
|
+
if (state.deps.image !== void 0) {
|
|
1237
|
+
considerNamedImage(state, named);
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1168
1240
|
const update = state.deps.update;
|
|
1169
1241
|
if (update === void 0 || named === void 0) return;
|
|
1170
1242
|
const configPath = state.config.configPath;
|
|
@@ -1187,6 +1259,34 @@ function considerNamedVersion(state, named) {
|
|
|
1187
1259
|
logOf(state).line(`this runner cannot update itself to ${named}: ${blocker}`);
|
|
1188
1260
|
}
|
|
1189
1261
|
}
|
|
1262
|
+
function considerNamedImage(state, named) {
|
|
1263
|
+
if (named !== void 0 && !isVersion(named)) named = void 0;
|
|
1264
|
+
if (named !== void 0) state.imageNamed = named;
|
|
1265
|
+
recordImageStatus(state);
|
|
1266
|
+
const own = ownVersionOf(state.deps);
|
|
1267
|
+
if (named === void 0 || state.imageLogged === named || (compareVersions(own, named) ?? 0) >= 0) return;
|
|
1268
|
+
state.imageLogged = named;
|
|
1269
|
+
logOf(state).line(`the factory names ${named}, newer than the ${own} this image runs \xB7 ${pullInstruction(imageTag(named))}`);
|
|
1270
|
+
}
|
|
1271
|
+
function recordImageStatus(state) {
|
|
1272
|
+
if (state.deps.image === void 0) return;
|
|
1273
|
+
const named = state.imageNamed;
|
|
1274
|
+
const record = {
|
|
1275
|
+
own: ownVersionOf(state.deps),
|
|
1276
|
+
...named === void 0 ? {} : { named, tag: imageTag(named) },
|
|
1277
|
+
upgradeRequired: state.upgradeRefused === true,
|
|
1278
|
+
at: nowOf(state).toISOString()
|
|
1279
|
+
};
|
|
1280
|
+
const key = JSON.stringify({ ...record, at: void 0 });
|
|
1281
|
+
if (state.imageRecord === key) return;
|
|
1282
|
+
try {
|
|
1283
|
+
writeUpdateStatus(runnerDir(state.config.configPath), record);
|
|
1284
|
+
state.imageRecord = key;
|
|
1285
|
+
reportRepeating(state, "the update-status.json record", void 0);
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
reportRepeating(state, "the update-status.json record", `could not write update-status.json (${describeCallFailure(err)}): \`runner status\` will not name the image to pull`);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1190
1290
|
function adoptUpdateWait(state, version, nowMs) {
|
|
1191
1291
|
const previous = state.updateWait;
|
|
1192
1292
|
const wait = { version, sinceMs: previous?.sinceMs ?? nowMs, holdSinceMs: previous?.holdSinceMs };
|
|
@@ -1209,12 +1309,20 @@ function updateArgsOf(state, update, version) {
|
|
|
1209
1309
|
function dropPendingUpdate(state) {
|
|
1210
1310
|
state.pendingUpdate = void 0;
|
|
1211
1311
|
state.preflightedUpdate = void 0;
|
|
1312
|
+
discardPrepared(state);
|
|
1212
1313
|
clearUpdateWait(state);
|
|
1213
1314
|
}
|
|
1315
|
+
function discardPrepared(state) {
|
|
1316
|
+
if (state.preparedUpdate === void 0) return;
|
|
1317
|
+
removeStaging(state.preparedUpdate.dir);
|
|
1318
|
+
state.preparedUpdate = void 0;
|
|
1319
|
+
}
|
|
1214
1320
|
function clearUpdateWait(state) {
|
|
1215
1321
|
state.updateWait = void 0;
|
|
1216
1322
|
state.updateLogged = void 0;
|
|
1217
1323
|
state.upgradeRefused = false;
|
|
1324
|
+
if (state.installWait !== void 0) return;
|
|
1325
|
+
state.waitsLogged = void 0;
|
|
1218
1326
|
recordPendingUpdate(state, void 0);
|
|
1219
1327
|
}
|
|
1220
1328
|
function recordPendingUpdate(state, record) {
|
|
@@ -1238,7 +1346,7 @@ function runningItems(state) {
|
|
|
1238
1346
|
const numbers = [...state.jobs.values()].map((entry) => Number(entry.job.item)).filter((n) => Number.isFinite(n));
|
|
1239
1347
|
return numbers.sort((a, b) => a - b);
|
|
1240
1348
|
}
|
|
1241
|
-
function holdForUpdate(state, version, mayHold = true) {
|
|
1349
|
+
function holdForUpdate(state, version, mayHold = true, waits = []) {
|
|
1242
1350
|
const log = logOf(state);
|
|
1243
1351
|
const nowMs = nowOf(state).getTime();
|
|
1244
1352
|
const wait = adoptUpdateWait(state, version, nowMs);
|
|
@@ -1253,6 +1361,11 @@ function holdForUpdate(state, version, mayHold = true) {
|
|
|
1253
1361
|
const maxWaitMs = (state.config.update?.maxWaitHours ?? DEFAULT_UPDATE_MAX_WAIT_HOURS) * 60 * 6e4;
|
|
1254
1362
|
const holding = mayHold && (state.upgradeRefused === true || nowMs - wait.sinceMs >= maxWaitMs);
|
|
1255
1363
|
const record = { version, since: new Date(wait.sinceMs).toISOString() };
|
|
1364
|
+
if (waits.length > 0) {
|
|
1365
|
+
record.via = "self-update";
|
|
1366
|
+
record.waits = recordedWaits(waits);
|
|
1367
|
+
}
|
|
1368
|
+
noteWaits(state, version, waits);
|
|
1256
1369
|
if (holding) {
|
|
1257
1370
|
wait.holdSinceMs ??= nowMs;
|
|
1258
1371
|
const builds = runningItems(state);
|
|
@@ -1269,6 +1382,16 @@ function holdForUpdate(state, version, mayHold = true) {
|
|
|
1269
1382
|
recordPendingUpdate(state, record);
|
|
1270
1383
|
return holding;
|
|
1271
1384
|
}
|
|
1385
|
+
function recordedWaits(waits) {
|
|
1386
|
+
return waits.flatMap((wait) => Number.isFinite(Number(wait.item)) ? [{ item: Number(wait.item), reason: wait.reason }] : []);
|
|
1387
|
+
}
|
|
1388
|
+
function noteWaits(state, version, waits) {
|
|
1389
|
+
const phrase = waits.map((wait) => `#${wait.item} ${wait.reason}`).join("; ");
|
|
1390
|
+
const key = waits.length === 0 ? void 0 : `${version}:${phrase}`;
|
|
1391
|
+
if (state.waitsLogged === key) return;
|
|
1392
|
+
state.waitsLogged = key;
|
|
1393
|
+
if (key !== void 0) logOf(state).line(`update to ${version} waits: ${phrase}`);
|
|
1394
|
+
}
|
|
1272
1395
|
function buildsPhrase(builds) {
|
|
1273
1396
|
return builds.length === 0 ? "the running builds" : builds.map((n) => `#${n}`).join(", ");
|
|
1274
1397
|
}
|
|
@@ -1292,7 +1415,7 @@ function installedSwitchOf(state, update) {
|
|
|
1292
1415
|
installed: current !== void 0 && existsSync(entryIn(versionDir(configPath, current)))
|
|
1293
1416
|
});
|
|
1294
1417
|
}
|
|
1295
|
-
function restartOntoInstalled(state) {
|
|
1418
|
+
async function restartOntoInstalled(state) {
|
|
1296
1419
|
const update = state.deps.update;
|
|
1297
1420
|
if (update === void 0) return false;
|
|
1298
1421
|
const configPath = state.config.configPath;
|
|
@@ -1300,6 +1423,8 @@ function restartOntoInstalled(state) {
|
|
|
1300
1423
|
const decision = installedSwitchOf(state, update);
|
|
1301
1424
|
if (decision.kind === "none") {
|
|
1302
1425
|
state.installedSwitch = void 0;
|
|
1426
|
+
state.installedFormats = void 0;
|
|
1427
|
+
state.installWait = void 0;
|
|
1303
1428
|
return false;
|
|
1304
1429
|
}
|
|
1305
1430
|
const said = `${decision.kind}:${decision.to}`;
|
|
@@ -1315,8 +1440,14 @@ function restartOntoInstalled(state) {
|
|
|
1315
1440
|
return false;
|
|
1316
1441
|
}
|
|
1317
1442
|
if (state.jobs.size > 0) {
|
|
1318
|
-
|
|
1319
|
-
|
|
1443
|
+
const waits = await installBlockers(state, update, decision.to);
|
|
1444
|
+
if (waits.length > 0) {
|
|
1445
|
+
if (first) log.line(`${decision.to} is installed \xB7 taking no new work, restarting onto it once ${state.jobs.size} running build(s) finish`);
|
|
1446
|
+
const wait = state.installWait = state.installWait?.version === decision.to ? state.installWait : { version: decision.to, sinceMs: nowOf(state).getTime() };
|
|
1447
|
+
noteWaits(state, decision.to, waits);
|
|
1448
|
+
recordPendingUpdate(state, { version: decision.to, since: new Date(wait.sinceMs).toISOString(), via: "install", waits: recordedWaits(waits) });
|
|
1449
|
+
return true;
|
|
1450
|
+
}
|
|
1320
1451
|
}
|
|
1321
1452
|
try {
|
|
1322
1453
|
writeMarker(configPath, { from: own, to: decision.to, starts: 0 });
|
|
@@ -1327,10 +1458,66 @@ function restartOntoInstalled(state) {
|
|
|
1327
1458
|
(state.exitForUpdate ?? (() => update.exit(RESTART_EXIT_STATUS)))();
|
|
1328
1459
|
return true;
|
|
1329
1460
|
}
|
|
1461
|
+
function runningBuilds(state) {
|
|
1462
|
+
return [...state.jobs.values()].map((active) => ({ job: active.job, ending: active.ending }));
|
|
1463
|
+
}
|
|
1464
|
+
async function installBlockers(state, update, to) {
|
|
1465
|
+
const stage = buildBlockers(runningBuilds(state));
|
|
1466
|
+
if (stage.length > 0) return stage;
|
|
1467
|
+
if (state.installedFormats?.version !== to) {
|
|
1468
|
+
const dir = versionDir(state.config.configPath, to);
|
|
1469
|
+
state.installedFormats = { version: to, reads: await askJobStateFormats(update.runNode, entryIn(dir), dir) };
|
|
1470
|
+
}
|
|
1471
|
+
return restartBlockers(runningBuilds(state), state.installedFormats.reads);
|
|
1472
|
+
}
|
|
1473
|
+
function formatBlocked(builds, reads) {
|
|
1474
|
+
const byStage = new Set(buildBlockers(builds).map((blocker) => blocker.item));
|
|
1475
|
+
return restartBlockers(builds, reads).some((blocker) => !byStage.has(blocker.item));
|
|
1476
|
+
}
|
|
1477
|
+
async function restartNow(state, update, version) {
|
|
1478
|
+
const early = buildBlockers(runningBuilds(state));
|
|
1479
|
+
if (early.length > 0) return { kind: "waiting", waits: early };
|
|
1480
|
+
if (state.preparedUpdate !== void 0 && state.preparedUpdate.version !== version) discardPrepared(state);
|
|
1481
|
+
const args = updateArgsOf(state, update, version);
|
|
1482
|
+
let reads;
|
|
1483
|
+
const declined = state.declinedFormats?.has(version) === true;
|
|
1484
|
+
if (state.preparedUpdate !== void 0) {
|
|
1485
|
+
reads = state.preparedUpdate.reads;
|
|
1486
|
+
} else if (declined && restartBlockers(runningBuilds(state), state.declinedFormats.get(version)).length > 0) {
|
|
1487
|
+
reads = state.declinedFormats.get(version);
|
|
1488
|
+
} else {
|
|
1489
|
+
const prepared = await prepareUpdate(args);
|
|
1490
|
+
if (prepared.kind !== "prepared") {
|
|
1491
|
+
dropPendingUpdate(state);
|
|
1492
|
+
reportUpdateResult(state, version, prepared);
|
|
1493
|
+
return { kind: "failed" };
|
|
1494
|
+
}
|
|
1495
|
+
reads = await askJobStateFormats(update.runNode, entryIn(prepared.dir), prepared.dir);
|
|
1496
|
+
if (formatBlocked(runningBuilds(state), reads)) {
|
|
1497
|
+
removeStaging(prepared.dir);
|
|
1498
|
+
(state.declinedFormats ??= /* @__PURE__ */ new Map()).set(version, reads);
|
|
1499
|
+
} else {
|
|
1500
|
+
state.preparedUpdate = { version, dir: prepared.dir, reads };
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
const waits = restartBlockers(runningBuilds(state), reads);
|
|
1504
|
+
if (waits.length > 0) return { kind: "waiting", waits };
|
|
1505
|
+
const staged = state.preparedUpdate;
|
|
1506
|
+
state.preparedUpdate = void 0;
|
|
1507
|
+
dropPendingUpdate(state);
|
|
1508
|
+
const result = installPrepared(args, staged.dir);
|
|
1509
|
+
if (result.kind === "switched") {
|
|
1510
|
+
(state.exitForUpdate ?? (() => update.exit(RESTART_EXIT_STATUS)))();
|
|
1511
|
+
return { kind: "restarted" };
|
|
1512
|
+
}
|
|
1513
|
+
reportUpdateResult(state, version, result);
|
|
1514
|
+
return { kind: "failed" };
|
|
1515
|
+
}
|
|
1330
1516
|
async function updateWhenIdle(state) {
|
|
1331
1517
|
const update = state.deps.update;
|
|
1332
1518
|
const version = state.pendingUpdate;
|
|
1333
1519
|
if (update === void 0 || version === void 0) {
|
|
1520
|
+
discardPrepared(state);
|
|
1334
1521
|
recordPendingUpdate(state, void 0);
|
|
1335
1522
|
return false;
|
|
1336
1523
|
}
|
|
@@ -1356,6 +1543,12 @@ async function updateWhenIdle(state) {
|
|
|
1356
1543
|
}
|
|
1357
1544
|
state.preflightedUpdate = version;
|
|
1358
1545
|
}
|
|
1546
|
+
if (update.underService === true) {
|
|
1547
|
+
const outcome = await restartNow(state, update, version);
|
|
1548
|
+
if (outcome.kind === "restarted") return true;
|
|
1549
|
+
if (outcome.kind === "failed") return false;
|
|
1550
|
+
return holdForUpdate(state, version, true, outcome.waits);
|
|
1551
|
+
}
|
|
1359
1552
|
return holdForUpdate(state, version);
|
|
1360
1553
|
}
|
|
1361
1554
|
dropPendingUpdate(state);
|
|
@@ -1488,8 +1681,9 @@ async function housekeepingPass(state) {
|
|
|
1488
1681
|
async function runTick(state) {
|
|
1489
1682
|
state.restarting = false;
|
|
1490
1683
|
state.holdingForUpdate = false;
|
|
1684
|
+
if (state.draining === true) return;
|
|
1491
1685
|
reloadConfig(state);
|
|
1492
|
-
if (restartOntoInstalled(state)) {
|
|
1686
|
+
if (await restartOntoInstalled(state)) {
|
|
1493
1687
|
state.restarting = true;
|
|
1494
1688
|
return;
|
|
1495
1689
|
}
|
|
@@ -1552,7 +1746,7 @@ var CLAIM_REFUSAL_CODES = new Set(
|
|
|
1552
1746
|
"pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous pull_request_repository_not_connected repository_not_reachable branch_claimed_elsewhere".split(" ")
|
|
1553
1747
|
);
|
|
1554
1748
|
async function tryClaimAndStart(state, item, queue) {
|
|
1555
|
-
const { postJson: postJson2 } = await import('./work-cmd-
|
|
1749
|
+
const { postJson: postJson2 } = await import('./work-cmd-LRAXUOJV.js');
|
|
1556
1750
|
const log = logOf(state);
|
|
1557
1751
|
const hostKey = await loadHostKey(state.config.configPath);
|
|
1558
1752
|
const claim = await retrySend(
|
|
@@ -1589,14 +1783,21 @@ async function tryClaimAndStart(state, item, queue) {
|
|
|
1589
1783
|
return { kind: "signature" };
|
|
1590
1784
|
}
|
|
1591
1785
|
if (claim.code === "runner_upgrade_required") {
|
|
1592
|
-
|
|
1786
|
+
const tag = tagToPull(state.imageNamed);
|
|
1787
|
+
reportRepeating(
|
|
1788
|
+
state,
|
|
1789
|
+
"the runner protocol",
|
|
1790
|
+
state.deps.image === void 0 ? claim.message ?? claim.reason : `${claim.message ?? claim.reason} \xB7 ${pullInstruction(tag)}`
|
|
1791
|
+
);
|
|
1593
1792
|
state.upgradeRefused = true;
|
|
1793
|
+
recordImageStatus(state);
|
|
1594
1794
|
return { kind: "outdated" };
|
|
1595
1795
|
}
|
|
1596
1796
|
return { kind: "error", reason: `${claim.reason} (${claim.attempts} attempt(s))` };
|
|
1597
1797
|
}
|
|
1598
1798
|
reportRepeating(state, "the runner protocol", void 0);
|
|
1599
1799
|
state.upgradeRefused = false;
|
|
1800
|
+
recordImageStatus(state);
|
|
1600
1801
|
reportRepeating(state, "the request signature", void 0);
|
|
1601
1802
|
const { data } = claim.value;
|
|
1602
1803
|
const claimId = data.id === void 0 || data.id === null ? "" : String(data.id);
|
|
@@ -1605,7 +1806,7 @@ async function tryClaimAndStart(state, item, queue) {
|
|
|
1605
1806
|
}
|
|
1606
1807
|
if (wasExtended(data)) {
|
|
1607
1808
|
log.line(
|
|
1608
|
-
`#${item.number} skipped: the claim extended a live lease under
|
|
1809
|
+
`#${item.number} skipped: the claim extended a live lease under the runner name "${state.config.host}" \xB7 set a distinct runner.name per config file`
|
|
1609
1810
|
);
|
|
1610
1811
|
return { kind: "held" };
|
|
1611
1812
|
}
|
|
@@ -1695,6 +1896,7 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity,
|
|
|
1695
1896
|
const runnerRoot = runnerDir(state.config.configPath);
|
|
1696
1897
|
const jobFilePath = join(dirPath, "job.json");
|
|
1697
1898
|
let job = {
|
|
1899
|
+
stateFormat: state.deps.jobStateFormat ?? JOB_STATE_FORMAT,
|
|
1698
1900
|
item: item.number,
|
|
1699
1901
|
queue,
|
|
1700
1902
|
claimId,
|
|
@@ -2514,6 +2716,13 @@ async function finishTrackedWhileAway(state, dirPath, job, where) {
|
|
|
2514
2716
|
`recovered job ${finished.queue} #${finished.item} (claim ${shortClaim(finished.claimId)}) as ${outcome}: ${code === void 0 ? `its container ${where === "missing" ? "is gone" : "stopped"} and its volume ${read.readable ? "holds no exit code" : "could not be read"}` : `its command recorded exit ${code}`}`
|
|
2515
2717
|
);
|
|
2516
2718
|
}
|
|
2719
|
+
async function logUnusableHelper(config, runtime, log) {
|
|
2720
|
+
if (!isBuiltinVm(config.hooks.provision)) return;
|
|
2721
|
+
const helper = await runtime.vm.helper.probe();
|
|
2722
|
+
if (helper.ok) return;
|
|
2723
|
+
if (helper.reason === "unsupported") log.line(helper.detail);
|
|
2724
|
+
else if (helper.unreachable === true) log.line(`${helper.detail}, so microVM builds run without the jailer`);
|
|
2725
|
+
}
|
|
2517
2726
|
async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
2518
2727
|
const log = deps.log ??= createRunnerLog(deps.now ?? (() => /* @__PURE__ */ new Date()));
|
|
2519
2728
|
const update = deps.update;
|
|
@@ -2521,7 +2730,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2521
2730
|
const outcome = await onStartUnderMarker({
|
|
2522
2731
|
configPath,
|
|
2523
2732
|
own: ownVersionOf(deps),
|
|
2524
|
-
check: update.check ? () => update.check(configPath) : async () => (await import('./check-
|
|
2733
|
+
check: update.check ? () => update.check(configPath) : async () => (await import('./check-EPYRTE3R.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
|
|
2525
2734
|
now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
|
|
2526
2735
|
log
|
|
2527
2736
|
});
|
|
@@ -2560,12 +2769,16 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2560
2769
|
const state = { config, jobs: /* @__PURE__ */ new Map(), deps, configMtimeMs };
|
|
2561
2770
|
log.line(`runner ${config.host} started \xB7 config ${configPath} \xB7 ${describeConfig(config)}`);
|
|
2562
2771
|
const nowMs = () => deps.now ? deps.now().getTime() : Date.now();
|
|
2563
|
-
|
|
2772
|
+
await logUnusableHelper(config, runtimeOf(state), log);
|
|
2773
|
+
const runningMicroVms = await stopOrphanedMicroVms({ jobs: unfinishedJobs(jobsDir(configPath)), runtime: runtimeOf(state), onError: (line) => log.error(line) }).catch((err) => {
|
|
2564
2774
|
log.error(`a microVM an earlier runner left could not be stopped: ${describeCallFailure(err)}`);
|
|
2565
2775
|
return [];
|
|
2566
2776
|
});
|
|
2567
2777
|
for (const buildId of runningMicroVms) log.line(`stopped microVM build ${buildId}, left running by an earlier runner`);
|
|
2568
2778
|
const attemptLogs = attemptLogsOf(state);
|
|
2779
|
+
for (const { job, format } of listUnreadableJobs(jobsDir(configPath))) {
|
|
2780
|
+
log.error(`leaving job ${job.queue} #${job.item} alone: its job-state format ${format} is not one this version reads`);
|
|
2781
|
+
}
|
|
2569
2782
|
for (const { dirPath, job } of listAdoptableJobs(jobsDir(configPath))) {
|
|
2570
2783
|
const adopted = { job, dirPath, lastRenewAtMs: nowMs(), cmd: null, cpuSample: null, ending: false };
|
|
2571
2784
|
state.jobs.set(dirPath, adopted);
|
|
@@ -2625,8 +2838,9 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2625
2838
|
const probeTimer = setInterval(() => {
|
|
2626
2839
|
for (const active of state.jobs.values()) void probeBuild(state, active);
|
|
2627
2840
|
}, deps.probeIntervalMs ?? PROBE_INTERVAL_MS);
|
|
2628
|
-
const onSigterm = () => void drain();
|
|
2841
|
+
const onSigterm = () => deps.image === void 0 ? void drain() : leave();
|
|
2629
2842
|
const onSigusr1 = () => void stopNow();
|
|
2843
|
+
const onSigusr2 = () => drainKeepingUp();
|
|
2630
2844
|
const onSigint = () => {
|
|
2631
2845
|
interrupts++;
|
|
2632
2846
|
if (interrupts === 1) {
|
|
@@ -2639,6 +2853,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2639
2853
|
const detachSignals = () => {
|
|
2640
2854
|
process.off("SIGTERM", onSigterm);
|
|
2641
2855
|
process.off("SIGUSR1", onSigusr1);
|
|
2856
|
+
process.off("SIGUSR2", onSigusr2);
|
|
2642
2857
|
process.off("SIGINT", onSigint);
|
|
2643
2858
|
};
|
|
2644
2859
|
const stopIntake = () => {
|
|
@@ -2685,6 +2900,19 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2685
2900
|
}
|
|
2686
2901
|
finish2();
|
|
2687
2902
|
};
|
|
2903
|
+
const drainKeepingUp = () => {
|
|
2904
|
+
if (state.draining === true) return;
|
|
2905
|
+
state.draining = true;
|
|
2906
|
+
stopIntake();
|
|
2907
|
+
log.line(`stopping: taking no more work, ${state.jobs.size} build(s) still managed \xB7 docker stop ends this container`);
|
|
2908
|
+
};
|
|
2909
|
+
const leave = () => {
|
|
2910
|
+
if (exited) return;
|
|
2911
|
+
log.line(`stopping: leaving ${state.jobs.size} running build(s) for the next runner to adopt`);
|
|
2912
|
+
state.draining = true;
|
|
2913
|
+
finish2();
|
|
2914
|
+
deps.image?.exit?.(0);
|
|
2915
|
+
};
|
|
2688
2916
|
const stopNow = async () => {
|
|
2689
2917
|
if (stopping) return;
|
|
2690
2918
|
stopping = true;
|
|
@@ -2705,6 +2933,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2705
2933
|
const handle = { state, drain, stopNow, close };
|
|
2706
2934
|
process.on("SIGTERM", onSigterm);
|
|
2707
2935
|
process.on("SIGUSR1", onSigusr1);
|
|
2936
|
+
if (deps.image !== void 0) process.on("SIGUSR2", onSigusr2);
|
|
2708
2937
|
process.on("SIGINT", onSigint);
|
|
2709
2938
|
deps.onReady?.();
|
|
2710
2939
|
await tick(state);
|
|
@@ -2717,7 +2946,8 @@ function describeWaiting(active, nowMs) {
|
|
|
2717
2946
|
}
|
|
2718
2947
|
var RunnerStartError = class extends Error {
|
|
2719
2948
|
};
|
|
2720
|
-
async function requestStop(configPath, stopNow = false, pollMs = 5e3) {
|
|
2949
|
+
async function requestStop(configPath, stopNow = false, pollMs = 5e3, options = {}) {
|
|
2950
|
+
const kill = options.kill ?? ((pid, signal2) => process.kill(pid, signal2));
|
|
2721
2951
|
const entry = readPidFile(pidFilePath(configPath));
|
|
2722
2952
|
if (!entry) {
|
|
2723
2953
|
process.stdout.write("no runner is running on this config\n");
|
|
@@ -2729,9 +2959,9 @@ async function requestStop(configPath, stopNow = false, pollMs = 5e3) {
|
|
|
2729
2959
|
`);
|
|
2730
2960
|
return;
|
|
2731
2961
|
}
|
|
2732
|
-
const signal = stopNow ? "SIGUSR1" : "SIGTERM";
|
|
2962
|
+
const signal = stopNow ? "SIGUSR1" : options.image === true ? "SIGUSR2" : "SIGTERM";
|
|
2733
2963
|
try {
|
|
2734
|
-
|
|
2964
|
+
kill(entry.pid, signal);
|
|
2735
2965
|
} catch (err) {
|
|
2736
2966
|
const code = err?.code;
|
|
2737
2967
|
if (code === "EPERM") {
|
|
@@ -2744,6 +2974,14 @@ async function requestStop(configPath, stopNow = false, pollMs = 5e3) {
|
|
|
2744
2974
|
`);
|
|
2745
2975
|
return;
|
|
2746
2976
|
}
|
|
2977
|
+
if (signal === "SIGUSR2") {
|
|
2978
|
+
process.stdout.write(
|
|
2979
|
+
`sent SIGUSR2 to runner pid ${entry.pid}: it takes no more work and keeps managing its builds.
|
|
2980
|
+
The container stays up. Run \`outerlayer runner status\` to see what is left, then \`docker stop\` the container once nothing is.
|
|
2981
|
+
`
|
|
2982
|
+
);
|
|
2983
|
+
return;
|
|
2984
|
+
}
|
|
2747
2985
|
process.stdout.write(
|
|
2748
2986
|
stopNow ? `sent SIGUSR1 to runner pid ${entry.pid}, stopping now
|
|
2749
2987
|
` : `sent SIGTERM to runner pid ${entry.pid}, draining
|
|
@@ -2777,4 +3015,4 @@ function runnerProcessState(configPath) {
|
|
|
2777
3015
|
return isSameProcess(entry.pid, entry.start) ? { state: "running", pid: entry.pid } : { state: "stale", pid: entry.pid };
|
|
2778
3016
|
}
|
|
2779
3017
|
|
|
2780
|
-
export { RunnerStartError, listJobFiles, probeBuild, probeCredentials, requestStop, runnerProcessState, start, tick, watchTick };
|
|
3018
|
+
export { RunnerStartError, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, start, tick, watchTick };
|
|
@@ -5,7 +5,7 @@ import { readCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
|
|
|
5
5
|
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
6
6
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
7
7
|
import { resolvePackageVersion } from './chunk-RA3O54FC.js';
|
|
8
|
-
import { signRunnerRequest, signerFor } from './chunk-
|
|
8
|
+
import { signRunnerRequest, signerFor } from './chunk-ZODVSFI4.js';
|
|
9
9
|
|
|
10
10
|
createRequire(import.meta.url);
|
|
11
11
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-
|
|
3
|
+
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZI2ZVWKT.js';
|
|
4
4
|
import { readFileSync, mkdirSync, writeFileSync, renameSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-
|
|
3
|
+
import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZI2ZVWKT.js';
|
|
4
4
|
import { readlinkSync, realpathSync, mkdirSync, unlinkSync, symlinkSync, renameSync, readFileSync, writeFileSync, rmSync, existsSync, readdirSync } from 'fs';
|
|
5
5
|
import { join, basename, sep, resolve } from 'path';
|
|
6
6
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { RecipeError, BUILDKIT_IMAGE } from './chunk-
|
|
3
|
+
import { RecipeError, BUILDKIT_IMAGE } from './chunk-RGW7ERF3.js';
|
|
4
4
|
import { parseSize } from './chunk-7RQ73DLO.js';
|
|
5
|
-
import { compareVersions } from './chunk-
|
|
6
|
-
import { ensureHostKey } from './chunk-
|
|
7
|
-
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE, runnerDir, jobsDir } from './chunk-
|
|
8
|
-
import { CLAUDE_PORT, JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-
|
|
9
|
-
import { JOIN_DIR, RELAY_ID, JOIN_SOCKET, TARGET_GATEWAY, TARGET_CLAUDE, destinationTarget, RELAY_USER } from './chunk-
|
|
5
|
+
import { compareVersions } from './chunk-D4AMAEZ7.js';
|
|
6
|
+
import { ensureHostKey } from './chunk-ZODVSFI4.js';
|
|
7
|
+
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE, runnerDir, jobsDir } from './chunk-ZI2ZVWKT.js';
|
|
8
|
+
import { CLAUDE_PORT, JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-2K3TCQHW.js';
|
|
9
|
+
import { JOIN_DIR, RELAY_ID, JOIN_SOCKET, TARGET_GATEWAY, TARGET_CLAUDE, destinationTarget, RELAY_USER } from './chunk-JGD5TWQ2.js';
|
|
10
10
|
import { StringDecoder } from 'string_decoder';
|
|
11
11
|
import { spawn } from 'child_process';
|
|
12
12
|
import { existsSync, readFileSync, mkdirSync, createWriteStream, rmSync, chmodSync, writeFileSync, realpathSync, readdirSync, renameSync } from 'fs';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { RUNNER_DIR_MODE } from './chunk-
|
|
3
|
+
import { launcherPath, writeLauncher, LauncherWriteError, pathNotes } from './chunk-ATGHVEU4.js';
|
|
4
|
+
import { currentVersion, currentLink, isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-QMQC6JCO.js';
|
|
5
|
+
import { compareVersions } from './chunk-TQMI335S.js';
|
|
6
|
+
import { RUNNER_DIR_MODE } from './chunk-ZI2ZVWKT.js';
|
|
7
7
|
import { realpathSync, readFileSync, mkdirSync, rmSync, cpSync, existsSync } from 'fs';
|
|
8
8
|
import { dirname, sep, join } from 'path';
|
|
9
9
|
|
|
@@ -92,7 +92,7 @@ function launcherSummary(launcher) {
|
|
|
92
92
|
}
|
|
93
93
|
function restartNote(result) {
|
|
94
94
|
if (result.previous === void 0 || result.previous === result.version) return void 0;
|
|
95
|
-
return `current moved from ${result.previous} to ${result.version}: a runner its service started
|
|
95
|
+
return `current moved from ${result.previous} to ${result.version}: a runner its service started restarts on ${result.version} at once when its running builds are container builds that carry on through the restart. Otherwise it takes no new work and waits for them to finish. A runner started by hand keeps running until you restart it`;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export { RunnerDowngradeError, RunnerInstallError, launcherSummary, restartNote, runRunnerInstall };
|