@outerlayer/cli 0.33.0-next.20261023120437 → 0.33.0-next.20261023122246
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/dist/build-info.json +1 -1
- package/dist/{check-4QNLMDP7.js → check-YCFZ3H35.js} +5 -5
- package/dist/{chunk-FZUFUVLK.js → chunk-RAMTJ2XP.js} +2 -2
- package/dist/{chunk-MZYOUIY5.js → chunk-TRP3KPGK.js} +1 -1
- package/dist/{chunk-YSM4EEUK.js → chunk-Y6KIGWFO.js} +40 -9
- package/dist/chunk-ZUVERBFB.js +81 -0
- package/dist/{cli-BC7JWQUQ.js → cli-WFLOFK42.js} +11 -11
- package/dist/{container-start-AQJ64LCF.js → container-start-C4XCYPUA.js} +31 -8
- package/dist/index.js +1 -1
- package/dist/{loop-YJF27PUS.js → loop-KRGNTFZ2.js} +5 -5
- package/dist/{status-AYHBGIAP.js → status-YVJQWWDP.js} +1 -1
- package/dist/{work-claim-cmd-CIVWB7EJ.js → work-claim-cmd-GBU2ACRF.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-YGZLRX5U.js +0 -36
package/README.md
CHANGED
|
@@ -168,9 +168,19 @@ content:
|
|
|
168
168
|
fetches the package's dependencies, and both npm runs use this user's npm
|
|
169
169
|
configuration, including any registry token in `~/.npmrc`. Set
|
|
170
170
|
`runner.autoUpdate` to `false` to stop them.
|
|
171
|
+
When `outerlayer runner start` fails a start-up check before its first
|
|
172
|
+
heartbeat, it sends one report with `POST /v1/hosts/startup-report`. The
|
|
173
|
+
report holds the host name, the CLI version, the name of the failed check
|
|
174
|
+
and the error text, with terminal control codes removed, scrubbed of the
|
|
175
|
+
keys the runner holds and cut to 200 characters. It sends none when another
|
|
176
|
+
runner already runs on the same config, or when the gateway refused the
|
|
177
|
+
runner key or its host key's signature. The call waits at most 5 seconds,
|
|
178
|
+
and a gateway with no such route ignores it.
|
|
171
179
|
`outerlayer runner container-start`, the runner image's entrypoint, writes
|
|
172
|
-
the config from its environment variables
|
|
173
|
-
|
|
180
|
+
the config from its environment variables. When the container reaches no
|
|
181
|
+
Docker it can use, it sends that report, with the check `docker`, and
|
|
182
|
+
stops. Otherwise it runs `outerlayer runner start`, which makes the calls
|
|
183
|
+
above. In the image
|
|
174
184
|
the runner never calls the npm registry. It logs the image tag to pull.
|
|
175
185
|
`runner check` makes a list call and a host-key lookup to confirm the key
|
|
176
186
|
works and sends nothing else; `runner status` and `runner logs` make no network call at all.
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"id":"2026-10-23T12:
|
|
1
|
+
{"id":"2026-10-23T12:24:08.386Z+0c94177","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { probeCredentials } from './chunk-
|
|
4
|
-
import './chunk-FZUFUVLK.js';
|
|
3
|
+
import { probeCredentials } from './chunk-Y6KIGWFO.js';
|
|
5
4
|
import './chunk-GH246BGV.js';
|
|
6
|
-
import './chunk-ZVB57WI6.js';
|
|
7
5
|
import './chunk-57L2YAJA.js';
|
|
8
6
|
import './chunk-3JVYMD4G.js';
|
|
9
7
|
import './chunk-E7R2GIAW.js';
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
8
|
+
import './chunk-ZUVERBFB.js';
|
|
9
|
+
import './chunk-RAMTJ2XP.js';
|
|
10
|
+
import './chunk-ZVB57WI6.js';
|
|
11
|
+
import './chunk-TRP3KPGK.js';
|
|
12
12
|
import './chunk-HVRQQOMH.js';
|
|
13
13
|
import './chunk-6LBSAW6I.js';
|
|
14
14
|
import './chunk-I3LTIAOR.js';
|
|
@@ -22,7 +22,7 @@ import { scrubText } from './chunk-NIY2UBT6.js';
|
|
|
22
22
|
import { readCloudConfig } from './chunk-PJDQPF5N.js';
|
|
23
23
|
import { signerFor } from './chunk-SOI6K5DY.js';
|
|
24
24
|
import { RUNNER_FILE_MODE, runnerDir, buildDir, vsockPath, jobConsolePath } from './chunk-PA6CK6WQ.js';
|
|
25
|
-
import { JOB_MOUNT, claudeCredential, repositoriesOf, primaryOf, buildEnvironment, CHECKOUT_DIR, AGENT_CREDENTIAL_MISSING, sharedUserEnvironment, headerVariables, authorEnvironment, withTunnelRecord, commitIdentityRecord, buildMavenSettingsXml,
|
|
25
|
+
import { JOB_MOUNT, claudeCredential, repositoriesOf, primaryOf, buildEnvironment, CHECKOUT_DIR, AGENT_CREDENTIAL_MISSING, sharedUserEnvironment, headerVariables, authorEnvironment, withTunnelRecord, commitIdentityRecord, buildMavenSettingsXml, CLAUDE_CREDENTIAL_VARIABLES, currentClaudeCredential, removedClaudeCredentialValues, RELAY_PORT, repositoryPath, lifecycleWorkdir, CHECK_ITEMS_FILE, MAVEN_SETTINGS_FILE, checkEnvironment, EVAL_INPUT_DIR } from './chunk-BALIE3BA.js';
|
|
26
26
|
import { resolvePackRoot } from './chunk-44V5SD4G.js';
|
|
27
27
|
import { MAINTAINED_SKILLS } from './chunk-CDDED64E.js';
|
|
28
28
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
@@ -3547,4 +3547,4 @@ async function stopSender(input) {
|
|
|
3547
3547
|
}
|
|
3548
3548
|
}
|
|
3549
3549
|
|
|
3550
|
-
export { ALREADY_RELEASED, AttemptLogBook, EXIT_CODE_FILE, GUEST_USAGE_INTERVAL_MS, MICROVM_COMMAND_DIR, RENEW_INTERVAL_SECONDS, appendCommandLog, commandLogOffset, deliverCommitHooks, describeHookEnd, finishJob, foldSample, hookLimitsFor, inTeardown, isContainerTracked, isGroupAlive, isIdle, isMicroVmTracked, isReadable, isTimedOut, isTracked, isUnfinished, jobEnv, judgeProbe, listAdoptableJobs, listTrackedJobs, listUnreadableJobs, microVmCommandLine, microVmOomKills, needsRenew, outcomeFromExitCode, probeCommand, probeMicroVmCommand, provisionMicroVm, provisionProcess, readCpuUsec, readProvisionOut, recoverLostJobs, releaseLease, renewLease, restartSender, retryFailedReleases, runCommand, runHook, sampleGuest, serveLease, setStage, startMicroVmCommand, startSender, stopOrphanedMicroVms, unfinishedJobs, vmAlive, workdirProblem, writeGuestGhConfig };
|
|
3550
|
+
export { ALREADY_RELEASED, AttemptLogBook, EXIT_CODE_FILE, GUEST_USAGE_INTERVAL_MS, MICROVM_COMMAND_DIR, RENEW_INTERVAL_SECONDS, appendCommandLog, commandLogOffset, deliverCommitHooks, describeHookEnd, finishJob, foldSample, hookLimitsFor, inTeardown, isContainerTracked, isGroupAlive, isIdle, isMicroVmTracked, isReadable, isTimedOut, isTracked, isUnfinished, jobEnv, judgeProbe, listAdoptableJobs, listTrackedJobs, listUnreadableJobs, microVmCommandLine, microVmOomKills, needsRenew, outcomeFromExitCode, probeCommand, probeMicroVmCommand, provisionMicroVm, provisionProcess, readCpuUsec, readProvisionOut, recoverLostJobs, releaseLease, renewLease, restartSender, retryFailedReleases, runCommand, runHook, sampleGuest, scrubReason, serveLease, setStage, startMicroVmCommand, startSender, stopOrphanedMicroVms, stripTerminalControls, unfinishedJobs, vmAlive, workdirProblem, writeGuestGhConfig };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, readProvisionOut, workdirProblem, MICROVM_COMMAND_DIR, commandLogOffset, startMicroVmCommand, microVmCommandLine, runCommand, startSender, finishJob, sampleGuest, foldSample, isContainerTracked, isMicroVmTracked, probeMicroVmCommand, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isTracked, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, GUEST_USAGE_INTERVAL_MS, hookLimitsFor, AttemptLogBook, microVmOomKills, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, serveLease, vmAlive, writeGuestGhConfig, ALREADY_RELEASED, inTeardown } from './chunk-FZUFUVLK.js';
|
|
4
3
|
import { writePendingUpdate } from './chunk-GH246BGV.js';
|
|
5
|
-
import { JOB_STATE_FORMAT, readsJobState, jobStateFormatOf } from './chunk-ZVB57WI6.js';
|
|
6
4
|
import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-57L2YAJA.js';
|
|
7
5
|
import { decideInstalledSwitch } from './chunk-3JVYMD4G.js';
|
|
8
6
|
import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-E7R2GIAW.js';
|
|
9
|
-
import { fitImageBuildMemory } from './chunk-
|
|
10
|
-
import {
|
|
7
|
+
import { reportFailedStart, fitImageBuildMemory } from './chunk-ZUVERBFB.js';
|
|
8
|
+
import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, readProvisionOut, workdirProblem, MICROVM_COMMAND_DIR, commandLogOffset, startMicroVmCommand, microVmCommandLine, runCommand, startSender, finishJob, sampleGuest, foldSample, isContainerTracked, isMicroVmTracked, probeMicroVmCommand, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isTracked, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, GUEST_USAGE_INTERVAL_MS, hookLimitsFor, AttemptLogBook, microVmOomKills, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, serveLease, vmAlive, writeGuestGhConfig, ALREADY_RELEASED, inTeardown } from './chunk-RAMTJ2XP.js';
|
|
9
|
+
import { JOB_STATE_FORMAT, readsJobState, jobStateFormatOf } from './chunk-ZVB57WI6.js';
|
|
10
|
+
import { RUNNER_PROTOCOL } from './chunk-TRP3KPGK.js';
|
|
11
11
|
import { realBlockedProbes, checkBlockedWithSlots, keepsHostBuilder } from './chunk-SQQD5MST.js';
|
|
12
12
|
import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, isInLayout, cleanVersions, stagingDir } from './chunk-NBZ7XBT6.js';
|
|
13
13
|
import { RepoFilter } from './chunk-TBT347UY.js';
|
|
@@ -2813,21 +2813,26 @@ async function probeCredentials(config, fetchImpl = fetch) {
|
|
|
2813
2813
|
return { ok: true };
|
|
2814
2814
|
} catch (err) {
|
|
2815
2815
|
const status = err instanceof WorkCommandError ? err.status : void 0;
|
|
2816
|
+
const code = err instanceof WorkCommandError ? err.code : void 0;
|
|
2816
2817
|
if (err instanceof WorkCommandError && isSignatureRefusal(err.code)) {
|
|
2817
2818
|
return {
|
|
2818
2819
|
ok: false,
|
|
2819
2820
|
fatal: err.code === "runner_key_signature_invalid",
|
|
2820
|
-
reason: `${config.configPath}: ${err.message}
|
|
2821
|
+
reason: `${config.configPath}: ${err.message}`,
|
|
2822
|
+
status,
|
|
2823
|
+
code
|
|
2821
2824
|
};
|
|
2822
2825
|
}
|
|
2823
2826
|
if (status === 401 || status === 403) {
|
|
2824
2827
|
return {
|
|
2825
2828
|
ok: false,
|
|
2826
2829
|
fatal: true,
|
|
2827
|
-
reason: `${config.configPath}: the API key was refused (${status}). A runner key needs git.read and work.read to list and read work items, and work.claim to claim, renew and release
|
|
2830
|
+
reason: `${config.configPath}: the API key was refused (${status}). A runner key needs git.read and work.read to list and read work items, and work.claim to claim, renew and release.`,
|
|
2831
|
+
status,
|
|
2832
|
+
code
|
|
2828
2833
|
};
|
|
2829
2834
|
}
|
|
2830
|
-
return { ok: false, fatal: false, reason: describeCallFailure(err) };
|
|
2835
|
+
return { ok: false, fatal: false, reason: describeCallFailure(err), status, code };
|
|
2831
2836
|
}
|
|
2832
2837
|
}
|
|
2833
2838
|
async function rejoinContainerBuild(state, adopted) {
|
|
@@ -3071,6 +3076,15 @@ function hooksOf(configPath) {
|
|
|
3071
3076
|
}
|
|
3072
3077
|
}
|
|
3073
3078
|
async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
3079
|
+
const startup = {};
|
|
3080
|
+
try {
|
|
3081
|
+
return await startRunner(configPath, deps, startup);
|
|
3082
|
+
} catch (err) {
|
|
3083
|
+
await startup.report?.(err);
|
|
3084
|
+
throw err;
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
async function startRunner(configPath, deps, startup) {
|
|
3074
3088
|
const log = deps.log ??= createRunnerLog(deps.now ?? (() => /* @__PURE__ */ new Date()));
|
|
3075
3089
|
takeClaudeCredential(process.env, hooksOf(configPath));
|
|
3076
3090
|
const update = deps.update;
|
|
@@ -3081,7 +3095,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
3081
3095
|
check: update.check ? () => update.check(configPath) : async () => {
|
|
3082
3096
|
const held = heldClaudeCredential();
|
|
3083
3097
|
const env = held === void 0 ? process.env : { ...process.env, [held.variable]: held.value };
|
|
3084
|
-
return (await import('./check-
|
|
3098
|
+
return (await import('./check-YCFZ3H35.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl, env });
|
|
3085
3099
|
},
|
|
3086
3100
|
now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
|
|
3087
3101
|
log
|
|
@@ -3092,22 +3106,37 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
3092
3106
|
}
|
|
3093
3107
|
}
|
|
3094
3108
|
const loaded = loadRunnerConfig(configPath);
|
|
3109
|
+
let check = "hooks";
|
|
3110
|
+
let probeRefusal;
|
|
3111
|
+
startup.report = (err) => reportFailedStart(
|
|
3112
|
+
{ config: loaded, cliVersion: deps.cliVersion ?? resolveVersion(), check, error: err, refusal: probeRefusal },
|
|
3113
|
+
deps.fetchImpl
|
|
3114
|
+
);
|
|
3095
3115
|
const hookProblem = checkHooks(loaded);
|
|
3096
3116
|
if (hookProblem) throw new RunnerStartError(hookProblem);
|
|
3117
|
+
check = "image";
|
|
3097
3118
|
const { config, note: fitNote } = fitForImage(deps, loaded);
|
|
3119
|
+
check = "host-key";
|
|
3098
3120
|
await ensureHostKey(configPath);
|
|
3121
|
+
check = "identity";
|
|
3099
3122
|
if (builtinKind(config.hooks.provision) === "container" || builtinKind(config.hooks.provision) === "vm") {
|
|
3100
3123
|
await ensureRunnerIdentity(configPath, {
|
|
3101
3124
|
docker: deps.runnerIdentity ?? (deps.container?.host === void 0 ? void 0 : { holdsObjects: async () => false }),
|
|
3102
3125
|
log: (line) => log.error(line)
|
|
3103
3126
|
}).catch((err) => log.error(`the runner's Docker identity could not be stored: ${describeCallFailure(err)} \xB7 using the names its folder's path gives`));
|
|
3104
3127
|
}
|
|
3128
|
+
check = "credentials";
|
|
3105
3129
|
const probe = await probeCredentials(config, deps.fetchImpl);
|
|
3106
|
-
if (!probe.ok && probe.fatal)
|
|
3130
|
+
if (!probe.ok && probe.fatal) {
|
|
3131
|
+
probeRefusal = { status: probe.status, code: probe.code };
|
|
3132
|
+
throw new RunnerStartError(probe.reason);
|
|
3133
|
+
}
|
|
3107
3134
|
if (!probe.ok) log.error(`the gateway did not answer at start: ${probe.reason} \xB7 starting anyway`);
|
|
3135
|
+
check = "pid-file";
|
|
3108
3136
|
mkdirSync(jobsDir(configPath), { recursive: true, mode: RUNNER_DIR_MODE });
|
|
3109
3137
|
const self = { pid: process.pid, start: startTimeOf(process.pid) ?? "" };
|
|
3110
3138
|
claimPidFile(pidFilePath(configPath), self);
|
|
3139
|
+
check = "cgroup";
|
|
3111
3140
|
const { delegated, refusal } = setUpRunnerCgroup();
|
|
3112
3141
|
if (refusal !== void 0) log.error(`the kernel refused a cgroup step for the runner's service: ${refusal}`);
|
|
3113
3142
|
if (isBuiltinVm(config.hooks.provision) && !delegated) {
|
|
@@ -3122,6 +3151,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
3122
3151
|
const state = { config, jobs: /* @__PURE__ */ new Map(), deps, configMtimeMs };
|
|
3123
3152
|
log.line(`runner ${config.host} started \xB7 config ${configPath} \xB7 ${describeConfig(config)}`);
|
|
3124
3153
|
if (fitNote !== void 0) log.line(fitNote);
|
|
3154
|
+
check = "recovery";
|
|
3125
3155
|
const leavesBuilds = await canLeaveBuilds(state);
|
|
3126
3156
|
let sigusr2Target;
|
|
3127
3157
|
let sigusr2Early = false;
|
|
@@ -3189,6 +3219,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
|
|
|
3189
3219
|
`recovered job ${recovered.queue} #${recovered.item} (claim ${shortClaim(recovered.claimId)}) as ${recovered.outcome ?? "interrupted"}: ${why}`
|
|
3190
3220
|
);
|
|
3191
3221
|
}
|
|
3222
|
+
startup.report = void 0;
|
|
3192
3223
|
let intakeClosed = false;
|
|
3193
3224
|
let closed = false;
|
|
3194
3225
|
let stopping = false;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { scrubReason, stripTerminalControls } from './chunk-RAMTJ2XP.js';
|
|
4
|
+
import { RunnerAlreadyRunningError, readPidFile } from './chunk-F5UL23I2.js';
|
|
5
|
+
import { isSameProcess } from './chunk-JBJTC3UU.js';
|
|
6
|
+
import { checkFit, RUNNER_RESERVE_BYTES } from './chunk-EHOFFTVX.js';
|
|
7
|
+
import { isSignatureRefusal, postJson } from './chunk-YXMGHGHR.js';
|
|
8
|
+
import { signerFor } from './chunk-SOI6K5DY.js';
|
|
9
|
+
import { pidFilePath } from './chunk-PA6CK6WQ.js';
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
|
|
12
|
+
createRequire(import.meta.url);
|
|
13
|
+
var GIB = 1024 ** 3;
|
|
14
|
+
var DEFAULT_GIB = 8;
|
|
15
|
+
var MINIMUM_GIB = 4;
|
|
16
|
+
var BUILD_MEMORY_VARIABLE = "OUTERLAYER_BUILD_MEMORY";
|
|
17
|
+
function memoryIsSet(configPath) {
|
|
18
|
+
try {
|
|
19
|
+
const raw = JSON.parse(readFileSync(configPath, "utf8"));
|
|
20
|
+
return raw.runner.build.memory !== void 0;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function gib(bytes) {
|
|
26
|
+
return `${Number((bytes / GIB).toFixed(1))} GiB`;
|
|
27
|
+
}
|
|
28
|
+
function fitImageBuildMemory(config, totalMemoryBytes) {
|
|
29
|
+
if (memoryIsSet(config.configPath)) return { config };
|
|
30
|
+
const current = config.build?.memory ?? `${DEFAULT_GIB}g`;
|
|
31
|
+
if (checkFit({ concurrency: config.concurrency, buildMemory: current, usableBytes: totalMemoryBytes }).fits) return { config };
|
|
32
|
+
const available = Math.max(0, totalMemoryBytes - RUNNER_RESERVE_BYTES);
|
|
33
|
+
const perBuild = Math.floor(available / config.concurrency / GIB);
|
|
34
|
+
if (perBuild < MINIMUM_GIB) return { config };
|
|
35
|
+
const memory = `${perBuild}g`;
|
|
36
|
+
return {
|
|
37
|
+
config: { ...config, build: { ...config.build, memory } },
|
|
38
|
+
note: `builds get ${memory} of memory to fit this machine's ${gib(totalMemoryBytes)}; set ${BUILD_MEMORY_VARIABLE} to choose another value`
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/runner/startup-report.ts
|
|
43
|
+
var REPORT_TIMEOUT_MS = 5e3;
|
|
44
|
+
var EMPTY_MESSAGE = "the check failed with no message";
|
|
45
|
+
async function reportFailedStart(failed, fetchImpl, deps = {}) {
|
|
46
|
+
try {
|
|
47
|
+
if (failed.error instanceof RunnerAlreadyRunningError || refusesReport(failed.refusal)) return;
|
|
48
|
+
if (otherRunnerLive(failed.config.configPath, deps.isSameProcess ?? isSameProcess)) return;
|
|
49
|
+
await sendStartupReport(failed, fetchImpl, deps);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function refusesReport(refusal) {
|
|
54
|
+
return refusal !== void 0 && (refusal.status === 401 || isSignatureRefusal(refusal.code));
|
|
55
|
+
}
|
|
56
|
+
function otherRunnerLive(configPath, isSame) {
|
|
57
|
+
const entry = readPidFile(pidFilePath(configPath));
|
|
58
|
+
return entry !== null && entry.pid !== process.pid && isSame(entry.pid, entry.start);
|
|
59
|
+
}
|
|
60
|
+
async function sendStartupReport(failed, fetchImpl, deps) {
|
|
61
|
+
const now = deps.now ?? (() => performance.now());
|
|
62
|
+
const startedAt = now();
|
|
63
|
+
const { config } = failed;
|
|
64
|
+
const text = failed.error instanceof Error ? failed.error.message : String(failed.error);
|
|
65
|
+
const message = (deps.scrub ?? scrubReason)(stripTerminalControls(text), config) ?? EMPTY_MESSAGE;
|
|
66
|
+
const signer = await signerFor(config.configPath).catch(() => void 0);
|
|
67
|
+
const left = REPORT_TIMEOUT_MS - (now() - startedAt);
|
|
68
|
+
if (left <= 0) return;
|
|
69
|
+
await postJson(
|
|
70
|
+
config.url,
|
|
71
|
+
"/v1/hosts/startup-report",
|
|
72
|
+
config.apiKey,
|
|
73
|
+
config.appId,
|
|
74
|
+
{ host: config.host, cliVersion: failed.cliVersion, check: failed.check, message },
|
|
75
|
+
fetchImpl,
|
|
76
|
+
left,
|
|
77
|
+
signer
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { BUILD_MEMORY_VARIABLE, fitImageBuildMemory, reportFailedStart };
|
|
@@ -4963,7 +4963,7 @@ by a different key is refused; claiming again with the same key extends
|
|
|
4963
4963
|
it. --host is a label only.
|
|
4964
4964
|
`
|
|
4965
4965
|
).action(async (opts) => {
|
|
4966
|
-
const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-
|
|
4966
|
+
const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-GBU2ACRF.js');
|
|
4967
4967
|
try {
|
|
4968
4968
|
await runWorkClaim(opts);
|
|
4969
4969
|
} catch (err) {
|
|
@@ -4983,7 +4983,7 @@ Extends the live lease this API key holds. Refused with a 410 if the
|
|
|
4983
4983
|
lease has expired, or a 403 if a different key holds it.
|
|
4984
4984
|
`
|
|
4985
4985
|
).action(async (opts) => {
|
|
4986
|
-
const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-
|
|
4986
|
+
const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-GBU2ACRF.js');
|
|
4987
4987
|
try {
|
|
4988
4988
|
await runWorkRenew(opts);
|
|
4989
4989
|
} catch (err) {
|
|
@@ -5015,7 +5015,7 @@ applies to a host's lease only. A later tool call in the session
|
|
|
5015
5015
|
takes the lease again.
|
|
5016
5016
|
`
|
|
5017
5017
|
).action(async (opts) => {
|
|
5018
|
-
const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-
|
|
5018
|
+
const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-GBU2ACRF.js');
|
|
5019
5019
|
try {
|
|
5020
5020
|
await runWorkRelease(opts);
|
|
5021
5021
|
} catch (err) {
|
|
@@ -5085,7 +5085,7 @@ function registerRunnerCommands(program2) {
|
|
|
5085
5085
|
const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
|
|
5086
5086
|
runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
|
|
5087
5087
|
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-MVA7YTFW.js');
|
|
5088
|
-
const { start, RunnerStartError } = await import('./loop-
|
|
5088
|
+
const { start, RunnerStartError } = await import('./loop-KRGNTFZ2.js');
|
|
5089
5089
|
const { RunnerAlreadyRunningError } = await import('./pidfile-5UDLYPMC.js');
|
|
5090
5090
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
5091
5091
|
try {
|
|
@@ -5104,8 +5104,8 @@ function registerRunnerCommands(program2) {
|
|
|
5104
5104
|
"\nReads OUTERLAYER_URL, OUTERLAYER_APP_ID, OUTERLAYER_API_KEY, OUTERLAYER_RUNNER_NAME and one Claude credential\n(CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY) from the environment. OUTERLAYER_AGENT\nis optional and defaults to claude. On a later start it refuses variables that disagree with the config in the volume.\nThe image sets OUTERLAYER_RUNNER_IMAGE; outside the image, use `runner start`.\n"
|
|
5105
5105
|
).action(async () => {
|
|
5106
5106
|
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-MVA7YTFW.js');
|
|
5107
|
-
const { containerStart } = await import('./container-start-
|
|
5108
|
-
const { start, RunnerStartError } = await import('./loop-
|
|
5107
|
+
const { containerStart } = await import('./container-start-C4XCYPUA.js');
|
|
5108
|
+
const { start, RunnerStartError } = await import('./loop-KRGNTFZ2.js');
|
|
5109
5109
|
const { RunnerAlreadyRunningError } = await import('./pidfile-5UDLYPMC.js');
|
|
5110
5110
|
try {
|
|
5111
5111
|
const result = await containerStart({
|
|
@@ -5125,7 +5125,7 @@ function registerRunnerCommands(program2) {
|
|
|
5125
5125
|
});
|
|
5126
5126
|
runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
|
|
5127
5127
|
const { defaultRunnerConfigPath } = await import('./config-MVA7YTFW.js');
|
|
5128
|
-
const { runRunnerCheck } = await import('./check-
|
|
5128
|
+
const { runRunnerCheck } = await import('./check-YCFZ3H35.js');
|
|
5129
5129
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
5130
5130
|
const result = await runRunnerCheck(configPath);
|
|
5131
5131
|
if (!result.ok) {
|
|
@@ -5525,7 +5525,7 @@ Next:
|
|
|
5525
5525
|
});
|
|
5526
5526
|
runnerCmd.command("stop").description("Take no more work; finish running jobs, then exit").option("--config <path>", "the cloud config file naming the runner to stop").option("--now", "end running jobs immediately, with outcome stopped").action(async (opts) => {
|
|
5527
5527
|
const { defaultRunnerConfigPath } = await import('./config-MVA7YTFW.js');
|
|
5528
|
-
const { requestStop } = await import('./loop-
|
|
5528
|
+
const { requestStop } = await import('./loop-KRGNTFZ2.js');
|
|
5529
5529
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
5530
5530
|
const { runnerImageVersion } = await import('./image-tag-ADSLWXBA.js');
|
|
5531
5531
|
await requestStop(configPath, Boolean(opts.now), void 0, { image: runnerImageVersion() !== void 0 });
|
|
@@ -5533,8 +5533,8 @@ Next:
|
|
|
5533
5533
|
runnerCmd.command("status").description("List running jobs; with --recent, finished ones too").option("--config <path>", "the cloud config file naming the runner to inspect").option("--recent", "also list finished jobs, newest first, capped at 20").option("--json", "machine-readable JSON output").action(async (opts) => {
|
|
5534
5534
|
const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-MVA7YTFW.js');
|
|
5535
5535
|
const { jobsDir, runnerDir } = await import('./paths-7HVTDE6J.js');
|
|
5536
|
-
const { listJobFiles, runnerProcessState } = await import('./loop-
|
|
5537
|
-
const { renderStatus } = await import('./status-
|
|
5536
|
+
const { listJobFiles, runnerProcessState } = await import('./loop-KRGNTFZ2.js');
|
|
5537
|
+
const { renderStatus } = await import('./status-YVJQWWDP.js');
|
|
5538
5538
|
const { readHousekeepingRecord } = await import('./record-PPZEXAVA.js');
|
|
5539
5539
|
const path2 = await import('path');
|
|
5540
5540
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
@@ -5594,7 +5594,7 @@ Next:
|
|
|
5594
5594
|
});
|
|
5595
5595
|
runnerCmd.command("logs").argument("<item>", "the work item's number in the factory").description("Print the newest attempt's log for one item").option("--config <path>", "the cloud config file naming the runner to inspect").option("-f, --follow", "keep printing as the log grows").action(async (itemArg, opts) => {
|
|
5596
5596
|
const { defaultRunnerConfigPath } = await import('./config-MVA7YTFW.js');
|
|
5597
|
-
const { listJobFiles } = await import('./loop-
|
|
5597
|
+
const { listJobFiles } = await import('./loop-KRGNTFZ2.js');
|
|
5598
5598
|
const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-HI46FO6Z.js');
|
|
5599
5599
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
5600
5600
|
const item = parseTrackerNumber(itemArg);
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { BUILD_MEMORY_VARIABLE } from './chunk-
|
|
3
|
+
import { reportFailedStart, BUILD_MEMORY_VARIABLE } from './chunk-ZUVERBFB.js';
|
|
4
|
+
import './chunk-RAMTJ2XP.js';
|
|
5
|
+
import './chunk-ZVB57WI6.js';
|
|
6
|
+
import './chunk-HVRQQOMH.js';
|
|
7
|
+
import './chunk-6LBSAW6I.js';
|
|
8
|
+
import './chunk-I3LTIAOR.js';
|
|
9
|
+
import './chunk-7IFYI7XF.js';
|
|
10
|
+
import './chunk-D3EDZPJR.js';
|
|
11
|
+
import './chunk-7UPMYRPS.js';
|
|
12
|
+
import './chunk-ESVW4MJY.js';
|
|
13
|
+
import './chunk-TBT347UY.js';
|
|
4
14
|
import { detectMachine, supportsContainerBuilds, MIN_ENGINE_MAJOR, describeMachineDocker, RunnerInitError, prepareRunnerInit, writeRunnerInit } from './chunk-IUPY54BZ.js';
|
|
5
15
|
import './chunk-2PGI6RDE.js';
|
|
6
16
|
import { isAgentName, AGENT_COMMANDS } from './chunk-EXZACZ2P.js';
|
|
@@ -36,17 +46,23 @@ import './chunk-PJDQPF5N.js';
|
|
|
36
46
|
import './chunk-SOI6K5DY.js';
|
|
37
47
|
import './chunk-PA6CK6WQ.js';
|
|
38
48
|
import { readClaudeCredential, FORWARDED_CLAUDE_CREDENTIAL_VARIABLES } from './chunk-BALIE3BA.js';
|
|
49
|
+
import './chunk-UK4RGH46.js';
|
|
39
50
|
import './chunk-ZJSNLVCE.js';
|
|
51
|
+
import './chunk-2O5KA67H.js';
|
|
52
|
+
import './chunk-BKO6JEZI.js';
|
|
40
53
|
import './chunk-FGF52V4V.js';
|
|
41
54
|
import './chunk-HCVLP7XA.js';
|
|
42
55
|
import './chunk-BJ3KTMDH.js';
|
|
43
56
|
import './chunk-44V5SD4G.js';
|
|
44
57
|
import './chunk-5BHIBJDA.js';
|
|
45
58
|
import './chunk-CDDED64E.js';
|
|
46
|
-
import './chunk-RA3O54FC.js';
|
|
59
|
+
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
60
|
+
import './chunk-T2Q7ISPE.js';
|
|
47
61
|
import './chunk-WZBHBH3J.js';
|
|
48
62
|
import './chunk-CRB3POP4.js';
|
|
63
|
+
import './chunk-URIZRCRY.js';
|
|
49
64
|
import './chunk-YQR6E6OV.js';
|
|
65
|
+
import './chunk-TUSYOL2O.js';
|
|
50
66
|
import './chunk-6CXNWKWD.js';
|
|
51
67
|
import './chunk-F2D5BSXS.js';
|
|
52
68
|
import './chunk-VNVZDWO3.js';
|
|
@@ -170,22 +186,29 @@ async function containerStart(deps) {
|
|
|
170
186
|
}
|
|
171
187
|
const settings = settingsOf(env);
|
|
172
188
|
if (typeof settings === "string") return refuse(settings);
|
|
189
|
+
const url = set(env, "OUTERLAYER_URL");
|
|
190
|
+
const appId = set(env, "OUTERLAYER_APP_ID");
|
|
191
|
+
const apiKey = set(env, "OUTERLAYER_API_KEY");
|
|
192
|
+
const host = named.name;
|
|
193
|
+
const refuseDocker = async (message) => {
|
|
194
|
+
await reportFailedStart(
|
|
195
|
+
{ config: { configPath, url, apiKey, appId, host }, cliVersion: resolveVersion(), check: "docker", error: message },
|
|
196
|
+
deps.fetchImpl ?? fetch
|
|
197
|
+
);
|
|
198
|
+
return refuse(message);
|
|
199
|
+
};
|
|
173
200
|
const socketPresent = deps.socketPresent ?? existsSync;
|
|
174
201
|
if (!socketPresent(DOCKER_SOCKET)) {
|
|
175
|
-
return
|
|
202
|
+
return refuseDocker(
|
|
176
203
|
`${DOCKER_SOCKET} is not in the container. The runner starts each build as a container on the host's Docker, so start this container with -v ${DOCKER_SOCKET}:${DOCKER_SOCKET}.`
|
|
177
204
|
);
|
|
178
205
|
}
|
|
179
206
|
const machine = { ...(deps.machine ?? (() => detectMachine()))(), inImage: true };
|
|
180
207
|
if (!supportsContainerBuilds(machine)) {
|
|
181
|
-
return
|
|
208
|
+
return refuseDocker(
|
|
182
209
|
`The container reaches ${describeMachineDocker(machine)} through ${DOCKER_SOCKET}, and builds need Docker Engine in a version that isolates a build (${MIN_ENGINE_MAJOR} or later), on Docker Engine or Docker Desktop. Check that the socket is the host's Docker and that it is running.`
|
|
183
210
|
);
|
|
184
211
|
}
|
|
185
|
-
const url = set(env, "OUTERLAYER_URL");
|
|
186
|
-
const appId = set(env, "OUTERLAYER_APP_ID");
|
|
187
|
-
const apiKey = set(env, "OUTERLAYER_API_KEY");
|
|
188
|
-
const host = named.name;
|
|
189
212
|
if (existsSync(configPath)) {
|
|
190
213
|
const stored = readConfig(configPath);
|
|
191
214
|
if (stored instanceof RunnerInitError) return refuse(stored.message);
|
package/dist/index.js
CHANGED
|
@@ -26,5 +26,5 @@ if (argv[0] === "claude") {
|
|
|
26
26
|
process.exit(await runClaudeLauncher(argv.slice(1)));
|
|
27
27
|
}
|
|
28
28
|
(await import('./hook-fast-3IYSWDL4.js')).recordLinkExitFailure(argv);
|
|
29
|
-
var { runCli } = await import('./cli-
|
|
29
|
+
var { runCli } = await import('./cli-WFLOFK42.js');
|
|
30
30
|
await runCli(process.argv);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, runtimeOf, sampleUsage, start, tick, watchTick } from './chunk-
|
|
4
|
-
import './chunk-FZUFUVLK.js';
|
|
3
|
+
export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, runtimeOf, sampleUsage, start, tick, watchTick } from './chunk-Y6KIGWFO.js';
|
|
5
4
|
import './chunk-GH246BGV.js';
|
|
6
|
-
import './chunk-ZVB57WI6.js';
|
|
7
5
|
import './chunk-57L2YAJA.js';
|
|
8
6
|
import './chunk-3JVYMD4G.js';
|
|
9
7
|
import './chunk-E7R2GIAW.js';
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
8
|
+
import './chunk-ZUVERBFB.js';
|
|
9
|
+
import './chunk-RAMTJ2XP.js';
|
|
10
|
+
import './chunk-ZVB57WI6.js';
|
|
11
|
+
import './chunk-TRP3KPGK.js';
|
|
12
12
|
import './chunk-HVRQQOMH.js';
|
|
13
13
|
import './chunk-6LBSAW6I.js';
|
|
14
14
|
import './chunk-I3LTIAOR.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { isReadable, ALREADY_RELEASED, RENEW_INTERVAL_SECONDS } from './chunk-
|
|
3
|
+
import { isReadable, ALREADY_RELEASED, RENEW_INTERVAL_SECONDS } from './chunk-RAMTJ2XP.js';
|
|
4
4
|
import { jobStateFormatOf } from './chunk-ZVB57WI6.js';
|
|
5
5
|
import './chunk-HVRQQOMH.js';
|
|
6
6
|
import './chunk-6LBSAW6I.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { RUNNER_PROTOCOL } from './chunk-
|
|
3
|
+
import { RUNNER_PROTOCOL } from './chunk-TRP3KPGK.js';
|
|
4
4
|
import { defaultRunnerConfigPath } from './chunk-VWQCYOBS.js';
|
|
5
5
|
import './chunk-X4JEBMYN.js';
|
|
6
6
|
import './chunk-OGMXVPCS.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outerlayer/cli",
|
|
3
|
-
"version": "0.33.0-next.
|
|
3
|
+
"version": "0.33.0-next.20261023122246",
|
|
4
4
|
"description": "OuterLayer CLI — commands: init, claude, connect, doctor, login, logout, sync, daemon (alias: watch), emit, findings, work, spec, runner, hooks, mcp, context. Capture and sync coding-agent sessions, and record proof of factory work.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Magu Studios, Inc.",
|
package/dist/chunk-YGZLRX5U.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import { checkFit, RUNNER_RESERVE_BYTES } from './chunk-EHOFFTVX.js';
|
|
4
|
-
import { readFileSync } from 'fs';
|
|
5
|
-
|
|
6
|
-
createRequire(import.meta.url);
|
|
7
|
-
var GIB = 1024 ** 3;
|
|
8
|
-
var DEFAULT_GIB = 8;
|
|
9
|
-
var MINIMUM_GIB = 4;
|
|
10
|
-
var BUILD_MEMORY_VARIABLE = "OUTERLAYER_BUILD_MEMORY";
|
|
11
|
-
function memoryIsSet(configPath) {
|
|
12
|
-
try {
|
|
13
|
-
const raw = JSON.parse(readFileSync(configPath, "utf8"));
|
|
14
|
-
return raw.runner.build.memory !== void 0;
|
|
15
|
-
} catch {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function gib(bytes) {
|
|
20
|
-
return `${Number((bytes / GIB).toFixed(1))} GiB`;
|
|
21
|
-
}
|
|
22
|
-
function fitImageBuildMemory(config, totalMemoryBytes) {
|
|
23
|
-
if (memoryIsSet(config.configPath)) return { config };
|
|
24
|
-
const current = config.build?.memory ?? `${DEFAULT_GIB}g`;
|
|
25
|
-
if (checkFit({ concurrency: config.concurrency, buildMemory: current, usableBytes: totalMemoryBytes }).fits) return { config };
|
|
26
|
-
const available = Math.max(0, totalMemoryBytes - RUNNER_RESERVE_BYTES);
|
|
27
|
-
const perBuild = Math.floor(available / config.concurrency / GIB);
|
|
28
|
-
if (perBuild < MINIMUM_GIB) return { config };
|
|
29
|
-
const memory = `${perBuild}g`;
|
|
30
|
-
return {
|
|
31
|
-
config: { ...config, build: { ...config.build, memory } },
|
|
32
|
-
note: `builds get ${memory} of memory to fit this machine's ${gib(totalMemoryBytes)}; set ${BUILD_MEMORY_VARIABLE} to choose another value`
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { BUILD_MEMORY_VARIABLE, fitImageBuildMemory };
|