@outerlayer/cli 0.28.1 → 0.28.2

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 (31) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/build-info.json +1 -1
  3. package/dist/{check-NDDOASVO.js → check-YEI6TCUH.js} +8 -8
  4. package/dist/{chunk-6BWJQGTV.js → chunk-25X2PJDI.js} +1 -1
  5. package/dist/{chunk-W3FSGH2M.js → chunk-6S4V4UIC.js} +1 -1
  6. package/dist/{chunk-IKXY47R5.js → chunk-GLL4TN2M.js} +120 -17
  7. package/dist/{chunk-T57XUI6N.js → chunk-HOB7Z4JQ.js} +1 -1
  8. package/dist/{chunk-KVDVNOUK.js → chunk-KU7QL4XW.js} +3 -3
  9. package/dist/{chunk-2YSCKEL2.js → chunk-MKIC65SD.js} +45 -2
  10. package/dist/{chunk-R7SS5RLJ.js → chunk-MNHMUZGC.js} +2 -2
  11. package/dist/{chunk-7UGFIWIW.js → chunk-O65LES4V.js} +6 -6
  12. package/dist/{chunk-QWAYRAUX.js → chunk-SFJXGISY.js} +1 -1
  13. package/dist/{cli-QC6ZKHPK.js → cli-SCTKM2Y5.js} +25 -25
  14. package/dist/{command-3F6GY4CK.js → command-PY3C2E4B.js} +2 -2
  15. package/dist/{container-start-P7O5XGOB.js → container-start-7WLZMPEI.js} +3 -3
  16. package/dist/{doctor-QPQDF7FB.js → doctor-DQWRUAEB.js} +4 -4
  17. package/dist/{emit-artifact-cmd-O3IBUMUY.js → emit-artifact-cmd-SOXLBPQB.js} +1 -1
  18. package/dist/{emit-result-cmd-BNS57DD3.js → emit-result-cmd-TKA3GAN7.js} +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/{init-HHEAJDPN.js → init-5LHTF72R.js} +3 -3
  21. package/dist/{init-36XMFFRQ.js → init-BTH5YPBC.js} +3 -3
  22. package/dist/{init-cmd-K2IKTSXJ.js → init-cmd-L4VW3ZCT.js} +1 -1
  23. package/dist/{loop-F5ASKFRJ.js → loop-QDV7T65M.js} +8 -8
  24. package/dist/{machine-6STGIRJJ.js → machine-PLNSGKNF.js} +2 -2
  25. package/dist/{relay-GFPPD6GF.js → relay-FJ5K37Z5.js} +8 -4
  26. package/dist/{runner-key-Y76QXVNV.js → runner-key-M4N2BY5A.js} +3 -3
  27. package/dist/{session-sender-LFYMN6TT.js → session-sender-UQ3VF732.js} +2 -2
  28. package/dist/{status-OANG2EM3.js → status-PWMPP4ES.js} +4 -4
  29. package/dist/{sync-cmd-TNOOUPY2.js → sync-cmd-N4R7ST6X.js} +1 -1
  30. package/dist/{watch-HBNNYATF.js → watch-L5MSAWEO.js} +1 -1
  31. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @outerlayer/cli
2
2
 
3
+ ## 0.28.2
4
+
5
+ ### Patch Changes
6
+
7
+ - b61b6ba: `outerlayer sync` uploads a helper agent as finished once its parent session was told it stopped, even while the parent still runs. Before, each `sync` uploaded every helper of a running session as open, so finished helpers read as running until the whole session ended.
8
+ - fc2ba91: A container build's downloads arrive whole, so package installs no longer fail with aborted requests. A burst of connections no longer drops the build's link to the runner.
9
+
3
10
  ## 0.28.1
4
11
 
5
12
  ### Patch Changes
@@ -1 +1 @@
1
- {"id":"2026-10-17T13:49:00.892Z+55dd868","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
1
+ {"id":"2026-10-17T15:23:11.099Z+00ea5d3","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { probeCredentials } from './chunk-7UGFIWIW.js';
4
- import './chunk-KVDVNOUK.js';
3
+ import { probeCredentials } from './chunk-O65LES4V.js';
4
+ import './chunk-KU7QL4XW.js';
5
5
  import './chunk-3JVYMD4G.js';
6
6
  import './chunk-E7R2GIAW.js';
7
7
  import './chunk-TPKYTORP.js';
@@ -9,18 +9,18 @@ import './chunk-IVX3U7KV.js';
9
9
  import './chunk-ZVB57WI6.js';
10
10
  import './chunk-66T6XJAB.js';
11
11
  import './chunk-N7WAEEIU.js';
12
- import './chunk-QWAYRAUX.js';
13
- import './chunk-2YSCKEL2.js';
12
+ import './chunk-SFJXGISY.js';
13
+ import './chunk-MKIC65SD.js';
14
14
  import './chunk-TVZAC2NP.js';
15
15
  import './chunk-ESVW4MJY.js';
16
16
  import './chunk-ZTY7HHYB.js';
17
- import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem, formerSkillQueues, formerSkillProblem } from './chunk-W3FSGH2M.js';
17
+ import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem, formerSkillQueues, formerSkillProblem } from './chunk-6S4V4UIC.js';
18
18
  import './chunk-YYYRBYWG.js';
19
19
  import './chunk-GUXWQIEY.js';
20
20
  import './chunk-TBT347UY.js';
21
- import './chunk-R7SS5RLJ.js';
22
- import './chunk-T57XUI6N.js';
23
- import './chunk-IKXY47R5.js';
21
+ import './chunk-MNHMUZGC.js';
22
+ import './chunk-HOB7Z4JQ.js';
23
+ import './chunk-GLL4TN2M.js';
24
24
  import './chunk-MHAR6S7B.js';
25
25
  import './chunk-WWQVKFN6.js';
26
26
  import './chunk-USJZ2LDK.js';
@@ -1193,7 +1193,7 @@ async function gatherDoctorChecks() {
1193
1193
  const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
1194
1194
  checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
1195
1195
  } else if (hasRunnerBlock(configPath)) {
1196
- const { runnerHostChecks } = await import('./doctor-QPQDF7FB.js');
1196
+ const { runnerHostChecks } = await import('./doctor-DQWRUAEB.js');
1197
1197
  const hooks = (() => {
1198
1198
  try {
1199
1199
  return loadRunnerConfig(configPath).hooks;
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isPlaceholderCommand } from './chunk-R7SS5RLJ.js';
3
+ import { isPlaceholderCommand } from './chunk-MNHMUZGC.js';
4
4
  import { describeCallFailure } from './chunk-USJZ2LDK.js';
5
5
  import { builtinKind } from './chunk-55XLX5PA.js';
6
6
  import { WorkCommandError, getJson } from './chunk-X52PMPOM.js';
@@ -1363,6 +1363,29 @@ async function resolveAgentUser(input) {
1363
1363
  var noop = () => void 0;
1364
1364
  var FRAME_HEADER_BYTES = 9;
1365
1365
  var GOAWAY_FRAME = 7;
1366
+ function describeGoawayCode(code) {
1367
+ const names = [
1368
+ "NO_ERROR",
1369
+ "PROTOCOL_ERROR",
1370
+ "INTERNAL_ERROR",
1371
+ "FLOW_CONTROL_ERROR",
1372
+ "SETTINGS_TIMEOUT",
1373
+ "STREAM_CLOSED",
1374
+ "FRAME_SIZE_ERROR",
1375
+ "REFUSED_STREAM",
1376
+ "CANCEL",
1377
+ "COMPRESSION_ERROR",
1378
+ "CONNECT_ERROR",
1379
+ "ENHANCE_YOUR_CALM",
1380
+ "INADEQUATE_SECURITY",
1381
+ "HTTP_1_1_REQUIRED"
1382
+ ];
1383
+ const name = names[code];
1384
+ return name === void 0 ? `error code ${code}` : `${name} (${code})`;
1385
+ }
1386
+ function goawayNote(label, code) {
1387
+ return code === void 0 ? "" : ` \xB7 ${label} ${describeGoawayCode(code)}`;
1388
+ }
1366
1389
  function watchSentGoaway(onError) {
1367
1390
  let head = Buffer.alloc(0);
1368
1391
  let want = FRAME_HEADER_BYTES;
@@ -1385,7 +1408,10 @@ function watchSentGoaway(onError) {
1385
1408
  want = FRAME_HEADER_BYTES + 8;
1386
1409
  continue;
1387
1410
  }
1388
- if (want > FRAME_HEADER_BYTES && head.readUInt32BE(FRAME_HEADER_BYTES + 4) !== http2.constants.NGHTTP2_NO_ERROR) onError();
1411
+ if (want > FRAME_HEADER_BYTES) {
1412
+ const code = head.readUInt32BE(FRAME_HEADER_BYTES + 4);
1413
+ if (code !== http2.constants.NGHTTP2_NO_ERROR) onError(code);
1414
+ }
1389
1415
  skip = length - (want - FRAME_HEADER_BYTES);
1390
1416
  head = Buffer.alloc(0);
1391
1417
  want = FRAME_HEADER_BYTES;
@@ -1397,9 +1423,11 @@ function serveSession(transport, services, opts = {}) {
1397
1423
  let open = 0;
1398
1424
  let served = 0;
1399
1425
  let malformed = false;
1426
+ let goawayCode;
1400
1427
  transport.on("error", noop);
1401
- const watch = watchSentGoaway(() => {
1428
+ const watch = watchSentGoaway((code) => {
1402
1429
  malformed = true;
1430
+ goawayCode ??= code;
1403
1431
  setImmediate(() => session.destroy());
1404
1432
  });
1405
1433
  const outbound = new Transform({
@@ -1421,7 +1449,10 @@ function serveSession(transport, services, opts = {}) {
1421
1449
  session.on("error", (err) => {
1422
1450
  if (typeof err.code === "string" && err.code.startsWith("ERR_HTTP2_")) malformed = true;
1423
1451
  });
1424
- session.on("close", () => resolve2({ malformed, served }));
1452
+ session.on("goaway", (code) => {
1453
+ if (code !== http2.constants.NGHTTP2_NO_ERROR) goawayCode ??= code;
1454
+ });
1455
+ session.on("close", () => resolve2({ malformed, served, goawayCode }));
1425
1456
  });
1426
1457
  session.on("stream", (stream, headers) => {
1427
1458
  stream.on("error", noop);
@@ -1495,14 +1526,14 @@ function superviseRelay(input) {
1495
1526
  if (joined) {
1496
1527
  backoff = FIRST_BACKOFF_MS;
1497
1528
  failing = false;
1498
- if (!closed) input.log?.(`the session with ${input.container} ended \xB7 joining again`);
1529
+ if (!closed) input.log?.(`the session with ${input.container} ended \xB7 joining again${goawayNote("GOAWAY", end.goawayCode)}`);
1499
1530
  }
1500
1531
  if (!end.malformed && end.served > 0) malformedInARow = 0;
1501
1532
  if (end.malformed) {
1502
1533
  malformedInARow++;
1503
1534
  if (malformedInARow >= MAX_MALFORMED_SESSIONS) {
1504
1535
  fatal = MALFORMED_REASON;
1505
- input.log?.(`the session with ${input.container} broke HTTP/2 framing ${malformedInARow} times in a row \xB7 ending the build`);
1536
+ input.log?.(`the session with ${input.container} broke HTTP/2 framing ${malformedInARow} times in a row${goawayNote("last GOAWAY", end.goawayCode)} \xB7 ending the build`);
1506
1537
  input.onFatal?.(fatal);
1507
1538
  return;
1508
1539
  }
@@ -2279,6 +2310,9 @@ var CONNECT_TIMEOUT_MS = 3e4;
2279
2310
  var NOT_ALLOWED_RANGE = "not-allowed";
2280
2311
  var NOT_RESOLVED = "not resolved";
2281
2312
  var IDLE_TIMEOUT_MS = 10 * 6e4;
2313
+ var STALLED_RESPONSE_MS = 6e4;
2314
+ var MAX_BAD_GATEWAY_LINES = 10;
2315
+ var BAD_GATEWAY_WINDOW_MS = 1e4;
2282
2316
  async function systemResolve(host) {
2283
2317
  const found = await lookup(host, { all: true, verbatim: true });
2284
2318
  return found.map((a) => ({ address: a.address }));
@@ -2286,6 +2320,13 @@ async function systemResolve(host) {
2286
2320
  function systemHostAddresses() {
2287
2321
  return Object.values(networkInterfaces()).flatMap((list) => (list ?? []).map((i) => i.address));
2288
2322
  }
2323
+ function errorCode(err) {
2324
+ const code = err?.code;
2325
+ return typeof code === "string" ? code : "unknown";
2326
+ }
2327
+ function abortedError(message) {
2328
+ return Object.assign(new Error(message), { code: "ECONNABORTED" });
2329
+ }
2289
2330
  function normalize(address) {
2290
2331
  const zone = address.indexOf("%");
2291
2332
  return (zone === -1 ? address : address.slice(0, zone)).toLowerCase();
@@ -2305,6 +2346,26 @@ async function startTunnel(socketPath, opts = {}) {
2305
2346
  const ownAddresses = opts.hostAddresses ?? systemHostAddresses;
2306
2347
  const connectTimeoutMs = opts.connectTimeoutMs ?? CONNECT_TIMEOUT_MS;
2307
2348
  const idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
2349
+ const stalledResponseMs = opts.stalledResponseMs ?? STALLED_RESPONSE_MS;
2350
+ let windowStartedMs = 0;
2351
+ let linesInWindow = 0;
2352
+ let suppressed = 0;
2353
+ const logBadGateway = (what) => {
2354
+ if (opts.log === void 0) return;
2355
+ const now = Date.now();
2356
+ if (now - windowStartedMs >= BAD_GATEWAY_WINDOW_MS) {
2357
+ windowStartedMs = now;
2358
+ linesInWindow = 0;
2359
+ }
2360
+ if (linesInWindow >= MAX_BAD_GATEWAY_LINES) {
2361
+ suppressed++;
2362
+ return;
2363
+ }
2364
+ linesInWindow++;
2365
+ const more = suppressed === 0 ? "" : ` (${suppressed} more 502 lines were not written)`;
2366
+ suppressed = 0;
2367
+ opts.log(`tunnel answered 502: ${what}${more}`);
2368
+ };
2308
2369
  const hosts = [];
2309
2370
  const seen = /* @__PURE__ */ new Set();
2310
2371
  const extraHosts = /* @__PURE__ */ new Set();
@@ -2376,7 +2437,7 @@ async function startTunnel(socketPath, opts = {}) {
2376
2437
  }
2377
2438
  persist();
2378
2439
  };
2379
- async function decide(host) {
2440
+ async function decide(host, port) {
2380
2441
  if (opts.allowHosts !== void 0 && !hostAllowed(host, opts.allowHosts)) {
2381
2442
  refused2(host, NOT_RESOLVED, NOT_ALLOWED_RANGE);
2382
2443
  return { ok: false, status: 403, body: `refused: ${host} is not in runner.build.allowHosts
@@ -2385,12 +2446,16 @@ async function startTunnel(socketPath, opts = {}) {
2385
2446
  let addresses;
2386
2447
  try {
2387
2448
  addresses = await resolve2(host);
2388
- } catch {
2449
+ } catch (err) {
2450
+ logBadGateway(`could not resolve ${host}:${port}, ${errorCode(err)}`);
2389
2451
  return { ok: false, status: 502, body: `could not resolve ${host}
2390
2452
  ` };
2391
2453
  }
2392
- if (addresses.length === 0) return { ok: false, status: 502, body: `${host} has no address
2454
+ if (addresses.length === 0) {
2455
+ logBadGateway(`${host}:${port} resolved to no address`);
2456
+ return { ok: false, status: 502, body: `${host} has no address
2393
2457
  ` };
2458
+ }
2394
2459
  const own = new Set(ownAddresses().map(normalize));
2395
2460
  let firstRefusal;
2396
2461
  for (const { address: address2 } of addresses) {
@@ -2432,36 +2497,70 @@ ${body}`);
2432
2497
  client.end("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
2433
2498
  return;
2434
2499
  }
2435
- const decision = await decide(target.host);
2500
+ const decision = await decide(target.host, target.port);
2436
2501
  if (!decision.ok) {
2437
2502
  reply(client, decision.status, decision.body);
2438
2503
  return;
2439
2504
  }
2440
2505
  const upstream = openConnection({ address: decision.address, port: target.port });
2441
2506
  upstream.setTimeout(connectTimeoutMs);
2442
- const failed = () => {
2507
+ const failed = (err) => {
2443
2508
  upstream.destroy();
2509
+ logBadGateway(`could not connect to ${target.host}:${target.port}, ${err === void 0 ? "ETIMEDOUT" : errorCode(err)}`);
2444
2510
  reply(client, 502, `could not connect to ${target.host}
2445
2511
  `);
2446
2512
  };
2513
+ const timedOut = () => failed();
2447
2514
  upstream.once("error", failed);
2448
- upstream.once("timeout", failed);
2515
+ upstream.once("timeout", timedOut);
2449
2516
  client.on("close", () => upstream.destroy());
2450
2517
  const established = () => {
2451
2518
  upstream.removeListener("error", failed);
2452
- upstream.removeListener("timeout", failed);
2519
+ upstream.removeListener("timeout", timedOut);
2453
2520
  upstream.setTimeout(idleTimeoutMs, () => upstream.destroy());
2454
- upstream.on("error", () => void 0);
2455
- upstream.on("close", () => client.destroy());
2521
+ upstream.on("error", (err) => client.destroy(err));
2522
+ upstream.on("close", () => {
2523
+ if (!upstream.readableEnded && !client.writableEnded) client.destroy(abortedError("the tunnel closed the connection to the server before it ended"));
2524
+ });
2525
+ client.once("end", () => {
2526
+ upstream.destroy();
2527
+ client.end();
2528
+ });
2456
2529
  reached(target.host);
2457
2530
  client.write("HTTP/1.1 200 Connection Established\r\n\r\n");
2458
2531
  upstream.write(head);
2532
+ releaseWhenStalled(client, upstream);
2459
2533
  upstream.pipe(client);
2460
2534
  client.pipe(upstream);
2461
2535
  };
2462
2536
  if (upstream.readyState === "open") established();
2463
2537
  else upstream.once("connect", established);
2464
2538
  }
2539
+ function releaseWhenStalled(client, upstream) {
2540
+ let delivered = 0;
2541
+ upstream.on("data", (chunk) => delivered += chunk.length);
2542
+ let read = delivered;
2543
+ let timer;
2544
+ const blocked = () => upstream.isPaused() || upstream.readableEnded;
2545
+ const check = () => {
2546
+ timer = void 0;
2547
+ if (client.writableFinished || !blocked()) return;
2548
+ if (delivered > read) {
2549
+ read = delivered;
2550
+ timer = setTimeout(check, stalledResponseMs);
2551
+ return;
2552
+ }
2553
+ client.destroy(abortedError("the build stopped reading the response"));
2554
+ };
2555
+ const watch = () => {
2556
+ if (timer !== void 0) return;
2557
+ read = delivered;
2558
+ timer = setTimeout(check, stalledResponseMs);
2559
+ };
2560
+ upstream.on("pause", watch);
2561
+ upstream.on("end", watch);
2562
+ client.once("close", () => clearTimeout(timer));
2563
+ }
2465
2564
  async function proxyPlain(req, res) {
2466
2565
  if (opts.gitRemote !== void 0 && (req.url ?? "").startsWith("/")) {
2467
2566
  await opts.gitRemote(req, res);
@@ -2482,7 +2581,7 @@ ${body}`);
2482
2581
  }
2483
2582
  const host = url.hostname.replace(/^\[|\]$/g, "");
2484
2583
  const port = url.port === "" ? 80 : Number(url.port);
2485
- const decision = await decide(host);
2584
+ const decision = await decide(host, port);
2486
2585
  if (!decision.ok) {
2487
2586
  res.writeHead(decision.status, { "Content-Type": "text/plain", Connection: "close" });
2488
2587
  res.end(decision.body);
@@ -2507,8 +2606,9 @@ ${body}`);
2507
2606
  );
2508
2607
  upstream.setTimeout(connectTimeoutMs, () => upstream.destroy());
2509
2608
  res.on("close", () => upstream.destroy());
2510
- upstream.on("error", () => {
2609
+ upstream.on("error", (err) => {
2511
2610
  if (!res.headersSent) {
2611
+ logBadGateway(`could not reach ${host}:${port}, ${errorCode(err)}`);
2512
2612
  res.writeHead(502, { "Content-Type": "text/plain", Connection: "close" });
2513
2613
  res.end(`could not reach ${host}
2514
2614
  `);
@@ -2561,6 +2661,9 @@ var RELAY_WAIT_MS = 500;
2561
2661
  var BUSY_IMAGE_WAIT_MS = 5e3;
2562
2662
  var VOLUME_REMOVE_ATTEMPTS = 4;
2563
2663
  var WORKFLOW_PERMISSION_REASON = "workflow_permission_required";
2664
+ function withTunnelLog(opts, log) {
2665
+ return { ...opts, tunnelOptions: { log, ...opts?.tunnelOptions } };
2666
+ }
2564
2667
  function createContainerRuntime(opts = {}) {
2565
2668
  const { cli, remoteFor } = opts;
2566
2669
  return {
@@ -3421,4 +3524,4 @@ async function startCheckContainer(input) {
3421
3524
  };
3422
3525
  }
3423
3526
 
3424
- 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, createLeaseChannel, deleteBuildDisk, deliverContainerHooks, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, helperFirecrackerNote, helperSocketPath, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, probeHelper, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, writeEvalInput };
3527
+ 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, createLeaseChannel, deleteBuildDisk, deliverContainerHooks, ensureFirecrackerAndJailer, ensureRootfs, ensureTunnel, filesAreCopied, ghHostsYml, gitRemoteFor, helperFirecrackerNote, helperSocketPath, isLiteralAddress, keepGhConfigCurrent, leaseExpiresAtMs, leaseTimeLeftMs, lifecycleFailureReason, lifecycleSteps, machineConfig, measureDisk, obtainImage, outOfMemoryReason, parseCpuList, prepareBranch, probeHelper, provisionContainer, resolveAgentUser, runBuildSteps, senderAliveScript, senderSignalScript, setUpRunnerCgroup, shellQuote, signalInContainer, startCheckContainer, startServicesFor, stopContainer, syncInContainer, withTunnelLog, writeEvalInput };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { MIN_ENGINE_MAJOR } from './chunk-IKXY47R5.js';
3
+ import { MIN_ENGINE_MAJOR } from './chunk-GLL4TN2M.js';
4
4
  import { runnerImageVersion } from './chunk-Z3ASAXVU.js';
5
5
  import { firecrackerArch, MICROVM_ARCHES, guestAssetsPinned } from './chunk-SJZL5F3F.js';
6
6
  import { spawnSync } from 'child_process';
@@ -2,10 +2,10 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { readsJobState, READ_JOB_STATE_FORMATS, jobStateFormatOf } from './chunk-ZVB57WI6.js';
4
4
  import { DOCKERD_LOG, HELPER_PATH, HELPER_RECORD } from './chunk-N7WAEEIU.js';
5
- import { senderPidfile } from './chunk-QWAYRAUX.js';
6
- import { installScrubContext } from './chunk-2YSCKEL2.js';
5
+ import { senderPidfile } from './chunk-SFJXGISY.js';
6
+ import { installScrubContext } from './chunk-MKIC65SD.js';
7
7
  import { writeDockerClientConfig } from './chunk-ZTY7HHYB.js';
8
- import { ADDED_USER, shellQuote, GH_CONFIG_YML, ghHostsYml, AssetError, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createLeaseChannel, createBuildDisk, machineConfig, resolveAgentUser, AgentUserError, runBuildSteps, LEASE_SECONDS, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, containerSenderCommand, signalInContainer, syncInContainer, copyTranscriptsFromContainer, senderAliveScript, helperFirecrackerNote, HelperRefusal, isLiteralAddress, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, DeliveryFailure, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript, containerJudgeEnvironment, copyJudgeTree } from './chunk-IKXY47R5.js';
8
+ import { ADDED_USER, shellQuote, GH_CONFIG_YML, ghHostsYml, AssetError, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createLeaseChannel, createBuildDisk, machineConfig, resolveAgentUser, AgentUserError, runBuildSteps, LEASE_SECONDS, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, containerSenderCommand, signalInContainer, syncInContainer, copyTranscriptsFromContainer, senderAliveScript, helperFirecrackerNote, HelperRefusal, isLiteralAddress, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, DeliveryFailure, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript, containerJudgeEnvironment, copyJudgeTree } from './chunk-GLL4TN2M.js';
9
9
  import { waitForAgent, vmExecArgs } from './chunk-MHAR6S7B.js';
10
10
  import { socketPathProblem, vsockLinks, LEASE_LINK, linkVsockSockets } from './chunk-WWQVKFN6.js';
11
11
  import { describeCallFailure, resolveGoverningSource, refusalCode, removeStagedContext, stageGovernedContext, pinnedSourceOf, commandWithShim, logStamp, createRunnerLog, removeKeptContext, formatDuration, retrySend, formatClock, keptContextTree } from './chunk-USJZ2LDK.js';
@@ -19,7 +19,7 @@ import { cliInvocation } from './chunk-CRB3POP4.js';
19
19
  import { removeJournalHooks } from './chunk-TUSYOL2O.js';
20
20
  import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-QZBXLLTV.js';
21
21
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
22
- import { dirname, basename, join } from 'path';
22
+ import { dirname, basename, join, sep } from 'path';
23
23
  import { statSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync, rmSync } from 'fs';
24
24
  import { execFileSync } from 'child_process';
25
25
  import { hostname, userInfo } from 'os';
@@ -834,6 +834,49 @@ var LiveUploader = class {
834
834
  }
835
835
  }
836
836
  };
837
+ var NOTICE = /<task-id>(?:\s|\\n)*([\w-]+)(?:\s|\\n)*<\/task-id>(?:(?!<task-notification>)[\s\S])*?<status>(?:\s|\\n)*(completed|failed|killed|stopped|cancelled|canceled|error)(?:\s|\\n)*<\/status>/gi;
838
+ var cache = /* @__PURE__ */ new Map();
839
+ function parentTranscriptOf(subagentFile) {
840
+ const segments = subagentFile.split(sep);
841
+ const at = segments.lastIndexOf("subagents");
842
+ if (at < 2) return void 0;
843
+ return join(segments.slice(0, at - 1).join(sep), `${segments[at - 1]}.jsonl`);
844
+ }
845
+ function endNotices(text) {
846
+ const endedAt = /* @__PURE__ */ new Map();
847
+ for (const raw of text.split("\n")) {
848
+ if (!raw.includes("<task-notification>")) continue;
849
+ let line;
850
+ try {
851
+ line = JSON.parse(raw);
852
+ } catch {
853
+ continue;
854
+ }
855
+ if (line.type !== "user" || typeof line.timestamp !== "string") continue;
856
+ for (const [, id] of raw.matchAll(NOTICE)) endedAt.set(id, [...endedAt.get(id) ?? [], line.timestamp]);
857
+ }
858
+ return endedAt;
859
+ }
860
+ function noticesIn(parentFile) {
861
+ try {
862
+ const { size, mtimeMs } = statSync(parentFile);
863
+ const key = `${parentFile}\0${size}\0${mtimeMs}`;
864
+ const known = cache.get(key) ?? endNotices(readFileSync(parentFile, "utf8"));
865
+ cache.set(key, known);
866
+ return known;
867
+ } catch {
868
+ return /* @__PURE__ */ new Map();
869
+ }
870
+ }
871
+ function subagentEndedInParent(subagentFile, lastActivityAt) {
872
+ const parent = parentTranscriptOf(subagentFile);
873
+ if (parent === void 0) return false;
874
+ const notices = noticesIn(parent).get(basename(subagentFile, ".jsonl").replace(/^agent-/, "")) ?? [];
875
+ return notices.some((at) => lastActivityAt === void 0 || Date.parse(at) >= Date.parse(lastActivityAt));
876
+ }
877
+ function runningForParent(entry, lastActivityAt) {
878
+ return !entry.isSubagent || !subagentEndedInParent(entry.file, lastActivityAt);
879
+ }
837
880
 
838
881
  // src/skip-verdict.ts
839
882
  var RESUME_WINDOW_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -1206,7 +1249,7 @@ async function runSyncInner(opts, stats) {
1206
1249
  applyContextProvenance(session, contextSourceBySessionId.get(session.id));
1207
1250
  applyReportedCost(session, home);
1208
1251
  const gated = prepareSessionForUpload(session, tier, envVars);
1209
- const liveEntry = liveUploads[gated.id];
1252
+ const liveEntry = runningForParent(entry, gated.endedAt) ? liveUploads[gated.id] : void 0;
1210
1253
  const daemonIsStreaming = liveEntry !== void 0 && !liveEntry.ended && !liveEntry.failed;
1211
1254
  if (daemonIsStreaming && !sessionHasEnded(home, gated.subagent?.parentSessionId ?? gated.id)) {
1212
1255
  const gatedTurns = gated.turns ?? [];
@@ -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-T57XUI6N.js';
4
- import { MIN_ENGINE_MAJOR } from './chunk-IKXY47R5.js';
3
+ import { detectMachine, supportsContainerBuilds, reachDockerStep, describeMachineDocker, supportsMicroVmBuilds } from './chunk-HOB7Z4JQ.js';
4
+ import { MIN_ENGINE_MAJOR } from './chunk-GLL4TN2M.js';
5
5
  import { hasStoredCredential, AGENT_COMMANDS, storeClaudeCredential, credentialFromStdin, isAgentName } from './chunk-F4FA3ZUT.js';
6
6
  import { runnerCredentialProblem } from './chunk-55XLX5PA.js';
7
7
  import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-5K3KB4YR.js';
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, MICROVM_COMMAND_DIR, commandLogOffset, startMicroVmCommand, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isContainerTracked, isMicroVmTracked, probeMicroVmCommand, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isTracked, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, AttemptLogBook, microVmOomKills, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, serveLease, vmAlive, writeGuestGhConfig, ALREADY_RELEASED, inTeardown } from './chunk-KVDVNOUK.js';
3
+ import { releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, MICROVM_COMMAND_DIR, commandLogOffset, startMicroVmCommand, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isContainerTracked, isMicroVmTracked, probeMicroVmCommand, probeCommand, appendCommandLog, judgeProbe, EXIT_CODE_FILE, isTracked, isGroupAlive, outcomeFromExitCode, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listUnreadableJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, AttemptLogBook, microVmOomKills, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, listTrackedJobs, restartSender, serveLease, vmAlive, writeGuestGhConfig, ALREADY_RELEASED, inTeardown } from './chunk-KU7QL4XW.js';
4
4
  import { decideInstalledSwitch } from './chunk-3JVYMD4G.js';
5
5
  import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-E7R2GIAW.js';
6
6
  import { RUNNER_PROTOCOL } from './chunk-TPKYTORP.js';
7
7
  import { writePendingUpdate } from './chunk-IVX3U7KV.js';
8
8
  import { JOB_STATE_FORMAT, readsJobState, jobStateFormatOf } from './chunk-ZVB57WI6.js';
9
9
  import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-66T6XJAB.js';
10
- import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-W3FSGH2M.js';
10
+ import { currentSkillCommand, formerSkillProblem, placeholderQueues, placeholderProblem } from './chunk-6S4V4UIC.js';
11
11
  import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
12
12
  import { writeMarker, readMarker, currentVersion, removeMarker, entryIn, versionDir, startedThroughCurrent, switchCurrent, isInLayout, cleanVersions, stagingDir } from './chunk-GUXWQIEY.js';
13
13
  import { RepoFilter } from './chunk-TBT347UY.js';
14
- import { leaseTimeLeftMs, LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec, setUpRunnerCgroup, createContainerRuntime, measureDisk, parseCpuList, ensureTunnel, keepGhConfigCurrent, filesAreCopied, gitRemoteFor, startServicesFor, createLeaseChannel } from './chunk-IKXY47R5.js';
14
+ import { leaseTimeLeftMs, createContainerRuntime, withTunnelLog, LEASE_SECONDS, provisionContainer, leaseExpiresAtMs, deliverContainerHooks, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandExec, setUpRunnerCgroup, measureDisk, parseCpuList, ensureTunnel, keepGhConfigCurrent, filesAreCopied, gitRemoteFor, startServicesFor, createLeaseChannel } from './chunk-GLL4TN2M.js';
15
15
  import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, BuildTokens, classifyRefusal, refusalCode, createRunnerLog, formatClock } from './chunk-USJZ2LDK.js';
16
16
  import { tagToPull, pullInstruction, imageTag, writeUpdateStatus } from './chunk-Z3ASAXVU.js';
17
17
  import { isVersion, compareVersions, satisfiesRange } from './chunk-TQMI335S.js';
@@ -1091,7 +1091,7 @@ function leaseTimeLeftFor(state, active) {
1091
1091
  return () => (state.deps.leaseTimeLeftMs ?? leaseTimeLeftMs)(active.job, nowOf(state).getTime());
1092
1092
  }
1093
1093
  function runtimeOf(state) {
1094
- state.containerRuntime ??= createContainerRuntime(state.deps.container);
1094
+ state.containerRuntime ??= createContainerRuntime(withTunnelLog(state.deps.container, (line) => logOf(state).line(line)));
1095
1095
  return state.containerRuntime;
1096
1096
  }
1097
1097
  function finishDepsOf(state) {
@@ -2955,7 +2955,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
2955
2955
  check: update.check ? () => update.check(configPath) : async () => {
2956
2956
  const held = heldClaudeCredential();
2957
2957
  const env = held === void 0 ? process.env : { ...process.env, [held.variable]: held.value };
2958
- return (await import('./check-NDDOASVO.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl, env });
2958
+ return (await import('./check-YEI6TCUH.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl, env });
2959
2959
  },
2960
2960
  now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
2961
2961
  log
@@ -3270,4 +3270,4 @@ function runnerProcessState(configPath) {
3270
3270
  return isSameProcess(entry.pid, entry.start) ? { state: "running", pid: entry.pid } : { state: "stale", pid: entry.pid };
3271
3271
  }
3272
3272
 
3273
- export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, start, tick, watchTick };
3273
+ export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, runtimeOf, start, tick, watchTick };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LiveUploader } from './chunk-2YSCKEL2.js';
3
+ import { LiveUploader } from './chunk-MKIC65SD.js';
4
4
  import { CaptureDaemon } from './chunk-UHU7H57K.js';
5
5
  import { spoolDir } from './chunk-DKWQMPSL.js';
6
6
  import { parseWorkItemEnv } from './chunk-T2Q7ISPE.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-6BWJQGTV.js';
3
+ import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-25X2PJDI.js';
4
4
  import './chunk-ITAIEJ2T.js';
5
5
  import './chunk-QBQHQEUG.js';
6
6
  import './chunk-KT4CN6OU.js';
@@ -3926,13 +3926,13 @@ what CLIs older than ${FIRST_VERSION_READING_AGENTS_SKILLS} do. \`` + cliInvocat
3926
3926
  if (changed.length > 0 && !opts.json) process.stdout.write(`Removed the claude function from ${changed.join(", ")}.
3927
3927
  `);
3928
3928
  }
3929
- const shell = !opts.remove && opts.shellFunction !== void 0 ? (await import('./init-cmd-K2IKTSXJ.js')).applyShellFunctionFlag(opts.shellFunction, { home: homeFromEnv(), shellPath: process.env.SHELL }) : void 0;
3929
+ const shell = !opts.remove && opts.shellFunction !== void 0 ? (await import('./init-cmd-L4VW3ZCT.js')).applyShellFunctionFlag(opts.shellFunction, { home: homeFromEnv(), shellPath: process.env.SHELL }) : void 0;
3930
3930
  if (opts.json) writeJson(shell === void 0 ? outcome.result : { ...outcome.result, shellFunction: { outcome: shell.outcome, reason: shell.reason } });
3931
3931
  else process.stdout.write(outcome.text + skillsLine + (shell?.text ?? ""));
3932
3932
  return;
3933
3933
  }
3934
3934
  await installMachineSkillsForSetup();
3935
- const { runInitCommand } = await import('./init-cmd-K2IKTSXJ.js');
3935
+ const { runInitCommand } = await import('./init-cmd-L4VW3ZCT.js');
3936
3936
  const code = await runInitCommand(
3937
3937
  { json: opts.json, factory: opts.factory, shellFunction: opts.shellFunction },
3938
3938
  {
@@ -4070,7 +4070,7 @@ code is 1: revoke the token on /profile/security.
4070
4070
  else fail(found.reason);
4071
4071
  return;
4072
4072
  }
4073
- const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-TNOOUPY2.js');
4073
+ const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-N4R7ST6X.js');
4074
4074
  try {
4075
4075
  const result = await runSync({
4076
4076
  url: opts.url,
@@ -4101,7 +4101,7 @@ code is 1: revoke the token on /profile/security.
4101
4101
  if (invokedCommandToken(argv) === "watch") {
4102
4102
  warnDeprecated(`\`${cliInvocation()} watch\` is now \`${cliInvocation()} daemon\`; the old name will be removed in a future release.`);
4103
4103
  }
4104
- const { runWatch } = await import('./watch-HBNNYATF.js');
4104
+ const { runWatch } = await import('./watch-L5MSAWEO.js');
4105
4105
  await runWatch({ once: opts.once });
4106
4106
  });
4107
4107
  program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
@@ -4113,7 +4113,7 @@ code is 1: revoke the token on /profile/security.
4113
4113
  program2.command("claude [args...]").description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
4114
4114
  });
4115
4115
  const brokerRelay = program2.command("broker-relay", { hidden: true }).description("relay a build's loopback connections to the runner's tunnel and destinations").enablePositionalOptions().option("--port <port>", "the loopback port to listen on").option("--socket <path>", "the runner's tunnel socket").option("--join <path>", "the socket the runner's joining process connects to").option("--lease-watchdog", "exit when the runner's lease expiry passes; needs --join").option("--forward <port=target>", "also relay a loopback port to a destination; repeatable", (value, previous) => [...previous, value], []).action(async (opts) => {
4116
- const { startRelay, startSessionRelay } = await import('./relay-GFPPD6GF.js');
4116
+ const { startRelay, startSessionRelay } = await import('./relay-FJ5K37Z5.js');
4117
4117
  const { TARGET_TUNNEL, targetOfPath } = await import('./relay-protocol-HELO5SNH.js');
4118
4118
  const port = Number(opts.port);
4119
4119
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
@@ -4146,7 +4146,7 @@ code is 1: revoke the token on /profile/security.
4146
4146
  await startRelay({ port, socketPath: opts.socket, forwards: forwards.map((forward) => ({ port: forward.port, socketPath: forward.spec })) });
4147
4147
  });
4148
4148
  brokerRelay.command("join").description("carry the runner's session to the relay over standard input and output").option("--socket <path>", "the relay's joining socket", "/run/outerlayer-relay/join.sock").action(async (opts) => {
4149
- const { joinRelay } = await import('./relay-GFPPD6GF.js');
4149
+ const { joinRelay } = await import('./relay-FJ5K37Z5.js');
4150
4150
  try {
4151
4151
  await joinRelay({ socketPath: opts.socket, input: process.stdin, output: process.stdout });
4152
4152
  } catch (err) {
@@ -4191,7 +4191,7 @@ code is 1: revoke the token on /profile/security.
4191
4191
  process.exitCode = await runBuildCommand({ dir: opts.dir, argv: command });
4192
4192
  });
4193
4193
  program2.command("session-sender", { hidden: true }).description("stream a runner build's sessions to its work item while the build runs").action(async () => {
4194
- const { runSessionSender } = await import('./session-sender-LFYMN6TT.js');
4194
+ const { runSessionSender } = await import('./session-sender-UQ3VF732.js');
4195
4195
  try {
4196
4196
  await runSessionSender();
4197
4197
  } catch (err) {
@@ -4281,7 +4281,7 @@ Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
4281
4281
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
4282
4282
  return;
4283
4283
  }
4284
- const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-BNS57DD3.js');
4284
+ const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-TKA3GAN7.js');
4285
4285
  try {
4286
4286
  const result = await runEmitResult({
4287
4287
  name,
@@ -4331,7 +4331,7 @@ everywhere, bytes and deep link untouched; a still-queued one is cancelled
4331
4331
  locally so it never uploads. One correction can retire several duplicates.
4332
4332
  `
4333
4333
  ).action(async (file, opts) => {
4334
- const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-O3IBUMUY.js');
4334
+ const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-SOXLBPQB.js');
4335
4335
  let pr;
4336
4336
  if (opts.pr !== void 0) {
4337
4337
  pr = parseTrackerNumber(opts.pr);
@@ -4910,7 +4910,7 @@ function registerRunnerCommands(program2) {
4910
4910
  const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
4911
4911
  runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
4912
4912
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-5QYIKYUP.js');
4913
- const { start, RunnerStartError } = await import('./loop-F5ASKFRJ.js');
4913
+ const { start, RunnerStartError } = await import('./loop-QDV7T65M.js');
4914
4914
  const { RunnerAlreadyRunningError } = await import('./pidfile-CYCTH6NQ.js');
4915
4915
  const configPath = opts.config ?? defaultRunnerConfigPath();
4916
4916
  try {
@@ -4929,8 +4929,8 @@ function registerRunnerCommands(program2) {
4929
4929
  "\nReads OUTERLAYER_URL, OUTERLAYER_APP_ID, OUTERLAYER_API_KEY, OUTERLAYER_RUNNER_NAME and one Claude credential\n(CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN) from the environment. OUTERLAYER_AGENT\nis optional and defaults to claude. On a later start it refuses variables that disagree with the config in the volume.\nThe image sets OUTERLAYER_RUNNER_IMAGE; outside the image, use `runner start`.\n"
4930
4930
  ).action(async () => {
4931
4931
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-5QYIKYUP.js');
4932
- const { containerStart } = await import('./container-start-P7O5XGOB.js');
4933
- const { start, RunnerStartError } = await import('./loop-F5ASKFRJ.js');
4932
+ const { containerStart } = await import('./container-start-7WLZMPEI.js');
4933
+ const { start, RunnerStartError } = await import('./loop-QDV7T65M.js');
4934
4934
  const { RunnerAlreadyRunningError } = await import('./pidfile-CYCTH6NQ.js');
4935
4935
  try {
4936
4936
  const result = await containerStart({
@@ -4950,7 +4950,7 @@ function registerRunnerCommands(program2) {
4950
4950
  });
4951
4951
  runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
4952
4952
  const { defaultRunnerConfigPath } = await import('./config-5QYIKYUP.js');
4953
- const { runRunnerCheck } = await import('./check-NDDOASVO.js');
4953
+ const { runRunnerCheck } = await import('./check-YEI6TCUH.js');
4954
4954
  const configPath = opts.config ?? defaultRunnerConfigPath();
4955
4955
  const result = await runRunnerCheck(configPath);
4956
4956
  if (!result.ok) {
@@ -4984,7 +4984,7 @@ function registerRunnerCommands(program2) {
4984
4984
  }
4985
4985
  try {
4986
4986
  if (opts.service === true) {
4987
- const { installServiceCommand } = await import('./command-3F6GY4CK.js');
4987
+ const { installServiceCommand } = await import('./command-PY3C2E4B.js');
4988
4988
  const result2 = await installServiceCommand({
4989
4989
  configPath,
4990
4990
  print: opts.print,
@@ -5040,7 +5040,7 @@ To keep it running, run ${C.yellow}${cliInvocation()} runner install --service${
5040
5040
  return;
5041
5041
  }
5042
5042
  const { defaultRunnerConfigPath } = await import('./config-5QYIKYUP.js');
5043
- const { uninstallServiceCommand } = await import('./command-3F6GY4CK.js');
5043
+ const { uninstallServiceCommand } = await import('./command-PY3C2E4B.js');
5044
5044
  const result = await uninstallServiceCommand({ configPath: opts.config ?? defaultRunnerConfigPath(), unitName: opts.unitName, home: homeFromEnv() });
5045
5045
  if (result.ok) for (const line of result.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
5046
5046
  `);
@@ -5068,10 +5068,10 @@ already in claude.env is used.
5068
5068
  `
5069
5069
  ).action(async (opts) => {
5070
5070
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-5QYIKYUP.js');
5071
- const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-HHEAJDPN.js');
5072
- const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-Y76QXVNV.js');
5073
- const { detectMachine } = await import('./machine-6STGIRJJ.js');
5074
- const { chooseVm, runVmInit, VmInitError } = await import('./init-36XMFFRQ.js');
5071
+ const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-5LHTF72R.js');
5072
+ const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-M4N2BY5A.js');
5073
+ const { detectMachine } = await import('./machine-PLNSGKNF.js');
5074
+ const { chooseVm, runVmInit, VmInitError } = await import('./init-BTH5YPBC.js');
5075
5075
  const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-EIB6WFPG.js');
5076
5076
  const configPath = opts.config ?? defaultRunnerConfigPath();
5077
5077
  if (opts.agent !== void 0 && !isAgentName(opts.agent)) {
@@ -5222,7 +5222,7 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
5222
5222
  let serviceUp = false;
5223
5223
  let restart;
5224
5224
  if (installedLayout) {
5225
- const { installServiceCommand } = await import('./command-3F6GY4CK.js');
5225
+ const { installServiceCommand } = await import('./command-PY3C2E4B.js');
5226
5226
  const service = await installServiceCommand({
5227
5227
  configPath,
5228
5228
  entryPath: process.argv[1] ?? "",
@@ -5350,7 +5350,7 @@ Next:
5350
5350
  });
5351
5351
  runnerCmd.command("stop").description("Take no more work; finish running jobs, then exit").option("--config <path>", "the cloud config file naming the runner to stop").option("--now", "end running jobs immediately, with outcome stopped").action(async (opts) => {
5352
5352
  const { defaultRunnerConfigPath } = await import('./config-5QYIKYUP.js');
5353
- const { requestStop } = await import('./loop-F5ASKFRJ.js');
5353
+ const { requestStop } = await import('./loop-QDV7T65M.js');
5354
5354
  const configPath = opts.config ?? defaultRunnerConfigPath();
5355
5355
  const { runnerImageVersion } = await import('./image-tag-SS7YKJHN.js');
5356
5356
  await requestStop(configPath, Boolean(opts.now), void 0, { image: runnerImageVersion() !== void 0 });
@@ -5358,8 +5358,8 @@ Next:
5358
5358
  runnerCmd.command("status").description("List running jobs; with --recent, finished ones too").option("--config <path>", "the cloud config file naming the runner to inspect").option("--recent", "also list finished jobs, newest first, capped at 20").option("--json", "machine-readable JSON output").action(async (opts) => {
5359
5359
  const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-5QYIKYUP.js');
5360
5360
  const { jobsDir, runnerDir } = await import('./paths-32DWGK35.js');
5361
- const { listJobFiles, runnerProcessState } = await import('./loop-F5ASKFRJ.js');
5362
- const { renderStatus } = await import('./status-OANG2EM3.js');
5361
+ const { listJobFiles, runnerProcessState } = await import('./loop-QDV7T65M.js');
5362
+ const { renderStatus } = await import('./status-PWMPP4ES.js');
5363
5363
  const { readHousekeepingRecord } = await import('./record-N4WPZCGK.js');
5364
5364
  const path2 = await import('path');
5365
5365
  const configPath = opts.config ?? defaultRunnerConfigPath();
@@ -5419,7 +5419,7 @@ Next:
5419
5419
  });
5420
5420
  runnerCmd.command("logs").argument("<item>", "the work item's number in the factory").description("Print the newest attempt's log for one item").option("--config <path>", "the cloud config file naming the runner to inspect").option("-f, --follow", "keep printing as the log grows").action(async (itemArg, opts) => {
5421
5421
  const { defaultRunnerConfigPath } = await import('./config-5QYIKYUP.js');
5422
- const { listJobFiles } = await import('./loop-F5ASKFRJ.js');
5422
+ const { listJobFiles } = await import('./loop-QDV7T65M.js');
5423
5423
  const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-X2IRDP5T.js');
5424
5424
  const configPath = opts.config ?? defaultRunnerConfigPath();
5425
5425
  const item = parseTrackerNumber(itemArg);
@@ -3,8 +3,8 @@ import { createRequire } from 'node:module';
3
3
  import { runRunnerInstall, launcherSummary, restartNote } from './chunk-ATJOFXTE.js';
4
4
  import './chunk-CTYSTE5C.js';
5
5
  import { currentLink, execStartCommand } from './chunk-GUXWQIEY.js';
6
- import { detectMachine } from './chunk-T57XUI6N.js';
7
- import { helperSocketPath, ensureFirecrackerAndJailer } from './chunk-IKXY47R5.js';
6
+ import { detectMachine } from './chunk-HOB7Z4JQ.js';
7
+ import { helperSocketPath, ensureFirecrackerAndJailer } from './chunk-GLL4TN2M.js';
8
8
  import './chunk-MHAR6S7B.js';
9
9
  import './chunk-WWQVKFN6.js';
10
10
  import './chunk-USJZ2LDK.js';
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RunnerInitError, prepareRunnerInit, writeRunnerInit } from './chunk-R7SS5RLJ.js';
4
- import { detectMachine, supportsContainerBuilds, describeMachineDocker } from './chunk-T57XUI6N.js';
5
- import { MIN_ENGINE_MAJOR } from './chunk-IKXY47R5.js';
3
+ import { RunnerInitError, prepareRunnerInit, writeRunnerInit } from './chunk-MNHMUZGC.js';
4
+ import { detectMachine, supportsContainerBuilds, describeMachineDocker } from './chunk-HOB7Z4JQ.js';
5
+ import { MIN_ENGINE_MAJOR } from './chunk-GLL4TN2M.js';
6
6
  import './chunk-MHAR6S7B.js';
7
7
  import './chunk-WWQVKFN6.js';
8
8
  import './chunk-USJZ2LDK.js';
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { launcherCheck } from './chunk-CTYSTE5C.js';
4
- import { needsClaudeCredential, claudeCredentialCheck, missingPermissionOf, missingPermissionFix } from './chunk-W3FSGH2M.js';
4
+ import { needsClaudeCredential, claudeCredentialCheck, missingPermissionOf, missingPermissionFix } from './chunk-6S4V4UIC.js';
5
5
  import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
6
6
  import './chunk-GUXWQIEY.js';
7
7
  import { RepoFilter } from './chunk-TBT347UY.js';
8
- import './chunk-R7SS5RLJ.js';
9
- import { detectMachine, supportsContainerBuilds, describeMachineDocker, reachDockerStep, supportsMicroVmBuilds, microVmArchSupported, microVmAssetsPinned } from './chunk-T57XUI6N.js';
10
- import { MIN_ENGINE_MAJOR, helperFirecrackerNote, probeHelper, helperSocketPath } from './chunk-IKXY47R5.js';
8
+ import './chunk-MNHMUZGC.js';
9
+ import { detectMachine, supportsContainerBuilds, describeMachineDocker, reachDockerStep, supportsMicroVmBuilds, microVmArchSupported, microVmAssetsPinned } from './chunk-HOB7Z4JQ.js';
10
+ import { MIN_ENGINE_MAJOR, helperFirecrackerNote, probeHelper, helperSocketPath } from './chunk-GLL4TN2M.js';
11
11
  import './chunk-MHAR6S7B.js';
12
12
  import './chunk-WWQVKFN6.js';
13
13
  import './chunk-USJZ2LDK.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { staleBuildRefusal, staleBuildWarning, detectCi } from './chunk-2YSCKEL2.js';
3
+ import { staleBuildRefusal, staleBuildWarning, detectCi } from './chunk-MKIC65SD.js';
4
4
  import './chunk-TVZAC2NP.js';
5
5
  import { launchRefusalForSession } from './chunk-ESVW4MJY.js';
6
6
  import './chunk-TBT347UY.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { detectCi } from './chunk-2YSCKEL2.js';
3
+ import { detectCi } from './chunk-MKIC65SD.js';
4
4
  import './chunk-TVZAC2NP.js';
5
5
  import { launchRefusalForSession } from './chunk-ESVW4MJY.js';
6
6
  import './chunk-TBT347UY.js';
package/dist/index.js CHANGED
@@ -26,5 +26,5 @@ if (argv[0] === "claude") {
26
26
  process.exit(await runClaudeLauncher(argv.slice(1)));
27
27
  }
28
28
  (await import('./hook-fast-EFC44SXV.js')).recordLinkExitFailure(argv);
29
- var { runCli } = await import('./cli-QC6ZKHPK.js');
29
+ var { runCli } = await import('./cli-SCTKM2Y5.js');
30
30
  await runCli(process.argv);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { PLACEHOLDER_MARKER, RunnerInitError, isPlaceholderCommand, prepareRunnerInit, readConfigObject, runRunnerInit, writeRunnerInit } from './chunk-R7SS5RLJ.js';
4
- import './chunk-T57XUI6N.js';
5
- import './chunk-IKXY47R5.js';
3
+ export { PLACEHOLDER_MARKER, RunnerInitError, isPlaceholderCommand, prepareRunnerInit, readConfigObject, runRunnerInit, writeRunnerInit } from './chunk-MNHMUZGC.js';
4
+ import './chunk-HOB7Z4JQ.js';
5
+ import './chunk-GLL4TN2M.js';
6
6
  import './chunk-MHAR6S7B.js';
7
7
  import './chunk-WWQVKFN6.js';
8
8
  import './chunk-USJZ2LDK.js';
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { npmSupportsProvenance } from './chunk-E7R2GIAW.js';
4
- import { RunnerInitError, readConfigObject } from './chunk-R7SS5RLJ.js';
5
- import './chunk-T57XUI6N.js';
6
- import './chunk-IKXY47R5.js';
4
+ import { RunnerInitError, readConfigObject } from './chunk-MNHMUZGC.js';
5
+ import './chunk-HOB7Z4JQ.js';
6
+ import './chunk-GLL4TN2M.js';
7
7
  import './chunk-MHAR6S7B.js';
8
8
  import './chunk-WWQVKFN6.js';
9
9
  import './chunk-USJZ2LDK.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { summarizeChecks, summaryText, renderDoctorText } from './chunk-6BWJQGTV.js';
3
+ import { summarizeChecks, summaryText, renderDoctorText } from './chunk-25X2PJDI.js';
4
4
  import './chunk-ITAIEJ2T.js';
5
5
  import { shellFunctionInstalled, removeShellFunction, installShellFunction, SHELL_FUNCTION_LINE } from './chunk-CJJDJ7AT.js';
6
6
  import './chunk-QBQHQEUG.js';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, start, tick, watchTick } from './chunk-7UGFIWIW.js';
4
- import './chunk-KVDVNOUK.js';
3
+ export { RunnerStartError, leaseTimeLeftFor, listJobFiles, logUnusableHelper, probeBuild, probeCredentials, requestStop, runnerProcessState, runtimeOf, start, tick, watchTick } from './chunk-O65LES4V.js';
4
+ import './chunk-KU7QL4XW.js';
5
5
  import './chunk-3JVYMD4G.js';
6
6
  import './chunk-E7R2GIAW.js';
7
7
  import './chunk-TPKYTORP.js';
@@ -9,18 +9,18 @@ import './chunk-IVX3U7KV.js';
9
9
  import './chunk-ZVB57WI6.js';
10
10
  import './chunk-66T6XJAB.js';
11
11
  import './chunk-N7WAEEIU.js';
12
- import './chunk-QWAYRAUX.js';
13
- import './chunk-2YSCKEL2.js';
12
+ import './chunk-SFJXGISY.js';
13
+ import './chunk-MKIC65SD.js';
14
14
  import './chunk-TVZAC2NP.js';
15
15
  import './chunk-ESVW4MJY.js';
16
16
  import './chunk-ZTY7HHYB.js';
17
- import './chunk-W3FSGH2M.js';
17
+ import './chunk-6S4V4UIC.js';
18
18
  import './chunk-YYYRBYWG.js';
19
19
  import './chunk-GUXWQIEY.js';
20
20
  import './chunk-TBT347UY.js';
21
- import './chunk-R7SS5RLJ.js';
22
- import './chunk-T57XUI6N.js';
23
- import './chunk-IKXY47R5.js';
21
+ import './chunk-MNHMUZGC.js';
22
+ import './chunk-HOB7Z4JQ.js';
23
+ import './chunk-GLL4TN2M.js';
24
24
  import './chunk-MHAR6S7B.js';
25
25
  import './chunk-WWQVKFN6.js';
26
26
  import './chunk-USJZ2LDK.js';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { describeMachineDocker, detectMachine, microVmArchSupported, microVmAssetsPinned, reachDockerStep, supportsContainerBuilds, supportsMicroVmBuilds } from './chunk-T57XUI6N.js';
4
- import './chunk-IKXY47R5.js';
3
+ export { describeMachineDocker, detectMachine, microVmArchSupported, microVmAssetsPinned, reachDockerStep, supportsContainerBuilds, supportsMicroVmBuilds } from './chunk-HOB7Z4JQ.js';
4
+ import './chunk-GLL4TN2M.js';
5
5
  import './chunk-MHAR6S7B.js';
6
6
  import './chunk-WWQVKFN6.js';
7
7
  import './chunk-USJZ2LDK.js';
@@ -20,7 +20,7 @@ async function startRelay(opts) {
20
20
  }
21
21
  async function listenRelay(port, socketPath) {
22
22
  const open = /* @__PURE__ */ new Set();
23
- const server = createServer((client) => {
23
+ const server = createServer({ allowHalfOpen: true }, (client) => {
24
24
  const upstream = connect(socketPath);
25
25
  open.add(client);
26
26
  client.on("error", () => void 0);
@@ -29,7 +29,9 @@ async function listenRelay(port, socketPath) {
29
29
  open.delete(client);
30
30
  upstream.destroy();
31
31
  });
32
- upstream.on("close", () => client.destroy());
32
+ upstream.on("close", (hadError) => {
33
+ if (hadError) client.resetAndDestroy();
34
+ });
33
35
  client.pipe(upstream);
34
36
  upstream.pipe(client);
35
37
  });
@@ -99,9 +101,11 @@ async function startSessionRelay(opts) {
99
101
  }
100
102
  stream.on("error", noop);
101
103
  stream.on("response", noop);
102
- stream.on("close", () => client.destroy());
104
+ stream.on("close", () => {
105
+ if (!stream.readableEnded) client.resetAndDestroy();
106
+ });
103
107
  client.on("close", () => {
104
- if (!stream.destroyed) stream.close(http2.constants.NGHTTP2_CANCEL);
108
+ if (!stream.destroyed && !client.readableEnded) stream.close(http2.constants.NGHTTP2_CANCEL);
105
109
  });
106
110
  client.pipe(stream);
107
111
  stream.pipe(client);
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { readConfigObject, RunnerInitError } from './chunk-R7SS5RLJ.js';
4
- import './chunk-T57XUI6N.js';
5
- import './chunk-IKXY47R5.js';
3
+ import { readConfigObject, RunnerInitError } from './chunk-MNHMUZGC.js';
4
+ import './chunk-HOB7Z4JQ.js';
5
+ import './chunk-GLL4TN2M.js';
6
6
  import './chunk-MHAR6S7B.js';
7
7
  import './chunk-WWQVKFN6.js';
8
8
  import './chunk-USJZ2LDK.js';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { runSessionSender, senderPidfile, startSessionSender } from './chunk-QWAYRAUX.js';
4
- import './chunk-2YSCKEL2.js';
3
+ export { runSessionSender, senderPidfile, startSessionSender } from './chunk-SFJXGISY.js';
4
+ import './chunk-MKIC65SD.js';
5
5
  import './chunk-TVZAC2NP.js';
6
6
  import './chunk-ESVW4MJY.js';
7
7
  import './chunk-TBT347UY.js';
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isReadable, ALREADY_RELEASED, RENEW_INTERVAL_SECONDS } from './chunk-KVDVNOUK.js';
3
+ import { isReadable, ALREADY_RELEASED, RENEW_INTERVAL_SECONDS } from './chunk-KU7QL4XW.js';
4
4
  import { jobStateFormatOf } from './chunk-ZVB57WI6.js';
5
5
  import './chunk-N7WAEEIU.js';
6
- import './chunk-QWAYRAUX.js';
7
- import './chunk-2YSCKEL2.js';
6
+ import './chunk-SFJXGISY.js';
7
+ import './chunk-MKIC65SD.js';
8
8
  import './chunk-TVZAC2NP.js';
9
9
  import './chunk-ESVW4MJY.js';
10
10
  import './chunk-ZTY7HHYB.js';
11
11
  import { formatBytes } from './chunk-YYYRBYWG.js';
12
12
  import './chunk-TBT347UY.js';
13
- import { LEASE_SECONDS } from './chunk-IKXY47R5.js';
13
+ import { LEASE_SECONDS } from './chunk-GLL4TN2M.js';
14
14
  import './chunk-MHAR6S7B.js';
15
15
  import './chunk-WWQVKFN6.js';
16
16
  import { formatDuration, formatClock, relativeToRunner } from './chunk-USJZ2LDK.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { CHUNK_PART_TARGET_BYTES, RETRYABLE_STATUSES, SyncConfigError, SyncTransportError, detectCi, isLoopbackUrl, resolveTier, runSync } from './chunk-2YSCKEL2.js';
3
+ export { CHUNK_PART_TARGET_BYTES, RETRYABLE_STATUSES, SyncConfigError, SyncTransportError, detectCi, isLoopbackUrl, resolveTier, runSync } from './chunk-MKIC65SD.js';
4
4
  import './chunk-TVZAC2NP.js';
5
5
  import './chunk-ESVW4MJY.js';
6
6
  import './chunk-TBT347UY.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LiveUploader } from './chunk-2YSCKEL2.js';
3
+ import { LiveUploader } from './chunk-MKIC65SD.js';
4
4
  import './chunk-TVZAC2NP.js';
5
5
  import './chunk-ESVW4MJY.js';
6
6
  import './chunk-TBT347UY.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outerlayer/cli",
3
- "version": "0.28.1",
3
+ "version": "0.28.2",
4
4
  "description": "OuterLayer CLI — commands: init, claude, connect, doctor, login, logout, sync, daemon (alias: watch), emit, work, spec, runner, hooks, mcp, context. Capture and sync coding-agent sessions, and record proof of factory work.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Magu Studios, Inc.",