@outerlayer/cli 0.8.0 → 0.8.2

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.
Files changed (91) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +27 -9
  3. package/dist/{agent-setup-C7PLRXZO.js → agent-setup-C5X4356W.js} +10 -10
  4. package/dist/{build-MS34XEGN.js → build-3FSJR5OO.js} +1 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/{builder-G52A6GW2.js → builder-QZA2Z3M3.js} +3 -3
  7. package/dist/{check-FOF3PUKI.js → check-HQHFAOXW.js} +30 -29
  8. package/dist/{chunk-R7STSBLC.js → chunk-2E2MG3KW.js} +1 -1
  9. package/dist/{chunk-OD2VTIHN.js → chunk-2FWL7CE2.js} +3 -2
  10. package/dist/{chunk-K35RW5HP.js → chunk-33GOCSRO.js} +4 -4
  11. package/dist/{chunk-4A5E2G4E.js → chunk-3J476JZC.js} +11 -11
  12. package/dist/{chunk-MQ3IPHIZ.js → chunk-47RS42OZ.js} +6 -3
  13. package/dist/{chunk-3S4P55NE.js → chunk-4ZZR5SKG.js} +3 -3
  14. package/dist/{chunk-PWBILI5P.js → chunk-7KI224YS.js} +1 -1
  15. package/dist/{chunk-5TNS3PL7.js → chunk-CLURXEWV.js} +4 -3
  16. package/dist/{chunk-7ZR5UPMB.js → chunk-CMFCCIQN.js} +167 -1
  17. package/dist/{chunk-AX23QKHS.js → chunk-CRLAB4PM.js} +1 -1
  18. package/dist/{chunk-CM5QTKM4.js → chunk-EQG7L6LM.js} +311 -29
  19. package/dist/{chunk-OEK4JEB3.js → chunk-ERI5GBNI.js} +18 -3
  20. package/dist/{chunk-ILEA3YHM.js → chunk-EWBM2USM.js} +2 -2
  21. package/dist/{chunk-EV3M3EH7.js → chunk-G54QHBTI.js} +2 -2
  22. package/dist/{chunk-M3SQ4YGD.js → chunk-GXSMDL4M.js} +1 -1
  23. package/dist/{chunk-GAYWY4GI.js → chunk-HN2JBGSI.js} +2 -1
  24. package/dist/{chunk-ZOAEPWGL.js → chunk-HWMYGAKF.js} +1 -1
  25. package/dist/chunk-I2UOAV7X.js +133 -0
  26. package/dist/{chunk-ABIWDUMS.js → chunk-IS4DIGBQ.js} +13 -1
  27. package/dist/{chunk-WVGSB3Z2.js → chunk-J5DPVNL3.js} +2 -2
  28. package/dist/{chunk-VXLJORHL.js → chunk-JXH6LEEH.js} +1 -1
  29. package/dist/{chunk-JPR2WHHF.js → chunk-KI7VPNKC.js} +1 -1
  30. package/dist/{chunk-TUUMW4TC.js → chunk-LSPJHYHM.js} +1 -1
  31. package/dist/{chunk-7VNURP6M.js → chunk-M2F2RAMK.js} +82 -26
  32. package/dist/{chunk-NALVDFIS.js → chunk-MJLUWGUD.js} +2 -2
  33. package/dist/{chunk-5FWNEQNZ.js → chunk-NACLOOXP.js} +5 -5
  34. package/dist/{chunk-U3GOI2B4.js → chunk-NPBLDMSD.js} +1 -1
  35. package/dist/{chunk-BOLTI6LR.js → chunk-PLMTLGYH.js} +1 -1
  36. package/dist/{chunk-IRCBTGWF.js → chunk-QJPO42VI.js} +6 -6
  37. package/dist/{chunk-5QLNZGAQ.js → chunk-R5SPFO6F.js} +6 -6
  38. package/dist/{chunk-M5POMKKW.js → chunk-V7NIVOFD.js} +5 -5
  39. package/dist/{chunk-IJBVPLZZ.js → chunk-VUGDEUMM.js} +71 -143
  40. package/dist/{chunk-4ACZCY4I.js → chunk-WMPO3SKK.js} +3 -3
  41. package/dist/{chunk-TTNFGMHO.js → chunk-Y7UQHKFY.js} +19 -1
  42. package/dist/{chunk-BCLJSQCV.js → chunk-YO4PSLVB.js} +1 -1
  43. package/dist/{chunk-AIL2R4SI.js → chunk-YU4Z2O3W.js} +5 -5
  44. package/dist/{chunk-ZZXLM64C.js → chunk-ZJ3WRVRG.js} +1 -1
  45. package/dist/{cli-AOJPAVFX.js → cli-OWM54BIU.js} +120 -93
  46. package/dist/{command-SY3SVLAI.js → command-LIHTWJHQ.js} +31 -25
  47. package/dist/{config-Z3USDBLU.js → config-OOBPCY7Q.js} +2 -2
  48. package/dist/{connect-cmd-PNZ6IJLJ.js → connect-cmd-NV7WVBY7.js} +3 -3
  49. package/dist/{context-adopt-CE4KDXS3.js → context-adopt-PPCNSN5D.js} +7 -7
  50. package/dist/{context-materialize-QL33HDJN.js → context-materialize-YR3JQCUF.js} +7 -7
  51. package/dist/{dist-3ZTZF2TP.js → dist-2LNAXGPZ.js} +1 -1
  52. package/dist/{docker-676FD3CQ.js → docker-RSALMGPL.js} +4 -4
  53. package/dist/{doctor-WR6TRPSU.js → doctor-PKT42NOJ.js} +59 -25
  54. package/dist/{emit-artifact-cmd-AVM4YXMQ.js → emit-artifact-cmd-BZYXRBCV.js} +8 -8
  55. package/dist/{emit-cmd-2QRMYPYO.js → emit-cmd-IRYNFHPM.js} +3 -3
  56. package/dist/{emit-criteria-cmd-LDBE4YDS.js → emit-criteria-cmd-PSZYZ32B.js} +6 -6
  57. package/dist/{emit-finding-cmd-6R5WBPCH.js → emit-finding-cmd-VTSYDJYZ.js} +6 -6
  58. package/dist/{emit-result-cmd-2DMN6O6U.js → emit-result-cmd-5P7ZFWMZ.js} +8 -8
  59. package/dist/{exec-client-NPYNUAF3.js → exec-client-2UX6NHAO.js} +3 -3
  60. package/dist/{guest-init-JWNNAH2H.js → guest-init-VHQNFCFS.js} +3 -3
  61. package/dist/{hook-fast-XBOZ3N6L.js → hook-fast-OCHVQZTU.js} +1 -1
  62. package/dist/{host-key-KDYZ5ECC.js → host-key-YMLXY6QB.js} +1 -1
  63. package/dist/{import-capture-cmd-T4556ELW.js → import-capture-cmd-2QFLZQFY.js} +3 -3
  64. package/dist/{import-ruler-cmd-SG3UVGI7.js → import-ruler-cmd-BD22GUJS.js} +1 -1
  65. package/dist/index.js +3 -3
  66. package/dist/{init-R2FJ5KNS.js → init-CY4IMZE4.js} +22 -22
  67. package/dist/{init-KDK5QLQZ.js → init-TQUN5RF7.js} +20 -20
  68. package/dist/{init-cmd-BYZYAJ5P.js → init-cmd-F4TZXQJH.js} +11 -11
  69. package/dist/{install-FHTVJZS6.js → install-C33LT5KQ.js} +3 -3
  70. package/dist/{install-cmd-DCF7TVXD.js → install-cmd-5HYMXLEW.js} +2 -1
  71. package/dist/{loop-AG3PLXPO.js → loop-NZP5FAC3.js} +30 -29
  72. package/dist/{machine-LV6WBRRK.js → machine-RUSNVLKO.js} +19 -19
  73. package/dist/{mcp-install-cmd-RLK4SO3N.js → mcp-install-cmd-4AQMSIGY.js} +1 -1
  74. package/dist/{mcp-serve-cmd-N6UD2KBX.js → mcp-serve-cmd-3KVYEUXG.js} +3 -3
  75. package/dist/{real-deps-SU24ZA2K.js → real-deps-TK6JMQSW.js} +3 -2
  76. package/dist/{session-sender-Q5HAMOL2.js → session-sender-EECVKXTC.js} +7 -7
  77. package/dist/{starter-pack-MUXMAU4S.js → starter-pack-VNWPYP5U.js} +3 -3
  78. package/dist/{status-HH4OSOHR.js → status-KCONQLOD.js} +31 -25
  79. package/dist/{sync-cmd-CAEPJR7B.js → sync-cmd-R54ZBHXX.js} +6 -6
  80. package/dist/{watch-LAAZFBHH.js → watch-YTFNBO3S.js} +6 -6
  81. package/dist/{work-claim-cmd-ARIYZARE.js → work-claim-cmd-HRPJ4VUF.js} +10 -10
  82. package/dist/{work-cmd-B3FOXZAL.js → work-cmd-W4GQUUBC.js} +7 -7
  83. package/dist/{work-comment-cmd-O5WGRI6K.js → work-comment-cmd-DDZ4SZ35.js} +7 -7
  84. package/dist/{work-open-pr-cmd-M6CQW7KW.js → work-open-pr-cmd-GXULDTSC.js} +8 -8
  85. package/dist/{work-pr-cmd-C4YEGKD6.js → work-pr-cmd-T6SU4TYN.js} +7 -7
  86. package/package.json +2 -2
  87. package/skill-pack/maintained/amend/SKILL.md +22 -6
  88. package/skill-pack/maintained/outerlayer/SKILL.md +12 -2
  89. package/skill-pack/maintained/outerlayer/references/open-pull-request.md +29 -0
  90. package/skill-pack/template/build/SKILL.md +3 -2
  91. package/skill-pack/template/build/references/release.md +11 -2
@@ -1,26 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-ABIWDUMS.js';
4
- 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-7VNURP6M.js';
3
+ import { decideInstalledSwitch, fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-IS4DIGBQ.js';
4
+ import { compareVersions, satisfiesRange } from './chunk-I2UOAV7X.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-M2F2RAMK.js';
5
6
  import { writeJobFile, readJobFile, readJobFileChecked } from './chunk-T6OIJQRT.js';
6
7
  import { RUNNER_PROTOCOL } from './chunk-AIW6GLET.js';
7
8
  import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
8
- import { placeholderQueues, placeholderProblem } from './chunk-IRCBTGWF.js';
9
- import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-TI7B7UEO.js';
9
+ import { placeholderQueues, placeholderProblem } from './chunk-QJPO42VI.js';
10
+ import { currentVersion, entryIn, versionDir, startedThroughCurrent, writeMarker, readMarker, removeMarker, switchCurrent, cleanVersions, isInLayout, stagingDir } from './chunk-TI7B7UEO.js';
10
11
  import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
11
12
  import { RepoFilter } from './chunk-TBT347UY.js';
12
- import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, measureDisk, createRunnerLog, setUpRunnerCgroup, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, formatClock } from './chunk-CM5QTKM4.js';
13
+ import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, measureDisk, createRunnerLog, setUpRunnerCgroup, parseCpuList, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, formatClock } from './chunk-EQG7L6LM.js';
13
14
  import { checkFit } from './chunk-JKIWMRFH.js';
14
15
  import { startTimeOf, claimPidFile, readPidFile, isSameProcess, releasePidFile } from './chunk-N5FOE5PS.js';
15
- import { spawnRun } from './chunk-U3GOI2B4.js';
16
- import { builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, BUILD_LABEL, RUNNER_LABEL } from './chunk-5TNS3PL7.js';
17
- import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-5QLNZGAQ.js';
18
- import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-PWBILI5P.js';
16
+ import { spawnRun } from './chunk-NPBLDMSD.js';
17
+ import { builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, BUILD_LABEL, RUNNER_LABEL } from './chunk-CLURXEWV.js';
18
+ import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-R5SPFO6F.js';
19
+ import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-7KI224YS.js';
19
20
  import { exceedsDisk } from './chunk-7RQ73DLO.js';
20
- import { sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-OD2VTIHN.js';
21
+ import { sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-2FWL7CE2.js';
21
22
  import { parseClaimIdentity } from './chunk-HKMPVPO7.js';
22
23
  import { resolveVersion } from './chunk-RA3O54FC.js';
23
- import { loadHostKey, ensureHostKey, signerFor } from './chunk-M5POMKKW.js';
24
+ import { loadHostKey, ensureHostKey, signerFor } from './chunk-V7NIVOFD.js';
24
25
  import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, jobsDir, pidFilePath, spoolDir, RUNNER_FILE_MODE, rootfsDir } from './chunk-ZM2IMMYN.js';
25
26
  import { HOOKS_DIR_NAME, writeCommitHooks } from './chunk-XCCLFVXM.js';
26
27
  import { randomBytes } from 'crypto';
@@ -189,133 +190,6 @@ function writeLastUpdate(configPath, update) {
189
190
  `, { mode: RUNNER_FILE_MODE });
190
191
  renameSync(temporary, path);
191
192
  }
192
-
193
- // src/runner/update/version-order.ts
194
- function parse(version) {
195
- const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version);
196
- if (match === null) return void 0;
197
- return { core: [Number(match[1]), Number(match[2]), Number(match[3])], pre: match[4] };
198
- }
199
- function comparePre(a, b) {
200
- const left = a.split(".");
201
- const right = b.split(".");
202
- for (let i = 0; i < Math.max(left.length, right.length); i++) {
203
- const x = left[i];
204
- const y = right[i];
205
- if (x === void 0) return -1;
206
- if (y === void 0) return 1;
207
- const xNum = /^\d+$/.test(x);
208
- const yNum = /^\d+$/.test(y);
209
- if (xNum && yNum) {
210
- const difference = Number(x) - Number(y);
211
- if (difference !== 0) return Math.sign(difference);
212
- } else if (xNum !== yNum) {
213
- return xNum ? -1 : 1;
214
- } else if (x < y) {
215
- return -1;
216
- } else if (x > y) {
217
- return 1;
218
- }
219
- }
220
- return 0;
221
- }
222
- function compareVersions(a, b) {
223
- const left = parse(a);
224
- const right = parse(b);
225
- if (left === void 0 || right === void 0) return void 0;
226
- for (let i = 0; i < 3; i++) {
227
- const difference = left.core[i] - right.core[i];
228
- if (difference !== 0) return Math.sign(difference);
229
- }
230
- if (left.pre === right.pre) return 0;
231
- if (left.pre === void 0) return 1;
232
- if (right.pre === void 0) return -1;
233
- return comparePre(left.pre, right.pre);
234
- }
235
- function compareCores(a, b) {
236
- for (let i = 0; i < 3; i++) {
237
- const difference = a[i] - b[i];
238
- if (difference !== 0) return Math.sign(difference);
239
- }
240
- return 0;
241
- }
242
- function parsePartial(text) {
243
- if (text === "" || text === "*" || text === "x" || text === "X") return [];
244
- const match = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?$/.exec(text);
245
- if (match === null) return void 0;
246
- const numbers = [];
247
- for (const part of [match[1], match[2], match[3]]) {
248
- if (part === void 0 || !/^\d+$/.test(part)) break;
249
- numbers.push(Number(part));
250
- }
251
- return numbers;
252
- }
253
- function bumpLast(numbers) {
254
- const core = [numbers[0] ?? 0, numbers[1] ?? 0, numbers[2] ?? 0];
255
- const last = numbers.length - 1;
256
- core[last] = core[last] + 1;
257
- for (let i = last + 1; i < 3; i++) core[i] = 0;
258
- return core;
259
- }
260
- function fill(numbers) {
261
- return [numbers[0] ?? 0, numbers[1] ?? 0, numbers[2] ?? 0];
262
- }
263
- function meets(version, comparator) {
264
- const match = /^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(comparator);
265
- const op = match[1] ?? "";
266
- const numbers = parsePartial(match[2]);
267
- if (numbers === void 0) return void 0;
268
- if (numbers.length === 0) return op === "" || op === "=" || op === ">=" || op === "<=" ? true : void 0;
269
- const low = fill(numbers);
270
- const whole = numbers.length === 3;
271
- switch (op) {
272
- case ">=":
273
- return compareCores(version, low) >= 0;
274
- case ">":
275
- return whole ? compareCores(version, low) > 0 : compareCores(version, bumpLast(numbers)) >= 0;
276
- case "<":
277
- return compareCores(version, low) < 0;
278
- case "<=":
279
- return whole ? compareCores(version, low) <= 0 : compareCores(version, bumpLast(numbers)) < 0;
280
- case "~":
281
- return compareCores(version, low) >= 0 && compareCores(version, bumpLast(numbers.slice(0, Math.min(numbers.length, 2)))) < 0;
282
- case "^": {
283
- let pivot = numbers.findIndex((n) => n !== 0);
284
- if (pivot === -1) pivot = numbers.length - 1;
285
- return compareCores(version, low) >= 0 && compareCores(version, bumpLast(numbers.slice(0, pivot + 1))) < 0;
286
- }
287
- default:
288
- return compareCores(version, low) >= 0 && (whole ? compareCores(version, low) <= 0 : compareCores(version, bumpLast(numbers)) < 0);
289
- }
290
- }
291
- function satisfiesRange(version, range) {
292
- const parsed = parse(version.trim().replace(/^v/, ""));
293
- if (parsed === void 0 || parsed.pre !== void 0) return void 0;
294
- let anyUnreadable = false;
295
- for (const alternative of range.split("||")) {
296
- if (/\s-\s/.test(alternative)) {
297
- anyUnreadable = true;
298
- continue;
299
- }
300
- const comparators = alternative.trim().replace(/(>=|<=|>|<|=|\^|~)\s+/g, "$1").split(/\s+/).filter((c) => c !== "");
301
- if (comparators.length === 0) comparators.push("*");
302
- let all = true;
303
- for (const comparator of comparators) {
304
- const met = meets(parsed.core, comparator);
305
- if (met === void 0) {
306
- anyUnreadable = true;
307
- all = false;
308
- break;
309
- }
310
- if (!met) {
311
- all = false;
312
- break;
313
- }
314
- }
315
- if (all) return true;
316
- }
317
- return anyUnreadable ? void 0 : false;
318
- }
319
193
  var RELEASE_REPOSITORY = "https://github.com/outerlayerai/outerlayer";
320
194
  var RELEASE_WORKFLOW_PATH = ".github/workflows/outerlayer-release.yml";
321
195
  var UpdateStepError = class extends Error {
@@ -588,6 +462,7 @@ function settleUpdate(args) {
588
462
 
589
463
  // src/runner/housekeeping/docker.ts
590
464
  var KIND_LABEL = "ai.outerlayer.kind";
465
+ var NO_BUILDER = /no builder .* found/i;
591
466
  function failure(result, what) {
592
467
  return new Error(`${what}: ${result.stderr.trim() || `docker exited ${result.status}`}`);
593
468
  }
@@ -679,8 +554,12 @@ function createHousekeepingDocker(deps) {
679
554
  if (result.status !== 0) throw failure(result, `docker rmi ${id}`);
680
555
  },
681
556
  async builderPrune(keepBytes) {
557
+ const inspected = await run("docker", ["buildx", "inspect", deps.builder]);
558
+ if (inspected.status !== 0 && NO_BUILDER.test(inspected.stderr)) return void 0;
559
+ const status = inspected.status === 0 ? /^Status:\s*(\S+)/m.exec(inspected.stdout)?.[1] : void 0;
560
+ if (status !== void 0 && status !== "running") return void 0;
682
561
  const result = await run("docker", ["buildx", "prune", "--builder", deps.builder, "--force", "--max-used-space", String(keepBytes)]);
683
- if (result.status !== 0 && /no builder .* found/i.test(result.stderr)) return { freedBytes: 0 };
562
+ if (result.status !== 0 && (NO_BUILDER.test(result.stderr) || /driver not running/i.test(result.stderr))) return void 0;
684
563
  if (result.status !== 0) throw failure(result, "docker buildx prune");
685
564
  return { freedBytes: parsePrunedBytes(result.stdout) };
686
565
  }
@@ -851,8 +730,12 @@ async function runHousekeeping(options) {
851
730
  if (options.buildCacheMax !== "off") {
852
731
  try {
853
732
  const pruned = await docker.builderPrune(options.buildCacheMax);
854
- freed += pruned.freedBytes;
855
- log.line(`housekeeping: pruned the image builder's build cache down to ${formatBytes(options.buildCacheMax)}, freed ${formatBytes(pruned.freedBytes)}`);
733
+ if (pruned === void 0) {
734
+ log.line("housekeeping: the image builder is not running, so its build cache is left for a later pass");
735
+ } else {
736
+ freed += pruned.freedBytes;
737
+ log.line(`housekeeping: pruned the image builder's build cache down to ${formatBytes(options.buildCacheMax)}, freed ${formatBytes(pruned.freedBytes)}`);
738
+ }
856
739
  } catch (err) {
857
740
  log.error(`housekeeping: the build cache could not be pruned: ${describeCallFailure(err)}`);
858
741
  }
@@ -1097,6 +980,48 @@ function reportUpdateResult(state, version, result) {
1097
980
  const retryAt = new Date(result.retryAtMs).toISOString().slice(11, 16);
1098
981
  logOf(state).error(`could not update to ${version}: ${result.detail} \xB7 attempt ${result.attempts}, trying again after ${retryAt} UTC`);
1099
982
  }
983
+ function restartOntoInstalled(state) {
984
+ const update = state.deps.update;
985
+ if (update === void 0) return false;
986
+ const configPath = state.config.configPath;
987
+ const own = ownVersionOf(state.deps);
988
+ const current = currentVersion(configPath);
989
+ const decision = decideInstalledSwitch({
990
+ own,
991
+ current,
992
+ fromCurrent: startedThroughCurrent(configPath, update.entryPath),
993
+ underService: update.underService === true,
994
+ installed: current !== void 0 && existsSync(entryIn(versionDir(configPath, current)))
995
+ });
996
+ if (decision.kind === "none") {
997
+ state.installedSwitch = void 0;
998
+ return false;
999
+ }
1000
+ const said = `${decision.kind}:${decision.to}`;
1001
+ const first = state.installedSwitch !== said;
1002
+ state.installedSwitch = said;
1003
+ const log = logOf(state);
1004
+ if (decision.kind === "missing") {
1005
+ if (first) log.error(`current names ${decision.to}, which is not installed \xB7 staying on ${own}; run \`outerlayer runner install\` again`);
1006
+ return false;
1007
+ }
1008
+ if (decision.kind === "foreground") {
1009
+ if (first) log.line(`${decision.to} is installed and current names it \xB7 this runner keeps running ${own} until it is restarted`);
1010
+ return false;
1011
+ }
1012
+ if (state.jobs.size > 0) {
1013
+ if (first) log.line(`${decision.to} is installed \xB7 taking no new work, restarting onto it once ${state.jobs.size} running build(s) finish`);
1014
+ return true;
1015
+ }
1016
+ try {
1017
+ writeMarker(configPath, { from: own, to: decision.to, starts: 0 });
1018
+ } catch (err) {
1019
+ log.error(`could not write the update marker, so ${decision.to} starts without going back to ${own} if its checks fail: ${describeCallFailure(err)}`);
1020
+ }
1021
+ log.line(`restarting ${own} -> ${decision.to}, which runner install put in place`);
1022
+ (state.exitForUpdate ?? (() => update.exit(RESTART_EXIT_STATUS)))();
1023
+ return true;
1024
+ }
1100
1025
  async function updateWhenIdle(state) {
1101
1026
  const update = state.deps.update;
1102
1027
  const version = state.pendingUpdate;
@@ -1250,6 +1175,7 @@ async function housekeepingPass(state) {
1250
1175
  }
1251
1176
  async function runTick(state) {
1252
1177
  reloadConfig(state);
1178
+ if (restartOntoInstalled(state)) return;
1253
1179
  if (await updateWhenIdle(state)) return;
1254
1180
  if (holdWhenBlocked(state)) return;
1255
1181
  if (holdOffForDisk(state)) return;
@@ -1306,7 +1232,7 @@ var CLAIM_REFUSAL_CODES = new Set(
1306
1232
  "pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous branch_claimed_elsewhere".split(" ")
1307
1233
  );
1308
1234
  async function tryClaimAndStart(state, item, queue) {
1309
- const { postJson: postJson2 } = await import('./work-cmd-B3FOXZAL.js');
1235
+ const { postJson: postJson2 } = await import('./work-cmd-W4GQUUBC.js');
1310
1236
  const log = logOf(state);
1311
1237
  const hostKey = await loadHostKey(state.config.configPath);
1312
1238
  const claim = await retrySend(
@@ -2030,7 +1956,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
2030
1956
  const outcome = await onStartUnderMarker({
2031
1957
  configPath,
2032
1958
  own: ownVersionOf(deps),
2033
- check: update.check ? () => update.check(configPath) : async () => (await import('./check-FOF3PUKI.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
1959
+ check: update.check ? () => update.check(configPath) : async () => (await import('./check-HQHFAOXW.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
2034
1960
  now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
2035
1961
  log
2036
1962
  });
@@ -2072,6 +1998,8 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
2072
1998
  const adopted = { job, dirPath, lastRenewAtMs: nowMs(), cmd: null, cpuSample: null, ending: false };
2073
1999
  state.jobs.set(dirPath, adopted);
2074
2000
  if (job.container !== void 0) {
2001
+ const cores = job.container.cpuset === void 0 ? void 0 : parseCpuList(job.container.cpuset);
2002
+ if (cores !== void 0) runtimeOf(state).cpus.hold(job.container.buildId, cores);
2075
2003
  const tokens = buildTokensFor(state, adopted, job.item);
2076
2004
  runtimeOf(state).credentials.set(dirPath, tokens);
2077
2005
  await ensureTunnel(runtimeOf(state), job.container, dirPath, config, job.itemKey, job.branch);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-ILEA3YHM.js';
4
- import { resolveRepoIdentity } from './chunk-GAYWY4GI.js';
5
- import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-EWBM2USM.js';
4
+ import { resolveRepoIdentity } from './chunk-HN2JBGSI.js';
5
+ import { resolveGatewayCredentials } from './chunk-PLMTLGYH.js';
6
6
  import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
7
7
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
8
8
 
@@ -111,6 +111,24 @@ async function fetchCommit(input) {
111
111
  return { ok: false, reason: `the fetch of ${input.commit.slice(0, 8)} from ${input.remote} failed: ${detail}` };
112
112
  }
113
113
  }
114
+ async function diffBetween(input) {
115
+ const credential = input.token === void 0 ? void 0 : tokenSettings(input.remote, input.token);
116
+ try {
117
+ mkdirSync(input.dir, { recursive: true, mode: RUNNER_DIR_MODE });
118
+ await git(input.dir, ["init", "--quiet"]);
119
+ await git(input.dir, ["fetch", "--quiet", "--no-tags", "--filter=blob:none", input.remote, input.base, input.head], CLONE_TIMEOUT_MS, credential);
120
+ await git(
121
+ input.dir,
122
+ ["diff", "--no-ext-diff", "--no-textconv", "--no-color", "--binary", `--output=${input.output}`, `${input.base}...${input.head}`],
123
+ CLONE_TIMEOUT_MS,
124
+ credential
125
+ );
126
+ return { ok: true };
127
+ } catch (err) {
128
+ const detail = (err instanceof Error ? err.message : String(err)).replace(/^git [\w-]+ failed: /, "").split("\n")[0];
129
+ return { ok: false, reason: `the diff of ${input.head.slice(0, 8)} from ${input.base.slice(0, 8)} could not be read from ${input.remote}: ${detail}` };
130
+ }
131
+ }
114
132
  var CLONE_TIMEOUT_MS = 6e5;
115
133
  async function cloneRepository(remote, dest, timeoutMs = CLONE_TIMEOUT_MS) {
116
134
  mkdirSync(dirname(dest), { recursive: true, mode: RUNNER_DIR_MODE });
@@ -485,4 +503,4 @@ async function prune(host, repository, repoRecords, keep, runnerDirPath) {
485
503
  return removed;
486
504
  }
487
505
 
488
- export { buildRepositoryImage, cloneRepository, fetchCommit, readBranchHead, readDefaultBranchHead };
506
+ export { buildRepositoryImage, cloneRepository, diffBetween, fetchCommit, readBranchHead, readDefaultBranchHead };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { readCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
4
- import { signRunnerRequest, signerFor } from './chunk-M5POMKKW.js';
4
+ import { signRunnerRequest, signerFor } from './chunk-V7NIVOFD.js';
5
5
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
6
6
 
7
7
  createRequire(import.meta.url);
@@ -5,16 +5,16 @@ import { RepoFilter } from './chunk-TBT347UY.js';
5
5
  import { hookExecSpoolPath } from './chunk-F7CU5ABH.js';
6
6
  import { applyReportedCost } from './chunk-BKO6JEZI.js';
7
7
  import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-ZYHKJKSU.js';
8
- import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-GAYWY4GI.js';
8
+ import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-HN2JBGSI.js';
9
9
  import { C } from './chunk-YRYMNBGQ.js';
10
10
  import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-GQD22KKN.js';
11
11
  import { readLatestProvenanceForSession, readContextProvenance } from './chunk-ZJSNLVCE.js';
12
- import { defaultFetch } from './chunk-BCLJSQCV.js';
13
- import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
12
+ import { defaultFetch } from './chunk-YO4PSLVB.js';
13
+ import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-PLMTLGYH.js';
14
14
  import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-YNJEOGDL.js';
15
15
  import { readCloudConfig, cloudConfigPath, writeCloudConfig } from './chunk-EABW6AJQ.js';
16
- import { signerFor, signRunnerRequest } from './chunk-M5POMKKW.js';
17
- import { writeSyncStatus, spoolDir } from './chunk-JPR2WHHF.js';
16
+ import { signerFor, signRunnerRequest } from './chunk-V7NIVOFD.js';
17
+ import { writeSyncStatus, spoolDir } from './chunk-KI7VPNKC.js';
18
18
  import { removeJournalHooks } from './chunk-XCCLFVXM.js';
19
19
  import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
20
20
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_PIN_FILENAME } from './chunk-7ZR5UPMB.js';
3
+ import { CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_PIN_FILENAME } from './chunk-CMFCCIQN.js';
4
4
  import { readFileSync, existsSync, writeFileSync, mkdirSync, utimesSync, statSync, unlinkSync } from 'fs';
5
5
  import { join, dirname } from 'path';
6
6