@outerlayer/cli 0.5.1 → 0.7.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 +29 -0
- package/README.md +19 -0
- package/dist/{agent-setup-IFH3FB5X.js → agent-setup-TXLDY5RV.js} +7 -6
- package/dist/{build-PAEKVYVK.js → build-JF5UOWKJ.js} +2 -1
- package/dist/build-info.json +1 -1
- package/dist/{check-4Q33B5ZE.js → check-ASZL5BEO.js} +39 -23
- package/dist/chunk-2VO25HHO.js +75 -0
- package/dist/{chunk-XDDW4FRS.js → chunk-5FWNEQNZ.js} +3 -3
- package/dist/{chunk-CHLVJNTE.js → chunk-6IYLDODX.js} +18 -6
- package/dist/{chunk-W7UTFZDH.js → chunk-6QWV3YDJ.js} +2 -2
- package/dist/{chunk-EGABNHZG.js → chunk-6ZZHWY2Z.js} +149 -18
- package/dist/{lima-XN65D7GN.js → chunk-77MM5RYD.js} +0 -1
- package/dist/chunk-7FTNIAHS.js +211 -0
- package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
- package/dist/{chunk-F4NU4H3V.js → chunk-AII7CKTH.js} +133 -35
- package/dist/{chunk-ZXBITXTS.js → chunk-AIW6GLET.js} +1 -1
- package/dist/{chunk-UWH5DSUP.js → chunk-AJKEHABI.js} +507 -90
- package/dist/{chunk-RTXKYLCA.js → chunk-AQ54MKSQ.js} +2 -2
- package/dist/{chunk-Z62HNKEJ.js → chunk-CEBIA5FD.js} +31 -5
- package/dist/{chunk-EX6M5JPR.js → chunk-D6FXM5OW.js} +6302 -28611
- package/dist/{chunk-RMAZ2NWA.js → chunk-DGAIVMMN.js} +23 -2
- package/dist/{chunk-3DD6AOWC.js → chunk-DTXOJDEH.js} +26 -2
- package/dist/{chunk-T52PKE2Y.js → chunk-E4PIFIC3.js} +244 -17
- package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
- package/dist/chunk-FBTE2A2X.js +38 -0
- package/dist/{chunk-DVDEBNQJ.js → chunk-GQD22KKN.js} +17 -6
- package/dist/{chunk-BCJNHMZT.js → chunk-HHJDN6AU.js} +18 -3
- package/dist/chunk-HKMPVPO7.js +55 -0
- package/dist/{chunk-UFFXNXLQ.js → chunk-JPR2WHHF.js} +31 -29
- package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
- package/dist/{chunk-H4CK2YK4.js → chunk-MQPRB5K7.js} +18 -10
- package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
- package/dist/chunk-OUUINEYB.js +27 -0
- package/dist/chunk-PUN7LMNS.js +39 -0
- package/dist/{install-cmd-7WXOIFDO.js → chunk-Q5G2ODUZ.js} +1 -2
- package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
- package/dist/{chunk-OR6AEEDO.js → chunk-SSU747O6.js} +85 -25
- package/dist/chunk-T6OIJQRT.js +31 -0
- package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
- package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
- package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
- package/dist/{chunk-JLDZTG3A.js → chunk-X2FSFU4C.js} +4 -1
- package/dist/chunk-YNJEOGDL.js +22434 -0
- package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
- package/dist/{chunk-WOBNRVQT.js → chunk-ZYHKJKSU.js} +1 -1
- package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
- package/dist/{cli-LHSUYYMI.js → cli-LEVCGAQV.js} +154 -79
- package/dist/command-FLSYCGIB.js +187 -0
- package/dist/config-I3TVFYLH.js +10 -0
- package/dist/{connect-cmd-OJBFHZWP.js → connect-cmd-MJMUONDY.js} +4 -4
- package/dist/{context-adopt-UMA4O5NY.js → context-adopt-CE4KDXS3.js} +5 -4
- package/dist/{context-materialize-G2FUFC72.js → context-materialize-QL33HDJN.js} +5 -4
- package/dist/{dist-WDV7U7UJ.js → dist-PXBSA7QX.js} +2 -1
- package/dist/{doctor-MOA3RIEP.js → doctor-FVDT3KJZ.js} +46 -19
- package/dist/{emit-artifact-cmd-FDWYKURA.js → emit-artifact-cmd-7RPMRSVP.js} +13 -7
- package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
- package/dist/{emit-criteria-cmd-OCXHLK34.js → emit-criteria-cmd-MKI7WETO.js} +12 -3
- package/dist/{emit-finding-cmd-POW7PKIA.js → emit-finding-cmd-RMLGZASB.js} +14 -3
- package/dist/{emit-result-cmd-ID35SH53.js → emit-result-cmd-MTXAZ2GV.js} +15 -9
- package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
- package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
- package/dist/{hook-fast-EYENPK6F.js → hook-fast-XBOZ3N6L.js} +1 -1
- package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
- package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
- package/dist/index.js +3 -2
- package/dist/{init-FYDJAKTM.js → init-BACXESVV.js} +21 -14
- package/dist/{init-2IPOIXJV.js → init-VLW7H6RW.js} +40 -62
- package/dist/{init-cmd-KLIDRVXQ.js → init-cmd-VJFB5L7X.js} +10 -9
- package/dist/inspect-XAUSB7L3.js +63 -0
- package/dist/install-NMAPLLBQ.js +14 -0
- package/dist/install-cmd-B5SEU3G7.js +8 -0
- package/dist/lima-7NPCNGWT.js +6 -0
- package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
- package/dist/loop-D3243JKT.js +64 -0
- package/dist/{machine-ECU3QCZD.js → machine-EB3GEVI4.js} +20 -13
- package/dist/session-sender-LMACEJJS.js +29 -0
- package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
- package/dist/{status-CLATHCTQ.js → status-F4THTJJK.js} +36 -16
- package/dist/{sync-cmd-SWQ5KLPL.js → sync-cmd-M6JA3OEE.js} +7 -7
- package/dist/{watch-3YW6Z3DQ.js → watch-NB5TGPEZ.js} +7 -7
- package/dist/{work-claim-cmd-3OPWA77E.js → work-claim-cmd-UHMWOS3G.js} +14 -7
- package/dist/{work-cmd-NUR4CAG6.js → work-cmd-6UMCFTAW.js} +9 -3
- package/dist/{work-comment-cmd-6TTTYGHM.js → work-comment-cmd-E4LEUIXZ.js} +9 -3
- package/dist/{work-launch-YI4CJDAP.js → work-launch-R5HTAP6X.js} +1 -1
- package/dist/{work-open-pr-cmd-KZ7QQFLD.js → work-open-pr-cmd-OPZWGSEQ.js} +10 -4
- package/dist/{work-pr-cmd-QNUBE6IQ.js → work-pr-cmd-IDIAFFRU.js} +9 -2
- package/package.json +2 -1
- package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
- package/dist/chunk-D2KWEAN6.js +0 -55
- package/dist/chunk-ZOC7JSYC.js +0 -83
- package/dist/config-HL2AIR3K.js +0 -9
- package/dist/loop-NEBUGD2Q.js +0 -45
|
@@ -1,33 +1,79 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { LEASE_SECONDS, releaseLease, isUnfinished, writeJobFile, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, readJobFile, hookLimitsFor, readJobFileChecked, ALREADY_RELEASED } from './chunk-UWH5DSUP.js';
|
|
4
|
-
import { RUNNER_PROTOCOL } from './chunk-ZXBITXTS.js';
|
|
5
|
-
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
|
|
6
3
|
import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-ABIWDUMS.js';
|
|
7
|
-
import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-
|
|
4
|
+
import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-TI7B7UEO.js';
|
|
5
|
+
import { LEASE_SECONDS, releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, ALREADY_RELEASED } from './chunk-AJKEHABI.js';
|
|
6
|
+
import { writeJobFile, readJobFile, readJobFileChecked } from './chunk-T6OIJQRT.js';
|
|
7
|
+
import { RUNNER_PROTOCOL } from './chunk-AIW6GLET.js';
|
|
8
|
+
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
|
|
9
|
+
import { placeholderQueues, placeholderProblem } from './chunk-6IYLDODX.js';
|
|
8
10
|
import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
|
|
9
11
|
import { RepoFilter } from './chunk-TBT347UY.js';
|
|
10
|
-
import {
|
|
12
|
+
import { checkFit } from './chunk-OUUINEYB.js';
|
|
13
|
+
import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, measureDisk, createRunnerLog, setUpRunnerCgroup, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, formatClock, runnerLabelValue, BUILD_LABEL, RUNNER_LABEL } from './chunk-E4PIFIC3.js';
|
|
11
14
|
import { startTimeOf, claimPidFile, readPidFile, isSameProcess, releasePidFile } from './chunk-N5FOE5PS.js';
|
|
12
15
|
import { spawnRun } from './chunk-774HEQL6.js';
|
|
13
|
-
import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-
|
|
14
|
-
import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-
|
|
16
|
+
import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-DGAIVMMN.js';
|
|
17
|
+
import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-DTXOJDEH.js';
|
|
15
18
|
import { exceedsDisk } from './chunk-F6GFZXZ3.js';
|
|
16
|
-
import {
|
|
19
|
+
import { sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-OD2VTIHN.js';
|
|
20
|
+
import { parseClaimIdentity } from './chunk-HKMPVPO7.js';
|
|
17
21
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
18
22
|
import { loadHostKey, ensureHostKey, signerFor } from './chunk-M5POMKKW.js';
|
|
19
23
|
import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, jobsDir, pidFilePath, spoolDir, RUNNER_FILE_MODE, rootfsDir } from './chunk-ZM2IMMYN.js';
|
|
20
24
|
import { HOOKS_DIR_NAME, writeCommitHooks } from './chunk-XCCLFVXM.js';
|
|
21
25
|
import { randomBytes } from 'crypto';
|
|
22
|
-
import { mkdirSync, existsSync, chmodSync, statSync, readdirSync, readFileSync, rmSync, renameSync, writeFileSync, lstatSync } from 'fs';
|
|
26
|
+
import { mkdirSync, existsSync, chmodSync, statSync, readdirSync, readFileSync, rmSync, renameSync, writeFileSync, closeSync, openSync, constants, lstatSync } from 'fs';
|
|
23
27
|
import { join, dirname } from 'path';
|
|
28
|
+
import { totalmem } from 'os';
|
|
24
29
|
|
|
25
30
|
createRequire(import.meta.url);
|
|
31
|
+
function openKvm() {
|
|
32
|
+
try {
|
|
33
|
+
closeSync(openSync("/dev/kvm", constants.O_RDWR));
|
|
34
|
+
return "usable";
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return err.code === "ENOENT" ? "absent" : "no-permission";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function realBlockedProbes() {
|
|
40
|
+
return { env: process.env, kvm: openKvm, totalMemoryBytes: totalmem };
|
|
41
|
+
}
|
|
42
|
+
var DEFAULT_BUILD_MEMORY = "8g";
|
|
43
|
+
function checkBlocked(config, probes) {
|
|
44
|
+
const placeholders = placeholderQueues(config);
|
|
45
|
+
if (placeholders.length > 0) return { reason: `${placeholderProblem(placeholders)}. The runner takes work again once the config is edited` };
|
|
46
|
+
const kind = builtinKind(config.hooks.provision);
|
|
47
|
+
if (kind === "container" || kind === "vm") {
|
|
48
|
+
const fit = checkFit({
|
|
49
|
+
concurrency: config.concurrency,
|
|
50
|
+
buildMemory: config.build?.memory ?? DEFAULT_BUILD_MEMORY,
|
|
51
|
+
usableBytes: probes.totalMemoryBytes()
|
|
52
|
+
});
|
|
53
|
+
if (!fit.fits) return { reason: `${fit.message}. Lower runner.concurrency or runner.build.memory` };
|
|
54
|
+
}
|
|
55
|
+
const kvm = kind === "vm" ? probes.kvm() : "usable";
|
|
56
|
+
if (kvm === "absent") {
|
|
57
|
+
return { reason: "/dev/kvm does not exist on this machine, so builtin:vm cannot start a microVM. Use a host with KVM enabled, or builtin:container hooks" };
|
|
58
|
+
}
|
|
59
|
+
if (kvm !== "usable") {
|
|
60
|
+
return {
|
|
61
|
+
reason: "the runner cannot open /dev/kvm, so builtin:vm cannot start a microVM. Add the runner's account to the kvm group, then restart the service, because a service reads its groups only when it starts"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (kind !== "own" && claudeCredential(probes.env) === void 0) {
|
|
65
|
+
return {
|
|
66
|
+
reason: "there is no Claude credential in the runner's environment. Put CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`) or ANTHROPIC_API_KEY in the runner.env beside the config, then restart the service"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
26
71
|
|
|
27
72
|
// src/runner/heartbeat.ts
|
|
28
73
|
var HEARTBEAT_TIMEOUT_MS = 1e4;
|
|
29
74
|
var ERROR_CODE_MAX = 100;
|
|
30
75
|
var ERROR_MESSAGE_MAX = 500;
|
|
76
|
+
var BLOCKED_REASON_MAX = 500;
|
|
31
77
|
var UNREACHABLE_MESSAGE = "the request did not reach the platform";
|
|
32
78
|
function noPlatformMessage(status) {
|
|
33
79
|
return `the request got HTTP ${status} with no error message from the platform`;
|
|
@@ -73,7 +119,9 @@ async function sendHeartbeat(args, fetchImpl) {
|
|
|
73
119
|
...args.lastUpdate.at !== void 0 ? { at: args.lastUpdate.at } : {}
|
|
74
120
|
},
|
|
75
121
|
// Free disk on the runner's file system, in bytes. Sent only while held, so a host with room sends nothing about its disk.
|
|
76
|
-
lowDisk: args.lowDisk === void 0 ? void 0 : { free: args.lowDisk.free, needed: args.lowDisk.needed }
|
|
122
|
+
lowDisk: args.lowDisk === void 0 ? void 0 : { free: args.lowDisk.free, needed: args.lowDisk.needed },
|
|
123
|
+
// Why the runner claims nothing. Sent only while it holds, so a runner that takes work says nothing about it.
|
|
124
|
+
blocked: args.blocked === void 0 ? void 0 : { reason: cutForGateway(args.blocked.reason, BLOCKED_REASON_MAX) }
|
|
77
125
|
};
|
|
78
126
|
try {
|
|
79
127
|
const response = await postJson(
|
|
@@ -643,7 +691,7 @@ function selectJobDirs(entries, nowMs, keepDays) {
|
|
|
643
691
|
function liveBuildIds(jobs) {
|
|
644
692
|
const ids = /* @__PURE__ */ new Set();
|
|
645
693
|
for (const job of jobs) {
|
|
646
|
-
for (const id of [job.container?.buildId, job.microvm?.buildId, job.build?.buildId]) if (id !== void 0) ids.add(id);
|
|
694
|
+
for (const id of [job.container?.buildId, job.microvm?.buildId, job.build?.buildId, job.checkContainer?.buildId]) if (id !== void 0) ids.add(id);
|
|
647
695
|
}
|
|
648
696
|
return ids;
|
|
649
697
|
}
|
|
@@ -964,7 +1012,8 @@ async function sendTickHeartbeat(state, workRequest) {
|
|
|
964
1012
|
slotsTotal: state.config.concurrency,
|
|
965
1013
|
workRequest: next,
|
|
966
1014
|
lastUpdate: readLastUpdate(state.config.configPath),
|
|
967
|
-
lowDisk: state.lowDisk
|
|
1015
|
+
lowDisk: state.lowDisk,
|
|
1016
|
+
blocked: state.blocked
|
|
968
1017
|
},
|
|
969
1018
|
state.deps.fetchImpl
|
|
970
1019
|
);
|
|
@@ -1088,6 +1137,25 @@ async function tick(state) {
|
|
|
1088
1137
|
}
|
|
1089
1138
|
await sendTickHeartbeat(state, state.lastWorkRequest);
|
|
1090
1139
|
}
|
|
1140
|
+
function holdWhenBlocked(state) {
|
|
1141
|
+
const probes = {
|
|
1142
|
+
...realBlockedProbes(),
|
|
1143
|
+
...state.deps.container?.hostEnv === void 0 ? {} : { env: state.deps.container.hostEnv },
|
|
1144
|
+
...state.deps.blocked
|
|
1145
|
+
};
|
|
1146
|
+
const blocked = checkBlocked(state.config, probes);
|
|
1147
|
+
const log = logOf(state);
|
|
1148
|
+
if (blocked !== void 0) {
|
|
1149
|
+
if (state.blocked?.reason !== blocked.reason) log.line(`claiming nothing: ${blocked.reason}`);
|
|
1150
|
+
state.blocked = blocked;
|
|
1151
|
+
return true;
|
|
1152
|
+
}
|
|
1153
|
+
if (state.blocked !== void 0) {
|
|
1154
|
+
state.blocked = void 0;
|
|
1155
|
+
log.line("the runner can run its work again \xB7 taking work");
|
|
1156
|
+
}
|
|
1157
|
+
return false;
|
|
1158
|
+
}
|
|
1091
1159
|
function holdOffForDisk(state) {
|
|
1092
1160
|
const minimum = state.config.housekeeping?.minFreeDisk ?? 0;
|
|
1093
1161
|
const root = runnerDir(state.config.configPath);
|
|
@@ -1145,6 +1213,7 @@ async function housekeepingPass(state) {
|
|
|
1145
1213
|
async function runTick(state) {
|
|
1146
1214
|
reloadConfig(state);
|
|
1147
1215
|
if (await updateWhenIdle(state)) return;
|
|
1216
|
+
if (holdWhenBlocked(state)) return;
|
|
1148
1217
|
if (holdOffForDisk(state)) return;
|
|
1149
1218
|
const log = logOf(state);
|
|
1150
1219
|
const repoFilter = new RepoFilter(state.config.repos);
|
|
@@ -1199,7 +1268,7 @@ var CLAIM_REFUSAL_CODES = new Set(
|
|
|
1199
1268
|
"pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous branch_claimed_elsewhere".split(" ")
|
|
1200
1269
|
);
|
|
1201
1270
|
async function tryClaimAndStart(state, item, queue) {
|
|
1202
|
-
const { postJson: postJson2 } = await import('./work-cmd-
|
|
1271
|
+
const { postJson: postJson2 } = await import('./work-cmd-6UMCFTAW.js');
|
|
1203
1272
|
const log = logOf(state);
|
|
1204
1273
|
const hostKey = await loadHostKey(state.config.configPath);
|
|
1205
1274
|
const claim = await retrySend(
|
|
@@ -1327,6 +1396,7 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity)
|
|
|
1327
1396
|
itemKey,
|
|
1328
1397
|
branch,
|
|
1329
1398
|
commitIdentity: identity,
|
|
1399
|
+
...item.specRepository === void 0 || item.specRepository === null || item.specRepository === "" ? {} : { repository: item.specRepository },
|
|
1330
1400
|
startedAt: startedAt.toISOString()
|
|
1331
1401
|
};
|
|
1332
1402
|
writeJobFile(jobFilePath, job);
|
|
@@ -1678,6 +1748,17 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity)
|
|
|
1678
1748
|
writeJobFile(jobFilePath, job);
|
|
1679
1749
|
const commandStartedMs = nowOf(state).getTime();
|
|
1680
1750
|
log.line(`${tag} command started \xB7 pid ${running.pid}`);
|
|
1751
|
+
const sender = await startSender({
|
|
1752
|
+
config: state.config,
|
|
1753
|
+
job,
|
|
1754
|
+
jobDir: dirPath,
|
|
1755
|
+
deps: { spawnFn: state.deps.spawnFn, runtime: job.microvm !== void 0 || job.container !== void 0 ? runtimeOf(state) : void 0, log }
|
|
1756
|
+
});
|
|
1757
|
+
if (sender !== void 0) {
|
|
1758
|
+
job = { ...active.job, sender };
|
|
1759
|
+
active.job = job;
|
|
1760
|
+
writeJobFile(jobFilePath, job);
|
|
1761
|
+
}
|
|
1681
1762
|
running.onExit.then(({ code, signal, error }) => {
|
|
1682
1763
|
if (active.ending) return;
|
|
1683
1764
|
if (error !== void 0) {
|
|
@@ -1785,8 +1866,39 @@ async function endJob(state, active, outcome, ending) {
|
|
|
1785
1866
|
state.jobs.delete(active.dirPath);
|
|
1786
1867
|
}
|
|
1787
1868
|
}
|
|
1869
|
+
async function renewLeaseIfDue(state, active, nowMs) {
|
|
1870
|
+
const log = logOf(state);
|
|
1871
|
+
const tag = `#${active.job.item}`;
|
|
1872
|
+
if (!needsRenew(active.lastRenewAtMs, nowMs)) return true;
|
|
1873
|
+
const renew = await retrySend(() => renewLease(state.config, active.job.item, state.deps.fetchImpl), {
|
|
1874
|
+
now: state.deps.now,
|
|
1875
|
+
sleep: state.deps.sleep
|
|
1876
|
+
});
|
|
1877
|
+
const result = renew.ok ? renew.value : "retry_later";
|
|
1878
|
+
if (result === "lease_lost") {
|
|
1879
|
+
if (active.ending) {
|
|
1880
|
+
log.error(`${tag} lease lost while the checks ran`);
|
|
1881
|
+
return false;
|
|
1882
|
+
}
|
|
1883
|
+
log.error(`${tag} lease lost \xB7 ending job as lease_lost`);
|
|
1884
|
+
await endJob(state, active, "lease_lost");
|
|
1885
|
+
return false;
|
|
1886
|
+
}
|
|
1887
|
+
if (result === "renewed") {
|
|
1888
|
+
active.job.lastRenewAt = new Date(nowMs).toISOString();
|
|
1889
|
+
writeJobFile(join(active.dirPath, "job.json"), active.job);
|
|
1890
|
+
log.line(`${tag} lease renewed \xB7 expires ${formatClock(new Date(nowMs + LEASE_SECONDS * 1e3), new Date(nowMs))}`);
|
|
1891
|
+
} else {
|
|
1892
|
+
log.error(`${tag} renew did not land \xB7 retrying in ${RENEW_INTERVAL_SECONDS / 60}m`);
|
|
1893
|
+
}
|
|
1894
|
+
active.lastRenewAtMs = nowMs;
|
|
1895
|
+
return true;
|
|
1896
|
+
}
|
|
1788
1897
|
async function watchTick(state, active, nowMs, logMtimeMs) {
|
|
1789
|
-
if (active.ending)
|
|
1898
|
+
if (active.ending) {
|
|
1899
|
+
if (active.job.stage === "checks") await renewLeaseIfDue(state, active, nowMs);
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1790
1902
|
const log = logOf(state);
|
|
1791
1903
|
const tag = `#${active.job.item}`;
|
|
1792
1904
|
const pid = active.job.pid;
|
|
@@ -1804,26 +1916,7 @@ async function watchTick(state, active, nowMs, logMtimeMs) {
|
|
|
1804
1916
|
}
|
|
1805
1917
|
return;
|
|
1806
1918
|
}
|
|
1807
|
-
if (
|
|
1808
|
-
const renew = await retrySend(() => renewLease(state.config, active.job.item, state.deps.fetchImpl), {
|
|
1809
|
-
now: state.deps.now,
|
|
1810
|
-
sleep: state.deps.sleep
|
|
1811
|
-
});
|
|
1812
|
-
const result = renew.ok ? renew.value : "retry_later";
|
|
1813
|
-
if (result === "lease_lost") {
|
|
1814
|
-
log.error(`${tag} lease lost \xB7 ending job as lease_lost`);
|
|
1815
|
-
await endJob(state, active, "lease_lost");
|
|
1816
|
-
return;
|
|
1817
|
-
}
|
|
1818
|
-
if (result === "renewed") {
|
|
1819
|
-
active.job.lastRenewAt = new Date(nowMs).toISOString();
|
|
1820
|
-
writeJobFile(join(active.dirPath, "job.json"), active.job);
|
|
1821
|
-
log.line(`${tag} lease renewed \xB7 expires ${formatClock(new Date(nowMs + LEASE_SECONDS * 1e3), new Date(nowMs))}`);
|
|
1822
|
-
} else {
|
|
1823
|
-
log.error(`${tag} renew did not land \xB7 retrying in ${RENEW_INTERVAL_SECONDS / 60}m`);
|
|
1824
|
-
}
|
|
1825
|
-
active.lastRenewAtMs = nowMs;
|
|
1826
|
-
}
|
|
1919
|
+
if (!await renewLeaseIfDue(state, active, nowMs)) return;
|
|
1827
1920
|
const tokens = active.job.container === void 0 && active.job.microvm === void 0 ? void 0 : runtimeOf(state).credentials.get(active.dirPath);
|
|
1828
1921
|
if (tokens !== void 0) {
|
|
1829
1922
|
await tokens.renewReadIfDue();
|
|
@@ -1899,7 +1992,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
1899
1992
|
const outcome = await onStartUnderMarker({
|
|
1900
1993
|
configPath,
|
|
1901
1994
|
own: ownVersionOf(deps),
|
|
1902
|
-
check: update.check ? () => update.check(configPath) : async () => (await import('./check-
|
|
1995
|
+
check: update.check ? () => update.check(configPath) : async () => (await import('./check-ASZL5BEO.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
|
|
1903
1996
|
now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
|
|
1904
1997
|
log
|
|
1905
1998
|
});
|
|
@@ -1918,6 +2011,11 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
1918
2011
|
mkdirSync(jobsDir(configPath), { recursive: true, mode: RUNNER_DIR_MODE });
|
|
1919
2012
|
const self = { pid: process.pid, start: startTimeOf(process.pid) ?? "" };
|
|
1920
2013
|
claimPidFile(pidFilePath(configPath), self);
|
|
2014
|
+
const { delegated, refusal } = setUpRunnerCgroup();
|
|
2015
|
+
if (refusal !== void 0) log.error(`the kernel refused a cgroup step for the runner's service: ${refusal}`);
|
|
2016
|
+
if (isBuiltinVm(config.hooks.provision) && !delegated) {
|
|
2017
|
+
log.line("microVM builds run with no memory limit of their own: the runner's service is not delegated its cgroup (Delegate=yes in the unit, cgroup v2)");
|
|
2018
|
+
}
|
|
1921
2019
|
let configMtimeMs;
|
|
1922
2020
|
try {
|
|
1923
2021
|
configMtimeMs = statSync(configPath).mtimeMs;
|