@outerlayer/cli 0.17.0 → 0.19.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 (160) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +36 -2
  3. package/dist/agent-setup-TPR4BBFV.js +27 -0
  4. package/dist/{artifact-link-cmd-2F47LT7F.js → artifact-link-cmd-W7XF5BFB.js} +4 -3
  5. package/dist/{build-BG2YENGK.js → build-TQ6X5PYN.js} +5 -4
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-2D3WSOOY.js → builder-C4QNTYMS.js} +5 -6
  8. package/dist/{check-5XE7XMC4.js → check-UWQAL2MN.js} +56 -52
  9. package/dist/{chunk-R7PF5OOU.js → chunk-3CWUOFV6.js} +21 -14
  10. package/dist/{chunk-4NPZVMJU.js → chunk-3UZTIRLF.js} +60 -4
  11. package/dist/chunk-452TM7J4.js +502 -0
  12. package/dist/{chunk-NNRTPG7X.js → chunk-5GHGAF6P.js} +4 -4
  13. package/dist/{chunk-WVUIRTWA.js → chunk-5MYFOW5V.js} +196 -37
  14. package/dist/{chunk-HGECYFEI.js → chunk-5TN7GLYX.js} +138 -109
  15. package/dist/{chunk-VQYBXPI7.js → chunk-6D7GT22T.js} +5 -5
  16. package/dist/{chunk-G5NPRL2K.js → chunk-6U3MV7TZ.js} +687 -76
  17. package/dist/{chunk-42ZI52JW.js → chunk-6X4SQ5MY.js} +4 -3
  18. package/dist/{chunk-MAK5LYRF.js → chunk-7KSSBQTS.js} +278 -535
  19. package/dist/{chunk-NWQTTSBB.js → chunk-7SJPQWBM.js} +41 -16
  20. package/dist/{chunk-J5M7BSJQ.js → chunk-7VUK5RFS.js} +23 -4
  21. package/dist/{chunk-OZGHL5Y5.js → chunk-7YP7T6GV.js} +2 -2
  22. package/dist/{chunk-TI7B7UEO.js → chunk-AMFWYESY.js} +1 -1
  23. package/dist/{chunk-YRYMNBGQ.js → chunk-ANPNT6PM.js} +2 -1
  24. package/dist/{chunk-4KSQKQXE.js → chunk-BM63HB2M.js} +20 -16
  25. package/dist/{chunk-4Q7OMKAT.js → chunk-BQXFBI7T.js} +81 -5
  26. package/dist/{chunk-ADJRGVZC.js → chunk-BWSUPRDK.js} +1 -1
  27. package/dist/{chunk-3NSNIIBE.js → chunk-CG36IONK.js} +18 -17
  28. package/dist/chunk-CJJDJ7AT.js +56 -0
  29. package/dist/chunk-CRB3POP4.js +34 -0
  30. package/dist/{chunk-LWSJQJC6.js → chunk-DADWEUH3.js} +7 -7
  31. package/dist/{chunk-KG5ECZGJ.js → chunk-DJ3ZUSC3.js} +11 -11
  32. package/dist/{chunk-F47JBIAW.js → chunk-DSF2FWAZ.js} +2 -1
  33. package/dist/{chunk-N5FOE5PS.js → chunk-ECODQ7II.js} +4 -33
  34. package/dist/{chunk-HHJDN6AU.js → chunk-ESVW4MJY.js} +1 -1
  35. package/dist/{chunk-YO4PSLVB.js → chunk-FVMYKL6L.js} +1 -1
  36. package/dist/chunk-G2YNJIGF.js +44 -0
  37. package/dist/{chunk-WUYTWNMA.js → chunk-G3IJ3N6F.js} +5 -3
  38. package/dist/{chunk-QKFB4K7X.js → chunk-GGOMT6KF.js} +1 -1
  39. package/dist/{chunk-N6LURUEF.js → chunk-GOSFARMS.js} +1 -1
  40. package/dist/{chunk-S3NYLI2P.js → chunk-HPJNLETG.js} +93 -38
  41. package/dist/{chunk-IP7BIBXJ.js → chunk-IF2OSI5T.js} +35 -1
  42. package/dist/{chunk-C5Y5ZJJZ.js → chunk-IXYZUUYQ.js} +5 -4
  43. package/dist/chunk-JBJTC3UU.js +35 -0
  44. package/dist/chunk-KYS3TQAG.js +296 -0
  45. package/dist/chunk-LLM3I5YU.js +89 -0
  46. package/dist/{chunk-YU3VKZ5F.js → chunk-LRG3ZMZD.js} +6 -7
  47. package/dist/{chunk-V7NIVOFD.js → chunk-M2ZWWTWZ.js} +1 -1
  48. package/dist/{chunk-ERI5GBNI.js → chunk-MLAAT4S6.js} +3 -3
  49. package/dist/{chunk-O765JR4W.js → chunk-MTP2QEVO.js} +1 -1
  50. package/dist/{chunk-ZM2IMMYN.js → chunk-N2PXGQRL.js} +9 -1
  51. package/dist/{chunk-BWQ66M6N.js → chunk-NFIR3GEE.js} +98 -24
  52. package/dist/{chunk-POJMEEJJ.js → chunk-NNLA7LLQ.js} +1 -1
  53. package/dist/{chunk-PLMTLGYH.js → chunk-NTRCK4NH.js} +5 -4
  54. package/dist/{chunk-22RMZBGW.js → chunk-P53VEAOF.js} +1 -1
  55. package/dist/{chunk-RLYZLUQ7.js → chunk-QEFKA2QD.js} +2 -2
  56. package/dist/{chunk-JXYVA45C.js → chunk-QNLX477Q.js} +1200 -322
  57. package/dist/{chunk-UGP76IZ5.js → chunk-S5PCA3SN.js} +1 -1
  58. package/dist/{chunk-RMWLBUCJ.js → chunk-SADUQSO4.js} +1 -1
  59. package/dist/{chunk-GQD22KKN.js → chunk-T2Q7ISPE.js} +2 -1
  60. package/dist/chunk-TUSYOL2O.js +113 -0
  61. package/dist/{chunk-NBGDBTO2.js → chunk-TWF3RICI.js} +9 -8
  62. package/dist/{chunk-ONKJUM6R.js → chunk-UVG35MWF.js} +1 -1
  63. package/dist/{chunk-KMDLFI4P.js → chunk-VMJPFQNE.js} +1 -1
  64. package/dist/chunk-VRRGENS4.js +144 -0
  65. package/dist/{chunk-PTW6W5NR.js → chunk-VYAL7PUE.js} +1 -1
  66. package/dist/{chunk-OHVJA253.js → chunk-WFSUUUAN.js} +47 -30
  67. package/dist/{chunk-RSNSZ2LJ.js → chunk-X5H2WYMB.js} +1 -1
  68. package/dist/{chunk-HYZRY4KZ.js → chunk-XNGMQ27R.js} +16 -6
  69. package/dist/chunk-XSZD4AZ6.js +490 -0
  70. package/dist/chunk-YQR6E6OV.js +109 -0
  71. package/dist/{chunk-XCK2YAY5.js → chunk-YVZJ6GKF.js} +3 -2
  72. package/dist/{chunk-2MNPHL23.js → chunk-ZHAUSEEN.js} +38 -15
  73. package/dist/claude-launcher-FPPHZPMR.js +115 -0
  74. package/dist/{cli-A76AXELQ.js → cli-HROW5T7X.js} +567 -285
  75. package/dist/{command-R2QCVX55.js → command-OEAV7BVX.js} +42 -40
  76. package/dist/{config-N3C6DFQA.js → config-CLSGABD5.js} +2 -3
  77. package/dist/{connect-cmd-JBKAQNSF.js → connect-cmd-UNYKGDAL.js} +10 -9
  78. package/dist/context-cleanup-HSVYDGMI.js +9 -0
  79. package/dist/control-plane-launch-NYVDJESK.js +216 -0
  80. package/dist/{dist-LKDWQWZ7.js → dist-WO7NOJNG.js} +2 -2
  81. package/dist/{docker-4J77Q2BF.js → docker-BFU3AQGY.js} +7 -8
  82. package/dist/{doctor-4TAIARIG.js → doctor-23BBJWBX.js} +48 -42
  83. package/dist/{emit-artifact-cmd-MPZVR56N.js → emit-artifact-cmd-O6SCM7TV.js} +27 -24
  84. package/dist/emit-cmd-7SP3I6UZ.js +14 -0
  85. package/dist/{emit-criteria-cmd-EFGYI23V.js → emit-criteria-cmd-LQNERZRV.js} +17 -16
  86. package/dist/{emit-finding-cmd-5GF3V4LR.js → emit-finding-cmd-AJPKHIOV.js} +18 -17
  87. package/dist/{emit-result-cmd-I4OADKMD.js → emit-result-cmd-RUICOKWQ.js} +22 -19
  88. package/dist/emit-step-cmd-347XNGPQ.js +26 -0
  89. package/dist/{exec-client-CQV746UF.js → exec-client-7UMESIE2.js} +3 -4
  90. package/dist/governing-source-V5EEGPTA.js +34 -0
  91. package/dist/guest-init-KPBQOFE5.js +9 -0
  92. package/dist/{hook-fast-R4FVSZ2H.js → hook-fast-YAZG5MDX.js} +5 -2
  93. package/dist/host-key-U4B5QETR.js +8 -0
  94. package/dist/{import-capture-cmd-EQ35EARA.js → import-capture-cmd-KKFFOGWP.js} +7 -5
  95. package/dist/{import-ruler-cmd-BGAZXCQM.js → import-ruler-cmd-5P6JOXQN.js} +5 -3
  96. package/dist/index.js +8 -4
  97. package/dist/{init-PWU5YVL7.js → init-LWHDMZQG.js} +40 -38
  98. package/dist/init-MOINY2DD.js +53 -0
  99. package/dist/{init-cmd-XAVO7HYZ.js → init-cmd-HSMRID6A.js} +75 -30
  100. package/dist/{init-update-CVCWD6VS.js → init-update-LWX5MPPR.js} +29 -29
  101. package/dist/{install-HDBIPHTX.js → install-4SEFIIW2.js} +4 -5
  102. package/dist/{install-cmd-5HYMXLEW.js → install-cmd-QDOTR4OM.js} +5 -4
  103. package/dist/{login-browser-QZCS3WW6.js → login-browser-DX35MARZ.js} +5 -4
  104. package/dist/{logout-cmd-QAUFDJ6J.js → logout-cmd-5V5MMBSY.js} +3 -2
  105. package/dist/{logs-H55NWW4H.js → logs-AMLKC3VP.js} +3 -1
  106. package/dist/loop-SYYPVFYW.js +77 -0
  107. package/dist/machine-6X63G2KH.js +48 -0
  108. package/dist/{mcp-install-cmd-FDTPQQS6.js → mcp-install-cmd-GGWB3JJ2.js} +3 -2
  109. package/dist/{mcp-serve-cmd-3KVYEUXG.js → mcp-serve-cmd-N3UTY6EE.js} +11 -9
  110. package/dist/paths-7XP63OAX.js +7 -0
  111. package/dist/pending-532ABZYC.js +8 -0
  112. package/dist/{pidfile-UZRH774M.js → pidfile-3DM4OBKO.js} +4 -2
  113. package/dist/{record-C43U4PKS.js → record-3WP6V2K5.js} +3 -2
  114. package/dist/{runner-env-EN7YE7QX.js → runner-env-FRZFFHDF.js} +5 -6
  115. package/dist/{runner-key-6SLBI7PP.js → runner-key-276SJU5R.js} +40 -38
  116. package/dist/session-sender-GGIY5OAX.js +36 -0
  117. package/dist/{pending-MXLSRYMO.js → shell-function-NRD4KVUK.js} +1 -2
  118. package/dist/spec-cmd-SIZBRN7D.js +115 -0
  119. package/dist/{starter-pack-KF66HGZR.js → starter-pack-6LQVLBIA.js} +7 -5
  120. package/dist/{status-7VNQN5PW.js → status-NAK6DYSF.js} +46 -42
  121. package/dist/{statusline-fast-SVTMBMD7.js → statusline-fast-KN3BX67H.js} +2 -1
  122. package/dist/sync-cmd-G7GF4UTW.js +35 -0
  123. package/dist/{watch-23HSAEI6.js → watch-EVM5GSMP.js} +22 -15
  124. package/dist/{work-claim-cmd-LKL3GHFQ.js → work-claim-cmd-3J3QW56U.js} +26 -29
  125. package/dist/work-cmd-5EPPD33Y.js +24 -0
  126. package/dist/{work-comment-cmd-AWHP56M2.js → work-comment-cmd-2ACOZQAE.js} +16 -15
  127. package/dist/{work-launch-R5HTAP6X.js → work-launch-LEQ2MPM3.js} +3 -1
  128. package/dist/work-logs-cmd-QDD2NMJL.js +60 -0
  129. package/dist/{work-open-pr-cmd-IOM4AVQQ.js → work-open-pr-cmd-XNCEI4ZM.js} +18 -17
  130. package/dist/work-pr-cmd-H4OQR26N.js +25 -0
  131. package/package.json +3 -2
  132. package/skill-pack/maintained/outerlayer-amend/SKILL.md +4 -2
  133. package/skill-pack/maintained/outerlayer-cli/SKILL.md +9 -2
  134. package/skill-pack/maintained/outerlayer-cli/references/find-out-why-a-build-ended.md +76 -0
  135. package/skill-pack/shipped.json +18 -2
  136. package/skill-pack/template/build/SKILL.md +23 -10
  137. package/skill-pack/template/build/references/agent-briefs.md +3 -1
  138. package/skill-pack/template/build/references/criteria-judge.md +27 -0
  139. package/skill-pack/template/build/references/release.md +22 -29
  140. package/skill-pack/template/spec/SKILL.md +35 -10
  141. package/skill-pack/validators/acceptance-criteria.yaml +25 -26
  142. package/dist/agent-setup-T624CWPD.js +0 -27
  143. package/dist/chunk-6Y5RUTHO.js +0 -39
  144. package/dist/chunk-BYT5O5RV.js +0 -61
  145. package/dist/chunk-WTE3MQML.js +0 -133
  146. package/dist/chunk-XCCLFVXM.js +0 -401
  147. package/dist/chunk-YZ5F4PIS.js +0 -797
  148. package/dist/context-adopt-NFHCLVUB.js +0 -108
  149. package/dist/context-materialize-IV2TUUFO.js +0 -22
  150. package/dist/emit-cmd-IJ3GVRFD.js +0 -12
  151. package/dist/guest-init-LJP5GPZF.js +0 -9
  152. package/dist/host-key-YMLXY6QB.js +0 -7
  153. package/dist/init-6XPDRDTC.js +0 -51
  154. package/dist/loop-FK3LPMMZ.js +0 -73
  155. package/dist/machine-SQXEBAM2.js +0 -46
  156. package/dist/paths-OYKMVYJP.js +0 -6
  157. package/dist/session-sender-FO3LCREV.js +0 -29
  158. package/dist/sync-cmd-GVPPFZ3G.js +0 -28
  159. package/dist/work-cmd-Z2WXLZPH.js +0 -23
  160. package/dist/work-pr-cmd-HNEUIEN7.js +0 -24
@@ -1,23 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { LaunchFilter } from './chunk-HHJDN6AU.js';
3
+ import { uploadSpooledSteps } from './chunk-KYS3TQAG.js';
4
+ import { LaunchFilter } from './chunk-ESVW4MJY.js';
4
5
  import { RepoFilter } from './chunk-TBT347UY.js';
6
+ import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, acquireArtifactSpoolLock, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-G3IJ3N6F.js';
7
+ import { writeSyncStatus, spoolDir } from './chunk-NFIR3GEE.js';
5
8
  import { hookExecSpoolPath } from './chunk-F7CU5ABH.js';
6
9
  import { applyReportedCost } from './chunk-BKO6JEZI.js';
7
- import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, acquireArtifactSpoolLock, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-WUYTWNMA.js';
8
- import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-JXYVA45C.js';
9
- import { C } from './chunk-YRYMNBGQ.js';
10
- import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-GQD22KKN.js';
10
+ import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-QNLX477Q.js';
11
+ import { C } from './chunk-ANPNT6PM.js';
12
+ import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-T2Q7ISPE.js';
13
+ import { defaultFetch } from './chunk-FVMYKL6L.js';
14
+ import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-NTRCK4NH.js';
11
15
  import { readLatestProvenanceForSession, readContextProvenance } from './chunk-ZJSNLVCE.js';
12
- import { defaultFetch } from './chunk-YO4PSLVB.js';
13
- import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-PLMTLGYH.js';
14
- import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-J5M7BSJQ.js';
15
- import { readCloudConfig, cloudConfigPath, writeCloudConfig } from './chunk-EABW6AJQ.js';
16
- import { signerFor, signRunnerRequest } from './chunk-V7NIVOFD.js';
17
- import { writeSyncStatus, spoolDir } from './chunk-BWQ66M6N.js';
18
- import { removeJournalHooks } from './chunk-XCCLFVXM.js';
19
16
  import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
17
+ import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-7VUK5RFS.js';
18
+ import { readCloudConfig, cloudConfigPath, writeCloudConfig } from './chunk-EABW6AJQ.js';
19
+ import { cliInvocation } from './chunk-CRB3POP4.js';
20
+ import { removeJournalHooks } from './chunk-TUSYOL2O.js';
20
21
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
22
+ import { signerFor, signRunnerRequest } from './chunk-M2ZWWTWZ.js';
21
23
  import { dirname, basename, join } from 'path';
22
24
  import { statSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync, rmSync } from 'fs';
23
25
  import { execFileSync } from 'child_process';
@@ -668,7 +670,7 @@ var LiveUploader = class {
668
670
  const credential = this.env.OUTERLAYER_API_KEY;
669
671
  const appId = this.env.OUTERLAYER_APP_ID;
670
672
  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.
673
+ 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 \`${cliInvocation()} sync\` runs.
672
674
  `);
673
675
  return false;
674
676
  }
@@ -724,7 +726,7 @@ var LiveUploader = class {
724
726
  this.stopped = true;
725
727
  this.onUnauthorized?.();
726
728
  this.stderr(
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.
729
+ destination.credential.startsWith("olu_") ? `live upload stopped: the login was refused (expired or revoked). No session streams from this daemon until you run \`${cliInvocation()} login\` and it restarts.
728
730
  ` : `live upload stopped: the API key was refused. No session streams from this daemon until it restarts with a valid key.
729
731
  `
730
732
  );
@@ -739,7 +741,7 @@ var LiveUploader = class {
739
741
  lastError: reason,
740
742
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
741
743
  });
742
- this.stderr(`live upload stopped for session ${prepared.id}: ${reason}. The next \`outerlayer sync\` uploads it whole.
744
+ this.stderr(`live upload stopped for session ${prepared.id}: ${reason}. The next \`${cliInvocation()} sync\` uploads it whole.
743
745
  `);
744
746
  return true;
745
747
  }
@@ -1439,7 +1441,7 @@ async function runSyncInner(opts, stats) {
1439
1441
  if (opts.quiet || shippedBatches === 0) return;
1440
1442
  process.stderr.write(
1441
1443
  `
1442
- ${C.yellow}!${C.reset} progress saved: ${synced} session(s) in ${shippedBatches}/${batches.length} batch(es) shipped before the failure \u2014 re-run ${C.dim}outerlayer sync${C.reset} to resume from there.
1444
+ ${C.yellow}!${C.reset} progress saved: ${synced} session(s) in ${shippedBatches}/${batches.length} batch(es) shipped before the failure \u2014 re-run ${C.dim}${cliInvocation()} sync${C.reset} to resume from there.
1443
1445
  `
1444
1446
  );
1445
1447
  };
@@ -1796,6 +1798,29 @@ ${C.yellow}!${C.reset} batch ${shippedBatches + 1}/${batches.length} accounting
1796
1798
  }
1797
1799
  }
1798
1800
  releaseArtifactLock();
1801
+ const stepPass = await uploadSpooledSteps({
1802
+ home,
1803
+ url,
1804
+ apiKey,
1805
+ appId,
1806
+ kind: resolved.kind,
1807
+ onlyItem: itemScope?.item,
1808
+ fetchImpl,
1809
+ quiet: opts.quiet,
1810
+ lockWaitMs: opts.artifactLockWaitMs
1811
+ });
1812
+ if (stepPass !== void 0) {
1813
+ if (stepPass.uploaded > 0) stats.contacted = true;
1814
+ if (!opts.quiet) {
1815
+ process.stderr.write(
1816
+ `${C.dim}steps${C.reset} ${stepPass.uploaded} uploaded \xB7 ${stepPass.pending} queued \xB7 ${stepPass.dropped} dropped
1817
+ `
1818
+ );
1819
+ }
1820
+ if (stepPass.unauthorized !== void 0) {
1821
+ throw new SyncTransportError(stepPass.unauthorized, 401);
1822
+ }
1823
+ }
1799
1824
  if (shippedBatches === batches.length && (opts.url || opts.apiKey || opts.appId)) {
1800
1825
  if (isLoopbackUrl(url)) {
1801
1826
  if (!opts.quiet) {
@@ -21728,12 +21728,13 @@ var UsageSchema = external_exports.looseObject({
21728
21728
  * open string: the provider adds tiers over time. Absent means standard. */
21729
21729
  speed: external_exports.string().min(1).max(SPEED_MAX_LENGTH).optional()
21730
21730
  });
21731
- var INPUT_BAND_BOUNDARIES = [128e3, 2e5, 256e3, 272e3, 512e3];
21731
+ var INPUT_BAND_BOUNDARIES = [1e5, 128e3, 2e5, 256e3, 272e3, 512e3];
21732
21732
  function inputBandOf(totalInput) {
21733
21733
  let band = 0;
21734
21734
  for (const boundary of INPUT_BAND_BOUNDARIES) if (totalInput >= boundary) band = boundary;
21735
21735
  return band;
21736
21736
  }
21737
+ var BAND_BOUNDARIES_MAX = 64;
21737
21738
  var TOKEN_BUCKETS_MAX = 1024;
21738
21739
  var TokenBucketSchema = external_exports.looseObject({
21739
21740
  model: external_exports.string().min(1).max(BUCKET_MODEL_MAX_LENGTH),
@@ -21950,7 +21951,12 @@ var AgentSessionSchema = external_exports.looseObject({
21950
21951
  /** Token counts so far, per model, speed and input band. On a chunk part
21951
21952
  * or a streamed piece these cover the whole session so far, never just
21952
21953
  * the turns that payload carries. Absent from older writers. */
21953
- buckets: external_exports.array(TokenBucketSchema).max(TOKEN_BUCKETS_MAX).optional()
21954
+ buckets: external_exports.array(TokenBucketSchema).max(TOKEN_BUCKETS_MAX).optional(),
21955
+ /** The input band boundaries `buckets` were grouped by. A price tier whose
21956
+ * threshold falls inside one of these bands cannot be applied from the
21957
+ * buckets alone. Absent from older writers, which used
21958
+ * {@link UNRECORDED_INPUT_BAND_BOUNDARIES}. */
21959
+ bandBoundaries: external_exports.array(count).max(BAND_BOUNDARIES_MAX).optional()
21954
21960
  }),
21955
21961
  /** Filled natively (`pr-link` lines, `git commit` tool results) or by later
21956
21962
  * joins. A session can link MANY pull requests (stacked PRs, long-lived seat
@@ -22273,7 +22279,7 @@ var ArtifactTombstoneRecordSchema = external_exports.looseObject({
22273
22279
  });
22274
22280
  external_exports.union([ArtifactSpoolRecordSchema, ArtifactTombstoneRecordSchema]);
22275
22281
  var EMITTED_RESULTS = ["pass", "fail"];
22276
- var RESERVED_EMIT_NAMES = ["artifact", "criteria", "finding", "findings"];
22282
+ var RESERVED_EMIT_NAMES = ["artifact", "criteria", "finding", "findings", "step"];
22277
22283
  var EmittedNameSchema = external_exports.string().regex(/^[a-z][a-z0-9._-]{0,63}$/).superRefine((name, ctx) => {
22278
22284
  if (RESERVED_EMIT_NAMES.includes(name)) {
22279
22285
  ctx.addIssue({
@@ -22318,6 +22324,19 @@ external_exports.object({
22318
22324
  item: external_exports.object({ number: external_exports.number().int().positive() }).optional(),
22319
22325
  sessionId: external_exports.string().optional()
22320
22326
  }).superRefine((request, ctx) => refuseDuplicateIds(request.criteria, ctx));
22327
+ var STEP_NAME_MAX = 80;
22328
+ var CONTROL_CHARACTER = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
22329
+ var StepNameSchema = external_exports.string().trim().min(1, "name must not be empty").max(STEP_NAME_MAX, `name must be at most ${STEP_NAME_MAX} characters`).refine((name) => !CONTROL_CHARACTER.test(name), {
22330
+ message: "name must be one line, with no line break or control character"
22331
+ });
22332
+ var StepBodySchema = external_exports.object({
22333
+ /** Minted by the CLI once per step; the same id on the same item is the same step. */
22334
+ clientStepId: external_exports.string().uuid(),
22335
+ name: StepNameSchema,
22336
+ item: external_exports.object({ number: external_exports.number().int().positive() }),
22337
+ /** When the agent started the step. The gateway clamps it to the receive time. */
22338
+ startedAt: external_exports.string().datetime({ offset: true })
22339
+ });
22321
22340
  var FINDING_CATEGORIES = ["context", "flaky-test", "tooling", "environment", "defect", "other"];
22322
22341
  var FINDING_RULE_RELATIONS = ["wrong", "broken", "missing"];
22323
22342
  var FINDING_ID_MAX_LENGTH = 64;
@@ -22525,4 +22544,4 @@ xmlchars/xmlns/1.0/ed3.js:
22525
22544
  *)
22526
22545
  */
22527
22546
 
22528
- export { ARTIFACT_KINDS, ARTIFACT_MAX_CAPTION_LENGTH, ARTIFACT_MAX_FILENAME_LENGTH, ARTIFACT_MAX_REPLACES_TARGETS, ArtifactCriterionIdSchema, ArtifactSpoolRecordSchema, ArtifactTombstoneRecordSchema, BUCKET_MODEL_MAX_LENGTH, CAPTURE_TIERS, CriteriaListSchema, EMITTED_RESULTS, EMITTED_RESULT_MAX_BODY_LENGTH, EMITTED_RESULT_MAX_LINK_LENGTH, EVENT_TYPES, EmittedNameSchema, FindingBatchSchema, FindingsResponseSchema, RESERVED_EMIT_NAMES, SAME_PROBLEM_RULES, SCHEMA_VERSION, SPEED_MAX_LENGTH, bannedPathsForTier, bindTests, downconvertSession, inferArtifactKind, inputBandOf, isHumanUserTurn, mediaTypeForArtifactPath, parseAgentSession, parseJunit, parseTestSelector, turnCountBound };
22547
+ export { ARTIFACT_KINDS, ARTIFACT_MAX_CAPTION_LENGTH, ARTIFACT_MAX_FILENAME_LENGTH, ARTIFACT_MAX_REPLACES_TARGETS, ArtifactCriterionIdSchema, ArtifactSpoolRecordSchema, ArtifactTombstoneRecordSchema, BUCKET_MODEL_MAX_LENGTH, CAPTURE_TIERS, CriteriaListSchema, EMITTED_RESULTS, EMITTED_RESULT_MAX_BODY_LENGTH, EMITTED_RESULT_MAX_LINK_LENGTH, EVENT_TYPES, EmittedNameSchema, FindingBatchSchema, FindingsResponseSchema, INPUT_BAND_BOUNDARIES, RESERVED_EMIT_NAMES, SAME_PROBLEM_RULES, SCHEMA_VERSION, SPEED_MAX_LENGTH, StepBodySchema, StepNameSchema, bannedPathsForTier, bindTests, downconvertSession, inferArtifactKind, inputBandOf, isHumanUserTurn, mediaTypeForArtifactPath, parseAgentSession, parseJunit, parseTestSelector, turnCountBound };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { DEFAULT_UNIT_NAME } from './chunk-RLYZLUQ7.js';
3
+ import { DEFAULT_UNIT_NAME } from './chunk-QEFKA2QD.js';
4
4
  import { parseRunnerEnv } from './chunk-6MZSX4M7.js';
5
- import { RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
5
+ import { RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
6
6
  import { existsSync, readFileSync, writeFileSync, renameSync, rmSync } from 'fs';
7
7
  import { join, dirname } from 'path';
8
8
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
3
+ import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
4
4
  import { readlinkSync, realpathSync, mkdirSync, unlinkSync, symlinkSync, renameSync, readFileSync, writeFileSync, rmSync, existsSync, readdirSync } from 'fs';
5
5
  import { join, basename, sep, resolve } from 'path';
6
6
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { cliInvocation } from './chunk-CRB3POP4.js';
3
4
 
4
5
  createRequire(import.meta.url);
5
6
 
@@ -49,6 +50,6 @@ function warnDeprecated(message) {
49
50
  process.stderr.write(`${C.yellow}!${C.reset} ${message}
50
51
  `);
51
52
  }
52
- var API_KEY_FLAG_DEPRECATION = "--api-key is deprecated: a key on the command line lands in shell history and process lists. Run `outerlayer login` once, or set OUTERLAYER_API_KEY.";
53
+ var API_KEY_FLAG_DEPRECATION = `--api-key is deprecated: a key on the command line lands in shell history and process lists. Run \`${cliInvocation()} login\` once, or set OUTERLAYER_API_KEY.`;
53
54
 
54
55
  export { API_KEY_FLAG_DEPRECATION, C, NO_COLOR_FLAG, stripNoColor, warnDeprecated };
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { revokeTokenOnDashboard } from './chunk-N6LURUEF.js';
4
- import { C } from './chunk-YRYMNBGQ.js';
5
- import { readCloudConfig, writeCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
3
+ import { revokeTokenOnDashboard } from './chunk-GOSFARMS.js';
4
+ import { C } from './chunk-ANPNT6PM.js';
6
5
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
6
+ import { readCloudConfig, writeCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
7
+ import { cliInvocation } from './chunk-CRB3POP4.js';
7
8
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
8
9
  import { generateKeyPairSync, privateDecrypt, constants, createPrivateKey } from 'crypto';
9
10
  import { spawn } from 'child_process';
@@ -18,7 +19,7 @@ var LoginError = class extends Error {
18
19
  };
19
20
  function runLogin(opts) {
20
21
  const apiKey = opts.apiKey.trim();
21
- if (apiKey.length === 0) throw new LoginError("no API key given \u2014 pipe it on stdin, or run outerlayer login with no key on stdin to sign in by browser");
22
+ if (apiKey.length === 0) throw new LoginError(`no API key given \u2014 pipe it on stdin, or run ${cliInvocation()} login with no key on stdin to sign in by browser`);
22
23
  if (/\s/.test(apiKey)) throw new LoginError("the API key must be a single token with no spaces or line breaks");
23
24
  const url = opts.url?.trim() || void 0;
24
25
  const appId = opts.appId?.trim() || void 0;
@@ -229,7 +230,7 @@ function decryptToken(privateKeyPem, encryptedToken) {
229
230
  Buffer.from(encryptedToken, "base64")
230
231
  ).toString("utf8");
231
232
  } catch {
232
- throw new LoginError("could not decrypt the token the dashboard sent; run outerlayer login again");
233
+ throw new LoginError(`could not decrypt the token the dashboard sent; run ${cliInvocation()} login again`);
233
234
  }
234
235
  }
235
236
  function normalizeDashboard(raw) {
@@ -246,7 +247,7 @@ function approveLink(dashboard, code) {
246
247
  return `${dashboard}/cli/login?code=${encodeURIComponent(code)}`;
247
248
  }
248
249
  function waitingDocument(link, code, id) {
249
- return JSON.stringify({ status: "waiting", url: link, code, check: `outerlayer login --check ${id}` }) + "\n";
250
+ return JSON.stringify({ status: "waiting", url: link, code, check: `${cliInvocation()} login --check ${id}` }) + "\n";
250
251
  }
251
252
  async function finishApproved(flags, deps, home, dashboard, approved, privateKeyPem) {
252
253
  const accountToken = decryptToken(privateKeyPem, approved.encryptedToken);
@@ -257,7 +258,7 @@ async function finishApproved(flags, deps, home, dashboard, approved, privateKey
257
258
  const revoked = await revokeTokenOnDashboard(deps.fetchImpl, dashboard, accountToken);
258
259
  return fail(
259
260
  deps,
260
- `could not save the login: ${err instanceof Error ? err.message : String(err)}. ` + (revoked === "revoked" ? "The token was revoked; run outerlayer login again." : "The token could not be revoked; revoke it on the CLI logins list at /profile/security.")
261
+ `could not save the login: ${err instanceof Error ? err.message : String(err)}. ` + (revoked === "revoked" ? `The token was revoked; run ${cliInvocation()} login again.` : "The token could not be revoked; revoke it on the CLI logins list at /profile/security.")
261
262
  );
262
263
  }
263
264
  if (before.accountToken && before.accountToken !== accountToken) {
@@ -279,9 +280,12 @@ async function finishApproved(flags, deps, home, dashboard, approved, privateKey
279
280
  }
280
281
  function nextAfterLogin(cwd) {
281
282
  const dirs = findGitDirs(cwd);
282
- if (dirs === void 0) return "Next: in your repository, run `outerlayer init --factory <org>/<factory>`.\n";
283
- if (existsSync(join(dirs.repoRoot, ".outerlayer"))) return "Next: run `outerlayer connect` to choose a factory.\n";
284
- return "Next: run `outerlayer init --factory <org>/<factory>` to set up this repository.\n";
283
+ if (dirs === void 0) return `Next: in your repository, run \`${cliInvocation()} init --factory <org>/<factory>\`.
284
+ `;
285
+ if (existsSync(join(dirs.repoRoot, ".outerlayer"))) return `Next: run \`${cliInvocation()} connect\` to choose a factory.
286
+ `;
287
+ return `Next: run \`${cliInvocation()} init --factory <org>/<factory>\` to set up this repository.
288
+ `;
285
289
  }
286
290
  function fail(deps, message) {
287
291
  deps.stderr.write(`${C.red}\u2717${C.reset} ${message}
@@ -301,10 +305,10 @@ async function runPastedKey(flags, deps, key, home) {
301
305
  }
302
306
  async function runCheck(flags, deps, home, id) {
303
307
  const pending = readPending(home, id);
304
- if (!pending) return fail(deps, `no pending login ${id}; run outerlayer login to start one`);
308
+ if (!pending) return fail(deps, `no pending login ${id}; run ${cliInvocation()} login to start one`);
305
309
  if (Date.parse(pending.expires_at) <= deps.now().getTime()) {
306
310
  deletePending(home, id);
307
- return fail(deps, "the login link expired; run outerlayer login again");
311
+ return fail(deps, `the login link expired; run ${cliInvocation()} login again`);
308
312
  }
309
313
  const result = await pollLogin(deps, pending.dashboard, pending.id);
310
314
  switch (result.kind) {
@@ -317,7 +321,7 @@ async function runCheck(flags, deps, home, id) {
317
321
  return fail(deps, "the login was denied");
318
322
  case "expired":
319
323
  deletePending(home, id);
320
- return fail(deps, "the login link expired; run outerlayer login again");
324
+ return fail(deps, `the login link expired; run ${cliInvocation()} login again`);
321
325
  case "unavailable":
322
326
  deps.stderr.write(`could not check the login yet: ${result.message}
323
327
  `);
@@ -376,7 +380,7 @@ Waiting for approval...
376
380
  case "denied":
377
381
  return fail(deps, "the login was denied");
378
382
  case "expired":
379
- return fail(deps, "the login link expired; run outerlayer login again");
383
+ return fail(deps, `the login link expired; run ${cliInvocation()} login again`);
380
384
  case "unavailable":
381
385
  case "error":
382
386
  failures += 1;
@@ -392,7 +396,7 @@ Waiting for approval...
392
396
  }
393
397
  const untilExpiryMs = Math.max(0, expiresAt - deps.now().getTime());
394
398
  await deps.sleep(Math.min(waitS * 1e3, untilExpiryMs));
395
- if (deps.now().getTime() >= expiresAt) return fail(deps, "the login link expired; run outerlayer login again");
399
+ if (deps.now().getTime() >= expiresAt) return fail(deps, `the login link expired; run ${cliInvocation()} login again`);
396
400
  }
397
401
  }
398
402
  async function runLoginCommand(flags, deps) {
@@ -414,7 +418,7 @@ async function runLoginCommand(flags, deps) {
414
418
  return EXIT_USAGE;
415
419
  }
416
420
  if (flags.noInput) {
417
- return fail(deps, 'no API key on stdin and --no-input forbids prompting \u2014 pipe the key: echo "$KEY" | outerlayer login');
421
+ return fail(deps, `no API key on stdin and --no-input forbids prompting \u2014 pipe the key: echo "$KEY" | ${cliInvocation()} login`);
418
422
  }
419
423
  purgeExpiredPending(home, deps.now());
420
424
  return await runBrowserLogin(flags, deps, home);
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { authorEnvironment, withHooksPath } from './chunk-BYT5O5RV.js';
4
3
  import { existsSync, unlinkSync, chmodSync } from 'fs';
5
4
  import { request as request$1, createServer } from 'http';
6
5
  import { request } from 'https';
@@ -345,6 +344,61 @@ async function startBuildServices(input) {
345
344
  }
346
345
  }
347
346
 
347
+ // src/runner/commit-identity.ts
348
+ var NOREPLY_SUFFIX = "@users.noreply.github.com";
349
+ var MAX_LENGTH = 200;
350
+ function parseIdentity(value) {
351
+ if (typeof value !== "object" || value === null) return void 0;
352
+ const { name, email } = value;
353
+ if (typeof name !== "string" || typeof email !== "string") return void 0;
354
+ if (name.trim() === "" || name.length > MAX_LENGTH || /[\r\n\0<>]/.test(name)) return void 0;
355
+ if (email.length > MAX_LENGTH || !email.endsWith(NOREPLY_SUFFIX) || /[\s\0<>]/.test(email) || email.length === NOREPLY_SUFFIX.length) return void 0;
356
+ return { name, email };
357
+ }
358
+ function parseClaimIdentity(data) {
359
+ const author = parseIdentity(data.commitAuthor);
360
+ if (author === void 0) return void 0;
361
+ const coAuthor = parseIdentity(data.coAuthor);
362
+ return coAuthor === void 0 ? { author } : { author, coAuthor };
363
+ }
364
+ function authorEnvironment(identity) {
365
+ if (identity === void 0) return {};
366
+ return {
367
+ GIT_AUTHOR_NAME: identity.name,
368
+ GIT_AUTHOR_EMAIL: identity.email,
369
+ GIT_COMMITTER_NAME: identity.name,
370
+ GIT_COMMITTER_EMAIL: identity.email
371
+ };
372
+ }
373
+ function configCount(env) {
374
+ const raw = String(env.GIT_CONFIG_COUNT);
375
+ return /^[0-9]+$/.test(raw) ? Number(raw) : 0;
376
+ }
377
+ function withGitConfig(env, key, value) {
378
+ const at = configCount(env);
379
+ return {
380
+ ...env,
381
+ GIT_CONFIG_COUNT: String(at + 1),
382
+ [`GIT_CONFIG_KEY_${at}`]: key,
383
+ [`GIT_CONFIG_VALUE_${at}`]: value
384
+ };
385
+ }
386
+ function tokenHeader(token) {
387
+ return `Authorization: Basic ${Buffer.from(`x-access-token:${token}`).toString("base64")}`;
388
+ }
389
+ function withTokenHeader(env, url, token) {
390
+ return withGitConfig(env, `http.${url}.extraHeader`, tokenHeader(token));
391
+ }
392
+ function withHooksPath(env, dir) {
393
+ return withGitConfig(env, "core.hooksPath", dir);
394
+ }
395
+ function commitIdentityRecord(identity) {
396
+ return {
397
+ author: identity === void 0 ? "host" : "app",
398
+ coAuthor: identity?.coAuthor !== void 0 && identity.hooksPath !== void 0 ? "credited" : "none"
399
+ };
400
+ }
401
+
348
402
  // src/runner/repositories.ts
349
403
  function parseClaimedRepositories(value) {
350
404
  if (!Array.isArray(value) || value.length === 0) return void 0;
@@ -372,10 +426,19 @@ function primaryOf(repositories) {
372
426
  var RELAY_PORT = 3128;
373
427
  var JOB_MOUNT = "/outerlayer/job";
374
428
  var EVAL_INPUT_DIR = `${JOB_MOUNT}/eval-input`;
429
+ var BUILD_HOME = "/build/home";
375
430
  var CHECKOUT_DIR = "/build/work/checkout";
376
431
  var REPOS_DIR = "/build/work/repos";
377
432
  function checkoutPath(entry) {
378
- return entry.primary ? CHECKOUT_DIR : `${REPOS_DIR}/${entry.repository}`;
433
+ return entry.primary ? CHECKOUT_DIR : repositoryPath(entry.repository);
434
+ }
435
+ function repositoryPath(repository) {
436
+ return `${REPOS_DIR}/${repository.toLowerCase()}`;
437
+ }
438
+ function lifecycleWorkdir(repositories, governingRepository) {
439
+ const governing = governingRepository?.toLowerCase();
440
+ const entry = governing === void 0 ? void 0 : repositories.find((candidate) => candidate.repository.toLowerCase() === governing);
441
+ return entry === void 0 ? CHECKOUT_DIR : checkoutPath(entry);
379
442
  }
380
443
  var MAX_HOSTS = 200;
381
444
  function tokenVariables() {
@@ -404,10 +467,16 @@ function proxyEnvironment(proxyUrl, alsoNoProxy) {
404
467
  YARN_HTTP_PROXY: proxyUrl
405
468
  };
406
469
  }
470
+ var PROXY_WARNING_FLAG = "--disable-warning=UNDICI-EHPA";
471
+ function withProxyWarningHidden(options) {
472
+ const given = options?.trim() ?? "";
473
+ if (given.split(/\s+/).includes(PROXY_WARNING_FLAG)) return given;
474
+ return given === "" ? PROXY_WARNING_FLAG : `${given} ${PROXY_WARNING_FLAG}`;
475
+ }
407
476
  function runnerLiterals(repository, repositories = []) {
408
477
  return {
409
478
  OUTERLAYER_JOB_DIR: JOB_MOUNT,
410
- HOME: "/build/home",
479
+ HOME: BUILD_HOME,
411
480
  TMPDIR: "/tmp",
412
481
  ...proxyEnvironment(PROXY_URL),
413
482
  GIT_TERMINAL_PROMPT: "0",
@@ -466,6 +535,11 @@ function buildEnvironment(input) {
466
535
  passed[name] = value;
467
536
  variables.push(name);
468
537
  }
538
+ const nodeOptions = {};
539
+ if (input.imageEnv !== void 0) {
540
+ if (passed.NODE_OPTIONS !== void 0) passed.NODE_OPTIONS = withProxyWarningHidden(passed.NODE_OPTIONS);
541
+ else nodeOptions.NODE_OPTIONS = withProxyWarningHidden(recipe.NODE_OPTIONS ?? input.imageEnv.NODE_OPTIONS);
542
+ }
469
543
  const destinations = destinationEnvironment(input.config.build?.destinations, containerLocalAddress);
470
544
  const builtInLiterals = builtIns ? builtInEnvironment(containerBuiltInAddress, claudeCredential(input.hostEnv)) : {};
471
545
  const hooksPath = input.identity?.hooksPath;
@@ -483,6 +557,7 @@ function buildEnvironment(input) {
483
557
  return {
484
558
  literals: {
485
559
  ...recipe,
560
+ ...nodeOptions,
486
561
  ...destinations,
487
562
  ...runnerLiterals(input.repository, repositoriesOf({ repositories: input.repositories, repository: input.repository, branch: input.branch })),
488
563
  ...builtInLiterals,
@@ -502,7 +577,8 @@ function checkEnvironment(input) {
502
577
  repository: input.repository,
503
578
  hostEnv: input.hostEnv,
504
579
  containerEnv: input.containerEnv,
505
- builtIns: false
580
+ builtIns: false,
581
+ imageEnv: input.imageEnv
506
582
  });
507
583
  const withheld = /* @__PURE__ */ new Set(["OUTERLAYER_URL", "OUTERLAYER_API_KEY", ...CLAUDE_CREDENTIAL_VARIABLES]);
508
584
  const literals = { OUTERLAYER_EVAL_INPUT: EVAL_INPUT_DIR };
@@ -544,4 +620,4 @@ function withTunnelRecord(environment, record, onlyWhenUsed = false) {
544
620
  };
545
621
  }
546
622
 
547
- export { AGENT_CREDENTIAL_MISSING, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, EVAL_INPUT_DIR, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, buildEnvironment, builtInEnvironment, checkEnvironment, checkoutPath, claudeCredential, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, parseClaimedRepositories, parseIsolation, primaryOf, proxyEnvironment, repositoriesOf, resolveDestinations, sharedUserEnvironment, startBuildServices, withTunnelRecord };
623
+ export { AGENT_CREDENTIAL_MISSING, BUILD_HOME, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, EVAL_INPUT_DIR, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, authorEnvironment, buildEnvironment, builtInEnvironment, checkEnvironment, checkoutPath, claudeCredential, commitIdentityRecord, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, lifecycleWorkdir, parseClaimIdentity, parseClaimedRepositories, parseIsolation, primaryOf, proxyEnvironment, repositoriesOf, repositoryPath, resolveDestinations, sharedUserEnvironment, startBuildServices, tokenHeader, withGitConfig, withHooksPath, withProxyWarningHidden, withTokenHeader, withTunnelRecord };
@@ -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 = 17;
7
+ var RUNNER_PROTOCOL = 20;
8
8
 
9
9
  export { RUNNER_PROTOCOL };
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { sanitizeTerminal } from './chunk-WUYTWNMA.js';
4
- import { remoteLookupFailed } from './chunk-JXYVA45C.js';
5
- import { DEFAULT_DASHBOARD } from './chunk-4KSQKQXE.js';
6
- import { resolveGatewayCredentials } from './chunk-PLMTLGYH.js';
7
- import { readCloudConfig } from './chunk-EABW6AJQ.js';
3
+ import { sanitizeTerminal } from './chunk-G3IJ3N6F.js';
4
+ import { DEFAULT_DASHBOARD } from './chunk-BM63HB2M.js';
5
+ import { remoteLookupFailed } from './chunk-QNLX477Q.js';
6
+ import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
8
7
  import { writeRepoConnection, findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
8
+ import { readCloudConfig } from './chunk-EABW6AJQ.js';
9
+ import { cliInvocation } from './chunk-CRB3POP4.js';
9
10
  import { execFileSync } from 'child_process';
10
11
  import { createInterface } from 'readline/promises';
11
12
 
@@ -53,7 +54,7 @@ function notLinkedText(factoryName, repository, url) {
53
54
  Link it on the factory's Work page: ${url}
54
55
  1. Connect GitHub repository, and grant the App access to ${name}.
55
56
  2. Link repository, and pick ${name} and its default branch.
56
- Then run \`outerlayer connect\` again.
57
+ Then run \`${cliInvocation()} connect\` again.
57
58
  `;
58
59
  }
59
60
 
@@ -151,7 +152,7 @@ async function fetchFactories(fetchImpl, url, token, repository) {
151
152
  return { ok: false, result: result(1, "failed", message, message) };
152
153
  }
153
154
  if (res.status === 401) {
154
- const message = "the gateway refused the login. Run `outerlayer login` to sign in again.";
155
+ const message = `the gateway refused the login. Run \`${cliInvocation()} login\` to sign in again.`;
155
156
  return { ok: false, result: result(1, "failed", message, message) };
156
157
  }
157
158
  if (!res.ok) {
@@ -160,7 +161,7 @@ async function fetchFactories(fetchImpl, url, token, repository) {
160
161
  }
161
162
  const factories = parseFactories(await res.json().catch(() => null));
162
163
  if (factories === void 0) {
163
- const message = `${url} answered, but the reply is not a list of factories. Check the gateway address with \`outerlayer doctor\`, then run \`outerlayer connect\` again.`;
164
+ const message = `${url} answered, but the reply is not a list of factories. Check the gateway address with \`${cliInvocation()} doctor\`, then run \`${cliInvocation()} connect\` again.`;
164
165
  return { ok: false, result: result(1, "failed", `${url} did not answer with a factory list`, message) };
165
166
  }
166
167
  return { ok: true, factories };
@@ -205,7 +206,7 @@ ${listText(factories, repository)}`;
205
206
  if (!deps.isTerminal) {
206
207
  const why = linked.length > 1 ? `${repository} is linked to more than one factory you can use` : `you can use more than one factory, and none is the only one ${repository} is linked to`;
207
208
  const message = `${why}, and there is no terminal to ask on.
208
- Run \`outerlayer connect --factory <org>/<factory>\` with one of:
209
+ Run \`${cliInvocation()} connect --factory <org>/<factory>\` with one of:
209
210
  ${listText(factories, repository)}`;
210
211
  return result(1, "failed", "more than one factory fits; pass --factory", message);
211
212
  }
@@ -226,18 +227,18 @@ ${listText(factories, repository)}`;
226
227
  }))
227
228
  });
228
229
  const factory = pool.find((f) => f.id === picked);
229
- if (!factory) return result(1, "failed", "no factory was chosen", "no factory was chosen. Run `outerlayer connect` again, or pass --factory <org>/<factory>.");
230
+ if (!factory) return result(1, "failed", "no factory was chosen", `no factory was chosen. Run \`${cliInvocation()} connect\` again, or pass --factory <org>/<factory>.`);
230
231
  return { factory, reason: "prompt" };
231
232
  }
232
233
  async function runConnect(flags, deps) {
233
234
  const creds = resolveGatewayCredentials({ home: deps.home, env: deps.env, cwd: deps.cwd });
234
235
  if (creds.credential === void 0) {
235
- const message = "no saved credential. Run `outerlayer login` to sign in, then run `outerlayer connect` again.";
236
- return { ...result(1, "skipped", "no credential; run `outerlayer login` first", message), next: "Run `outerlayer login`, then `outerlayer init` again." };
236
+ const message = `no saved credential. Run \`${cliInvocation()} login\` to sign in, then run \`${cliInvocation()} connect\` again.`;
237
+ return { ...result(1, "skipped", `no credential; run \`${cliInvocation()} login\` first`, message), next: `Run \`${cliInvocation()} login\`, then \`${cliInvocation()} init\` again.` };
237
238
  }
238
239
  if (creds.kind === "key") {
239
240
  if (flags.factory !== void 0 && flags.factory !== creds.appId) {
240
- const message2 = `a factory key decides the factory${creds.appId ? ` (${creds.appId})` : ""}, so --factory ${flags.factory} cannot apply. Remove --factory, or sign in with \`outerlayer login\` and unset the key.`;
241
+ const message2 = `a factory key decides the factory${creds.appId ? ` (${creds.appId})` : ""}, so --factory ${flags.factory} cannot apply. Remove --factory, or sign in with \`${cliInvocation()} login\` and unset the key.`;
241
242
  return result(1, "failed", "--factory names a factory other than the key's", message2);
242
243
  }
243
244
  const message = `Your factory key decides the factory${creds.appId ? ` (${creds.appId})` : ""}, so there is nothing to connect. No file was changed.`;
@@ -248,14 +249,14 @@ async function runConnect(flags, deps) {
248
249
  }
249
250
  const repository = deps.resolveRepository(deps.cwd);
250
251
  if (repository === void 0 && remoteLookupFailed(deps.cwd)) {
251
- const message = "git did not answer when asked for this repository's remote, so connect cannot tell which repository it is. Run `git remote -v` here, then run `outerlayer connect` again.";
252
+ const message = `git did not answer when asked for this repository's remote, so connect cannot tell which repository it is. Run \`git remote -v\` here, then run \`${cliInvocation()} connect\` again.`;
252
253
  return result(1, "failed", "git could not read this repository's remote", message);
253
254
  }
254
255
  if (repository === void 0) {
255
- return result(1, "skipped", "this repository has no git remote", "this repository has no git remote, so connect cannot tell which repository it is. Add one (`git remote add origin <url>`), then run `outerlayer connect` again.");
256
+ return result(1, "skipped", "this repository has no git remote", `this repository has no git remote, so connect cannot tell which repository it is. Add one (\`git remote add origin <url>\`), then run \`${cliInvocation()} connect\` again.`);
256
257
  }
257
258
  if (creds.url === void 0) {
258
- const message = "no gateway address is saved. Run `outerlayer login` to sign in.";
259
+ const message = `no gateway address is saved. Run \`${cliInvocation()} login\` to sign in.`;
259
260
  return result(1, "failed", message, message);
260
261
  }
261
262
  const listed = await fetchFactories(deps.fetchImpl, creds.url, creds.credential, repository);
@@ -285,7 +286,7 @@ async function runConnect(flags, deps) {
285
286
  const linkUrl = workPageUrl(deps.home, factory.organization.name, factory.name);
286
287
  return { ...result(EXIT_NOT_LINKED, "done", why, connected + notLinkedText(factory.displayName, repository, linkUrl)), ...chosen, linked, linkUrl };
287
288
  }
288
- const changeIt = "Run `outerlayer connect --factory <org>/<factory>` to change it.";
289
+ const changeIt = `Run \`${cliInvocation()} connect --factory <org>/<factory>\` to change it.`;
289
290
  const text = linked === null ? `${connected}Could not check whether ${sanitizeTerminal(repository)} is linked to ${factory.displayName}.
290
291
  ${changeIt}` : connected + changeIt;
291
292
  return { ...result(0, "done", why, text), ...chosen, linked };
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
4
+ import { join, basename } from 'path';
5
+
6
+ createRequire(import.meta.url);
7
+ var BEGIN = "# BEGIN outerlayer claude";
8
+ var END = "# END outerlayer claude";
9
+ var SHELL_FUNCTION_LINE = 'claude() { outerlayer claude "$@"; }';
10
+ var STARTUP_FILES = { zsh: ".zshrc", bash: ".bashrc" };
11
+ function startupFileFor(home, shellPath) {
12
+ const name = STARTUP_FILES[basename(shellPath ?? "")];
13
+ return name === void 0 ? void 0 : join(home, name);
14
+ }
15
+ function blockLines() {
16
+ return [BEGIN, "# Added by `outerlayer init`. Remove this block, or run `outerlayer init --no-shell-function`, to undo it.", SHELL_FUNCTION_LINE, END];
17
+ }
18
+ function find(lines) {
19
+ let begin = -1;
20
+ for (let i = 0; i < lines.length; i++) {
21
+ if (lines[i] === BEGIN) begin = i;
22
+ else if (lines[i] === END && begin >= 0) return { begin, end: i };
23
+ }
24
+ return void 0;
25
+ }
26
+ function installShellFunction(input) {
27
+ const file = startupFileFor(input.home, input.shellPath);
28
+ if (file === void 0) return { status: "unsupported" };
29
+ const text = existsSync(file) ? readFileSync(file, "utf8") : "";
30
+ if (find(text.split("\n")) !== void 0) return { status: "unchanged", file };
31
+ const endsLine = text === "" || text.endsWith("\n");
32
+ writeFileSync(file, `${text}${endsLine ? "" : "\n"}
33
+ ${blockLines().join("\n")}${endsLine ? "\n" : ""}`);
34
+ return { status: "added", file };
35
+ }
36
+ function removeShellFunction(input) {
37
+ const changed = [];
38
+ for (const name of Object.values(STARTUP_FILES)) {
39
+ const file = join(input.home, name);
40
+ if (!existsSync(file)) continue;
41
+ const lines = readFileSync(file, "utf8").split("\n");
42
+ const found = find(lines);
43
+ if (found === void 0) continue;
44
+ const from = found.begin > 0 && lines[found.begin - 1] === "" ? found.begin - 1 : found.begin;
45
+ lines.splice(from, found.end - from + 1);
46
+ writeFileSync(file, lines.join("\n"));
47
+ changed.push(file);
48
+ }
49
+ return changed;
50
+ }
51
+ function shellFunctionInstalled(input) {
52
+ const file = startupFileFor(input.home, input.shellPath);
53
+ return file !== void 0 && existsSync(file) && find(readFileSync(file, "utf8").split("\n")) !== void 0;
54
+ }
55
+
56
+ export { SHELL_FUNCTION_LINE, installShellFunction, removeShellFunction, shellFunctionInstalled };