@outerlayer/cli 0.6.0 → 0.7.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 (80) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +10 -0
  3. package/dist/{agent-setup-USZ2SAXC.js → agent-setup-TXLDY5RV.js} +7 -6
  4. package/dist/{build-PAEKVYVK.js → build-JF5UOWKJ.js} +2 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/{check-CCVPBN7A.js → check-ASZL5BEO.js} +29 -23
  7. package/dist/{chunk-ZILGTTY6.js → chunk-2VO25HHO.js} +3 -3
  8. package/dist/{chunk-OIRNH6UO.js → chunk-5FWNEQNZ.js} +3 -3
  9. package/dist/{chunk-MXB5VB4Y.js → chunk-6IYLDODX.js} +6 -6
  10. package/dist/{chunk-4NLKY4WR.js → chunk-6QWV3YDJ.js} +2 -2
  11. package/dist/{chunk-UMFWVGJO.js → chunk-6ZZHWY2Z.js} +4 -3
  12. package/dist/{chunk-NQXFAGHU.js → chunk-7FTNIAHS.js} +1 -1
  13. package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
  14. package/dist/{chunk-43J3M6KB.js → chunk-AII7CKTH.js} +45 -31
  15. package/dist/{chunk-VMJ3MMBX.js → chunk-AJKEHABI.js} +312 -18
  16. package/dist/{chunk-RBOMWNOG.js → chunk-AQ54MKSQ.js} +2 -2
  17. package/dist/{chunk-Z62HNKEJ.js → chunk-CEBIA5FD.js} +31 -5
  18. package/dist/{chunk-ANK2B36Y.js → chunk-D6FXM5OW.js} +6182 -28607
  19. package/dist/{chunk-BNMCXPG7.js → chunk-DGAIVMMN.js} +12 -3
  20. package/dist/{chunk-3DD6AOWC.js → chunk-DTXOJDEH.js} +26 -2
  21. package/dist/{chunk-RZSF5B46.js → chunk-E4PIFIC3.js} +100 -15
  22. package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
  23. package/dist/chunk-HKMPVPO7.js +55 -0
  24. package/dist/{chunk-FA2BOX4O.js → chunk-JPR2WHHF.js} +1 -1
  25. package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
  26. package/dist/{chunk-MIGEDH5P.js → chunk-MQPRB5K7.js} +9 -9
  27. package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
  28. package/dist/chunk-PUN7LMNS.js +39 -0
  29. package/dist/{chunk-JWOQNNN2.js → chunk-Q5G2ODUZ.js} +1 -1
  30. package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
  31. package/dist/{chunk-PMAMOSTP.js → chunk-SSU747O6.js} +85 -25
  32. package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
  33. package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
  34. package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
  35. package/dist/{chunk-IASWYRVG.js → chunk-X2FSFU4C.js} +4 -1
  36. package/dist/chunk-YNJEOGDL.js +22434 -0
  37. package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
  38. package/dist/{chunk-3DEVYTNQ.js → chunk-ZYHKJKSU.js} +1 -1
  39. package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
  40. package/dist/{cli-7WCNPBYC.js → cli-LEVCGAQV.js} +73 -71
  41. package/dist/{command-ARFK3OYF.js → command-FLSYCGIB.js} +47 -22
  42. package/dist/config-I3TVFYLH.js +10 -0
  43. package/dist/{connect-cmd-PCESZLTR.js → connect-cmd-MJMUONDY.js} +4 -4
  44. package/dist/{context-adopt-G5JAELE7.js → context-adopt-CE4KDXS3.js} +5 -4
  45. package/dist/{context-materialize-3HLPZAF6.js → context-materialize-QL33HDJN.js} +5 -4
  46. package/dist/{dist-RDLP4GGJ.js → dist-PXBSA7QX.js} +2 -1
  47. package/dist/{doctor-VOMYOHQU.js → doctor-FVDT3KJZ.js} +23 -16
  48. package/dist/{emit-artifact-cmd-TBF46VXZ.js → emit-artifact-cmd-7RPMRSVP.js} +11 -4
  49. package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
  50. package/dist/{emit-criteria-cmd-3427XKFW.js → emit-criteria-cmd-MKI7WETO.js} +10 -1
  51. package/dist/{emit-finding-cmd-GSI75K36.js → emit-finding-cmd-RMLGZASB.js} +12 -1
  52. package/dist/{emit-result-cmd-3PRQKB55.js → emit-result-cmd-MTXAZ2GV.js} +13 -6
  53. package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
  54. package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
  55. package/dist/{hook-fast-NJBBZQ5Q.js → hook-fast-XBOZ3N6L.js} +1 -1
  56. package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
  57. package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
  58. package/dist/index.js +3 -3
  59. package/dist/{init-WVR4BZQ4.js → init-BACXESVV.js} +21 -14
  60. package/dist/{init-OHYFIKZD.js → init-VLW7H6RW.js} +22 -15
  61. package/dist/{init-cmd-HMFNIFPI.js → init-cmd-VJFB5L7X.js} +10 -9
  62. package/dist/{install-DSUZE2TJ.js → install-NMAPLLBQ.js} +4 -3
  63. package/dist/{install-cmd-453C7IZT.js → install-cmd-B5SEU3G7.js} +2 -2
  64. package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
  65. package/dist/{loop-UAJB34KA.js → loop-D3243JKT.js} +29 -23
  66. package/dist/{machine-2JOWGRSZ.js → machine-EB3GEVI4.js} +20 -13
  67. package/dist/{session-sender-ED26V45B.js → session-sender-LMACEJJS.js} +6 -5
  68. package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
  69. package/dist/{status-6WNXX2O7.js → status-F4THTJJK.js} +24 -18
  70. package/dist/{sync-cmd-YONVGUYS.js → sync-cmd-M6JA3OEE.js} +5 -4
  71. package/dist/{watch-HHKAF26L.js → watch-NB5TGPEZ.js} +5 -4
  72. package/dist/{work-claim-cmd-LXBZTMJA.js → work-claim-cmd-UHMWOS3G.js} +13 -6
  73. package/dist/{work-cmd-OVNF44FY.js → work-cmd-6UMCFTAW.js} +9 -3
  74. package/dist/{work-comment-cmd-6DGQNTAH.js → work-comment-cmd-E4LEUIXZ.js} +9 -3
  75. package/dist/{work-open-pr-cmd-FCZHFHZS.js → work-open-pr-cmd-OPZWGSEQ.js} +10 -4
  76. package/dist/{work-pr-cmd-QJJVHZDC.js → work-pr-cmd-IDIAFFRU.js} +9 -2
  77. package/package.json +1 -1
  78. package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
  79. package/dist/chunk-7DBI6SNT.js +0 -55
  80. package/dist/config-HL2AIR3K.js +0 -9
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { autoConnect } from './chunk-PUN7LMNS.js';
3
4
  import { detectActiveSession } from './chunk-BFESLKPP.js';
4
- import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
5
- import { resolveRepoIdentity } from './chunk-ANK2B36Y.js';
5
+ import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
6
+ import { resolveRepoIdentity } from './chunk-D6FXM5OW.js';
6
7
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
7
8
  import { defaultFetch } from './chunk-BCLJSQCV.js';
8
9
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
@@ -79,6 +80,10 @@ function resolveCredentials(opts) {
79
80
  if (!resolved.ok) throw new WorkCommandError(resolved.message);
80
81
  return { url: resolved.url, apiKey: resolved.credential, appId: resolved.appId };
81
82
  }
83
+ async function connectIfOneFits(opts) {
84
+ const refusal = await autoConnect(opts);
85
+ if (refusal !== void 0) throw new WorkCommandError(refusal);
86
+ }
82
87
  function resolveRepository(repoFlag, cwd) {
83
88
  if (repoFlag) return repoFlag;
84
89
  const identity = resolveRepoIdentity(cwd);
@@ -299,6 +304,7 @@ async function runWorkBuild(opts) {
299
304
  const cwd = opts.cwd ?? process.cwd();
300
305
  const env = opts.env ?? process.env;
301
306
  const home = opts.home ?? homeFromEnv(env);
307
+ await connectIfOneFits(opts);
302
308
  const { url, apiKey, appId } = resolveCredentials(opts);
303
309
  const fetchImpl = opts.fetchImpl ?? defaultFetch;
304
310
  const facts = environmentFacts({ cwd, env, home, sessionIdOverride: opts.sessionId });
@@ -341,7 +347,7 @@ async function runWorkLinkSession(opts) {
341
347
  return await linkSession(opts);
342
348
  } catch (err) {
343
349
  if (opts.logFailures) {
344
- const { logHookError } = await import('./hook-fast-NJBBZQ5Q.js');
350
+ const { logHookError } = await import('./hook-fast-XBOZ3N6L.js');
345
351
  const reason = err instanceof Error ? err.message : String(err);
346
352
  logHookError(opts.home ?? homeFromEnv(opts.env ?? process.env), new Error(`work link-session #${opts.number} failed: ${reason}`));
347
353
  }
@@ -389,6 +395,7 @@ async function runWorkRemove(opts) {
389
395
  const cwd = opts.cwd ?? process.cwd();
390
396
  const env = opts.env ?? process.env;
391
397
  const home = opts.home ?? homeFromEnv(env);
398
+ await connectIfOneFits(opts);
392
399
  const creds = resolveCredentials(opts);
393
400
  if (!opts.reason) {
394
401
  throw new WorkCommandError("--reason is required \u2014 a removal records why");
@@ -432,6 +439,7 @@ async function runWorkRemove(opts) {
432
439
  }
433
440
  async function runWorkStatus(opts) {
434
441
  const cwd = opts.cwd ?? process.cwd();
442
+ await connectIfOneFits(opts);
435
443
  const creds = resolveCredentials(opts);
436
444
  const fetchByItem = opts.item !== void 0 ? parsePositiveInt(opts.item, "--item") : void 0;
437
445
  if (fetchByItem !== void 0) {
@@ -461,6 +469,7 @@ async function runWorkStatus(opts) {
461
469
  }
462
470
  async function runWorkList(opts) {
463
471
  const cwd = opts.cwd ?? process.cwd();
472
+ await connectIfOneFits(opts);
464
473
  const { url, apiKey, appId } = resolveCredentials(opts);
465
474
  const fetchImpl = opts.fetchImpl ?? defaultFetch;
466
475
  const repository = opts.repo ?? resolveRepoIdentity(cwd).gitRepo;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { parseSize, MAX_ALLOW_HOSTS, allowHostProblem } from './chunk-F6GFZXZ3.js';
4
- import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-AUFG23AA.js';
4
+ import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-OD2VTIHN.js';
5
5
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
6
6
  import { existsSync, statSync, accessSync, constants, readFileSync } from 'fs';
7
7
  import { hostname } from 'os';
@@ -30,6 +30,9 @@ var DEFAULT_CONCURRENCY = 1;
30
30
  var DEFAULT_POLL_SECONDS = 60;
31
31
  var DEFAULT_TIME_LIMIT_MINUTES = 480;
32
32
  var DEFAULT_IDLE_LIMIT_MINUTES = 30;
33
+ var DEFAULT_CHECK_TIME_LIMIT_MINUTES = 10;
34
+ var CHECKS_KEYS = ["timeLimitMinutes"];
35
+ var MAX_CHECK_TIME_LIMIT_MINUTES = 240;
33
36
  var DEFAULT_BUILD = { memory: "8g", cpus: 4, pids: 4096, disk: "40g", variables: [] };
34
37
  var BUILD_KEYS = ["memory", "cpus", "pids", "disk", "variables", "destinations", "allowHosts"];
35
38
  var HOUSEKEEPING_KEYS = ["jobsKeepDays", "buildCacheMax", "minFreeDisk"];
@@ -81,6 +84,7 @@ var RUNNER_KEYS = [
81
84
  "hooks",
82
85
  "build",
83
86
  "housekeeping",
87
+ "checks",
84
88
  "autoUpdate"
85
89
  ];
86
90
  function runnerNumbers() {
@@ -199,6 +203,7 @@ function loadRunnerConfig(configPath) {
199
203
  checkBuiltinHooks(configPath, runner.hooks);
200
204
  const build = resolveBuild(configPath, runner.build);
201
205
  const housekeeping = resolveHousekeeping(configPath, runner.housekeeping, build.disk);
206
+ const checks = resolveChecks(configPath, runner.checks);
202
207
  if (config.scrub?.literals !== void 0 && !Array.isArray(config.scrub.literals)) {
203
208
  fail(configPath, "scrub.literals", "must be a list of strings");
204
209
  }
@@ -226,6 +231,7 @@ function loadRunnerConfig(configPath) {
226
231
  },
227
232
  build,
228
233
  housekeeping,
234
+ checks,
229
235
  // A host with executables of its own for provision and cleanup chose
230
236
  // its own environment, and an update could change what its hooks run
231
237
  // under; it opts in. The built-in hooks are the runner's own. Provision
@@ -275,6 +281,24 @@ function resolveHousekeeping(configPath, block, buildDisk) {
275
281
  if (minFreeDisk === void 0) fail(configPath, "runner.housekeeping.minFreeDisk", 'must be a size such as "40g"');
276
282
  return { jobsKeepDays: keys.jobsKeepDays ?? DEFAULT_JOBS_KEEP_DAYS, buildCacheMax, minFreeDisk };
277
283
  }
284
+ function resolveChecks(configPath, block) {
285
+ const given = block ?? {};
286
+ if (typeof given !== "object" || Array.isArray(given)) fail(configPath, "runner.checks", "must be an object");
287
+ const keys = given;
288
+ for (const key of Object.keys(keys)) {
289
+ if (CHECKS_KEYS.includes(key)) continue;
290
+ const near = nearestKey(key, CHECKS_KEYS);
291
+ fail(configPath, `runner.checks.${key}`, near ? `is not a key this block accepts; did you mean ${near}?` : "is not a key this block accepts");
292
+ }
293
+ const limit = keys.timeLimitMinutes === void 0 ? DEFAULT_CHECK_TIME_LIMIT_MINUTES : keys.timeLimitMinutes;
294
+ if (!Number.isInteger(limit) || limit < 1) {
295
+ fail(configPath, "runner.checks.timeLimitMinutes", "must be a whole number of at least 1");
296
+ }
297
+ if (limit > MAX_CHECK_TIME_LIMIT_MINUTES) {
298
+ fail(configPath, "runner.checks.timeLimitMinutes", `must be at most ${MAX_CHECK_TIME_LIMIT_MINUTES}`);
299
+ }
300
+ return { timeLimitMinutes: limit };
301
+ }
278
302
  function wholeBytes(bytes) {
279
303
  if (bytes === void 0) return void 0;
280
304
  const whole = Math.floor(bytes);
@@ -334,4 +358,4 @@ function resolveBuild(configPath, block) {
334
358
  };
335
359
  }
336
360
 
337
- export { RunnerConfigError, builtinKind, checkHooks, defaultRunnerConfigPath, hasRunnerBlock, isBuiltinContainer, isBuiltinProcess, isBuiltinVm, loadRunnerConfig, resolveBuild, runnerVmOf };
361
+ export { DEFAULT_CHECK_TIME_LIMIT_MINUTES, RunnerConfigError, builtinKind, checkHooks, defaultRunnerConfigPath, hasRunnerBlock, isBuiltinContainer, isBuiltinProcess, isBuiltinVm, loadRunnerConfig, resolveBuild, runnerVmOf };
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { readDefaultBranchHead, cloneRepository, buildRepositoryImage, 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-Z62HNKEJ.js';
3
+ import { readDefaultBranchHead, cloneRepository, buildRepositoryImage, 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-CEBIA5FD.js';
4
4
  import { startTimeOf, isSameProcess } from './chunk-N5FOE5PS.js';
5
5
  import { currentCliBuild } from './chunk-OGFGZQA3.js';
6
6
  import { createDockerHost, childEnvironment, spawnRun } from './chunk-774HEQL6.js';
7
7
  import { RecipeError } from './chunk-QOZKPLVJ.js';
8
- import { execCapture } from './chunk-W4SQCOZU.js';
9
- import { GUEST_CID } from './chunk-B2G7JHHB.js';
10
- import { WorkCommandError, postJson } from './chunk-BNMCXPG7.js';
8
+ import { execCapture } from './chunk-ZOAEPWGL.js';
9
+ import { GUEST_CID } from './chunk-R7STSBLC.js';
10
+ import { WorkCommandError, postJson } from './chunk-DGAIVMMN.js';
11
11
  import { parseDuKilobytes, hostAllowed } from './chunk-F6GFZXZ3.js';
12
- import { RELAY_PORT, CHECKOUT_DIR, JOB_MOUNT, claudeCredential, buildEnvironment, startBuildServices, AGENT_CREDENTIAL_MISSING, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT } from './chunk-AUFG23AA.js';
13
- import { defaultGitRunner, materializeContext } from './chunk-OIRNH6UO.js';
14
- import { readContextManifest, readSourceCache } from './chunk-WIOZAJ2W.js';
12
+ import { RELAY_PORT, CHECKOUT_DIR, JOB_MOUNT, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT } from './chunk-OD2VTIHN.js';
13
+ import { defaultGitRunner, materializeContext } from './chunk-5FWNEQNZ.js';
14
+ import { readContextManifest, readSourceCache } from './chunk-ZZXLM64C.js';
15
15
  import { signingFetchFor } from './chunk-BCLJSQCV.js';
16
16
  import { signerFor } from './chunk-M5POMKKW.js';
17
17
  import { rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, stagedContextDir, contextHomeDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, buildDir, runnerDir, RUNNER_DIR_MODE, vmAssetsDir } from './chunk-ZM2IMMYN.js';
@@ -283,12 +283,14 @@ function prepareRunnerCgroup(setup) {
283
283
  fs.write(join(root, "cgroup.subtree_control"), "+memory");
284
284
  return { root };
285
285
  }
286
+ var BUILD_RECLAIM_HEADROOM_BYTES = 256 * 1024 ** 2;
287
+ var BUILD_KILL_HEADROOM_BYTES = 1024 ** 3;
286
288
  function createBuildCgroup(fs, root, buildId, buildMemoryBytes) {
287
289
  const path = join(root, `${BUILD_PREFIX}${buildId}`);
288
- const firecrackerOverheadBytes = 256 * 1024 ** 2;
289
290
  fs.mkdir(path);
290
291
  try {
291
- fs.write(join(path, "memory.max"), String(buildMemoryBytes + firecrackerOverheadBytes));
292
+ fs.write(join(path, "memory.high"), String(buildMemoryBytes + BUILD_RECLAIM_HEADROOM_BYTES));
293
+ fs.write(join(path, "memory.max"), String(buildMemoryBytes + BUILD_KILL_HEADROOM_BYTES));
292
294
  fs.write(join(path, "memory.swap.max"), "0");
293
295
  } catch (err) {
294
296
  removeBuildCgroup(fs, path);
@@ -296,6 +298,9 @@ function createBuildCgroup(fs, root, buildId, buildMemoryBytes) {
296
298
  }
297
299
  return path;
298
300
  }
301
+ function outOfMemoryReason(memory) {
302
+ return `the build ran out of memory: the kernel killed its microVM at the limit of runner.build.memory (${memory ?? "8g"}) plus 1 GiB for Firecracker and its disks' page cache. Raise runner.build.memory, or lower runner.concurrency`;
303
+ }
299
304
  function oomKills(fs, path) {
300
305
  const match = /^oom_kill (\d+)$/m.exec(fs.read(join(path, "memory.events")) ?? "");
301
306
  return match === null ? 0 : Number(match[1]);
@@ -536,12 +541,12 @@ function containerRunArgs(input) {
536
541
  "--forward",
537
542
  `${DESTINATION_BASE_PORT + index}=${JOB_MOUNT}/dest-${index}.sock`
538
543
  ]).flat(),
539
- ...[
544
+ ...input.builtIns === true ? [
540
545
  "--forward",
541
546
  `${GATEWAY_PORT}=${JOB_MOUNT}/${GATEWAY_SOCKET}`,
542
547
  "--forward",
543
548
  `${CLAUDE_PORT}=${JOB_MOUNT}/${CLAUDE_SOCKET}`
544
- ]
549
+ ] : []
545
550
  ];
546
551
  }
547
552
  function prepareRunArgs(input) {
@@ -1537,6 +1542,11 @@ function createGitRemote(options) {
1537
1542
  req.resume();
1538
1543
  return plain(res, 404, "not found\n");
1539
1544
  }
1545
+ if (options.readOnly === true && (route.kind === "receive-pack" || route.kind === "info-refs" && route.service === "git-receive-pack")) {
1546
+ log(`push refused: this remote is read-only`);
1547
+ req.resume();
1548
+ return plain(res, 403, "this remote is read-only: a check cannot push\n");
1549
+ }
1540
1550
  const own = isOwnRepository(options.repository, route.owner, route.name);
1541
1551
  if (own && route.kind === "receive-pack") return push(req, res, route);
1542
1552
  let kind = route.kind === "info-refs" && route.service === "git-receive-pack" ? "push" : "read";
@@ -1545,6 +1555,7 @@ function createGitRemote(options) {
1545
1555
  body = await readBody(req, maxLfsBodyBytes);
1546
1556
  if (body === void 0) return plain(res, 413, "the request is too large\n");
1547
1557
  kind = isLfsUpload(body) ? "push" : "read";
1558
+ if (options.readOnly === true && kind === "push") return plain(res, 403, "this remote is read-only: a check cannot upload\n");
1548
1559
  }
1549
1560
  let authorization;
1550
1561
  if (own) {
@@ -2021,7 +2032,8 @@ function gitRemoteFor(runtime, input) {
2021
2032
  onWorkflowRefused: () => {
2022
2033
  input.tokens.reason = WORKFLOW_PERMISSION_REASON;
2023
2034
  },
2024
- log: input.log
2035
+ log: input.log,
2036
+ ...input.readOnly === true ? { readOnly: true } : {}
2025
2037
  });
2026
2038
  }
2027
2039
  function firstLine4(text) {
@@ -2105,7 +2117,8 @@ async function provisionContainer(input) {
2105
2117
  repository,
2106
2118
  imageId: report.imageId,
2107
2119
  containerEnv: report.apply.containerEnv,
2108
- builtIns: true
2120
+ builtIns: true,
2121
+ lifecycle: report.apply.lifecycle
2109
2122
  };
2110
2123
  const env = buildEnvironment({
2111
2124
  config,
@@ -2171,7 +2184,9 @@ async function provisionContainer(input) {
2171
2184
  image: report.imageId,
2172
2185
  user: ADDED_USER,
2173
2186
  limits: limits2,
2174
- destinations: config.build?.destinations?.length ?? 0};
2187
+ destinations: config.build?.destinations?.length ?? 0,
2188
+ builtIns: true
2189
+ };
2175
2190
  const prepared = await host.run(prepareRunArgs(runInput), { logPath });
2176
2191
  if (prepared.status !== 0) return dockerFailed("preparing the build's volume", prepared);
2177
2192
  const started = await host.run(containerRunArgs(runInput), { logPath });
@@ -2388,5 +2403,75 @@ async function cleanupContainer(runtime, state, jobDir) {
2388
2403
  rmSync(state.buildDir, { recursive: true, force: true });
2389
2404
  if (failures.length > 0) throw new Error(failures.join("; "));
2390
2405
  }
2406
+ async function startCheckContainer(input) {
2407
+ const { config, runtime, job, jobDir, tokens, log } = input;
2408
+ const { host } = runtime;
2409
+ const tag = `#${job.item}`;
2410
+ const built = job.container;
2411
+ const repository = built?.repository ?? job.repository;
2412
+ if (built === void 0 || built.imageId === void 0 || repository === void 0 || job.branch === void 0) {
2413
+ return { ok: false, reason: "the build's image, repository or branch is not recorded" };
2414
+ }
2415
+ const buildId = randomBytes(6).toString("hex");
2416
+ const name = `outerlayer-check-${buildId}`;
2417
+ const buildDir2 = buildDir(config.configPath, buildId);
2418
+ const agentUser = built.agentUser ?? ADDED_USER;
2419
+ const state = { buildId, container: name, volume: name, buildDir: buildDir2, repository, imageId: built.imageId, agentUser };
2420
+ const checksDir = join(jobDir, "checks");
2421
+ mkdirSync(checksDir, { recursive: true });
2422
+ const logPath = join(checksDir, "environment.log");
2423
+ input.save(state);
2424
+ const fail = async (reason) => {
2425
+ try {
2426
+ await cleanupContainer(runtime, state);
2427
+ } catch (err) {
2428
+ log.error(`${tag} cleanup of the check environment failed: ${describeCallFailure(err)}`);
2429
+ }
2430
+ return { ok: false, reason };
2431
+ };
2432
+ const dockerFailed = (what, result) => fail(`${what} failed (exit ${result.status})${firstLine4(result.stderr) === "" ? "" : `: ${firstLine4(result.stderr)}`}`);
2433
+ mkdirSync(buildDir2, { recursive: true });
2434
+ chmodSync(buildDir2, 493);
2435
+ try {
2436
+ const gitRemote = gitRemoteFor(runtime, { repository, branch: job.branch, tokens, buildDir: buildDir2, log: (line) => log.line(`${tag} ${line}`), readOnly: true });
2437
+ runtime.tunnels.set(buildId, await startServicesFor(runtime, config, buildDir2, checksDir, void 0, false, gitRemote));
2438
+ } catch (err) {
2439
+ return fail(`the tunnel could not start: ${describeCallFailure(err)}`);
2440
+ }
2441
+ const limits2 = { memory: config.build?.memory ?? "8g", cpus: config.build?.cpus ?? 4, pids: config.build?.pids ?? 4096 };
2442
+ const runnerId = runnerLabelValue(config.configPath);
2443
+ const volume = await host.createVolume(name, { [BUILD_LABEL]: buildId, [RUNNER_LABEL]: runnerId });
2444
+ if (volume.status !== 0) return dockerFailed("creating the check environment's volume", volume);
2445
+ const runInput = {
2446
+ buildId,
2447
+ runnerId,
2448
+ container: name,
2449
+ volume: name,
2450
+ buildDir: buildDir2,
2451
+ image: built.imageId,
2452
+ user: ADDED_USER,
2453
+ limits: limits2,
2454
+ destinations: config.build?.destinations?.length ?? 0,
2455
+ builtIns: false
2456
+ };
2457
+ const prepared = await host.run(prepareRunArgs(runInput), { logPath });
2458
+ if (prepared.status !== 0) return dockerFailed("preparing the check environment's volume", prepared);
2459
+ const started = await host.run(containerRunArgs(runInput), { logPath });
2460
+ if (started.status !== 0) return dockerFailed("starting the check environment's container", started);
2461
+ if (!await waitForRelay(runtime, state)) return fail("the relay in the check environment's container did not start");
2462
+ const env = checkEnvironment({ config, item: job.item, repository, hostEnv: runtime.hostEnv, containerEnv: built.containerEnv ?? {} });
2463
+ return {
2464
+ ok: true,
2465
+ container: {
2466
+ state,
2467
+ exec: (argv, workdir, opts) => host.exec({ container: name, user: agentUser, workdir, env, argv }, opts?.logPath === void 0 ? void 0 : { logPath: opts.logPath }),
2468
+ restart: async () => {
2469
+ await host.stop(name);
2470
+ const again = await host.start(name);
2471
+ return again.status === 0 && await waitForRelay(runtime, state);
2472
+ }
2473
+ }
2474
+ };
2475
+ }
2391
2476
 
2392
- export { ADDED_USER, AgentUserError, AssetError, BUILD_LABEL, BuildTokens, GH_CONFIG_YML, MIN_ENGINE_MAJOR, RUNNER_LABEL, classifyRefusal, cleanupContainer, containerCommandLine, containerSenderCommand, createBuildDisk, createContainerRuntime, createRunnerLog, deleteBuildDisk, describeCallFailure, ensureRootfs, ensureTunnel, formatClock, formatDuration, ghHostsYml, gitRemoteFor, isLiteralAddress, keepGhConfigCurrent, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, prepareBranch, provisionContainer, refusalCode, relativeToRunner, removeStagedContext, resolveAgentUser, retrySend, runBuildSteps, runnerLabelValue, senderSignalScript, setUpRunnerCgroup, shellQuote, shortClaim, signalInContainer, stageGovernedContext, startServicesFor, stopContainer, syncInContainer };
2477
+ export { ADDED_USER, AgentUserError, AssetError, BUILD_LABEL, BuildTokens, GH_CONFIG_YML, MIN_ENGINE_MAJOR, RUNNER_LABEL, classifyRefusal, cleanupContainer, containerCommandLine, containerSenderCommand, createBuildDisk, createContainerRuntime, createRunnerLog, deleteBuildDisk, describeCallFailure, ensureRootfs, ensureTunnel, formatClock, formatDuration, ghHostsYml, gitRemoteFor, isLiteralAddress, keepGhConfigCurrent, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, prepareBranch, provisionContainer, refusalCode, relativeToRunner, removeStagedContext, resolveAgentUser, retrySend, runBuildSteps, runnerLabelValue, senderSignalScript, setUpRunnerCgroup, shellQuote, shortClaim, signalInContainer, stageGovernedContext, startCheckContainer, startServicesFor, stopContainer, syncInContainer };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-WO2BXCTQ.js';
4
- import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-EMY4I27X.js';
3
+ import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-VXLJORHL.js';
4
+ import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-7ZR5UPMB.js';
5
5
  import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, readdirSync } from 'fs';
6
6
  import { join, dirname, relative, sep } from 'path';
7
7
 
@@ -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 };
@@ -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,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,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isLinkedRepository } from './chunk-7DBI6SNT.js';
4
3
  import { readStatuslineState, STATE_FRESH_MS } from './chunk-F47JBIAW.js';
5
- import { resolveCredentials, getJson, WorkCommandError } from './chunk-BNMCXPG7.js';
6
- import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
7
- import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-ANK2B36Y.js';
4
+ import { resolveCredentials, getJson, WorkCommandError } from './chunk-DGAIVMMN.js';
5
+ import { isLinkedRepository } from './chunk-SSU747O6.js';
6
+ import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
7
+ import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-D6FXM5OW.js';
8
8
  import { C } from './chunk-YRYMNBGQ.js';
9
9
  import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-5QRP3MVS.js';
10
- import { readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-WIOZAJ2W.js';
10
+ import { readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-ZZXLM64C.js';
11
11
  import { defaultFetch } from './chunk-BCLJSQCV.js';
12
12
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
13
13
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
14
- import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-FA2BOX4O.js';
14
+ import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-JPR2WHHF.js';
15
15
  import { deadHooksState, preparePackageManagerCommand, contextExcludesPresent } from './chunk-XCCLFVXM.js';
16
16
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
17
17
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1004,7 +1004,7 @@ function doctorExitCode(checks) {
1004
1004
 
1005
1005
  // src/doctor-report.ts
1006
1006
  async function gatherDoctorChecks() {
1007
- const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-HL2AIR3K.js');
1007
+ const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-I3TVFYLH.js');
1008
1008
  const configPath = defaultRunnerConfigPath();
1009
1009
  const checks = runDoctor({ runnerHost: hasRunnerBlock(configPath) });
1010
1010
  const credential = await credentialChecks();
@@ -1016,7 +1016,7 @@ async function gatherDoctorChecks() {
1016
1016
  const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
1017
1017
  checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
1018
1018
  } else if (hasRunnerBlock(configPath)) {
1019
- const { runnerHostChecks } = await import('./doctor-VOMYOHQU.js');
1019
+ const { runnerHostChecks } = await import('./doctor-FVDT3KJZ.js');
1020
1020
  const hooks = (() => {
1021
1021
  try {
1022
1022
  return loadRunnerConfig(configPath).hooks;
@@ -1051,7 +1051,7 @@ async function gatherDoctorChecks() {
1051
1051
  const { existsSync: existsSync2 } = await import('fs');
1052
1052
  if (process.platform !== "linux" || !existsSync2("/run/systemd/system")) return void 0;
1053
1053
  const { inspectService, realInspectProbes } = await import('./inspect-XAUSB7L3.js');
1054
- const { DEFAULT_UNIT_NAME } = await import('./install-DSUZE2TJ.js');
1054
+ const { DEFAULT_UNIT_NAME } = await import('./install-NMAPLLBQ.js');
1055
1055
  const { dirname: dirname2 } = await import('path');
1056
1056
  return inspectService(DEFAULT_UNIT_NAME, dirname2(configPath), realInspectProbes());
1057
1057
  })();
@@ -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 };
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, connectedLine } from './chunk-SSU747O6.js';
4
+ import { resolveRepoIdentity } from './chunk-D6FXM5OW.js';
5
+ import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
6
+ import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
7
+ import { homeFromEnv } from './chunk-VNVZDWO3.js';
8
+
9
+ createRequire(import.meta.url);
10
+
11
+ // src/auto-connect.ts
12
+ async function autoConnect(opts) {
13
+ const env = opts.env ?? process.env;
14
+ const home = opts.home ?? homeFromEnv(env);
15
+ const cwd = opts.cwd ?? process.cwd();
16
+ const resolved = resolveGatewayCredentials({ url: opts.url, apiKey: opts.apiKey, appId: opts.appId, home, env, cwd });
17
+ if (resolved.ok || resolved.kind !== "login" || !resolved.credential || !resolved.url) return void 0;
18
+ const dirs = findGitDirs(cwd);
19
+ const repository = resolveRepoIdentity(cwd).gitRepo;
20
+ if (dirs === void 0 || repository === void 0) return void 0;
21
+ const listed = await fetchFactories(opts.fetchImpl ?? fetch, resolved.url, resolved.credential, repository);
22
+ if (!listed.ok || listed.factories.length === 0) return void 0;
23
+ const chosen = selectFactory(listed.factories, readRepoConnection(cwd), repository);
24
+ if (chosen.factory === void 0) {
25
+ return `you are logged in, but no factory is chosen for this repository, and more than one fits. Run \`outerlayer connect --factory <org>/<factory>\` with one of:
26
+ ${chosen.text}
27
+ Or pass --app-id / set OUTERLAYER_APP_ID.`;
28
+ }
29
+ try {
30
+ saveFactoryConnection(dirs.gitCommonDir, void 0, chosen.factory, /* @__PURE__ */ new Date());
31
+ } catch {
32
+ return void 0;
33
+ }
34
+ process.stderr.write(`${connectedLine(repository, chosen.factory, chosen.reason)}
35
+ `);
36
+ return void 0;
37
+ }
38
+
39
+ export { autoConnect };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-YYYXRJUW.js';
3
+ import { isInLayout, packageRootIn, versionDir, switchCurrent, execStartLine } from './chunk-TI7B7UEO.js';
4
4
  import { RUNNER_DIR_MODE } from './chunk-ZM2IMMYN.js';
5
5
  import { realpathSync, readFileSync, mkdirSync, rmSync, cpSync, existsSync } from 'fs';
6
6
  import { dirname, sep, join } from 'path';
@@ -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-AUFG23AA.js';
3
+ import { RELAY_PORT, GATEWAY_SOCKET, GATEWAY_PORT, CLAUDE_SOCKET, CLAUDE_PORT, DESTINATION_BASE_PORT } from './chunk-OD2VTIHN.js';
4
4
  import { symlinkSync, unlinkSync } from 'fs';
5
5
  import { join } from 'path';
6
6