@outerlayer/cli 0.24.0 → 0.25.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 (111) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +9 -0
  3. package/dist/{agent-setup-QQYRBPK2.js → agent-setup-PDIIGMKE.js} +7 -7
  4. package/dist/{bridge-4ZARDVGS.js → bridge-5KZ36YDG.js} +3 -3
  5. package/dist/build-Q2OBF77R.js +12 -0
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-MECDEKXX.js → builder-PRSCX5AH.js} +6 -6
  8. package/dist/{check-YYKNYFNI.js → check-EPYRTE3R.js} +38 -37
  9. package/dist/{chunk-BN3CSI7S.js → chunk-2K3TCQHW.js} +1 -1
  10. package/dist/{chunk-A62QFN2M.js → chunk-2N72GPS2.js} +3 -3
  11. package/dist/{chunk-W7O4LA4E.js → chunk-34ANPNVB.js} +2 -2
  12. package/dist/{chunk-6GSA2SKT.js → chunk-3I44PQ26.js} +205 -56
  13. package/dist/{chunk-WH2QV3UL.js → chunk-4S4VBDSO.js} +1 -1
  14. package/dist/{chunk-IDSHLKQA.js → chunk-5222PA6S.js} +1 -1
  15. package/dist/{chunk-V5Q3S4NM.js → chunk-6CNHXHI2.js} +1 -1
  16. package/dist/{chunk-LY2L3O2O.js → chunk-7OWPLRJR.js} +1 -1
  17. package/dist/{chunk-HHXBOTRO.js → chunk-ATGHVEU4.js} +1 -1
  18. package/dist/{chunk-TTLVQZSH.js → chunk-AXPCGD46.js} +5 -5
  19. package/dist/{chunk-FWEWFW3F.js → chunk-DEBOL6ON.js} +1 -1
  20. package/dist/{chunk-E4OUL7ZP.js → chunk-FXUVXSY2.js} +2 -2
  21. package/dist/{chunk-BUBCPP3F.js → chunk-HBLLZLOH.js} +2 -2
  22. package/dist/{chunk-F2W2IYNP.js → chunk-HWEIFHSW.js} +2 -2
  23. package/dist/{chunk-F7Y2USIM.js → chunk-IDJIWKTY.js} +2 -2
  24. package/dist/{chunk-DG2ULWM6.js → chunk-IGRRD7PX.js} +11 -7
  25. package/dist/{chunk-GISNHSYL.js → chunk-JGD5TWQ2.js} +4 -2
  26. package/dist/{chunk-BOQY756V.js → chunk-JKILLWZF.js} +8 -7
  27. package/dist/{chunk-D7X5ITVT.js → chunk-JWRX5ZTT.js} +6 -2
  28. package/dist/{chunk-755WXDBI.js → chunk-K5WVK7IC.js} +1 -1
  29. package/dist/{chunk-H6IUKXXI.js → chunk-L2FZLBF7.js} +207 -35
  30. package/dist/{chunk-FKXGQOF5.js → chunk-M4B6QKNZ.js} +1 -1
  31. package/dist/{chunk-NTQTDCYR.js → chunk-O2WYUIK7.js} +1 -1
  32. package/dist/{chunk-VV7ZD5LR.js → chunk-QMQC6JCO.js} +1 -1
  33. package/dist/{chunk-5XCAPBE2.js → chunk-QUGYGO6L.js} +5 -5
  34. package/dist/{chunk-FQPN5S4Q.js → chunk-QXNJWSTM.js} +4 -4
  35. package/dist/{chunk-3W333NFO.js → chunk-RGW7ERF3.js} +15 -4
  36. package/dist/{chunk-CZUH2SLQ.js → chunk-UNF7MWEL.js} +1 -1
  37. package/dist/{chunk-ZFLOFAUG.js → chunk-VMF5LK3D.js} +7 -7
  38. package/dist/{chunk-VBEXKEBV.js → chunk-VNGENFOG.js} +19 -6
  39. package/dist/{chunk-5ECUMU53.js → chunk-VPUNOGXO.js} +6 -6
  40. package/dist/{chunk-RVYOOYOA.js → chunk-X5LNCIZT.js} +18 -9
  41. package/dist/{chunk-PDIM5T65.js → chunk-XGJUNNXL.js} +1 -1
  42. package/dist/{chunk-GU4PKXN7.js → chunk-XHXDCYSK.js} +184 -37
  43. package/dist/{chunk-NGZID7UI.js → chunk-XRYUJTAT.js} +8 -1
  44. package/dist/{chunk-TQ6Y7YV6.js → chunk-YMKQVCKC.js} +5 -5
  45. package/dist/{chunk-D7K446H6.js → chunk-YTTHDPWF.js} +4 -4
  46. package/dist/{chunk-LBCZXXOX.js → chunk-ZGMQQWCV.js} +2 -2
  47. package/dist/{chunk-KF37SUDM.js → chunk-ZI2ZVWKT.js} +1 -1
  48. package/dist/{chunk-PVRBE7S4.js → chunk-ZODVSFI4.js} +1 -1
  49. package/dist/chunk-ZVB57WI6.js +19 -0
  50. package/dist/{claude-launcher-JCPSHDZQ.js → claude-launcher-WGOCLTG6.js} +1 -1
  51. package/dist/{cli-ZTBH3FBG.js → cli-2LGSPAYZ.js} +105 -100
  52. package/dist/command-ITLPJ5XU.js +533 -0
  53. package/dist/{config-7Z5DHSGY.js → config-JJ3EO7SB.js} +3 -3
  54. package/dist/{connect-cmd-NY5LIKVC.js → connect-cmd-JFDZKPND.js} +6 -6
  55. package/dist/{container-start-OHBUZEJJ.js → container-start-X22OXY6E.js} +44 -35
  56. package/dist/{control-plane-launch-GKGI6HJA.js → control-plane-launch-ZFT6SI4N.js} +6 -6
  57. package/dist/{docker-RKGBJESN.js → docker-PQHWAY5J.js} +6 -6
  58. package/dist/{doctor-DOAFZV4O.js → doctor-73GNT4VV.js} +78 -32
  59. package/dist/{emit-artifact-cmd-VZHIDPXQ.js → emit-artifact-cmd-AIOTX6YT.js} +10 -10
  60. package/dist/{emit-criteria-cmd-SYLBCWHW.js → emit-criteria-cmd-7PJINOHA.js} +7 -7
  61. package/dist/{emit-finding-cmd-52M43NPC.js → emit-finding-cmd-JRDSZ4DR.js} +7 -7
  62. package/dist/{emit-result-cmd-BTMTGDAV.js → emit-result-cmd-ZGF6Q6OP.js} +10 -10
  63. package/dist/{emit-step-cmd-6XTJITZT.js → emit-step-cmd-DUR34STQ.js} +8 -8
  64. package/dist/{exec-client-CKPK62K2.js → exec-client-S5IA7JRG.js} +4 -4
  65. package/dist/{governing-source-GWN7GVEN.js → governing-source-DKJABQAT.js} +10 -10
  66. package/dist/{guest-init-ZBL5CN7Y.js → guest-init-TOSKPGPF.js} +5 -5
  67. package/dist/{hook-fast-3JL4PXLG.js → hook-fast-NEELST6G.js} +1 -1
  68. package/dist/host-key-ICJEQBWH.js +9 -0
  69. package/dist/{image-tag-AO4RBAKW.js → image-tag-6KJOGBQK.js} +4 -4
  70. package/dist/index.js +4 -4
  71. package/dist/{init-EQTR7AEF.js → init-NE3VR3EY.js} +24 -22
  72. package/dist/{init-TSQ3EOQW.js → init-SKOXNJND.js} +24 -22
  73. package/dist/{init-cmd-AF2MH36A.js → init-cmd-UEDOJ7LG.js} +10 -10
  74. package/dist/{init-update-SHISHMXV.js → init-update-VKZ4S6HH.js} +8 -8
  75. package/dist/{install-ORQC26ZE.js → install-MPEJJ7X6.js} +5 -5
  76. package/dist/{install-cmd-4LA3UJZ4.js → install-cmd-SE6NCTJK.js} +6 -6
  77. package/dist/job-state-format-WJQGQB6F.js +6 -0
  78. package/dist/{logs-5EPHIPZB.js → logs-T4ERSOQ4.js} +3 -3
  79. package/dist/{loop-4WUCS5JP.js → loop-BPVEA5OC.js} +37 -36
  80. package/dist/{machine-6UNLIPLE.js → machine-G3GICXQN.js} +20 -18
  81. package/dist/{mcp-serve-cmd-KMWEKM7C.js → mcp-serve-cmd-7M4VLNI4.js} +5 -5
  82. package/dist/{paths-XY5ADO32.js → paths-2KGM2LZV.js} +3 -3
  83. package/dist/pending-BGLMTB5Q.js +9 -0
  84. package/dist/{pidfile-OJ7RP4Q2.js → pidfile-VYBH3IMN.js} +4 -4
  85. package/dist/{record-BEJB4J7N.js → record-GNOHDJ2O.js} +4 -4
  86. package/dist/{relay-PSZ4LGMW.js → relay-GFPPD6GF.js} +1 -1
  87. package/dist/relay-protocol-HELO5SNH.js +6 -0
  88. package/dist/{runner-env-ZJWJOJKQ.js → runner-env-GUFV544G.js} +6 -6
  89. package/dist/{runner-identity-2OOUJSFJ.js → runner-identity-J6DXJ6MF.js} +6 -6
  90. package/dist/{runner-key-WDFBSJRX.js → runner-key-L55O7Y7W.js} +24 -22
  91. package/dist/{session-sender-X3BBQZMF.js → session-sender-LXTASWBY.js} +11 -11
  92. package/dist/{spec-cmd-QRF5YXKK.js → spec-cmd-G2JNXKD7.js} +8 -8
  93. package/dist/{status-ZCAAF6MD.js → status-U6DXOR6C.js} +34 -28
  94. package/dist/{sync-cmd-UQK3RYAC.js → sync-cmd-VPNS5ITY.js} +10 -10
  95. package/dist/{watch-MOQ3GQTE.js → watch-ZOCYD2NE.js} +10 -10
  96. package/dist/{work-claim-cmd-RT343CLA.js → work-claim-cmd-BUMIPJNF.js} +11 -11
  97. package/dist/{work-cmd-APXSER2D.js → work-cmd-LRAXUOJV.js} +8 -8
  98. package/dist/{work-comment-cmd-AT5NUYUU.js → work-comment-cmd-4RDIBUYO.js} +8 -8
  99. package/dist/{work-logs-cmd-Z5DMNEJP.js → work-logs-cmd-YYN2CPJQ.js} +8 -8
  100. package/dist/{work-open-pr-cmd-ZTS6MJHL.js → work-open-pr-cmd-3MCND2LZ.js} +9 -9
  101. package/dist/{work-pr-cmd-IWZCC3WH.js → work-pr-cmd-BODEZAXN.js} +8 -8
  102. package/dist/{work-stop-cmd-DCAWFDZC.js → work-stop-cmd-P7HXVKEG.js} +8 -8
  103. package/package.json +2 -2
  104. package/skill-pack/maintained/outerlayer-build/SKILL.md +1 -1
  105. package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +3 -2
  106. package/skill-pack/maintained/outerlayer-build/references/review-briefs.md +3 -1
  107. package/dist/build-OVZIT2G2.js +0 -12
  108. package/dist/command-DO4TERRT.js +0 -208
  109. package/dist/host-key-W2DLZGZ7.js +0 -9
  110. package/dist/pending-35J3ZPLR.js +0 -9
  111. package/dist/relay-protocol-K7KP2SPI.js +0 -6
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { checkStarterFiles, contextIsGoverned, checkBuildSkill } from './chunk-XFGL53GU.js';
4
- import { resolveCredentials, getJson, WorkCommandError } from './chunk-RVYOOYOA.js';
5
- import { isLinkedRepository } from './chunk-V5Q3S4NM.js';
4
+ import { resolveCredentials, getJson, WorkCommandError } from './chunk-X5LNCIZT.js';
5
+ import { isLinkedRepository } from './chunk-6CNHXHI2.js';
6
6
  import { sanitizeTerminal } from './chunk-BUP5N3X6.js';
7
7
  import { checkFormerSkillNames } from './chunk-MQ743JX3.js';
8
- import { resolveGatewayCredentials, defaultFetch } from './chunk-FKXGQOF5.js';
9
- import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-755WXDBI.js';
8
+ import { resolveGatewayCredentials, defaultFetch } from './chunk-M4B6QKNZ.js';
9
+ import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-K5WVK7IC.js';
10
10
  import { readStatuslineState, STATE_FRESH_MS } from './chunk-DXDF43YG.js';
11
11
  import { hookCommandEscapesControlPlane, CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
12
12
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
@@ -1174,7 +1174,7 @@ function doctorExitCode(checks) {
1174
1174
 
1175
1175
  // src/doctor-report.ts
1176
1176
  async function gatherDoctorChecks() {
1177
- const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-7Z5DHSGY.js');
1177
+ const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-JJ3EO7SB.js');
1178
1178
  const configPath = defaultRunnerConfigPath();
1179
1179
  const checks = runDoctor({ runnerHost: hasRunnerBlock(configPath) });
1180
1180
  const credential = await credentialChecks();
@@ -1186,7 +1186,7 @@ async function gatherDoctorChecks() {
1186
1186
  const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
1187
1187
  checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
1188
1188
  } else if (hasRunnerBlock(configPath)) {
1189
- const { runnerHostChecks } = await import('./doctor-DOAFZV4O.js');
1189
+ const { runnerHostChecks } = await import('./doctor-73GNT4VV.js');
1190
1190
  const hooks = (() => {
1191
1191
  try {
1192
1192
  return loadRunnerConfig(configPath).hooks;
@@ -1221,7 +1221,7 @@ async function gatherDoctorChecks() {
1221
1221
  const { existsSync: existsSync3 } = await import('fs');
1222
1222
  if (process.platform !== "linux" || !existsSync3("/run/systemd/system")) return void 0;
1223
1223
  const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
1224
- const { DEFAULT_UNIT_NAME } = await import('./install-ORQC26ZE.js');
1224
+ const { DEFAULT_UNIT_NAME } = await import('./install-MPEJJ7X6.js');
1225
1225
  const { dirname: dirname2 } = await import('path');
1226
1226
  return inspectService(DEFAULT_UNIT_NAME, dirname2(configPath), realInspectProbes());
1227
1227
  })();
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { MIN_ENGINE_MAJOR } from './chunk-GU4PKXN7.js';
4
- import { firecrackerArch, MICROVM_ARCHES, guestAssetsPinned } from './chunk-3W333NFO.js';
3
+ import { MIN_ENGINE_MAJOR } from './chunk-XHXDCYSK.js';
4
+ import { runnerImageVersion } from './chunk-5222PA6S.js';
5
+ import { firecrackerArch, MICROVM_ARCHES, guestAssetsPinned } from './chunk-RGW7ERF3.js';
5
6
  import { spawnSync } from 'child_process';
6
7
  import { existsSync, accessSync, constants, statSync, readFileSync } from 'fs';
7
8
 
@@ -53,17 +54,20 @@ function detectMachine(probes = {}) {
53
54
  const platform = platformOf(probes);
54
55
  const kvm = (probes.kvm ?? (() => detectKvm(probes.kvmDevice ?? "/dev/kvm")))();
55
56
  const arch = firecrackerArch(probes.nodeArch ?? process.arch);
57
+ const inImage = runnerImageVersion(probes.env ?? process.env) !== void 0 ? { inImage: true } : {};
56
58
  const version = (probes.dockerVersion ?? (() => docker(["version", "--format", "{{.Server.Version}}"])))();
57
59
  if (version === void 0) {
58
60
  const failure = (probes.dockerFailure ?? (probes.dockerVersion === void 0 ? dockerFailure : () => void 0))();
59
- return { platform, docker: failure === void 0 ? { kind: "none" } : { kind: "unreachable", reason: failure }, kvm, arch };
61
+ return { platform, ...inImage, docker: failure === void 0 ? { kind: "none" } : { kind: "unreachable", reason: failure }, kvm, arch };
60
62
  }
61
63
  const system = (probes.dockerOperatingSystem ?? (() => docker(["info", "--format", "{{.OperatingSystem}}"])))() ?? "";
62
- return { platform, docker: { kind: /docker desktop/i.test(system) ? "desktop" : "engine", version }, kvm, arch };
64
+ return { platform, ...inImage, docker: { kind: /docker desktop/i.test(system) ? "desktop" : "engine", version }, kvm, arch };
63
65
  }
64
66
  function supportsContainerBuilds(machine) {
65
67
  if (machine.platform !== "linux" && machine.platform !== "wsl2") return false;
66
- return machine.docker.kind === "engine" && Number.parseInt(machine.docker.version ?? "", 10) >= MIN_ENGINE_MAJOR;
68
+ const { kind, version } = machine.docker;
69
+ if (kind !== "engine" && !(kind === "desktop" && machine.inImage === true)) return false;
70
+ return Number.parseInt(version ?? "", 10) >= MIN_ENGINE_MAJOR;
67
71
  }
68
72
  function supportsMicroVmBuilds(machine) {
69
73
  return machine.platform === "linux" && machine.kvm?.state === "usable" && supportsContainerBuilds(machine) && microVmAssetsPinned(machine);
@@ -81,7 +85,16 @@ function reachDockerStep(machine) {
81
85
  function describeMachineDocker(machine) {
82
86
  const { kind, version, reason } = machine.docker;
83
87
  const where = machine.platform === "windows" ? "Windows" : machine.platform === "darwin" ? "macOS" : machine.platform === "wsl2" ? "WSL2" : "Linux";
84
- if (kind === "desktop") return `Docker Desktop ${version ?? ""} on ${where}, which cannot pass a Unix socket into a container`.replace(" ", " ");
88
+ if (kind === "desktop") {
89
+ const engine = version === void 0 ? "" : ` with engine ${version}`;
90
+ if (machine.inImage === true && (machine.platform === "linux" || machine.platform === "wsl2")) {
91
+ const major = Number.parseInt(version ?? "", 10);
92
+ if (Number.isNaN(major)) return `Docker Desktop${engine}, whose engine version is not readable`;
93
+ if (major < MIN_ENGINE_MAJOR) return `Docker Desktop${engine}, older than the ${MIN_ENGINE_MAJOR} that container builds need`;
94
+ return `Docker Desktop${engine}`;
95
+ }
96
+ return `Docker Desktop${engine} on ${where}, which a runner accepts only in the runner image`;
97
+ }
85
98
  if (kind === "none") return `no Docker on ${where}`;
86
99
  if (kind === "unreachable") {
87
100
  const problem = reason === "permission" ? "this user has no permission on its socket" : "its daemon is not running";
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isPlaceholderCommand } from './chunk-BOQY756V.js';
4
- import { describeCallFailure } from './chunk-TQ6Y7YV6.js';
5
- import { WorkCommandError, getJson } from './chunk-RVYOOYOA.js';
3
+ import { isPlaceholderCommand } from './chunk-JKILLWZF.js';
4
+ import { describeCallFailure } from './chunk-YMKQVCKC.js';
5
+ import { WorkCommandError, getJson } from './chunk-X5LNCIZT.js';
6
6
  import { sanitizeTerminal } from './chunk-BUP5N3X6.js';
7
- import { builtinKind } from './chunk-D7X5ITVT.js';
8
- import { signerFor } from './chunk-PVRBE7S4.js';
9
- import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential } from './chunk-BN3CSI7S.js';
7
+ import { builtinKind } from './chunk-JWRX5ZTT.js';
8
+ import { signerFor } from './chunk-ZODVSFI4.js';
9
+ import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential } from './chunk-2K3TCQHW.js';
10
10
 
11
11
  createRequire(import.meta.url);
12
12
 
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { detectActiveSession, autoConnect } from './chunk-F2W2IYNP.js';
4
- import { workPageUrl } from './chunk-V5Q3S4NM.js';
3
+ import { detectActiveSession, autoConnect } from './chunk-HWEIFHSW.js';
4
+ import { workPageUrl } from './chunk-6CNHXHI2.js';
5
5
  import { sanitizeTerminal } from './chunk-BUP5N3X6.js';
6
- import { resolveGatewayCredentials, unauthorizedMessage, defaultFetch } from './chunk-FKXGQOF5.js';
6
+ import { resolveGatewayCredentials, unauthorizedMessage, defaultFetch } from './chunk-M4B6QKNZ.js';
7
7
  import { readRepoConnection } from './chunk-BJ3KTMDH.js';
8
8
  import { resolveRepoIdentity } from './chunk-D4AMAEZ7.js';
9
9
  import { C } from './chunk-ANPNT6PM.js';
10
10
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
11
11
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
12
- import { signRunnerRequest } from './chunk-PVRBE7S4.js';
12
+ import { signRunnerRequest } from './chunk-ZODVSFI4.js';
13
13
 
14
14
  createRequire(import.meta.url);
15
15
 
@@ -368,10 +368,11 @@ function issueLabel(subject) {
368
368
  if ("issue" in subject) return `issue ${sanitizeTerminal(subject.repository)}#${subject.issue}`;
369
369
  return `issue ${sanitizeTerminal(subject.key)}`;
370
370
  }
371
- function itemPageUrl(home, cwd, appId, workItemId) {
371
+ function itemPageUrl(home, cwd, appId, workItemId, number) {
372
372
  const connection = readRepoConnection(cwd);
373
373
  if (connection === void 0 || connection.appId !== appId || typeof workItemId !== "string" || workItemId === "") return void 0;
374
- return `${workPageUrl(home, connection.organization.name, connection.factory.name)}/${encodeURIComponent(workItemId)}`;
374
+ const segment = encodeURIComponent(number == null ? workItemId : String(number));
375
+ return `${workPageUrl(home, connection.organization.name, connection.factory.name)}/${segment}`;
375
376
  }
376
377
  async function runWorkBuild(opts) {
377
378
  const cwd = opts.cwd ?? process.cwd();
@@ -416,7 +417,7 @@ async function runWorkBuild(opts) {
416
417
  ...facts
417
418
  };
418
419
  const { data } = await postJsonWithRetry(url, "/v1/work-items/build", apiKey, appId, body, fetchImpl, retries, sleep);
419
- const page = itemPageUrl(home, cwd, appId, data.workItemId);
420
+ const page = itemPageUrl(home, cwd, appId, data.workItemId, data.number);
420
421
  const output = opts.json ? JSON.stringify(data) : `${C.green}\u2713${C.reset} build requested ${C.dim}\xB7${C.reset} ${itemLabel(data)}${"subject" in body ? ` (${issueLabel(body.subject)})` : ""} ${C.dim}\xB7${C.reset} by ${data.attestor}` + (page !== void 0 ? `
421
422
  ${page}` : "") + tokenWarning(data);
422
423
  if (!opts.quiet) process.stdout.write(output + "\n");
@@ -427,7 +428,7 @@ async function runWorkLinkSession(opts) {
427
428
  return await linkSession(opts);
428
429
  } catch (err) {
429
430
  if (opts.logFailures) {
430
- const { logHookError } = await import('./hook-fast-3JL4PXLG.js');
431
+ const { logHookError } = await import('./hook-fast-NEELST6G.js');
431
432
  const reason = err instanceof Error ? err.message : String(err);
432
433
  logHookError(opts.home ?? homeFromEnv(opts.env ?? process.env), new Error(`work link-session #${opts.number} failed: ${reason}`));
433
434
  }
@@ -514,9 +515,17 @@ async function runWorkRemove(opts) {
514
515
  if (!opts.quiet) process.stdout.write(output + "\n");
515
516
  return { data, output };
516
517
  }
518
+ function mergedUnverifiedLine(data) {
519
+ const block = data.gates?.block;
520
+ if (block?.mergedDespiteVerdict !== true) return "";
521
+ const at = typeof block.mergedAt === "string" ? ` at ${sanitizeTerminal(block.mergedAt)}` : "";
522
+ return `${C.yellow}Merged, unverified${C.reset}: the pull request merged${at} before its checks or review passed, so the stage stays at review.
523
+
524
+ `;
525
+ }
517
526
  function statusOutput(data, json) {
518
527
  if (json) return JSON.stringify(data);
519
- const document = JSON.stringify(data, null, 2);
528
+ const document = mergedUnverifiedLine(data) + JSON.stringify(data, null, 2);
520
529
  const criteria = data.criteria;
521
530
  if (criteria === void 0) return document;
522
531
  if (criteria === null || !Array.isArray(criteria.items)) return `${document}
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RELAY_PORT, GATEWAY_SOCKET, GATEWAY_PORT, CLAUDE_SOCKET, CLAUDE_PORT, DESTINATION_BASE_PORT } from './chunk-BN3CSI7S.js';
3
+ import { RELAY_PORT, GATEWAY_SOCKET, GATEWAY_PORT, CLAUDE_SOCKET, CLAUDE_PORT, DESTINATION_BASE_PORT } from './chunk-2K3TCQHW.js';
4
4
  import { symlinkSync, unlinkSync } from 'fs';
5
5
  import { join } from 'path';
6
6
 
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { readDefaultBranchHead, cloneRepository, buildRepositoryImage } from './chunk-TTLVQZSH.js';
3
+ import { runnerImageVersion } from './chunk-5222PA6S.js';
4
+ import { readDefaultBranchHead, cloneRepository, buildRepositoryImage } from './chunk-AXPCGD46.js';
4
5
  import { startTimeOf, isSameProcess } from './chunk-JBJTC3UU.js';
5
6
  import { currentCliBuild } from './chunk-OGFGZQA3.js';
6
- import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, JUDGE_DIR, JUDGE_REPORT, MAX_REPORT_BYTES, spawnRun } from './chunk-5XCAPBE2.js';
7
- import { RecipeError, CLAUDE_CODE_VERSION, firecrackerArch, MICROVM_ARCHES, DEFAULT_BASE_IMAGE, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, FIRECRACKER_VERSION, GUEST_ASSETS_VERSION } from './chunk-3W333NFO.js';
8
- import { execCapture } from './chunk-LY2L3O2O.js';
9
- import { GUEST_CID } from './chunk-PDIM5T65.js';
10
- import { describeCallFailure, controlPlaneTokenFailure, refusalCode, resolveGoverningSource, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, shimScript } from './chunk-TQ6Y7YV6.js';
11
- import { WorkCommandError } from './chunk-RVYOOYOA.js';
7
+ import { createDockerHost, builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, HASH_ARGV, parseProgramHash, JUDGE_PROGRAM, containerExecArgs, childEnvironment, JUDGE_DIR, JUDGE_REPORT, MAX_REPORT_BYTES, spawnRun } from './chunk-QUGYGO6L.js';
8
+ import { hostHelperPinned, firecrackerArch, MICROVM_ARCHES, RecipeError, DOCKER_FEATURE, CLAUDE_CODE_VERSION, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, JAILER_BINARY_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, FIRECRACKER_VERSION, GUEST_ASSETS_VERSION, DEFAULT_BASE_IMAGE } from './chunk-RGW7ERF3.js';
9
+ import { execCapture } from './chunk-7OWPLRJR.js';
10
+ import { GUEST_CID } from './chunk-XGJUNNXL.js';
11
+ import { describeCallFailure, controlPlaneTokenFailure, refusalCode, resolveGoverningSource, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, shimScript } from './chunk-YMKQVCKC.js';
12
+ import { WorkCommandError } from './chunk-X5LNCIZT.js';
12
13
  import { hostAllowed } from './chunk-UXYLWVTQ.js';
13
14
  import { parseDuKilobytes } from './chunk-7RQ73DLO.js';
14
15
  import { sharedSkillNames, skillConflictMessage } from './chunk-VPEGE3QZ.js';
@@ -16,11 +17,12 @@ import { versionAtLeast, MINIMUM_CLAUDE_VERSION } from './chunk-HCVLP7XA.js';
16
17
  import { setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-D4AMAEZ7.js';
17
18
  import { orderSessions, extractFacts, sessionsToTimeline } from './chunk-RKOTJQVG.js';
18
19
  import { downconvertSession } from './chunk-QZBXLLTV.js';
19
- import { rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, deliveryDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, buildDir, RUNNER_DIR_MODE, SHIM_DIR, vmAssetsDir } from './chunk-KF37SUDM.js';
20
- import { repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING, checkoutPath, JOB_MOUNT } from './chunk-BN3CSI7S.js';
21
- import { RELAY_USER, RELAY_ID, UNKNOWN_TRANSPORT_REASON, MAX_MALFORMED_SESSIONS, MALFORMED_REASON, MAX_OPEN_STREAMS, STREAM_WINDOW, SESSION_WINDOW, targetOfPath } from './chunk-GISNHSYL.js';
22
- import { readFileSync, existsSync, mkdirSync, chmodSync, truncateSync, rmSync, writeFileSync, readdirSync, lstatSync, copyFileSync, accessSync, constants, statSync, rmdirSync, renameSync, unlinkSync, openSync, closeSync, mkdtempSync, createWriteStream, createReadStream } from 'fs';
20
+ import { vmAssetsDir, RUNNER_DIR_MODE, rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, deliveryDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, buildDir, SHIM_DIR } from './chunk-ZI2ZVWKT.js';
21
+ import { repositoriesOf, primaryOf, RELAY_PORT, repositoryPath, CHECKOUT_DIR, lifecycleWorkdir, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING, checkoutPath, JOB_MOUNT } from './chunk-2K3TCQHW.js';
22
+ import { RELAY_USER, RELAY_ID, UNKNOWN_TRANSPORT_REASON, DOCKER_DESKTOP_REASON, MAX_MALFORMED_SESSIONS, MALFORMED_REASON, MAX_OPEN_STREAMS, STREAM_WINDOW, SESSION_WINDOW, targetOfPath } from './chunk-JGD5TWQ2.js';
23
+ import { readFileSync, mkdirSync, existsSync, mkdtempSync, rmSync, chmodSync, truncateSync, writeFileSync, readdirSync, lstatSync, copyFileSync, accessSync, constants, statSync, rmdirSync, renameSync, unlinkSync, openSync, closeSync, createWriteStream, createReadStream } from 'fs';
23
24
  import { join, dirname, basename } from 'path';
25
+ import { isIP, createConnection, connect, createServer as createServer$1 } from 'net';
24
26
  import { spawnSync, spawn } from 'child_process';
25
27
  import { availableParallelism, networkInterfaces } from 'os';
26
28
  import { randomBytes, createHash } from 'crypto';
@@ -30,7 +32,6 @@ import { createServer, request } from 'http';
30
32
  import { request as request$1 } from 'https';
31
33
  import { pipeline, finished } from 'stream/promises';
32
34
  import { createGunzip, gunzipSync, constants as constants$1 } from 'zlib';
33
- import { isIP, connect, createServer as createServer$1 } from 'net';
34
35
  import { lookup } from 'dns/promises';
35
36
 
36
37
  createRequire(import.meta.url);
@@ -144,6 +145,101 @@ function realCgroupPort() {
144
145
  remove: (path) => removeBuildCgroup(fs, path)
145
146
  };
146
147
  }
148
+ var SUPPORTED_HELPER_PROTOCOLS = [1];
149
+ var HELPER_ENV = "OUTERLAYER_HELPER_SOCKET";
150
+ var HelperRefusal = class extends Error {
151
+ constructor(code, reason) {
152
+ super(reason);
153
+ this.code = code;
154
+ }
155
+ };
156
+ function helperSocketPath(unitName) {
157
+ return `/run/${unitName}-helper/helper.sock`;
158
+ }
159
+ var START_TIMEOUT_MS = 12e4;
160
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
161
+ var MAX_REPLY_BYTES = 1024 * 1024;
162
+ function ask(socketPath, request, timeoutMs) {
163
+ return new Promise((resolve, reject) => {
164
+ const conn = createConnection(socketPath);
165
+ let text = "";
166
+ let settled = false;
167
+ const settle = (finish) => {
168
+ if (settled) return;
169
+ settled = true;
170
+ conn.destroy();
171
+ finish();
172
+ };
173
+ conn.setTimeout(timeoutMs, () => settle(() => reject(new Error(`the helper at ${socketPath} did not answer within ${Math.round(timeoutMs / 1e3)} seconds`))));
174
+ conn.on("connect", () => conn.write(`${JSON.stringify(request)}
175
+ `));
176
+ conn.on("data", (chunk) => {
177
+ text += chunk.toString("utf8");
178
+ if (text.length > MAX_REPLY_BYTES) return settle(() => reject(new Error(`the helper at ${socketPath} sent a reply that is too long`)));
179
+ const end = text.indexOf("\n");
180
+ if (end === -1) return;
181
+ settle(() => {
182
+ let reply;
183
+ try {
184
+ reply = JSON.parse(text.slice(0, end));
185
+ } catch {
186
+ return reject(new Error(`the helper at ${socketPath} sent a reply that is not JSON`));
187
+ }
188
+ if (reply.status === "refused") return reject(new HelperRefusal(String(reply.code ?? "refused"), String(reply.reason ?? "the helper refused the request")));
189
+ resolve(reply);
190
+ });
191
+ });
192
+ conn.on("error", (err) => settle(() => reject(new Error(`the helper at ${socketPath} did not answer: ${err.message}`))));
193
+ conn.on("close", () => settle(() => reject(new Error(`the helper at ${socketPath} closed the connection without a reply`))));
194
+ });
195
+ }
196
+ function helperClient(socketPath, options = {}) {
197
+ const REQUEST_TIMEOUT_MS = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
198
+ return {
199
+ async start({ build, kind }) {
200
+ const reply = await ask(socketPath, { v: 1, op: "start", build, kind }, START_TIMEOUT_MS);
201
+ return { unit: String(reply.unit), chroot: String(reply.chroot), vsock: String(reply.vsock) };
202
+ },
203
+ async stop(build) {
204
+ await ask(socketPath, { v: 1, op: "stop", build }, REQUEST_TIMEOUT_MS);
205
+ },
206
+ async state(build) {
207
+ const reply = await ask(socketPath, { v: 1, op: "state", build }, REQUEST_TIMEOUT_MS);
208
+ return { active: reply.active === true, oomKills: typeof reply.oomKills === "number" ? reply.oomKills : 0 };
209
+ },
210
+ async list() {
211
+ const reply = await ask(socketPath, { v: 1, op: "list" }, REQUEST_TIMEOUT_MS);
212
+ return Array.isArray(reply.builds) ? reply.builds.map(String) : [];
213
+ }
214
+ };
215
+ }
216
+ function reinstallMessage(protocol) {
217
+ const spoken = protocol === void 0 ? "a protocol it does not name" : `protocol ${protocol}`;
218
+ return `the root helper speaks ${spoken}, which this runner does not support, so microVM builds run without the jailer; run \`outerlayer runner install --service --replace\` to install the helper that goes with this release`;
219
+ }
220
+ async function probeHelper(socketPath, options = {}) {
221
+ if (socketPath === void 0 || socketPath === "") return { ok: false, reason: "absent", detail: `${HELPER_ENV} is not set, so this runner was not started by a service that has a helper` };
222
+ if (!(options.pinned ?? hostHelperPinned())) return { ok: false, reason: "unpinned", detail: "this release of the CLI pins no helper, so builds run without the jailer" };
223
+ try {
224
+ const reply = await ask(socketPath, { v: 1, op: "hello" }, options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS);
225
+ const protocol = typeof reply.protocol === "number" ? reply.protocol : void 0;
226
+ if (protocol === void 0 || !SUPPORTED_HELPER_PROTOCOLS.includes(protocol)) return { ok: false, reason: "unsupported", detail: reinstallMessage(protocol) };
227
+ return { ok: true, client: helperClient(socketPath, { requestTimeoutMs: options.requestTimeoutMs }), firecracker: String(reply.firecracker ?? "") };
228
+ } catch (err) {
229
+ const message = err instanceof Error ? err.message : String(err);
230
+ return { ok: false, reason: "absent", unreachable: true, detail: message.includes(socketPath) ? message : `the helper at ${socketPath} did not answer: ${message}` };
231
+ }
232
+ }
233
+ function jailedAlive(unit, cgroupRoot = "/sys/fs/cgroup") {
234
+ try {
235
+ return /^populated 1$/m.test(readFileSync(join(cgroupRoot, "system.slice", `${unit}.service`, "cgroup.events"), "utf8"));
236
+ } catch {
237
+ return false;
238
+ }
239
+ }
240
+ function realHelperPort(env = process.env) {
241
+ return { probe: () => probeHelper(env[HELPER_ENV]), alive: (unit) => jailedAlive(unit) };
242
+ }
147
243
  var BranchPrepareError = class extends Error {
148
244
  };
149
245
  var OWN_PREFIX = "outerlayer/";
@@ -353,7 +449,8 @@ function pinnedAssets(arch) {
353
449
  firecracker: {
354
450
  url: `${FIRECRACKER_RELEASES}/v${version}/firecracker-v${version}-${arch}.tgz`,
355
451
  sha256: FIRECRACKER_SHA256[arch],
356
- binarySha256: FIRECRACKER_BINARY_SHA256[arch]
452
+ binarySha256: FIRECRACKER_BINARY_SHA256[arch],
453
+ jailerSha256: JAILER_BINARY_SHA256[arch]
357
454
  },
358
455
  kernel: { url: `${GUEST_ASSETS_BASE_URL}/vmlinux-${arch}`, sha256: GUEST_KERNEL_SHA256[arch] },
359
456
  helper: { url: `${GUEST_ASSETS_BASE_URL}/outerlayer-guest-${arch}`, sha256: GUEST_HELPER_SHA256[arch] }
@@ -392,14 +489,45 @@ async function ensureFile(dir, file, pin, fetchImpl, mode) {
392
489
  writeAtomic(path, bytes, mode);
393
490
  return path;
394
491
  }
395
- function extractWithTar(arch) {
396
- const name = `firecracker-v${FIRECRACKER_VERSION}-${arch}`;
492
+ function extractWithTar(arch, program = "firecracker") {
493
+ const name = `${program}-v${FIRECRACKER_VERSION}-${arch}`;
397
494
  return async (tarball, destDir) => {
398
495
  const result = spawnSync("tar", ["-xzf", tarball, "-C", destDir, "--strip-components=1", `release-v${FIRECRACKER_VERSION}-${arch}/${name}`], { encoding: "utf8" });
399
496
  if (result.status !== 0) throw new Error(`tar could not unpack ${tarball}: ${result.stderr.trim()}`);
400
497
  return join(destDir, name);
401
498
  };
402
499
  }
500
+ async function ensureFirecracker(input) {
501
+ const { dir, arch, pins, fetchImpl } = input;
502
+ const firecracker = join(dir, "firecracker");
503
+ if (existsSync(firecracker)) {
504
+ const actual = sha256Of(readFileSync(firecracker));
505
+ if (actual !== pins.firecracker.binarySha256) throw pinProblem("firecracker", pins.firecracker.binarySha256, actual, `at ${firecracker}`);
506
+ return firecracker;
507
+ }
508
+ const tarballName = `firecracker-${arch}.tgz`;
509
+ const tarball = await ensureFile(dir, tarballName, pins.firecracker, fetchImpl, RUNNER_FILE_MODE);
510
+ const scratch = mkdtempSync(join(dir, ".extract-"));
511
+ try {
512
+ const extracted = await (input.extract ?? extractWithTar(arch))(tarball, scratch);
513
+ const bytes = readFileSync(extracted);
514
+ const actual = sha256Of(bytes);
515
+ if (actual !== pins.firecracker.binarySha256) throw pinProblem("firecracker", pins.firecracker.binarySha256, actual, `unpacked from ${tarballName}`);
516
+ writeAtomic(firecracker, bytes, 493);
517
+ } finally {
518
+ rmSync(scratch, { recursive: true, force: true });
519
+ }
520
+ return firecracker;
521
+ }
522
+ async function ensureFirecrackerAndJailer(options) {
523
+ const arch = options.arch ?? firecrackerArch(process.arch);
524
+ if (!MICROVM_ARCHES.includes(arch)) throw new AssetError("firecracker", `no Firecracker assets are pinned for ${arch}, so microVM builds run on ${MICROVM_ARCHES.join(" or ")} hosts only`);
525
+ const pins = options.pins ?? pinnedAssets(arch);
526
+ const dir = vmAssetsDir(options.runnerDir);
527
+ mkdirSync(dir, { recursive: true, mode: RUNNER_DIR_MODE });
528
+ const firecracker = await ensureFirecracker({ dir, arch, pins, fetchImpl: options.fetchImpl ?? fetch, extract: options.extractFirecracker });
529
+ return { firecracker, jailer: await ensureJailer(options) };
530
+ }
403
531
  async function ensureAssets(options) {
404
532
  const arch = options.arch ?? firecrackerArch(process.arch);
405
533
  if (!MICROVM_ARCHES.includes(arch)) throw new AssetError("firecracker", `no Firecracker or guest assets are pinned for ${arch}, so microVM builds run on ${MICROVM_ARCHES.join(" or ")} hosts only`);
@@ -407,28 +535,40 @@ async function ensureAssets(options) {
407
535
  const fetchImpl = options.fetchImpl ?? fetch;
408
536
  const dir = vmAssetsDir(options.runnerDir);
409
537
  mkdirSync(dir, { recursive: true, mode: RUNNER_DIR_MODE });
410
- const firecracker = join(dir, "firecracker");
411
- if (existsSync(firecracker)) {
412
- const actual = sha256Of(readFileSync(firecracker));
413
- if (actual !== pins.firecracker.binarySha256) throw pinProblem("firecracker", pins.firecracker.binarySha256, actual, `at ${firecracker}`);
414
- } else {
415
- const tarballName = `firecracker-${arch}.tgz`;
416
- const tarball = await ensureFile(dir, tarballName, pins.firecracker, fetchImpl, RUNNER_FILE_MODE);
417
- const scratch = mkdtempSync(join(dir, ".extract-"));
418
- try {
419
- const extracted = await (options.extractFirecracker ?? extractWithTar(arch))(tarball, scratch);
420
- const bytes = readFileSync(extracted);
421
- const actual = sha256Of(bytes);
422
- if (actual !== pins.firecracker.binarySha256) throw pinProblem("firecracker", pins.firecracker.binarySha256, actual, `unpacked from ${tarballName}`);
423
- writeAtomic(firecracker, bytes, 493);
424
- } finally {
425
- rmSync(scratch, { recursive: true, force: true });
426
- }
427
- }
538
+ const firecracker = await ensureFirecracker({ dir, arch, pins, fetchImpl, extract: options.extractFirecracker });
428
539
  const kernel = await ensureFile(dir, `vmlinux-${arch}`, pins.kernel, fetchImpl, RUNNER_FILE_MODE);
429
540
  const helper = await ensureFile(dir, `outerlayer-guest-${arch}`, pins.helper, fetchImpl, 493);
430
541
  return { firecracker, kernel, helper, helperSha256: pins.helper.sha256 };
431
542
  }
543
+ async function ensureJailer(options) {
544
+ const arch = options.arch ?? firecrackerArch(process.arch);
545
+ if (!MICROVM_ARCHES.includes(arch)) throw new AssetError("jailer", `no Firecracker assets are pinned for ${arch}, so microVM builds run on ${MICROVM_ARCHES.join(" or ")} hosts only`);
546
+ const pins = options.pins ?? pinnedAssets(arch);
547
+ const expected = pins.firecracker.jailerSha256;
548
+ if (expected === void 0) throw new AssetError("jailer", "this release pins no hash for the jailer, so it cannot be had");
549
+ const fetchImpl = options.fetchImpl ?? fetch;
550
+ const dir = vmAssetsDir(options.runnerDir);
551
+ mkdirSync(dir, { recursive: true, mode: RUNNER_DIR_MODE });
552
+ const jailer = join(dir, "jailer");
553
+ if (existsSync(jailer)) {
554
+ const actual = sha256Of(readFileSync(jailer));
555
+ if (actual !== expected) throw pinProblem("jailer", expected, actual, `at ${jailer}`);
556
+ return jailer;
557
+ }
558
+ const tarballName = `firecracker-${arch}.tgz`;
559
+ const tarball = await ensureFile(dir, tarballName, pins.firecracker, fetchImpl, RUNNER_FILE_MODE);
560
+ const scratch = mkdtempSync(join(dir, ".extract-"));
561
+ try {
562
+ const extracted = await (options.extractJailer ?? extractWithTar(arch, "jailer"))(tarball, scratch);
563
+ const bytes = readFileSync(extracted);
564
+ const actual = sha256Of(bytes);
565
+ if (actual !== expected) throw pinProblem("jailer", expected, actual, `unpacked from ${tarballName}`);
566
+ writeAtomic(jailer, bytes, 493);
567
+ } finally {
568
+ rmSync(scratch, { recursive: true, force: true });
569
+ }
570
+ return jailer;
571
+ }
432
572
  var STOP_GRACE_SECONDS = 15;
433
573
  function parseImageConfig(json) {
434
574
  const config = JSON.parse(json);
@@ -755,6 +895,7 @@ function createMicroVmPorts(over = {}) {
755
895
  rootfs: over.rootfs ?? createRootfsHost(),
756
896
  firecracker: over.firecracker ?? createFirecrackerHost(),
757
897
  cgroup: over.cgroup ?? realCgroupPort(),
898
+ helper: over.helper ?? realHelperPort(),
758
899
  exec: over.exec ?? execCapture
759
900
  };
760
901
  }
@@ -2343,6 +2484,7 @@ function createContainerRuntime(opts = {}) {
2343
2484
  tunnelOptions: opts.tunnelOptions,
2344
2485
  sleep: opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
2345
2486
  hostEnv: opts.hostEnv ?? process.env,
2487
+ platform: opts.platform ?? process.platform,
2346
2488
  credentials: opts.credentials ?? /* @__PURE__ */ new Map(),
2347
2489
  github: { gitUrl: opts.github?.gitUrl ?? "https://github.com", apiUrl: opts.github?.apiUrl ?? "https://api.github.com" },
2348
2490
  remoteFor,
@@ -2531,8 +2673,8 @@ async function provisionContainer(input) {
2531
2673
  if (!(Number.parseInt(engine, 10) >= MIN_ENGINE_MAJOR)) {
2532
2674
  return fail(`Docker Engine ${engine} is too old: container builds need Engine ${MIN_ENGINE_MAJOR} or later`);
2533
2675
  }
2534
- if (/docker desktop/i.test(await host.operatingSystem() ?? "")) {
2535
- return fail("Docker Desktop cannot pass the tunnel's socket into a container, so container builds need Docker Engine: install it (on Windows, inside WSL2) or use builtin:process");
2676
+ if (/docker desktop/i.test(await host.operatingSystem() ?? "") && !(runnerImageVersion(runtime.hostEnv) !== void 0 && runtime.platform === "linux")) {
2677
+ return fail(DOCKER_DESKTOP_REASON);
2536
2678
  }
2537
2679
  const governing = await resolveGoverningSource({ config, repository, fetchImpl: input.fetchImpl });
2538
2680
  if (!governing.ok) return fail(governing.reason);
@@ -2587,11 +2729,16 @@ async function provisionContainer(input) {
2587
2729
  if (env.skippedTokenVariables.length > 0) {
2588
2730
  log.line(`${tag} not passing ${env.skippedTokenVariables.join(", ")} from runner.build.variables into the build: its repository token comes from the runner`);
2589
2731
  }
2732
+ const ignoredProperties = report.ignored.map(({ property, source }) => ({ property, source }));
2733
+ if (report.docker) {
2734
+ ignoredProperties.push({ property: "docker daemon", source: `feature ${DOCKER_FEATURE}` });
2735
+ log.line(`${tag} container builds have no Docker daemon, so steps that run Docker will fail`);
2736
+ }
2590
2737
  const environment = {
2591
2738
  isolation: "container",
2592
2739
  recipe: { sourceCommit: report.sourceCommit, key: report.recipeKey, path: report.recipe },
2593
2740
  imageId: report.imageId,
2594
- ignoredProperties: report.ignored.map(({ property, source }) => ({ property, source })),
2741
+ ignoredProperties,
2595
2742
  variables: env.variables,
2596
2743
  cliVersion: input.cliVersion
2597
2744
  };
@@ -3157,4 +3304,4 @@ async function startCheckContainer(input) {
3157
3304
  };
3158
3305
  }
3159
3306
 
3160
- export { ADDED_USER, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, LEASE_SECONDS, MIN_ENGINE_MAJOR, cleanupContainer, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, deleteBuildDisk, deliverContainerHooks, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, writeEvalInput };
3307
+ export { ADDED_USER, AgentUserError, AssetError, DeliveryFailure, EVAL_INPUT_NAME, GH_CONFIG_YML, HelperRefusal, LEASE_SECONDS, MIN_ENGINE_MAJOR, cleanupContainer, containerCommandExec, containerJudgeEnvironment, containerSenderCommand, copyJudgeTree, copyTranscripts, copyTranscriptsFromContainer, createBuildDisk, createContainerRuntime, deleteBuildDisk, deliverContainerHooks, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, helperSocketPath, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, probeHelper, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, writeEvalInput };
@@ -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-KF37SUDM.js';
3
+ import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZI2ZVWKT.js';
4
4
  import { readFileSync, existsSync, rmSync, mkdirSync, writeFileSync, renameSync } from 'fs';
5
5
  import { join } from 'path';
6
6
 
@@ -11,6 +11,13 @@ function readPendingUpdate(runnerDirPath) {
11
11
  const raw = JSON.parse(readFileSync(join(runnerDirPath, FILE), "utf8"));
12
12
  if (typeof raw.version !== "string" || typeof raw.since !== "string") return void 0;
13
13
  const record = { version: raw.version, since: raw.since };
14
+ if (raw.via === "self-update" || raw.via === "install") record.via = raw.via;
15
+ if (Array.isArray(raw.waits)) {
16
+ record.waits = raw.waits.flatMap((entry) => {
17
+ const wait = entry;
18
+ return wait && typeof wait.item === "number" && typeof wait.reason === "string" ? [{ item: wait.item, reason: wait.reason }] : [];
19
+ });
20
+ }
14
21
  const holding = raw.holding;
15
22
  if (holding && Array.isArray(holding.builds) && typeof holding.since === "string") {
16
23
  record.holding = { builds: holding.builds.filter((n) => typeof n === "number"), since: holding.since };
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { WorkCommandError, postJson } from './chunk-RVYOOYOA.js';
4
- import { defaultGitRunner, materializeContext, isStagingWriteFault, lookupGoverningSource } from './chunk-E4OUL7ZP.js';
5
- import { signingFetchFor } from './chunk-FKXGQOF5.js';
3
+ import { WorkCommandError, postJson } from './chunk-X5LNCIZT.js';
4
+ import { defaultGitRunner, materializeContext, isStagingWriteFault, lookupGoverningSource } from './chunk-FXUVXSY2.js';
5
+ import { signingFetchFor } from './chunk-M4B6QKNZ.js';
6
6
  import { unsupportedLayout, layoutRefusalReason, composeDelivery } from './chunk-VPEGE3QZ.js';
7
7
  import { SHIM_SCRIPT, GOVERNANCE_VARIABLE } from './chunk-HCVLP7XA.js';
8
8
  import { readDegraded, readContextManifest, readSourceCache } from './chunk-YQR6E6OV.js';
9
- import { signerFor } from './chunk-PVRBE7S4.js';
10
- import { SHIM_DIR, stagedContextDir, contextHomeDir, deliveryDir } from './chunk-KF37SUDM.js';
9
+ import { signerFor } from './chunk-ZODVSFI4.js';
10
+ import { SHIM_DIR, stagedContextDir, contextHomeDir, deliveryDir } from './chunk-ZI2ZVWKT.js';
11
11
  import { fstatSync, mkdirSync, writeFileSync, chmodSync, rmSync, lstatSync } from 'fs';
12
12
  import { relative, join, dirname } from 'path';
13
13
 
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { uploadSpooledSteps } from './chunk-F7Y2USIM.js';
3
+ import { uploadSpooledSteps } from './chunk-IDJIWKTY.js';
4
4
  import { LaunchFilter } from './chunk-ESVW4MJY.js';
5
5
  import { RepoFilter } from './chunk-TBT347UY.js';
6
6
  import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, acquireArtifactSpoolLock, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-BUP5N3X6.js';
7
- import { cliFetch, resolveGatewayCredentials, defaultFetch, unauthorizedMessage } from './chunk-FKXGQOF5.js';
8
- import { writeSyncStatus, spoolDir } from './chunk-755WXDBI.js';
7
+ import { cliFetch, resolveGatewayCredentials, defaultFetch, unauthorizedMessage } from './chunk-M4B6QKNZ.js';
8
+ import { writeSyncStatus, spoolDir } from './chunk-K5WVK7IC.js';
9
9
  import { readLatestProvenanceForSession, readContextProvenance } from './chunk-ZJSNLVCE.js';
10
10
  import { hookExecSpoolPath } from './chunk-DYEFPYME.js';
11
11
  import { applyReportedCost } from './chunk-BKO6JEZI.js';
@@ -18,7 +18,7 @@ import { cliInvocation } from './chunk-CRB3POP4.js';
18
18
  import { removeJournalHooks } from './chunk-TUSYOL2O.js';
19
19
  import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-QZBXLLTV.js';
20
20
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
21
- import { signerFor, signRunnerRequest } from './chunk-PVRBE7S4.js';
21
+ import { signerFor, signRunnerRequest } from './chunk-ZODVSFI4.js';
22
22
  import { dirname, basename, join } from 'path';
23
23
  import { statSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync, rmSync } from 'fs';
24
24
  import { execFileSync } from 'child_process';
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { DEFAULT_UNIT_NAME } from './chunk-DG2ULWM6.js';
3
+ import { DEFAULT_UNIT_NAME } from './chunk-IGRRD7PX.js';
4
4
  import { parseRunnerEnv } from './chunk-6MZSX4M7.js';
5
- import { RUNNER_FILE_MODE } from './chunk-KF37SUDM.js';
5
+ import { RUNNER_FILE_MODE } from './chunk-ZI2ZVWKT.js';
6
6
  import { existsSync, readFileSync, writeFileSync, renameSync, rmSync } from 'fs';
7
7
  import { join, dirname } from 'path';
8
8
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { BUILD_HOME } from './chunk-BN3CSI7S.js';
3
+ import { BUILD_HOME } from './chunk-2K3TCQHW.js';
4
4
  import { join, dirname } from 'path';
5
5
 
6
6
  createRequire(import.meta.url);
@@ -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-KF37SUDM.js';
3
+ import { hostKeyPath, runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZI2ZVWKT.js';
4
4
  import { generateKeyPairSync, createPrivateKey, createPublicKey, sign } from 'crypto';
5
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
6
6
 
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/runner/job-state-format.ts
7
+ var JOB_STATE_FORMAT = 1;
8
+ var READ_JOB_STATE_FORMATS = [1];
9
+ function jobStateFormatOf(job) {
10
+ return job.stateFormat ?? 1;
11
+ }
12
+ function readsJobState(job, formats) {
13
+ return formats.includes(jobStateFormatOf(job));
14
+ }
15
+ function jobStateFormatsAnswer() {
16
+ return { reads: [...READ_JOB_STATE_FORMATS], writes: JOB_STATE_FORMAT };
17
+ }
18
+
19
+ export { JOB_STATE_FORMAT, READ_JOB_STATE_FORMATS, jobStateFormatOf, jobStateFormatsAnswer, readsJobState };