@outerlayer/cli 0.6.0 → 0.8.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 (92) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +15 -5
  3. package/dist/{agent-setup-USZ2SAXC.js → agent-setup-C7PLRXZO.js} +7 -6
  4. package/dist/{build-PAEKVYVK.js → build-MS34XEGN.js} +3 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/builder-G52A6GW2.js +13 -0
  7. package/dist/{check-CCVPBN7A.js → check-FOF3PUKI.js} +35 -26
  8. package/dist/{chunk-ZILGTTY6.js → chunk-3S4P55NE.js} +3 -3
  9. package/dist/{chunk-MIGEDH5P.js → chunk-4A5E2G4E.js} +9 -9
  10. package/dist/chunk-4ACZCY4I.js +39 -0
  11. package/dist/{chunk-OIRNH6UO.js → chunk-5FWNEQNZ.js} +3 -3
  12. package/dist/{chunk-BNMCXPG7.js → chunk-5QLNZGAQ.js} +12 -3
  13. package/dist/chunk-5TNS3PL7.js +263 -0
  14. package/dist/chunk-7RQ73DLO.js +23 -0
  15. package/dist/{chunk-VMJ3MMBX.js → chunk-7VNURP6M.js} +538 -46
  16. package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
  17. package/dist/{chunk-UMFWVGJO.js → chunk-AIL2R4SI.js} +4 -3
  18. package/dist/{chunk-NQXFAGHU.js → chunk-AX23QKHS.js} +7 -3
  19. package/dist/{chunk-RZSF5B46.js → chunk-CM5QTKM4.js} +152 -158
  20. package/dist/chunk-CX22S5BA.js +45 -0
  21. package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
  22. package/dist/{chunk-ANK2B36Y.js → chunk-GAYWY4GI.js} +6190 -28615
  23. package/dist/chunk-HKMPVPO7.js +55 -0
  24. package/dist/{chunk-43J3M6KB.js → chunk-IJBVPLZZ.js} +91 -39
  25. package/dist/{chunk-PMAMOSTP.js → chunk-ILEA3YHM.js} +85 -25
  26. package/dist/{chunk-MXB5VB4Y.js → chunk-IRCBTGWF.js} +6 -6
  27. package/dist/{chunk-OUUINEYB.js → chunk-JKIWMRFH.js} +1 -1
  28. package/dist/{chunk-FA2BOX4O.js → chunk-JPR2WHHF.js} +1 -1
  29. package/dist/{chunk-IASWYRVG.js → chunk-K35RW5HP.js} +4 -1
  30. package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
  31. package/dist/{chunk-4NLKY4WR.js → chunk-NALVDFIS.js} +2 -2
  32. package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
  33. package/dist/{chunk-JWOQNNN2.js → chunk-OEK4JEB3.js} +33 -4
  34. package/dist/chunk-PTW6W5NR.js +127 -0
  35. package/dist/{chunk-3DD6AOWC.js → chunk-PWBILI5P.js} +28 -3
  36. package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
  37. package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
  38. package/dist/{chunk-Z62HNKEJ.js → chunk-TTNFGMHO.js} +72 -54
  39. package/dist/{chunk-RBOMWNOG.js → chunk-TUUMW4TC.js} +2 -2
  40. package/dist/{chunk-774HEQL6.js → chunk-U3GOI2B4.js} +91 -8
  41. package/dist/{chunk-F6GFZXZ3.js → chunk-UXYLWVTQ.js} +1 -18
  42. package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
  43. package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
  44. package/dist/chunk-YNJEOGDL.js +22434 -0
  45. package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
  46. package/dist/{chunk-3DEVYTNQ.js → chunk-ZYHKJKSU.js} +1 -1
  47. package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
  48. package/dist/{cli-7WCNPBYC.js → cli-AOJPAVFX.js} +109 -81
  49. package/dist/{command-ARFK3OYF.js → command-SY3SVLAI.js} +67 -27
  50. package/dist/config-Z3USDBLU.js +11 -0
  51. package/dist/{connect-cmd-PCESZLTR.js → connect-cmd-PNZ6IJLJ.js} +4 -4
  52. package/dist/{context-adopt-G5JAELE7.js → context-adopt-CE4KDXS3.js} +5 -4
  53. package/dist/{context-materialize-3HLPZAF6.js → context-materialize-QL33HDJN.js} +5 -4
  54. package/dist/{dist-RDLP4GGJ.js → dist-3ZTZF2TP.js} +2 -1
  55. package/dist/docker-676FD3CQ.js +15 -0
  56. package/dist/{doctor-VOMYOHQU.js → doctor-WR6TRPSU.js} +49 -19
  57. package/dist/{emit-artifact-cmd-TBF46VXZ.js → emit-artifact-cmd-AVM4YXMQ.js} +11 -4
  58. package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
  59. package/dist/{emit-criteria-cmd-3427XKFW.js → emit-criteria-cmd-LDBE4YDS.js} +10 -1
  60. package/dist/{emit-finding-cmd-GSI75K36.js → emit-finding-cmd-6R5WBPCH.js} +12 -1
  61. package/dist/{emit-result-cmd-3PRQKB55.js → emit-result-cmd-2DMN6O6U.js} +13 -6
  62. package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
  63. package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
  64. package/dist/{hook-fast-NJBBZQ5Q.js → hook-fast-XBOZ3N6L.js} +1 -1
  65. package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
  66. package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
  67. package/dist/index.js +3 -3
  68. package/dist/init-KDK5QLQZ.js +46 -0
  69. package/dist/{init-OHYFIKZD.js → init-R2FJ5KNS.js} +35 -21
  70. package/dist/{init-cmd-HMFNIFPI.js → init-cmd-BYZYAJ5P.js} +10 -9
  71. package/dist/{install-DSUZE2TJ.js → install-FHTVJZS6.js} +7 -5
  72. package/dist/{install-cmd-453C7IZT.js → install-cmd-DCF7TVXD.js} +3 -2
  73. package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
  74. package/dist/{loop-UAJB34KA.js → loop-AG3PLXPO.js} +35 -26
  75. package/dist/machine-LV6WBRRK.js +45 -0
  76. package/dist/{session-sender-ED26V45B.js → session-sender-Q5HAMOL2.js} +6 -5
  77. package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
  78. package/dist/{status-6WNXX2O7.js → status-HH4OSOHR.js} +29 -20
  79. package/dist/{sync-cmd-YONVGUYS.js → sync-cmd-CAEPJR7B.js} +5 -4
  80. package/dist/{watch-HHKAF26L.js → watch-LAAZFBHH.js} +5 -4
  81. package/dist/{work-claim-cmd-LXBZTMJA.js → work-claim-cmd-ARIYZARE.js} +15 -7
  82. package/dist/{work-cmd-OVNF44FY.js → work-cmd-B3FOXZAL.js} +9 -3
  83. package/dist/{work-comment-cmd-6DGQNTAH.js → work-comment-cmd-O5WGRI6K.js} +9 -3
  84. package/dist/{work-open-pr-cmd-FCZHFHZS.js → work-open-pr-cmd-M6CQW7KW.js} +10 -4
  85. package/dist/{work-pr-cmd-QJJVHZDC.js → work-pr-cmd-C4YEGKD6.js} +9 -2
  86. package/package.json +1 -1
  87. package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
  88. package/dist/chunk-7DBI6SNT.js +0 -55
  89. package/dist/config-HL2AIR3K.js +0 -9
  90. package/dist/docker-NEGDLU6D.js +0 -7
  91. package/dist/init-WVR4BZQ4.js +0 -36
  92. package/dist/machine-2JOWGRSZ.js +0 -35
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/runner/commit-identity.ts
7
+ var NOREPLY_SUFFIX = "@users.noreply.github.com";
8
+ var MAX_LENGTH = 200;
9
+ function parseIdentity(value) {
10
+ if (typeof value !== "object" || value === null) return void 0;
11
+ const { name, email } = value;
12
+ if (typeof name !== "string" || typeof email !== "string") return void 0;
13
+ if (name.trim() === "" || name.length > MAX_LENGTH || /[\r\n\0<>]/.test(name)) return void 0;
14
+ if (email.length > MAX_LENGTH || !email.endsWith(NOREPLY_SUFFIX) || /[\s\0<>]/.test(email) || email.length === NOREPLY_SUFFIX.length) return void 0;
15
+ return { name, email };
16
+ }
17
+ function parseClaimIdentity(data) {
18
+ const author = parseIdentity(data.commitAuthor);
19
+ if (author === void 0) return void 0;
20
+ const coAuthor = parseIdentity(data.coAuthor);
21
+ return coAuthor === void 0 ? { author } : { author, coAuthor };
22
+ }
23
+ function authorEnvironment(identity) {
24
+ if (identity === void 0) return {};
25
+ return {
26
+ GIT_AUTHOR_NAME: identity.name,
27
+ GIT_AUTHOR_EMAIL: identity.email,
28
+ GIT_COMMITTER_NAME: identity.name,
29
+ GIT_COMMITTER_EMAIL: identity.email
30
+ };
31
+ }
32
+ function configCount(env) {
33
+ const raw = String(env.GIT_CONFIG_COUNT);
34
+ return /^[0-9]+$/.test(raw) ? Number(raw) : 0;
35
+ }
36
+ function withGitConfig(env, key, value) {
37
+ const at = configCount(env);
38
+ return {
39
+ ...env,
40
+ GIT_CONFIG_COUNT: String(at + 1),
41
+ [`GIT_CONFIG_KEY_${at}`]: key,
42
+ [`GIT_CONFIG_VALUE_${at}`]: value
43
+ };
44
+ }
45
+ function withHooksPath(env, dir) {
46
+ return withGitConfig(env, "core.hooksPath", dir);
47
+ }
48
+ function commitIdentityRecord(identity) {
49
+ return {
50
+ author: identity === void 0 ? "host" : "app",
51
+ coAuthor: identity?.coAuthor !== void 0 && identity.hooksPath !== void 0 ? "credited" : "none"
52
+ };
53
+ }
54
+
55
+ export { authorEnvironment, commitIdentityRecord, parseClaimIdentity, withGitConfig, withHooksPath };
@@ -1,22 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-ABIWDUMS.js';
4
- import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-YYYXRJUW.js';
5
- import { LEASE_SECONDS, releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, ALREADY_RELEASED } from './chunk-VMJ3MMBX.js';
4
+ import { LEASE_SECONDS, releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, ALREADY_RELEASED } from './chunk-7VNURP6M.js';
6
5
  import { writeJobFile, readJobFile, readJobFileChecked } from './chunk-T6OIJQRT.js';
7
6
  import { RUNNER_PROTOCOL } from './chunk-AIW6GLET.js';
8
7
  import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
9
- import { placeholderQueues, placeholderProblem } from './chunk-MXB5VB4Y.js';
8
+ import { placeholderQueues, placeholderProblem } from './chunk-IRCBTGWF.js';
9
+ import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-TI7B7UEO.js';
10
10
  import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
11
11
  import { RepoFilter } from './chunk-TBT347UY.js';
12
- import { checkFit } from './chunk-OUUINEYB.js';
13
- import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, formatClock, measureDisk, createRunnerLog, setUpRunnerCgroup, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, runnerLabelValue, BUILD_LABEL, RUNNER_LABEL } from './chunk-RZSF5B46.js';
12
+ import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, measureDisk, createRunnerLog, setUpRunnerCgroup, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, formatClock } from './chunk-CM5QTKM4.js';
13
+ import { checkFit } from './chunk-JKIWMRFH.js';
14
14
  import { startTimeOf, claimPidFile, readPidFile, isSameProcess, releasePidFile } from './chunk-N5FOE5PS.js';
15
- import { spawnRun } from './chunk-774HEQL6.js';
16
- import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-BNMCXPG7.js';
17
- import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-3DD6AOWC.js';
18
- import { exceedsDisk } from './chunk-F6GFZXZ3.js';
19
- import { parseClaimIdentity, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-AUFG23AA.js';
15
+ import { spawnRun } from './chunk-U3GOI2B4.js';
16
+ import { builderName, runnerLabelValue, ensureFailureCount, builderSpec, ensureBuilder, BUILD_LABEL, RUNNER_LABEL } from './chunk-5TNS3PL7.js';
17
+ import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-5QLNZGAQ.js';
18
+ import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-PWBILI5P.js';
19
+ import { exceedsDisk } from './chunk-7RQ73DLO.js';
20
+ import { sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-OD2VTIHN.js';
21
+ import { parseClaimIdentity } from './chunk-HKMPVPO7.js';
20
22
  import { resolveVersion } from './chunk-RA3O54FC.js';
21
23
  import { loadHostKey, ensureHostKey, signerFor } from './chunk-M5POMKKW.js';
22
24
  import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, jobsDir, pidFilePath, spoolDir, RUNNER_FILE_MODE, rootfsDir } from './chunk-ZM2IMMYN.js';
@@ -36,7 +38,7 @@ function openKvm() {
36
38
  }
37
39
  }
38
40
  function realBlockedProbes() {
39
- return { env: process.env, kvm: openKvm, totalMemoryBytes: totalmem };
41
+ return { env: process.env, kvm: openKvm, totalMemoryBytes: totalmem, imageBuilder: "unknown" };
40
42
  }
41
43
  var DEFAULT_BUILD_MEMORY = "8g";
42
44
  function checkBlocked(config, probes) {
@@ -60,6 +62,13 @@ function checkBlocked(config, probes) {
60
62
  reason: "the runner cannot open /dev/kvm, so builtin:vm cannot start a microVM. Add the runner's account to the kvm group, then restart the service, because a service reads its groups only when it starts"
61
63
  };
62
64
  }
65
+ if (kind === "container" || kind === "vm") {
66
+ const builder = probes.imageBuilder;
67
+ if (builder === "unknown") {
68
+ return { reason: "the runner is still preparing its image builder, the container that limits image builds to runner.build.memory, so it claims nothing yet" };
69
+ }
70
+ if (builder !== "usable") return { reason: `${builder.problem}. The runner takes work again once its image builder works` };
71
+ }
63
72
  if (kind !== "own" && claudeCredential(probes.env) === void 0) {
64
73
  return {
65
74
  reason: "there is no Claude credential in the runner's environment. Put CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`) or ANTHROPIC_API_KEY in the runner.env beside the config, then restart the service"
@@ -670,8 +679,9 @@ function createHousekeepingDocker(deps) {
670
679
  if (result.status !== 0) throw failure(result, `docker rmi ${id}`);
671
680
  },
672
681
  async builderPrune(keepBytes) {
673
- const result = await run("docker", ["builder", "prune", "--force", "--keep-storage", String(keepBytes)]);
674
- if (result.status !== 0) throw failure(result, "docker builder prune");
682
+ const result = await run("docker", ["buildx", "prune", "--builder", deps.builder, "--force", "--max-used-space", String(keepBytes)]);
683
+ if (result.status !== 0 && /no builder .* found/i.test(result.stderr)) return { freedBytes: 0 };
684
+ if (result.status !== 0) throw failure(result, "docker buildx prune");
675
685
  return { freedBytes: parsePrunedBytes(result.stdout) };
676
686
  }
677
687
  };
@@ -690,7 +700,7 @@ function selectJobDirs(entries, nowMs, keepDays) {
690
700
  function liveBuildIds(jobs) {
691
701
  const ids = /* @__PURE__ */ new Set();
692
702
  for (const job of jobs) {
693
- for (const id of [job.container?.buildId, job.microvm?.buildId, job.build?.buildId]) if (id !== void 0) ids.add(id);
703
+ for (const id of [job.container?.buildId, job.microvm?.buildId, job.build?.buildId, job.checkContainer?.buildId]) if (id !== void 0) ids.add(id);
694
704
  }
695
705
  return ids;
696
706
  }
@@ -842,7 +852,7 @@ async function runHousekeeping(options) {
842
852
  try {
843
853
  const pruned = await docker.builderPrune(options.buildCacheMax);
844
854
  freed += pruned.freedBytes;
845
- log.line(`housekeeping: pruned the build cache down to ${formatBytes(options.buildCacheMax)}, freed ${formatBytes(pruned.freedBytes)}`);
855
+ log.line(`housekeeping: pruned the image builder's build cache down to ${formatBytes(options.buildCacheMax)}, freed ${formatBytes(pruned.freedBytes)}`);
846
856
  } catch (err) {
847
857
  log.error(`housekeeping: the build cache could not be pruned: ${describeCallFailure(err)}`);
848
858
  }
@@ -1136,10 +1146,39 @@ async function tick(state) {
1136
1146
  }
1137
1147
  await sendTickHeartbeat(state, state.lastWorkRequest);
1138
1148
  }
1149
+ function imageBuilderState(state) {
1150
+ const kind = builtinKind(state.config.hooks.provision);
1151
+ if (kind !== "container" && kind !== "vm") return "usable";
1152
+ if (state.deps.container?.buildImage !== void 0 || state.deps.container?.imageHost !== void 0) return "usable";
1153
+ const memory = state.config.build?.memory ?? "8g";
1154
+ let probe = state.imageBuilder;
1155
+ if (probe === void 0 || probe.memory !== memory) probe = state.imageBuilder = { memory, at: 0, running: false };
1156
+ if (probe.result?.ok === true && !probe.running && probe.failures !== void 0 && ensureFailureCount() !== probe.failures) probe.result = void 0;
1157
+ const nowMs = nowOf(state).getTime();
1158
+ const recheckMs = 10 * 6e4;
1159
+ const due = !probe.running && (probe.result === void 0 || !probe.result.ok || nowMs - probe.at >= recheckMs);
1160
+ if (due) {
1161
+ const checking = probe;
1162
+ checking.running = true;
1163
+ const spec = builderSpec(state.config.configPath, memory, state.deps.container?.hostEnv ?? process.env);
1164
+ const check = state.deps.builderProbe ?? ((s) => ensureBuilder(spawnRun, s, { bootstrap: true }));
1165
+ void check(spec).catch((err) => ({ ok: false, problem: `the image builder could not be checked: ${describeCallFailure(err)}` })).then((result2) => {
1166
+ checking.result = result2;
1167
+ checking.failures = ensureFailureCount();
1168
+ checking.at = nowOf(state).getTime();
1169
+ checking.running = false;
1170
+ if (result2.ok && state.blocked !== void 0 && state.pollTimerSeconds !== void 0) void tick(state);
1171
+ });
1172
+ }
1173
+ const result = probe.result;
1174
+ if (result === void 0) return "unknown";
1175
+ return result.ok ? "usable" : { problem: result.problem };
1176
+ }
1139
1177
  function holdWhenBlocked(state) {
1140
1178
  const probes = {
1141
1179
  ...realBlockedProbes(),
1142
1180
  ...state.deps.container?.hostEnv === void 0 ? {} : { env: state.deps.container.hostEnv },
1181
+ ...state.deps.blocked?.imageBuilder === void 0 ? { imageBuilder: imageBuilderState(state) } : {},
1143
1182
  ...state.deps.blocked
1144
1183
  };
1145
1184
  const blocked = checkBlocked(state.config, probes);
@@ -1193,7 +1232,7 @@ async function housekeepingPass(state) {
1193
1232
  state.housekeepingRunning = true;
1194
1233
  try {
1195
1234
  state.deps.housekeeping ??= {};
1196
- state.deps.housekeeping.docker ??= createHousekeepingDocker({ runnerId: runnerLabelValue(state.config.configPath) });
1235
+ state.deps.housekeeping.docker ??= createHousekeepingDocker({ runnerId: runnerLabelValue(state.config.configPath), builder: builderName(state.config.configPath) });
1197
1236
  const result = await runHousekeeping({
1198
1237
  configPath: state.config.configPath,
1199
1238
  keepDays: config.jobsKeepDays,
@@ -1267,7 +1306,7 @@ var CLAIM_REFUSAL_CODES = new Set(
1267
1306
  "pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous branch_claimed_elsewhere".split(" ")
1268
1307
  );
1269
1308
  async function tryClaimAndStart(state, item, queue) {
1270
- const { postJson: postJson2 } = await import('./work-cmd-OVNF44FY.js');
1309
+ const { postJson: postJson2 } = await import('./work-cmd-B3FOXZAL.js');
1271
1310
  const log = logOf(state);
1272
1311
  const hostKey = await loadHostKey(state.config.configPath);
1273
1312
  const claim = await retrySend(
@@ -1395,6 +1434,7 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity)
1395
1434
  itemKey,
1396
1435
  branch,
1397
1436
  commitIdentity: identity,
1437
+ ...item.specRepository === void 0 || item.specRepository === null || item.specRepository === "" ? {} : { repository: item.specRepository },
1398
1438
  startedAt: startedAt.toISOString()
1399
1439
  };
1400
1440
  writeJobFile(jobFilePath, job);
@@ -1864,8 +1904,39 @@ async function endJob(state, active, outcome, ending) {
1864
1904
  state.jobs.delete(active.dirPath);
1865
1905
  }
1866
1906
  }
1907
+ async function renewLeaseIfDue(state, active, nowMs) {
1908
+ const log = logOf(state);
1909
+ const tag = `#${active.job.item}`;
1910
+ if (!needsRenew(active.lastRenewAtMs, nowMs)) return true;
1911
+ const renew = await retrySend(() => renewLease(state.config, active.job.item, state.deps.fetchImpl), {
1912
+ now: state.deps.now,
1913
+ sleep: state.deps.sleep
1914
+ });
1915
+ const result = renew.ok ? renew.value : "retry_later";
1916
+ if (result === "lease_lost") {
1917
+ if (active.ending) {
1918
+ log.error(`${tag} lease lost while the checks ran`);
1919
+ return false;
1920
+ }
1921
+ log.error(`${tag} lease lost \xB7 ending job as lease_lost`);
1922
+ await endJob(state, active, "lease_lost");
1923
+ return false;
1924
+ }
1925
+ if (result === "renewed") {
1926
+ active.job.lastRenewAt = new Date(nowMs).toISOString();
1927
+ writeJobFile(join(active.dirPath, "job.json"), active.job);
1928
+ log.line(`${tag} lease renewed \xB7 expires ${formatClock(new Date(nowMs + LEASE_SECONDS * 1e3), new Date(nowMs))}`);
1929
+ } else {
1930
+ log.error(`${tag} renew did not land \xB7 retrying in ${RENEW_INTERVAL_SECONDS / 60}m`);
1931
+ }
1932
+ active.lastRenewAtMs = nowMs;
1933
+ return true;
1934
+ }
1867
1935
  async function watchTick(state, active, nowMs, logMtimeMs) {
1868
- if (active.ending) return;
1936
+ if (active.ending) {
1937
+ if (active.job.stage === "checks") await renewLeaseIfDue(state, active, nowMs);
1938
+ return;
1939
+ }
1869
1940
  const log = logOf(state);
1870
1941
  const tag = `#${active.job.item}`;
1871
1942
  const pid = active.job.pid;
@@ -1883,26 +1954,7 @@ async function watchTick(state, active, nowMs, logMtimeMs) {
1883
1954
  }
1884
1955
  return;
1885
1956
  }
1886
- if (needsRenew(active.lastRenewAtMs, nowMs)) {
1887
- const renew = await retrySend(() => renewLease(state.config, active.job.item, state.deps.fetchImpl), {
1888
- now: state.deps.now,
1889
- sleep: state.deps.sleep
1890
- });
1891
- const result = renew.ok ? renew.value : "retry_later";
1892
- if (result === "lease_lost") {
1893
- log.error(`${tag} lease lost \xB7 ending job as lease_lost`);
1894
- await endJob(state, active, "lease_lost");
1895
- return;
1896
- }
1897
- if (result === "renewed") {
1898
- active.job.lastRenewAt = new Date(nowMs).toISOString();
1899
- writeJobFile(join(active.dirPath, "job.json"), active.job);
1900
- log.line(`${tag} lease renewed \xB7 expires ${formatClock(new Date(nowMs + LEASE_SECONDS * 1e3), new Date(nowMs))}`);
1901
- } else {
1902
- log.error(`${tag} renew did not land \xB7 retrying in ${RENEW_INTERVAL_SECONDS / 60}m`);
1903
- }
1904
- active.lastRenewAtMs = nowMs;
1905
- }
1957
+ if (!await renewLeaseIfDue(state, active, nowMs)) return;
1906
1958
  const tokens = active.job.container === void 0 && active.job.microvm === void 0 ? void 0 : runtimeOf(state).credentials.get(active.dirPath);
1907
1959
  if (tokens !== void 0) {
1908
1960
  await tokens.renewReadIfDue();
@@ -1978,7 +2030,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
1978
2030
  const outcome = await onStartUnderMarker({
1979
2031
  configPath,
1980
2032
  own: ownVersionOf(deps),
1981
- check: update.check ? () => update.check(configPath) : async () => (await import('./check-CCVPBN7A.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
2033
+ check: update.check ? () => update.check(configPath) : async () => (await import('./check-FOF3PUKI.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
1982
2034
  now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
1983
2035
  log
1984
2036
  });
@@ -1,13 +1,62 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { dashboardBase, isRepositoryLinked, workPageUrl, notLinkedText } from './chunk-7DBI6SNT.js';
4
- import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
5
- import { remoteLookupFailed } from './chunk-ANK2B36Y.js';
3
+ import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
4
+ import { remoteLookupFailed } from './chunk-GAYWY4GI.js';
5
+ import { DEFAULT_DASHBOARD } from './chunk-USO2DKBD.js';
6
6
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
7
- import { findGitDirs, readRepoConnection, writeRepoConnection } from './chunk-BJ3KTMDH.js';
7
+ import { readCloudConfig } from './chunk-EABW6AJQ.js';
8
+ import { writeRepoConnection, findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
8
9
  import { createInterface } from 'readline/promises';
9
10
 
10
11
  createRequire(import.meta.url);
12
+
13
+ // src/repository-link.ts
14
+ var LINKS_TIMEOUT_MS = 15e3;
15
+ var GITHUB_PREFIX = "github.com/";
16
+ function isLinkedRepository(local, linked) {
17
+ if (linked.provider !== "github" || typeof linked.repository !== "string") return false;
18
+ return local.toLowerCase() === `${GITHUB_PREFIX}${linked.repository.toLowerCase()}`;
19
+ }
20
+ function ownerAndName(repository) {
21
+ return repository.toLowerCase().startsWith(GITHUB_PREFIX) ? repository.slice(GITHUB_PREFIX.length) : repository;
22
+ }
23
+ async function isRepositoryLinked(fetchImpl, gatewayUrl, token, appId, repository) {
24
+ if (!repository.toLowerCase().startsWith(GITHUB_PREFIX)) return null;
25
+ let res;
26
+ try {
27
+ res = await fetchImpl(`${gatewayUrl.replace(/\/+$/, "")}/v1/apps/${encodeURIComponent(appId)}/git/links`, {
28
+ method: "GET",
29
+ headers: { authorization: `Bearer ${token}`, "x-outerlayer-app-id": appId },
30
+ signal: AbortSignal.timeout(LINKS_TIMEOUT_MS)
31
+ });
32
+ } catch {
33
+ return null;
34
+ }
35
+ if (!res.ok) return null;
36
+ const listed = (await res.json().catch(() => void 0))?.data;
37
+ if (!Array.isArray(listed)) return null;
38
+ return listed.some((entry) => isLinkedRepository(repository, entry ?? {}));
39
+ }
40
+ function dashboardBase(home) {
41
+ const saved = readCloudConfig(home).dashboard;
42
+ const base = typeof saved === "string" && saved.trim() !== "" ? saved : DEFAULT_DASHBOARD;
43
+ return base.replace(/\/+$/, "");
44
+ }
45
+ function workPageUrl(home, organization, factory) {
46
+ return `${dashboardBase(home)}/orgs/${encodeURIComponent(organization)}/factories/${encodeURIComponent(factory)}/work`;
47
+ }
48
+ function notLinkedText(factoryName, repository, url) {
49
+ const shown = sanitizeTerminal(repository);
50
+ const name = sanitizeTerminal(ownerAndName(repository));
51
+ return `${factoryName} has no link to ${shown} yet, so work from this repository cannot reach it.
52
+ Link it on the factory's Work page: ${url}
53
+ 1. Connect GitHub repository, and grant the App access to ${name}.
54
+ 2. Link repository, and pick ${name} and its default branch.
55
+ Then run \`outerlayer connect\` again.
56
+ `;
57
+ }
58
+
59
+ // src/connect-cmd.ts
11
60
  var REQUEST_TIMEOUT_MS = 15e3;
12
61
  var EXIT_NOT_LINKED = 2;
13
62
  var REASON_TEXT = {
@@ -72,10 +121,10 @@ function parseFactories(body) {
72
121
  function listText(factories, repository) {
73
122
  return factories.map((f) => ` ${slug(f)} ${f.displayName}${f.linked === true ? ` (linked to ${repository})` : ""}`).join("\n");
74
123
  }
75
- async function fetchFactories(deps, url, token, repository) {
124
+ async function fetchFactories(fetchImpl, url, token, repository) {
76
125
  let res;
77
126
  try {
78
- res = await deps.fetchImpl(`${url.replace(/\/+$/, "")}/v1/me/factories?${new URLSearchParams({ repository }).toString()}`, {
127
+ res = await fetchImpl(`${url.replace(/\/+$/, "")}/v1/me/factories?${new URLSearchParams({ repository }).toString()}`, {
79
128
  method: "GET",
80
129
  headers: { authorization: `Bearer ${token}` },
81
130
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
@@ -99,6 +148,26 @@ async function fetchFactories(deps, url, token, repository) {
99
148
  }
100
149
  return { ok: true, factories };
101
150
  }
151
+ function selectFactory(factories, saved, repository) {
152
+ const remembered = saved && factories.find((f) => f.id === saved.appId);
153
+ if (remembered) return { factory: remembered, reason: "saved" };
154
+ const linked = factories.filter((f) => f.linked === true);
155
+ if (linked.length === 1) return { factory: linked[0], reason: "linked" };
156
+ if (factories.length === 1) return { factory: factories[0], reason: "only" };
157
+ return { factory: void 0, values: factories.map(slug), text: listText(factories, repository) };
158
+ }
159
+ function saveFactoryConnection(gitCommonDir, saved, factory, now) {
160
+ if (saved?.appId === factory.id) return;
161
+ writeRepoConnection(gitCommonDir, {
162
+ appId: factory.id,
163
+ organization: { name: factory.organization.name, displayName: factory.organization.displayName },
164
+ factory: { name: factory.name, displayName: factory.displayName },
165
+ savedAt: now.toISOString()
166
+ });
167
+ }
168
+ function connectedLine(repository, factory, reason) {
169
+ return `Connected ${repository} to factory "${factory.displayName}" in ${factory.organization.displayName} (${REASON_TEXT[reason]}).`;
170
+ }
102
171
  async function choose(flags, deps, factories, saved, repository) {
103
172
  if (flags.factory !== void 0) {
104
173
  const wanted = flags.factory.toLowerCase();
@@ -108,11 +177,9 @@ async function choose(flags, deps, factories, saved, repository) {
108
177
  ${listText(factories, repository)}`;
109
178
  return result(1, "failed", `--factory ${flags.factory} names no factory you can use`, message);
110
179
  }
111
- const remembered = saved && factories.find((f) => f.id === saved.appId);
112
- if (remembered) return { factory: remembered, reason: "saved" };
180
+ const decided = selectFactory(factories, saved, repository);
181
+ if (decided.factory) return { factory: decided.factory, reason: decided.reason };
113
182
  const linked = factories.filter((f) => f.linked === true);
114
- if (linked.length === 1) return { factory: linked[0], reason: "linked" };
115
- if (factories.length === 1) return { factory: factories[0], reason: "only" };
116
183
  if (!deps.isTerminal) {
117
184
  const why = linked.length > 1 ? `${repository} is linked to more than one factory you can use` : `you can use more than one factory, and none is the only one ${repository} is linked to`;
118
185
  const message = `${why}, and there is no terminal to ask on.
@@ -169,7 +236,7 @@ async function runConnect(flags, deps) {
169
236
  const message = "no gateway address is saved. Run `outerlayer login` to sign in.";
170
237
  return result(1, "failed", message, message);
171
238
  }
172
- const listed = await fetchFactories(deps, creds.url, creds.credential, repository);
239
+ const listed = await fetchFactories(deps.fetchImpl, creds.url, creds.credential, repository);
173
240
  if (!listed.ok) return listed.result;
174
241
  const { factories } = listed;
175
242
  if (factories.length === 0) {
@@ -181,20 +248,13 @@ async function runConnect(flags, deps) {
181
248
  const choice = await choose(flags, deps, factories, saved, repository);
182
249
  if ("code" in choice) return choice;
183
250
  const { factory, reason } = choice;
184
- if (saved?.appId !== factory.id) {
185
- try {
186
- writeRepoConnection(dirs.gitCommonDir, {
187
- appId: factory.id,
188
- organization: { name: factory.organization.name, displayName: factory.organization.displayName },
189
- factory: { name: factory.name, displayName: factory.displayName },
190
- savedAt: deps.now().toISOString()
191
- });
192
- } catch (err) {
193
- const message = `could not save the connection under ${dirs.gitCommonDir}: ${err instanceof Error ? err.message : String(err)}`;
194
- return result(1, "failed", "could not save the connection", message);
195
- }
251
+ try {
252
+ saveFactoryConnection(dirs.gitCommonDir, saved, factory, deps.now());
253
+ } catch (err) {
254
+ const message = `could not save the connection under ${dirs.gitCommonDir}: ${err instanceof Error ? err.message : String(err)}`;
255
+ return result(1, "failed", "could not save the connection", message);
196
256
  }
197
- const connected = `Connected ${repository} to factory "${factory.displayName}" in ${factory.organization.displayName} (${REASON_TEXT[reason]}).
257
+ const connected = `${connectedLine(repository, factory, reason)}
198
258
  `;
199
259
  const why = `connected to ${slug(factory)}: ${REASON_TEXT[reason]}`;
200
260
  const linked = await isRepositoryLinked(deps.fetchImpl, creds.url, creds.credential, factory.id, repository);
@@ -229,4 +289,4 @@ async function runConnectCommand(flags, deps, out) {
229
289
  return r.code;
230
290
  }
231
291
 
232
- export { promptOnTerminal, realConnectDeps, runConnect, runConnectCommand };
292
+ export { connectedLine, fetchFactories, isLinkedRepository, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory };
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isPlaceholderCommand } from './chunk-4NLKY4WR.js';
4
- import { describeCallFailure } from './chunk-RZSF5B46.js';
5
- import { WorkCommandError, getJson } from './chunk-BNMCXPG7.js';
6
- import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
7
- import { builtinKind } from './chunk-3DD6AOWC.js';
8
- import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential } from './chunk-AUFG23AA.js';
3
+ import { isPlaceholderCommand } from './chunk-NALVDFIS.js';
4
+ import { describeCallFailure } from './chunk-CM5QTKM4.js';
5
+ import { WorkCommandError, getJson } from './chunk-5QLNZGAQ.js';
6
+ import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
7
+ import { builtinKind } from './chunk-PWBILI5P.js';
8
+ import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential } from './chunk-OD2VTIHN.js';
9
9
  import { signerFor } from './chunk-M5POMKKW.js';
10
10
 
11
11
  createRequire(import.meta.url);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { parseSize } from './chunk-F6GFZXZ3.js';
3
+ import { parseSize } from './chunk-7RQ73DLO.js';
4
4
 
5
5
  createRequire(import.meta.url);
6
6
 
@@ -628,7 +628,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
628
628
  recordHookErrorsSeen(home, hookErrorsBytes);
629
629
  if (contextPossiblyGoverned(sessionCwd, home)) {
630
630
  try {
631
- const { materializeContext: materialize } = await import('./context-materialize-3HLPZAF6.js');
631
+ const { materializeContext: materialize } = await import('./context-materialize-QL33HDJN.js');
632
632
  const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
633
633
  const result = await materialize({ cwd: sessionCwd, sessionId, home });
634
634
  materializeMessage = result.message;
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { autoConnect } from './chunk-4ACZCY4I.js';
3
4
  import { detectActiveSession } from './chunk-BFESLKPP.js';
4
- import { resolveRepoIdentity } from './chunk-ANK2B36Y.js';
5
+ import { resolveRepoIdentity } from './chunk-GAYWY4GI.js';
5
6
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
6
7
  import { defaultFetch } from './chunk-BCLJSQCV.js';
7
8
  import { unauthorizedMessage, resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
@@ -37,6 +38,8 @@ async function runWorkPr(opts) {
37
38
  const cwd = opts.cwd ?? process.cwd();
38
39
  const env = opts.env ?? process.env;
39
40
  const home = opts.home ?? homeFromEnv(env);
41
+ const refusal = await autoConnect(opts);
42
+ if (refusal !== void 0) throw new WorkPrCommandError(refusal);
40
43
  const creds = resolveCredentials(opts);
41
44
  const prNumber = resolvePrNumber(opts.number);
42
45
  const repository = resolveRepository(opts.repo, cwd);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { C } from './chunk-YRYMNBGQ.js';
4
- import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-WO2BXCTQ.js';
4
+ import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-VXLJORHL.js';
5
5
  import { resolvePackageVersion } from './chunk-RA3O54FC.js';
6
6
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
7
7
  import { join, dirname } from 'path';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { detectMachine, supportsContainerBuilds, reachDockerStep, describeMachineDocker, supportsMicroVmBuilds } from './chunk-RBOMWNOG.js';
4
- import { MIN_ENGINE_MAJOR } from './chunk-RZSF5B46.js';
3
+ import { detectMachine, supportsContainerBuilds, reachDockerStep, describeMachineDocker, supportsMicroVmBuilds } from './chunk-TUUMW4TC.js';
4
+ import { MIN_ENGINE_MAJOR } from './chunk-CM5QTKM4.js';
5
5
  import { RUNNER_DIR_MODE, runnerDir, RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
6
6
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
7
7
  import { dirname } from 'path';
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { authorEnvironment, withHooksPath } from './chunk-HKMPVPO7.js';
3
4
  import { existsSync, unlinkSync, chmodSync } from 'fs';
4
5
  import { request as request$1, createServer } from 'http';
5
6
  import { request } from 'https';
@@ -344,52 +345,6 @@ async function startBuildServices(input) {
344
345
  }
345
346
  }
346
347
 
347
- // src/runner/commit-identity.ts
348
- var NOREPLY_SUFFIX = "@users.noreply.github.com";
349
- var MAX_LENGTH = 200;
350
- function parseIdentity(value) {
351
- if (typeof value !== "object" || value === null) return void 0;
352
- const { name, email } = value;
353
- if (typeof name !== "string" || typeof email !== "string") return void 0;
354
- if (name.trim() === "" || name.length > MAX_LENGTH || /[\r\n\0<>]/.test(name)) return void 0;
355
- if (email.length > MAX_LENGTH || !email.endsWith(NOREPLY_SUFFIX) || /[\s\0<>]/.test(email) || email.length === NOREPLY_SUFFIX.length) return void 0;
356
- return { name, email };
357
- }
358
- function parseClaimIdentity(data) {
359
- const author = parseIdentity(data.commitAuthor);
360
- if (author === void 0) return void 0;
361
- const coAuthor = parseIdentity(data.coAuthor);
362
- return coAuthor === void 0 ? { author } : { author, coAuthor };
363
- }
364
- function authorEnvironment(identity) {
365
- if (identity === void 0) return {};
366
- return {
367
- GIT_AUTHOR_NAME: identity.name,
368
- GIT_AUTHOR_EMAIL: identity.email,
369
- GIT_COMMITTER_NAME: identity.name,
370
- GIT_COMMITTER_EMAIL: identity.email
371
- };
372
- }
373
- function configCount(env) {
374
- const raw = String(env.GIT_CONFIG_COUNT);
375
- return /^[0-9]+$/.test(raw) ? Number(raw) : 0;
376
- }
377
- function withHooksPath(env, dir) {
378
- const at = configCount(env);
379
- return {
380
- ...env,
381
- GIT_CONFIG_COUNT: String(at + 1),
382
- [`GIT_CONFIG_KEY_${at}`]: "core.hooksPath",
383
- [`GIT_CONFIG_VALUE_${at}`]: dir
384
- };
385
- }
386
- function commitIdentityRecord(identity) {
387
- return {
388
- author: identity === void 0 ? "host" : "app",
389
- coAuthor: identity?.coAuthor !== void 0 && identity.hooksPath !== void 0 ? "credited" : "none"
390
- };
391
- }
392
-
393
348
  // src/runner/container/environment.ts
394
349
  var RELAY_PORT = 3128;
395
350
  var JOB_MOUNT = "/outerlayer/job";
@@ -498,6 +453,23 @@ function buildEnvironment(input) {
498
453
  skippedTokenVariables
499
454
  };
500
455
  }
456
+ function checkEnvironment(input) {
457
+ const env = buildEnvironment({
458
+ config: input.config,
459
+ item: input.item,
460
+ itemKey: void 0,
461
+ repository: input.repository,
462
+ hostEnv: input.hostEnv,
463
+ containerEnv: input.containerEnv,
464
+ builtIns: false
465
+ });
466
+ const withheld = /* @__PURE__ */ new Set(["OUTERLAYER_URL", "OUTERLAYER_API_KEY", ...CLAUDE_CREDENTIAL_VARIABLES]);
467
+ const literals = {};
468
+ for (const [name, value] of Object.entries(env.literals)) if (!withheld.has(name)) literals[name] = value;
469
+ const passed = {};
470
+ for (const [name, value] of Object.entries(env.passed)) if (!withheld.has(name)) passed[name] = value;
471
+ return { literals, passed };
472
+ }
501
473
  function parseIsolation(value) {
502
474
  return value === "container" || value === "vm" ? value : "shared-user";
503
475
  }
@@ -531,4 +503,4 @@ function withTunnelRecord(environment, record, onlyWhenUsed = false) {
531
503
  };
532
504
  }
533
505
 
534
- export { AGENT_CREDENTIAL_MISSING, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, authorEnvironment, buildEnvironment, builtInEnvironment, claudeCredential, commitIdentityRecord, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, parseClaimIdentity, parseIsolation, proxyEnvironment, resolveDestinations, sharedUserEnvironment, startBuildServices, withHooksPath, withTunnelRecord };
506
+ export { AGENT_CREDENTIAL_MISSING, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, buildEnvironment, builtInEnvironment, checkEnvironment, claudeCredential, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, parseIsolation, proxyEnvironment, resolveDestinations, sharedUserEnvironment, startBuildServices, withTunnelRecord };