@outerlayer/cli 0.34.0-next.20261027023105 → 0.34.0-next.20261027162612

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 (124) hide show
  1. package/dist/{agent-setup-2A6P2SYL.js → agent-setup-THDNZ5ME.js} +6 -6
  2. package/dist/{bridge-F5FBQSPZ.js → bridge-MLB57JP6.js} +2 -2
  3. package/dist/build-25GDCEZ7.js +18 -0
  4. package/dist/{build-disk-RZ7AZKTY.js → build-disk-NFMQCZM3.js} +8 -8
  5. package/dist/build-info.json +1 -1
  6. package/dist/{builder-MQIL24HI.js → builder-OWDGC3VQ.js} +7 -7
  7. package/dist/{check-YIUZ3UX3.js → check-QGM2SECF.js} +39 -39
  8. package/dist/{chunk-RR3VDM7M.js → chunk-2YPOSVC7.js} +3 -3
  9. package/dist/{chunk-66LH5QAV.js → chunk-36M4KVBT.js} +2 -2
  10. package/dist/{chunk-LQHCNXPK.js → chunk-3FTIUB7I.js} +1 -1
  11. package/dist/{chunk-QWXBWOVV.js → chunk-3RRYEZAC.js} +4 -4
  12. package/dist/{chunk-GJ4KBHBD.js → chunk-3VJYDWFV.js} +1 -1
  13. package/dist/{chunk-CCHSD7RS.js → chunk-4QQJTJUN.js} +1 -1
  14. package/dist/{chunk-P3NPTFLF.js → chunk-5ARXP3BP.js} +3 -3
  15. package/dist/{chunk-IYQPUGST.js → chunk-5FHBVV25.js} +104 -59
  16. package/dist/{chunk-7QAJQDHS.js → chunk-62URQYCB.js} +1 -1
  17. package/dist/{chunk-QABXXQ67.js → chunk-6IMQXBTZ.js} +6 -6
  18. package/dist/{chunk-77VBS2RT.js → chunk-7Q7GQELE.js} +5 -5
  19. package/dist/{chunk-QRJIBTNQ.js → chunk-7SJNVGVC.js} +6 -6
  20. package/dist/{chunk-FQGC22IP.js → chunk-7TLGRE5F.js} +2 -2
  21. package/dist/{chunk-OOD5NDQA.js → chunk-A6PJSNP6.js} +349 -94
  22. package/dist/{chunk-7PCA37ZS.js → chunk-ANFNZCXZ.js} +5 -5
  23. package/dist/{chunk-MN3PP45X.js → chunk-AV5T7HV3.js} +1 -1
  24. package/dist/{chunk-DX4FF5P5.js → chunk-BCIBSJZH.js} +43 -24
  25. package/dist/{chunk-6KFJIU73.js → chunk-BS3OYFAD.js} +1 -1
  26. package/dist/{chunk-TS3EFB7S.js → chunk-BS4CZMT6.js} +1 -1
  27. package/dist/{chunk-SDELQEG4.js → chunk-CFJOONWM.js} +1 -1
  28. package/dist/{chunk-UWDFA6WW.js → chunk-CKVJSOY3.js} +20 -20
  29. package/dist/{chunk-GTBY7BTI.js → chunk-CMMEJJTL.js} +10 -35
  30. package/dist/{chunk-OKGHWCSK.js → chunk-EYJRVHBN.js} +3 -3
  31. package/dist/{chunk-GR7ZVGNI.js → chunk-FLHBUQ2W.js} +7 -6
  32. package/dist/{chunk-72CJOYN6.js → chunk-FVVHQIZR.js} +1 -1
  33. package/dist/{chunk-SDAEXUIX.js → chunk-GMKDAF37.js} +26 -6
  34. package/dist/{chunk-CFFVCI2I.js → chunk-GPO7F757.js} +1 -1
  35. package/dist/{chunk-EBVK3QBO.js → chunk-HJCNWEQK.js} +3 -3
  36. package/dist/{chunk-LKTH7PUH.js → chunk-J3Q3QCOF.js} +393 -91
  37. package/dist/{chunk-MYLOOVRJ.js → chunk-JO4SAEHH.js} +3 -3
  38. package/dist/{chunk-3VZTNXK5.js → chunk-JVNQNKHV.js} +1 -1
  39. package/dist/{chunk-DEJCZ43H.js → chunk-JWMJMQRF.js} +83 -7
  40. package/dist/{chunk-JL4GSPGD.js → chunk-KVGK2JL3.js} +6 -6
  41. package/dist/{chunk-BLSEHKZ4.js → chunk-LYX2RRSF.js} +2 -2
  42. package/dist/{chunk-WPDL7MBC.js → chunk-MGF346ND.js} +3 -3
  43. package/dist/{chunk-SSRB5HEL.js → chunk-N33OOF3K.js} +11 -11
  44. package/dist/{chunk-36U7LY7C.js → chunk-NEBMTP7T.js} +6 -6
  45. package/dist/{chunk-O7QPHJWN.js → chunk-NO6E72RM.js} +2 -2
  46. package/dist/{chunk-7QF2EXAN.js → chunk-OHTMTMFX.js} +4 -4
  47. package/dist/{chunk-Q2KGDDUX.js → chunk-OP2L7OXA.js} +3 -3
  48. package/dist/{chunk-WBTPI5MP.js → chunk-QRIE4JZE.js} +3 -3
  49. package/dist/{chunk-ZK3A4W3I.js → chunk-QWSAZGH6.js} +14 -6
  50. package/dist/{chunk-7DK2FOZ4.js → chunk-RCAMBC3H.js} +3 -3
  51. package/dist/{chunk-L5VHGRQE.js → chunk-RJZZFAXS.js} +1 -1
  52. package/dist/{chunk-JA2ARVY6.js → chunk-T6ALNN3H.js} +1 -1
  53. package/dist/{chunk-HOUFCUMH.js → chunk-UZIAZXXO.js} +1 -1
  54. package/dist/{chunk-25XBOX3K.js → chunk-W246VXU4.js} +3 -3
  55. package/dist/{chunk-YL3RWW7X.js → chunk-WR2GRWK3.js} +1 -1
  56. package/dist/{chunk-QUOITPN7.js → chunk-WX2HW2G2.js} +8 -1
  57. package/dist/{chunk-HDLON3RJ.js → chunk-X7M73LKT.js} +9 -2
  58. package/dist/{chunk-WYR4INK3.js → chunk-Z4LFCJT6.js} +3 -3
  59. package/dist/{claude-launcher-EO3ALKBS.js → claude-launcher-LYGS66AC.js} +1 -1
  60. package/dist/{cli-MP5AUR36.js → cli-HVBFWC3J.js} +114 -113
  61. package/dist/{command-RGBJLW72.js → command-J3CDQLWC.js} +27 -27
  62. package/dist/{config-NGCQD6SN.js → config-5NWSCHIO.js} +9 -9
  63. package/dist/{connect-cmd-65YBQRSY.js → connect-cmd-HB3K3AHE.js} +6 -6
  64. package/dist/{container-start-KT2KKAQX.js → container-start-YLKDT2JG.js} +33 -33
  65. package/dist/{context-show-cmd-S5SEBOI2.js → context-show-cmd-RJIQS2KF.js} +7 -7
  66. package/dist/{control-plane-launch-BDSUP4DK.js → control-plane-launch-TS4DFJF4.js} +5 -5
  67. package/dist/{demo-record-cmd-BUNOOCNM.js → demo-record-cmd-VVZGUCWB.js} +4 -4
  68. package/dist/{demo-voice-cmd-RWTRJUAX.js → demo-voice-cmd-3ADGIWK6.js} +13 -13
  69. package/dist/{dist-ADKRGE7I.js → dist-BUSLJNSZ.js} +1 -1
  70. package/dist/{docker-TRGA5QRL.js → docker-5VGCFZV2.js} +7 -7
  71. package/dist/{doctor-NEO7NXJJ.js → doctor-AG73VZNG.js} +32 -30
  72. package/dist/{emit-artifact-cmd-56C6DBUP.js → emit-artifact-cmd-WJT7AXTZ.js} +11 -11
  73. package/dist/{emit-criteria-cmd-HRCWXD3W.js → emit-criteria-cmd-45IYB535.js} +8 -8
  74. package/dist/{emit-demo-cmd-QMRDQGB6.js → emit-demo-cmd-AIIQNPXS.js} +13 -13
  75. package/dist/{emit-finding-cmd-6MVFN4BO.js → emit-finding-cmd-6YTJK2NA.js} +8 -8
  76. package/dist/{emit-result-cmd-E3YYBXRY.js → emit-result-cmd-TZGFY743.js} +10 -10
  77. package/dist/{emit-step-cmd-DM4CRYYI.js → emit-step-cmd-LGBTIAXC.js} +8 -8
  78. package/dist/{exec-client-LXHTMVIB.js → exec-client-LR67CA24.js} +3 -3
  79. package/dist/find-unit-YGDFVHVU.js +19 -0
  80. package/dist/{findings-cmd-K2OYBTUH.js → findings-cmd-ETJXUDQI.js} +8 -8
  81. package/dist/{fleet-readiness-VIAVQYRP.js → fleet-readiness-MYIMDBF7.js} +5 -5
  82. package/dist/{governing-source-MQA2SDJT.js → governing-source-GBJTVMK2.js} +10 -10
  83. package/dist/{guest-init-WWL2WL7R.js → guest-init-GXPOW53F.js} +4 -4
  84. package/dist/{hook-fast-KXAQ22LZ.js → hook-fast-5WOGLR7V.js} +1 -1
  85. package/dist/{host-checks-JH2ILNZT.js → host-checks-6G2F2HTK.js} +31 -31
  86. package/dist/{pending-UWFDVFOA.js → host-key-GAZM4EOH.js} +3 -3
  87. package/dist/{image-tag-BTXKIH73.js → image-tag-OYHGRHVV.js} +3 -3
  88. package/dist/index.js +4 -4
  89. package/dist/{init-WGVNY4NP.js → init-7VWIU5TG.js} +24 -24
  90. package/dist/{init-HGJQW2NL.js → init-Y2OJSOAA.js} +24 -24
  91. package/dist/{init-cmd-L2SG2WSN.js → init-cmd-77XKBRUF.js} +11 -11
  92. package/dist/{init-update-JMVLGBDE.js → init-update-TXQHBY3H.js} +9 -9
  93. package/dist/{install-cmd-RGO7NWKP.js → install-cmd-VZGXSS73.js} +5 -5
  94. package/dist/{logs-LEVH6VAI.js → logs-42QPBCMC.js} +2 -2
  95. package/dist/{loop-F6E6PGWG.js → loop-FRT5NSFG.js} +38 -38
  96. package/dist/{machine-GYTMJSIY.js → machine-TEG554M5.js} +24 -24
  97. package/dist/{mcp-serve-cmd-4O5INM77.js → mcp-serve-cmd-LYJQO6U4.js} +4 -4
  98. package/dist/{paths-AQ47ZRHK.js → paths-QLFRPIKS.js} +2 -2
  99. package/dist/{host-key-TSOKVSZX.js → pending-6DDSCXUD.js} +3 -3
  100. package/dist/{pidfile-PCG2H5T4.js → pidfile-WLZ427QQ.js} +3 -3
  101. package/dist/{record-SVCNFCGQ.js → record-WGCMQLQS.js} +3 -3
  102. package/dist/{runner-env-DH7YA4BU.js → runner-env-6FSJOSWS.js} +11 -11
  103. package/dist/{runner-identity-GLL56XY7.js → runner-identity-XODZ7YBP.js} +7 -7
  104. package/dist/{runner-key-HMXSBRBE.js → runner-key-T3V7N7CL.js} +24 -24
  105. package/dist/{session-sender-KLOMLL7X.js → session-sender-U54EQJNR.js} +11 -11
  106. package/dist/{spec-cmd-MX5QFW32.js → spec-cmd-EM24GTAM.js} +9 -9
  107. package/dist/{status-QNKTP6OU.js → status-4YO4TUEH.js} +31 -31
  108. package/dist/{sync-cmd-CO4DFMHU.js → sync-cmd-Y5RKWVF7.js} +10 -10
  109. package/dist/{update-steps-M2UKG4QZ.js → update-steps-KNN4Y2ZU.js} +32 -32
  110. package/dist/{watch-GU62YVQY.js → watch-X5VYY4LH.js} +10 -10
  111. package/dist/{work-claim-cmd-JF5GGDFZ.js → work-claim-cmd-IU3YJQKR.js} +15 -15
  112. package/dist/{work-cmd-VR7PPSP6.js → work-cmd-LUKJHAMH.js} +8 -8
  113. package/dist/{work-comment-cmd-HVZF72B4.js → work-comment-cmd-BDNFAVKL.js} +9 -9
  114. package/dist/{work-demo-cmd-EDGNM5VJ.js → work-demo-cmd-GPDJHU6F.js} +8 -8
  115. package/dist/{work-logs-cmd-ZZVAHX36.js → work-logs-cmd-B6EX4RPE.js} +8 -8
  116. package/dist/{work-open-pr-cmd-AQWZRJHZ.js → work-open-pr-cmd-TRXDCMSG.js} +9 -9
  117. package/dist/{work-pr-cmd-UJ7VWCJN.js → work-pr-cmd-5GUR5SIU.js} +8 -8
  118. package/dist/{work-proofs-cmd-A7SZSM2A.js → work-proofs-cmd-PBY7WNYI.js} +9 -9
  119. package/dist/{work-proofs-record-YG6HD6SJ.js → work-proofs-record-AVKJFZOD.js} +16 -16
  120. package/dist/{work-stop-cmd-SAT4XVM2.js → work-stop-cmd-J47GZB2N.js} +8 -8
  121. package/package.json +1 -1
  122. package/skill-pack/maintained/outerlayer-build/SKILL.md +15 -0
  123. package/dist/build-FS7TQEJ6.js +0 -18
  124. package/dist/find-unit-IOCVYPNW.js +0 -19
@@ -1,30 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { sha256OfFile, downloadPinned, VoiceDownloadError } from './chunk-2PGI6RDE.js';
4
- import { readDefaultBranchHead, cloneRepository, buildRepositoryImage, prepareImageBuild, KEY_PREFIX, TAG_HOST, metadataFromLabels, writeRecord } from './chunk-IYQPUGST.js';
5
- import { FETCHED_DIR, toolsDockerfile, FETCHED_FFMPEG, FETCHED_GH, FETCHED_TINI, FETCHED_HEADLESS_SHELL, FETCHED_PLAYWRIGHT_FFMPEG, FETCHED_VOICE_DIR } from './chunk-GTBY7BTI.js';
4
+ import { readDefaultBranchHead, cloneRepository, buildRepositoryImage, prepareImageBuild, KEY_PREFIX, TAG_HOST, SHARED_OWNER, SHARED_NAME, metadataFromLabels, writeRecord } from './chunk-5FHBVV25.js';
5
+ import { FETCHED_DIR, toolsDockerfile, FETCHED_FFMPEG, FETCHED_GH, FETCHED_TINI, FETCHED_HEADLESS_SHELL, FETCHED_PLAYWRIGHT_FFMPEG, FETCHED_VOICE_DIR } from './chunk-CMMEJJTL.js';
6
6
  import { currentCliBuild } from './chunk-OGFGZQA3.js';
7
- import { runExec, execCapture, waitForAgent } from './chunk-3VZTNXK5.js';
8
- import { GUEST_CID, linkVsockSockets } from './chunk-6KFJIU73.js';
9
- import { retrySend, describeCallFailure, keepStagedContext, controlPlaneTokenFailure, refusalCode, resolveGoverningSource, prefetchGovernedContext, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, shimScript, WORKFLOW_PERMISSION_REASON } from './chunk-77VBS2RT.js';
10
- import { runnerImageVersion } from './chunk-SDELQEG4.js';
11
- import { hasStoredCredential, AGENT_COMMANDS, storeClaudeCredential, credentialFromStdin, isAgentName } from './chunk-Q2KGDDUX.js';
12
- import { runnerCredentialProblem, builtinKind, allowHostProblem, hostAllowed } from './chunk-DEJCZ43H.js';
13
- import { formatBytes, allocatedBytes } from './chunk-BLSEHKZ4.js';
14
- import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, readDu, JUDGE_DIR, MAX_ITEMS_BYTES, JUDGE_ITEMS, MAX_REPORT_BYTES, JUDGE_REPORT, spawnRun } from './chunk-GR7ZVGNI.js';
15
- import { RecipeError, DOCKER_FEATURE, writeSanitizedRecipe, classifyProperties } from './chunk-HDLON3RJ.js';
16
- import { firecrackerArch, MICROVM_ARCHES, FIRECRACKER_VERSION, hostHelperPinned, CLAUDE_CODE_VERSION, builderDiskPinned, guestAssetsPinned, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, JAILER_BINARY_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, GUEST_ASSETS_VERSION, BUILDER_DISK_VERSION, FFMPEG_STATIC, FFMPEG_BUILD_TAG, GH_SHA256, GH_VERSION, TINI_SHA256, TINI_VERSION, HEADLESS_SHELL, HEADLESS_SHELL_BASE_URL, PLAYWRIGHT_FFMPEG, PLAYWRIGHT_FFMPEG_BASE_URL, VOICE_PACK_FILES, BUILDER_DISK_SHA256, BUILDER_DISK_BASE_URL, DEFAULT_BASE_IMAGE } from './chunk-QUOITPN7.js';
7
+ import { runExec, execCapture, waitForAgent } from './chunk-JVNQNKHV.js';
8
+ import { GUEST_CID, linkVsockSockets } from './chunk-BS3OYFAD.js';
9
+ import { retrySend, describeCallFailure, keepStagedContext, controlPlaneTokenFailure, refusalCode, resolveGoverningSource, prefetchGovernedContext, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, shimScript, WORKFLOW_PERMISSION_REASON } from './chunk-7Q7GQELE.js';
10
+ import { runnerImageVersion } from './chunk-CFJOONWM.js';
11
+ import { hasStoredCredential, AGENT_COMMANDS, storeClaudeCredential, credentialFromStdin, isAgentName } from './chunk-OP2L7OXA.js';
12
+ import { optionalEgress, runnerCredentialProblem, builtinKind, allowHostProblem, systemClock, emptyEgressCounts, hostAllowed } from './chunk-JWMJMQRF.js';
13
+ import { formatBytes, allocatedBytes } from './chunk-LYX2RRSF.js';
14
+ import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, readDu, JUDGE_DIR, MAX_ITEMS_BYTES, JUDGE_ITEMS, MAX_REPORT_BYTES, JUDGE_REPORT, spawnRun } from './chunk-FLHBUQ2W.js';
15
+ import { RecipeError, DOCKER_FEATURE, universalImagePending, writeSanitizedRecipe, classifyProperties } from './chunk-X7M73LKT.js';
16
+ import { firecrackerArch, MICROVM_ARCHES, FIRECRACKER_VERSION, hostHelperPinned, CLAUDE_CODE_VERSION, builderDiskPinned, guestAssetsPinned, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, JAILER_BINARY_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, GUEST_ASSETS_VERSION, BUILDER_DISK_VERSION, universalImagePinned, UNIVERSAL_IMAGE, UNIVERSAL_IMAGE_DIGEST, UNIVERSAL_IMAGE_REPOSITORY, UNIVERSAL_IMAGE_SOURCE, FFMPEG_STATIC, FFMPEG_BUILD_TAG, GH_SHA256, GH_VERSION, TINI_SHA256, TINI_VERSION, HEADLESS_SHELL, HEADLESS_SHELL_BASE_URL, PLAYWRIGHT_FFMPEG, PLAYWRIGHT_FFMPEG_BASE_URL, VOICE_PACK_FILES, BUILDER_DISK_SHA256, BUILDER_DISK_BASE_URL, DEFAULT_BASE_IMAGE } from './chunk-WX2HW2G2.js';
17
17
  import { startTimeOf, isSameProcess } from './chunk-JBJTC3UU.js';
18
- import { postJson, WorkCommandError, getJson } from './chunk-QABXXQ67.js';
18
+ import { postJson, WorkCommandError, getJson } from './chunk-6IMQXBTZ.js';
19
19
  import { sanitizeTerminal } from './chunk-IXPH4EXK.js';
20
- import { signerFor } from './chunk-L5VHGRQE.js';
20
+ import { signerFor } from './chunk-RJZZFAXS.js';
21
21
  import { sharedSkillNames, skillConflictMessage } from './chunk-FGF52V4V.js';
22
22
  import { versionAtLeast, MINIMUM_CLAUDE_VERSION } from './chunk-HCVLP7XA.js';
23
- import { MIN_SCRUBBED_LITERAL, setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-OOD5NDQA.js';
23
+ import { MIN_SCRUBBED_LITERAL, setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-A6PJSNP6.js';
24
24
  import { orderSessions, extractFacts, sessionsToTimeline } from './chunk-XFJ7YOPD.js';
25
25
  import { downconvertSession } from './chunk-DINRXUQA.js';
26
- import { vmAssetsDir, RUNNER_DIR_MODE, rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, buildsDir, buildDir, runnerDir, deliveryDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, SHIM_DIR, vsockPath, builderCacheDiskPath, builderConsolePath } from './chunk-GJ4KBHBD.js';
27
- import { claudeCredential, parseIsolation, proxyEnvironment, withProxyWarningHidden, containerLocalAddress, destinationEnvironment, CLAUDE_CREDENTIAL_VARIABLES, builtInEnvironment, withHooksPath, startBuildServices, BUILT_IN_NAMES, repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, buildEnvironment, writeBuildMavenSettings, checkEnvironment, AGENT_CREDENTIAL_MISSING, mavenSettingsXml, namesGlobalSettings, MAVEN_NO_PROXY_NOTE, mavenArgs, MAVEN_SPACE_NOTE, writeMavenSettings, checkoutPath, JOB_MOUNT, realFdStorePort } from './chunk-SDAEXUIX.js';
26
+ import { vmAssetsDir, RUNNER_DIR_MODE, rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, buildsDir, buildDir, runnerDir, deliveryDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, SHIM_DIR, vsockPath, builderCacheDiskPath, builderConsolePath } from './chunk-3VJYDWFV.js';
27
+ import { claudeCredential, parseIsolation, proxyEnvironment, withProxyWarningHidden, containerLocalAddress, destinationEnvironment, CLAUDE_CREDENTIAL_VARIABLES, builtInEnvironment, withHooksPath, startBuildServices, BUILT_IN_NAMES, repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, buildEnvironment, writeBuildMavenSettings, checkEnvironment, AGENT_CREDENTIAL_MISSING, mavenSettingsXml, namesGlobalSettings, MAVEN_NO_PROXY_NOTE, mavenArgs, MAVEN_SPACE_NOTE, writeMavenSettings, checkoutPath, nodeAcceptsProxyWarningFlag, PROXY_WARNING_FLAG, JOB_MOUNT, realFdStorePort } from './chunk-GMKDAF37.js';
28
28
  import { RELAY_USER, RELAY_ID, UNKNOWN_TRANSPORT_REASON, DOCKER_DESKTOP_REASON, MAX_MALFORMED_SESSIONS, MALFORMED_REASON, JOIN_WAIT_MS, MAX_OPEN_STREAMS, STREAM_RESET_RATE, STREAM_RESET_BURST, STREAM_WINDOW, SESSION_WINDOW, targetOfPath } from './chunk-MESOOLF4.js';
29
29
  import { spawn, spawnSync } from 'child_process';
30
30
  import { mkdirSync, existsSync, readFileSync, mkdtempSync, rmSync, chmodSync, truncateSync, statSync, accessSync, constants, readdirSync, writeFileSync, lstatSync, copyFileSync, renameSync, rmdirSync, unlinkSync, linkSync, openSync, closeSync, cpSync, writeSync, appendFileSync, createWriteStream, createReadStream } from 'fs';
@@ -32,7 +32,7 @@ import { randomBytes, createHash } from 'crypto';
32
32
  import { join, dirname, isAbsolute, relative, resolve, basename } from 'path';
33
33
  import { createConnection, connect, createServer as createServer$1, isIP } from 'net';
34
34
  import { availableParallelism, networkInterfaces, tmpdir } from 'os';
35
- import { Duplex, PassThrough, Transform } from 'stream';
35
+ import { Transform, Duplex, PassThrough } from 'stream';
36
36
  import { createServer, request } from 'http';
37
37
  import { lookup } from 'dns/promises';
38
38
  import http2 from 'http2';
@@ -726,9 +726,9 @@ function createFirecrackerHost(options = {}) {
726
726
  var BUILD_PREFIX = "build-";
727
727
  var LEAF = "runner";
728
728
  function serviceDirectory(selfCgroup, mount) {
729
- const line = selfCgroup?.split("\n").find((l) => l.startsWith("0::"));
730
- if (line === void 0) return void 0;
731
- const path = line.slice(3).trim();
729
+ const line2 = selfCgroup?.split("\n").find((l) => l.startsWith("0::"));
730
+ if (line2 === void 0) return void 0;
731
+ const path = line2.slice(3).trim();
732
732
  if (!path.endsWith(".service")) return void 0;
733
733
  return join(mount, path);
734
734
  }
@@ -1111,6 +1111,9 @@ var IDLE_TIMEOUT_MS = 10 * 6e4;
1111
1111
  var STALLED_RESPONSE_MS = 6e4;
1112
1112
  var MAX_BAD_GATEWAY_LINES = 10;
1113
1113
  var BAD_GATEWAY_WINDOW_MS = 1e4;
1114
+ var CONNECTION_RATE_RANGE = "connection-rate";
1115
+ var OPEN_CONNECTIONS_RANGE = "open-connections";
1116
+ var COUNTS_SAVE_MS = 500;
1114
1117
  async function systemResolve(host) {
1115
1118
  const found = await lookup(host, { all: true, verbatim: true });
1116
1119
  return found.map((a) => ({ address: a.address }));
@@ -1145,6 +1148,8 @@ async function startTunnel(socketPath, opts = {}) {
1145
1148
  const connectTimeoutMs = opts.connectTimeoutMs ?? CONNECT_TIMEOUT_MS;
1146
1149
  const idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
1147
1150
  const stalledResponseMs = opts.stalledResponseMs ?? STALLED_RESPONSE_MS;
1151
+ const limits2 = opts.egress ?? { connectionsPerSecond: 0, connectionBurst: 1, openConnections: 0, sendBytesPerSecond: 0, flagHosts: 0 };
1152
+ const clock = opts.clock ?? systemClock;
1148
1153
  let windowStartedMs = 0;
1149
1154
  let linesInWindow = 0;
1150
1155
  let suppressed = 0;
@@ -1173,6 +1178,15 @@ async function startTunnel(socketPath, opts = {}) {
1173
1178
  const extraRefusalKeys = /* @__PURE__ */ new Set();
1174
1179
  let refusalsMore = 0;
1175
1180
  const destinations = [];
1181
+ const counts = emptyEgressCounts();
1182
+ let openNow = 0;
1183
+ let secondOf = 0;
1184
+ let openedInSecond = 0;
1185
+ let tokens = limits2.connectionBurst;
1186
+ let refilledAt = clock.now();
1187
+ let nextSendFree = 0;
1188
+ let lastSendClock = 0;
1189
+ const limitLogged = /* @__PURE__ */ new Set();
1176
1190
  const routes = /* @__PURE__ */ Object.create(null);
1177
1191
  if (opts.recordPath !== void 0 && existsSync(opts.recordPath)) {
1178
1192
  try {
@@ -1183,8 +1197,12 @@ async function startTunnel(socketPath, opts = {}) {
1183
1197
  }
1184
1198
  hostsMore = saved.hostsMore ?? 0;
1185
1199
  for (const name of saved.destinations ?? []) destinations.push(name);
1186
- for (const [name, counts] of Object.entries(saved.routes ?? {})) routes[name] = { requests: counts.requests, failures: counts.failures };
1200
+ for (const [name, counts2] of Object.entries(saved.routes ?? {})) routes[name] = { requests: counts2.requests, failures: counts2.failures };
1187
1201
  refusalsMore = saved.refusalsMore ?? 0;
1202
+ if (saved.egress !== void 0) {
1203
+ const kept = saved.egress;
1204
+ Object.assign(counts, kept, { refused: { ...counts.refused, ...kept.refused } });
1205
+ }
1188
1206
  for (const refusal of saved.refusals ?? []) {
1189
1207
  refusals.push(refusal);
1190
1208
  refusalKeys.add(`${refusal.host}|${refusal.address}|${refusal.range}`);
@@ -1198,8 +1216,9 @@ async function startTunnel(socketPath, opts = {}) {
1198
1216
  refusalsMore,
1199
1217
  refusals: refusals.map((r) => ({ ...r })),
1200
1218
  destinations: [...destinations],
1219
+ egress: { ...counts, refused: { ...counts.refused } },
1201
1220
  // Absent until a route is served, so a record of a tunnel that served none is the shape an older runner wrote.
1202
- ...Object.keys(routes).length === 0 ? {} : { routes: Object.fromEntries(Object.entries(routes).map(([name, counts]) => [name, { ...counts }])) }
1221
+ ...Object.keys(routes).length === 0 ? {} : { routes: Object.fromEntries(Object.entries(routes).map(([name, counts2]) => [name, { ...counts2 }])) }
1203
1222
  });
1204
1223
  const persist = () => {
1205
1224
  if (opts.recordPath === void 0) return;
@@ -1208,6 +1227,15 @@ async function startTunnel(socketPath, opts = {}) {
1208
1227
  } catch {
1209
1228
  }
1210
1229
  };
1230
+ let saveTimer;
1231
+ const persistSoon = () => {
1232
+ if (opts.recordPath === void 0 || saveTimer !== void 0) return;
1233
+ saveTimer = setTimeout(() => {
1234
+ saveTimer = void 0;
1235
+ persist();
1236
+ }, COUNTS_SAVE_MS);
1237
+ saveTimer.unref();
1238
+ };
1211
1239
  const destinationUsed = (name) => {
1212
1240
  if (destinations.includes(name)) return;
1213
1241
  destinations.push(name);
@@ -1219,9 +1247,9 @@ async function startTunnel(socketPath, opts = {}) {
1219
1247
  persist();
1220
1248
  };
1221
1249
  const routeFinished = (name, ok) => {
1222
- const counts = routes[name] ??= { requests: 0, failures: 0 };
1223
- counts.requests++;
1224
- if (!ok) counts.failures++;
1250
+ const counts2 = routes[name] ??= { requests: 0, failures: 0 };
1251
+ counts2.requests++;
1252
+ if (!ok) counts2.failures++;
1225
1253
  persist();
1226
1254
  };
1227
1255
  const reached = (host) => {
@@ -1235,6 +1263,10 @@ async function startTunnel(socketPath, opts = {}) {
1235
1263
  hosts.push(name);
1236
1264
  seen.add(name);
1237
1265
  }
1266
+ if (limits2.flagHosts > 0 && !counts.hostsFlagged && hosts.length + hostsMore > limits2.flagHosts) {
1267
+ counts.hostsFlagged = true;
1268
+ opts.log?.(`tunnel: this build reached more than ${limits2.flagHosts} distinct remote hosts`);
1269
+ }
1238
1270
  persist();
1239
1271
  };
1240
1272
  const refused2 = (host, address, range) => {
@@ -1250,6 +1282,64 @@ async function startTunnel(socketPath, opts = {}) {
1250
1282
  }
1251
1283
  persist();
1252
1284
  };
1285
+ const limitText = (range) => range === CONNECTION_RATE_RANGE ? `${limits2.connectionsPerSecond} new connections per second, burst ${limits2.connectionBurst}` : `${limits2.openConnections} open connections`;
1286
+ const admit = () => {
1287
+ const now = clock.now();
1288
+ if (limits2.openConnections > 0 && openNow >= limits2.openConnections) return OPEN_CONNECTIONS_RANGE;
1289
+ if (limits2.connectionsPerSecond > 0) {
1290
+ tokens = Math.min(limits2.connectionBurst, tokens + Math.max(0, now - refilledAt) / 1e3 * limits2.connectionsPerSecond);
1291
+ refilledAt = now;
1292
+ if (tokens < 1) return CONNECTION_RATE_RANGE;
1293
+ tokens -= 1;
1294
+ }
1295
+ counts.connectionsOpened++;
1296
+ openNow++;
1297
+ counts.peakOpenConnections = Math.max(counts.peakOpenConnections, openNow);
1298
+ const second = Math.floor(now / 1e3);
1299
+ if (second !== secondOf) {
1300
+ secondOf = second;
1301
+ openedInSecond = 0;
1302
+ }
1303
+ openedInSecond++;
1304
+ counts.peakConnectionsPerSecond = Math.max(counts.peakConnectionsPerSecond, openedInSecond);
1305
+ persistSoon();
1306
+ return void 0;
1307
+ };
1308
+ const release = () => {
1309
+ openNow--;
1310
+ };
1311
+ const refuseOverLimit = (host, range) => {
1312
+ if (range === CONNECTION_RATE_RANGE) counts.refused.connectionRate++;
1313
+ else counts.refused.openConnections++;
1314
+ refused2(host, NOT_RESOLVED, range);
1315
+ if (!limitLogged.has(range)) {
1316
+ limitLogged.add(range);
1317
+ opts.log?.(`tunnel refused ${host}: over the ${range} limit of ${limitText(range)}. Later refusals of this kind are counted when the build ends`);
1318
+ }
1319
+ persistSoon();
1320
+ return { status: 429, body: `refused: this build is over the ${range} limit of ${limitText(range)}
1321
+ ` };
1322
+ };
1323
+ const waitToSend = async (n) => {
1324
+ const now = clock.now();
1325
+ if (now < lastSendClock) nextSendFree = Math.max(0, nextSendFree - (lastSendClock - now));
1326
+ lastSendClock = now;
1327
+ nextSendFree = Math.max(nextSendFree, now) + n * 1e3 / limits2.sendBytesPerSecond;
1328
+ await clock.sleep(nextSendFree - now);
1329
+ };
1330
+ const meter = () => new Transform({
1331
+ highWaterMark: 64 * 1024,
1332
+ transform(chunk, _encoding, done) {
1333
+ waitToSend(chunk.length).then(
1334
+ () => {
1335
+ counts.bytesSent += chunk.length;
1336
+ persistSoon();
1337
+ done(null, chunk);
1338
+ },
1339
+ (err) => done(err)
1340
+ );
1341
+ }
1342
+ });
1253
1343
  async function decide(host, port) {
1254
1344
  if (opts.allowHosts !== void 0 && !hostAllowed(host, opts.allowHosts)) {
1255
1345
  refused2(host, NOT_RESOLVED, NOT_ALLOWED_RANGE);
@@ -1294,7 +1384,7 @@ async function startTunnel(socketPath, opts = {}) {
1294
1384
  server.on("connect", (req, client, head) => {
1295
1385
  void tunnelConnect(req, client, head);
1296
1386
  });
1297
- const statusLine = (status) => `HTTP/1.1 ${status} ${status === 403 ? "Forbidden" : "Bad Gateway"}`;
1387
+ const statusLine = (status) => `HTTP/1.1 ${status} ${status === 403 ? "Forbidden" : status === 429 ? "Too Many Requests" : "Bad Gateway"}`;
1298
1388
  const reply = (client, status, body) => {
1299
1389
  client.end(`${statusLine(status)}\r
1300
1390
  Content-Type: text/plain\r
@@ -1310,6 +1400,13 @@ ${body}`);
1310
1400
  client.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
1311
1401
  return;
1312
1402
  }
1403
+ const over = admit();
1404
+ if (over !== void 0) {
1405
+ const refusal = refuseOverLimit(target.host, over);
1406
+ reply(client, refusal.status, refusal.body);
1407
+ return;
1408
+ }
1409
+ client.once("close", release);
1313
1410
  const decision = await decide(target.host, target.port);
1314
1411
  if (!decision.ok) {
1315
1412
  reply(client, decision.status, decision.body);
@@ -1336,16 +1433,33 @@ ${body}`);
1336
1433
  if (!upstream.readableEnded && !client.writableEnded) client.destroy(abortedError("the tunnel closed the connection to the server before it ended"));
1337
1434
  else client.resume();
1338
1435
  });
1339
- client.once("end", () => {
1436
+ const buildEnded = () => {
1340
1437
  upstream.destroy();
1341
1438
  client.end();
1342
- });
1439
+ };
1440
+ const metered = limits2.sendBytesPerSecond > 0 ? meter() : void 0;
1441
+ if (metered === void 0) client.once("end", buildEnded);
1442
+ else metered.once("end", buildEnded);
1343
1443
  reached(target.host);
1344
1444
  client.write("HTTP/1.1 200 Connection Established\r\n\r\n");
1345
- upstream.write(head);
1445
+ if (metered !== void 0) {
1446
+ if (head.length > 0) metered.write(head);
1447
+ } else {
1448
+ counts.bytesSent += head.length;
1449
+ upstream.write(head);
1450
+ }
1346
1451
  releaseWhenStalled(client, upstream);
1347
1452
  upstream.pipe(client);
1348
- client.pipe(upstream);
1453
+ if (metered === void 0) {
1454
+ client.on("data", (chunk) => {
1455
+ counts.bytesSent += chunk.length;
1456
+ persistSoon();
1457
+ });
1458
+ client.pipe(upstream);
1459
+ } else {
1460
+ client.once("close", () => metered.destroy());
1461
+ client.pipe(metered).pipe(upstream);
1462
+ }
1349
1463
  };
1350
1464
  if (upstream.readyState === "open") established();
1351
1465
  else upstream.once("connect", established);
@@ -1395,6 +1509,14 @@ ${body}`);
1395
1509
  }
1396
1510
  const host = url.hostname.replace(/^\[|\]$/g, "");
1397
1511
  const port = url.port === "" ? 80 : Number(url.port);
1512
+ const over = admit();
1513
+ if (over !== void 0) {
1514
+ const refusal = refuseOverLimit(host, over);
1515
+ res.writeHead(refusal.status, { "Content-Type": "text/plain", Connection: "close" });
1516
+ res.end(refusal.body);
1517
+ return;
1518
+ }
1519
+ res.once("close", release);
1398
1520
  const decision = await decide(host, port);
1399
1521
  if (!decision.ok) {
1400
1522
  res.writeHead(decision.status, { "Content-Type": "text/plain", Connection: "close" });
@@ -1430,7 +1552,17 @@ ${body}`);
1430
1552
  res.destroy();
1431
1553
  }
1432
1554
  });
1433
- req.pipe(upstream);
1555
+ if (limits2.sendBytesPerSecond > 0) {
1556
+ const metered = meter();
1557
+ res.once("close", () => metered.destroy());
1558
+ req.pipe(metered).pipe(upstream);
1559
+ } else {
1560
+ req.on("data", (chunk) => {
1561
+ counts.bytesSent += chunk.length;
1562
+ persistSoon();
1563
+ });
1564
+ req.pipe(upstream);
1565
+ }
1434
1566
  }
1435
1567
  if (opts.socket !== false) {
1436
1568
  if (opts.listenOn !== void 0) {
@@ -1463,6 +1595,9 @@ ${body}`);
1463
1595
  return { port: tcp.address().port };
1464
1596
  },
1465
1597
  close: () => new Promise((resolveClose) => {
1598
+ clearTimeout(saveTimer);
1599
+ saveTimer = void 0;
1600
+ persist();
1466
1601
  for (const socket of sockets) socket.destroy();
1467
1602
  for (const tcp of tcpServers) tcp.close();
1468
1603
  server.close(() => resolveClose());
@@ -1646,14 +1781,14 @@ async function deliverExecMaven(build, workdir, base, run, note) {
1646
1781
  }
1647
1782
  function onceNote(write) {
1648
1783
  const seen = /* @__PURE__ */ new Set();
1649
- return (line) => {
1650
- if (seen.has(line)) return;
1651
- seen.add(line);
1652
- write(line);
1784
+ return (line2) => {
1785
+ if (seen.has(line2)) return;
1786
+ seen.add(line2);
1787
+ write(line2);
1653
1788
  };
1654
1789
  }
1655
1790
  function attemptNote(log, tag) {
1656
- return onceNote((line) => log.line(`${tag} ${line}`));
1791
+ return onceNote((line2) => log.line(`${tag} ${line2}`));
1657
1792
  }
1658
1793
  function hostCommandEnvironment(base, build, config, hooksPath, note) {
1659
1794
  let env = { ...base };
@@ -1690,6 +1825,7 @@ async function startHostServices(input) {
1690
1825
  jobDir: input.jobDir,
1691
1826
  destinations,
1692
1827
  allowHosts: config.build?.allowHosts,
1828
+ ...optionalEgress(config),
1693
1829
  serve: input.process ? "tcp" : "both",
1694
1830
  proxy: input.process,
1695
1831
  ...input.process ? { builtIns: { gatewayUrl: config.url, itemKey: input.itemKey, claudeUpstream: runtime.claudeUpstream } } : {},
@@ -1739,7 +1875,7 @@ function e2fsckRunner(run = runWithSpawn(), env = process.env) {
1739
1875
  };
1740
1876
  }
1741
1877
  function firstLine2(text) {
1742
- return text.split("\n").find((line) => line.trim() !== "")?.trim() ?? "";
1878
+ return text.split("\n").find((line2) => line2.trim() !== "")?.trim() ?? "";
1743
1879
  }
1744
1880
  async function giveBackCacheSpace(input) {
1745
1881
  try {
@@ -1985,7 +2121,8 @@ function readStored(prepared) {
1985
2121
  toolsBuilt: false,
1986
2122
  checkedCommit: prepared.checkout.commit,
1987
2123
  recordDir: prepared.recordDir,
1988
- report: stored.report,
2124
+ // On the universal image the stored report is shared by every repository, so the reused result names this build's repository and commit.
2125
+ report: prepared.location.kind === "default" ? { ...stored.report, repository: prepared.repository, sourceCommit: prepared.checkout.commit, defaultBranch: prepared.checkout.defaultBranch } : stored.report,
1989
2126
  removed: [],
1990
2127
  rootfs: { path, env: stored.env, user: stored.user }
1991
2128
  };
@@ -2012,6 +2149,7 @@ async function buildRootDiskInMicroVm(opts, deps) {
2012
2149
  try {
2013
2150
  const stored = readStored(prepared);
2014
2151
  if (stored !== void 0) return stored;
2152
+ if (prepared.location.kind === "default" && !(deps.universalPublished ?? universalImagePinned)()) throw universalImagePending();
2015
2153
  return await buildInBuilder(opts, deps, prepared);
2016
2154
  } finally {
2017
2155
  prepared.release();
@@ -2025,8 +2163,8 @@ async function buildInBuilder(opts, deps, prepared) {
2025
2163
  const { repository, owner, name, checkout, location, recipe, repoRecords, recordDir, logPath } = prepared;
2026
2164
  const rKey = prepared.recipeKey.slice(0, KEY_PREFIX);
2027
2165
  const tKey = prepared.toolsKey.slice(0, KEY_PREFIX);
2028
- const recipeTag = `${TAG_HOST}/recipe/${repository}:${rKey}`;
2029
- const buildTag = `${TAG_HOST}/build/${repository}:${rKey}-${tKey}`;
2166
+ const recipeTag = `${TAG_HOST}/recipe/${prepared.tagName}:${rKey}`;
2167
+ const buildTag = `${TAG_HOST}/build/${prepared.tagName}:${rKey}-${tKey}`;
2030
2168
  const runner = runnerDir(opts.configPath);
2031
2169
  const builderDisk = await ports.builderDisk(runner);
2032
2170
  const toolFilesDir = await ports.toolFiles(runner);
@@ -2037,7 +2175,7 @@ async function buildInBuilder(opts, deps, prepared) {
2037
2175
  const dir = buildDir(opts.configPath, id);
2038
2176
  const state = { buildId: id, buildDir: dir, vsockPath: vsockPath(dir) };
2039
2177
  const record = { owner, name, id };
2040
- const cachePath = builderCacheDiskPath(opts.configPath, owner, name);
2178
+ const cachePath = location.kind === "default" ? builderCacheDiskPath(opts.configPath, SHARED_OWNER, SHARED_NAME) : builderCacheDiskPath(opts.configPath, owner, name);
2041
2179
  const diskPath = join(dir, "build.ext4");
2042
2180
  const partial = join(recordDir, "rootfs.ext4.partial");
2043
2181
  const scratchRoot = opts.tmpDir ?? tmpdir();
@@ -2080,12 +2218,12 @@ async function buildInBuilder(opts, deps, prepared) {
2080
2218
  lines.push(pending);
2081
2219
  pending = "";
2082
2220
  }
2083
- for (const line of lines) {
2084
- if (line.startsWith(RESULT_PREFIX)) result = line.slice(RESULT_PREFIX.length);
2085
- else if (line.startsWith(ENGINE_PANIC_PREFIX)) enginePanic ??= line.slice(ENGINE_PANIC_PREFIX.length);
2086
- else if (line === ENGINE_STOPPED_LINE) continue;
2221
+ for (const line2 of lines) {
2222
+ if (line2.startsWith(RESULT_PREFIX)) result = line2.slice(RESULT_PREFIX.length);
2223
+ else if (line2.startsWith(ENGINE_PANIC_PREFIX)) enginePanic ??= line2.slice(ENGINE_PANIC_PREFIX.length);
2224
+ else if (line2 === ENGINE_STOPPED_LINE) continue;
2087
2225
  else {
2088
- tail.push(line);
2226
+ tail.push(line2);
2089
2227
  if (tail.length > LOG_TAIL_LINES) tail.shift();
2090
2228
  }
2091
2229
  }
@@ -2126,6 +2264,7 @@ async function buildInBuilder(opts, deps, prepared) {
2126
2264
  tunnel = await deps.startTunnel(join(dir, TUNNEL_SOCKET), {
2127
2265
  ...deps.tunnelOptions,
2128
2266
  ...opts.allowHosts === void 0 ? {} : { allowHosts: opts.allowHosts },
2267
+ ...opts.egress === void 0 ? {} : { egress: opts.egress },
2129
2268
  recordPath: join(dir, "tunnel.json")
2130
2269
  });
2131
2270
  const configPath = join(dir, "vm.json");
@@ -2158,7 +2297,8 @@ async function buildInBuilder(opts, deps, prepared) {
2158
2297
  let recipeParts = { kind: "default" };
2159
2298
  const recipeDir = join(scratch, "recipe");
2160
2299
  mkdirSync(recipeDir);
2161
- if (location.kind === "default") writeFileSync(join(recipeDir, "Dockerfile"), prepared.defaultText);
2300
+ if (location.kind === "default") writeFileSync(join(recipeDir, "Dockerfile"), `FROM ${UNIVERSAL_IMAGE}
2301
+ `);
2162
2302
  else {
2163
2303
  sanitized = writeSanitizedRecipe(checkout.dir, location, recipe);
2164
2304
  recipeParts = { kind: "file", config: relative(checkout.dir, sanitized) };
@@ -2173,7 +2313,15 @@ async function buildInBuilder(opts, deps, prepared) {
2173
2313
  mkdirSync(join(toolsDir, FETCHED_DIR));
2174
2314
  writeFileSync(
2175
2315
  join(toolsDir, "Dockerfile"),
2176
- toolsDockerfile({ recipeImage: recipeTag, nodeImage: prepared.nodeImage, claudeCodeVersion: prepared.claudeCodeVersion, buildId: opts.cli.buildId, guestHelper: true, fetched: true })
2316
+ toolsDockerfile({
2317
+ recipeImage: recipeTag,
2318
+ nodeImage: prepared.nodeImage,
2319
+ claudeCodeVersion: prepared.claudeCodeVersion,
2320
+ buildId: opts.cli.buildId,
2321
+ guestHelper: true,
2322
+ fetched: true,
2323
+ ...location.kind === "default" ? { universal: true } : {}
2324
+ })
2177
2325
  );
2178
2326
  inputs = builderInput({ checkoutDir: checkout.dir, toolsDir, toolFilesDir, recipeDir }, archive);
2179
2327
  for (const { target, stream } of inputs) {
@@ -2223,6 +2371,7 @@ async function buildInBuilder(opts, deps, prepared) {
2223
2371
  sourceCommit: checkout.commit,
2224
2372
  defaultBranch: checkout.defaultBranch,
2225
2373
  recipe: location.kind === "default" ? "default" : location.path,
2374
+ ...location.kind === "default" ? { base: { reference: `${UNIVERSAL_IMAGE_REPOSITORY}:${UNIVERSAL_IMAGE_SOURCE}`, digest: UNIVERSAL_IMAGE_DIGEST } } : {},
2226
2375
  recipeKey: prepared.recipeKey,
2227
2376
  toolsKey: prepared.toolsKey,
2228
2377
  imageId: `${ROOT_DISK_ID_PREFIX}${rKey}-${tKey}`,
@@ -2291,7 +2440,7 @@ async function buildInBuilder(opts, deps, prepared) {
2291
2440
  }
2292
2441
  const refusals = tunnel?.record().refusals ?? [];
2293
2442
  if (err instanceof StepFailed && refusals.length > 0) return new RecipeError("image_builder_failed", refusalReason(refusals, logPath), logPath);
2294
- const last = tail.filter((line) => line.trim() !== "").at(-1);
2443
+ const last = tail.filter((line2) => line2.trim() !== "").at(-1);
2295
2444
  const why = err instanceof StepFailed ? err.message : `the builder microVM failed: ${describeCallFailure(err)}`;
2296
2445
  const panicNote = enginePanic === void 0 ? "" : `; the first panic in the Docker engine's log was: ${enginePanic}`;
2297
2446
  return new RecipeError("image_builder_failed", `${why}${panicNote}${last === void 0 ? "" : `; the last line was: ${last}`}. The build log is at ${logPath}`, logPath);
@@ -2745,14 +2894,145 @@ function lifecycleFailureReason(step, exitCode) {
2745
2894
  return `lifecycle command ${step.name} (${step.source}) exited ${exitCode}`;
2746
2895
  }
2747
2896
 
2897
+ // src/runner/runtimes.ts
2898
+ var RUNTIMES = ["node", "python", "go", "rust", "ruby", "java"];
2899
+ var MANIFESTS = {
2900
+ "package.json": "node",
2901
+ "pyproject.toml": "python",
2902
+ "requirements.txt": "python",
2903
+ "go.mod": "go",
2904
+ "Cargo.toml": "rust",
2905
+ Gemfile: "ruby",
2906
+ "pom.xml": "java",
2907
+ "build.gradle": "java",
2908
+ "build.gradle.kts": "java"
2909
+ };
2910
+ var IMAGE_CONFIG = "/etc/mise/config.toml";
2911
+ var RUST_PIN_FILES = ["rust-toolchain.toml", "rust-toolchain"];
2912
+ var REFUSALS_NAMED2 = 3;
2913
+ var PLAIN = { withoutProxyWarning: true };
2914
+ function firstLine4(text) {
2915
+ return text.trim().split("\n")[0] ?? "";
2916
+ }
2917
+ function toolFailure(stderr) {
2918
+ for (const l of stderr.split("\n")) {
2919
+ if (/^\S+@\S+: /.test(l)) return l;
2920
+ const summary = /^\s*mise ✗ (\S+@\S+)\s+.*?· failed: (.+)$/.exec(l);
2921
+ if (summary !== null) return `${summary[1]}: ${summary[2]}`;
2922
+ }
2923
+ return "";
2924
+ }
2925
+ function describeSource(source, path) {
2926
+ if (source === void 0 || source === IMAGE_CONFIG) return "the image default";
2927
+ return source.startsWith(`${path}/`) ? source.slice(path.length + 1) : source;
2928
+ }
2929
+ function parseListing(stdout) {
2930
+ try {
2931
+ const parsed = JSON.parse(stdout);
2932
+ return Object.entries(parsed).flatMap(
2933
+ ([tool, versions]) => (Array.isArray(versions) ? versions : []).flatMap(
2934
+ (entry) => typeof entry.version === "string" ? [{ tool, version: entry.version, source: typeof entry.source?.path === "string" ? entry.source.path : void 0, installed: entry.installed !== false }] : []
2935
+ )
2936
+ );
2937
+ } catch {
2938
+ return void 0;
2939
+ }
2940
+ }
2941
+ async function listing(context) {
2942
+ const ran = await context.input.exec(["mise", "ls", "--current", "--json"], context.path, { quiet: true, ...PLAIN });
2943
+ return ran.status === 0 ? parseListing(ran.stdout) : void 0;
2944
+ }
2945
+ function refusalNote(context) {
2946
+ const named = context.input.refusals().slice(context.refusalsBefore).slice(0, REFUSALS_NAMED2).map((r) => r.range === "not-allowed" ? `${r.host} (not in runner.build.allowHosts)` : `${r.host} (${r.range})`);
2947
+ return named.length === 0 ? "" : `; the build's tunnel refused ${named.join(", ")}`;
2948
+ }
2949
+ function line(context, text) {
2950
+ context.input.log.line(`${context.input.tag} runtimes ${context.entry.repository}: ${text}`);
2951
+ }
2952
+ var installWithMise = async (context) => {
2953
+ const { input, entry, path } = context;
2954
+ context.before = await listing(context) ?? [];
2955
+ const installed = await input.exec(["mise", "install"], path, PLAIN);
2956
+ if (installed.status !== 0) {
2957
+ const missing = context.before.filter((r) => !r.installed).map((r) => `${r.tool} ${r.version} (from ${describeSource(r.source, path)})`);
2958
+ const what = missing.length === 0 ? `mise install failed in ${entry.repository} (exit ${installed.status})${firstLine4(installed.stderr) === "" ? "" : `: ${firstLine4(installed.stderr)}`}` : `mise could not install ${missing.join(", ")} in ${entry.repository} (exit ${installed.status})${toolFailure(installed.stderr) === "" ? "" : `: ${toolFailure(installed.stderr)}`}`;
2959
+ return `runtime_install_failed: ${what}${refusalNote(context)}`;
2960
+ }
2961
+ const after = await listing(context);
2962
+ if (after === void 0) return `runtime_install_failed: mise installed the tools but its listing failed in ${entry.repository}${refusalNote(context)}`;
2963
+ context.resolved = after;
2964
+ for (const r of context.resolved) line(context, `${r.tool} ${r.version} from ${describeSource(r.source, path)}`);
2965
+ return void 0;
2966
+ };
2967
+ var goToolchain = async (context) => {
2968
+ if (!context.files.has("go.mod")) return void 0;
2969
+ const ran = await context.input.exec(["go", "version"], context.path);
2970
+ if (ran.status !== 0) return `runtime_install_failed: go version failed in ${context.entry.repository} (exit ${ran.status})${firstLine4(ran.stderr) === "" ? "" : `: ${firstLine4(ran.stderr)}`}${refusalNote(context)}`;
2971
+ const version = /\bgo(\d+\.\d+(?:\.\d+)?\S*)/.exec(ran.stdout)?.[1];
2972
+ line(context, `go ${version ?? firstLine4(ran.stdout)} from go.mod`);
2973
+ return void 0;
2974
+ };
2975
+ var rustToolchain = async (context) => {
2976
+ const pin = RUST_PIN_FILES.find((file) => context.files.has(file));
2977
+ if (pin === void 0) return void 0;
2978
+ const ran = await context.input.exec(["rustc", "--version"], context.path);
2979
+ if (ran.status !== 0) return `runtime_install_failed: rustc --version failed in ${context.entry.repository} (exit ${ran.status})${firstLine4(ran.stderr) === "" ? "" : `: ${firstLine4(ran.stderr)}`}${refusalNote(context)}`;
2980
+ const version = /\brustc (\S+)/.exec(ran.stdout)?.[1];
2981
+ line(context, `rust ${version ?? firstLine4(ran.stdout)} from ${pin}`);
2982
+ return void 0;
2983
+ };
2984
+ var CHECKOUT_STEPS = [installWithMise, goToolchain, rustToolchain];
2985
+ function unpinnedIn(context) {
2986
+ const used = new Set([...context.files].map((file) => MANIFESTS[file]));
2987
+ const pinned = new Set(context.resolved.filter((r) => r.source?.startsWith(`${context.path}/`)).map((r) => r.tool));
2988
+ pinned.add("go");
2989
+ if (RUST_PIN_FILES.some((file) => context.files.has(file))) pinned.add("rust");
2990
+ return RUNTIMES.filter((runtime) => used.has(runtime) && !pinned.has(runtime));
2991
+ }
2992
+ async function provisionRuntimes(input) {
2993
+ const unpinned = {};
2994
+ let dropProxyWarning = false;
2995
+ for (const entry of input.repositories) {
2996
+ if (input.aborted?.() === true) return { ok: false, reason: "", aborted: true };
2997
+ const path = checkoutPath(entry);
2998
+ const listed = await input.exec(["ls", "-1", "-A"], path, { quiet: true });
2999
+ const context = {
3000
+ input,
3001
+ entry,
3002
+ path,
3003
+ files: new Set(listed.status === 0 ? listed.stdout.split("\n").map((name) => name.trim()) : []),
3004
+ refusalsBefore: input.refusals().length,
3005
+ before: [],
3006
+ resolved: []
3007
+ };
3008
+ for (const step of CHECKOUT_STEPS) {
3009
+ const reason = await step(context);
3010
+ if (reason !== void 0) return { ok: false, reason };
3011
+ }
3012
+ unpinned[entry.repository] = unpinnedIn(context);
3013
+ const old = context.resolved.find((r) => r.tool === "node" && !nodeAcceptsProxyWarningFlag(r.version));
3014
+ if (old !== void 0) {
3015
+ dropProxyWarning = true;
3016
+ line(context, `leaving ${PROXY_WARNING_FLAG} out of NODE_OPTIONS because node ${old.version} does not accept it`);
3017
+ }
3018
+ }
3019
+ return { ok: true, unpinned, dropProxyWarning };
3020
+ }
3021
+ function runtimeStepInput(report, services, dropProxyWarning) {
3022
+ return report.base === void 0 ? {} : { runtimes: { refusals: () => services.record().refusals, dropProxyWarning } };
3023
+ }
3024
+ function keepUnpinnedRuntimes(state, steps) {
3025
+ if (steps.unpinnedRuntimes !== void 0) state.unpinnedRuntimes = steps.unpinnedRuntimes;
3026
+ }
3027
+
2748
3028
  // src/runner/build-steps.ts
2749
3029
  var aborted = () => ({ ok: false, reason: "", aborted: true });
2750
- function firstLine4(text) {
3030
+ function firstLine5(text) {
2751
3031
  return text.trim().split("\n")[0] ?? "";
2752
3032
  }
2753
3033
  function gitErrorLine(text) {
2754
- const lines = text.split("\n").map((line) => line.trim()).filter((line) => line !== "");
2755
- return lines.find((line) => /^(fatal|error):/.test(line)) ?? lines.at(-1) ?? "";
3034
+ const lines = text.split("\n").map((line2) => line2.trim()).filter((line2) => line2 !== "");
3035
+ return lines.find((line2) => /^(fatal|error):/.test(line2)) ?? lines.at(-1) ?? "";
2756
3036
  }
2757
3037
  var STAGED_TREE = `${JOB_MOUNT}/context/tree`;
2758
3038
  var DELIVER_SCRIPT = [
@@ -2768,7 +3048,7 @@ var DELIVER_SCRIPT = [
2768
3048
  var RECORD_SCRIPT = 'd="$(git rev-parse --git-common-dir)" && mkdir -p "$d/outerlayer" && printf "%s" "$1" > "$d/outerlayer/delivery.json"';
2769
3049
  var WRITE_SHIM_SCRIPT = 'mkdir -p "$1" && printf "%s" "$2" > "$1/claude" && chmod 755 "$1/claude"';
2770
3050
  function failure(what, result) {
2771
- return `context_delivery_failed: ${what} (exit ${result.status})${firstLine4(result.stderr) === "" ? "" : `: ${firstLine4(result.stderr)}`}`;
3051
+ return `context_delivery_failed: ${what} (exit ${result.status})${firstLine5(result.stderr) === "" ? "" : `: ${firstLine5(result.stderr)}`}`;
2772
3052
  }
2773
3053
  async function repositorySkills(input, folder) {
2774
3054
  const listed = await input.exec(["ls", "-1", folder], CHECKOUT_DIR, { quiet: true });
@@ -2870,6 +3150,14 @@ async function runBuildSteps(input) {
2870
3150
  if (!checked.ok) return checked;
2871
3151
  }
2872
3152
  if (input.governing !== void 0) await noteIgnoredDevcontainers(input, repositories, input.governing.repository);
3153
+ let unpinnedRuntimes;
3154
+ if (input.runtimes !== void 0) {
3155
+ const ordered = [{ ...primary, primary: true }, ...repositories.filter((candidate) => candidate.repository !== primary.repository).map((entry) => ({ ...entry, primary: false }))];
3156
+ const chosen = await provisionRuntimes({ repositories: ordered, exec, log, tag, refusals: input.runtimes.refusals, aborted: input.aborted });
3157
+ if (!chosen.ok) return chosen.aborted === true ? aborted() : { ok: false, reason: chosen.reason };
3158
+ unpinnedRuntimes = chosen.unpinned;
3159
+ if (chosen.dropProxyWarning) input.runtimes.dropProxyWarning();
3160
+ }
2873
3161
  const lifecycleDir = lifecycleWorkdir(repositories, input.governing?.repository);
2874
3162
  for (const step of lifecycleSteps(input.lifecycle)) {
2875
3163
  if (input.aborted()) return aborted();
@@ -2914,7 +3202,7 @@ async function runBuildSteps(input) {
2914
3202
  }
2915
3203
  if (input.aborted()) return aborted();
2916
3204
  }
2917
- return { ok: true, startCommit, ...controlPlane === void 0 ? {} : { controlPlane } };
3205
+ return { ok: true, startCommit, ...controlPlane === void 0 ? {} : { controlPlane }, ...unpinnedRuntimes === void 0 ? {} : { unpinnedRuntimes } };
2918
3206
  }
2919
3207
  var EVAL_INPUT_NAME = "eval-input";
2920
3208
  var TRANSCRIPT_ROOT = "/build/home/.claude/projects";
@@ -2923,7 +3211,7 @@ var MAX_TRANSCRIPTS = 500;
2923
3211
  var MAX_TOTAL_TRANSCRIPT_BYTES = 64 * 1024 * 1024;
2924
3212
  var TRANSCRIPT_COPY_MS = 2 * 60 * 1e3;
2925
3213
  var BUILD_HOME = "/build/home";
2926
- function firstLine5(text) {
3214
+ function firstLine6(text) {
2927
3215
  return text.trim().split("\n")[0] ?? "";
2928
3216
  }
2929
3217
  async function copyTranscripts(run, now = Date.now) {
@@ -2935,7 +3223,7 @@ async function copyTranscripts(run, now = Date.now) {
2935
3223
  return { ok: false, reason: describeCallFailure(err) };
2936
3224
  }
2937
3225
  if (listed.status !== 0 && !/No such file or directory/.test(listed.stderr)) {
2938
- return { ok: false, reason: `listing the transcripts failed (exit ${listed.status})${firstLine5(listed.stderr) === "" ? "" : `: ${firstLine5(listed.stderr)}`}` };
3226
+ return { ok: false, reason: `listing the transcripts failed (exit ${listed.status})${firstLine6(listed.stderr) === "" ? "" : `: ${firstLine6(listed.stderr)}`}` };
2939
3227
  }
2940
3228
  const paths = listed.stdout.split("\0").filter((entry) => entry.startsWith(`${TRANSCRIPT_ROOT}/`) && !entry.includes("\n") && !entry.slice(TRANSCRIPT_ROOT.length + 1).split("/").includes("..")).map((entry) => entry.slice(TRANSCRIPT_ROOT.length + 1)).sort();
2941
3229
  const copied = [];
@@ -2952,7 +3240,7 @@ async function copyTranscripts(run, now = Date.now) {
2952
3240
  }
2953
3241
  try {
2954
3242
  const read = await run(["head", "-c", String(MAX_TRANSCRIPT_BYTES + 1), `${TRANSCRIPT_ROOT}/${path}`]);
2955
- if (read.status !== 0) missed.push({ path, reason: `reading it failed (exit ${read.status})${firstLine5(read.stderr) === "" ? "" : `: ${firstLine5(read.stderr)}`}` });
3243
+ if (read.status !== 0) missed.push({ path, reason: `reading it failed (exit ${read.status})${firstLine6(read.stderr) === "" ? "" : `: ${firstLine6(read.stderr)}`}` });
2956
3244
  else if (Buffer.byteLength(read.stdout) > MAX_TRANSCRIPT_BYTES) missed.push({ path, reason: `it is larger than ${MAX_TRANSCRIPT_BYTES / (1024 * 1024)} MiB` });
2957
3245
  else if (total + Buffer.byteLength(read.stdout) > MAX_TOTAL_TRANSCRIPT_BYTES) missed.push({ path, reason: `copying it would take the transcripts past ${MAX_TOTAL_TRANSCRIPT_BYTES / (1024 * 1024)} MiB` });
2958
3246
  else {
@@ -2996,11 +3284,11 @@ function scrubbing(scrub, author, work) {
2996
3284
  setRepoRoot(void 0);
2997
3285
  }
2998
3286
  }
2999
- function scrubLine(line) {
3287
+ function scrubLine(line2) {
3000
3288
  try {
3001
- return JSON.stringify(scrubDeep(JSON.parse(line)));
3289
+ return JSON.stringify(scrubDeep(JSON.parse(line2)));
3002
3290
  } catch {
3003
- return scrubText(line);
3291
+ return scrubText(line2);
3004
3292
  }
3005
3293
  }
3006
3294
  function writeReadOnly(path, text) {
@@ -3074,7 +3362,7 @@ async function writeEvalInput(request) {
3074
3362
  continue;
3075
3363
  }
3076
3364
  const file = `sessions/${traceId}.jsonl`;
3077
- const text = transcript.content.split("\n").filter((line) => line.trim() !== "").map(scrubLine).join("\n");
3365
+ const text = transcript.content.split("\n").filter((line2) => line2.trim() !== "").map(scrubLine).join("\n");
3078
3366
  writeReadOnly(join(dir, file), `${text}
3079
3367
  `);
3080
3368
  scrubDeep(session);
@@ -3501,8 +3789,8 @@ async function deliverTar(runtime, state, input) {
3501
3789
  { timeoutMs: DELIVERY_TIMEOUT_MS }
3502
3790
  );
3503
3791
  if (result.status === 0) return { ok: true };
3504
- const line = scrubDelivery(result.stderr.trim().split("\n")[0] ?? "", input.secrets);
3505
- return { ok: false, reason: `${input.step} could not be delivered (exit ${result.status})${line === "" ? "" : `: ${line}`}` };
3792
+ const line2 = scrubDelivery(result.stderr.trim().split("\n")[0] ?? "", input.secrets);
3793
+ return { ok: false, reason: `${input.step} could not be delivered (exit ${result.status})${line2 === "" ? "" : `: ${line2}`}` };
3506
3794
  } catch (err) {
3507
3795
  return { ok: false, reason: `${input.step} could not be delivered: ${scrubDelivery(describeCallFailure(err), input.secrets)}` };
3508
3796
  }
@@ -3625,18 +3913,18 @@ function parse(data) {
3625
3913
  const length = Number.parseInt(header, 16);
3626
3914
  if (length === 0) return { kind: "commands", commands, capabilities };
3627
3915
  if (data.length - offset < length) return { kind: "need-more" };
3628
- const line = data.subarray(offset + 4, offset + length);
3916
+ const line2 = data.subarray(offset + 4, offset + length);
3629
3917
  offset += length;
3630
3918
  if (offset > limits().sectionBytes) return refused(TOO_LONG);
3631
3919
  const first = commands.length === 0;
3632
- const nul = line.indexOf(0);
3633
- const decoded = decodeText(first && nul !== -1 ? line.subarray(0, nul) : line);
3920
+ const nul = line2.indexOf(0);
3921
+ const decoded = decodeText(first && nul !== -1 ? line2.subarray(0, nul) : line2);
3634
3922
  if (decoded === void 0) return refused(UNREADABLE);
3635
3923
  const text = decoded.replace(/\n$/, "");
3636
3924
  if (first && text.startsWith("shallow ")) continue;
3637
3925
  const match = COMMAND.exec(text);
3638
3926
  if (match === null) return refused(UNREADABLE);
3639
- if (first && nul !== -1) capabilities = line.subarray(nul + 1).toString("latin1").split(/\s+/).filter((word) => word !== "");
3927
+ if (first && nul !== -1) capabilities = line2.subarray(nul + 1).toString("latin1").split(/\s+/).filter((word) => word !== "");
3640
3928
  commands.push({ oldId: match[1], newId: match[2], ref: match[3] });
3641
3929
  }
3642
3930
  }
@@ -3790,7 +4078,7 @@ function createGitRemote(options) {
3790
4078
  const claimed = options.repositories ?? (options.repository === void 0 || options.branch === void 0 || options.mirrorDir === void 0 ? [] : [{ repository: options.repository, branch: options.branch, mirrorDir: options.mirrorDir }]);
3791
4079
  const maxLfsBodyBytes = 1024 * 1024;
3792
4080
  const hopByHop = /* @__PURE__ */ new Set(["connection", "keep-alive", "transfer-encoding", "upgrade", "proxy-authenticate", "proxy-authorization", "te", "trailer", "set-cookie"]);
3793
- const log = (line) => options.log?.(line);
4081
+ const log = (line2) => options.log?.(line2);
3794
4082
  function forward(input) {
3795
4083
  const { route, res } = input;
3796
4084
  const url = new URL(`${gitUrl}/${route.owner}/${route.name}.git/${route.kind === "info-refs" ? "info/refs" : route.kind === "lfs-batch" ? "info/lfs/objects/batch" : `git-${route.kind}`}${route.search === "" ? "" : `?${route.search}`}`);
@@ -4208,7 +4496,7 @@ function gitRemoteFor(runtime, input) {
4208
4496
  ...input.readOnly === true ? { readOnly: true } : {}
4209
4497
  });
4210
4498
  }
4211
- function firstLine6(text) {
4499
+ function firstLine7(text) {
4212
4500
  return text.trim().split("\n")[0] ?? "";
4213
4501
  }
4214
4502
  var NO_ENV = { literals: {}, passed: {} };
@@ -4272,7 +4560,7 @@ async function obtainImage(input) {
4272
4560
  };
4273
4561
  }
4274
4562
  try {
4275
- const common = { repository, configPath: config.configPath, readToken, pinned: input.pinned, log: (line) => log.line(`${tag} ${line}`) };
4563
+ const common = { repository, configPath: config.configPath, readToken, pinned: input.pinned, log: (line2) => log.line(`${tag} ${line2}`) };
4276
4564
  if (input.inBuilder !== void 0) {
4277
4565
  return { ok: true, built: await runtime.buildRootDisk({ ...input.inBuilder, ...common, guestHelper: input.guestHelper, deadlineMs: input.deadlineMs }) };
4278
4566
  }
@@ -4410,7 +4698,7 @@ async function provisionContainer(input) {
4410
4698
  }
4411
4699
  return aborted2 ? { ok: false, reason: "ended before provision finished", aborted: true } : fail(reason);
4412
4700
  };
4413
- const dockerFailed = (what, result) => bail(`${what} failed (exit ${result.status})${firstLine6(result.stderr) === "" ? "" : `: ${firstLine6(result.stderr)}`}`);
4701
+ const dockerFailed = (what, result) => bail(`${what} failed (exit ${result.status})${firstLine7(result.stderr) === "" ? "" : `: ${firstLine7(result.stderr)}`}`);
4414
4702
  if (input.aborted()) return bail("", true);
4415
4703
  mkdirSync(buildDir2, { recursive: true });
4416
4704
  const ghDir = ghConfigDir(buildDir2);
@@ -4441,8 +4729,8 @@ async function provisionContainer(input) {
4441
4729
  environment.credentials = tokens.used();
4442
4730
  let services;
4443
4731
  try {
4444
- const gitRemote = gitRemoteFor(runtime, { repositories, tokens, buildDir: buildDir2, log: (line) => log.line(`${tag} ${line}`) });
4445
- services = await startServicesFor(runtime, config, buildDir2, jobDir, itemKey, true, gitRemote, "stream", input.leaseExpiryMs === void 0 ? void 0 : leaseFor(runtime, buildId, input.leaseExpiryMs), void 0, (line) => log.line(`${tag} ${line}`));
4732
+ const gitRemote = gitRemoteFor(runtime, { repositories, tokens, buildDir: buildDir2, log: (line2) => log.line(`${tag} ${line2}`) });
4733
+ services = await startServicesFor(runtime, config, buildDir2, jobDir, itemKey, true, gitRemote, "stream", input.leaseExpiryMs === void 0 ? void 0 : leaseFor(runtime, buildId, input.leaseExpiryMs), void 0, (line2) => log.line(`${tag} ${line2}`));
4446
4734
  runtime.tunnels.set(buildId, services);
4447
4735
  } catch (err) {
4448
4736
  return bail(`the tunnel could not start: ${describeCallFailure(err)}`);
@@ -4469,7 +4757,7 @@ async function provisionContainer(input) {
4469
4757
  if (prepared.status !== 0) return dockerFailed("preparing the build's volume", prepared);
4470
4758
  const started = await host.run(containerRunArgs(runInput), { logPath });
4471
4759
  if (started.status !== 0) return dockerFailed("starting the build's container", started);
4472
- joinBuild(runtime, state, services, (line) => log.line(`${tag} ${line}`));
4760
+ joinBuild(runtime, state, services, (line2) => log.line(`${tag} ${line2}`));
4473
4761
  if (input.aborted()) return bail("", true);
4474
4762
  if (!await waitForRelay(runtime, state)) return bail("the relay in the build's container did not start");
4475
4763
  const ghDelivered = await deliverJobFiles(runtime, state, ["gh", "maven"], secrets);
@@ -4506,9 +4794,10 @@ async function provisionContainer(input) {
4506
4794
  const hashed = program.status === 0 ? parseProgramHash(program.stdout) : void 0;
4507
4795
  if (hashed !== void 0) state.judgeProgram = { path: JUDGE_PROGRAM, sha256: hashed };
4508
4796
  input.save(state, environment);
4509
- const execEnv = buildEnvironment({ ...envInput, imageEnv: state.imageEnv });
4797
+ let execEnv = buildEnvironment({ ...envInput, imageEnv: state.imageEnv });
4510
4798
  for (const notice of execEnv.notices) log.line(`${tag} ${notice}`);
4511
- const exec = (argv, workdir, opts) => host.exec({ container: name, user: agentUser, workdir, env: execEnv, argv }, opts?.quiet === true ? void 0 : { logPath });
4799
+ const plainEnv = buildEnvironment({ ...envInput, imageEnv: state.imageEnv, proxyWarning: false });
4800
+ const exec = (argv, workdir, opts) => host.exec({ container: name, user: agentUser, workdir, env: opts?.withoutProxyWarning === true ? plainEnv : execEnv, argv }, opts?.quiet === true ? void 0 : { logPath });
4512
4801
  const steps = await runBuildSteps({
4513
4802
  repository,
4514
4803
  branch: primary.branch,
@@ -4539,10 +4828,16 @@ async function provisionContainer(input) {
4539
4828
  },
4540
4829
  removeStagedContext: () => removeStagedContext(buildDir2),
4541
4830
  keepIn: jobDir,
4542
- ...input.requireBuildSkill === true ? { requireBuildSkill: true } : {}
4831
+ ...input.requireBuildSkill === true ? { requireBuildSkill: true } : {},
4832
+ // A repository with no devcontainer file builds on the universal image, whose runtimes the build chooses and installs.
4833
+ ...runtimeStepInput(report, services, () => {
4834
+ state.proxyWarningDropped = true;
4835
+ execEnv = plainEnv;
4836
+ })
4543
4837
  });
4544
4838
  if (!steps.ok) return bail(steps.reason, steps.aborted === true);
4545
4839
  state.startCommit = steps.startCommit;
4840
+ keepUnpinnedRuntimes(state, steps);
4546
4841
  if (steps.controlPlane !== void 0) environment.controlPlane = steps.controlPlane;
4547
4842
  return { ok: true, workdir: CHECKOUT_DIR, state, environment };
4548
4843
  }
@@ -4568,9 +4863,11 @@ function containerCommandExec(input) {
4568
4863
  repositories: input.job.repositories,
4569
4864
  hostEnv: input.runtime.hostEnv,
4570
4865
  containerEnv: state.containerEnv ?? {},
4866
+ unpinnedRuntimes: state.unpinnedRuntimes,
4571
4867
  builtIns: state.builtIns === true,
4572
4868
  identity: input.job.commitIdentity,
4573
- imageEnv: state.imageEnv
4869
+ imageEnv: state.imageEnv,
4870
+ proxyWarning: state.proxyWarningDropped !== true
4574
4871
  });
4575
4872
  return {
4576
4873
  container: state.container,
@@ -4592,9 +4889,11 @@ function containerSenderCommand(input) {
4592
4889
  repositories: input.job.repositories,
4593
4890
  hostEnv: input.runtime.hostEnv,
4594
4891
  containerEnv: state.containerEnv ?? {},
4892
+ unpinnedRuntimes: state.unpinnedRuntimes,
4595
4893
  builtIns: state.builtIns === true,
4596
4894
  identity: input.job.commitIdentity,
4597
- imageEnv: state.imageEnv
4895
+ imageEnv: state.imageEnv,
4896
+ proxyWarning: state.proxyWarningDropped !== true
4598
4897
  });
4599
4898
  const args = containerExecArgs({
4600
4899
  container: state.container,
@@ -4658,6 +4957,7 @@ async function startServicesFor(runtime, config, buildDir2, jobDir, itemKey, bui
4658
4957
  destinations: config.build?.destinations ?? [],
4659
4958
  // A managed build's tunnel allows the factory's hosts beside the runner's own.
4660
4959
  allowHosts: withFactoryHosts(config.build?.allowHosts, managedBuildSettingsFor(settingsDir ?? jobDir)),
4960
+ ...optionalEgress(config),
4661
4961
  serve,
4662
4962
  ...lease === void 0 ? {} : { lease },
4663
4963
  ...inherit === void 0 ? {} : { inherit },
@@ -4722,9 +5022,11 @@ async function syncInContainer(input) {
4722
5022
  repositories: job.repositories,
4723
5023
  hostEnv: runtime.hostEnv,
4724
5024
  containerEnv: state.containerEnv ?? {},
5025
+ unpinnedRuntimes: state.unpinnedRuntimes,
4725
5026
  builtIns: state.builtIns === true,
4726
5027
  identity: job.commitIdentity,
4727
- imageEnv: state.imageEnv
5028
+ imageEnv: state.imageEnv,
5029
+ proxyWarning: state.proxyWarningDropped !== true
4728
5030
  });
4729
5031
  const result = await runtime.host.exec(
4730
5032
  { container: state.container, user: state.agentUser ?? ADDED_USER, workdir: job.workdir ?? CHECKOUT_DIR, env, argv: ["outerlayer", "sync"] },
@@ -4799,7 +5101,7 @@ function containerJudgeEnvironment(input) {
4799
5101
  env: NO_ENV,
4800
5102
  argv: ["/bin/sh", "-c", `[ -f ${file} ] && [ ! -L ${file} ] && head -c ${maxBytes + 1} ${file}`]
4801
5103
  }, { timeoutMs: REPORT_READ_TIMEOUT_MS });
4802
- if (read.status > 1) throw new Error(`reading the judge's ${name} exited ${read.status}: ${firstLine6(read.stderr)}`);
5104
+ if (read.status > 1) throw new Error(`reading the judge's ${name} exited ${read.status}: ${firstLine7(read.stderr)}`);
4803
5105
  return read.status === 0 && Buffer.byteLength(read.stdout) <= maxBytes ? read.stdout : void 0;
4804
5106
  };
4805
5107
  return {
@@ -4817,7 +5119,7 @@ function containerJudgeEnvironment(input) {
4817
5119
  hashProgram: async () => {
4818
5120
  const ran = await runtime.host.exec({ container: state.container, user: ADDED_USER, env: NO_ENV, argv: [...HASH_ARGV] });
4819
5121
  const sha256 = ran.status === 0 ? parseProgramHash(ran.stdout) : void 0;
4820
- return sha256 === void 0 ? { ok: false, reason: firstLine6(ran.stderr) || `the hash could not be taken (exit ${ran.status})` } : { ok: true, sha256 };
5122
+ return sha256 === void 0 ? { ok: false, reason: firstLine7(ran.stderr) || `the hash could not be taken (exit ${ran.status})` } : { ok: true, sha256 };
4821
5123
  },
4822
5124
  prepare: async (files, tree) => {
4823
5125
  if (filesAreCopied(state)) {
@@ -4850,7 +5152,7 @@ function containerJudgeEnvironment(input) {
4850
5152
  // host. Every capability is dropped in the container, so root there could not either; the build's user removes its own, and the runner removes the rest.
4851
5153
  clear: async () => {
4852
5154
  const removed = await runtime.host.exec({ container: state.container, user, env: NO_ENV, argv: ["find", JUDGE_DIR, "-mindepth", "1", "-user", user, "-delete"] });
4853
- if (removed.status !== 0) throw new Error(`find exited ${removed.status}: ${firstLine6(removed.stderr)}`);
5155
+ if (removed.status !== 0) throw new Error(`find exited ${removed.status}: ${firstLine7(removed.stderr)}`);
4854
5156
  if (!filesAreCopied(state)) return;
4855
5157
  const emptied = await clearJudgeFolder(runtime, state, secretsOf(runtime, input.jobDir));
4856
5158
  if (!emptied.ok) throw new Error(emptied.reason);
@@ -4906,7 +5208,7 @@ async function startCheckContainer(input) {
4906
5208
  }
4907
5209
  return { ok: false, reason };
4908
5210
  };
4909
- const dockerFailed = (what, result) => fail(`${what} failed (exit ${result.status})${firstLine6(result.stderr) === "" ? "" : `: ${firstLine6(result.stderr)}`}`);
5211
+ const dockerFailed = (what, result) => fail(`${what} failed (exit ${result.status})${firstLine7(result.stderr) === "" ? "" : `: ${firstLine7(result.stderr)}`}`);
4910
5212
  mkdirSync(buildDir2, { recursive: true });
4911
5213
  if (!filesAreCopied(state)) chmodSync(buildDir2, 493);
4912
5214
  let services;
@@ -4915,7 +5217,7 @@ async function startCheckContainer(input) {
4915
5217
  repositories: repositoriesOf({ repositories: job.repositories, repository, branch: job.branch }),
4916
5218
  tokens,
4917
5219
  buildDir: buildDir2,
4918
- log: (line) => log.line(`${tag} ${line}`),
5220
+ log: (line2) => log.line(`${tag} ${line2}`),
4919
5221
  readOnly: true
4920
5222
  });
4921
5223
  services = await startServicesFor(runtime, config, buildDir2, checksDir, void 0, false, gitRemote, transport === "exec" ? "stream" : "socket");
@@ -4944,7 +5246,7 @@ async function startCheckContainer(input) {
4944
5246
  if (prepared.status !== 0) return dockerFailed("preparing the check environment's volume", prepared);
4945
5247
  const started = await host.run(containerRunArgs(runInput), { logPath });
4946
5248
  if (started.status !== 0) return dockerFailed("starting the check environment's container", started);
4947
- if (transport === "exec") joinBuild(runtime, state, services, (line) => log.line(`${tag} ${line}`));
5249
+ if (transport === "exec") joinBuild(runtime, state, services, (line2) => log.line(`${tag} ${line2}`));
4948
5250
  if (!await waitForRelay(runtime, state)) return fail("the relay in the check environment's container did not start");
4949
5251
  const env = checkEnvironment({ config, item: job.item, repository, hostEnv: runtime.hostEnv, containerEnv: built.containerEnv ?? {}, imageEnv: built.imageEnv });
4950
5252
  const secrets = () => tokens.issuedTokens();
@@ -4973,7 +5275,7 @@ async function startCheckContainer(input) {
4973
5275
  await host.stop(name);
4974
5276
  const again = await host.start(name);
4975
5277
  if (again.status !== 0 || !await waitForRelay(runtime, state)) return false;
4976
- rejoinBuild(runtime, state, (line) => log.line(`${tag} ${line}`));
5278
+ rejoinBuild(runtime, state, (line2) => log.line(`${tag} ${line2}`));
4977
5279
  if (delivered) {
4978
5280
  const again2 = await deliverInput();
4979
5281
  if (!again2.ok) {
@@ -4990,8 +5292,8 @@ async function startCheckContainer(input) {
4990
5292
  // src/runner/machine.ts
4991
5293
  function groupName(gid) {
4992
5294
  try {
4993
- for (const line of readFileSync("/etc/group", "utf8").split("\n")) {
4994
- const [name, , id] = line.split(":");
5295
+ for (const line2 of readFileSync("/etc/group", "utf8").split("\n")) {
5296
+ const [name, , id] = line2.split(":");
4995
5297
  if (name !== void 0 && Number(id) === gid) return name;
4996
5298
  }
4997
5299
  } catch {
@@ -5086,4 +5388,4 @@ function describeMachineDocker(machine) {
5086
5388
  return `Docker Engine ${version ?? "of no known version"}, older than the ${MIN_ENGINE_MAJOR} that container builds need`;
5087
5389
  }
5088
5390
 
5089
- export { ADDED_USER, ADOPTED_FETCH_RETRY_WINDOW_MS, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, HELPER_ENV, LEASE_SECONDS, MANAGED_UNJAILED_REASON, MIN_ENGINE_MAJOR, PLACEHOLDER_MARKER, ROOT_DISK_ID_PREFIX, RunnerInitError, attemptNote, claimPermissionProblem, claudeCredentialCheck, cleanupContainer, closeHostBuild, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, createLeaseChannel, currentSkillCommand, decideHostBuildSkill, deleteBuildDisk, deliverContainerHooks, deliverExecMaven, describeMachineDocker, detectMachine, dropManagedBuildSettings, dropManagedClaudeKey, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, execArgv, execCommandLine, fetchManagedBuildSettings, fetchManagedClaudeKey, filesAreCopied, formerSkillProblem, formerSkillQueues, ghHostsYml, gitRemoteFor, hasClaudeCredential, helperFirecrackerNote, helperSocketPath, holdManagedBuildSettings, holdManagedClaudeKey, hostCommandEnvironment, hostEnvironment, isPlaceholderCommand, keepGhConfigCurrent, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, listenOnBroker, machineConfig, makeBuildsDirPrivate, managedBuildSettingValues, managedBuildSettingsFor, managedClaudeKeyFor, managedClaudeKeyValues, managedMachineLimits, measureDisk, microVmArchSupported, microVmAssetsPinned, missingPermissionFix, missingPermissionOf, needsBuildSkill, needsClaudeCredential, obtainImage, outOfMemoryReason, parseCpuList, permissionModeProblem, permissionModeProblems, placeholderProblem, placeholderQueues, prepareBranch, prepareRunnerInit, probeHelper, provisionContainer, provisionEnvironment, reachDockerStep, readConfigObject, resolveAgentUser, resolveHostBuild, runBuildSteps, runRunnerInit, runWithSpawn, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startHostServices, startJailedInto, startServicesFor, stopContainer, stopJailed, supportsContainerBuilds, supportsMicroVmBuilds, sweepImageBuilders, syncInContainer, withFactoryHosts, withTunnelLog, writeEvalInput, writeRunnerInit };
5391
+ export { ADDED_USER, ADOPTED_FETCH_RETRY_WINDOW_MS, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, HELPER_ENV, LEASE_SECONDS, MANAGED_UNJAILED_REASON, MIN_ENGINE_MAJOR, PLACEHOLDER_MARKER, ROOT_DISK_ID_PREFIX, RunnerInitError, attemptNote, claimPermissionProblem, claudeCredentialCheck, cleanupContainer, closeHostBuild, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, createLeaseChannel, currentSkillCommand, decideHostBuildSkill, deleteBuildDisk, deliverContainerHooks, deliverExecMaven, describeMachineDocker, detectMachine, dropManagedBuildSettings, dropManagedClaudeKey, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, execArgv, execCommandLine, fetchManagedBuildSettings, fetchManagedClaudeKey, filesAreCopied, formerSkillProblem, formerSkillQueues, ghHostsYml, gitRemoteFor, hasClaudeCredential, helperFirecrackerNote, helperSocketPath, holdManagedBuildSettings, holdManagedClaudeKey, hostCommandEnvironment, hostEnvironment, isPlaceholderCommand, keepGhConfigCurrent, keepUnpinnedRuntimes, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, listenOnBroker, machineConfig, makeBuildsDirPrivate, managedBuildSettingValues, managedBuildSettingsFor, managedClaudeKeyFor, managedClaudeKeyValues, managedMachineLimits, measureDisk, microVmArchSupported, microVmAssetsPinned, missingPermissionFix, missingPermissionOf, needsBuildSkill, needsClaudeCredential, obtainImage, outOfMemoryReason, parseCpuList, permissionModeProblem, permissionModeProblems, placeholderProblem, placeholderQueues, prepareBranch, prepareRunnerInit, probeHelper, provisionContainer, provisionEnvironment, reachDockerStep, readConfigObject, resolveAgentUser, resolveHostBuild, runBuildSteps, runRunnerInit, runWithSpawn, runtimeStepInput, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startHostServices, startJailedInto, startServicesFor, stopContainer, stopJailed, supportsContainerBuilds, supportsMicroVmBuilds, sweepImageBuilders, syncInContainer, withFactoryHosts, withTunnelLog, writeEvalInput, writeRunnerInit };