@outerlayer/cli 0.19.1 → 0.22.0

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 (146) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +26 -7
  3. package/dist/{agent-setup-AM42SA2D.js → agent-setup-XAJH6MPW.js} +13 -12
  4. package/dist/build-GTMEADQD.js +12 -0
  5. package/dist/build-command-ND2ENDBS.js +50 -0
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-C4QNTYMS.js → builder-OAUSTZHL.js} +7 -5
  8. package/dist/{check-W2JGXN3B.js → check-3YHMJQ3P.js} +48 -50
  9. package/dist/{chunk-F2KXHIFI.js → chunk-22DYXLU7.js} +360 -66
  10. package/dist/{chunk-P53VEAOF.js → chunk-2CMJLYV6.js} +1 -1
  11. package/dist/{chunk-FBTGMSQF.js → chunk-2HT2XGJX.js} +16 -9
  12. package/dist/{chunk-S5PCA3SN.js → chunk-2J5JGLW5.js} +1 -1
  13. package/dist/{chunk-R22NZSGA.js → chunk-34XORKFD.js} +9 -9
  14. package/dist/{chunk-QOZKPLVJ.js → chunk-3W333NFO.js} +40 -1
  15. package/dist/{chunk-HOKXGFDR.js → chunk-4JHVPFH6.js} +22 -16
  16. package/dist/{chunk-AMFWYESY.js → chunk-4NM3I3VV.js} +1 -1
  17. package/dist/{chunk-PIZRPNKR.js → chunk-4QKLMNI3.js} +5 -5
  18. package/dist/{chunk-NNLA7LLQ.js → chunk-5OCIHFGE.js} +29 -5
  19. package/dist/{chunk-PSN33ERW.js → chunk-6IO62VJS.js} +3 -3
  20. package/dist/{chunk-7YP7T6GV.js → chunk-7V7KG3YM.js} +2 -2
  21. package/dist/{chunk-QNLX477Q.js → chunk-AEKSX4EY.js} +165 -72
  22. package/dist/{chunk-JHGEBPLE.js → chunk-ATRIVTRE.js} +3 -3
  23. package/dist/{chunk-X5H2WYMB.js → chunk-BLW6GPBZ.js} +1 -1
  24. package/dist/{chunk-MLAAT4S6.js → chunk-C3HKR67W.js} +3 -3
  25. package/dist/{chunk-XZ4H4X5F.js → chunk-C3OVGKVJ.js} +15 -8
  26. package/dist/{chunk-BM63HB2M.js → chunk-EAQSOE62.js} +2 -2
  27. package/dist/{chunk-LW7G5TJB.js → chunk-EXV37PKS.js} +2 -2
  28. package/dist/{chunk-B6SCN5NY.js → chunk-FGW2774C.js} +175 -44
  29. package/dist/{chunk-KYS3TQAG.js → chunk-G2WME4RG.js} +4 -4
  30. package/dist/{chunk-LRG3ZMZD.js → chunk-G6DZCKA6.js} +4 -4
  31. package/dist/chunk-GISNHSYL.js +41 -0
  32. package/dist/{chunk-G2YNJIGF.js → chunk-HCVLP7XA.js} +10 -1
  33. package/dist/{chunk-QEFKA2QD.js → chunk-I66MQDXH.js} +2 -2
  34. package/dist/{chunk-3CWUOFV6.js → chunk-IRBNIRQJ.js} +12 -7
  35. package/dist/{chunk-CG36IONK.js → chunk-JRCSET55.js} +2 -2
  36. package/dist/{chunk-CGGPS7SI.js → chunk-JVB63NIB.js} +5 -5
  37. package/dist/{chunk-M2ZWWTWZ.js → chunk-KDHYLBRR.js} +1 -1
  38. package/dist/{chunk-N2PXGQRL.js → chunk-KIGSGZBB.js} +1 -1
  39. package/dist/{chunk-EAEELQVQ.js → chunk-KOQELWQ6.js} +5 -5
  40. package/dist/{chunk-MTP2QEVO.js → chunk-KPBQYEND.js} +1 -1
  41. package/dist/{chunk-VYAL7PUE.js → chunk-LOB2SUM3.js} +1 -1
  42. package/dist/{chunk-GGOMT6KF.js → chunk-PHHBYAL6.js} +1 -1
  43. package/dist/{chunk-IF2OSI5T.js → chunk-QOALB6ZD.js} +2 -2
  44. package/dist/{chunk-BWSUPRDK.js → chunk-TPKYTORP.js} +1 -1
  45. package/dist/{chunk-XNGMQ27R.js → chunk-UD3EXMKB.js} +2 -2
  46. package/dist/{chunk-7UWVLZXD.js → chunk-USWVXQIH.js} +1 -1
  47. package/dist/{chunk-BQXFBI7T.js → chunk-V7MQKOZY.js} +32 -7
  48. package/dist/{chunk-6X4SQ5MY.js → chunk-V7SAQ645.js} +1 -1
  49. package/dist/{chunk-TWF3RICI.js → chunk-VSUXCMMH.js} +110 -11
  50. package/dist/{chunk-FVMYKL6L.js → chunk-VWLOQ6FI.js} +1 -1
  51. package/dist/{chunk-3ZR7Y23Y.js → chunk-VX74ND77.js} +650 -70
  52. package/dist/{chunk-Z7K3L4FC.js → chunk-W3SWJ2TD.js} +2 -2
  53. package/dist/chunk-WERZMIKA.js +718 -0
  54. package/dist/{chunk-GEMQLBMW.js → chunk-WMHYIBJW.js} +6 -6
  55. package/dist/{chunk-5VML45HH.js → chunk-XCRZTXRL.js} +2 -2
  56. package/dist/{chunk-ECODQ7II.js → chunk-ZFLOGMUC.js} +1 -1
  57. package/dist/chunk-ZNPE7FW5.js +137 -0
  58. package/dist/claude-launcher-4BQNXYAF.js +267 -0
  59. package/dist/{cli-EXX2R73G.js → cli-NMGVZQPB.js} +189 -119
  60. package/dist/{command-ZQNEPDS6.js → command-GE62AJZY.js} +32 -34
  61. package/dist/{config-CLSGABD5.js → config-7Q52COZ3.js} +3 -2
  62. package/dist/{connect-cmd-UNYKGDAL.js → connect-cmd-ZFOK6HEL.js} +5 -5
  63. package/dist/{context-cleanup-CHEWNYU6.js → context-cleanup-DSA3HGQU.js} +1 -1
  64. package/dist/{control-plane-launch-34LNRJWR.js → control-plane-launch-SZTE4TUS.js} +62 -28
  65. package/dist/{dist-WO7NOJNG.js → dist-7IH56ELA.js} +1 -1
  66. package/dist/{docker-BFU3AQGY.js → docker-2OVBKVRK.js} +7 -7
  67. package/dist/{doctor-DHUM5DBB.js → doctor-3SQGZVYP.js} +35 -36
  68. package/dist/{emit-artifact-cmd-XBHM647X.js → emit-artifact-cmd-R42BE6ID.js} +19 -18
  69. package/dist/{emit-cmd-W55AEBCA.js → emit-cmd-3W5IO5ET.js} +3 -3
  70. package/dist/{emit-criteria-cmd-CRTYEF7D.js → emit-criteria-cmd-MQZE7W4Y.js} +52 -16
  71. package/dist/{emit-finding-cmd-7JHVRYOP.js → emit-finding-cmd-ZS5JEGGM.js} +13 -12
  72. package/dist/{emit-result-cmd-5NZMLCJK.js → emit-result-cmd-FUE3DXBW.js} +19 -18
  73. package/dist/{emit-step-cmd-347XNGPQ.js → emit-step-cmd-T7PRA44X.js} +14 -13
  74. package/dist/{exec-client-7UMESIE2.js → exec-client-YIDTWXMZ.js} +4 -3
  75. package/dist/{governing-source-HAA4OW57.js → governing-source-TORXL4I4.js} +19 -18
  76. package/dist/{guest-init-KPBQOFE5.js → guest-init-TO6HAWIT.js} +4 -3
  77. package/dist/{hook-fast-RL5E5OXE.js → hook-fast-WFB2ZMRB.js} +2 -2
  78. package/dist/host-key-2LXQDSBO.js +9 -0
  79. package/dist/{import-capture-cmd-TK4XY7RD.js → import-capture-cmd-Q56DDZVO.js} +1 -1
  80. package/dist/index.js +5 -5
  81. package/dist/init-2CRAVIUU.js +52 -0
  82. package/dist/{init-V6FOMD2V.js → init-AHDZCMDC.js} +32 -33
  83. package/dist/{init-cmd-Z4O4PPLZ.js → init-cmd-IXDL2ZSL.js} +25 -23
  84. package/dist/{init-update-7DVAKWW3.js → init-update-YB3PODDH.js} +69 -24
  85. package/dist/{install-4SEFIIW2.js → install-CZUIW2AF.js} +5 -4
  86. package/dist/{install-cmd-QDOTR4OM.js → install-cmd-Q7RJGFUO.js} +6 -5
  87. package/dist/{login-browser-DX35MARZ.js → login-browser-BN5UKPHS.js} +3 -3
  88. package/dist/{logout-cmd-5V5MMBSY.js → logout-cmd-RZFWTNYD.js} +2 -2
  89. package/dist/{logs-AMLKC3VP.js → logs-RJPYTVQE.js} +3 -2
  90. package/dist/loop-ZDW6TRAA.js +75 -0
  91. package/dist/machine-JCOHLASP.js +47 -0
  92. package/dist/{mcp-install-cmd-GGWB3JJ2.js → mcp-install-cmd-GD4QUP7Z.js} +2 -2
  93. package/dist/{mcp-serve-cmd-N3UTY6EE.js → mcp-serve-cmd-IULQPVHL.js} +6 -5
  94. package/dist/{paths-7XP63OAX.js → paths-N3LU4O2Z.js} +3 -2
  95. package/dist/pending-GRCV3ZR4.js +9 -0
  96. package/dist/{pidfile-3DM4OBKO.js → pidfile-IF3TCL5A.js} +4 -3
  97. package/dist/receive-files-T2BIUBQL.js +254 -0
  98. package/dist/{record-3WP6V2K5.js → record-73PQE77B.js} +4 -3
  99. package/dist/relay-PSZ4LGMW.js +210 -0
  100. package/dist/relay-protocol-K7KP2SPI.js +6 -0
  101. package/dist/{runner-env-FRZFFHDF.js → runner-env-LDOBJESN.js} +6 -5
  102. package/dist/runner-identity-RWCBTY2A.js +14 -0
  103. package/dist/{runner-key-5FOWCW7J.js → runner-key-HMYLP6WN.js} +32 -33
  104. package/dist/{session-sender-U2BBUWNO.js → session-sender-2G25JYHI.js} +20 -19
  105. package/dist/{spec-cmd-FVLJOFGC.js → spec-cmd-LBVXM6XS.js} +13 -12
  106. package/dist/{starter-pack-6LQVLBIA.js → starter-pack-5EQYGSJF.js} +2 -2
  107. package/dist/{status-BINH7MBG.js → status-QZB2GWXJ.js} +36 -38
  108. package/dist/{statusline-fast-KN3BX67H.js → statusline-fast-2OK3DVAA.js} +2 -2
  109. package/dist/{sync-cmd-VXOUFS4I.js → sync-cmd-TQQIR4PN.js} +19 -18
  110. package/dist/{watch-OH645CV2.js → watch-4JES4PCS.js} +19 -18
  111. package/dist/{work-claim-cmd-ZRPSHMPT.js → work-claim-cmd-XG6O7B63.js} +17 -16
  112. package/dist/{work-cmd-5I3J2XQQ.js → work-cmd-L6WMPAA2.js} +13 -12
  113. package/dist/{work-comment-cmd-UCCPWUSR.js → work-comment-cmd-SNTDCPGH.js} +13 -12
  114. package/dist/{work-logs-cmd-7352CJPG.js → work-logs-cmd-3S7IAVII.js} +13 -12
  115. package/dist/{work-open-pr-cmd-LSH4VHJM.js → work-open-pr-cmd-E3WMO5XT.js} +15 -14
  116. package/dist/{work-pr-cmd-H4OQR26N.js → work-pr-cmd-22T6FG4T.js} +14 -13
  117. package/dist/work-stop-cmd-WR7ESS4Z.js +53 -0
  118. package/package.json +2 -2
  119. package/skill-pack/maintained/outerlayer-build/SKILL.md +347 -0
  120. package/skill-pack/{template/build → maintained/outerlayer-build}/references/evidence.md +2 -2
  121. package/skill-pack/{template/build → maintained/outerlayer-build}/references/release.md +4 -4
  122. package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-loop.md +3 -1
  123. package/skill-pack/shipped.json +2 -0
  124. package/skill-pack/template/build/SKILL.md +4 -253
  125. package/skill-pack/validators/acceptance-criteria.yaml +1 -1
  126. package/dist/build-TQ6X5PYN.js +0 -12
  127. package/dist/chunk-3UZTIRLF.js +0 -320
  128. package/dist/chunk-CX22S5BA.js +0 -45
  129. package/dist/chunk-LLM3I5YU.js +0 -89
  130. package/dist/chunk-SADUQSO4.js +0 -50
  131. package/dist/chunk-VMJPFQNE.js +0 -261
  132. package/dist/claude-launcher-J5M44PFS.js +0 -115
  133. package/dist/host-key-U4B5QETR.js +0 -8
  134. package/dist/init-XG47KCI4.js +0 -53
  135. package/dist/loop-TPUYUMSY.js +0 -77
  136. package/dist/machine-TRHBT5NE.js +0 -48
  137. package/dist/pending-532ABZYC.js +0 -8
  138. package/dist/relay-L76HDX72.js +0 -46
  139. package/dist/{chunk-YVZJ6GKF.js → chunk-DIB2WLBL.js} +1 -1
  140. package/dist/{chunk-GOSFARMS.js → chunk-F35VMF5M.js} +1 -1
  141. package/dist/{chunk-DSF2FWAZ.js → chunk-IZSVXRDR.js} +1 -1
  142. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/agent-briefs.md +0 -0
  143. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/criteria-judge.md +0 -0
  144. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-briefs.md +0 -0
  145. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/criterion-citations.mjs +0 -0
  146. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/record-criteria.mjs +0 -0
@@ -1,38 +1,98 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { writeJobFile, readJobFile } from './chunk-SADUQSO4.js';
4
- import { senderPidfile } from './chunk-JHGEBPLE.js';
5
- import { DOCKERD_LOG, HELPER_PATH, HELPER_RECORD } from './chunk-XNGMQ27R.js';
6
- import { installScrubContext } from './chunk-R22NZSGA.js';
7
- import { AssetError, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createBuildDisk, machineConfig, resolveAgentUser, AgentUserError, runBuildSteps, shellQuote, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, containerSenderCommand, syncInContainer, copyTranscriptsFromContainer, GH_CONFIG_YML, ghHostsYml, ADDED_USER, isLiteralAddress, signalInContainer, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript, containerJudgeEnvironment, copyJudgeTree } from './chunk-3ZR7Y23Y.js';
8
- import { childEnvironment } from './chunk-VMJPFQNE.js';
9
- import { HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, judgeCommand, MAX_REPORT_BYTES, JUDGE_MAX_TURNS, JUDGE_DIR } from './chunk-3UZTIRLF.js';
10
- import { waitForAgent, vmExecArgs } from './chunk-GGOMT6KF.js';
11
- import { socketPathProblem, vsockLinks, linkVsockSockets } from './chunk-X5H2WYMB.js';
12
- import { describeCallFailure, resolveGoverningSource, refusalCode, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, logStamp, createRunnerLog, formatDuration, retrySend, formatClock } from './chunk-XZ4H4X5F.js';
13
- import { WorkCommandError, postJson, isSignatureRefusal, getJson } from './chunk-FBTGMSQF.js';
3
+ import { senderPidfile } from './chunk-ATRIVTRE.js';
4
+ import { DOCKERD_LOG, HELPER_PATH, HELPER_RECORD } from './chunk-UD3EXMKB.js';
5
+ import { installScrubContext } from './chunk-34XORKFD.js';
6
+ import { ADDED_USER, AssetError, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createBuildDisk, machineConfig, resolveAgentUser, AgentUserError, runBuildSteps, shellQuote, LEASE_SECONDS, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, containerSenderCommand, signalInContainer, syncInContainer, copyTranscriptsFromContainer, senderAliveScript, GH_CONFIG_YML, ghHostsYml, isLiteralAddress, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, DeliveryFailure, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript, containerJudgeEnvironment, copyJudgeTree } from './chunk-VX74ND77.js';
7
+ import { readBranchHead, fetchCommit, diffBetween } from './chunk-IRBNIRQJ.js';
8
+ import { HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, writeJobFile, readJobFile, COMMAND_DIR, childEnvironment, judgeCommand, JUDGE_MAX_TURNS, MAX_REPORT_BYTES, JUDGE_DIR } from './chunk-WERZMIKA.js';
9
+ import { CLAUDE_CODE_VERSION } from './chunk-3W333NFO.js';
10
+ import { waitForAgent, vmExecArgs } from './chunk-PHHBYAL6.js';
11
+ import { socketPathProblem, vsockLinks, linkVsockSockets } from './chunk-BLW6GPBZ.js';
12
+ import { describeCallFailure, resolveGoverningSource, refusalCode, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, logStamp, createRunnerLog, formatDuration, retrySend, formatClock } from './chunk-C3OVGKVJ.js';
13
+ import { WorkCommandError, postJson, isSignatureRefusal, getJson } from './chunk-2HT2XGJX.js';
14
14
  import { planArtifactUpload } from './chunk-G3IJ3N6F.js';
15
- import { isBuiltinContainer, isBuiltinProcess, isBuiltinVm, DEFAULT_CHECK_TIME_LIMIT_MINUTES } from './chunk-P53VEAOF.js';
15
+ import { isBuiltinContainer, isBuiltinProcess, isBuiltinVm, DEFAULT_CHECK_TIME_LIMIT_MINUTES } from './chunk-2CMJLYV6.js';
16
16
  import { parseSize } from './chunk-7RQ73DLO.js';
17
- import { readBranchHead, fetchCommit, diffBetween } from './chunk-3CWUOFV6.js';
18
- import { CLAUDE_CODE_VERSION } from './chunk-CX22S5BA.js';
19
17
  import { isSameProcess, startTimeOf } from './chunk-JBJTC3UU.js';
20
- import { scrubText } from './chunk-QNLX477Q.js';
21
- import { resolvePackRoot } from './chunk-NNLA7LLQ.js';
18
+ import { scrubText } from './chunk-AEKSX4EY.js';
22
19
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
20
+ import { resolvePackRoot } from './chunk-5OCIHFGE.js';
23
21
  import { parsePolicy } from './chunk-WFSUUUAN.js';
24
22
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
25
23
  import { resolveVersion } from './chunk-RA3O54FC.js';
26
- import { signerFor } from './chunk-M2ZWWTWZ.js';
27
- import { runnerDir, buildDir, vsockPath, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
28
- import { claudeCredential, repositoriesOf, primaryOf, buildEnvironment, JOB_MOUNT, CHECKOUT_DIR, parseIsolation, proxyEnvironment, withProxyWarningHidden, containerLocalAddress, destinationEnvironment, CLAUDE_CREDENTIAL_VARIABLES, builtInEnvironment, withHooksPath, startBuildServices, BUILT_IN_NAMES, AGENT_CREDENTIAL_MISSING, sharedUserEnvironment, headerVariables, authorEnvironment, withTunnelRecord, commitIdentityRecord, RELAY_PORT, repositoryPath, lifecycleWorkdir, checkEnvironment, EVAL_INPUT_DIR } from './chunk-BQXFBI7T.js';
24
+ import { signerFor } from './chunk-KDHYLBRR.js';
25
+ import { RUNNER_FILE_MODE, runnerDir, buildDir, vsockPath } from './chunk-KIGSGZBB.js';
26
+ import { claudeCredential, repositoriesOf, primaryOf, buildEnvironment, JOB_MOUNT, CHECKOUT_DIR, parseIsolation, proxyEnvironment, withProxyWarningHidden, containerLocalAddress, destinationEnvironment, CLAUDE_CREDENTIAL_VARIABLES, builtInEnvironment, withHooksPath, startBuildServices, BUILT_IN_NAMES, AGENT_CREDENTIAL_MISSING, sharedUserEnvironment, headerVariables, authorEnvironment, withTunnelRecord, commitIdentityRecord, RELAY_PORT, repositoryPath, lifecycleWorkdir, checkEnvironment, EVAL_INPUT_DIR } from './chunk-V7MQKOZY.js';
27
+ import { RUNNER_WORDED_REASONS, UNKNOWN_TRACKING_REASON } from './chunk-GISNHSYL.js';
28
+ import { existsSync, statSync, appendFileSync, mkdirSync, chmodSync, writeFileSync, accessSync, constants, openSync, readFileSync, closeSync, rmSync, readdirSync, lstatSync, fstatSync, readSync, realpathSync } from 'fs';
29
+ import { join, isAbsolute, dirname, delimiter, sep } from 'path';
29
30
  import { spawn, spawnSync } from 'child_process';
30
31
  import { randomBytes, createHash } from 'crypto';
31
- import { mkdirSync, chmodSync, writeFileSync, appendFileSync, statSync, accessSync, constants, openSync, existsSync, readFileSync, closeSync, rmSync, readdirSync, lstatSync, fstatSync, readSync, realpathSync } from 'fs';
32
- import { join, isAbsolute, dirname, delimiter, sep } from 'path';
33
32
  import { pathToFileURL } from 'url';
34
33
 
35
34
  createRequire(import.meta.url);
35
+ var PROBE_TIMEOUT_MS = 3e4;
36
+ var PROBE_BYTES = 256 * 1024;
37
+ var PROBE_SCRIPT = `d=${COMMAND_DIR}
38
+ code=$(cat "$d/exit-code" 2>/dev/null | tr -d ' \\r\\n')
39
+ pid=$(cat "$d/command.pid" 2>/dev/null | tr -d ' \\r\\n')
40
+ alive=0
41
+ if [ -n "$pid" ] && grep -qa build-command "/proc/$pid/cmdline" 2>/dev/null; then alive=1; fi
42
+ size=$(wc -c < "$d/command.log" 2>/dev/null || echo 0)
43
+ size=$(echo $size)
44
+ echo "OL-COMMAND exit=$code alive=$alive size=$size"
45
+ n=$((size - $1))
46
+ if [ "$n" -gt "$2" ]; then n=$2; fi
47
+ if [ "$n" -gt 0 ]; then tail -c +$(($1 + 1)) "$d/command.log" | head -c "$n" | base64 | tr -d '\\n'; fi
48
+ echo
49
+ `;
50
+ function probeArgv(offset) {
51
+ return ["/bin/sh", "-c", PROBE_SCRIPT, "probe", String(offset), String(PROBE_BYTES)];
52
+ }
53
+ function parseProbe(stdout) {
54
+ const [header = "", body = ""] = stdout.split("\n");
55
+ const match = /^OL-COMMAND exit=(\d*) alive=([01]) size=(\d+)$/.exec(header);
56
+ if (match === null) return void 0;
57
+ return {
58
+ ...match[1] === "" ? {} : { exitCode: Number(match[1]) },
59
+ alive: match[2] === "1",
60
+ size: Number(match[3]),
61
+ bytes: Buffer.from(body.trim(), "base64")
62
+ };
63
+ }
64
+ async function probeCommand(runtime, state, offset) {
65
+ const result = await runtime.host.exec({
66
+ container: state.container,
67
+ user: state.agentUser ?? ADDED_USER,
68
+ env: { literals: {}, passed: {} },
69
+ argv: probeArgv(offset)
70
+ }, { timeoutMs: PROBE_TIMEOUT_MS });
71
+ return result.status === 0 ? parseProbe(result.stdout) : void 0;
72
+ }
73
+ async function copyCommandLogTail(runtime, state, jobDir) {
74
+ for (let reads = 0; reads < MAX_TAIL_READS; reads++) {
75
+ const offset = commandLogOffset(jobDir, state.commandLogBase);
76
+ const probe = await probeCommand(runtime, state, offset);
77
+ if (probe === void 0) return false;
78
+ appendCommandLog(jobDir, probe.bytes);
79
+ if (probe.bytes.length === 0 || offset + probe.bytes.length >= probe.size) return true;
80
+ }
81
+ return false;
82
+ }
83
+ var MAX_TAIL_READS = 8;
84
+ function commandLogOffset(jobDir, base) {
85
+ const path = join(jobDir, "command.log");
86
+ return existsSync(path) ? Math.max(0, statSync(path).size - (base ?? 0)) : 0;
87
+ }
88
+ function appendCommandLog(jobDir, bytes) {
89
+ if (bytes.length > 0) appendFileSync(join(jobDir, "command.log"), bytes, { mode: RUNNER_FILE_MODE });
90
+ }
91
+ function judgeProbe(probe, missedBefore) {
92
+ if (probe.exitCode !== void 0) return { kind: "exited", code: probe.exitCode };
93
+ if (probe.alive) return { kind: "running" };
94
+ return missedBefore ? { kind: "lost" } : { kind: "recheck" };
95
+ }
36
96
  var DEFAULT_MEMORY = "8g";
37
97
  var DEFAULT_DISK = "40g";
38
98
  var DEFAULT_CPUS = 4;
@@ -1460,10 +1520,14 @@ async function runHostChecks(input) {
1460
1520
  fetchDiff: deps.fetchDiff ?? ((input2) => diffBetween(input2)),
1461
1521
  log
1462
1522
  });
1463
- await ready.evalInput.deliver();
1464
1523
  } catch (err) {
1465
1524
  return await failAll(`the checks' input could not be written: ${describeCallFailure(err)}`);
1466
1525
  }
1526
+ try {
1527
+ await ready.evalInput.deliver();
1528
+ } catch (err) {
1529
+ return await failAll(err instanceof DeliveryFailure ? err.message : `the checks' input could not be written: ${describeCallFailure(err)}`);
1530
+ }
1467
1531
  let usable = true;
1468
1532
  for (const check of checks) {
1469
1533
  if (!usable) {
@@ -1569,7 +1633,7 @@ var MAX_TEST_FILE_BYTES = 1024 * 1024;
1569
1633
  var NO_CLAUDE = "the image has no Claude Code for the judge";
1570
1634
  var REPORT_CAPTION = "The host's criteria judge, each criterion judged against the test that cites it";
1571
1635
  async function loadCitationFinder() {
1572
- return await import(pathToFileURL(join(resolvePackRoot(), "template", "build", "scripts", "criterion-citations.mjs")).href);
1636
+ return await import(pathToFileURL(join(resolvePackRoot(), "maintained", "outerlayer-build", "scripts", "criterion-citations.mjs")).href);
1573
1637
  }
1574
1638
  function testFilesIn(root, isTest, limits = { files: MAX_TEST_FILES, bytes: MAX_TEST_FILE_BYTES }) {
1575
1639
  const files = [];
@@ -1619,7 +1683,7 @@ function criteriaOf(workItem) {
1619
1683
  function environmentFor(input) {
1620
1684
  const { config, job, jobDir, deps } = input;
1621
1685
  if (deps.judgeEnvironment !== void 0) return deps.judgeEnvironment;
1622
- if (job.container !== void 0) return containerJudgeEnvironment({ runtime: deps.runtime, config, job, jobDir });
1686
+ if (job.container !== void 0) return containerJudgeEnvironment({ runtime: deps.runtime, config, job, jobDir, log: (line) => deps.log.line(`#${job.item} ${line}`) });
1623
1687
  if (job.microvm !== void 0) return microVmJudgeEnvironment({ runtime: deps.runtime, job, jobDir });
1624
1688
  return void 0;
1625
1689
  }
@@ -1757,19 +1821,25 @@ async function runJudge(input) {
1757
1821
  } finally {
1758
1822
  timer.cancel();
1759
1823
  }
1760
- if (outcome === "timeout") await environment.stop().catch((err) => log.error(`${tag} the judge could not be stopped after its time ran out: ${describeCallFailure(err)}`));
1824
+ let report;
1825
+ const readReport2 = async () => {
1826
+ try {
1827
+ report = await environment.readReport();
1828
+ } catch (err) {
1829
+ log.error(`${tag} the judge's report could not be read: ${describeCallFailure(err)}`);
1830
+ }
1831
+ };
1832
+ if (outcome === "timeout") {
1833
+ await readReport2();
1834
+ await environment.stop().catch((err) => log.error(`${tag} the judge could not be stopped after its time ran out: ${describeCallFailure(err)}`));
1835
+ }
1761
1836
  const decision = decideVerdict({
1762
1837
  run: outcome === "timeout" ? { kind: "timeout" } : { kind: "exited", status: outcome.status, stdout: outcome.stdout, stderr: outcome.stderr },
1763
1838
  criteria,
1764
1839
  citations,
1765
1840
  minutes
1766
1841
  });
1767
- let report;
1768
- try {
1769
- report = await environment.readReport();
1770
- } catch (err) {
1771
- log.error(`${tag} the judge's report could not be read: ${describeCallFailure(err)}`);
1772
- }
1842
+ if (outcome !== "timeout") await readReport2();
1773
1843
  await clear();
1774
1844
  const link = report === void 0 ? void 0 : await uploadReport(check, report, { branch, head });
1775
1845
  await record(check.name, decision.result, decision.reason, { keyTail: decision.limitKey === true ? LIMIT_KEY_TAIL2 : "", link });
@@ -1811,7 +1881,6 @@ async function runJudge(input) {
1811
1881
  }
1812
1882
 
1813
1883
  // src/runner/job.ts
1814
- var LEASE_SECONDS = 900;
1815
1884
  var RENEW_INTERVAL_SECONDS = 300;
1816
1885
  var IDLE_CPU_USEC_PER_MINUTE_FLOOR = 2e6;
1817
1886
  function jobEnv(config, item, itemKey, jobDirPath, baseEnv = process.env, branch, author) {
@@ -2256,6 +2325,10 @@ function leaseExpiry(job, fallback) {
2256
2325
  const base = Date.parse(job.lastRenewAt ?? job.startedAt);
2257
2326
  return new Date((Number.isFinite(base) ? base : fallback.getTime()) + LEASE_SECONDS * 1e3);
2258
2327
  }
2328
+ var TEARDOWN_STAGES = ["judge", "checks", "sync", "cleanup", "report"];
2329
+ function inTeardown(job) {
2330
+ return job.stage !== void 0 && TEARDOWN_STAGES.includes(job.stage);
2331
+ }
2259
2332
  function setStage(job, jobDirPath, stage) {
2260
2333
  job.stage = stage;
2261
2334
  writeJobFile(join(jobDirPath, "job.json"), job);
@@ -2282,7 +2355,13 @@ async function finishJob(job, jobDirPath, outcome, config, deps, ending) {
2282
2355
  }
2283
2356
  const build = job.container === void 0 ? void 0 : { state: job.container, runtime: deps.container ?? createContainerRuntime() };
2284
2357
  const vmBuild = job.microvm === void 0 ? void 0 : { state: job.microvm, runtime: deps.container ?? createContainerRuntime() };
2285
- if (build !== void 0 && job.pid !== void 0 && isGroupAlive(job.pid)) {
2358
+ const commandMayRun = job.pid !== void 0 && isGroupAlive(job.pid) || isContainerTracked(job) && job.exitCode === void 0;
2359
+ if (build !== void 0 && commandMayRun) {
2360
+ if (isContainerTracked(job) && build.state.stopped !== true) {
2361
+ await copyCommandLogTail(build.runtime, build.state, jobDirPath).catch((err) => {
2362
+ log.error(`${tag} copying the end of the command's log failed: ${describeCallFailure(err)} \xB7 continuing`);
2363
+ });
2364
+ }
2286
2365
  await stopContainer(build.runtime, build.state).catch((err) => {
2287
2366
  log.error(`${tag} stopping the container failed: ${describeCallFailure(err)} \xB7 continuing`);
2288
2367
  });
@@ -2292,14 +2371,13 @@ async function finishJob(job, jobDirPath, outcome, config, deps, ending) {
2292
2371
  await stopProcessGroup(job.pid);
2293
2372
  }
2294
2373
  if (outcome !== void 0 && job.endStage === void 0) {
2295
- const TEARDOWN_STAGES = ["judge", "checks", "sync", "cleanup", "report"];
2296
- const staleTeardownStage = job.stage !== void 0 && TEARDOWN_STAGES.includes(job.stage);
2374
+ const staleTeardownStage = inTeardown(job);
2297
2375
  job.endStage = ending?.stage ?? (staleTeardownStage ? job.exitCode !== void 0 ? "command" : void 0 : job.stage);
2298
2376
  job.endExitCode = ending?.exitCode ?? (outcome === "ok" || outcome === "failed" ? job.exitCode : void 0);
2299
2377
  writeJobFile(jobFilePath, job);
2300
2378
  }
2301
2379
  if (outcome !== void 0 && ending?.reason !== void 0) {
2302
- job.reason = scrubReason(ending.reason, config);
2380
+ job.reason = RUNNER_WORDED_REASONS.has(ending.reason) ? ending.reason : scrubReason(ending.reason, config);
2303
2381
  writeJobFile(jobFilePath, job);
2304
2382
  }
2305
2383
  const uploadSessions = async (workdir) => {
@@ -2310,7 +2388,7 @@ async function finishJob(job, jobDirPath, outcome, config, deps, ending) {
2310
2388
  } else {
2311
2389
  log.line(`${tag} sync started`);
2312
2390
  const startedMs = now().getTime();
2313
- const sync = build !== void 0 ? await syncInContainer({ config, runtime: build.runtime, job, jobDir: jobDirPath }) : vmBuild !== void 0 ? await syncInMicroVm({ config, runtime: vmBuild.runtime, job, jobDir: jobDirPath }) : job.build?.exec !== void 0 ? await runSyncViaExec(config, job, jobDirPath, spawnFn) : await runSync(config, job.item, job.itemKey, workdir, jobDirPath, spawnFn, job.branch, job.commitIdentity?.author);
2391
+ const sync = build !== void 0 ? await syncInContainer({ config, runtime: build.runtime, job, jobDir: jobDirPath, log: (line) => log.line(`${tag} ${line}`) }) : vmBuild !== void 0 ? await syncInMicroVm({ config, runtime: vmBuild.runtime, job, jobDir: jobDirPath }) : job.build?.exec !== void 0 ? await runSyncViaExec(config, job, jobDirPath, spawnFn) : await runSync(config, job.item, job.itemKey, workdir, jobDirPath, spawnFn, job.branch, job.commitIdentity?.author);
2314
2392
  const took = formatDuration(now().getTime() - startedMs);
2315
2393
  if (sync.ok) log.line(`${tag} sync ok (${took})`);
2316
2394
  else log.error(`${tag} sync failed: ${sync.reason ?? "no reason given"} \xB7 continuing`);
@@ -2338,8 +2416,12 @@ async function finishJob(job, jobDirPath, outcome, config, deps, ending) {
2338
2416
  const collectSessions = build !== void 0 ? () => copyTranscriptsFromContainer(build.runtime, build.state) : vmBuild !== void 0 ? () => copyTranscriptsFromMicroVm(vmBuild.runtime, vmBuild.state) : void 0;
2339
2417
  if (job.checkContainer !== void 0 && job.checksRan === true) {
2340
2418
  try {
2341
- await cleanupContainer(deps.container ?? createContainerRuntime(), job.checkContainer);
2419
+ const runtime = deps.container ?? createContainerRuntime();
2420
+ const again = isContainerTracked(job) && outcome === "ok" && !job.cleanupRan;
2421
+ if (again) await runtime.host.stop(job.checkContainer.container);
2422
+ await cleanupContainer(runtime, job.checkContainer);
2342
2423
  delete job.checkContainer;
2424
+ if (again) job.checksRan = false;
2343
2425
  writeJobFile(jobFilePath, job);
2344
2426
  } catch (err) {
2345
2427
  log.error(`${tag} removing an earlier attempt's check environment failed: ${describeCallFailure(err)} \xB7 continuing`);
@@ -2653,6 +2735,17 @@ function unfinishedJobs(jobsDirPath) {
2653
2735
  }
2654
2736
  return found;
2655
2737
  }
2738
+ function isContainerTracked(job) {
2739
+ return job.container?.tracking === "container";
2740
+ }
2741
+ function listTrackedJobs(jobsDirPath) {
2742
+ return unfinishedJobs(jobsDirPath).flatMap(({ dirPath, job }) => {
2743
+ const tracking = job.container?.tracking;
2744
+ if (tracking === void 0) return [];
2745
+ if (tracking === "container" && inTeardown(job)) return [];
2746
+ return [{ dirPath, job, known: tracking === "container" }];
2747
+ });
2748
+ }
2656
2749
  function listAdoptableJobs(jobsDirPath) {
2657
2750
  return unfinishedJobs(jobsDirPath).filter(
2658
2751
  ({ job }) => job.microvm === void 0 && job.pid !== void 0 && job.start !== void 0 && isSameProcess(job.pid, job.start)
@@ -2661,6 +2754,12 @@ function listAdoptableJobs(jobsDirPath) {
2661
2754
  async function recoverLostJobs(jobsDirPath, config, deps) {
2662
2755
  const recovered = [];
2663
2756
  for (const { dirPath, job } of unfinishedJobs(jobsDirPath)) {
2757
+ const tracking = job.container?.tracking;
2758
+ if (tracking !== void 0 && tracking !== "container") {
2759
+ recovered.push(await finishJob(job, dirPath, "interrupted", config, deps, { reason: UNKNOWN_TRACKING_REASON }));
2760
+ continue;
2761
+ }
2762
+ if (tracking === "container" && !inTeardown(job)) continue;
2664
2763
  const alive = job.pid !== void 0 && job.start !== void 0 && isSameProcess(job.pid, job.start);
2665
2764
  if (alive) continue;
2666
2765
  const recorded = outcomeFromExitCode(dirPath);
@@ -2673,6 +2772,7 @@ async function recoverLostJobs(jobsDirPath, config, deps) {
2673
2772
  // src/runner/sender.ts
2674
2773
  var STOP_WAIT_MS = 3e4;
2675
2774
  var POLL_MS = 200;
2775
+ var ASK_AGAIN_MS = 1e3;
2676
2776
  var EXIT_REPORT_WAIT_MS = 2e3;
2677
2777
  var exitsLogged = /* @__PURE__ */ new Map();
2678
2778
  var BUILD_HOME = "/build/home";
@@ -2729,6 +2829,31 @@ function launchFor(config, job, jobDir, deps) {
2729
2829
  }
2730
2830
  return { command: process.execPath, args: [deps.cliPath ?? process.argv[1] ?? "outerlayer", "session-sender"], env: hostEnv, cwd: job.workdir ?? jobDir };
2731
2831
  }
2832
+ async function restartSender(input) {
2833
+ const { job, deps } = input;
2834
+ const state = job.container;
2835
+ if (state !== void 0 && job.itemKey !== void 0) {
2836
+ const runtime = deps.runtime ?? createContainerRuntime();
2837
+ const pidfile = senderPidfile(BUILD_HOME, Number(job.item));
2838
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2839
+ const running = async () => {
2840
+ const probe = await runtime.host.exec({ container: state.container, user: state.agentUser ?? ADDED_USER, env: { literals: {}, passed: {} }, argv: ["/bin/sh", "-c", senderAliveScript(pidfile)] });
2841
+ return probe.status === 0 && probe.stdout.trim() === "alive";
2842
+ };
2843
+ try {
2844
+ await signalInContainer(runtime, state, pidfile, "TERM");
2845
+ const deadline = (deps.waitMs ?? STOP_WAIT_MS) / POLL_MS;
2846
+ for (let waited = 0; await running() && waited < deadline; waited += 1) await sleep(POLL_MS);
2847
+ if (await running()) {
2848
+ deps.log.error(`#${job.item} the session sender an earlier runner left did not stop in time \xB7 killing it`);
2849
+ await signalInContainer(runtime, state, pidfile, "KILL");
2850
+ }
2851
+ } catch (err) {
2852
+ deps.log.error(`#${job.item} stopping the session sender an earlier runner left failed: ${describeCallFailure(err)} \xB7 continuing`);
2853
+ }
2854
+ }
2855
+ return startSender(input);
2856
+ }
2732
2857
  function isLive(sender) {
2733
2858
  if (sender.start !== void 0) return isSameProcess(sender.pid, sender.start);
2734
2859
  try {
@@ -2750,12 +2875,13 @@ function signalHost(sender, signal) {
2750
2875
  }
2751
2876
  }
2752
2877
  async function signalInGuest(runtime, state, pidfile, signal) {
2753
- await runtime.vm.exec(state.vsockPath, {
2878
+ const { status } = await runtime.vm.exec(state.vsockPath, {
2754
2879
  argv: ["/bin/sh", "-c", senderSignalScript(pidfile, signal)],
2755
2880
  user: state.agentUser ?? ADDED_USER,
2756
2881
  cwd: "/",
2757
2882
  env: { PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" }
2758
2883
  });
2884
+ return status === 0;
2759
2885
  }
2760
2886
  async function exitReported(pid) {
2761
2887
  const logged = exitsLogged.get(pid);
@@ -2777,14 +2903,19 @@ async function stopSender(input) {
2777
2903
  const inContainer = job.container === void 0 ? void 0 : { state: job.container, runtime: deps.runtime ?? createContainerRuntime(), pidfile: senderPidfile(BUILD_HOME, Number(job.item)) };
2778
2904
  const inGuest = job.microvm === void 0 ? void 0 : { state: job.microvm, runtime: deps.runtime ?? createContainerRuntime(), pidfile: senderPidfile(BUILD_HOME, Number(job.item)) };
2779
2905
  const signalInside = async (signal) => {
2780
- if (inContainer !== void 0) await signalInContainer(inContainer.runtime, inContainer.state, inContainer.pidfile, signal).catch(() => void 0);
2781
- if (inGuest !== void 0) await signalInGuest(inGuest.runtime, inGuest.state, inGuest.pidfile, signal).catch(() => void 0);
2906
+ if (inContainer !== void 0) return signalInContainer(inContainer.runtime, inContainer.state, inContainer.pidfile, signal).catch(() => void 0);
2907
+ if (inGuest !== void 0) return signalInGuest(inGuest.runtime, inGuest.state, inGuest.pidfile, signal).catch(() => void 0);
2908
+ return void 0;
2782
2909
  };
2783
2910
  try {
2784
- if (inContainer !== void 0 || inGuest !== void 0) await signalInside("TERM");
2911
+ let reached = true;
2912
+ if (inContainer !== void 0 || inGuest !== void 0) reached = await signalInside("TERM");
2785
2913
  else signalHost(sender, "SIGTERM");
2786
2914
  const deadline = (deps.waitMs ?? STOP_WAIT_MS) / POLL_MS;
2787
- for (let waited = 0; isLive(sender) && waited < deadline; waited += 1) await sleep(POLL_MS);
2915
+ for (let waited = 0; isLive(sender) && waited < deadline; waited += 1) {
2916
+ await sleep(POLL_MS);
2917
+ if (!reached && (waited + 1) % (ASK_AGAIN_MS / POLL_MS) === 0) reached = await signalInside("TERM");
2918
+ }
2788
2919
  if (isLive(sender)) {
2789
2920
  deps.log.error(`${tag} session sender did not stop in time \xB7 killing it`);
2790
2921
  await signalInside("KILL");
@@ -2796,4 +2927,4 @@ async function stopSender(input) {
2796
2927
  }
2797
2928
  }
2798
2929
 
2799
- export { ALREADY_RELEASED, AttemptLogBook, LEASE_SECONDS, RENEW_INTERVAL_SECONDS, deliverCommitHooks, describeHookEnd, execArgv, execCommandLine, finishJob, hookLimitsFor, hostCommandEnvironment, hostEnvironment, isGroupAlive, isIdle, isTimedOut, isUnfinished, jobEnv, listAdoptableJobs, listenOnBroker, microVmCommandLine, needsRenew, outcomeFromExitCode, provisionEnvironment, provisionMicroVm, provisionProcess, readCpuUsec, readProvisionOut, recoverLostJobs, releaseLease, renewLease, resolveHostBuild, retryFailedReleases, runCommand, runHook, setStage, startHostServices, startSender, stopOrphanedMicroVms, unfinishedJobs, workdirProblem };
2930
+ export { ALREADY_RELEASED, AttemptLogBook, EXIT_CODE_FILE, RENEW_INTERVAL_SECONDS, appendCommandLog, commandLogOffset, deliverCommitHooks, describeHookEnd, execArgv, execCommandLine, finishJob, hookLimitsFor, hostCommandEnvironment, hostEnvironment, isContainerTracked, isGroupAlive, isIdle, isTimedOut, isUnfinished, jobEnv, judgeProbe, listAdoptableJobs, listTrackedJobs, listenOnBroker, microVmCommandLine, needsRenew, outcomeFromExitCode, probeCommand, provisionEnvironment, provisionMicroVm, provisionProcess, readCpuUsec, readProvisionOut, recoverLostJobs, releaseLease, renewLease, resolveHostBuild, restartSender, retryFailedReleases, runCommand, runHook, setStage, startHostServices, startSender, stopOrphanedMicroVms, unfinishedJobs, workdirProblem };
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { launchRefusalForSession } from './chunk-ESVW4MJY.js';
4
- import { autoConnect, detectActiveSession } from './chunk-IF2OSI5T.js';
4
+ import { autoConnect, detectActiveSession } from './chunk-QOALB6ZD.js';
5
5
  import { acquireSpoolLockAt } from './chunk-G3IJ3N6F.js';
6
- import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
6
+ import { defaultFetch } from './chunk-VWLOQ6FI.js';
7
+ import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-NTRCK4NH.js';
8
+ import { resolveRepoIdentity } from './chunk-AEKSX4EY.js';
7
9
  import { C } from './chunk-ANPNT6PM.js';
8
10
  import { launchedItemForSession } from './chunk-T2Q7ISPE.js';
9
11
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
10
- import { defaultFetch } from './chunk-FVMYKL6L.js';
11
- import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-NTRCK4NH.js';
12
12
  import { StepNameSchema, StepBodySchema } from './chunk-7VUK5RFS.js';
13
13
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
14
14
  import { randomUUID } from 'crypto';
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { autoConnect, detectActiveSession } from './chunk-IF2OSI5T.js';
4
- import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
3
+ import { autoConnect, detectActiveSession } from './chunk-QOALB6ZD.js';
4
+ import { defaultFetch } from './chunk-VWLOQ6FI.js';
5
+ import { unauthorizedMessage, resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
6
+ import { resolveRepoIdentity } from './chunk-AEKSX4EY.js';
5
7
  import { C } from './chunk-ANPNT6PM.js';
6
8
  import { parseWorkItemEnv } from './chunk-T2Q7ISPE.js';
7
9
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
8
- import { defaultFetch } from './chunk-FVMYKL6L.js';
9
- import { unauthorizedMessage, resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
10
10
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
11
11
 
12
12
  createRequire(import.meta.url);
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/runner/container/relay-protocol.ts
7
+ var RELAY_USER = "ol-relay";
8
+ var RELAY_ID = 60100;
9
+ var JOIN_DIR = "/run/outerlayer-relay";
10
+ var JOIN_SOCKET = `${JOIN_DIR}/join.sock`;
11
+ var MAX_OPEN_STREAMS = 1024;
12
+ var JOIN_WAIT_MS = 3e4;
13
+ var MAX_MALFORMED_SESSIONS = 5;
14
+ var STREAM_WINDOW = 256 * 1024;
15
+ var SESSION_WINDOW = MAX_OPEN_STREAMS * STREAM_WINDOW;
16
+ var TARGET_TUNNEL = "tunnel";
17
+ var TARGET_GATEWAY = "gateway";
18
+ var TARGET_CLAUDE = "claude";
19
+ var TARGET_LEASE = "lease";
20
+ function destinationTarget(index) {
21
+ return `destination/${index}`;
22
+ }
23
+ function targetOfPath(path) {
24
+ if (path === void 0 || !path.startsWith("/")) return void 0;
25
+ const target = path.slice(1);
26
+ return /^(tunnel|gateway|claude|lease|destination\/\d{1,4})$/.test(target) ? target : void 0;
27
+ }
28
+ var MALFORMED_REASON = `the build broke its connection to the runner ${MAX_MALFORMED_SESSIONS} times`;
29
+ var UNKNOWN_TRANSPORT_REASON = "the runner cannot tell how this build reaches it";
30
+ var COMMAND_LOST_REASON = "the build's command ended without recording an exit code";
31
+ var CONTAINER_STOPPED_REASON = "the build's container stopped while no runner was managing it";
32
+ var UNKNOWN_TRACKING_REASON = "the runner cannot tell how this build is tracked";
33
+ var RUNNER_WORDED_REASONS = /* @__PURE__ */ new Set([
34
+ MALFORMED_REASON,
35
+ UNKNOWN_TRANSPORT_REASON,
36
+ COMMAND_LOST_REASON,
37
+ CONTAINER_STOPPED_REASON,
38
+ UNKNOWN_TRACKING_REASON
39
+ ]);
40
+
41
+ export { COMMAND_LOST_REASON, CONTAINER_STOPPED_REASON, JOIN_DIR, JOIN_SOCKET, JOIN_WAIT_MS, MALFORMED_REASON, MAX_MALFORMED_SESSIONS, MAX_OPEN_STREAMS, RELAY_ID, RELAY_USER, RUNNER_WORDED_REASONS, SESSION_WINDOW, STREAM_WINDOW, TARGET_CLAUDE, TARGET_GATEWAY, TARGET_LEASE, TARGET_TUNNEL, UNKNOWN_TRACKING_REASON, UNKNOWN_TRANSPORT_REASON, destinationTarget, targetOfPath };
@@ -21,10 +21,19 @@ function rewriteHookCommand(command, dir) {
21
21
  function rewriteControlPlanePaths(text, dir) {
22
22
  return text.replace(/(?<![\w./~$}:-])(\.outerlayer|\.claude)\//g, (_match, root) => `${dir}/${root}/`);
23
23
  }
24
+ function rewriteAgentsFilePaths(text, dir, holds) {
25
+ return text.replace(/(?<![\w./~$}:-])\.agents\/[\w@+./-]*/g, (match) => {
26
+ const path = match.replace(/\.+$/, "");
27
+ if (path.split("/").includes("..") || !holds(path)) return match;
28
+ return `${dir}/${path}${match.slice(path.length)}`;
29
+ });
30
+ }
24
31
  function hookCommandEscapesControlPlane(command) {
25
32
  const remaining = [...PROJECT_DIR_SPELLINGS, ...CONTROL_PLANE_VARIABLE_FORMS].reduce((text, pattern) => text.replace(pattern, " "), command);
26
33
  return /\.claude(?:\/|["'\s;|&)]|$)/.test(remaining) || /\$\{?CLAUDE_PROJECT_DIR\}?"?\/\.claude/.test(remaining);
27
34
  }
35
+ var GOVERNANCE_VARIABLE = "OUTERLAYER_GOVERNANCE";
36
+ var SUPPORTED_CONTROL_PLANE_LAYOUT = 2;
28
37
  var MINIMUM_CLAUDE_VERSION = "2.1.284";
29
38
  function versionParts(text) {
30
39
  const found = /(\d+)\.(\d+)\.(\d+)/.exec(text);
@@ -41,4 +50,4 @@ var SHIM_SCRIPT = `#!/bin/sh
41
50
  exec outerlayer claude "$@"
42
51
  `;
43
52
 
44
- export { CONTROL_PLANE_DIR_VARIABLE, MINIMUM_CLAUDE_VERSION, SHIM_SCRIPT, hookCommandEscapesControlPlane, rewriteControlPlanePaths, rewriteHookCommand, versionAtLeast };
53
+ export { CONTROL_PLANE_DIR_VARIABLE, GOVERNANCE_VARIABLE, MINIMUM_CLAUDE_VERSION, SHIM_SCRIPT, SUPPORTED_CONTROL_PLANE_LAYOUT, hookCommandEscapesControlPlane, rewriteAgentsFilePaths, rewriteControlPlanePaths, rewriteHookCommand, versionAtLeast };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { builtinKind } from './chunk-P53VEAOF.js';
3
+ import { builtinKind } from './chunk-2CMJLYV6.js';
4
4
  import { parseSize } from './chunk-7RQ73DLO.js';
5
- import { runnerDir } from './chunk-N2PXGQRL.js';
5
+ import { runnerDir } from './chunk-KIGSGZBB.js';
6
6
  import { dirname } from 'path';
7
7
  import { spawnSync } from 'child_process';
8
8
 
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RecipeError, locateRecipe, readRecipe, assertBuildable, writeSanitizedRecipe, classifyProperties, SANITIZED_NAME } from './chunk-QOZKPLVJ.js';
4
- import { CLAUDE_CODE_VERSION, NODE_IMAGE, DEFAULT_BASE_IMAGE, TINI_VERSION, GH_VERSION, GH_SHA256, TINI_SHA256 } from './chunk-CX22S5BA.js';
5
- import { claimPidFile, RunnerAlreadyRunningError, releasePidFile } from './chunk-ECODQ7II.js';
3
+ import { CLAUDE_CODE_VERSION, NODE_IMAGE, DEFAULT_BASE_IMAGE, RecipeError, locateRecipe, readRecipe, assertBuildable, TINI_VERSION, GH_VERSION, writeSanitizedRecipe, classifyProperties, GH_SHA256, TINI_SHA256, SANITIZED_NAME } from './chunk-3W333NFO.js';
4
+ import { claimPidFile, RunnerAlreadyRunningError, releasePidFile } from './chunk-ZFLOGMUC.js';
6
5
  import { startTimeOf } from './chunk-JBJTC3UU.js';
7
- import { RUNNER_DIR_MODE, repoCacheDir, imagesDir, attemptStamp, runnerDir, rootfsPathFor, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
8
- import { withGitConfig, tokenHeader } from './chunk-BQXFBI7T.js';
6
+ import { RUNNER_DIR_MODE, repoCacheDir, imagesDir, attemptStamp, runnerDir, rootfsPathFor, RUNNER_FILE_MODE } from './chunk-KIGSGZBB.js';
7
+ import { withGitConfig, tokenHeader } from './chunk-V7MQKOZY.js';
8
+ import { RELAY_ID, RELAY_USER } from './chunk-GISNHSYL.js';
9
9
  import { mkdirSync, rmSync, existsSync, mkdtempSync, cpSync, readFileSync, writeFileSync, readdirSync, lstatSync, readlinkSync } from 'fs';
10
10
  import { tmpdir } from 'os';
11
11
  import { dirname, join } from 'path';
@@ -216,10 +216,15 @@ function toolsDockerfile(parts) {
216
216
  "COPY --from=recipe /etc/group /tmp/recipe-group",
217
217
  `RUN uid=$(awk -F: 'BEGIN{m=1499} $3>=1500 && $3<60000 && $3>m{m=$3} END{print m+1}' /tmp/recipe-passwd) \\`,
218
218
  ` && gid=$(awk -F: 'BEGIN{m=1499} $3>=1500 && $3<60000 && $3>m{m=$3} END{print m+1}' /tmp/recipe-group) \\`,
219
- " && { grep -v '^ol-agent:' /tmp/recipe-passwd > /out/etc/passwd || true; } \\",
220
- " && { grep -v '^ol-agent:' /tmp/recipe-group > /out/etc/group || true; } \\",
219
+ " && { grep -v -e '^ol-agent:' -e '^ol-relay:' /tmp/recipe-passwd > /out/etc/passwd || true; } \\",
220
+ " && { grep -v -e '^ol-agent:' -e '^ol-relay:' /tmp/recipe-group > /out/etc/group || true; } \\",
221
+ // The relay's id is fixed because the runner names it in the container's `--tmpfs` options before the container exists.
222
+ ` && if awk -F: '$3==${RELAY_ID}{found=1} END{exit !found}' /out/etc/passwd; then echo "uid ${RELAY_ID} is taken by a user of the recipe image, and the relay needs it" >&2; exit 1; fi \\`,
223
+ ` && if awk -F: '$3==${RELAY_ID}{found=1} END{exit !found}' /out/etc/group; then echo "gid ${RELAY_ID} is taken by a group of the recipe image, and the relay needs it" >&2; exit 1; fi \\`,
221
224
  ` && printf '%s\\n' "ol-agent:x:$uid:$gid::/build/home:/bin/sh" >> /out/etc/passwd \\`,
222
225
  ` && printf '%s\\n' "ol-agent:x:$gid:" >> /out/etc/group \\`,
226
+ ` && printf '%s\\n' "${RELAY_USER}:x:${RELAY_ID}:${RELAY_ID}::/nonexistent:/usr/sbin/nologin" >> /out/etc/passwd \\`,
227
+ ` && printf '%s\\n' "${RELAY_USER}:x:${RELAY_ID}:" >> /out/etc/group \\`,
223
228
  " && chmod 0644 /out/etc/passwd /out/etc/group \\",
224
229
  " && chmod -R a+rX /out",
225
230
  `FROM ${recipeImage}`,
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { sanitizeTerminal } from './chunk-G3IJ3N6F.js';
4
- import { DEFAULT_DASHBOARD } from './chunk-BM63HB2M.js';
5
- import { remoteLookupFailed } from './chunk-QNLX477Q.js';
4
+ import { DEFAULT_DASHBOARD } from './chunk-EAQSOE62.js';
6
5
  import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
7
6
  import { writeRepoConnection, findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
7
+ import { remoteLookupFailed } from './chunk-AEKSX4EY.js';
8
8
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
9
9
  import { cliInvocation } from './chunk-CRB3POP4.js';
10
10
  import { execFileSync } from 'child_process';
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { runEmit } from './chunk-5VML45HH.js';
4
- import { addStdioMcpEntryIfAbsent, addDocsMcpEntryIfAbsent, DOCS_MCP_SERVER_NAME } from './chunk-YVZJ6GKF.js';
5
- import { installStarterPack } from './chunk-6X4SQ5MY.js';
3
+ import { runEmit } from './chunk-XCRZTXRL.js';
4
+ import { resolveGitCommonDir, defaultGitRunner } from './chunk-KOQELWQ6.js';
5
+ import { addStdioMcpEntryIfAbsent, addDocsMcpEntryIfAbsent, DOCS_MCP_SERVER_NAME } from './chunk-DIB2WLBL.js';
6
+ import { installStarterPack } from './chunk-V7SAQ645.js';
7
+ import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-5OCIHFGE.js';
6
8
  import { C } from './chunk-ANPNT6PM.js';
7
- import { resolveGitCommonDir, defaultGitRunner } from './chunk-EAEELQVQ.js';
8
- import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-NNLA7LLQ.js';
9
9
  import { cliInvocation } from './chunk-CRB3POP4.js';
10
10
  import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
11
11
  import { generatedHeaderSource } from './chunk-WFSUUUAN.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { hostKeyPath, runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
3
+ import { hostKeyPath, runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-KIGSGZBB.js';
4
4
  import { generateKeyPairSync, createPrivateKey, createPublicKey, sign } from 'crypto';
5
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
6
6
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { BUILD_HOME } from './chunk-BQXFBI7T.js';
3
+ import { BUILD_HOME } from './chunk-V7MQKOZY.js';
4
4
  import { join, dirname } from 'path';
5
5
 
6
6
  createRequire(import.meta.url);
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { removeRetiredSkills } from './chunk-7UWVLZXD.js';
4
- import { defaultFetch } from './chunk-FVMYKL6L.js';
3
+ import { removeRetiredSkills } from './chunk-USWVXQIH.js';
4
+ import { defaultFetch } from './chunk-VWLOQ6FI.js';
5
5
  import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
6
6
  import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
7
- import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-NNLA7LLQ.js';
7
+ import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-5OCIHFGE.js';
8
8
  import { cliInvocation } from './chunk-CRB3POP4.js';
9
9
  import { writeDegraded, writeSourceCache, SOURCE_CACHE_TTL_RETRY_MS, writeContextManifest, SOURCE_CACHE_TTL_SUCCESS_MS, readSourceCache, isSourceCacheFresh, clearDegraded } from './chunk-YQR6E6OV.js';
10
10
  import { normalizeRepoName, parseOuterlayerConfig, classifyTree, emitTree } from './chunk-WFSUUUAN.js';
11
11
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
12
- import { withTokenHeader } from './chunk-BQXFBI7T.js';
12
+ import { withTokenHeader } from './chunk-V7MQKOZY.js';
13
13
  import { execFileSync } from 'child_process';
14
14
  import { existsSync, mkdirSync, writeFileSync, chmodSync, lstatSync, readFileSync, copyFileSync } from 'fs';
15
15
  import { isAbsolute, join, dirname } from 'path';
@@ -437,7 +437,7 @@ function ensureBareCache(git, home, repository, host) {
437
437
  }
438
438
  return dir;
439
439
  }
440
- var MATERIALIZED_ROOTS = ["AGENTS.md", ".claude", ".outerlayer"];
440
+ var MATERIALIZED_ROOTS = ["AGENTS.md", ".claude", ".outerlayer", ".agents"];
441
441
  function listMaterializedFiles(git, cacheRepoDir, sha) {
442
442
  const result = git(["ls-tree", "-r", "-z", sha, "--", ...MATERIALIZED_ROOTS], { cwd: cacheRepoDir, timeoutMs: 1e4 });
443
443
  if (!result.ok) return [];
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
3
+ import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-KIGSGZBB.js';
4
4
  import { readFileSync, existsSync, rmSync, mkdirSync, writeFileSync, renameSync } from 'fs';
5
5
  import { join } from 'path';
6
6
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { currentLink } from './chunk-AMFWYESY.js';
3
+ import { currentLink } from './chunk-4NM3I3VV.js';
4
4
  import { readFileSync, statSync, chmodSync, mkdirSync, writeFileSync, renameSync, rmSync, existsSync, lstatSync, accessSync, constants, realpathSync } from 'fs';
5
5
  import { randomBytes } from 'crypto';
6
6
  import { join, dirname, delimiter, resolve } from 'path';