@outerlayer/cli 0.7.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 (74) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +5 -5
  3. package/dist/{agent-setup-TXLDY5RV.js → agent-setup-K6RD2Z4P.js} +4 -4
  4. package/dist/{build-JF5UOWKJ.js → build-MS34XEGN.js} +2 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/builder-IG6FNA54.js +13 -0
  7. package/dist/{check-ASZL5BEO.js → check-GX5ND6RO.js} +26 -22
  8. package/dist/chunk-2BRSMBBB.js +264 -0
  9. package/dist/{chunk-PUN7LMNS.js → chunk-4ACZCY4I.js} +2 -2
  10. package/dist/{chunk-2VO25HHO.js → chunk-4FPWKV7L.js} +3 -3
  11. package/dist/{chunk-AII7CKTH.js → chunk-5ODHQP6O.js} +68 -145
  12. package/dist/chunk-7RQ73DLO.js +23 -0
  13. package/dist/{chunk-7FTNIAHS.js → chunk-AX23QKHS.js} +7 -3
  14. package/dist/{chunk-6ZZHWY2Z.js → chunk-BF4KKEFY.js} +4 -4
  15. package/dist/{chunk-5FWNEQNZ.js → chunk-BQFNZOMQ.js} +1 -1
  16. package/dist/chunk-CX22S5BA.js +45 -0
  17. package/dist/{chunk-D6FXM5OW.js → chunk-GAYWY4GI.js} +8 -8
  18. package/dist/{chunk-MQPRB5K7.js → chunk-HSN5QNS5.js} +8 -8
  19. package/dist/chunk-I2UOAV7X.js +133 -0
  20. package/dist/chunk-I7CJIRMM.js +93 -0
  21. package/dist/{chunk-SSU747O6.js → chunk-ILEA3YHM.js} +1 -1
  22. package/dist/{chunk-OUUINEYB.js → chunk-JKIWMRFH.js} +1 -1
  23. package/dist/{chunk-JPR2WHHF.js → chunk-KSLNQOOS.js} +1 -1
  24. package/dist/{chunk-DGAIVMMN.js → chunk-KV47VQJZ.js} +5 -5
  25. package/dist/{chunk-E4PIFIC3.js → chunk-M4ERCYDB.js} +133 -159
  26. package/dist/chunk-PTW6W5NR.js +127 -0
  27. package/dist/{chunk-DTXOJDEH.js → chunk-PWBILI5P.js} +3 -2
  28. package/dist/{chunk-X2FSFU4C.js → chunk-PXFEYBDE.js} +3 -3
  29. package/dist/{chunk-6IYLDODX.js → chunk-Q4432IZT.js} +5 -5
  30. package/dist/{chunk-AJKEHABI.js → chunk-QB5JQH5V.js} +255 -54
  31. package/dist/{chunk-AQ54MKSQ.js → chunk-QNRSFEGY.js} +2 -2
  32. package/dist/{chunk-774HEQL6.js → chunk-TEKZRTM3.js} +91 -8
  33. package/dist/{chunk-CEBIA5FD.js → chunk-TTNFGMHO.js} +42 -50
  34. package/dist/{chunk-F6GFZXZ3.js → chunk-UXYLWVTQ.js} +1 -18
  35. package/dist/{chunk-M5POMKKW.js → chunk-V7NIVOFD.js} +5 -5
  36. package/dist/{chunk-BCLJSQCV.js → chunk-YO4PSLVB.js} +1 -1
  37. package/dist/{chunk-6QWV3YDJ.js → chunk-Z2THOHPP.js} +2 -2
  38. package/dist/{cli-LEVCGAQV.js → cli-X5ONGYNY.js} +128 -78
  39. package/dist/{command-FLSYCGIB.js → command-7NFU3IPO.js} +38 -20
  40. package/dist/{config-I3TVFYLH.js → config-Z3USDBLU.js} +3 -2
  41. package/dist/{connect-cmd-MJMUONDY.js → connect-cmd-PNZ6IJLJ.js} +2 -2
  42. package/dist/{context-adopt-CE4KDXS3.js → context-adopt-D2Z7F7PB.js} +3 -3
  43. package/dist/{context-materialize-QL33HDJN.js → context-materialize-4PMTDS6K.js} +3 -3
  44. package/dist/{dist-PXBSA7QX.js → dist-3ZTZF2TP.js} +1 -1
  45. package/dist/docker-PRHRSJM5.js +15 -0
  46. package/dist/{doctor-FVDT3KJZ.js → doctor-KALLPCRB.js} +39 -16
  47. package/dist/{emit-artifact-cmd-7RPMRSVP.js → emit-artifact-cmd-D5GMVWNC.js} +7 -7
  48. package/dist/{emit-criteria-cmd-MKI7WETO.js → emit-criteria-cmd-IE7VIM64.js} +5 -5
  49. package/dist/{emit-finding-cmd-RMLGZASB.js → emit-finding-cmd-46PTPN3A.js} +5 -5
  50. package/dist/{emit-result-cmd-MTXAZ2GV.js → emit-result-cmd-KXHHP6HX.js} +7 -7
  51. package/dist/{hook-fast-XBOZ3N6L.js → hook-fast-5H5QBJKT.js} +1 -1
  52. package/dist/{host-key-KDYZ5ECC.js → host-key-YMLXY6QB.js} +1 -1
  53. package/dist/index.js +3 -3
  54. package/dist/{init-VLW7H6RW.js → init-B4CECVOX.js} +25 -18
  55. package/dist/{init-BACXESVV.js → init-S4DH6PWW.js} +16 -13
  56. package/dist/{init-cmd-VJFB5L7X.js → init-cmd-P4MVCBCZ.js} +8 -8
  57. package/dist/{install-NMAPLLBQ.js → install-FHTVJZS6.js} +5 -4
  58. package/dist/{install-cmd-B5SEU3G7.js → install-cmd-BEC7XTNG.js} +3 -1
  59. package/dist/{loop-D3243JKT.js → loop-ODMRE3CW.js} +26 -22
  60. package/dist/{machine-EB3GEVI4.js → machine-J4SAB3Z2.js} +15 -12
  61. package/dist/{mcp-serve-cmd-N6UD2KBX.js → mcp-serve-cmd-CT47P4YQ.js} +2 -2
  62. package/dist/{session-sender-LMACEJJS.js → session-sender-V46VPWQ5.js} +6 -6
  63. package/dist/{status-F4THTJJK.js → status-QBKSH3QE.js} +19 -16
  64. package/dist/{sync-cmd-M6JA3OEE.js → sync-cmd-RJR77V4O.js} +5 -5
  65. package/dist/{watch-NB5TGPEZ.js → watch-YNZTFLEY.js} +5 -5
  66. package/dist/{work-claim-cmd-UHMWOS3G.js → work-claim-cmd-KAD3ZAH7.js} +10 -9
  67. package/dist/{work-cmd-6UMCFTAW.js → work-cmd-CNWPTH7W.js} +6 -6
  68. package/dist/{work-comment-cmd-E4LEUIXZ.js → work-comment-cmd-HH45S6UE.js} +6 -6
  69. package/dist/{work-open-pr-cmd-OPZWGSEQ.js → work-open-pr-cmd-5KR3KFCN.js} +7 -7
  70. package/dist/{work-pr-cmd-IDIAFFRU.js → work-pr-cmd-TTEGCP76.js} +6 -6
  71. package/package.json +2 -2
  72. package/skill-pack/maintained/amend/SKILL.md +22 -6
  73. package/dist/chunk-Q5G2ODUZ.js +0 -54
  74. package/dist/docker-NEGDLU6D.js +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
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
+
17
+ ## 0.8.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 8da1a39: The runner now builds every image in a Buildx builder of its own, whose container has a memory limit of `runner.build.memory`. A recipe step that uses more memory is stopped, and the build is released failed at provision with a reason that names the limit. Hosts need Docker's Buildx plugin (`docker-buildx-plugin`, version 0.18 or later); a host without it claims no work, and `outerlayer doctor` fails an "Image build limit" check that names the package. Housekeeping now trims the runner's builder cache, not Docker's default builder.
22
+
23
+ `outerlayer runner install`, `runner install --service` and `runner init` also write `~/.local/bin/outerlayer`, a launcher that runs the CLI in the runner's `current` link, so the command on PATH follows a self-update. `runner install --replace` replaces a launcher file the runner did not write.
24
+
25
+ ### Patch Changes
26
+
27
+ - 983c221: A build whose clone fails now says why: the release reason ends with the fatal or error line git printed, not only its exit status.
28
+ - 5a7ca29: The README now says the `OuterLayer evidence` check on GitHub completes once the automated checks pass, without waiting for a person's review in OuterLayer. It also gives the `review` policy key's default correctly as `required`.
29
+ - 628c6c9: A `builtin:vm` build's host checks now run in a new microVM booted from the build's image, where they used to always fail.
30
+ - c2a0315: `outerlayer runner init --vm` sizes the VM's disk with room for the free-disk minimum and the Docker build cache, so the runner in the VM keeps claiming work once its disk fills. With the default limits the disk is 90 GiB, allocated as it is used.
31
+ - 983c221: On WSL2, `outerlayer runner install --service` makes no scheduled task when `WSL_DISTRO_NAME` is unset, as under `sudo`, and prints the `schtasks` command to run instead. It no longer guesses `Ubuntu`, which made a task that started nothing.
32
+
3
33
  ## 0.7.0
4
34
 
5
35
  ### Minor Changes
package/README.md CHANGED
@@ -413,11 +413,11 @@ pass or fail on an item that is closed or shipped, has no evaluation yet,
413
413
  or whose evaluation is still waiting on a session link, with the code
414
414
  `not_reviewable`. A recorded pass on the general thread carries the head
415
415
  commit of every pull request the item had at the time; once one of them
416
- moves, that pass stops counting and a fresh review is needed. A repository
417
- can require a current pass before the evidence check completes by setting
418
- the base branch's `review` policy key to `required` (default `optional`,
419
- alongside `merge_gate`) — the check then stays in progress, not failed,
420
- until a current pass exists.
416
+ moves, that pass stops counting and a fresh review is needed. The base
417
+ branch's `review` policy key (default `required`, beside `merge_gate`)
418
+ holds the item at "Awaiting a person's review" until a current pass
419
+ exists. The evidence check on GitHub does not wait for that review: it
420
+ completes once the automated checks pass and says the review is pending.
421
421
 
422
422
  A criterion thread is scoped to one acceptance criterion rather than the
423
423
  whole item: an agent attaches proof with `outerlayer work comment
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { addStdioMcpEntryIfAbsent } from './chunk-MQ3IPHIZ.js';
3
4
  import { installStarterPack } from './chunk-M3SQ4YGD.js';
4
5
  import { runEmit } from './chunk-EV3M3EH7.js';
5
- import { addStdioMcpEntryIfAbsent } from './chunk-MQ3IPHIZ.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,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { buildRepositoryImage } from './chunk-CEBIA5FD.js';
3
+ export { buildRepositoryImage } from './chunk-TTNFGMHO.js';
4
4
  import './chunk-N5FOE5PS.js';
5
5
  export { RecipeError } from './chunk-QOZKPLVJ.js';
6
+ import './chunk-CX22S5BA.js';
6
7
  import './chunk-HKMPVPO7.js';
7
8
  import './chunk-ZM2IMMYN.js';
8
9
  import './chunk-Z5GEFMRW.js';
@@ -1 +1 @@
1
- {"id":"2026-10-05T00:52:06.865Z+90312df","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"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ export { MIN_BUILDX_VERSION, builderName, builderSpec, buildxState, ensureBuilder, ensureFailureCount, isOutOfMemory, proxyEnvironment, trackImageBuild } from './chunk-2BRSMBBB.js';
4
+ import './chunk-CX22S5BA.js';
5
+ import './chunk-GAYWY4GI.js';
6
+ import './chunk-7RQ73DLO.js';
7
+ import './chunk-OD2VTIHN.js';
8
+ import './chunk-HKMPVPO7.js';
9
+ import './chunk-YNJEOGDL.js';
10
+ import './chunk-ZM2IMMYN.js';
11
+ import './chunk-Z5GEFMRW.js';
12
+
13
+ createRequire(import.meta.url);
@@ -1,61 +1,65 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { probeCredentials } from './chunk-AII7CKTH.js';
3
+ import { probeCredentials } from './chunk-5ODHQP6O.js';
4
4
  import './chunk-ABIWDUMS.js';
5
- import './chunk-TI7B7UEO.js';
6
- import './chunk-AJKEHABI.js';
5
+ import './chunk-I2UOAV7X.js';
6
+ import './chunk-QB5JQH5V.js';
7
7
  import './chunk-T6OIJQRT.js';
8
8
  import './chunk-AIW6GLET.js';
9
9
  import './chunk-UGP76IZ5.js';
10
- import './chunk-2VO25HHO.js';
10
+ import './chunk-4FPWKV7L.js';
11
11
  import './chunk-WVGSB3Z2.js';
12
- import './chunk-6ZZHWY2Z.js';
12
+ import './chunk-BF4KKEFY.js';
13
13
  import './chunk-HHJDN6AU.js';
14
- import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-6IYLDODX.js';
14
+ import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-Q4432IZT.js';
15
+ import './chunk-TI7B7UEO.js';
15
16
  import './chunk-YYYRBYWG.js';
16
17
  import './chunk-TBT347UY.js';
17
- import './chunk-6QWV3YDJ.js';
18
- import './chunk-OUUINEYB.js';
19
- import './chunk-AQ54MKSQ.js';
20
- import './chunk-E4PIFIC3.js';
21
- import './chunk-CEBIA5FD.js';
18
+ import './chunk-Z2THOHPP.js';
19
+ import './chunk-QNRSFEGY.js';
20
+ import './chunk-M4ERCYDB.js';
21
+ import './chunk-JKIWMRFH.js';
22
+ import './chunk-TTNFGMHO.js';
22
23
  import './chunk-N5FOE5PS.js';
23
24
  import './chunk-OGFGZQA3.js';
24
- import './chunk-774HEQL6.js';
25
+ import './chunk-TEKZRTM3.js';
25
26
  import './chunk-QOZKPLVJ.js';
27
+ import './chunk-2BRSMBBB.js';
28
+ import './chunk-CX22S5BA.js';
26
29
  import './chunk-ZOAEPWGL.js';
27
30
  import './chunk-R7STSBLC.js';
28
31
  import './chunk-F7CU5ABH.js';
29
32
  import './chunk-BKO6JEZI.js';
30
- import './chunk-DGAIVMMN.js';
31
- import './chunk-PUN7LMNS.js';
33
+ import './chunk-KV47VQJZ.js';
34
+ import './chunk-4ACZCY4I.js';
32
35
  import './chunk-BFESLKPP.js';
33
- import './chunk-SSU747O6.js';
36
+ import './chunk-ILEA3YHM.js';
34
37
  import './chunk-ZYHKJKSU.js';
35
- import './chunk-D6FXM5OW.js';
38
+ import './chunk-GAYWY4GI.js';
36
39
  import './chunk-USO2DKBD.js';
37
40
  import './chunk-N6LURUEF.js';
38
41
  import './chunk-YRYMNBGQ.js';
39
- import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-DTXOJDEH.js';
40
- import './chunk-F6GFZXZ3.js';
42
+ import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-PWBILI5P.js';
43
+ import './chunk-UXYLWVTQ.js';
44
+ import './chunk-7RQ73DLO.js';
41
45
  import './chunk-OD2VTIHN.js';
42
46
  import './chunk-HKMPVPO7.js';
43
47
  import './chunk-GQD22KKN.js';
44
48
  import './chunk-WZBHBH3J.js';
45
49
  import './chunk-5QRP3MVS.js';
46
- import './chunk-5FWNEQNZ.js';
50
+ import './chunk-BQFNZOMQ.js';
47
51
  import './chunk-ZJSNLVCE.js';
48
52
  import './chunk-ZZXLM64C.js';
49
53
  import './chunk-VXLJORHL.js';
50
54
  import './chunk-7ZR5UPMB.js';
51
- import './chunk-BCLJSQCV.js';
55
+ import './chunk-YO4PSLVB.js';
52
56
  import './chunk-BOLTI6LR.js';
53
57
  import './chunk-YNJEOGDL.js';
54
58
  import './chunk-EABW6AJQ.js';
55
59
  import './chunk-RA3O54FC.js';
56
- import './chunk-M5POMKKW.js';
60
+ import './chunk-V7NIVOFD.js';
57
61
  import './chunk-ZM2IMMYN.js';
58
- import './chunk-JPR2WHHF.js';
62
+ import './chunk-KSLNQOOS.js';
59
63
  import './chunk-XCCLFVXM.js';
60
64
  import './chunk-BJ3KTMDH.js';
61
65
  import './chunk-VNVZDWO3.js';
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { BUILDKIT_IMAGE } from './chunk-CX22S5BA.js';
4
+ import { compareVersions } from './chunk-GAYWY4GI.js';
5
+ import { parseSize } from './chunk-7RQ73DLO.js';
6
+ import { JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_PORT, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-OD2VTIHN.js';
7
+ import { runnerDir } from './chunk-ZM2IMMYN.js';
8
+ import { createHash } from 'crypto';
9
+ import { realpathSync } from 'fs';
10
+ import { join, dirname, resolve } from 'path';
11
+
12
+ createRequire(import.meta.url);
13
+ var BUILD_LABEL = "ai.outerlayer.build";
14
+ var RUNNER_LABEL = "ai.outerlayer.runner";
15
+ function resolvedRunnerDir(configPath) {
16
+ try {
17
+ return realpathSync(runnerDir(configPath));
18
+ } catch {
19
+ try {
20
+ return join(realpathSync(dirname(resolve(configPath))), "runner");
21
+ } catch {
22
+ return resolve(runnerDir(configPath));
23
+ }
24
+ }
25
+ }
26
+ function runnerLabelValue(configPath) {
27
+ return createHash("sha256").update(resolvedRunnerDir(configPath)).digest("hex").slice(0, 12);
28
+ }
29
+ function hardened(input) {
30
+ const { memory, cpus, pids, cpuset } = input.limits;
31
+ return [
32
+ "--label",
33
+ `${BUILD_LABEL}=${input.buildId}`,
34
+ "--label",
35
+ `${RUNNER_LABEL}=${input.runnerId}`,
36
+ "--network",
37
+ "none",
38
+ "--cap-drop",
39
+ "ALL",
40
+ "--security-opt",
41
+ "no-new-privileges",
42
+ "--read-only",
43
+ "--user",
44
+ input.user,
45
+ // The same figure for swap as for memory leaves the container none.
46
+ "--memory",
47
+ memory,
48
+ "--memory-swap",
49
+ memory,
50
+ "--cpus",
51
+ String(cpus),
52
+ ...cpuset === void 0 ? [] : ["--cpuset-cpus", cpuset],
53
+ "--pids-limit",
54
+ String(pids)
55
+ ];
56
+ }
57
+ function mountPath(path) {
58
+ if (/[",]/.test(path)) throw new Error(`${path} holds a comma or a quote, which a Docker mount cannot carry; move the runner's config file`);
59
+ return path;
60
+ }
61
+ function containerRunArgs(input) {
62
+ return [
63
+ "--detach",
64
+ "--name",
65
+ input.container,
66
+ ...hardened(input),
67
+ "--mount",
68
+ `type=volume,src=${input.volume},dst=/build`,
69
+ // `/tmp` is a directory of the same volume, so it is measured and limited with the rest of the build.
70
+ "--mount",
71
+ `type=volume,src=${input.volume},dst=/tmp,volume-subpath=tmp`,
72
+ "--mount",
73
+ `type=bind,src=${mountPath(input.buildDir)},dst=${JOB_MOUNT},readonly`,
74
+ "--entrypoint",
75
+ "/opt/outerlayer/bin/tini",
76
+ input.image,
77
+ "--",
78
+ "/opt/outerlayer/bin/node",
79
+ "/opt/outerlayer/cli/dist/index.js",
80
+ "broker-relay",
81
+ "--port",
82
+ String(RELAY_PORT),
83
+ "--socket",
84
+ `${JOB_MOUNT}/tunnel.sock`,
85
+ ...Array.from({ length: input.destinations ?? 0 }, (_unused, index) => [
86
+ "--forward",
87
+ `${DESTINATION_BASE_PORT + index}=${JOB_MOUNT}/dest-${index}.sock`
88
+ ]).flat(),
89
+ ...input.builtIns === true ? [
90
+ "--forward",
91
+ `${GATEWAY_PORT}=${JOB_MOUNT}/${GATEWAY_SOCKET}`,
92
+ "--forward",
93
+ `${CLAUDE_PORT}=${JOB_MOUNT}/${CLAUDE_SOCKET}`
94
+ ] : []
95
+ ];
96
+ }
97
+ function prepareRunArgs(input) {
98
+ return [
99
+ "--rm",
100
+ ...hardened(input),
101
+ "--mount",
102
+ `type=volume,src=${input.volume},dst=/build`,
103
+ "--entrypoint",
104
+ "mkdir",
105
+ input.image,
106
+ "-p",
107
+ "-m",
108
+ "1777",
109
+ "/build/tmp",
110
+ "/build/home",
111
+ "/build/work"
112
+ ];
113
+ }
114
+ function containerExecArgs(input) {
115
+ const literals = Object.keys(input.env.literals).sort().flatMap((name) => ["-e", `${name}=${input.env.literals[name]}`]);
116
+ const passed = Object.keys(input.env.passed).filter((name) => input.env.passed[name] !== void 0).sort().flatMap((name) => ["-e", name]);
117
+ return [
118
+ "-u",
119
+ input.user,
120
+ ...input.workdir === void 0 ? [] : ["-w", input.workdir],
121
+ ...literals,
122
+ ...passed,
123
+ input.container,
124
+ ...input.argv
125
+ ];
126
+ }
127
+
128
+ // src/runner/image/builder.ts
129
+ var MIN_BUILDX_VERSION = "0.18.0";
130
+ var INSTALL_HINT = "install Docker's Buildx plugin (docker-buildx-plugin on Debian and Ubuntu with Docker's apt repository, docker-buildx on Ubuntu's own packages)";
131
+ function builderName(configPath) {
132
+ return `outerlayer-${runnerLabelValue(configPath)}`;
133
+ }
134
+ function proxyEnvironment(env) {
135
+ const found = {};
136
+ for (const name of ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy"]) {
137
+ const value = env[name];
138
+ if (value !== void 0 && value !== "") found[name] = value;
139
+ }
140
+ return found;
141
+ }
142
+ function builderSpec(configPath, memory, env) {
143
+ return { name: builderName(configPath), memory, env: proxyEnvironment(env) };
144
+ }
145
+ function driverOpt(pair) {
146
+ return /[",]/.test(pair) ? `"${pair.replace(/"/g, '""')}"` : pair;
147
+ }
148
+ async function buildxState(run) {
149
+ const result = await run("docker", ["buildx", "version"]);
150
+ if (result.status !== 0) {
151
+ const said = (result.stderr.trim() || result.stdout.trim()).split("\n")[0] ?? "";
152
+ return { problem: `docker buildx is not available${said === "" ? "" : ` (${said})`}, so image builds cannot be limited; ${INSTALL_HINT}` };
153
+ }
154
+ const version = /\bv?(\d+\.\d+\.\d+)/.exec(result.stdout)?.[1];
155
+ if (version !== void 0 && compareVersions(version, MIN_BUILDX_VERSION) < 0) {
156
+ return { problem: `docker buildx ${version} is too old: the runner's image builder needs Buildx ${MIN_BUILDX_VERSION} or later; update ${INSTALL_HINT}` };
157
+ }
158
+ return "usable";
159
+ }
160
+ function isOutOfMemory(output) {
161
+ if (/cannot allocate memory/i.test(output)) return true;
162
+ if (/did not complete successfully: (exit code: 137|signal: killed)/i.test(output)) return true;
163
+ return /ResourceExhausted/i.test(output) && !/larger than max|message size|too large/i.test(output);
164
+ }
165
+ var running = 0;
166
+ async function trackImageBuild(work) {
167
+ running++;
168
+ try {
169
+ return await work();
170
+ } finally {
171
+ running--;
172
+ }
173
+ }
174
+ var queue = Promise.resolve();
175
+ function serialized(work) {
176
+ const next = queue.then(work, work);
177
+ queue = next.catch(() => void 0);
178
+ return next;
179
+ }
180
+ function readExisting(inspectOutput) {
181
+ const options = /^Driver Options:\s*(.*)$/m.exec(inspectOutput)?.[1] ?? "";
182
+ const option = (key) => new RegExp(`(?:^|\\s)${key}="([^"]*)"`).exec(options)?.[1];
183
+ return { driver: /^Driver:\s*(\S+)/m.exec(inspectOutput)?.[1], memory: option("memory"), image: option("image") };
184
+ }
185
+ function sameMemory(found, wanted) {
186
+ return (parseSize(found) ?? found) === (parseSize(wanted) ?? wanted);
187
+ }
188
+ var IDLE_POLL_MS = 1e3;
189
+ var failures = 0;
190
+ function ensureFailureCount() {
191
+ return failures;
192
+ }
193
+ function ensureBuilder(rawRun, spec, options = {}) {
194
+ const run = (command, args, opts) => rawRun(command, args, { ...opts, timeoutMs: args.includes("--bootstrap") ? 15 * 6e4 : 2 * 6e4 });
195
+ const result = serialized(async () => {
196
+ const state = await buildxState(run);
197
+ if (state !== "usable") return { ok: false, problem: state.problem };
198
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
199
+ const inspected = await run("docker", ["buildx", "inspect", spec.name]);
200
+ let create = inspected.status !== 0;
201
+ if (!create) {
202
+ const found = readExisting(inspected.stdout);
203
+ const current = found.driver === "docker-container" && sameMemory(found.memory ?? "", spec.memory) && found.image === BUILDKIT_IMAGE;
204
+ if (!current && options.replaceStale === false) {
205
+ return {
206
+ ok: false,
207
+ problem: `the image builder ${spec.name} was made with other settings than runner.build.memory (${spec.memory}) and the pinned BuildKit image; the runner service replaces it when no build is running, or remove it with docker buildx rm ${spec.name}`
208
+ };
209
+ }
210
+ if (!current) {
211
+ if (options.waitForIdle === true) while (running > 0) await sleep(IDLE_POLL_MS);
212
+ if (running === 0) {
213
+ const removed = await run("docker", ["buildx", "rm", spec.name]);
214
+ if (removed.status !== 0) return { ok: false, problem: `could not replace the image builder ${spec.name}: ${removed.stderr.trim() || `docker exited ${removed.status}`}` };
215
+ create = true;
216
+ }
217
+ }
218
+ }
219
+ if (create) {
220
+ const opts = [
221
+ `memory=${spec.memory}`,
222
+ `memory-swap=${spec.memory}`,
223
+ `image=${BUILDKIT_IMAGE}`,
224
+ ...Object.entries(spec.env ?? {}).map(([name, value]) => `env.${name}=${value}`),
225
+ ...spec.driverOpts ?? []
226
+ ];
227
+ const created = await run("docker", [
228
+ "buildx",
229
+ "create",
230
+ "--name",
231
+ spec.name,
232
+ "--driver",
233
+ "docker-container",
234
+ ...opts.flatMap((opt) => ["--driver-opt", driverOpt(opt)])
235
+ ]);
236
+ if (created.status !== 0) {
237
+ const said = created.stderr.trim() || `docker exited ${created.status}`;
238
+ if (/failed to find driver/i.test(said)) {
239
+ return { ok: false, problem: `this Docker's Buildx has no docker-container driver, so image builds cannot be limited; ${INSTALL_HINT}` };
240
+ }
241
+ return { ok: false, problem: `could not create the image builder ${spec.name}: ${said}` };
242
+ }
243
+ }
244
+ if (options.bootstrap === true) {
245
+ const started = await run("docker", ["buildx", "inspect", "--bootstrap", spec.name]);
246
+ if (started.status !== 0) {
247
+ return { ok: false, problem: `the image builder ${spec.name} did not start: ${started.stderr.trim() || `docker exited ${started.status}`}` };
248
+ }
249
+ }
250
+ return { ok: true, changed: create };
251
+ });
252
+ return result.then(
253
+ (outcome) => {
254
+ if (!outcome.ok) failures++;
255
+ return outcome;
256
+ },
257
+ (err) => {
258
+ failures++;
259
+ throw err;
260
+ }
261
+ );
262
+ }
263
+
264
+ export { BUILD_LABEL, MIN_BUILDX_VERSION, RUNNER_LABEL, builderName, builderSpec, buildxState, containerExecArgs, containerRunArgs, ensureBuilder, ensureFailureCount, isOutOfMemory, prepareRunArgs, proxyEnvironment, runnerLabelValue, trackImageBuild };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-SSU747O6.js';
4
- import { resolveRepoIdentity } from './chunk-D6FXM5OW.js';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-ILEA3YHM.js';
4
+ import { resolveRepoIdentity } from './chunk-GAYWY4GI.js';
5
5
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
6
6
  import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
7
7
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LiveUploader } from './chunk-6ZZHWY2Z.js';
4
- import { CaptureDaemon } from './chunk-D6FXM5OW.js';
3
+ import { LiveUploader } from './chunk-BF4KKEFY.js';
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';