@outerlayer/cli 0.8.0 → 0.8.1

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 (55) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{agent-setup-C7PLRXZO.js → agent-setup-K6RD2Z4P.js} +3 -3
  3. package/dist/build-info.json +1 -1
  4. package/dist/{builder-G52A6GW2.js → builder-IG6FNA54.js} +1 -1
  5. package/dist/{check-FOF3PUKI.js → check-GX5ND6RO.js} +16 -15
  6. package/dist/{chunk-5TNS3PL7.js → chunk-2BRSMBBB.js} +2 -1
  7. package/dist/{chunk-3S4P55NE.js → chunk-4FPWKV7L.js} +2 -2
  8. package/dist/{chunk-IJBVPLZZ.js → chunk-5ODHQP6O.js} +24 -139
  9. package/dist/{chunk-AIL2R4SI.js → chunk-BF4KKEFY.js} +3 -3
  10. package/dist/{chunk-5FWNEQNZ.js → chunk-BQFNZOMQ.js} +1 -1
  11. package/dist/{chunk-4A5E2G4E.js → chunk-HSN5QNS5.js} +4 -4
  12. package/dist/chunk-I2UOAV7X.js +133 -0
  13. package/dist/{chunk-OEK4JEB3.js → chunk-I7CJIRMM.js} +13 -3
  14. package/dist/{chunk-JPR2WHHF.js → chunk-KSLNQOOS.js} +1 -1
  15. package/dist/{chunk-5QLNZGAQ.js → chunk-KV47VQJZ.js} +3 -3
  16. package/dist/{chunk-CM5QTKM4.js → chunk-M4ERCYDB.js} +84 -19
  17. package/dist/{chunk-K35RW5HP.js → chunk-PXFEYBDE.js} +1 -1
  18. package/dist/{chunk-IRCBTGWF.js → chunk-Q4432IZT.js} +4 -4
  19. package/dist/{chunk-7VNURP6M.js → chunk-QB5JQH5V.js} +15 -12
  20. package/dist/{chunk-TUUMW4TC.js → chunk-QNRSFEGY.js} +1 -1
  21. package/dist/{chunk-U3GOI2B4.js → chunk-TEKZRTM3.js} +1 -1
  22. package/dist/{chunk-M5POMKKW.js → chunk-V7NIVOFD.js} +5 -5
  23. package/dist/{chunk-BCLJSQCV.js → chunk-YO4PSLVB.js} +1 -1
  24. package/dist/{chunk-NALVDFIS.js → chunk-Z2THOHPP.js} +2 -2
  25. package/dist/{cli-AOJPAVFX.js → cli-X5ONGYNY.js} +80 -56
  26. package/dist/{command-SY3SVLAI.js → command-7NFU3IPO.js} +14 -11
  27. package/dist/{context-adopt-CE4KDXS3.js → context-adopt-D2Z7F7PB.js} +3 -3
  28. package/dist/{context-materialize-QL33HDJN.js → context-materialize-4PMTDS6K.js} +3 -3
  29. package/dist/{docker-676FD3CQ.js → docker-PRHRSJM5.js} +2 -2
  30. package/dist/{doctor-WR6TRPSU.js → doctor-KALLPCRB.js} +10 -10
  31. package/dist/{emit-artifact-cmd-AVM4YXMQ.js → emit-artifact-cmd-D5GMVWNC.js} +4 -4
  32. package/dist/{emit-criteria-cmd-LDBE4YDS.js → emit-criteria-cmd-IE7VIM64.js} +2 -2
  33. package/dist/{emit-finding-cmd-6R5WBPCH.js → emit-finding-cmd-46PTPN3A.js} +2 -2
  34. package/dist/{emit-result-cmd-2DMN6O6U.js → emit-result-cmd-KXHHP6HX.js} +4 -4
  35. package/dist/{hook-fast-XBOZ3N6L.js → hook-fast-5H5QBJKT.js} +1 -1
  36. package/dist/{host-key-KDYZ5ECC.js → host-key-YMLXY6QB.js} +1 -1
  37. package/dist/index.js +3 -3
  38. package/dist/{init-R2FJ5KNS.js → init-B4CECVOX.js} +9 -9
  39. package/dist/{init-KDK5QLQZ.js → init-S4DH6PWW.js} +9 -9
  40. package/dist/{init-cmd-BYZYAJ5P.js → init-cmd-P4MVCBCZ.js} +5 -5
  41. package/dist/{install-cmd-DCF7TVXD.js → install-cmd-BEC7XTNG.js} +2 -1
  42. package/dist/{loop-AG3PLXPO.js → loop-ODMRE3CW.js} +16 -15
  43. package/dist/{machine-LV6WBRRK.js → machine-J4SAB3Z2.js} +8 -8
  44. package/dist/{mcp-serve-cmd-N6UD2KBX.js → mcp-serve-cmd-CT47P4YQ.js} +2 -2
  45. package/dist/{session-sender-Q5HAMOL2.js → session-sender-V46VPWQ5.js} +5 -5
  46. package/dist/{status-HH4OSOHR.js → status-QBKSH3QE.js} +11 -11
  47. package/dist/{sync-cmd-CAEPJR7B.js → sync-cmd-RJR77V4O.js} +4 -4
  48. package/dist/{watch-LAAZFBHH.js → watch-YNZTFLEY.js} +4 -4
  49. package/dist/{work-claim-cmd-ARIYZARE.js → work-claim-cmd-KAD3ZAH7.js} +4 -4
  50. package/dist/{work-cmd-B3FOXZAL.js → work-cmd-CNWPTH7W.js} +3 -3
  51. package/dist/{work-comment-cmd-O5WGRI6K.js → work-comment-cmd-HH45S6UE.js} +3 -3
  52. package/dist/{work-open-pr-cmd-M6CQW7KW.js → work-open-pr-cmd-5KR3KFCN.js} +4 -4
  53. package/dist/{work-pr-cmd-C4YEGKD6.js → work-pr-cmd-TTEGCP76.js} +3 -3
  54. package/package.json +2 -2
  55. package/skill-pack/maintained/amend/SKILL.md +22 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @outerlayer/cli
2
2
 
3
+ ## 0.8.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2bfa3a8: The `amend` skill now works in a build a runner started. It posts its closing report on the work item's general thread with `outerlayer work comment`, because a build's GitHub token cannot comment on the pull request. A local session posts the report there too, and still comments on the pull request. The SSH keep-alive advice for a dropped push now applies only to a local session pushing over SSH. Run `outerlayer context emit` to pick up the new copy.
8
+ - d2ad3fc: A microVM build's root disk and build disk are made in containers held to `runner.build.memory`, with no swap, like the build's image builds. Docker runs those containers outside the runner's own cgroup, so nothing else limited them.
9
+ - cf56a33: Three runner fixes:
10
+
11
+ - `outerlayer runner install` no longer moves a runner back to an older version. When the CLI you run is older than the version the runner updated itself to, the command refuses and names both versions. Run `~/.local/bin/outerlayer runner install` instead, which runs the newer version. Pass `--allow-downgrade` to install the older one on purpose. `runner install --service` and `runner init` refuse the same way.
12
+ - Housekeeping no longer logs an error when the runner's image builder has not started yet. It leaves the build cache for a later pass and logs that it did.
13
+ - A container build now sees only its own CPU cores: `runner.build.cpus`, rounded up. `nproc` inside the build reports that count, not the host's. Builds running at once get different cores while the host has enough. `runner.build.cpus` stays the limit.
14
+
15
+ - 857e376: Update the bundled `structured-headers` library from 2.0.3 to 2.1.0. The runner uses it to sign its requests to the gateway; signed requests are unchanged.
16
+
3
17
  ## 0.8.0
4
18
 
5
19
  ### Minor Changes
@@ -4,17 +4,17 @@ import { addStdioMcpEntryIfAbsent } from './chunk-MQ3IPHIZ.js';
4
4
  import { installStarterPack } from './chunk-M3SQ4YGD.js';
5
5
  import { runEmit } from './chunk-EV3M3EH7.js';
6
6
  import { C } from './chunk-YRYMNBGQ.js';
7
- import { resolveGitCommonDir, defaultGitRunner } from './chunk-5FWNEQNZ.js';
7
+ import { resolveGitCommonDir, defaultGitRunner } from './chunk-BQFNZOMQ.js';
8
8
  import './chunk-ZJSNLVCE.js';
9
9
  import { pinExists, readContextManifest } from './chunk-ZZXLM64C.js';
10
10
  import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-VXLJORHL.js';
11
11
  import { generatedHeaderSource } from './chunk-7ZR5UPMB.js';
12
- import './chunk-BCLJSQCV.js';
12
+ import './chunk-YO4PSLVB.js';
13
13
  import './chunk-BOLTI6LR.js';
14
14
  import './chunk-YNJEOGDL.js';
15
15
  import './chunk-EABW6AJQ.js';
16
16
  import './chunk-RA3O54FC.js';
17
- import './chunk-M5POMKKW.js';
17
+ import './chunk-V7NIVOFD.js';
18
18
  import './chunk-ZM2IMMYN.js';
19
19
  import './chunk-XCCLFVXM.js';
20
20
  import './chunk-BJ3KTMDH.js';
@@ -1 +1 @@
1
- {"id":"2026-10-05T12:31:55.812Z+ff35a38","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
1
+ {"id":"2026-10-05T15:51:32.122Z+87b226c","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { MIN_BUILDX_VERSION, builderName, builderSpec, buildxState, ensureBuilder, ensureFailureCount, isOutOfMemory, proxyEnvironment, trackImageBuild } from './chunk-5TNS3PL7.js';
3
+ export { MIN_BUILDX_VERSION, builderName, builderSpec, buildxState, ensureBuilder, ensureFailureCount, isOutOfMemory, proxyEnvironment, trackImageBuild } from './chunk-2BRSMBBB.js';
4
4
  import './chunk-CX22S5BA.js';
5
5
  import './chunk-GAYWY4GI.js';
6
6
  import './chunk-7RQ73DLO.js';
@@ -1,35 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { probeCredentials } from './chunk-IJBVPLZZ.js';
3
+ import { probeCredentials } from './chunk-5ODHQP6O.js';
4
4
  import './chunk-ABIWDUMS.js';
5
- import './chunk-7VNURP6M.js';
5
+ import './chunk-I2UOAV7X.js';
6
+ import './chunk-QB5JQH5V.js';
6
7
  import './chunk-T6OIJQRT.js';
7
8
  import './chunk-AIW6GLET.js';
8
9
  import './chunk-UGP76IZ5.js';
9
- import './chunk-3S4P55NE.js';
10
+ import './chunk-4FPWKV7L.js';
10
11
  import './chunk-WVGSB3Z2.js';
11
- import './chunk-AIL2R4SI.js';
12
+ import './chunk-BF4KKEFY.js';
12
13
  import './chunk-HHJDN6AU.js';
13
- import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-IRCBTGWF.js';
14
+ import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-Q4432IZT.js';
14
15
  import './chunk-TI7B7UEO.js';
15
16
  import './chunk-YYYRBYWG.js';
16
17
  import './chunk-TBT347UY.js';
17
- import './chunk-NALVDFIS.js';
18
- import './chunk-TUUMW4TC.js';
19
- import './chunk-CM5QTKM4.js';
18
+ import './chunk-Z2THOHPP.js';
19
+ import './chunk-QNRSFEGY.js';
20
+ import './chunk-M4ERCYDB.js';
20
21
  import './chunk-JKIWMRFH.js';
21
22
  import './chunk-TTNFGMHO.js';
22
23
  import './chunk-N5FOE5PS.js';
23
24
  import './chunk-OGFGZQA3.js';
24
- import './chunk-U3GOI2B4.js';
25
+ import './chunk-TEKZRTM3.js';
25
26
  import './chunk-QOZKPLVJ.js';
26
- import './chunk-5TNS3PL7.js';
27
+ import './chunk-2BRSMBBB.js';
27
28
  import './chunk-CX22S5BA.js';
28
29
  import './chunk-ZOAEPWGL.js';
29
30
  import './chunk-R7STSBLC.js';
30
31
  import './chunk-F7CU5ABH.js';
31
32
  import './chunk-BKO6JEZI.js';
32
- import './chunk-5QLNZGAQ.js';
33
+ import './chunk-KV47VQJZ.js';
33
34
  import './chunk-4ACZCY4I.js';
34
35
  import './chunk-BFESLKPP.js';
35
36
  import './chunk-ILEA3YHM.js';
@@ -46,19 +47,19 @@ import './chunk-HKMPVPO7.js';
46
47
  import './chunk-GQD22KKN.js';
47
48
  import './chunk-WZBHBH3J.js';
48
49
  import './chunk-5QRP3MVS.js';
49
- import './chunk-5FWNEQNZ.js';
50
+ import './chunk-BQFNZOMQ.js';
50
51
  import './chunk-ZJSNLVCE.js';
51
52
  import './chunk-ZZXLM64C.js';
52
53
  import './chunk-VXLJORHL.js';
53
54
  import './chunk-7ZR5UPMB.js';
54
- import './chunk-BCLJSQCV.js';
55
+ import './chunk-YO4PSLVB.js';
55
56
  import './chunk-BOLTI6LR.js';
56
57
  import './chunk-YNJEOGDL.js';
57
58
  import './chunk-EABW6AJQ.js';
58
59
  import './chunk-RA3O54FC.js';
59
- import './chunk-M5POMKKW.js';
60
+ import './chunk-V7NIVOFD.js';
60
61
  import './chunk-ZM2IMMYN.js';
61
- import './chunk-JPR2WHHF.js';
62
+ import './chunk-KSLNQOOS.js';
62
63
  import './chunk-XCCLFVXM.js';
63
64
  import './chunk-BJ3KTMDH.js';
64
65
  import './chunk-VNVZDWO3.js';
@@ -27,7 +27,7 @@ function runnerLabelValue(configPath) {
27
27
  return createHash("sha256").update(resolvedRunnerDir(configPath)).digest("hex").slice(0, 12);
28
28
  }
29
29
  function hardened(input) {
30
- const { memory, cpus, pids } = input.limits;
30
+ const { memory, cpus, pids, cpuset } = input.limits;
31
31
  return [
32
32
  "--label",
33
33
  `${BUILD_LABEL}=${input.buildId}`,
@@ -49,6 +49,7 @@ function hardened(input) {
49
49
  memory,
50
50
  "--cpus",
51
51
  String(cpus),
52
+ ...cpuset === void 0 ? [] : ["--cpuset-cpus", cpuset],
52
53
  "--pids-limit",
53
54
  String(pids)
54
55
  ];
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LiveUploader } from './chunk-AIL2R4SI.js';
3
+ import { LiveUploader } from './chunk-BF4KKEFY.js';
4
4
  import { CaptureDaemon } from './chunk-GAYWY4GI.js';
5
5
  import { parseWorkItemEnv } from './chunk-GQD22KKN.js';
6
- import { spoolDir } from './chunk-JPR2WHHF.js';
6
+ import { spoolDir } from './chunk-KSLNQOOS.js';
7
7
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
8
8
  import { mkdirSync, writeFileSync, rmSync } from 'fs';
9
9
  import { join } from 'path';
@@ -1,26 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
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';
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-QB5JQH5V.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 { placeholderQueues, placeholderProblem } from './chunk-Q4432IZT.js';
9
10
  import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, 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-M4ERCYDB.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';
16
+ import { spawnRun } from './chunk-TEKZRTM3.js';
17
+ import { builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, BUILD_LABEL, RUNNER_LABEL } from './chunk-2BRSMBBB.js';
18
+ import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-KV47VQJZ.js';
18
19
  import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-PWBILI5P.js';
19
20
  import { exceedsDisk } from './chunk-7RQ73DLO.js';
20
21
  import { sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-OD2VTIHN.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
  }
@@ -1306,7 +1189,7 @@ var CLAIM_REFUSAL_CODES = new Set(
1306
1189
  "pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous branch_claimed_elsewhere".split(" ")
1307
1190
  );
1308
1191
  async function tryClaimAndStart(state, item, queue) {
1309
- const { postJson: postJson2 } = await import('./work-cmd-B3FOXZAL.js');
1192
+ const { postJson: postJson2 } = await import('./work-cmd-CNWPTH7W.js');
1310
1193
  const log = logOf(state);
1311
1194
  const hostKey = await loadHostKey(state.config.configPath);
1312
1195
  const claim = await retrySend(
@@ -2030,7 +1913,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
2030
1913
  const outcome = await onStartUnderMarker({
2031
1914
  configPath,
2032
1915
  own: ownVersionOf(deps),
2033
- check: update.check ? () => update.check(configPath) : async () => (await import('./check-FOF3PUKI.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
1916
+ check: update.check ? () => update.check(configPath) : async () => (await import('./check-GX5ND6RO.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
2034
1917
  now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
2035
1918
  log
2036
1919
  });
@@ -2072,6 +1955,8 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
2072
1955
  const adopted = { job, dirPath, lastRenewAtMs: nowMs(), cmd: null, cpuSample: null, ending: false };
2073
1956
  state.jobs.set(dirPath, adopted);
2074
1957
  if (job.container !== void 0) {
1958
+ const cores = job.container.cpuset === void 0 ? void 0 : parseCpuList(job.container.cpuset);
1959
+ if (cores !== void 0) runtimeOf(state).cpus.hold(job.container.buildId, cores);
2075
1960
  const tokens = buildTokensFor(state, adopted, job.item);
2076
1961
  runtimeOf(state).credentials.set(dirPath, tokens);
2077
1962
  await ensureTunnel(runtimeOf(state), job.container, dirPath, config, job.itemKey, job.branch);
@@ -9,12 +9,12 @@ import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo
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';
12
+ import { defaultFetch } from './chunk-YO4PSLVB.js';
13
13
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.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-KSLNQOOS.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';
@@ -4,7 +4,7 @@ import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
4
4
  import { readPin, pinExists, readBuildHold, readContextManifest, manifestFilesPresent, writeDegraded, writeSourceCache, SOURCE_CACHE_TTL_RETRY_MS, SOURCE_CACHE_TTL_SUCCESS_MS, isLastCheckFresh, readDegraded, touchLastCheck, clearDegraded, writeContextManifest, writePinIfChanged, readSourceCache, isSourceCacheFresh } from './chunk-ZZXLM64C.js';
5
5
  import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-VXLJORHL.js';
6
6
  import { parseGoverns, normalizeRepoName, CONTEXT_SOURCE_CONFIG_PATH, parseOuterlayerConfig, classifyTree, emitTree } from './chunk-7ZR5UPMB.js';
7
- import { defaultFetch } from './chunk-BCLJSQCV.js';
7
+ import { defaultFetch } from './chunk-YO4PSLVB.js';
8
8
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
9
9
  import { ensureContextExcludes, ensurePreCommitGuardHook } from './chunk-XCCLFVXM.js';
10
10
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { readStatuslineState, STATE_FRESH_MS } from './chunk-F47JBIAW.js';
4
- import { resolveCredentials, getJson, WorkCommandError } from './chunk-5QLNZGAQ.js';
4
+ import { resolveCredentials, getJson, WorkCommandError } from './chunk-KV47VQJZ.js';
5
5
  import { isLinkedRepository } from './chunk-ILEA3YHM.js';
6
6
  import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
7
7
  import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-GAYWY4GI.js';
8
8
  import { C } from './chunk-YRYMNBGQ.js';
9
9
  import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-5QRP3MVS.js';
10
10
  import { readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-ZZXLM64C.js';
11
- import { defaultFetch } from './chunk-BCLJSQCV.js';
11
+ import { defaultFetch } from './chunk-YO4PSLVB.js';
12
12
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
13
13
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
14
- import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-JPR2WHHF.js';
14
+ import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-KSLNQOOS.js';
15
15
  import { deadHooksState, preparePackageManagerCommand, contextExcludesPresent } from './chunk-XCCLFVXM.js';
16
16
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
17
17
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1016,7 +1016,7 @@ async function gatherDoctorChecks() {
1016
1016
  const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
1017
1017
  checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
1018
1018
  } else if (hasRunnerBlock(configPath)) {
1019
- const { runnerHostChecks } = await import('./doctor-WR6TRPSU.js');
1019
+ const { runnerHostChecks } = await import('./doctor-KALLPCRB.js');
1020
1020
  const hooks = (() => {
1021
1021
  try {
1022
1022
  return loadRunnerConfig(configPath).hooks;
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/runner/update/version-order.ts
7
+ function parse(version) {
8
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version);
9
+ if (match === null) return void 0;
10
+ return { core: [Number(match[1]), Number(match[2]), Number(match[3])], pre: match[4] };
11
+ }
12
+ function comparePre(a, b) {
13
+ const left = a.split(".");
14
+ const right = b.split(".");
15
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
16
+ const x = left[i];
17
+ const y = right[i];
18
+ if (x === void 0) return -1;
19
+ if (y === void 0) return 1;
20
+ const xNum = /^\d+$/.test(x);
21
+ const yNum = /^\d+$/.test(y);
22
+ if (xNum && yNum) {
23
+ const difference = Number(x) - Number(y);
24
+ if (difference !== 0) return Math.sign(difference);
25
+ } else if (xNum !== yNum) {
26
+ return xNum ? -1 : 1;
27
+ } else if (x < y) {
28
+ return -1;
29
+ } else if (x > y) {
30
+ return 1;
31
+ }
32
+ }
33
+ return 0;
34
+ }
35
+ function compareVersions(a, b) {
36
+ const left = parse(a);
37
+ const right = parse(b);
38
+ if (left === void 0 || right === void 0) return void 0;
39
+ for (let i = 0; i < 3; i++) {
40
+ const difference = left.core[i] - right.core[i];
41
+ if (difference !== 0) return Math.sign(difference);
42
+ }
43
+ if (left.pre === right.pre) return 0;
44
+ if (left.pre === void 0) return 1;
45
+ if (right.pre === void 0) return -1;
46
+ return comparePre(left.pre, right.pre);
47
+ }
48
+ function compareCores(a, b) {
49
+ for (let i = 0; i < 3; i++) {
50
+ const difference = a[i] - b[i];
51
+ if (difference !== 0) return Math.sign(difference);
52
+ }
53
+ return 0;
54
+ }
55
+ function parsePartial(text) {
56
+ if (text === "" || text === "*" || text === "x" || text === "X") return [];
57
+ const match = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?$/.exec(text);
58
+ if (match === null) return void 0;
59
+ const numbers = [];
60
+ for (const part of [match[1], match[2], match[3]]) {
61
+ if (part === void 0 || !/^\d+$/.test(part)) break;
62
+ numbers.push(Number(part));
63
+ }
64
+ return numbers;
65
+ }
66
+ function bumpLast(numbers) {
67
+ const core = [numbers[0] ?? 0, numbers[1] ?? 0, numbers[2] ?? 0];
68
+ const last = numbers.length - 1;
69
+ core[last] = core[last] + 1;
70
+ for (let i = last + 1; i < 3; i++) core[i] = 0;
71
+ return core;
72
+ }
73
+ function fill(numbers) {
74
+ return [numbers[0] ?? 0, numbers[1] ?? 0, numbers[2] ?? 0];
75
+ }
76
+ function meets(version, comparator) {
77
+ const match = /^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(comparator);
78
+ const op = match[1] ?? "";
79
+ const numbers = parsePartial(match[2]);
80
+ if (numbers === void 0) return void 0;
81
+ if (numbers.length === 0) return op === "" || op === "=" || op === ">=" || op === "<=" ? true : void 0;
82
+ const low = fill(numbers);
83
+ const whole = numbers.length === 3;
84
+ switch (op) {
85
+ case ">=":
86
+ return compareCores(version, low) >= 0;
87
+ case ">":
88
+ return whole ? compareCores(version, low) > 0 : compareCores(version, bumpLast(numbers)) >= 0;
89
+ case "<":
90
+ return compareCores(version, low) < 0;
91
+ case "<=":
92
+ return whole ? compareCores(version, low) <= 0 : compareCores(version, bumpLast(numbers)) < 0;
93
+ case "~":
94
+ return compareCores(version, low) >= 0 && compareCores(version, bumpLast(numbers.slice(0, Math.min(numbers.length, 2)))) < 0;
95
+ case "^": {
96
+ let pivot = numbers.findIndex((n) => n !== 0);
97
+ if (pivot === -1) pivot = numbers.length - 1;
98
+ return compareCores(version, low) >= 0 && compareCores(version, bumpLast(numbers.slice(0, pivot + 1))) < 0;
99
+ }
100
+ default:
101
+ return compareCores(version, low) >= 0 && (whole ? compareCores(version, low) <= 0 : compareCores(version, bumpLast(numbers)) < 0);
102
+ }
103
+ }
104
+ function satisfiesRange(version, range) {
105
+ const parsed = parse(version.trim().replace(/^v/, ""));
106
+ if (parsed === void 0 || parsed.pre !== void 0) return void 0;
107
+ let anyUnreadable = false;
108
+ for (const alternative of range.split("||")) {
109
+ if (/\s-\s/.test(alternative)) {
110
+ anyUnreadable = true;
111
+ continue;
112
+ }
113
+ const comparators = alternative.trim().replace(/(>=|<=|>|<|=|\^|~)\s+/g, "$1").split(/\s+/).filter((c) => c !== "");
114
+ if (comparators.length === 0) comparators.push("*");
115
+ let all = true;
116
+ for (const comparator of comparators) {
117
+ const met = meets(parsed.core, comparator);
118
+ if (met === void 0) {
119
+ anyUnreadable = true;
120
+ all = false;
121
+ break;
122
+ }
123
+ if (!met) {
124
+ all = false;
125
+ break;
126
+ }
127
+ }
128
+ if (all) return true;
129
+ }
130
+ return anyUnreadable ? void 0 : false;
131
+ }
132
+
133
+ export { compareVersions, satisfiesRange };
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { writeLauncher, LauncherWriteError, pathNotes, launcherPath } from './chunk-PTW6W5NR.js';
4
- import { isInLayout, packageRootIn, versionDir, switchCurrent, currentLink, execStartLine } from './chunk-TI7B7UEO.js';
3
+ import { compareVersions } from './chunk-I2UOAV7X.js';
4
+ import { launcherPath, writeLauncher, LauncherWriteError, pathNotes } from './chunk-PTW6W5NR.js';
5
+ import { currentVersion, currentLink, isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-TI7B7UEO.js';
5
6
  import { RUNNER_DIR_MODE } from './chunk-ZM2IMMYN.js';
6
7
  import { realpathSync, readFileSync, mkdirSync, rmSync, cpSync, existsSync } from 'fs';
7
8
  import { dirname, sep, join } from 'path';
@@ -9,6 +10,8 @@ import { dirname, sep, join } from 'path';
9
10
  createRequire(import.meta.url);
10
11
  var RunnerInstallError = class extends Error {
11
12
  };
13
+ var RunnerDowngradeError = class extends RunnerInstallError {
14
+ };
12
15
  function runRunnerInstall(args) {
13
16
  const { configPath, nodePath } = args;
14
17
  let entry;
@@ -32,6 +35,13 @@ function runRunnerInstall(args) {
32
35
  if (manifest.name !== "@outerlayer/cli") throw new RunnerInstallError(`${packageRoot} is not the @outerlayer/cli package`);
33
36
  const version = manifest.version;
34
37
  if (typeof version !== "string" || version === "") throw new RunnerInstallError(`${packageRoot}/package.json has no version`);
38
+ const installed = currentVersion(configPath);
39
+ if (args.allowDowngrade !== true && installed !== void 0 && (compareVersions(version, installed) ?? 0) < 0) {
40
+ const command = args.command ?? "runner install";
41
+ throw new RunnerDowngradeError(
42
+ `this CLI is ${version}, older than ${installed}, the version the runner runs from ${currentLink(configPath)}. Installing it would move the runner back to ${version}. Run \`${launcherPath(args.home)} ${command}\` instead, which runs ${installed}. To install ${version} anyway, run \`outerlayer ${command} --allow-downgrade\``
43
+ );
44
+ }
35
45
  if (!isInLayout(configPath, entry) && !sameBuildInstalled(packageRoot, packageRootIn(versionDir(configPath, version)))) {
36
46
  const target = packageRootIn(versionDir(configPath, version));
37
47
  mkdirSync(dirname(target), { recursive: true, mode: RUNNER_DIR_MODE });
@@ -80,4 +90,4 @@ function launcherSummary(launcher) {
80
90
  return `${launcher.state === "unchanged" ? "outerlayer command already at" : "wrote the outerlayer command at"} ${launcher.path}, which runs the CLI that ${launcher.follows} names`;
81
91
  }
82
92
 
83
- export { RunnerInstallError, launcherSummary, runRunnerInstall };
93
+ export { RunnerDowngradeError, RunnerInstallError, launcherSummary, runRunnerInstall };
@@ -628,7 +628,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
628
628
  recordHookErrorsSeen(home, hookErrorsBytes);
629
629
  if (contextPossiblyGoverned(sessionCwd, home)) {
630
630
  try {
631
- const { materializeContext: materialize } = await import('./context-materialize-QL33HDJN.js');
631
+ const { materializeContext: materialize } = await import('./context-materialize-4PMTDS6K.js');
632
632
  const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
633
633
  const result = await materialize({ cwd: sessionCwd, sessionId, home });
634
634
  materializeMessage = result.message;