@outerlayer/cli 0.5.1 → 0.6.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 (65) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +9 -0
  3. package/dist/{agent-setup-IFH3FB5X.js → agent-setup-USZ2SAXC.js} +2 -2
  4. package/dist/build-info.json +1 -1
  5. package/dist/{check-4Q33B5ZE.js → check-CCVPBN7A.js} +24 -14
  6. package/dist/{chunk-WOBNRVQT.js → chunk-3DEVYTNQ.js} +1 -1
  7. package/dist/{chunk-F4NU4H3V.js → chunk-43J3M6KB.js} +95 -11
  8. package/dist/{chunk-W7UTFZDH.js → chunk-4NLKY4WR.js} +2 -2
  9. package/dist/{lima-XN65D7GN.js → chunk-77MM5RYD.js} +0 -1
  10. package/dist/{chunk-D2KWEAN6.js → chunk-7DBI6SNT.js} +1 -1
  11. package/dist/{chunk-ZXBITXTS.js → chunk-AIW6GLET.js} +1 -1
  12. package/dist/{chunk-EX6M5JPR.js → chunk-ANK2B36Y.js} +131 -15
  13. package/dist/{chunk-RMAZ2NWA.js → chunk-BNMCXPG7.js} +14 -2
  14. package/dist/{chunk-UFFXNXLQ.js → chunk-FA2BOX4O.js} +31 -29
  15. package/dist/chunk-FBTE2A2X.js +38 -0
  16. package/dist/{chunk-DVDEBNQJ.js → chunk-GQD22KKN.js} +17 -6
  17. package/dist/{chunk-BCJNHMZT.js → chunk-HHJDN6AU.js} +18 -3
  18. package/dist/{chunk-JLDZTG3A.js → chunk-IASWYRVG.js} +1 -1
  19. package/dist/{install-cmd-7WXOIFDO.js → chunk-JWOQNNN2.js} +0 -1
  20. package/dist/{chunk-H4CK2YK4.js → chunk-MIGEDH5P.js} +16 -8
  21. package/dist/{chunk-CHLVJNTE.js → chunk-MXB5VB4Y.js} +17 -5
  22. package/dist/chunk-NQXFAGHU.js +211 -0
  23. package/dist/chunk-OUUINEYB.js +27 -0
  24. package/dist/{chunk-OR6AEEDO.js → chunk-PMAMOSTP.js} +3 -3
  25. package/dist/{chunk-RTXKYLCA.js → chunk-RBOMWNOG.js} +1 -1
  26. package/dist/{chunk-T52PKE2Y.js → chunk-RZSF5B46.js} +149 -7
  27. package/dist/chunk-T6OIJQRT.js +31 -0
  28. package/dist/{chunk-EGABNHZG.js → chunk-UMFWVGJO.js} +148 -18
  29. package/dist/{chunk-UWH5DSUP.js → chunk-VMJ3MMBX.js} +203 -80
  30. package/dist/chunk-ZILGTTY6.js +75 -0
  31. package/dist/{cli-LHSUYYMI.js → cli-7WCNPBYC.js} +134 -61
  32. package/dist/command-ARFK3OYF.js +162 -0
  33. package/dist/{connect-cmd-OJBFHZWP.js → connect-cmd-PCESZLTR.js} +4 -4
  34. package/dist/{context-adopt-UMA4O5NY.js → context-adopt-G5JAELE7.js} +2 -2
  35. package/dist/{context-materialize-G2FUFC72.js → context-materialize-3HLPZAF6.js} +2 -2
  36. package/dist/{dist-WDV7U7UJ.js → dist-RDLP4GGJ.js} +1 -1
  37. package/dist/{doctor-MOA3RIEP.js → doctor-VOMYOHQU.js} +32 -12
  38. package/dist/{emit-artifact-cmd-FDWYKURA.js → emit-artifact-cmd-TBF46VXZ.js} +6 -7
  39. package/dist/{emit-criteria-cmd-OCXHLK34.js → emit-criteria-cmd-3427XKFW.js} +3 -3
  40. package/dist/{emit-finding-cmd-POW7PKIA.js → emit-finding-cmd-GSI75K36.js} +3 -3
  41. package/dist/{emit-result-cmd-ID35SH53.js → emit-result-cmd-3PRQKB55.js} +6 -7
  42. package/dist/{hook-fast-EYENPK6F.js → hook-fast-NJBBZQ5Q.js} +1 -1
  43. package/dist/index.js +3 -2
  44. package/dist/{init-2IPOIXJV.js → init-OHYFIKZD.js} +26 -55
  45. package/dist/{init-FYDJAKTM.js → init-WVR4BZQ4.js} +8 -8
  46. package/dist/{init-cmd-KLIDRVXQ.js → init-cmd-HMFNIFPI.js} +7 -7
  47. package/dist/inspect-XAUSB7L3.js +63 -0
  48. package/dist/install-DSUZE2TJ.js +13 -0
  49. package/dist/install-cmd-453C7IZT.js +8 -0
  50. package/dist/lima-7NPCNGWT.js +6 -0
  51. package/dist/{loop-NEBUGD2Q.js → loop-UAJB34KA.js} +24 -11
  52. package/dist/{machine-ECU3QCZD.js → machine-2JOWGRSZ.js} +7 -7
  53. package/dist/session-sender-ED26V45B.js +28 -0
  54. package/dist/{status-CLATHCTQ.js → status-6WNXX2O7.js} +22 -8
  55. package/dist/{sync-cmd-SWQ5KLPL.js → sync-cmd-YONVGUYS.js} +6 -7
  56. package/dist/{watch-3YW6Z3DQ.js → watch-HHKAF26L.js} +6 -7
  57. package/dist/{work-claim-cmd-3OPWA77E.js → work-claim-cmd-LXBZTMJA.js} +5 -5
  58. package/dist/{work-cmd-NUR4CAG6.js → work-cmd-OVNF44FY.js} +3 -3
  59. package/dist/{work-comment-cmd-6TTTYGHM.js → work-comment-cmd-6DGQNTAH.js} +3 -3
  60. package/dist/{work-launch-YI4CJDAP.js → work-launch-R5HTAP6X.js} +1 -1
  61. package/dist/{work-open-pr-cmd-KZ7QQFLD.js → work-open-pr-cmd-FCZHFHZS.js} +4 -4
  62. package/dist/{work-pr-cmd-QNUBE6IQ.js → work-pr-cmd-QJJVHZDC.js} +2 -2
  63. package/package.json +2 -1
  64. package/dist/chunk-ZOC7JSYC.js +0 -83
  65. package/dist/{chunk-XDDW4FRS.js → chunk-OIRNH6UO.js} +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @outerlayer/cli
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - cb41102: A runner build's agent session now appears on its work item, with its running cost, while the build runs. The runner starts a hidden `session-sender` command beside each build's command, in a microVM, a container, a host `exec` hook or on the host. The end-of-attempt sync stays the complete upload. The capture daemon gains a watch-only mode that reports changed transcripts without copying them.
8
+ - 21b7405: `outerlayer runner init` now sets the runner up to keep running on Linux, macOS and Windows (WSL2), with the same commands on each: `runner install --service` (with `--print`, `--user` and `--replace`) writes, enables and starts one systemd unit, and `runner uninstall --service` removes it. Each microVM build runs in a cgroup of its own with a memory limit of `build.memory` plus 256 MiB, and a build the kernel kills for want of memory ends `failed` with a reason that says so, without stopping the runner or the other builds. Setup refuses builds that cannot fit in memory together. The runner claims nothing, and says why in its heartbeat as `blocked`, when it cannot open `/dev/kvm`, has no Claude credential, still has the placeholder command, or has builds that do not fit in memory. `outerlayer doctor` now reports the running service's groups and credential instead of your shell's. The runner now reports protocol 14 to its gateway.
9
+
10
+ ### Patch Changes
11
+
12
+ - 573abaa: A session link that worked no longer leaves a Node warning in `~/.outerlayer/spool/hook-errors.log`. Only links that fail are logged, with one line naming the item.
13
+
3
14
  ## 0.5.1
4
15
 
5
16
  ### Patch Changes
package/README.md CHANGED
@@ -56,6 +56,15 @@ send, so turning it off takes effect without restarting the daemon.
56
56
  authoritative upload — the daemon exists so a session's page can follow
57
57
  along before that sync ever runs.
58
58
 
59
+ **`outerlayer session-sender` is started only by a runner, inside each build,
60
+ and streams that build's sessions to its work item while the build runs.** It
61
+ sends under the build's own item key to the build's own gateway, both taken
62
+ from the job's environment and never from your config file, and only sessions
63
+ the build itself launched. It sends no session that belongs to anyone else on
64
+ the machine, and your own `outerlayer daemon` skips sessions launched inside a
65
+ runner build. The runner stops it before the build's final `outerlayer sync`,
66
+ which remains the complete upload.
67
+
59
68
  These commands also talk to your workspace. None of them sends session
60
69
  content:
61
70
 
@@ -4,11 +4,11 @@ import { installStarterPack } from './chunk-ZMYPLFG3.js';
4
4
  import { runEmit } from './chunk-H5NCNVDA.js';
5
5
  import { addStdioMcpEntryIfAbsent } from './chunk-MQ3IPHIZ.js';
6
6
  import { C } from './chunk-YRYMNBGQ.js';
7
- import { resolveGitCommonDir, defaultGitRunner } from './chunk-XDDW4FRS.js';
7
+ import { resolveGitCommonDir, defaultGitRunner } from './chunk-OIRNH6UO.js';
8
+ import './chunk-ZJSNLVCE.js';
8
9
  import { pinExists, readContextManifest } from './chunk-WIOZAJ2W.js';
9
10
  import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-WO2BXCTQ.js';
10
11
  import { generatedHeaderSource } from './chunk-EMY4I27X.js';
11
- import './chunk-ZJSNLVCE.js';
12
12
  import './chunk-BCLJSQCV.js';
13
13
  import './chunk-BOLTI6LR.js';
14
14
  import './chunk-EABW6AJQ.js';
@@ -1 +1 @@
1
- {"id":"2026-10-04T00:10:45.902Z+d37533c","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
1
+ {"id":"2026-10-04T12:35:01.048Z+a19ef31","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
@@ -1,19 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { probeCredentials } from './chunk-F4NU4H3V.js';
4
- import './chunk-UWH5DSUP.js';
5
- import './chunk-ZXBITXTS.js';
6
- import './chunk-UGP76IZ5.js';
3
+ import { probeCredentials } from './chunk-43J3M6KB.js';
7
4
  import './chunk-ABIWDUMS.js';
8
5
  import './chunk-YYYXRJUW.js';
6
+ import './chunk-VMJ3MMBX.js';
7
+ import './chunk-T6OIJQRT.js';
8
+ import './chunk-AIW6GLET.js';
9
+ import './chunk-UGP76IZ5.js';
10
+ import './chunk-ZILGTTY6.js';
9
11
  import './chunk-CBPPJSAR.js';
10
- import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-CHLVJNTE.js';
12
+ import './chunk-UMFWVGJO.js';
13
+ import './chunk-HHJDN6AU.js';
14
+ import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-MXB5VB4Y.js';
11
15
  import './chunk-YYYRBYWG.js';
12
- import './chunk-ZOC7JSYC.js';
13
16
  import './chunk-TBT347UY.js';
14
- import './chunk-W7UTFZDH.js';
15
- import './chunk-RTXKYLCA.js';
16
- import './chunk-T52PKE2Y.js';
17
+ import './chunk-OUUINEYB.js';
18
+ import './chunk-4NLKY4WR.js';
19
+ import './chunk-RBOMWNOG.js';
20
+ import './chunk-RZSF5B46.js';
17
21
  import './chunk-Z62HNKEJ.js';
18
22
  import './chunk-N5FOE5PS.js';
19
23
  import './chunk-OGFGZQA3.js';
@@ -21,25 +25,31 @@ import './chunk-774HEQL6.js';
21
25
  import './chunk-QOZKPLVJ.js';
22
26
  import './chunk-W4SQCOZU.js';
23
27
  import './chunk-B2G7JHHB.js';
24
- import './chunk-RMAZ2NWA.js';
28
+ import './chunk-F7CU5ABH.js';
29
+ import './chunk-BKO6JEZI.js';
30
+ import './chunk-BNMCXPG7.js';
25
31
  import './chunk-BFESLKPP.js';
26
- import './chunk-WOBNRVQT.js';
27
- import './chunk-EX6M5JPR.js';
32
+ import './chunk-3DEVYTNQ.js';
33
+ import './chunk-ANK2B36Y.js';
34
+ import './chunk-YRYMNBGQ.js';
28
35
  import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-3DD6AOWC.js';
29
36
  import './chunk-F6GFZXZ3.js';
30
37
  import './chunk-AUFG23AA.js';
38
+ import './chunk-GQD22KKN.js';
31
39
  import './chunk-WZBHBH3J.js';
32
- import './chunk-XDDW4FRS.js';
40
+ import './chunk-5QRP3MVS.js';
41
+ import './chunk-OIRNH6UO.js';
42
+ import './chunk-ZJSNLVCE.js';
33
43
  import './chunk-WIOZAJ2W.js';
34
44
  import './chunk-WO2BXCTQ.js';
35
45
  import './chunk-EMY4I27X.js';
36
- import './chunk-ZJSNLVCE.js';
37
46
  import './chunk-BCLJSQCV.js';
38
47
  import './chunk-BOLTI6LR.js';
39
48
  import './chunk-EABW6AJQ.js';
40
49
  import './chunk-RA3O54FC.js';
41
50
  import './chunk-M5POMKKW.js';
42
51
  import './chunk-ZM2IMMYN.js';
52
+ import './chunk-FA2BOX4O.js';
43
53
  import './chunk-XCCLFVXM.js';
44
54
  import './chunk-BJ3KTMDH.js';
45
55
  import './chunk-VNVZDWO3.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { ArtifactTombstoneRecordSchema, ArtifactSpoolRecordSchema } from './chunk-EX6M5JPR.js';
3
+ import { ArtifactTombstoneRecordSchema, ArtifactSpoolRecordSchema } from './chunk-ANK2B36Y.js';
4
4
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
5
5
  import { mkdirSync, appendFileSync, writeFileSync, renameSync, existsSync, unlinkSync, readdirSync, readFileSync } from 'fs';
6
6
  import { join, dirname } from 'path';
@@ -1,33 +1,78 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LEASE_SECONDS, releaseLease, isUnfinished, writeJobFile, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, readJobFile, hookLimitsFor, readJobFileChecked, ALREADY_RELEASED } from './chunk-UWH5DSUP.js';
4
- import { RUNNER_PROTOCOL } from './chunk-ZXBITXTS.js';
5
- import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
6
3
  import { fetchVersionMeta, npmVersion, npmSupportsProvenance, fetchTarballDigest, fetchProvenance, installVersion, auditSignatures } from './chunk-ABIWDUMS.js';
7
4
  import { readMarker, currentVersion, removeMarker, writeMarker, entryIn, versionDir, switchCurrent, cleanVersions, isInLayout, startedThroughCurrent, stagingDir } from './chunk-YYYXRJUW.js';
5
+ import { LEASE_SECONDS, releaseLease, isUnfinished, setStage, jobEnv, runHook, describeHookEnd, provisionMicroVm, deliverCommitHooks, provisionProcess, provisionEnvironment, readProvisionOut, resolveHostBuild, workdirProblem, listenOnBroker, hostEnvironment, hostCommandEnvironment, execArgv, microVmCommandLine, runCommand, execCommandLine, startSender, startHostServices, finishJob, isGroupAlive, outcomeFromExitCode, needsRenew, renewLease, RENEW_INTERVAL_SECONDS, isTimedOut, readCpuUsec, isIdle, stopOrphanedMicroVms, unfinishedJobs, listAdoptableJobs, retryFailedReleases, recoverLostJobs, hookLimitsFor, ALREADY_RELEASED } from './chunk-VMJ3MMBX.js';
6
+ import { writeJobFile, readJobFile, readJobFileChecked } from './chunk-T6OIJQRT.js';
7
+ import { RUNNER_PROTOCOL } from './chunk-AIW6GLET.js';
8
+ import { readHousekeepingRecord, writeHousekeepingRecord } from './chunk-UGP76IZ5.js';
9
+ import { placeholderQueues, placeholderProblem } from './chunk-MXB5VB4Y.js';
8
10
  import { freeBytes, formatBytes } from './chunk-YYYRBYWG.js';
9
11
  import { RepoFilter } from './chunk-TBT347UY.js';
10
- import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, formatClock, measureDisk, createRunnerLog, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, runnerLabelValue, BUILD_LABEL, RUNNER_LABEL } from './chunk-T52PKE2Y.js';
12
+ import { checkFit } from './chunk-OUUINEYB.js';
13
+ import { describeCallFailure, retrySend, shortClaim, relativeToRunner, formatDuration, provisionContainer, lifecycleSteps, lifecycleFailureReason, prepareBranch, containerCommandLine, BuildTokens, classifyRefusal, refusalCode, formatClock, measureDisk, createRunnerLog, setUpRunnerCgroup, ensureTunnel, keepGhConfigCurrent, createContainerRuntime, runnerLabelValue, BUILD_LABEL, RUNNER_LABEL } from './chunk-RZSF5B46.js';
11
14
  import { startTimeOf, claimPidFile, readPidFile, isSameProcess, releasePidFile } from './chunk-N5FOE5PS.js';
12
15
  import { spawnRun } from './chunk-774HEQL6.js';
13
- import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-RMAZ2NWA.js';
16
+ import { isSignatureRefusal, WorkCommandError, getJson, postJson } from './chunk-BNMCXPG7.js';
14
17
  import { isBuiltinContainer, isBuiltinVm, isBuiltinProcess, loadRunnerConfig, checkHooks, builtinKind } from './chunk-3DD6AOWC.js';
15
18
  import { exceedsDisk } from './chunk-F6GFZXZ3.js';
16
- import { parseClaimIdentity, sharedUserEnvironment, JOB_MOUNT } from './chunk-AUFG23AA.js';
19
+ import { parseClaimIdentity, sharedUserEnvironment, JOB_MOUNT, claudeCredential } from './chunk-AUFG23AA.js';
17
20
  import { resolveVersion } from './chunk-RA3O54FC.js';
18
21
  import { loadHostKey, ensureHostKey, signerFor } from './chunk-M5POMKKW.js';
19
22
  import { RUNNER_DIR_MODE, runnerDir, buildDir, attemptStamp, jobDir, jobsDir, pidFilePath, spoolDir, RUNNER_FILE_MODE, rootfsDir } from './chunk-ZM2IMMYN.js';
20
23
  import { HOOKS_DIR_NAME, writeCommitHooks } from './chunk-XCCLFVXM.js';
21
24
  import { randomBytes } from 'crypto';
22
- import { mkdirSync, existsSync, chmodSync, statSync, readdirSync, readFileSync, rmSync, renameSync, writeFileSync, lstatSync } from 'fs';
25
+ import { mkdirSync, existsSync, chmodSync, statSync, readdirSync, readFileSync, rmSync, renameSync, writeFileSync, closeSync, openSync, constants, lstatSync } from 'fs';
23
26
  import { join, dirname } from 'path';
27
+ import { totalmem } from 'os';
24
28
 
25
29
  createRequire(import.meta.url);
30
+ function openKvm() {
31
+ try {
32
+ closeSync(openSync("/dev/kvm", constants.O_RDWR));
33
+ return "usable";
34
+ } catch (err) {
35
+ return err.code === "ENOENT" ? "absent" : "no-permission";
36
+ }
37
+ }
38
+ function realBlockedProbes() {
39
+ return { env: process.env, kvm: openKvm, totalMemoryBytes: totalmem };
40
+ }
41
+ var DEFAULT_BUILD_MEMORY = "8g";
42
+ function checkBlocked(config, probes) {
43
+ const placeholders = placeholderQueues(config);
44
+ if (placeholders.length > 0) return { reason: `${placeholderProblem(placeholders)}. The runner takes work again once the config is edited` };
45
+ const kind = builtinKind(config.hooks.provision);
46
+ if (kind === "container" || kind === "vm") {
47
+ const fit = checkFit({
48
+ concurrency: config.concurrency,
49
+ buildMemory: config.build?.memory ?? DEFAULT_BUILD_MEMORY,
50
+ usableBytes: probes.totalMemoryBytes()
51
+ });
52
+ if (!fit.fits) return { reason: `${fit.message}. Lower runner.concurrency or runner.build.memory` };
53
+ }
54
+ const kvm = kind === "vm" ? probes.kvm() : "usable";
55
+ if (kvm === "absent") {
56
+ return { reason: "/dev/kvm does not exist on this machine, so builtin:vm cannot start a microVM. Use a host with KVM enabled, or builtin:container hooks" };
57
+ }
58
+ if (kvm !== "usable") {
59
+ return {
60
+ reason: "the runner cannot open /dev/kvm, so builtin:vm cannot start a microVM. Add the runner's account to the kvm group, then restart the service, because a service reads its groups only when it starts"
61
+ };
62
+ }
63
+ if (kind !== "own" && claudeCredential(probes.env) === void 0) {
64
+ return {
65
+ reason: "there is no Claude credential in the runner's environment. Put CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`) or ANTHROPIC_API_KEY in the runner.env beside the config, then restart the service"
66
+ };
67
+ }
68
+ return void 0;
69
+ }
26
70
 
27
71
  // src/runner/heartbeat.ts
28
72
  var HEARTBEAT_TIMEOUT_MS = 1e4;
29
73
  var ERROR_CODE_MAX = 100;
30
74
  var ERROR_MESSAGE_MAX = 500;
75
+ var BLOCKED_REASON_MAX = 500;
31
76
  var UNREACHABLE_MESSAGE = "the request did not reach the platform";
32
77
  function noPlatformMessage(status) {
33
78
  return `the request got HTTP ${status} with no error message from the platform`;
@@ -73,7 +118,9 @@ async function sendHeartbeat(args, fetchImpl) {
73
118
  ...args.lastUpdate.at !== void 0 ? { at: args.lastUpdate.at } : {}
74
119
  },
75
120
  // Free disk on the runner's file system, in bytes. Sent only while held, so a host with room sends nothing about its disk.
76
- lowDisk: args.lowDisk === void 0 ? void 0 : { free: args.lowDisk.free, needed: args.lowDisk.needed }
121
+ lowDisk: args.lowDisk === void 0 ? void 0 : { free: args.lowDisk.free, needed: args.lowDisk.needed },
122
+ // Why the runner claims nothing. Sent only while it holds, so a runner that takes work says nothing about it.
123
+ blocked: args.blocked === void 0 ? void 0 : { reason: cutForGateway(args.blocked.reason, BLOCKED_REASON_MAX) }
77
124
  };
78
125
  try {
79
126
  const response = await postJson(
@@ -964,7 +1011,8 @@ async function sendTickHeartbeat(state, workRequest) {
964
1011
  slotsTotal: state.config.concurrency,
965
1012
  workRequest: next,
966
1013
  lastUpdate: readLastUpdate(state.config.configPath),
967
- lowDisk: state.lowDisk
1014
+ lowDisk: state.lowDisk,
1015
+ blocked: state.blocked
968
1016
  },
969
1017
  state.deps.fetchImpl
970
1018
  );
@@ -1088,6 +1136,25 @@ async function tick(state) {
1088
1136
  }
1089
1137
  await sendTickHeartbeat(state, state.lastWorkRequest);
1090
1138
  }
1139
+ function holdWhenBlocked(state) {
1140
+ const probes = {
1141
+ ...realBlockedProbes(),
1142
+ ...state.deps.container?.hostEnv === void 0 ? {} : { env: state.deps.container.hostEnv },
1143
+ ...state.deps.blocked
1144
+ };
1145
+ const blocked = checkBlocked(state.config, probes);
1146
+ const log = logOf(state);
1147
+ if (blocked !== void 0) {
1148
+ if (state.blocked?.reason !== blocked.reason) log.line(`claiming nothing: ${blocked.reason}`);
1149
+ state.blocked = blocked;
1150
+ return true;
1151
+ }
1152
+ if (state.blocked !== void 0) {
1153
+ state.blocked = void 0;
1154
+ log.line("the runner can run its work again \xB7 taking work");
1155
+ }
1156
+ return false;
1157
+ }
1091
1158
  function holdOffForDisk(state) {
1092
1159
  const minimum = state.config.housekeeping?.minFreeDisk ?? 0;
1093
1160
  const root = runnerDir(state.config.configPath);
@@ -1145,6 +1212,7 @@ async function housekeepingPass(state) {
1145
1212
  async function runTick(state) {
1146
1213
  reloadConfig(state);
1147
1214
  if (await updateWhenIdle(state)) return;
1215
+ if (holdWhenBlocked(state)) return;
1148
1216
  if (holdOffForDisk(state)) return;
1149
1217
  const log = logOf(state);
1150
1218
  const repoFilter = new RepoFilter(state.config.repos);
@@ -1199,7 +1267,7 @@ var CLAIM_REFUSAL_CODES = new Set(
1199
1267
  "pull_request_from_fork pull_request_on_default_branch pull_request_ambiguous branch_claimed_elsewhere".split(" ")
1200
1268
  );
1201
1269
  async function tryClaimAndStart(state, item, queue) {
1202
- const { postJson: postJson2 } = await import('./work-cmd-NUR4CAG6.js');
1270
+ const { postJson: postJson2 } = await import('./work-cmd-OVNF44FY.js');
1203
1271
  const log = logOf(state);
1204
1272
  const hostKey = await loadHostKey(state.config.configPath);
1205
1273
  const claim = await retrySend(
@@ -1678,6 +1746,17 @@ async function startJob(state, item, queue, claimId, itemKey, branch, identity)
1678
1746
  writeJobFile(jobFilePath, job);
1679
1747
  const commandStartedMs = nowOf(state).getTime();
1680
1748
  log.line(`${tag} command started \xB7 pid ${running.pid}`);
1749
+ const sender = await startSender({
1750
+ config: state.config,
1751
+ job,
1752
+ jobDir: dirPath,
1753
+ deps: { spawnFn: state.deps.spawnFn, runtime: job.microvm !== void 0 || job.container !== void 0 ? runtimeOf(state) : void 0, log }
1754
+ });
1755
+ if (sender !== void 0) {
1756
+ job = { ...active.job, sender };
1757
+ active.job = job;
1758
+ writeJobFile(jobFilePath, job);
1759
+ }
1681
1760
  running.onExit.then(({ code, signal, error }) => {
1682
1761
  if (active.ending) return;
1683
1762
  if (error !== void 0) {
@@ -1899,7 +1978,7 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
1899
1978
  const outcome = await onStartUnderMarker({
1900
1979
  configPath,
1901
1980
  own: ownVersionOf(deps),
1902
- check: update.check ? () => update.check(configPath) : async () => (await import('./check-4Q33B5ZE.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
1981
+ check: update.check ? () => update.check(configPath) : async () => (await import('./check-CCVPBN7A.js')).runRunnerCheck(configPath, { fetchImpl: deps.fetchImpl }),
1903
1982
  now: () => (deps.now ?? (() => /* @__PURE__ */ new Date()))().getTime(),
1904
1983
  log
1905
1984
  });
@@ -1918,6 +1997,11 @@ async function start(configPath, deps = { fetchImpl: fetch }) {
1918
1997
  mkdirSync(jobsDir(configPath), { recursive: true, mode: RUNNER_DIR_MODE });
1919
1998
  const self = { pid: process.pid, start: startTimeOf(process.pid) ?? "" };
1920
1999
  claimPidFile(pidFilePath(configPath), self);
2000
+ const { delegated, refusal } = setUpRunnerCgroup();
2001
+ if (refusal !== void 0) log.error(`the kernel refused a cgroup step for the runner's service: ${refusal}`);
2002
+ if (isBuiltinVm(config.hooks.provision) && !delegated) {
2003
+ log.line("microVM builds run with no memory limit of their own: the runner's service is not delegated its cgroup (Delegate=yes in the unit, cgroup v2)");
2004
+ }
1921
2005
  let configMtimeMs;
1922
2006
  try {
1923
2007
  configMtimeMs = statSync(configPath).mtimeMs;
@@ -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-RTXKYLCA.js';
4
- import { MIN_ENGINE_MAJOR } from './chunk-T52PKE2Y.js';
3
+ import { detectMachine, supportsContainerBuilds, reachDockerStep, describeMachineDocker, supportsMicroVmBuilds } from './chunk-RBOMWNOG.js';
4
+ import { MIN_ENGINE_MAJOR } from './chunk-RZSF5B46.js';
5
5
  import { RUNNER_DIR_MODE, runnerDir, RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
6
6
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
7
7
  import { dirname } from 'path';
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import './chunk-Z5GEFMRW.js';
4
3
  import { spawnSync, spawn } from 'child_process';
5
4
  import { statSync, accessSync, constants } from 'fs';
6
5
  import { delimiter, resolve } from 'path';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { sanitizeTerminal } from './chunk-WOBNRVQT.js';
3
+ import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
4
4
  import { DEFAULT_DASHBOARD } from './chunk-USO2DKBD.js';
5
5
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
6
6
 
@@ -4,6 +4,6 @@ import { createRequire } from 'node:module';
4
4
  createRequire(import.meta.url);
5
5
 
6
6
  // src/runner/protocol.ts
7
- var RUNNER_PROTOCOL = 13;
7
+ var RUNNER_PROTOCOL = 14;
8
8
 
9
9
  export { RUNNER_PROTOCOL };
@@ -44368,14 +44368,14 @@ var ModelRegistryImpl = class {
44368
44368
  };
44369
44369
  var models_default = {
44370
44370
  version: "1.0.0",
44371
- generatedAt: "2026-10-03T04:32:34.999Z",
44371
+ generatedAt: "2026-10-04T05:04:28.506Z",
44372
44372
  sources: {
44373
44373
  litellm: {
44374
- fetchedAt: "2026-10-03T04:32:34.999Z",
44375
- modelCount: 1882
44374
+ fetchedAt: "2026-10-04T05:04:28.506Z",
44375
+ modelCount: 1887
44376
44376
  },
44377
44377
  openrouter: {
44378
- fetchedAt: "2026-10-03T04:32:34.999Z",
44378
+ fetchedAt: "2026-10-04T05:04:28.506Z",
44379
44379
  modelCount: 198
44380
44380
  }
44381
44381
  },
@@ -65888,12 +65888,12 @@ var models_default = {
65888
65888
  "top_p"
65889
65889
  ],
65890
65890
  pricing: {
65891
- inputCostPerToken: 29e-8,
65892
- outputCostPerToken: 114e-8
65891
+ inputCostPerToken: 25e-8,
65892
+ outputCostPerToken: 1e-6
65893
65893
  },
65894
65894
  context: {
65895
65895
  maxInputTokens: 163840,
65896
- maxOutputTokens: 115200
65896
+ maxOutputTokens: 147456
65897
65897
  },
65898
65898
  capabilities: {
65899
65899
  functionCalling: true,
@@ -70352,7 +70352,10 @@ var models_default = {
70352
70352
  provider: "azure",
70353
70353
  displayName: "Flux.2 Pro",
70354
70354
  mode: "image_generation",
70355
- source: "litellm"
70355
+ source: "litellm",
70356
+ context: {
70357
+ maxInputTokens: 32e3
70358
+ }
70356
70359
  },
70357
70360
  "Llama-3.2-11B-Vision-Instruct": {
70358
70361
  provider: "azure",
@@ -73327,6 +73330,9 @@ var models_default = {
73327
73330
  displayName: "MAI Image 2.5",
73328
73331
  mode: "image_generation",
73329
73332
  source: "litellm",
73333
+ context: {
73334
+ maxInputTokens: 32e3
73335
+ },
73330
73336
  deprecationDate: "2026-10-01"
73331
73337
  },
73332
73338
  "MAI-Image-2.5-Flash": {
@@ -73334,6 +73340,9 @@ var models_default = {
73334
73340
  displayName: "MAI Image 2.5 Flash",
73335
73341
  mode: "image_generation",
73336
73342
  source: "litellm",
73343
+ context: {
73344
+ maxInputTokens: 32e3
73345
+ },
73337
73346
  deprecationDate: "2026-10-01"
73338
73347
  },
73339
73348
  "MAI-Image-2e": {
@@ -79250,6 +79259,10 @@ var models_default = {
79250
79259
  inputCostPerToken: 2e-6,
79251
79260
  outputCostPerToken: 12e-6
79252
79261
  },
79262
+ context: {
79263
+ maxInputTokens: 98304,
79264
+ maxOutputTokens: 32768
79265
+ },
79253
79266
  capabilities: {
79254
79267
  functionCalling: false,
79255
79268
  audioInput: true
@@ -79264,6 +79277,10 @@ var models_default = {
79264
79277
  inputCostPerToken: 35e-7,
79265
79278
  outputCostPerToken: 21e-6
79266
79279
  },
79280
+ context: {
79281
+ maxInputTokens: 131072,
79282
+ maxOutputTokens: 65536
79283
+ },
79267
79284
  capabilities: {
79268
79285
  functionCalling: false,
79269
79286
  audioInput: true
@@ -84381,6 +84398,9 @@ var models_default = {
84381
84398
  displayName: "MAI Image 2.5 Pro",
84382
84399
  mode: "image_generation",
84383
84400
  source: "litellm",
84401
+ context: {
84402
+ maxInputTokens: 32e3
84403
+ },
84384
84404
  deprecationDate: "2026-10-01"
84385
84405
  },
84386
84406
  "ap-northeast-1/qwen.qwen3-next-80b-a3b": {
@@ -87196,13 +87216,19 @@ var models_default = {
87196
87216
  provider: "azure",
87197
87217
  displayName: "MAI Image 2.6",
87198
87218
  mode: "image_generation",
87199
- source: "litellm"
87219
+ source: "litellm",
87220
+ context: {
87221
+ maxInputTokens: 32e3
87222
+ }
87200
87223
  },
87201
87224
  "MAI-Image-2.6-Flash": {
87202
87225
  provider: "azure",
87203
87226
  displayName: "MAI Image 2.6 Flash",
87204
87227
  mode: "image_generation",
87205
- source: "litellm"
87228
+ source: "litellm",
87229
+ context: {
87230
+ maxInputTokens: 32e3
87231
+ }
87206
87232
  },
87207
87233
  "FW-DeepSeek-V4.1-Flash": {
87208
87234
  provider: "azure",
@@ -88198,6 +88224,72 @@ var models_default = {
88198
88224
  }
88199
88225
  ]
88200
88226
  }
88227
+ },
88228
+ "embed-v5.0-pro": {
88229
+ provider: "cohere",
88230
+ displayName: "Embed V5.0 Pro",
88231
+ mode: "embedding",
88232
+ source: "litellm",
88233
+ pricing: {
88234
+ inputCostPerToken: 12e-8,
88235
+ outputCostPerToken: 0
88236
+ },
88237
+ context: {
88238
+ maxInputTokens: 128e3
88239
+ }
88240
+ },
88241
+ "embed-v5.0-fast": {
88242
+ provider: "cohere",
88243
+ displayName: "Embed V5.0 Fast",
88244
+ mode: "embedding",
88245
+ source: "litellm",
88246
+ pricing: {
88247
+ inputCostPerToken: 8e-8,
88248
+ outputCostPerToken: 0
88249
+ },
88250
+ context: {
88251
+ maxInputTokens: 128e3
88252
+ }
88253
+ },
88254
+ "pplx-decider-v1-27b": {
88255
+ provider: "perplexity",
88256
+ displayName: "Pplx Decider V1 27b",
88257
+ mode: "chat",
88258
+ source: "litellm",
88259
+ pricing: {
88260
+ inputCostPerToken: 4e-8,
88261
+ outputCostPerToken: 0
88262
+ },
88263
+ context: {
88264
+ maxInputTokens: 262144
88265
+ }
88266
+ },
88267
+ "grok-imagine-video-1.5-lite": {
88268
+ provider: "xai",
88269
+ displayName: "Grok Imagine Video 1.5 Lite",
88270
+ mode: "chat",
88271
+ source: "litellm"
88272
+ },
88273
+ "kimi-k2-thinking": {
88274
+ provider: "azure",
88275
+ displayName: "Kimi K2 Thinking",
88276
+ mode: "chat",
88277
+ source: "litellm",
88278
+ pricing: {
88279
+ inputCostPerToken: 6e-7,
88280
+ outputCostPerToken: 25e-7
88281
+ },
88282
+ context: {
88283
+ maxInputTokens: 262144,
88284
+ maxOutputTokens: 262144
88285
+ },
88286
+ capabilities: {
88287
+ vision: false,
88288
+ functionCalling: true,
88289
+ promptCaching: false,
88290
+ reasoning: true
88291
+ },
88292
+ deprecationDate: "2026-03-29"
88201
88293
  }
88202
88294
  }
88203
88295
  };
@@ -90223,7 +90315,8 @@ function scanAll(opts = {}) {
90223
90315
  var CaptureDaemon = class {
90224
90316
  constructor(options = {}) {
90225
90317
  this.pending = /* @__PURE__ */ new Map();
90226
- var _a5, _b, _c, _d, _e, _f, _g;
90318
+ this.reported = /* @__PURE__ */ new Map();
90319
+ var _a5, _b, _c, _d, _e, _f, _g, _h;
90227
90320
  this.root = (_a5 = options.root) != null ? _a5 : defaultProjectsDir();
90228
90321
  this.rawRoot = (_b = options.rawRoot) != null ? _b : defaultRawDir();
90229
90322
  this.debounceMs = (_c = options.debounceMs) != null ? _c : 2e3;
@@ -90233,18 +90326,23 @@ var CaptureDaemon = class {
90233
90326
  this.excludeProjects = options.excludeProjects;
90234
90327
  this.log = (_f = options.onLog) != null ? _f : (() => void 0);
90235
90328
  this.now = (_g = options.now) != null ? _g : Date.now;
90329
+ this.watchOnly = (_h = options.watchOnly) != null ? _h : false;
90236
90330
  }
90237
90331
  /** Begin watching. Resolves once the initial scan completes. */
90238
90332
  async start() {
90239
- mkdirSync(this.rawRoot, { recursive: true });
90333
+ if (!this.watchOnly) mkdirSync(this.rawRoot, { recursive: true });
90240
90334
  this.rescanNow();
90241
- this.watcher = watch(`${this.root}/**/*.jsonl`, {
90335
+ if (this.watchOnly) mkdirSync(this.root, { recursive: true });
90336
+ this.watcher = watch(this.watchOnly ? this.root : `${this.root}/**/*.jsonl`, {
90242
90337
  ignoreInitial: true,
90338
+ ...this.watchOnly ? { ignored: (path, stats) => (stats == null ? void 0 : stats.isFile()) === true && !path.endsWith(".jsonl") } : {},
90243
90339
  awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
90244
90340
  });
90341
+ const ready = this.watchOnly ? new Promise((resolve3) => this.watcher.once("ready", () => resolve3())) : void 0;
90245
90342
  this.watcher.on("add", (f) => this.schedule(f));
90246
90343
  this.watcher.on("change", (f) => this.schedule(f));
90247
90344
  this.rescanTimer = setInterval(() => this.rescanNow(), this.rescanMs);
90345
+ await ready;
90248
90346
  this.log({ type: "started" });
90249
90347
  }
90250
90348
  async stop() {
@@ -90263,7 +90361,8 @@ var CaptureDaemon = class {
90263
90361
  file22,
90264
90362
  setTimeout(() => {
90265
90363
  this.pending.delete(file22);
90266
- this.mirror(file22);
90364
+ if (this.watchOnly) this.report(file22);
90365
+ else this.mirror(file22);
90267
90366
  }, this.debounceMs)
90268
90367
  );
90269
90368
  }
@@ -90275,6 +90374,21 @@ var CaptureDaemon = class {
90275
90374
  if (this.excludeProjects && this.excludeProjects.test(projectDir)) return false;
90276
90375
  return true;
90277
90376
  }
90377
+ /** Watch-only mode: names a source transcript that exists and is not empty. Nothing is copied or evicted. */
90378
+ report(file22) {
90379
+ if (!this.included(file22)) return;
90380
+ let signature;
90381
+ try {
90382
+ const st = statSync(file22);
90383
+ if (st.size === 0) return;
90384
+ signature = `${st.size}:${st.mtimeMs}`;
90385
+ } catch {
90386
+ return;
90387
+ }
90388
+ if (this.reported.get(file22) === signature) return;
90389
+ this.reported.set(file22, signature);
90390
+ this.log({ type: "changed", file: file22 });
90391
+ }
90278
90392
  /** Copy one transcript to the raw mirror atomically. Public for the tailer
90279
90393
  * loop and tests. Returns bytes written, or null if skipped/unchanged. */
90280
90394
  mirror(file22) {
@@ -90308,7 +90422,9 @@ var CaptureDaemon = class {
90308
90422
  rescanNow() {
90309
90423
  const files = this.listJsonl(this.root);
90310
90424
  for (const file22 of files) {
90311
- if (this.included(file22)) this.mirror(file22);
90425
+ if (!this.included(file22)) continue;
90426
+ if (this.watchOnly) this.report(file22);
90427
+ else this.mirror(file22);
90312
90428
  }
90313
90429
  this.log({ type: "rescan", detail: `${files.length} files` });
90314
90430
  }
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { detectActiveSession } from './chunk-BFESLKPP.js';
4
- import { sanitizeTerminal } from './chunk-WOBNRVQT.js';
5
- import { resolveRepoIdentity } from './chunk-EX6M5JPR.js';
4
+ import { sanitizeTerminal } from './chunk-3DEVYTNQ.js';
5
+ import { resolveRepoIdentity } from './chunk-ANK2B36Y.js';
6
6
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
7
7
  import { defaultFetch } from './chunk-BCLJSQCV.js';
8
8
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
@@ -337,6 +337,18 @@ async function runWorkBuild(opts) {
337
337
  return { data, output };
338
338
  }
339
339
  async function runWorkLinkSession(opts) {
340
+ try {
341
+ return await linkSession(opts);
342
+ } catch (err) {
343
+ if (opts.logFailures) {
344
+ const { logHookError } = await import('./hook-fast-NJBBZQ5Q.js');
345
+ const reason = err instanceof Error ? err.message : String(err);
346
+ logHookError(opts.home ?? homeFromEnv(opts.env ?? process.env), new Error(`work link-session #${opts.number} failed: ${reason}`));
347
+ }
348
+ throw err;
349
+ }
350
+ }
351
+ async function linkSession(opts) {
340
352
  const cwd = opts.cwd ?? process.cwd();
341
353
  const env = opts.env ?? process.env;
342
354
  const home = opts.home ?? homeFromEnv(env);