@outerlayer/cli 0.26.4 → 0.27.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 +16 -0
- package/README.md +12 -9
- package/dist/{agent-setup-5DXPEO64.js → agent-setup-UW36TAQM.js} +11 -11
- package/dist/{bridge-5KZ36YDG.js → bridge-B5VJVECY.js} +2 -2
- package/dist/{build-F5QWH7G5.js → build-TNM7HYCA.js} +4 -4
- package/dist/build-info.json +1 -1
- package/dist/{builder-KDUXCHTY.js → builder-LDJGS2JC.js} +5 -5
- package/dist/{check-ZSYCR5WG.js → check-JVBAWIN6.js} +40 -39
- package/dist/{chunk-GFHLEVUE.js → chunk-24ID7EQ2.js} +6 -3
- package/dist/{chunk-H57M3HC7.js → chunk-2F762IXY.js} +2 -2
- package/dist/{chunk-2K3TCQHW.js → chunk-2I3LIRZP.js} +26 -8
- package/dist/{chunk-6CGXSMKX.js → chunk-55GNQPO6.js} +17 -6
- package/dist/{chunk-MWPBF2XG.js → chunk-6KKM7VGZ.js} +32 -4
- package/dist/{chunk-VPEGE3QZ.js → chunk-6TRNCUM4.js} +1 -1
- package/dist/{chunk-6SPXKRQR.js → chunk-7AQ5AM7U.js} +12 -5
- package/dist/{chunk-HBISTTG3.js → chunk-7OUOLGUV.js} +20 -5
- package/dist/{chunk-NWPRNKZ5.js → chunk-ABXQBEYK.js} +1 -1
- package/dist/chunk-BM7EC3OZ.js +181 -0
- package/dist/{chunk-4UFSTKE5.js → chunk-BPKO76QR.js} +4 -4
- package/dist/{chunk-MCSINUVC.js → chunk-BWH36FOC.js} +1 -1
- package/dist/{chunk-IZAOO5AR.js → chunk-D7ECMB7B.js} +4 -4
- package/dist/{chunk-UZEQVPKF.js → chunk-DJHNEGNM.js} +27 -3
- package/dist/{chunk-O4362FPA.js → chunk-E5IJ5533.js} +2 -2
- package/dist/{chunk-JWRX5ZTT.js → chunk-EPPIISRD.js} +2 -2
- package/dist/{chunk-KNBWOL2B.js → chunk-FP23SVDD.js} +5 -5
- package/dist/{chunk-6WTAYEKJ.js → chunk-G3EZA6MK.js} +55 -7
- package/dist/{chunk-VGHKTSHU.js → chunk-GFUE5TKO.js} +3 -3
- package/dist/{chunk-XLC7KEUV.js → chunk-GLUKDQS4.js} +1 -1
- package/dist/{chunk-QUP6CVBQ.js → chunk-JH2GQU5T.js} +4 -4
- package/dist/{chunk-JKNYTNYD.js → chunk-LOKSLO25.js} +1 -1
- package/dist/{chunk-2J46BQ5Y.js → chunk-M3MHHIUW.js} +1 -1
- package/dist/{chunk-7Z2WMXM5.js → chunk-MATUHHN4.js} +1 -1
- package/dist/{chunk-MQ743JX3.js → chunk-MHX7YX7Y.js} +1 -1
- package/dist/{chunk-PZA6ZFYW.js → chunk-N4D5TMVU.js} +2 -2
- package/dist/{chunk-WK35HB56.js → chunk-O2IJTY7L.js} +2 -2
- package/dist/{chunk-K4FXNMV5.js → chunk-QHH4OSD4.js} +1 -1
- package/dist/{chunk-OQUD3UYF.js → chunk-QIVOTQOQ.js} +5 -5
- package/dist/{chunk-Y4BXRVDI.js → chunk-QKIQ2R7F.js} +3 -3
- package/dist/{chunk-F3BBEBPL.js → chunk-RHAGBUL5.js} +1 -1
- package/dist/{chunk-OFTFW7TH.js → chunk-RHGF73IU.js} +1 -1
- package/dist/{chunk-27RDUTQH.js → chunk-RK7FWC6B.js} +194 -38
- package/dist/{chunk-6MZSX4M7.js → chunk-STSLH5EJ.js} +3 -1
- package/dist/{chunk-ZMZGWLYD.js → chunk-TXHJ7BGR.js} +13 -13
- package/dist/{chunk-EHBDYLM6.js → chunk-UQYBCJ2L.js} +2 -2
- package/dist/{chunk-VQ7OAG6H.js → chunk-VS27BP3E.js} +4 -4
- package/dist/{chunk-OZKEEXVH.js → chunk-WSYXLLA5.js} +6 -6
- package/dist/{chunk-WX2WEERU.js → chunk-WUL2OP5A.js} +3 -3
- package/dist/{chunk-UOGQZQXN.js → chunk-WVDP6HVZ.js} +6 -6
- package/dist/{chunk-MXTN35XN.js → chunk-XBPUTQ7E.js} +1 -1
- package/dist/{chunk-UNF7MWEL.js → chunk-XS3FDWSZ.js} +1 -1
- package/dist/{chunk-VJBFQP3H.js → chunk-XZ6Q6ZNR.js} +9 -5
- package/dist/{chunk-GWRDL75D.js → chunk-Y4OKEFAX.js} +1 -1
- package/dist/{chunk-Q2SVLBMI.js → chunk-Y7ZCHBYB.js} +2 -2
- package/dist/chunk-YB3CSYXX.js +95 -0
- package/dist/{chunk-SBW4K3XZ.js → chunk-YF56R4DV.js} +75 -29
- package/dist/chunk-YJLHUKYS.js +38 -0
- package/dist/{chunk-V3YJFEZA.js → chunk-ZXRWMOJ3.js} +274 -45
- package/dist/{claude-launcher-TTLTS4N6.js → claude-launcher-TKX4WCUN.js} +8 -4
- package/dist/{cli-SKF3AMZ5.js → cli-XVXQDKZT.js} +133 -127
- package/dist/{command-E5OG5NCH.js → command-B2T7VR77.js} +29 -28
- package/dist/{config-JJ3EO7SB.js → config-TWS5VZEN.js} +3 -3
- package/dist/{connect-cmd-SL4S5HJM.js → connect-cmd-HGS7YPA2.js} +7 -7
- package/dist/{container-start-IA2HK4QI.js → container-start-JE7HTKZG.js} +28 -27
- package/dist/{control-plane-launch-JIQOE6BP.js → control-plane-launch-DBQA3KLJ.js} +8 -8
- package/dist/{docker-KKE5Q5S2.js → docker-MJEEHUUA.js} +5 -5
- package/dist/{doctor-U2N7AF3N.js → doctor-6ZIF2BRZ.js} +180 -33
- package/dist/{emit-artifact-cmd-SDG5H6D7.js → emit-artifact-cmd-ALDK55Y2.js} +11 -11
- package/dist/{emit-cmd-WQH2NK7H.js → emit-cmd-VAQHRWJR.js} +4 -4
- package/dist/{emit-criteria-cmd-QGSP77AG.js → emit-criteria-cmd-Q7SM6VP2.js} +8 -8
- package/dist/{emit-finding-cmd-6FGMTEFM.js → emit-finding-cmd-2NBAPDSV.js} +8 -8
- package/dist/{emit-result-cmd-AUPIXPEU.js → emit-result-cmd-KUSL56RI.js} +11 -11
- package/dist/{emit-step-cmd-PORHEKHN.js → emit-step-cmd-KD4AKEAT.js} +9 -9
- package/dist/{exec-client-J6L5FDRR.js → exec-client-6WVS7DRZ.js} +3 -3
- package/dist/{governing-source-YPBK4H5H.js → governing-source-VVUA5TKB.js} +13 -13
- package/dist/{guest-init-CXIHA5VI.js → guest-init-H5K2RW3P.js} +4 -4
- package/dist/{hook-fast-XMZFMBKC.js → hook-fast-3SUJM765.js} +1 -1
- package/dist/{host-key-GQFBRX3J.js → host-key-XNKZCWTS.js} +3 -3
- package/dist/{image-tag-W4JKVNP4.js → image-tag-R34J4O3F.js} +3 -3
- package/dist/index.js +4 -4
- package/dist/{init-GEFKJNJU.js → init-ETKGFCXR.js} +28 -27
- package/dist/{init-Y64OAKKQ.js → init-Q2RPUUVP.js} +29 -28
- package/dist/{init-cmd-YR4LLIRU.js → init-cmd-M6MQRGOU.js} +15 -14
- package/dist/{init-update-46G6QJHB.js → init-update-N4HTZGVS.js} +55 -26
- package/dist/{inspect-6UYAAXH7.js → inspect-IPFA7AAT.js} +1 -1
- package/dist/{install-AFMXH25X.js → install-6OIY3KHZ.js} +6 -5
- package/dist/{install-cmd-X5XCUTSX.js → install-cmd-JMT67P35.js} +5 -5
- package/dist/{layout-UOJQGEPW.js → layout-XNFDTOET.js} +2 -2
- package/dist/{logs-PKNQOJN6.js → logs-XHAS6LMZ.js} +2 -2
- package/dist/{loop-3TJKFRN7.js → loop-2Y4CUFNP.js} +40 -39
- package/dist/{machine-3W4LKTEW.js → machine-Z2S47JW7.js} +23 -22
- package/dist/machine-skills-RRF4HLAD.js +11 -0
- package/dist/{mcp-serve-cmd-MJIJHSQ6.js → mcp-serve-cmd-LY5A3CE7.js} +4 -4
- package/dist/{paths-6V7572NN.js → paths-LHSPNORF.js} +2 -2
- package/dist/{pending-GUHHKO42.js → pending-3YZCSKON.js} +3 -3
- package/dist/{pidfile-ZQOFDY7T.js → pidfile-DKMYYXLH.js} +3 -3
- package/dist/{record-C4ZVSLKV.js → record-3LPTY3G5.js} +3 -3
- package/dist/{runner-env-6Q2RMENH.js → runner-env-YRRNRKF4.js} +8 -7
- package/dist/{runner-identity-DP577A7S.js → runner-identity-EX7HXPUE.js} +5 -5
- package/dist/{runner-key-LR5P2EJ5.js → runner-key-GO277GW2.js} +28 -27
- package/dist/{session-sender-ZTPWIU5L.js → session-sender-SC5PSU2G.js} +12 -12
- package/dist/{spec-cmd-RLZMX67G.js → spec-cmd-JGYHHJ4P.js} +9 -9
- package/dist/{starter-pack-55EFILC5.js → starter-pack-GPU4X6B7.js} +2 -2
- package/dist/{status-GNUOTHRH.js → status-CJCE2FHD.js} +30 -29
- package/dist/{sync-cmd-GLWEAULP.js → sync-cmd-ATXJVS7S.js} +11 -11
- package/dist/{watch-F47NPUDX.js → watch-M7NR3DOW.js} +11 -11
- package/dist/{work-claim-cmd-GXPIRRBG.js → work-claim-cmd-DNUDZKJA.js} +13 -13
- package/dist/{work-cmd-S2FHIFJA.js → work-cmd-VECTYST6.js} +9 -9
- package/dist/{work-comment-cmd-UJRKULO6.js → work-comment-cmd-F3NRWKPZ.js} +9 -9
- package/dist/{work-logs-cmd-SCAHJXSP.js → work-logs-cmd-QF6P32FE.js} +9 -9
- package/dist/{work-open-pr-cmd-BGMHUQGD.js → work-open-pr-cmd-XE23JA3R.js} +10 -10
- package/dist/{work-pr-cmd-EDDRP5DK.js → work-pr-cmd-BH56GUKN.js} +9 -9
- package/dist/{work-stop-cmd-ADE5K6UX.js → work-stop-cmd-C3F5HNUO.js} +9 -9
- package/package.json +1 -1
- package/skill-pack/maintained/outerlayer-cli/SKILL.md +6 -5
- package/skill-pack/shipped.json +1 -0
- package/skill-pack/template/build/SKILL.md +1 -1
- package/dist/chunk-7RQ73DLO.js +0 -23
|
@@ -1,34 +1,35 @@
|
|
|
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,
|
|
4
|
-
import { writePendingUpdate } from './chunk-
|
|
3
|
+
import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, MICROVM_COMMAND_DIR, commandLogOffset, startMicroVmCommand, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isContainerTracked, isMicroVmTracked, probeMicroVmCommand, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isTracked, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, AttemptLogBook, microVmOomKills, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, serveLease, vmAlive, writeGuestGhConfig, ALREADY_RELEASED, inTeardown } from './chunk-RK7FWC6B.js';
|
|
4
|
+
import { writePendingUpdate } from './chunk-RHGF73IU.js';
|
|
5
5
|
import { JOB_STATE_FORMAT, readsJobState, jobStateFormatOf } from './chunk-ZVB57WI6.js';
|
|
6
|
-
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-
|
|
6
|
+
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-ABXQBEYK.js';
|
|
7
7
|
import { decideInstalledSwitch } from './chunk-3JVYMD4G.js';
|
|
8
8
|
import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-YETTWTAY.js';
|
|
9
9
|
import { RUNNER_PROTOCOL } from './chunk-TPKYTORP.js';
|
|
10
|
-
import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-
|
|
11
|
-
import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, isInLayout, cleanVersions, stagingDir } from './chunk-
|
|
10
|
+
import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-WVDP6HVZ.js';
|
|
11
|
+
import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, isInLayout, cleanVersions, stagingDir } from './chunk-MATUHHN4.js';
|
|
12
12
|
import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
|
|
13
13
|
import { RepoFilter } from './chunk-TBT347UY.js';
|
|
14
|
-
import { leaseTimeLeftMs, LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec,
|
|
15
|
-
import {
|
|
14
|
+
import { leaseTimeLeftMs, LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec, setUpRunnerCgroup, createContainerRuntime, measureDisk, parseCpuList, ensureTunnel, keepGhConfigCurrent, filesAreCopied, gitRemoteFor, startServicesFor, createLeaseChannel } from './chunk-YF56R4DV.js';
|
|
15
|
+
import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, BuildTokens, classifyRefusal, refusalCode, createRunnerLog, formatClock } from './chunk-WSYXLLA5.js';
|
|
16
|
+
import { tagToPull, pullInstruction, imageTag, writeUpdateStatus } from './chunk-M3MHHIUW.js';
|
|
16
17
|
import { isVersion, compareVersions, satisfiesRange } from './chunk-TQMI335S.js';
|
|
17
|
-
import { checkFit } from './chunk-
|
|
18
|
-
import {
|
|
18
|
+
import { checkFit } from './chunk-7AQ5AM7U.js';
|
|
19
|
+
import { fdName } from './chunk-YB3CSYXX.js';
|
|
20
|
+
import { claimPidFile, writePidFile, readPidFile, releasePidFile } from './chunk-D7ECMB7B.js';
|
|
19
21
|
import { startTimeOf, isSameProcess } from './chunk-JBJTC3UU.js';
|
|
20
|
-
import { writeJobFile, ensureRunnerIdentity, readJobFile, builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, spawnRun, BUILD_LABEL, RUNNER_LABEL, readJobFileChecked } from './chunk-
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import { exceedsDisk } from './chunk-7RQ73DLO.js';
|
|
22
|
+
import { writeJobFile, ensureRunnerIdentity, readJobFile, builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, spawnRun, BUILD_LABEL, RUNNER_LABEL, readJobFileChecked } from './chunk-JH2GQU5T.js';
|
|
23
|
+
import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-55GNQPO6.js';
|
|
24
|
+
import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind, DEFAULT_UPDATE_MAX_WAIT_HOURS } from './chunk-EPPIISRD.js';
|
|
25
|
+
import { exceedsDisk } from './chunk-YJLHUKYS.js';
|
|
25
26
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
26
|
-
import { loadHostKey, ensureHostKey, signerFor } from './chunk-
|
|
27
|
-
import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, RUNNER_FILE_MODE, jobsDir, pidFilePath, spoolDir, rootfsDir } from './chunk-
|
|
28
|
-
import { parseClaimIdentity, parseClaimedRepositories, parseUnreachable, repositoriesOf, primaryOf, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-
|
|
27
|
+
import { loadHostKey, ensureHostKey, signerFor } from './chunk-Y4OKEFAX.js';
|
|
28
|
+
import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, RUNNER_FILE_MODE, jobsDir, pidFilePath, spoolDir, rootfsDir } from './chunk-RHAGBUL5.js';
|
|
29
|
+
import { parseClaimIdentity, parseClaimedRepositories, parseUnreachable, repositoriesOf, primaryOf, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-2I3LIRZP.js';
|
|
29
30
|
import { COMMAND_LOST_REASON, CONTAINER_STOPPED_REASON } from './chunk-JGD5TWQ2.js';
|
|
30
31
|
import { randomBytes } from 'crypto';
|
|
31
|
-
import { mkdirSync, existsSync, chmodSync, writeFileSync, renameSync, statSync, readdirSync, readFileSync,
|
|
32
|
+
import { mkdirSync, existsSync, chmodSync, writeFileSync, renameSync, statSync, readdirSync, readFileSync, closeSync, rmSync, openSync, constants, lstatSync } from 'fs';
|
|
32
33
|
import { join, dirname } from 'path';
|
|
33
34
|
import { totalmem, constants as constants$1 } from 'os';
|
|
34
35
|
|
|
@@ -272,8 +273,11 @@ function stageReason(job) {
|
|
|
272
273
|
}
|
|
273
274
|
}
|
|
274
275
|
function ownReason({ job, ending }) {
|
|
275
|
-
if (job.microvm !== void 0)
|
|
276
|
-
|
|
276
|
+
if (job.microvm !== void 0) {
|
|
277
|
+
if (!isMicroVmTracked(job)) return "is a microVM build that a restarted runner cannot adopt";
|
|
278
|
+
} else if (!isContainerTracked(job)) {
|
|
279
|
+
return "is not a container build tracked inside its container";
|
|
280
|
+
}
|
|
277
281
|
if (ending) return "is being ended";
|
|
278
282
|
return stageReason(job);
|
|
279
283
|
}
|
|
@@ -986,6 +990,30 @@ function writeCommitHooks(buildDir2, coAuthor) {
|
|
|
986
990
|
chmodSync(data, 420);
|
|
987
991
|
return dir;
|
|
988
992
|
}
|
|
993
|
+
|
|
994
|
+
// src/runner/microvm/adopt.ts
|
|
995
|
+
var MICROVM_STOPPED_REASON = "the build's microVM stopped while no runner was managing it";
|
|
996
|
+
var MICROVM_SOCKETS_LOST_REASON = "the build's sockets did not survive the runner's restart";
|
|
997
|
+
var MICROVM_HELPER_UNREACHABLE_REASON = "the runner could not ask its helper about the build's microVM when it started";
|
|
998
|
+
async function judgeMicroVmAdoption(input) {
|
|
999
|
+
const { job, runtime } = input;
|
|
1000
|
+
const state = job.microvm;
|
|
1001
|
+
if (state === void 0 || !isMicroVmTracked(job)) return "unservable";
|
|
1002
|
+
const probe = await runtime.vm.helper.probe();
|
|
1003
|
+
if (probe.ok) {
|
|
1004
|
+
const unit = await probe.client.state(state.buildId).catch((err) => {
|
|
1005
|
+
input.onError?.(`the state of the unit of build ${state.buildId} could not be read: ${describeCallFailure(err)}`);
|
|
1006
|
+
return { active: true, oomKills: 0 };
|
|
1007
|
+
});
|
|
1008
|
+
if (!unit.active) return "stopped";
|
|
1009
|
+
} else {
|
|
1010
|
+
input.onError?.(`the unit of build ${state.buildId} could not be asked about, because there is no helper to ask: ${probe.detail}`);
|
|
1011
|
+
return probe.unreachable === true ? "unasked" : "unservable";
|
|
1012
|
+
}
|
|
1013
|
+
const inherited = runtime.vm.fdStore.inherited();
|
|
1014
|
+
const names = state.fdStore ?? [];
|
|
1015
|
+
return names.length > 0 && names.every((name) => inherited.has(name)) ? "adopt" : "unservable";
|
|
1016
|
+
}
|
|
989
1017
|
function linuxSignalName(number) {
|
|
990
1018
|
const names = {
|
|
991
1019
|
1: "SIGHUP",
|
|
@@ -1749,7 +1777,7 @@ var CLAIM_REFUSAL_CODES = new Set(
|
|
|
1749
1777
|
"pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous pull_request_repository_not_connected repository_not_reachable branch_claimed_elsewhere".split(" ")
|
|
1750
1778
|
);
|
|
1751
1779
|
async function tryClaimAndStart(state, item, queue) {
|
|
1752
|
-
const { postJson: postJson2 } = await import('./work-cmd-
|
|
1780
|
+
const { postJson: postJson2 } = await import('./work-cmd-VECTYST6.js');
|
|
1753
1781
|
const log = logOf(state);
|
|
1754
1782
|
const hostKey = await loadHostKey(state.config.configPath);
|
|
1755
1783
|
const claim = await retrySend(
|
|
@@ -2247,8 +2275,16 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity,
|
|
|
2247
2275
|
try {
|
|
2248
2276
|
if (job.microvm !== void 0) {
|
|
2249
2277
|
const runtime = runtimeOf(state);
|
|
2250
|
-
|
|
2251
|
-
|
|
2278
|
+
if (job.microvm.jailed !== void 0 && (job.microvm.fdStore?.length ?? 0) > 0) {
|
|
2279
|
+
job.microvm.tracking = "microvm";
|
|
2280
|
+
job.microvm.commandDir = MICROVM_COMMAND_DIR;
|
|
2281
|
+
job.microvm.commandLogBase = commandLogOffset(dirPath, 0);
|
|
2282
|
+
writeJobFile(jobFilePath, job);
|
|
2283
|
+
await startMicroVmCommand({ job, cmdline, runtime, config: state.config });
|
|
2284
|
+
} else {
|
|
2285
|
+
const composed = microVmCommandLine({ job, cmdline, runtime, config: state.config, cli: join(runtime.cliBuild().distDir, "index.js") });
|
|
2286
|
+
running = runCommand(composed.line, { ...composed.env, OUTERLAYER_JOB_DIR: dirPath }, dirPath, join(dirPath, "command.log"), state.deps.spawnFn);
|
|
2287
|
+
}
|
|
2252
2288
|
} else if (job.container !== void 0) {
|
|
2253
2289
|
const runtime = runtimeOf(state);
|
|
2254
2290
|
const exec = containerCommandExec({ job, cmdline, runtime, config: state.config });
|
|
@@ -2276,7 +2312,9 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity,
|
|
|
2276
2312
|
writeJobFile(jobFilePath, job);
|
|
2277
2313
|
const commandStartedMs = nowOf(state).getTime();
|
|
2278
2314
|
active.commandStartedMs = commandStartedMs;
|
|
2279
|
-
log.line(
|
|
2315
|
+
log.line(
|
|
2316
|
+
running !== void 0 ? `${tag} command started \xB7 pid ${running.pid}` : job.container !== void 0 ? `${tag} command started \xB7 in container ${job.container.container}` : `${tag} command started \xB7 in microVM build ${job.microvm.buildId}`
|
|
2317
|
+
);
|
|
2280
2318
|
const sender = await startSender({
|
|
2281
2319
|
config: state.config,
|
|
2282
2320
|
job,
|
|
@@ -2464,19 +2502,67 @@ async function endStoppedBuild(state, active, where) {
|
|
|
2464
2502
|
);
|
|
2465
2503
|
void endJob(state, active, "interrupted", { stage: "command", reason: COMMAND_LOST_REASON });
|
|
2466
2504
|
}
|
|
2505
|
+
var DISK_FAILURES_LIMIT = 2;
|
|
2506
|
+
async function checkDisk(state, active, container, tag) {
|
|
2507
|
+
const log = logOf(state);
|
|
2508
|
+
const limit = state.config.build?.disk ?? "40g";
|
|
2509
|
+
const runtime = runtimeOf(state);
|
|
2510
|
+
const reading = await measureDisk(runtime, container);
|
|
2511
|
+
if (active.ending) return false;
|
|
2512
|
+
if (exceedsDisk(reading.kib ?? 0, limit)) {
|
|
2513
|
+
log.line(`${tag} the build's volume holds ${reading.kib} KiB, past ${limit} \xB7 ending job as failed`);
|
|
2514
|
+
await endJob(state, active, "failed", { stage: "command", reason: "disk_limit_exceeded" });
|
|
2515
|
+
return true;
|
|
2516
|
+
}
|
|
2517
|
+
if (reading.failure === void 0) {
|
|
2518
|
+
active.diskFailures = 0;
|
|
2519
|
+
return false;
|
|
2520
|
+
}
|
|
2521
|
+
if (await runtime.host.state(container.container) !== "running" || active.ending) return false;
|
|
2522
|
+
active.diskFailures = (active.diskFailures ?? 0) + 1;
|
|
2523
|
+
if (active.diskFailures < DISK_FAILURES_LIMIT) {
|
|
2524
|
+
log.error(`${tag} disk check failed (${active.diskFailures} of ${DISK_FAILURES_LIMIT}): ${reading.failure} \xB7 checking again`);
|
|
2525
|
+
return false;
|
|
2526
|
+
}
|
|
2527
|
+
log.error(`${tag} disk check failed (${active.diskFailures} of ${DISK_FAILURES_LIMIT}): ${reading.failure} \xB7 ending job as failed`);
|
|
2528
|
+
await endJob(state, active, "failed", { stage: "command", reason: "disk_check_failed" });
|
|
2529
|
+
return true;
|
|
2530
|
+
}
|
|
2531
|
+
async function endOrWaitForMicroVm(state, active) {
|
|
2532
|
+
const log = logOf(state);
|
|
2533
|
+
const tag = `#${active.job.item}`;
|
|
2534
|
+
const microvm = active.job.microvm;
|
|
2535
|
+
const runtime = runtimeOf(state);
|
|
2536
|
+
const helper = await runtime.vm.helper.probe();
|
|
2537
|
+
const unit = helper.ok ? await helper.client.state(microvm.buildId).catch(() => void 0) : void 0;
|
|
2538
|
+
if (active.ending) return;
|
|
2539
|
+
if (unit?.active === false) {
|
|
2540
|
+
const killed = await microVmOomKills(runtime, microvm).catch(() => 0);
|
|
2541
|
+
log.line(`${tag} the build's microVM stopped \xB7 ending job as interrupted`);
|
|
2542
|
+
void endJob(state, active, "interrupted", killed > 0 ? { stage: "command" } : { stage: "command", reason: MICROVM_STOPPED_REASON });
|
|
2543
|
+
} else if (active.probeFailing !== true) {
|
|
2544
|
+
active.probeFailing = true;
|
|
2545
|
+
log.error(`${tag} the build's command could not be read from its microVM \xB7 trying again`);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2467
2548
|
async function probeBuild(state, active) {
|
|
2468
2549
|
const container = active.job.container;
|
|
2469
|
-
|
|
2550
|
+
const tracked = container !== void 0 && isContainerTracked(active.job) ? container : isMicroVmTracked(active.job) ? active.job.microvm : void 0;
|
|
2551
|
+
if (tracked === void 0 || active.ending || active.probing) return;
|
|
2470
2552
|
active.probing = true;
|
|
2471
2553
|
const log = logOf(state);
|
|
2472
2554
|
const tag = `#${active.job.item}`;
|
|
2473
2555
|
try {
|
|
2474
2556
|
const runtime = runtimeOf(state);
|
|
2475
2557
|
for (; ; ) {
|
|
2476
|
-
const offset = commandLogOffset(active.dirPath,
|
|
2477
|
-
const probe = await probeCommand(runtime, container, offset);
|
|
2558
|
+
const offset = commandLogOffset(active.dirPath, tracked.commandLogBase);
|
|
2559
|
+
const probe = container === void 0 ? await probeMicroVmCommand(runtime, active.job.microvm, offset) : await probeCommand(runtime, container, offset);
|
|
2478
2560
|
if (active.ending) return;
|
|
2479
2561
|
if (probe === void 0) {
|
|
2562
|
+
if (container === void 0) {
|
|
2563
|
+
await endOrWaitForMicroVm(state, active);
|
|
2564
|
+
return;
|
|
2565
|
+
}
|
|
2480
2566
|
const where = await runtime.host.state(container.container);
|
|
2481
2567
|
if (where === "stopped" || where === "missing") {
|
|
2482
2568
|
await endStoppedBuild(state, active, where);
|
|
@@ -2527,7 +2613,7 @@ async function watchTick(state, active, nowMs, logMtimeMs) {
|
|
|
2527
2613
|
const log = logOf(state);
|
|
2528
2614
|
const tag = `#${active.job.item}`;
|
|
2529
2615
|
const pid = active.job.pid;
|
|
2530
|
-
const started = pid !== void 0 ||
|
|
2616
|
+
const started = pid !== void 0 || isTracked(active.job);
|
|
2531
2617
|
if (pid !== void 0 && !isGroupAlive(pid)) {
|
|
2532
2618
|
if (active.cmd === null) {
|
|
2533
2619
|
const recorded = outcomeFromExitCode(active.dirPath);
|
|
@@ -2570,13 +2656,12 @@ async function watchTick(state, active, nowMs, logMtimeMs) {
|
|
|
2570
2656
|
return;
|
|
2571
2657
|
}
|
|
2572
2658
|
if (!started) return;
|
|
2573
|
-
if (active.job.container !== void 0) {
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
return;
|
|
2659
|
+
if (active.job.container !== void 0 && active.diskChecking !== true) {
|
|
2660
|
+
active.diskChecking = true;
|
|
2661
|
+
try {
|
|
2662
|
+
if (await checkDisk(state, active, active.job.container, tag)) return;
|
|
2663
|
+
} finally {
|
|
2664
|
+
active.diskChecking = false;
|
|
2580
2665
|
}
|
|
2581
2666
|
}
|
|
2582
2667
|
let cpuUsecPerMinute = null;
|
|
@@ -2648,7 +2733,7 @@ async function adoptTrackedBuilds(state, jobsDirPath) {
|
|
|
2648
2733
|
const attemptLogs = attemptLogsOf(state);
|
|
2649
2734
|
const runtime = runtimeOf(state);
|
|
2650
2735
|
for (const { dirPath, job, known } of listTrackedJobs(jobsDirPath)) {
|
|
2651
|
-
if (!known) continue;
|
|
2736
|
+
if (!known || job.container === void 0) continue;
|
|
2652
2737
|
const container = job.container;
|
|
2653
2738
|
const where = await runtime.host.state(container.container).catch(() => "unknown");
|
|
2654
2739
|
if (where === "stopped" || where === "missing") {
|
|
@@ -2669,6 +2754,116 @@ async function adoptTrackedBuilds(state, jobsDirPath) {
|
|
|
2669
2754
|
void probeBuild(state, adopted);
|
|
2670
2755
|
}
|
|
2671
2756
|
}
|
|
2757
|
+
async function planMicroVmAdoption(state, jobsDirPath) {
|
|
2758
|
+
const plan = { adopt: [], away: [], unservable: [], unasked: [] };
|
|
2759
|
+
for (const { dirPath, job, known } of listTrackedJobs(jobsDirPath)) {
|
|
2760
|
+
if (!known || !isMicroVmTracked(job)) continue;
|
|
2761
|
+
const verdict = await judgeMicroVmAdoption({ job, runtime: runtimeOf(state), onError: (line) => logOf(state).error(line) });
|
|
2762
|
+
plan[verdict === "adopt" ? "adopt" : verdict === "stopped" ? "away" : verdict === "unasked" ? "unasked" : "unservable"].push({ dirPath, job });
|
|
2763
|
+
}
|
|
2764
|
+
return plan;
|
|
2765
|
+
}
|
|
2766
|
+
async function rejoinMicroVmBuild(state, adopted) {
|
|
2767
|
+
const { job, dirPath } = adopted;
|
|
2768
|
+
const config = state.config;
|
|
2769
|
+
const microvm = job.microvm;
|
|
2770
|
+
const runtime = runtimeOf(state);
|
|
2771
|
+
const tag = `#${job.item}`;
|
|
2772
|
+
const log = logOf(state);
|
|
2773
|
+
const inherited = runtime.vm.fdStore.inherited();
|
|
2774
|
+
const inherit = (socket) => {
|
|
2775
|
+
const fd = inherited.get(fdName(microvm.buildId, socket.replace(/\.sock$/, "")));
|
|
2776
|
+
return fd === void 0 ? void 0 : (server) => runtime.vm.fdStore.listenOn(server, fd);
|
|
2777
|
+
};
|
|
2778
|
+
const tokens = buildTokensFor(state, adopted, job.item);
|
|
2779
|
+
runtime.credentials.set(dirPath, tokens);
|
|
2780
|
+
let servicesServed = false;
|
|
2781
|
+
let leaseServed = false;
|
|
2782
|
+
try {
|
|
2783
|
+
const repositories = repositoriesOf({ repositories: job.repositories, repository: microvm.repository, branch: job.branch });
|
|
2784
|
+
const gitRemote = repositories.length === 0 ? void 0 : gitRemoteFor(runtime, { repositories, tokens, buildDir: microvm.buildDir, log: (line) => log.line(`${tag} ${line}`) });
|
|
2785
|
+
runtime.tunnels.set(microvm.buildId, await startServicesFor(runtime, config, microvm.buildDir, dirPath, job.itemKey, microvm.builtIns === true, gitRemote, "socket", void 0, inherit));
|
|
2786
|
+
servicesServed = true;
|
|
2787
|
+
} catch (err) {
|
|
2788
|
+
log.error(`${tag} the adopted build's services could not be served again: ${describeCallFailure(err)}`);
|
|
2789
|
+
}
|
|
2790
|
+
try {
|
|
2791
|
+
const channel = createLeaseChannel(leaseTimeLeftFor(state, adopted));
|
|
2792
|
+
const served = await serveLease(join(microvm.buildDir, "lease.sock"), { ...channel, accept: (stream) => runtime.leases.get(microvm.buildId)?.accept(stream) }, void 0, inherit("lease.sock"));
|
|
2793
|
+
runtime.leases.set(microvm.buildId, { ...channel, close: served.close });
|
|
2794
|
+
leaseServed = true;
|
|
2795
|
+
} catch (err) {
|
|
2796
|
+
log.error(`${tag} the adopted build's lease stream could not be served again: ${describeCallFailure(err)}`);
|
|
2797
|
+
}
|
|
2798
|
+
try {
|
|
2799
|
+
await tokens.token("read");
|
|
2800
|
+
} catch (err) {
|
|
2801
|
+
log.error(`${tag} could not give the adopted build a read token: ${describeCallFailure(err)}`);
|
|
2802
|
+
}
|
|
2803
|
+
let pushes = Promise.resolve();
|
|
2804
|
+
tokens.onRead((token) => {
|
|
2805
|
+
pushes = pushes.then(async () => {
|
|
2806
|
+
if (vmAlive(runtime, microvm)) await writeGuestGhConfig(runtime, microvm, token);
|
|
2807
|
+
}).catch((err) => log.error(`${tag} the read token could not be written for gh in the guest: ${describeCallFailure(err)}`));
|
|
2808
|
+
});
|
|
2809
|
+
await pushes;
|
|
2810
|
+
return servicesServed && leaseServed;
|
|
2811
|
+
}
|
|
2812
|
+
async function adoptTrackedMicroVms(state, plan) {
|
|
2813
|
+
const log = logOf(state);
|
|
2814
|
+
const attemptLogs = attemptLogsOf(state);
|
|
2815
|
+
const runtime = runtimeOf(state);
|
|
2816
|
+
for (const { dirPath, job } of plan.away) await finishMicroVmWhileAway(state, dirPath, job, MICROVM_STOPPED_REASON, "its unit stopped");
|
|
2817
|
+
for (const { dirPath, job } of plan.unservable) await finishMicroVmWhileAway(state, dirPath, job, MICROVM_SOCKETS_LOST_REASON, "the sockets it reaches the runner on are gone");
|
|
2818
|
+
for (const { dirPath, job } of plan.unasked) await finishMicroVmWhileAway(state, dirPath, job, MICROVM_HELPER_UNREACHABLE_REASON, "the helper did not answer about its unit");
|
|
2819
|
+
for (const { dirPath, job } of plan.adopt) {
|
|
2820
|
+
const adopted = { job, dirPath, lastRenewAtMs: 0, cmd: null, cpuSample: null, ending: false };
|
|
2821
|
+
state.jobs.set(dirPath, adopted);
|
|
2822
|
+
attemptLogs.open(job.item, dirPath);
|
|
2823
|
+
if (!await rejoinMicroVmBuild(state, adopted)) {
|
|
2824
|
+
state.jobs.delete(dirPath);
|
|
2825
|
+
await finishMicroVmWhileAway(state, dirPath, job, MICROVM_SOCKETS_LOST_REASON, "the sockets it reaches the runner on could not be served again");
|
|
2826
|
+
continue;
|
|
2827
|
+
}
|
|
2828
|
+
if (!await renewLeaseIfDue(state, adopted, nowOf(state).getTime())) continue;
|
|
2829
|
+
const sender = await restartSender({ config: state.config, job: adopted.job, jobDir: dirPath, deps: { spawnFn: state.deps.spawnFn, runtime, log, sleep: state.deps.sleep } });
|
|
2830
|
+
adopted.job = sender === void 0 ? { ...adopted.job, sender: void 0 } : { ...adopted.job, sender };
|
|
2831
|
+
writeJobFile(join(dirPath, "job.json"), adopted.job);
|
|
2832
|
+
const line = `adopted job ${job.queue} #${job.item} (claim ${shortClaim(job.claimId)}) \xB7 command tracked in microVM build ${job.microvm.buildId}`;
|
|
2833
|
+
log.line(line);
|
|
2834
|
+
attemptLogs.note(job.item, line);
|
|
2835
|
+
void probeBuild(state, adopted);
|
|
2836
|
+
}
|
|
2837
|
+
await removeUnadoptedSockets(state, new Set(plan.adopt.map(({ job }) => job.microvm.buildId)));
|
|
2838
|
+
}
|
|
2839
|
+
async function removeUnadoptedSockets(state, adopted) {
|
|
2840
|
+
const store = runtimeOf(state).vm.fdStore;
|
|
2841
|
+
for (const [name, fd] of store.inherited()) {
|
|
2842
|
+
const buildId = /^ol-([0-9a-f]+)-/.exec(name)?.[1];
|
|
2843
|
+
if (buildId === void 0 || adopted.has(buildId)) continue;
|
|
2844
|
+
await store.remove(name).catch((err) => logOf(state).error(`the descriptor ${name} could not be taken out of the store: ${describeCallFailure(err)}`));
|
|
2845
|
+
try {
|
|
2846
|
+
closeSync(fd);
|
|
2847
|
+
} catch {
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
async function finishMicroVmWhileAway(state, dirPath, job, reason, why) {
|
|
2852
|
+
const log = logOf(state);
|
|
2853
|
+
const recorded = outcomeFromExitCode(dirPath);
|
|
2854
|
+
let outcome = "interrupted";
|
|
2855
|
+
let ending = { reason };
|
|
2856
|
+
if (recorded !== void 0) {
|
|
2857
|
+
job.exitCode = recorded.code;
|
|
2858
|
+
job.commandEndReason = jobNotEndedByRunnerReason({ code: recorded.code, signal: null }, job);
|
|
2859
|
+
outcome = recorded.outcome === "ok" ? "ok" : "failed";
|
|
2860
|
+
ending = void 0;
|
|
2861
|
+
}
|
|
2862
|
+
const finished = await finishJob(job, dirPath, outcome, state.config, finishDepsOf(state), ending);
|
|
2863
|
+
log.line(
|
|
2864
|
+
`recovered job ${finished.queue} #${finished.item} (claim ${shortClaim(finished.claimId)}) as ${outcome}: ${recorded === void 0 ? `${why}, and no exit code had been read` : `its command recorded exit ${recorded.code}`}`
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2672
2867
|
async function readStoppedBuild(state, dirPath, job) {
|
|
2673
2868
|
const runtime = runtimeOf(state);
|
|
2674
2869
|
const container = job.container;
|
|
@@ -2728,6 +2923,11 @@ async function finishTrackedWhileAway(state, dirPath, job, where) {
|
|
|
2728
2923
|
`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}`}`
|
|
2729
2924
|
);
|
|
2730
2925
|
}
|
|
2926
|
+
async function canLeaveBuilds(state) {
|
|
2927
|
+
if (state.deps.leave === void 0 || state.deps.image !== void 0 || !isBuiltinVm(state.config.hooks.provision)) return false;
|
|
2928
|
+
const runtime = runtimeOf(state);
|
|
2929
|
+
return (await runtime.vm.helper.probe()).ok && (await runtime.vm.fdStore.status()).ok;
|
|
2930
|
+
}
|
|
2731
2931
|
async function logUnusableHelper(config, runtime, log) {
|
|
2732
2932
|
if (!isBuiltinVm(config.hooks.provision)) return;
|
|
2733
2933
|
const helper = await runtime.vm.helper.probe();
|
|
@@ -2742,7 +2942,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2742
2942
|
const outcome = await onStartUnderMarker({
|
|
2743
2943
|
configPath,
|
|
2744
2944
|
own: ownVersionOf(deps),
|
|
2745
|
-
check: update.check ? () => update.check(configPath) : async () => (await import('./check-
|
|
2945
|
+
check: update.check ? () => update.check(configPath) : async () => (await import('./check-JVBAWIN6.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
|
|
2746
2946
|
now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
|
|
2747
2947
|
log
|
|
2748
2948
|
});
|
|
@@ -2780,9 +2980,29 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2780
2980
|
}
|
|
2781
2981
|
const state = { config, jobs: /* @__PURE__ */ new Map(), deps, configMtimeMs };
|
|
2782
2982
|
log.line(`runner ${config.host} started \xB7 config ${configPath} \xB7 ${describeConfig(config)}`);
|
|
2983
|
+
const leavesBuilds = await canLeaveBuilds(state);
|
|
2984
|
+
let sigusr2Target;
|
|
2985
|
+
let sigusr2Early = false;
|
|
2986
|
+
const forwardSigusr2 = () => {
|
|
2987
|
+
if (sigusr2Target === void 0) sigusr2Early = true;
|
|
2988
|
+
else sigusr2Target();
|
|
2989
|
+
};
|
|
2990
|
+
if (leavesBuilds) {
|
|
2991
|
+
process.on("SIGUSR2", forwardSigusr2);
|
|
2992
|
+
writePidFile(pidFilePath(configPath), { ...self, leaves: true });
|
|
2993
|
+
}
|
|
2783
2994
|
const nowMs = () => deps.now ? deps.now().getTime() : Date.now();
|
|
2784
2995
|
await logUnusableHelper(config, runtimeOf(state), log);
|
|
2785
|
-
const
|
|
2996
|
+
const microVmPlan = await planMicroVmAdoption(state, jobsDir(configPath)).catch((err) => {
|
|
2997
|
+
log.error(`the microVM builds an earlier runner left could not be told apart: ${describeCallFailure(err)}`);
|
|
2998
|
+
return { adopt: [], away: [], unservable: [], unasked: [] };
|
|
2999
|
+
});
|
|
3000
|
+
const runningMicroVms = await stopOrphanedMicroVms({
|
|
3001
|
+
jobs: unfinishedJobs(jobsDir(configPath)),
|
|
3002
|
+
runtime: runtimeOf(state),
|
|
3003
|
+
onError: (line) => log.error(line),
|
|
3004
|
+
keep: new Set(microVmPlan.adopt.map(({ job }) => job.microvm.buildId))
|
|
3005
|
+
}).catch((err) => {
|
|
2786
3006
|
log.error(`a microVM an earlier runner left could not be stopped: ${describeCallFailure(err)}`);
|
|
2787
3007
|
return [];
|
|
2788
3008
|
});
|
|
@@ -2806,6 +3026,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2806
3026
|
attemptLogs.note(job.item, adoptedLine);
|
|
2807
3027
|
}
|
|
2808
3028
|
await adoptTrackedBuilds(state, jobsDir(configPath));
|
|
3029
|
+
await adoptTrackedMicroVms(state, microVmPlan);
|
|
2809
3030
|
for (const { job, released } of await retryFailedReleases(jobsDir(configPath), config, {
|
|
2810
3031
|
fetchImpl: deps.fetchImpl,
|
|
2811
3032
|
now: deps.now,
|
|
@@ -2850,9 +3071,13 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2850
3071
|
const probeTimer = setInterval(() => {
|
|
2851
3072
|
for (const active of state.jobs.values()) void probeBuild(state, active);
|
|
2852
3073
|
}, deps.probeIntervalMs ?? PROBE_INTERVAL_MS);
|
|
2853
|
-
const onSigterm = () =>
|
|
3074
|
+
const onSigterm = () => {
|
|
3075
|
+
if (deps.image !== void 0) leave();
|
|
3076
|
+
else if (leavesBuilds && buildBlockers(runningBuilds(state)).length === 0) leave();
|
|
3077
|
+
else void drain();
|
|
3078
|
+
};
|
|
2854
3079
|
const onSigusr1 = () => void stopNow();
|
|
2855
|
-
const onSigusr2 = () => drainKeepingUp();
|
|
3080
|
+
const onSigusr2 = () => deps.image === void 0 ? void drain() : drainKeepingUp();
|
|
2856
3081
|
const onSigint = () => {
|
|
2857
3082
|
interrupts++;
|
|
2858
3083
|
if (interrupts === 1) {
|
|
@@ -2866,6 +3091,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2866
3091
|
process.off("SIGTERM", onSigterm);
|
|
2867
3092
|
process.off("SIGUSR1", onSigusr1);
|
|
2868
3093
|
process.off("SIGUSR2", onSigusr2);
|
|
3094
|
+
process.off("SIGUSR2", forwardSigusr2);
|
|
2869
3095
|
process.off("SIGINT", onSigint);
|
|
2870
3096
|
};
|
|
2871
3097
|
const stopIntake = () => {
|
|
@@ -2923,7 +3149,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2923
3149
|
log.line(`stopping: leaving ${state.jobs.size} running build(s) for the next runner to adopt`);
|
|
2924
3150
|
state.draining = true;
|
|
2925
3151
|
finish2();
|
|
2926
|
-
deps.image?.exit?.(0);
|
|
3152
|
+
(deps.image?.exit ?? deps.leave?.exit)?.(0);
|
|
2927
3153
|
};
|
|
2928
3154
|
const stopNow = async () => {
|
|
2929
3155
|
if (stopping) return;
|
|
@@ -2945,7 +3171,10 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
2945
3171
|
const handle = { state, drain, stopNow, close };
|
|
2946
3172
|
process.on("SIGTERM", onSigterm);
|
|
2947
3173
|
process.on("SIGUSR1", onSigusr1);
|
|
2948
|
-
if (
|
|
3174
|
+
if (leavesBuilds) {
|
|
3175
|
+
sigusr2Target = onSigusr2;
|
|
3176
|
+
if (sigusr2Early) onSigusr2();
|
|
3177
|
+
} else if (deps.image !== void 0) process.on("SIGUSR2", onSigusr2);
|
|
2949
3178
|
process.on("SIGINT", onSigint);
|
|
2950
3179
|
deps.onReady?.();
|
|
2951
3180
|
await tick(state);
|
|
@@ -2971,7 +3200,7 @@ async function requestStop(configPath, stopNow = false, pollMs = 5e3, options =
|
|
|
2971
3200
|
`);
|
|
2972
3201
|
return;
|
|
2973
3202
|
}
|
|
2974
|
-
const signal = stopNow ? "SIGUSR1" : options.image === true ? "SIGUSR2" : "SIGTERM";
|
|
3203
|
+
const signal = stopNow ? "SIGUSR1" : options.image === true || entry.leaves === true ? "SIGUSR2" : "SIGTERM";
|
|
2975
3204
|
try {
|
|
2976
3205
|
kill(entry.pid, signal);
|
|
2977
3206
|
} catch (err) {
|
|
@@ -2986,7 +3215,7 @@ async function requestStop(configPath, stopNow = false, pollMs = 5e3, options =
|
|
|
2986
3215
|
`);
|
|
2987
3216
|
return;
|
|
2988
3217
|
}
|
|
2989
|
-
if (signal === "SIGUSR2") {
|
|
3218
|
+
if (signal === "SIGUSR2" && entry.leaves !== true) {
|
|
2990
3219
|
process.stdout.write(
|
|
2991
3220
|
`sent SIGUSR2 to runner pid ${entry.pid}: it takes no more work and keeps managing its builds.
|
|
2992
3221
|
The container stays up. Run \`outerlayer runner status\` to see what is left, then \`docker stop\` the container once nothing is.
|
|
@@ -2996,7 +3225,7 @@ The container stays up. Run \`outerlayer runner status\` to see what is left, th
|
|
|
2996
3225
|
}
|
|
2997
3226
|
process.stdout.write(
|
|
2998
3227
|
stopNow ? `sent SIGUSR1 to runner pid ${entry.pid}, stopping now
|
|
2999
|
-
` : `sent
|
|
3228
|
+
` : `sent ${signal} to runner pid ${entry.pid}, draining
|
|
3000
3229
|
`
|
|
3001
3230
|
);
|
|
3002
3231
|
while (isSameProcess(entry.pid, entry.start)) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { sharedSkillNames } from './chunk-
|
|
3
|
+
import { sharedSkillNames } from './chunk-6TRNCUM4.js';
|
|
4
4
|
import { GOVERNANCE_VARIABLE, versionAtLeast, MINIMUM_CLAUDE_VERSION, SHIM_SCRIPT, CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
|
|
5
5
|
export { MINIMUM_CLAUDE_VERSION } from './chunk-HCVLP7XA.js';
|
|
6
6
|
import { findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import { setupMachineSkills } from './chunk-BM7EC3OZ.js';
|
|
8
|
+
import './chunk-7OUOLGUV.js';
|
|
8
9
|
import './chunk-RKOTJQVG.js';
|
|
9
10
|
import './chunk-QZBXLLTV.js';
|
|
10
11
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
@@ -210,12 +211,15 @@ async function runClaudeLauncher(args, deps = {}) {
|
|
|
210
211
|
const cwd = deps.cwd ?? process.cwd();
|
|
211
212
|
const env = deps.env ?? process.env;
|
|
212
213
|
const stderr = deps.stderr ?? ((text) => void process.stderr.write(text));
|
|
214
|
+
const home = homeFromEnv(env);
|
|
215
|
+
const installed = setupMachineSkills(home);
|
|
216
|
+
for (const failure of installed.failures) stderr(`outerlayer claude: could not write a maintained skill: ${failure}
|
|
217
|
+
`);
|
|
213
218
|
const claude = findClaude(env.PATH);
|
|
214
219
|
if (claude === void 0) {
|
|
215
220
|
stderr("outerlayer claude: no claude program found on PATH\n");
|
|
216
221
|
return 127;
|
|
217
222
|
}
|
|
218
|
-
const home = homeFromEnv(env);
|
|
219
223
|
try {
|
|
220
224
|
removeStaleOwnSkillsDirs(home);
|
|
221
225
|
} catch {
|
|
@@ -236,7 +240,7 @@ async function runClaudeLauncher(args, deps = {}) {
|
|
|
236
240
|
return 1;
|
|
237
241
|
}
|
|
238
242
|
} else {
|
|
239
|
-
const { resolveLaunchPlane } = await import('./control-plane-launch-
|
|
243
|
+
const { resolveLaunchPlane } = await import('./control-plane-launch-DBQA3KLJ.js');
|
|
240
244
|
const plane = env[GOVERNANCE_VARIABLE] === "self" ? { kind: "none" } : await resolveLaunchPlane({ cwd, env, home, fetchImpl: deps.fetchImpl, stderr });
|
|
241
245
|
if (plane.kind === "none") {
|
|
242
246
|
const own2 = ownSkillsDirFor(cwd, home, [], stderr);
|