@outerlayer/cli 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +19 -0
  3. package/dist/{agent-setup-IFH3FB5X.js → agent-setup-TXLDY5RV.js} +7 -6
  4. package/dist/{build-PAEKVYVK.js → build-JF5UOWKJ.js} +2 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/{check-4Q33B5ZE.js → check-ASZL5BEO.js} +39 -23
  7. package/dist/chunk-2VO25HHO.js +75 -0
  8. package/dist/{chunk-XDDW4FRS.js → chunk-5FWNEQNZ.js} +3 -3
  9. package/dist/{chunk-CHLVJNTE.js → chunk-6IYLDODX.js} +18 -6
  10. package/dist/{chunk-W7UTFZDH.js → chunk-6QWV3YDJ.js} +2 -2
  11. package/dist/{chunk-EGABNHZG.js → chunk-6ZZHWY2Z.js} +149 -18
  12. package/dist/{lima-XN65D7GN.js → chunk-77MM5RYD.js} +0 -1
  13. package/dist/chunk-7FTNIAHS.js +211 -0
  14. package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
  15. package/dist/{chunk-F4NU4H3V.js → chunk-AII7CKTH.js} +133 -35
  16. package/dist/{chunk-ZXBITXTS.js → chunk-AIW6GLET.js} +1 -1
  17. package/dist/{chunk-UWH5DSUP.js → chunk-AJKEHABI.js} +507 -90
  18. package/dist/{chunk-RTXKYLCA.js → chunk-AQ54MKSQ.js} +2 -2
  19. package/dist/{chunk-Z62HNKEJ.js → chunk-CEBIA5FD.js} +31 -5
  20. package/dist/{chunk-EX6M5JPR.js → chunk-D6FXM5OW.js} +6302 -28611
  21. package/dist/{chunk-RMAZ2NWA.js → chunk-DGAIVMMN.js} +23 -2
  22. package/dist/{chunk-3DD6AOWC.js → chunk-DTXOJDEH.js} +26 -2
  23. package/dist/{chunk-T52PKE2Y.js → chunk-E4PIFIC3.js} +244 -17
  24. package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
  25. package/dist/chunk-FBTE2A2X.js +38 -0
  26. package/dist/{chunk-DVDEBNQJ.js → chunk-GQD22KKN.js} +17 -6
  27. package/dist/{chunk-BCJNHMZT.js → chunk-HHJDN6AU.js} +18 -3
  28. package/dist/chunk-HKMPVPO7.js +55 -0
  29. package/dist/{chunk-UFFXNXLQ.js → chunk-JPR2WHHF.js} +31 -29
  30. package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
  31. package/dist/{chunk-H4CK2YK4.js → chunk-MQPRB5K7.js} +18 -10
  32. package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
  33. package/dist/chunk-OUUINEYB.js +27 -0
  34. package/dist/chunk-PUN7LMNS.js +39 -0
  35. package/dist/{install-cmd-7WXOIFDO.js → chunk-Q5G2ODUZ.js} +1 -2
  36. package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
  37. package/dist/{chunk-OR6AEEDO.js → chunk-SSU747O6.js} +85 -25
  38. package/dist/chunk-T6OIJQRT.js +31 -0
  39. package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
  40. package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
  41. package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
  42. package/dist/{chunk-JLDZTG3A.js → chunk-X2FSFU4C.js} +4 -1
  43. package/dist/chunk-YNJEOGDL.js +22434 -0
  44. package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
  45. package/dist/{chunk-WOBNRVQT.js → chunk-ZYHKJKSU.js} +1 -1
  46. package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
  47. package/dist/{cli-LHSUYYMI.js → cli-LEVCGAQV.js} +154 -79
  48. package/dist/command-FLSYCGIB.js +187 -0
  49. package/dist/config-I3TVFYLH.js +10 -0
  50. package/dist/{connect-cmd-OJBFHZWP.js → connect-cmd-MJMUONDY.js} +4 -4
  51. package/dist/{context-adopt-UMA4O5NY.js → context-adopt-CE4KDXS3.js} +5 -4
  52. package/dist/{context-materialize-G2FUFC72.js → context-materialize-QL33HDJN.js} +5 -4
  53. package/dist/{dist-WDV7U7UJ.js → dist-PXBSA7QX.js} +2 -1
  54. package/dist/{doctor-MOA3RIEP.js → doctor-FVDT3KJZ.js} +46 -19
  55. package/dist/{emit-artifact-cmd-FDWYKURA.js → emit-artifact-cmd-7RPMRSVP.js} +13 -7
  56. package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
  57. package/dist/{emit-criteria-cmd-OCXHLK34.js → emit-criteria-cmd-MKI7WETO.js} +12 -3
  58. package/dist/{emit-finding-cmd-POW7PKIA.js → emit-finding-cmd-RMLGZASB.js} +14 -3
  59. package/dist/{emit-result-cmd-ID35SH53.js → emit-result-cmd-MTXAZ2GV.js} +15 -9
  60. package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
  61. package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
  62. package/dist/{hook-fast-EYENPK6F.js → hook-fast-XBOZ3N6L.js} +1 -1
  63. package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
  64. package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
  65. package/dist/index.js +3 -2
  66. package/dist/{init-FYDJAKTM.js → init-BACXESVV.js} +21 -14
  67. package/dist/{init-2IPOIXJV.js → init-VLW7H6RW.js} +40 -62
  68. package/dist/{init-cmd-KLIDRVXQ.js → init-cmd-VJFB5L7X.js} +10 -9
  69. package/dist/inspect-XAUSB7L3.js +63 -0
  70. package/dist/install-NMAPLLBQ.js +14 -0
  71. package/dist/install-cmd-B5SEU3G7.js +8 -0
  72. package/dist/lima-7NPCNGWT.js +6 -0
  73. package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
  74. package/dist/loop-D3243JKT.js +64 -0
  75. package/dist/{machine-ECU3QCZD.js → machine-EB3GEVI4.js} +20 -13
  76. package/dist/session-sender-LMACEJJS.js +29 -0
  77. package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
  78. package/dist/{status-CLATHCTQ.js → status-F4THTJJK.js} +36 -16
  79. package/dist/{sync-cmd-SWQ5KLPL.js → sync-cmd-M6JA3OEE.js} +7 -7
  80. package/dist/{watch-3YW6Z3DQ.js → watch-NB5TGPEZ.js} +7 -7
  81. package/dist/{work-claim-cmd-3OPWA77E.js → work-claim-cmd-UHMWOS3G.js} +14 -7
  82. package/dist/{work-cmd-NUR4CAG6.js → work-cmd-6UMCFTAW.js} +9 -3
  83. package/dist/{work-comment-cmd-6TTTYGHM.js → work-comment-cmd-E4LEUIXZ.js} +9 -3
  84. package/dist/{work-launch-YI4CJDAP.js → work-launch-R5HTAP6X.js} +1 -1
  85. package/dist/{work-open-pr-cmd-KZ7QQFLD.js → work-open-pr-cmd-OPZWGSEQ.js} +10 -4
  86. package/dist/{work-pr-cmd-QNUBE6IQ.js → work-pr-cmd-IDIAFFRU.js} +9 -2
  87. package/package.json +2 -1
  88. package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
  89. package/dist/chunk-D2KWEAN6.js +0 -55
  90. package/dist/chunk-ZOC7JSYC.js +0 -83
  91. package/dist/config-HL2AIR3K.js +0 -9
  92. package/dist/loop-NEBUGD2Q.js +0 -45
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @outerlayer/cli
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b4fdd73: The runner now runs a repository's `where: host` validators itself after a build, in a new container from the build's image, and records each result under the host's own key. A check that cannot run is recorded as a fail with a reason. `runner.checks.timeLimitMinutes` (default 10, 1 to 240) bounds the environment setup and each check command. The runner CLI is not updated for you on a host with `runner.autoUpdate` off: refresh it by hand on each host to get host checks.
8
+
9
+ ### Patch Changes
10
+
11
+ - 35b0fed: Fixes found by running the runner service on real machines:
12
+
13
+ - A repository fetch with a claim's read token keeps the git settings the host passes in `GIT_CONFIG_*`, such as one in `runner.env`. It added the token over them.
14
+ - `runner install --service --user <account>` refuses when that account cannot execute the Node the install runs on, or read the runner's CLI, instead of installing a service that cannot start.
15
+ - A microVM the kernel kills at its memory limit while it is still starting is released with a reason saying the build ran out of memory, not that the microVM did not start.
16
+ - A microVM build's cgroup reclaims above `build.memory` plus 256 MiB and kills above `build.memory` plus 1 GiB. A real build was killed at plus 256 MiB, because the page cache of its disks' writes is charged to the same cgroup.
17
+
18
+ - f633a70: The template build skill's `record-criteria.mjs` now records a criterion that declares `(proof: test)` with proof `test`. Test results for that criterion now count toward it.
19
+ - 735d939: `work` and `emit` commands now connect the repository themselves when you are logged in, the repository has no saved connection, and exactly one factory fits. They print one line naming the factory and why, save the connection, and carry on. When several factories fit, they refuse and list the `--factory` value for each.
20
+
21
+ ## 0.6.0
22
+
23
+ ### Minor Changes
24
+
25
+ - 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.
26
+ - 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.
27
+
28
+ ### Patch Changes
29
+
30
+ - 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.
31
+
3
32
  ## 0.5.1
4
33
 
5
34
  ### 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
 
@@ -92,6 +101,12 @@ content:
92
101
  work — success, or the error code and message the platform returned.
93
102
  When a build's command exits 0, it reads that work item once more, for its
94
103
  evidence verdict, before releasing it: it sends nothing but the request.
104
+ Just before that read, the runner runs the repository's host checks. A host
105
+ check is a command the repository's `where: host` validators declare. The
106
+ runner reads the definitions with the host's own git credentials, runs each
107
+ command in a new container, and sends one `POST /v1/emitted-results` for
108
+ each: the check's name, pass or fail, and for a fail the exit status and the
109
+ last line of its output, scrubbed.
95
110
  Before a build's command starts, the runner also runs `git ls-remote` and
96
111
  `git fetch` in the job's workdir, with the host's own git credentials, to
97
112
  put it on the branch the claim named. Nothing about the job leaves the host
@@ -124,6 +139,10 @@ content:
124
139
  never printed. If this machine held a token from an earlier login, login
125
140
  asks the dashboard to revoke it. A key piped on stdin makes no network
126
141
  call.
142
+ - **`outerlayer work`** and **`outerlayer emit`**, in the subcommands named below, with a login and no saved
143
+ connection for the repository send the same `GET /v1/me/factories?repository=<host/owner/name>`
144
+ request before their own, to connect the repository when exactly one factory
145
+ fits. They send nothing extra with a factory key, `--app-id` or `OUTERLAYER_APP_ID`. The subcommands are `work build`, `list`, `status`, `remove` and `pr`, and `emit artifact`, `result`, `criteria`, `finding` and `findings`. Other `work` subcommands never connect.
127
146
  - **`outerlayer connect`**, and the first step of `outerlayer init`, send a
128
147
  request with your login's token: `GET /v1/me/factories?repository=<host/owner/name>`,
129
148
  naming this checkout's remote. The gateway answers with the factories you can
@@ -1,16 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { installStarterPack } from './chunk-ZMYPLFG3.js';
4
- import { runEmit } from './chunk-H5NCNVDA.js';
3
+ import { installStarterPack } from './chunk-M3SQ4YGD.js';
4
+ import { runEmit } from './chunk-EV3M3EH7.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';
8
- import { pinExists, readContextManifest } from './chunk-WIOZAJ2W.js';
9
- import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-WO2BXCTQ.js';
10
- import { generatedHeaderSource } from './chunk-EMY4I27X.js';
7
+ import { resolveGitCommonDir, defaultGitRunner } from './chunk-5FWNEQNZ.js';
11
8
  import './chunk-ZJSNLVCE.js';
9
+ import { pinExists, readContextManifest } from './chunk-ZZXLM64C.js';
10
+ import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-VXLJORHL.js';
11
+ import { generatedHeaderSource } from './chunk-7ZR5UPMB.js';
12
12
  import './chunk-BCLJSQCV.js';
13
13
  import './chunk-BOLTI6LR.js';
14
+ import './chunk-YNJEOGDL.js';
14
15
  import './chunk-EABW6AJQ.js';
15
16
  import './chunk-RA3O54FC.js';
16
17
  import './chunk-M5POMKKW.js';
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { buildRepositoryImage } from './chunk-Z62HNKEJ.js';
3
+ export { buildRepositoryImage } from './chunk-CEBIA5FD.js';
4
4
  import './chunk-N5FOE5PS.js';
5
5
  export { RecipeError } from './chunk-QOZKPLVJ.js';
6
+ import './chunk-HKMPVPO7.js';
6
7
  import './chunk-ZM2IMMYN.js';
7
8
  import './chunk-Z5GEFMRW.js';
8
9
 
@@ -1 +1 @@
1
- {"id":"2026-10-04T00:10:45.902Z+d37533c","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
1
+ {"id":"2026-10-05T00:52:06.865Z+90312df","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
@@ -1,45 +1,61 @@
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-AII7CKTH.js';
7
4
  import './chunk-ABIWDUMS.js';
8
- import './chunk-YYYXRJUW.js';
9
- import './chunk-CBPPJSAR.js';
10
- import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-CHLVJNTE.js';
5
+ import './chunk-TI7B7UEO.js';
6
+ import './chunk-AJKEHABI.js';
7
+ import './chunk-T6OIJQRT.js';
8
+ import './chunk-AIW6GLET.js';
9
+ import './chunk-UGP76IZ5.js';
10
+ import './chunk-2VO25HHO.js';
11
+ import './chunk-WVGSB3Z2.js';
12
+ import './chunk-6ZZHWY2Z.js';
13
+ import './chunk-HHJDN6AU.js';
14
+ import { placeholderQueues, placeholderProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-6IYLDODX.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-Z62HNKEJ.js';
17
+ import './chunk-6QWV3YDJ.js';
18
+ import './chunk-OUUINEYB.js';
19
+ import './chunk-AQ54MKSQ.js';
20
+ import './chunk-E4PIFIC3.js';
21
+ import './chunk-CEBIA5FD.js';
18
22
  import './chunk-N5FOE5PS.js';
19
23
  import './chunk-OGFGZQA3.js';
20
24
  import './chunk-774HEQL6.js';
21
25
  import './chunk-QOZKPLVJ.js';
22
- import './chunk-W4SQCOZU.js';
23
- import './chunk-B2G7JHHB.js';
24
- import './chunk-RMAZ2NWA.js';
26
+ import './chunk-ZOAEPWGL.js';
27
+ import './chunk-R7STSBLC.js';
28
+ import './chunk-F7CU5ABH.js';
29
+ import './chunk-BKO6JEZI.js';
30
+ import './chunk-DGAIVMMN.js';
31
+ import './chunk-PUN7LMNS.js';
25
32
  import './chunk-BFESLKPP.js';
26
- import './chunk-WOBNRVQT.js';
27
- import './chunk-EX6M5JPR.js';
28
- import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-3DD6AOWC.js';
33
+ import './chunk-SSU747O6.js';
34
+ import './chunk-ZYHKJKSU.js';
35
+ import './chunk-D6FXM5OW.js';
36
+ import './chunk-USO2DKBD.js';
37
+ import './chunk-N6LURUEF.js';
38
+ import './chunk-YRYMNBGQ.js';
39
+ import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-DTXOJDEH.js';
29
40
  import './chunk-F6GFZXZ3.js';
30
- import './chunk-AUFG23AA.js';
41
+ import './chunk-OD2VTIHN.js';
42
+ import './chunk-HKMPVPO7.js';
43
+ import './chunk-GQD22KKN.js';
31
44
  import './chunk-WZBHBH3J.js';
32
- import './chunk-XDDW4FRS.js';
33
- import './chunk-WIOZAJ2W.js';
34
- import './chunk-WO2BXCTQ.js';
35
- import './chunk-EMY4I27X.js';
45
+ import './chunk-5QRP3MVS.js';
46
+ import './chunk-5FWNEQNZ.js';
36
47
  import './chunk-ZJSNLVCE.js';
48
+ import './chunk-ZZXLM64C.js';
49
+ import './chunk-VXLJORHL.js';
50
+ import './chunk-7ZR5UPMB.js';
37
51
  import './chunk-BCLJSQCV.js';
38
52
  import './chunk-BOLTI6LR.js';
53
+ import './chunk-YNJEOGDL.js';
39
54
  import './chunk-EABW6AJQ.js';
40
55
  import './chunk-RA3O54FC.js';
41
56
  import './chunk-M5POMKKW.js';
42
57
  import './chunk-ZM2IMMYN.js';
58
+ import './chunk-JPR2WHHF.js';
43
59
  import './chunk-XCCLFVXM.js';
44
60
  import './chunk-BJ3KTMDH.js';
45
61
  import './chunk-VNVZDWO3.js';
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { LiveUploader } from './chunk-6ZZHWY2Z.js';
4
+ import { CaptureDaemon } from './chunk-D6FXM5OW.js';
5
+ import { parseWorkItemEnv } from './chunk-GQD22KKN.js';
6
+ import { spoolDir } from './chunk-JPR2WHHF.js';
7
+ import { homeFromEnv } from './chunk-VNVZDWO3.js';
8
+ import { mkdirSync, writeFileSync, rmSync } from 'fs';
9
+ import { join } from 'path';
10
+
11
+ createRequire(import.meta.url);
12
+ var SENDER_STOP_WAIT_MS = 25e3;
13
+ var RESCAN_MS = 3e4;
14
+ function senderPidfile(home, item) {
15
+ return join(spoolDir(home), `session-sender-${item}.pid`);
16
+ }
17
+ async function startSessionSender(opts = {}) {
18
+ const env = opts.env ?? process.env;
19
+ const stderr = opts.stderr ?? ((s) => void process.stderr.write(s));
20
+ const parsed = parseWorkItemEnv(env.OUTERLAYER_WORK);
21
+ const jobDir = env.OUTERLAYER_JOB_DIR;
22
+ if ("reason" in parsed || !jobDir) {
23
+ throw new Error("a session sender runs inside a runner job: OUTERLAYER_WORK must name the item and OUTERLAYER_JOB_DIR the job");
24
+ }
25
+ const home = opts.home ?? homeFromEnv(env);
26
+ const uploader = new LiveUploader({
27
+ home,
28
+ env,
29
+ fetchImpl: opts.fetchImpl,
30
+ sleepImpl: opts.sleepImpl,
31
+ debounceMs: opts.debounceMs,
32
+ stderr,
33
+ build: { item: parsed.number, jobDir },
34
+ onUnauthorized: opts.onFatal
35
+ });
36
+ const onLog = (event) => {
37
+ if (event.type === "changed" && event.file !== void 0) uploader.notify(event.file);
38
+ if (event.type === "error") stderr(`error ${event.file}: ${event.detail}
39
+ `);
40
+ };
41
+ const daemon = new CaptureDaemon({ ...opts.root === void 0 ? {} : { root: opts.root }, watchOnly: true, rescanMs: RESCAN_MS, onLog });
42
+ const pidfile = senderPidfile(home, parsed.number);
43
+ try {
44
+ mkdirSync(spoolDir(home), { recursive: true });
45
+ writeFileSync(pidfile, String(process.pid));
46
+ } catch {
47
+ }
48
+ await daemon.start();
49
+ let stopped;
50
+ return {
51
+ stop: () => stopped ??= (async () => {
52
+ daemon.rescanNow();
53
+ await uploader.stop(opts.stopWaitMs ?? SENDER_STOP_WAIT_MS);
54
+ await daemon.stop();
55
+ rmSync(pidfile, { force: true });
56
+ })()
57
+ };
58
+ }
59
+ async function runSessionSender() {
60
+ let sender;
61
+ const exit = async (code) => {
62
+ await sender?.stop().catch(() => void 0);
63
+ process.exit(code);
64
+ };
65
+ sender = await startSessionSender({ onFatal: () => void exit(1) });
66
+ process.on("SIGTERM", () => void exit(0));
67
+ process.on("SIGINT", () => void exit(0));
68
+ process.on("unhandledRejection", (reason) => {
69
+ process.stderr.write(`session-sender: unhandled error, continuing: ${String(reason)}
70
+ `);
71
+ });
72
+ await new Promise(() => void 0);
73
+ }
74
+
75
+ export { runSessionSender, senderPidfile, startSessionSender };
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { readPin, pinExists, readBuildHold, readContextManifest, manifestFilesPresent, writeDegraded, writeSourceCache, SOURCE_CACHE_TTL_RETRY_MS, SOURCE_CACHE_TTL_SUCCESS_MS, isLastCheckFresh, readDegraded, touchLastCheck, clearDegraded, writeContextManifest, writePinIfChanged, readSourceCache, isSourceCacheFresh } from './chunk-WIOZAJ2W.js';
4
- import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-WO2BXCTQ.js';
5
- import { parseGoverns, normalizeRepoName, CONTEXT_SOURCE_CONFIG_PATH, parseOuterlayerConfig, classifyTree, emitTree } from './chunk-EMY4I27X.js';
6
3
  import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
4
+ import { readPin, pinExists, readBuildHold, readContextManifest, manifestFilesPresent, writeDegraded, writeSourceCache, SOURCE_CACHE_TTL_RETRY_MS, SOURCE_CACHE_TTL_SUCCESS_MS, isLastCheckFresh, readDegraded, touchLastCheck, clearDegraded, writeContextManifest, writePinIfChanged, readSourceCache, isSourceCacheFresh } from './chunk-ZZXLM64C.js';
5
+ import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-VXLJORHL.js';
6
+ import { parseGoverns, normalizeRepoName, CONTEXT_SOURCE_CONFIG_PATH, parseOuterlayerConfig, classifyTree, emitTree } from './chunk-7ZR5UPMB.js';
7
7
  import { defaultFetch } from './chunk-BCLJSQCV.js';
8
8
  import { resolveGatewayCredentials } from './chunk-BOLTI6LR.js';
9
9
  import { ensureContextExcludes, ensurePreCommitGuardHook } from './chunk-XCCLFVXM.js';
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { isPlaceholderCommand } from './chunk-W7UTFZDH.js';
4
- import { describeCallFailure } from './chunk-T52PKE2Y.js';
5
- import { WorkCommandError, getJson } from './chunk-RMAZ2NWA.js';
6
- import { sanitizeTerminal } from './chunk-WOBNRVQT.js';
7
- import { builtinKind } from './chunk-3DD6AOWC.js';
8
- import { claudeCredential, CLAUDE_CREDENTIAL_VARIABLES } from './chunk-AUFG23AA.js';
3
+ import { isPlaceholderCommand } from './chunk-6QWV3YDJ.js';
4
+ import { describeCallFailure } from './chunk-E4PIFIC3.js';
5
+ import { WorkCommandError, getJson } from './chunk-DGAIVMMN.js';
6
+ import { sanitizeTerminal } from './chunk-ZYHKJKSU.js';
7
+ import { builtinKind } from './chunk-DTXOJDEH.js';
8
+ import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential } from './chunk-OD2VTIHN.js';
9
9
  import { signerFor } from './chunk-M5POMKKW.js';
10
10
 
11
11
  createRequire(import.meta.url);
@@ -27,6 +27,18 @@ function needsClaudeCredential(hooks) {
27
27
  var CREDENTIAL_FIX = "Run `claude setup-token`, then start the runner with CLAUDE_CODE_OAUTH_TOKEN set to the token it prints (or ANTHROPIC_API_KEY set to an API key), for example with EnvironmentFile= in the runner's systemd unit";
28
28
  function claudeCredentialCheck(env, options = {}) {
29
29
  const name = "Claude credential";
30
+ if (options.service !== void 0) {
31
+ const { unit, variables } = options.service;
32
+ if (variables.length === 0) {
33
+ return {
34
+ name,
35
+ status: "fail",
36
+ detail: `the service ${unit} has no Claude credential: neither ${CLAUDE_CREDENTIAL_VARIABLES.slice(0, 2).join(" nor ")} is set in its runner.env, so every build fails at provision as agent_credential_missing`,
37
+ fix: `${CREDENTIAL_FIX}, then restart the service: sudo systemctl restart ${unit}.`
38
+ };
39
+ }
40
+ return { name, status: "pass", detail: `${variables[0]} is set in the runner.env of the service ${unit}` };
41
+ }
30
42
  const held = claudeCredential(env);
31
43
  if (held === void 0) {
32
44
  return {
@@ -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-AQ54MKSQ.js';
4
+ import { MIN_ENGINE_MAJOR } from './chunk-E4PIFIC3.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,29 +1,105 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { applyContextProvenance, installScrubContext, prepareSessionForUpload, wholeSessionCounts, sliceTurnIo } from './chunk-ZOC7JSYC.js';
4
- import { LaunchFilter } from './chunk-BCJNHMZT.js';
3
+ import { LaunchFilter } from './chunk-HHJDN6AU.js';
5
4
  import { RepoFilter } from './chunk-TBT347UY.js';
6
5
  import { hookExecSpoolPath } from './chunk-F7CU5ABH.js';
7
6
  import { applyReportedCost } from './chunk-BKO6JEZI.js';
8
- import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-WOBNRVQT.js';
9
- import { tailTranscript, enrichSessionRepo, CAPTURE_TIERS, scanAll, setRepoRoot, resolveRepoIdentity, inferArtifactKind, bannedPathsForTier, sessionIdFromPath, SOURCE_ADAPTERS, EVENT_TYPES } from './chunk-EX6M5JPR.js';
7
+ import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-ZYHKJKSU.js';
8
+ import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-D6FXM5OW.js';
10
9
  import { C } from './chunk-YRYMNBGQ.js';
11
- import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-DVDEBNQJ.js';
10
+ import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-GQD22KKN.js';
12
11
  import { readLatestProvenanceForSession, readContextProvenance } from './chunk-ZJSNLVCE.js';
13
12
  import { defaultFetch } from './chunk-BCLJSQCV.js';
14
13
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
14
+ import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-YNJEOGDL.js';
15
15
  import { readCloudConfig, cloudConfigPath, writeCloudConfig } from './chunk-EABW6AJQ.js';
16
16
  import { signerFor, signRunnerRequest } from './chunk-M5POMKKW.js';
17
- import { writeSyncStatus, spoolDir } from './chunk-UFFXNXLQ.js';
17
+ import { writeSyncStatus, spoolDir } from './chunk-JPR2WHHF.js';
18
18
  import { removeJournalHooks } from './chunk-XCCLFVXM.js';
19
19
  import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
20
20
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
21
21
  import { dirname, basename, join } from 'path';
22
22
  import { statSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync, rmSync } from 'fs';
23
+ import { execFileSync } from 'child_process';
24
+ import { hostname, userInfo } from 'os';
23
25
  import { fileURLToPath } from 'url';
24
26
  import { createRequire as createRequire$1 } from 'module';
25
27
 
26
28
  createRequire(import.meta.url);
29
+ function detectCi(env = process.env) {
30
+ return env.CI === "true" || env.CI === "1" || !!env.JENKINS_URL;
31
+ }
32
+ function gitGlobalConfig(key) {
33
+ try {
34
+ return execFileSync("git", ["config", "--global", key], { encoding: "utf8", timeout: 2e3 }).trim() || void 0;
35
+ } catch {
36
+ return void 0;
37
+ }
38
+ }
39
+ function installScrubContext(home, scrub) {
40
+ setCustomScrubbers(scrub);
41
+ setLocalIdentity({
42
+ name: gitGlobalConfig("user.name"),
43
+ email: gitGlobalConfig("user.email"),
44
+ username: (() => {
45
+ try {
46
+ return userInfo().username;
47
+ } catch {
48
+ return void 0;
49
+ }
50
+ })(),
51
+ hostname: (() => {
52
+ try {
53
+ return hostname();
54
+ } catch {
55
+ return void 0;
56
+ }
57
+ })(),
58
+ home
59
+ });
60
+ }
61
+ function applyContextProvenance(session, record) {
62
+ if (!record) return;
63
+ if (record.repository !== void 0) session.env.contextSourceRepo = record.repository;
64
+ if (record.ref !== void 0) session.env.contextSourceRef = record.ref;
65
+ if (record.sha !== null) session.env.contextSourceSha = record.sha;
66
+ session.env.contextSourceVerification = record.verification;
67
+ }
68
+ function prepareSessionForUpload(session, tier, envVars = process.env) {
69
+ setRepoRoot(resolveRepoIdentity(session.env.cwd).repoRoot);
70
+ scrubDeep(session);
71
+ session.workerKind ??= detectCi(envVars) ? "ci" : "seat";
72
+ return downconvertSession(session, tier);
73
+ }
74
+ var MAX_TOOL_IO_CHARS = 64e3;
75
+ function sliceToolIo(value) {
76
+ const text = typeof value === "string" ? value : JSON.stringify(value);
77
+ if (typeof text !== "string" || text.length <= MAX_TOOL_IO_CHARS) return value;
78
+ return `${text.slice(0, MAX_TOOL_IO_CHARS)}\u2026[sliced: ${text.length} chars exceeded the sync per-call cap]`;
79
+ }
80
+ function sliceTurnIo(turn) {
81
+ return {
82
+ ...turn,
83
+ toolCalls: (turn.toolCalls ?? []).map((call) => ({
84
+ ...call,
85
+ ...call.input !== void 0 ? { input: sliceToolIo(call.input) } : {},
86
+ ...call.output !== void 0 ? { output: sliceToolIo(call.output) } : {}
87
+ }))
88
+ };
89
+ }
90
+ function wholeSessionCounts(turns) {
91
+ const allCalls = turns.flatMap((t) => t.toolCalls ?? []);
92
+ return {
93
+ // An index BOUND (`1 + max(turn.index)`), not the shipped turn count —
94
+ // turn indexes are not guaranteed dense from zero, and a late artifact
95
+ // anchored at its real turn index must still validate against the
96
+ // summary row this produces (see turnCountBound).
97
+ turns: turnCountBound(turns),
98
+ toolCalls: allCalls.length,
99
+ errors: allCalls.filter((c) => c.status === "error").length,
100
+ userTurns: turns.filter(isHumanUserTurn).length
101
+ };
102
+ }
27
103
  var IRRELEVANT = /* @__PURE__ */ new Set(["__tests__", "__mocks__", "node_modules"]);
28
104
  function newestSourceMs(dir) {
29
105
  let newest = 0;
@@ -481,6 +557,8 @@ function retryAfterMs(response) {
481
557
  }
482
558
  var LiveUploader = class {
483
559
  constructor(opts) {
560
+ /** Set by `stop()`: no more debounce or retry waits, so what is pending is sent once and given up on. */
561
+ this.stopping = false;
484
562
  this.cycles = /* @__PURE__ */ new Map();
485
563
  /** Sessions this sender is done with: ended, or permanently rejected. The
486
564
  * daemon keeps mirroring a transcript after its session closes, and every
@@ -491,12 +569,31 @@ var LiveUploader = class {
491
569
  * every session, so the sender stops entirely for the rest of this
492
570
  * process rather than retrying session by session. */
493
571
  this.stopped = false;
572
+ this.warned = /* @__PURE__ */ new Set();
494
573
  this.home = opts.home;
495
574
  this.fetchImpl = opts.fetchImpl ?? fetch;
496
575
  this.sleepImpl = opts.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
497
576
  this.debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
498
577
  this.env = opts.env ?? process.env;
499
578
  this.stderr = opts.stderr ?? ((s) => void process.stderr.write(s));
579
+ this.build = opts.build;
580
+ this.onUnauthorized = opts.onUnauthorized;
581
+ }
582
+ /**
583
+ * Final pass for a build sender: sends what is pending now, without waiting out the debounce and without
584
+ * retrying a failed send, and resolves once every cycle has finished or `timeoutMs` has passed.
585
+ */
586
+ async stop(timeoutMs) {
587
+ this.stopping = true;
588
+ let timer;
589
+ const expired = new Promise((resolve) => {
590
+ timer = setTimeout(resolve, timeoutMs);
591
+ });
592
+ try {
593
+ await Promise.race([this.flush(), expired]);
594
+ } finally {
595
+ clearTimeout(timer);
596
+ }
500
597
  }
501
598
  /** Called for every daemon `mirrored` event. Cheap and synchronous — the
502
599
  * actual read/send work happens on the debounced cycle. */
@@ -536,7 +633,7 @@ var LiveUploader = class {
536
633
  for (; ; ) {
537
634
  for (; ; ) {
538
635
  const generationAtWaitStart = cycle.generation;
539
- await this.sleepImpl(this.debounceMs);
636
+ if (!this.stopping) await this.sleepImpl(this.debounceMs);
540
637
  if (cycle.generation !== generationAtWaitStart) continue;
541
638
  break;
542
639
  }
@@ -562,8 +659,21 @@ var LiveUploader = class {
562
659
  const priorEntry = state.sessions[key];
563
660
  if (priorEntry?.ended || priorEntry?.failed) return true;
564
661
  const cloudConfig = readCloudConfig(this.home);
565
- if (cloudConfig.autoSync === false) return false;
566
- if (!cloudConfig.url || !(cloudConfig.apiKey || cloudConfig.accountToken)) return false;
662
+ let destination;
663
+ if (this.build === void 0) {
664
+ if (cloudConfig.autoSync === false) return false;
665
+ if (!cloudConfig.url || !(cloudConfig.apiKey || cloudConfig.accountToken)) return false;
666
+ } else {
667
+ const url = this.env.OUTERLAYER_URL;
668
+ const credential = this.env.OUTERLAYER_API_KEY;
669
+ const appId = this.env.OUTERLAYER_APP_ID;
670
+ if (!url || !credential || !appId) {
671
+ this.warnOnce("incomplete", `live upload is idle: this build's environment lacks ${[!url && "OUTERLAYER_URL", !credential && "OUTERLAYER_API_KEY", !appId && "OUTERLAYER_APP_ID"].filter(Boolean).join(", ")}, so nothing streams until \`outerlayer sync\` runs.
672
+ `);
673
+ return false;
674
+ }
675
+ destination = { ok: true, url, credential, appId, kind: "key" };
676
+ }
567
677
  const info = subagentInfo(mirrorPath);
568
678
  const tail = tailTranscript(mirrorPath, void 0, {
569
679
  isSubagent: info.isSubagent,
@@ -573,17 +683,16 @@ var LiveUploader = class {
573
683
  if (!tail.session) return false;
574
684
  const session = tail.session;
575
685
  enrichSessionRepo(session);
576
- const destination = resolveGatewayCredentials({ home: this.home, env: {}, cwd: session.env.cwd ?? "/" });
686
+ destination ??= resolveGatewayCredentials({ home: this.home, env: {}, cwd: session.env.cwd ?? "/" });
577
687
  if (!destination.ok) return false;
578
- const repoFilter = new RepoFilter(cloudConfig.repos);
579
- if (!repoFilter.allows(session.env.gitRepo)) return false;
688
+ if (this.build === void 0 && !new RepoFilter(cloudConfig.repos).allows(session.env.gitRepo)) return false;
580
689
  const launchSpool = readLaunchSpoolState(this.home);
581
690
  if (!launchStatusIsDecisive(launchSpool)) return false;
582
- const launchFilter = new LaunchFilter(launchSpool.ids);
691
+ const launchFilter = new LaunchFilter(launchSpool.ids, launchSpool.records, this.build);
583
692
  if (!launchFilter.allows(session)) return false;
584
693
  let tier;
585
694
  try {
586
- tier = resolveTier(cloudConfig.tier);
695
+ tier = resolveTier(this.build === void 0 ? cloudConfig.tier : this.env.OUTERLAYER_TIER ?? cloudConfig.tier);
587
696
  } catch (err) {
588
697
  if (err instanceof SyncConfigError) return false;
589
698
  throw err;
@@ -613,6 +722,7 @@ var LiveUploader = class {
613
722
  const outcome = await this.sendWithRetry(endpoint, destination.credential, destination.appId, prepared.id, payload);
614
723
  if (outcome === "unauthorized") {
615
724
  this.stopped = true;
725
+ this.onUnauthorized?.();
616
726
  this.stderr(
617
727
  destination.credential.startsWith("olu_") ? `live upload stopped: the login was refused (expired or revoked). No session streams from this daemon until you run \`outerlayer login\` and it restarts.
618
728
  ` : `live upload stopped: the API key was refused. No session streams from this daemon until it restarts with a valid key.
@@ -620,8 +730,9 @@ var LiveUploader = class {
620
730
  );
621
731
  return true;
622
732
  }
733
+ if (outcome === "unreachable") return false;
623
734
  if (outcome === "rejected") {
624
- const reason = "the server refused this delta permanently";
735
+ const reason = `the server refused this delta permanently${this.lastRejectStatus === void 0 ? "" : ` (HTTP ${this.lastRejectStatus})`}`;
625
736
  this.mergeSessionState(key, {
626
737
  ackedTurnIndex: currentAcked,
627
738
  failed: true,
@@ -654,6 +765,7 @@ var LiveUploader = class {
654
765
  * key bound to a host key is refused on every route unless that key signed the request. A login token is
655
766
  * never signed: only the saved factory key is bound to a host key. */
656
767
  async signatureHeaders(endpoint, body, credential) {
768
+ if (this.build !== void 0) return {};
657
769
  if (readCloudConfig(this.home).apiKey !== credential) return {};
658
770
  let signer;
659
771
  try {
@@ -664,6 +776,12 @@ var LiveUploader = class {
664
776
  if (signer === void 0) return {};
665
777
  return { ...await signRunnerRequest({ method: "POST", url: endpoint, body: new TextEncoder().encode(body), signer }) };
666
778
  }
779
+ /** Writes `message` the first time `key` is seen, so a condition that holds on every fire logs once. */
780
+ warnOnce(key, message) {
781
+ if (this.warned.has(key)) return;
782
+ this.warned.add(key);
783
+ this.stderr(message);
784
+ }
667
785
  /** Sends one request, retrying a network error or a retryable 5xx forever
668
786
  * with exponential backoff (2s → 60s cap) — the daemon runs unattended, so
669
787
  * there is no bounded attempt count. A 401 or a permanent 4xx/rejection
@@ -673,6 +791,7 @@ var LiveUploader = class {
673
791
  let delayMs = RETRY_BASE_DELAY_MS;
674
792
  for (; ; ) {
675
793
  let response;
794
+ let failure = "";
676
795
  try {
677
796
  const signature = await this.signatureHeaders(endpoint, body, apiKey);
678
797
  response = await this.fetchImpl(endpoint, {
@@ -685,18 +804,30 @@ var LiveUploader = class {
685
804
  },
686
805
  body
687
806
  });
688
- } catch {
807
+ } catch (err) {
689
808
  response = void 0;
809
+ failure = err instanceof Error ? err.message : String(err);
690
810
  }
691
811
  if (response) {
692
812
  if (response.status === 401) return "unauthorized";
693
813
  if (response.ok) {
694
814
  const accepted = await acceptedSessionIds(response);
695
- if (accepted) return accepted.includes(sessionId) ? "accepted" : "rejected";
815
+ if (accepted) {
816
+ if (accepted.includes(sessionId)) return "accepted";
817
+ this.lastRejectStatus = void 0;
818
+ return "rejected";
819
+ }
696
820
  } else if (!RETRYABLE_STATUSES.has(response.status)) {
821
+ this.lastRejectStatus = response.status;
697
822
  return "rejected";
698
823
  }
699
824
  }
825
+ if (this.build !== void 0) {
826
+ const why = response === void 0 ? failure : `the gateway answered ${response.status}`;
827
+ this.stderr(`live upload of session ${sessionId} failed: ${why}${this.stopping ? "" : " \xB7 retrying"}
828
+ `);
829
+ }
830
+ if (this.stopping) return "unreachable";
700
831
  await this.sleepImpl(Math.max(retryAfterMs(response), delayMs));
701
832
  delayMs = Math.min(delayMs * 2, RETRY_MAX_DELAY_MS);
702
833
  }
@@ -1683,4 +1814,4 @@ ${C.yellow}!${C.reset} batch ${shippedBatches + 1}/${batches.length} accounting
1683
1814
  }
1684
1815
  }
1685
1816
 
1686
- export { CHUNK_PART_TARGET_BYTES, LiveUploader, RETRYABLE_STATUSES, SyncConfigError, SyncTransportError, isLoopbackUrl, resolveTier, runSync, staleBuildRefusal, staleBuildWarning };
1817
+ export { CHUNK_PART_TARGET_BYTES, LiveUploader, RETRYABLE_STATUSES, SyncConfigError, SyncTransportError, detectCi, installScrubContext, isLoopbackUrl, resolveTier, runSync, staleBuildRefusal, staleBuildWarning };
@@ -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';