@outerlayer/cli 0.17.0 → 0.18.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 (144) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +15 -0
  3. package/dist/agent-setup-RBTEACYU.js +28 -0
  4. package/dist/{artifact-link-cmd-2F47LT7F.js → artifact-link-cmd-AVM2EKTV.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-DUI2ZH2H.js} +5 -6
  8. package/dist/{check-5XE7XMC4.js → check-5C4YDZYV.js} +53 -50
  9. package/dist/{chunk-R7PF5OOU.js → chunk-3CWUOFV6.js} +21 -14
  10. package/dist/{chunk-G5NPRL2K.js → chunk-3OFZM4X6.js} +548 -68
  11. package/dist/{chunk-2MNPHL23.js → chunk-47TTLEDX.js} +6 -5
  12. package/dist/{chunk-PLMTLGYH.js → chunk-52NC2FIU.js} +4 -3
  13. package/dist/chunk-6CHIYEZZ.js +564 -0
  14. package/dist/{chunk-TI7B7UEO.js → chunk-AMFWYESY.js} +1 -1
  15. package/dist/{chunk-YRYMNBGQ.js → chunk-ANPNT6PM.js} +2 -1
  16. package/dist/{chunk-YU3VKZ5F.js → chunk-B3UKB46N.js} +6 -6
  17. package/dist/{chunk-JXYVA45C.js → chunk-BMYGAGBJ.js} +1050 -304
  18. package/dist/{chunk-4Q7OMKAT.js → chunk-BQXFBI7T.js} +81 -5
  19. package/dist/chunk-CRB3POP4.js +34 -0
  20. package/dist/{chunk-F47JBIAW.js → chunk-DSF2FWAZ.js} +2 -1
  21. package/dist/{chunk-N5FOE5PS.js → chunk-ECODQ7II.js} +4 -33
  22. package/dist/{chunk-NBGDBTO2.js → chunk-ESC6UR76.js} +6 -5
  23. package/dist/{chunk-HHJDN6AU.js → chunk-ESVW4MJY.js} +1 -1
  24. package/dist/{chunk-42ZI52JW.js → chunk-F4XSVQJ4.js} +4 -3
  25. package/dist/{chunk-LWSJQJC6.js → chunk-FUB7LRUE.js} +7 -7
  26. package/dist/chunk-G2YNJIGF.js +44 -0
  27. package/dist/{chunk-QKFB4K7X.js → chunk-GGOMT6KF.js} +1 -1
  28. package/dist/{chunk-VQYBXPI7.js → chunk-GOBOJMOJ.js} +5 -5
  29. package/dist/{chunk-N6LURUEF.js → chunk-GOSFARMS.js} +1 -1
  30. package/dist/chunk-JBJTC3UU.js +35 -0
  31. package/dist/{chunk-NWQTTSBB.js → chunk-JF42URPU.js} +16 -15
  32. package/dist/{chunk-ADJRGVZC.js → chunk-KDVIU23F.js} +1 -1
  33. package/dist/{chunk-S3NYLI2P.js → chunk-KK4VBOH6.js} +93 -37
  34. package/dist/{chunk-KMDLFI4P.js → chunk-L2USZT6T.js} +1 -1
  35. package/dist/{chunk-WTE3MQML.js → chunk-LXAY4A2G.js} +3 -12
  36. package/dist/{chunk-V7NIVOFD.js → chunk-M2ZWWTWZ.js} +1 -1
  37. package/dist/{chunk-ERI5GBNI.js → chunk-MLAAT4S6.js} +3 -3
  38. package/dist/{chunk-POJMEEJJ.js → chunk-MNTSH4CL.js} +1 -1
  39. package/dist/{chunk-WUYTWNMA.js → chunk-MQJSXHV7.js} +1 -1
  40. package/dist/{chunk-O765JR4W.js → chunk-MTP2QEVO.js} +1 -1
  41. package/dist/{chunk-ZM2IMMYN.js → chunk-N2PXGQRL.js} +9 -1
  42. package/dist/{chunk-J5M7BSJQ.js → chunk-N3CUDFCW.js} +9 -3
  43. package/dist/{chunk-4KSQKQXE.js → chunk-NACDBXUG.js} +19 -15
  44. package/dist/{chunk-ONKJUM6R.js → chunk-NL4XPC7W.js} +1 -1
  45. package/dist/{chunk-WVUIRTWA.js → chunk-QQM2UJ6T.js} +31 -26
  46. package/dist/{chunk-KG5ECZGJ.js → chunk-RAZTWYZN.js} +10 -9
  47. package/dist/{chunk-4NPZVMJU.js → chunk-S26M3YBJ.js} +60 -4
  48. package/dist/{chunk-UGP76IZ5.js → chunk-S5PCA3SN.js} +1 -1
  49. package/dist/{chunk-3NSNIIBE.js → chunk-S76AYB4M.js} +17 -16
  50. package/dist/{chunk-RMWLBUCJ.js → chunk-SADUQSO4.js} +1 -1
  51. package/dist/{chunk-OZGHL5Y5.js → chunk-SWCTGCSC.js} +2 -2
  52. package/dist/{chunk-GQD22KKN.js → chunk-T2Q7ISPE.js} +2 -1
  53. package/dist/{chunk-C5Y5ZJJZ.js → chunk-T4Y6SCG3.js} +5 -4
  54. package/dist/{chunk-BWQ66M6N.js → chunk-ULSIJGLS.js} +45 -13
  55. package/dist/{chunk-NNRTPG7X.js → chunk-UYOYTKE2.js} +4 -4
  56. package/dist/{chunk-PTW6W5NR.js → chunk-VYAL7PUE.js} +1 -1
  57. package/dist/{chunk-YZ5F4PIS.js → chunk-W5VPCONO.js} +146 -247
  58. package/dist/{chunk-6Y5RUTHO.js → chunk-WBT5X3NH.js} +5 -4
  59. package/dist/{chunk-RLYZLUQ7.js → chunk-WGAUY5LE.js} +2 -2
  60. package/dist/{chunk-RSNSZ2LJ.js → chunk-X5H2WYMB.js} +1 -1
  61. package/dist/{chunk-OHVJA253.js → chunk-X5N6KC6V.js} +47 -29
  62. package/dist/{chunk-22RMZBGW.js → chunk-XGP3VYOG.js} +1 -1
  63. package/dist/{chunk-HYZRY4KZ.js → chunk-XNGMQ27R.js} +16 -6
  64. package/dist/{chunk-HGECYFEI.js → chunk-Y5GE76XC.js} +131 -54
  65. package/dist/{chunk-MAK5LYRF.js → chunk-Y5MXET4M.js} +277 -535
  66. package/dist/{chunk-XCK2YAY5.js → chunk-YVZJ6GKF.js} +3 -2
  67. package/dist/{chunk-YO4PSLVB.js → chunk-ZRL6HKBY.js} +1 -1
  68. package/dist/claude-launcher-YVXI76NX.js +102 -0
  69. package/dist/{cli-A76AXELQ.js → cli-C77H54BV.js} +468 -161
  70. package/dist/{command-R2QCVX55.js → command-H5CILO4S.js} +40 -37
  71. package/dist/{config-N3C6DFQA.js → config-FXDG4NPJ.js} +2 -3
  72. package/dist/{connect-cmd-JBKAQNSF.js → connect-cmd-ZW5FV3ZW.js} +9 -8
  73. package/dist/{context-adopt-NFHCLVUB.js → context-adopt-O5OFXMKI.js} +13 -12
  74. package/dist/context-materialize-Y5IJ4MQT.js +23 -0
  75. package/dist/{dist-LKDWQWZ7.js → dist-QTX4RSCL.js} +2 -2
  76. package/dist/{docker-4J77Q2BF.js → docker-RC3PRX3Q.js} +7 -8
  77. package/dist/{doctor-4TAIARIG.js → doctor-2NQQML6P.js} +46 -39
  78. package/dist/{emit-artifact-cmd-MPZVR56N.js → emit-artifact-cmd-7MP63KXU.js} +25 -22
  79. package/dist/emit-cmd-PPN4QQF2.js +14 -0
  80. package/dist/{emit-criteria-cmd-EFGYI23V.js → emit-criteria-cmd-3RXPDLNK.js} +16 -14
  81. package/dist/{emit-finding-cmd-5GF3V4LR.js → emit-finding-cmd-OL7JB6H3.js} +18 -16
  82. package/dist/{emit-result-cmd-I4OADKMD.js → emit-result-cmd-UZVMOCF4.js} +20 -17
  83. package/dist/{exec-client-CQV746UF.js → exec-client-7UMESIE2.js} +3 -4
  84. package/dist/governing-source-BUU4IABS.js +35 -0
  85. package/dist/guest-init-KPBQOFE5.js +9 -0
  86. package/dist/{hook-fast-R4FVSZ2H.js → hook-fast-W5MKHMJT.js} +4 -1
  87. package/dist/host-key-U4B5QETR.js +8 -0
  88. package/dist/{import-capture-cmd-EQ35EARA.js → import-capture-cmd-ZO6KGHI2.js} +7 -5
  89. package/dist/{import-ruler-cmd-BGAZXCQM.js → import-ruler-cmd-KJMWL5V6.js} +5 -3
  90. package/dist/index.js +8 -4
  91. package/dist/init-VWXIZEAN.js +54 -0
  92. package/dist/{init-PWU5YVL7.js → init-WNXXYMO7.js} +38 -35
  93. package/dist/{init-cmd-XAVO7HYZ.js → init-cmd-WS6TIRYT.js} +28 -24
  94. package/dist/{init-update-CVCWD6VS.js → init-update-E3J6TVIN.js} +27 -26
  95. package/dist/{install-HDBIPHTX.js → install-CBWIEF3R.js} +4 -5
  96. package/dist/{install-cmd-5HYMXLEW.js → install-cmd-QDOTR4OM.js} +5 -4
  97. package/dist/{login-browser-QZCS3WW6.js → login-browser-O63QZN7D.js} +4 -3
  98. package/dist/{logout-cmd-QAUFDJ6J.js → logout-cmd-5V5MMBSY.js} +3 -2
  99. package/dist/{logs-H55NWW4H.js → logs-AMLKC3VP.js} +3 -1
  100. package/dist/loop-UGI2BJOT.js +76 -0
  101. package/dist/machine-JOW4RNZ7.js +49 -0
  102. package/dist/{mcp-install-cmd-FDTPQQS6.js → mcp-install-cmd-GGWB3JJ2.js} +3 -2
  103. package/dist/{mcp-serve-cmd-3KVYEUXG.js → mcp-serve-cmd-DOTY5FKY.js} +10 -8
  104. package/dist/paths-7XP63OAX.js +7 -0
  105. package/dist/pending-532ABZYC.js +8 -0
  106. package/dist/{pidfile-UZRH774M.js → pidfile-3DM4OBKO.js} +4 -2
  107. package/dist/{record-C43U4PKS.js → record-3WP6V2K5.js} +3 -2
  108. package/dist/{runner-env-EN7YE7QX.js → runner-env-4NB2GA7O.js} +5 -6
  109. package/dist/{runner-key-6SLBI7PP.js → runner-key-TC3NFWFV.js} +38 -35
  110. package/dist/{session-sender-FO3LCREV.js → session-sender-NNVPSPY7.js} +17 -14
  111. package/dist/spec-cmd-OWVTBB4J.js +116 -0
  112. package/dist/{starter-pack-KF66HGZR.js → starter-pack-OPWUDOWX.js} +7 -5
  113. package/dist/{status-7VNQN5PW.js → status-TKCLLKFG.js} +42 -39
  114. package/dist/{statusline-fast-SVTMBMD7.js → statusline-fast-KN3BX67H.js} +2 -1
  115. package/dist/{sync-cmd-GVPPFZ3G.js → sync-cmd-Q6VYNPWG.js} +16 -13
  116. package/dist/{watch-23HSAEI6.js → watch-ARAGADTF.js} +16 -13
  117. package/dist/{work-claim-cmd-LKL3GHFQ.js → work-claim-cmd-34FERLYX.js} +25 -27
  118. package/dist/work-cmd-7S5B2H2P.js +25 -0
  119. package/dist/{work-comment-cmd-AWHP56M2.js → work-comment-cmd-SZJSPM5S.js} +15 -13
  120. package/dist/{work-launch-R5HTAP6X.js → work-launch-LEQ2MPM3.js} +3 -1
  121. package/dist/{work-open-pr-cmd-IOM4AVQQ.js → work-open-pr-cmd-RPXKCBWS.js} +17 -15
  122. package/dist/work-pr-cmd-5LGANL32.js +26 -0
  123. package/package.json +3 -2
  124. package/skill-pack/maintained/outerlayer-amend/SKILL.md +4 -2
  125. package/skill-pack/shipped.json +17 -2
  126. package/skill-pack/template/build/SKILL.md +23 -10
  127. package/skill-pack/template/build/references/agent-briefs.md +3 -1
  128. package/skill-pack/template/build/references/criteria-judge.md +27 -0
  129. package/skill-pack/template/build/references/release.md +19 -28
  130. package/skill-pack/template/spec/SKILL.md +35 -10
  131. package/skill-pack/validators/acceptance-criteria.yaml +25 -26
  132. package/dist/agent-setup-T624CWPD.js +0 -27
  133. package/dist/chunk-BYT5O5RV.js +0 -61
  134. package/dist/context-materialize-IV2TUUFO.js +0 -22
  135. package/dist/emit-cmd-IJ3GVRFD.js +0 -12
  136. package/dist/guest-init-LJP5GPZF.js +0 -9
  137. package/dist/host-key-YMLXY6QB.js +0 -7
  138. package/dist/init-6XPDRDTC.js +0 -51
  139. package/dist/loop-FK3LPMMZ.js +0 -73
  140. package/dist/machine-SQXEBAM2.js +0 -46
  141. package/dist/paths-OYKMVYJP.js +0 -6
  142. package/dist/pending-MXLSRYMO.js +0 -7
  143. package/dist/work-cmd-Z2WXLZPH.js +0 -23
  144. package/dist/work-pr-cmd-HNEUIEN7.js +0 -24
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @outerlayer/cli
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2ef9133: Add `outerlayer claude`, which starts Claude Code with the repository's control plane attached. A governed build reads its control plane from a directory outside the checkout, so nothing from it is written into the checkout.
8
+ - e92982d: A session now takes its control plane from the one the factory stores, chosen in the factory's Settings with Use as control plane in the Repositories list. Nothing reads a `governs` list in a control plane's config any more, and `doctor` reports a list left there as unused. A gateway older than 0.17.0 does not store the answer, and the CLI says so instead of guessing.
9
+
10
+ A validator or policy `when` can name `repositories`, so a check applies only to pull requests in those repositories.
11
+
12
+ A session that could not reach the gateway, or reached a gateway too old to answer, no longer reads the retry guess it wrote as a confirmed answer on the next start. A build that cannot write the staged control-plane files now says so, and no longer reports that a credential cannot read the control plane.
13
+
14
+ - 2cb58e8: A container or microVM build now runs on the devcontainer of the repository that governs it. For a governed repository that is the control plane's `.devcontainer/devcontainer.json` (or `.devcontainer.json`), read at the commit the build's instructions come from. A governed repository's own devcontainer is not read, and the build log says so. A repository that governs itself builds from its own devcontainer, as before. `outerlayer runner image --repository <name>` builds the same image a build of that repository uses.
15
+
16
+ Before upgrading a runner host, copy the devcontainer your builds rely on into the control plane. A control plane with no devcontainer gives its builds the runner's default image. A factory whose only repository is its own control plane needs no move.
17
+
18
+ In a build with more than one repository, every repository is at `/build/work/repos/<owner>/<repo>`, the primary included. The primary is also at `/build/work/checkout`. The control plane devcontainer's setup commands run once, in the control plane's checkout, so they can name each repository by its fixed path. Host checks check out every repository at the same paths, each at the branch the build pushed there or else at its default branch.
19
+
20
+ - 07bb510: A `where: host` check can declare `run.judge.brief` instead of `run.command`. After a build ends well, the runner stops everything the build left running, checks that the image's Claude Code is unchanged, and runs a read-only Claude Code session with that brief. It records the verdict under the check's name with the host's own key and links the judge's report.
21
+
22
+ The starter `acceptance-criteria` check now uses this form, and the starter `/build` skill no longer records its own `acceptance-criteria` pass. Run `outerlayer doctor` to see an unedited copy of the old file as outdated, and `outerlayer init --update` to replace it.
23
+
24
+ - d776d34: `outerlayer spec` files and edits specs through OuterLayer, with no tracker tool of your own. `spec target` says where a spec would be filed. `spec search <query>` finds open and closed issues that match. `spec file --title <text> --body-file <path>` creates the issue and prints its key, URL and the `work build` command for it. `spec edit <key> --body-file <path>` replaces an issue's body, and `--updated-at` refuses the edit if the issue changed since you read it.
25
+
26
+ Filing works for GitHub today. An API key needs the new `spec.insert` permission to file and `spec.update` to edit, so re-mint keys that should do either. A GitHub organization admin must also approve the OuterLayer App's Issues write permission once.
27
+
28
+ ### Patch Changes
29
+
30
+ - 8f46b70: The starter `/build` skill reads the issue from `outerlayer work status --json`, under the new `issue` field, instead of from a tracker tool. A build on a host holds no Linear or Jira credential, so it could not read those issues before. The build saves the issue to `build-reports/issue.md` and gives every agent that file. `/outerlayer-amend` reads the issue the same way.
31
+
32
+ To pick up the new `/build`, run `outerlayer init --update`. A copy you edited is left as it is.
33
+
34
+ - fe8bb20: Printed command hints now name the command the way you ran the CLI. Run it through `npx @outerlayer/cli` (or `pnpm dlx`, `yarn dlx` or `bunx`) and a hint says `npx @outerlayer/cli login`, not an `outerlayer login` that is not on your PATH. `--help` usage lines follow the same rule.
35
+
36
+ `work build --local` no longer prints a branch name. The session it hands off to works on a branch of its own, so the printed name was never used. `--json` still carries the `branch` field.
37
+
38
+ `doctor` no longer warns when Claude Code is newer than the newest version this release was tested with. It passes, and names that tested version. A Claude Code older than the tested range still warns.
39
+
40
+ - 9b898aa: Session cost estimates price Claude Haiku 5.5 requests over 100,000 input tokens at Haiku 5.5's long-context rates. Token buckets now start a new input band at 100,000 tokens.
41
+ - 5cc77dc: Builds no longer print a Node warning on the stderr of every Node process. The runner sets `NODE_USE_ENV_PROXY` so Node uses the build's proxy, and Node 22 then warns `[UNDICI-EHPA] EnvHttpProxyAgent is experimental`. A test that expects a child process's stderr to be empty failed in a build and passed on a laptop.
42
+
43
+ The runner now adds `--disable-warning=UNDICI-EHPA` to `NODE_OPTIONS` in container, microVM and process builds. It keeps the options the image, the recipe's `containerEnv` or a named host variable already set. A build run through a provision hook's `exec` is left as it was. Node before 20.11 does not know the flag and refuses to start with it.
44
+
45
+ - daac363: Uploaded sessions record the input band boundaries their token buckets were grouped by. The server uses them to tell when a bucket cannot be priced at a single rate, and prices that model from its individual requests instead.
46
+ - 7a16e3f: `outerlayer work status`, `work remove`, `work claim`, `work renew` and `work release` take a Linear or Jira key in `--issue`, such as `--issue ENG-142`. Pass `--tracker linear` or `--tracker jira` when both trackers hold the key. Before, `--issue` took only a GitHub issue number, so a Linear or Jira item could be named only with `--item`.
47
+
48
+ A runner's `repos.include` and `repos.exclude` now match a Linear or Jira item by the repository it was added with (`work build --repo`), instead of skipping it. A runner using `builtin:process`, or its own provision hook, now clones the repository the claim chose, so it can build an item that was added without a repository.
49
+
3
50
  ## 0.17.0
4
51
 
5
52
  ### Minor Changes
package/README.md CHANGED
@@ -95,6 +95,12 @@ content:
95
95
  list and read items, and `work.claim` to claim, renew or release — `work.claim`
96
96
  is not granted to a dashboard role by default, since a claim is a host's
97
97
  lease, not a person's.
98
+ - **`outerlayer spec target`, `search`, `file` and `edit`** each make one
99
+ request to your gateway (`GET /v1/specs/target`, `GET /v1/specs/search`,
100
+ `POST /v1/specs`, `PATCH /v1/specs/{key}`). `search` sends your query, and
101
+ `file` and `edit` send the title and the Markdown body you give them.
102
+ Your gateway files the issue in your tracker; the CLI never holds a tracker
103
+ credential.
98
104
  - **`outerlayer runner start`** lists, claims, renews and releases work
99
105
  items the same way `work claim`/`renew`/`release` do, on the schedule its
100
106
  config sets — it sends nothing about the job it runs beyond that; the
@@ -116,6 +122,15 @@ content:
116
122
  command in a new container, and sends one `POST /v1/emitted-results` for
117
123
  each: the check's name, pass or fail, and for a fail the exit status and the
118
124
  last line of its output, scrubbed.
125
+ A `where: host` check that declares a `judge` runs after a successful
126
+ build instead of a command. The runner reads the item's recorded criteria
127
+ with `GET /v1/work-items/{id}`, fetches the build's commits and the brief
128
+ with the host's own git credentials, and copies out the tests that cite the
129
+ criteria. It starts a Claude Code agent in the build's image with the host's
130
+ Claude credential. The judge sees only a read-only folder of the criteria,
131
+ citations and diff, and it has no shell. The runner uploads the judge's
132
+ `report.html` as an artifact with its own key, and sends one
133
+ `POST /v1/emitted-results` with pass or fail and a one-line reason.
119
134
  Before each check's command runs, the runner writes a read-only folder for it
120
135
  to read: the work item, from `GET /v1/work-items/{id}` with the runner's own
121
136
  key; the branch's diff, from `git fetch` of the build's commits with the
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ export { keepHandWritten, runAgentSetup } from './chunk-RAZTWYZN.js';
4
+ import './chunk-47TTLEDX.js';
5
+ import './chunk-YVZJ6GKF.js';
6
+ import './chunk-F4XSVQJ4.js';
7
+ import './chunk-ANPNT6PM.js';
8
+ import './chunk-W5VPCONO.js';
9
+ import './chunk-LXAY4A2G.js';
10
+ import './chunk-T4Y6SCG3.js';
11
+ import './chunk-ZRL6HKBY.js';
12
+ import './chunk-52NC2FIU.js';
13
+ import './chunk-MNTSH4CL.js';
14
+ import './chunk-X5N6KC6V.js';
15
+ import './chunk-N3CUDFCW.js';
16
+ import './chunk-EABW6AJQ.js';
17
+ import './chunk-RA3O54FC.js';
18
+ import './chunk-M2ZWWTWZ.js';
19
+ import './chunk-N2PXGQRL.js';
20
+ import './chunk-BQXFBI7T.js';
21
+ import './chunk-XCCLFVXM.js';
22
+ import './chunk-ZJSNLVCE.js';
23
+ import './chunk-BJ3KTMDH.js';
24
+ import './chunk-CRB3POP4.js';
25
+ import './chunk-VNVZDWO3.js';
26
+ import './chunk-Z5GEFMRW.js';
27
+
28
+ createRequire(import.meta.url);
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { sanitizeTerminal, readEffectiveArtifactSpoolState } from './chunk-WUYTWNMA.js';
4
- import './chunk-J5M7BSJQ.js';
3
+ import { sanitizeTerminal, readEffectiveArtifactSpoolState } from './chunk-MQJSXHV7.js';
4
+ import './chunk-N3CUDFCW.js';
5
+ import { cliInvocation } from './chunk-CRB3POP4.js';
5
6
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
6
7
  import './chunk-Z5GEFMRW.js';
7
8
 
@@ -13,7 +14,7 @@ function lookupArtifactLink(artifactId, home = homeFromEnv()) {
13
14
  const entry = readEffectiveArtifactSpoolState(home).state.get(artifactId);
14
15
  if (entry === void 0) return { ok: false, reason: `no artifact ${shown} is queued or uploaded on this machine` };
15
16
  if (entry.state !== "uploaded") {
16
- return { ok: false, reason: `artifact ${shown} is ${entry.state}, not uploaded yet \u2014 run \`outerlayer sync\` first` };
17
+ return { ok: false, reason: `artifact ${shown} is ${entry.state}, not uploaded yet \u2014 run \`${cliInvocation()} sync\` first` };
17
18
  }
18
19
  if (entry.url === void 0) {
19
20
  return { ok: false, reason: `artifact ${shown} uploaded, but the gateway returned no link for it` };
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { buildRepositoryImage } from './chunk-R7PF5OOU.js';
3
+ export { buildRepositoryImage } from './chunk-3CWUOFV6.js';
4
4
  export { RecipeError } from './chunk-QOZKPLVJ.js';
5
- import './chunk-N5FOE5PS.js';
6
5
  import './chunk-CX22S5BA.js';
7
- import './chunk-BYT5O5RV.js';
8
- import './chunk-ZM2IMMYN.js';
6
+ import './chunk-ECODQ7II.js';
7
+ import './chunk-JBJTC3UU.js';
8
+ import './chunk-N2PXGQRL.js';
9
+ import './chunk-BQXFBI7T.js';
9
10
  import './chunk-Z5GEFMRW.js';
10
11
 
11
12
  createRequire(import.meta.url);
@@ -1 +1 @@
1
- {"id":"2026-10-09T21:24:47.045Z+8773e8e","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
1
+ {"id":"2026-10-13T00:18:48.455Z+4c5e4a3","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- export { MIN_BUILDX_VERSION, builderName, builderSpec, buildxState, ensureBuilder, ensureFailureCount, isOutOfMemory, proxyEnvironment, trackImageBuild } from './chunk-4NPZVMJU.js';
3
+ export { MIN_BUILDX_VERSION, builderName, builderSpec, buildxState, ensureBuilder, ensureFailureCount, isOutOfMemory, proxyEnvironment, trackImageBuild } from './chunk-S26M3YBJ.js';
4
4
  import './chunk-7RQ73DLO.js';
5
- import './chunk-4Q7OMKAT.js';
6
5
  import './chunk-CX22S5BA.js';
7
- import './chunk-JXYVA45C.js';
8
- import './chunk-BYT5O5RV.js';
9
- import './chunk-J5M7BSJQ.js';
10
- import './chunk-ZM2IMMYN.js';
6
+ import './chunk-BMYGAGBJ.js';
7
+ import './chunk-N3CUDFCW.js';
8
+ import './chunk-N2PXGQRL.js';
9
+ import './chunk-BQXFBI7T.js';
11
10
  import './chunk-Z5GEFMRW.js';
12
11
 
13
12
  createRequire(import.meta.url);
@@ -1,72 +1,75 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { probeCredentials } from './chunk-WVUIRTWA.js';
4
- import './chunk-G5NPRL2K.js';
5
- import './chunk-RMWLBUCJ.js';
6
- import './chunk-O765JR4W.js';
7
- import './chunk-UGP76IZ5.js';
3
+ import { probeCredentials } from './chunk-QQM2UJ6T.js';
8
4
  import './chunk-3JVYMD4G.js';
9
- import './chunk-YETTWTAY.js';
10
5
  import './chunk-I2UOAV7X.js';
11
- import './chunk-NNRTPG7X.js';
12
- import './chunk-HYZRY4KZ.js';
13
- import './chunk-ADJRGVZC.js';
14
- import './chunk-NWQTTSBB.js';
15
- import './chunk-HHJDN6AU.js';
16
- import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem, formerSkillQueues, formerSkillProblem } from './chunk-LWSJQJC6.js';
6
+ import './chunk-YETTWTAY.js';
7
+ import './chunk-3OFZM4X6.js';
8
+ import './chunk-SADUQSO4.js';
9
+ import './chunk-KDVIU23F.js';
10
+ import './chunk-MTP2QEVO.js';
11
+ import './chunk-S5PCA3SN.js';
12
+ import './chunk-UYOYTKE2.js';
13
+ import './chunk-XNGMQ27R.js';
14
+ import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem, formerSkillQueues, formerSkillProblem } from './chunk-FUB7LRUE.js';
15
+ import './chunk-AMFWYESY.js';
17
16
  import './chunk-YYYRBYWG.js';
18
- import './chunk-TI7B7UEO.js';
17
+ import './chunk-GOBOJMOJ.js';
18
+ import './chunk-JF42URPU.js';
19
+ import './chunk-ESVW4MJY.js';
19
20
  import './chunk-TBT347UY.js';
20
- import './chunk-VQYBXPI7.js';
21
- import './chunk-ONKJUM6R.js';
22
- import './chunk-MAK5LYRF.js';
23
- import './chunk-KMDLFI4P.js';
24
- import './chunk-QKFB4K7X.js';
25
- import './chunk-RSNSZ2LJ.js';
26
- import './chunk-OZGHL5Y5.js';
27
- import './chunk-RLYZLUQ7.js';
21
+ import './chunk-NL4XPC7W.js';
22
+ import './chunk-Y5MXET4M.js';
23
+ import './chunk-L2USZT6T.js';
24
+ import './chunk-S26M3YBJ.js';
25
+ import './chunk-GGOMT6KF.js';
26
+ import './chunk-X5H2WYMB.js';
27
+ import './chunk-6CHIYEZZ.js';
28
+ import './chunk-SWCTGCSC.js';
29
+ import './chunk-WGAUY5LE.js';
28
30
  import { parseRunnerEnv } from './chunk-6MZSX4M7.js';
29
- import './chunk-S3NYLI2P.js';
30
- import './chunk-6Y5RUTHO.js';
31
+ import './chunk-KK4VBOH6.js';
32
+ import './chunk-WBT5X3NH.js';
31
33
  import './chunk-IP7BIBXJ.js';
32
- import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-22RMZBGW.js';
34
+ import './chunk-S76AYB4M.js';
35
+ import './chunk-MQJSXHV7.js';
36
+ import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-XGP3VYOG.js';
33
37
  import './chunk-UXYLWVTQ.js';
34
- import './chunk-R7PF5OOU.js';
35
- import './chunk-QOZKPLVJ.js';
36
- import './chunk-N5FOE5PS.js';
37
- import './chunk-OGFGZQA3.js';
38
- import './chunk-4NPZVMJU.js';
39
38
  import './chunk-7RQ73DLO.js';
40
- import './chunk-4Q7OMKAT.js';
39
+ import './chunk-3CWUOFV6.js';
40
+ import './chunk-QOZKPLVJ.js';
41
41
  import './chunk-CX22S5BA.js';
42
+ import './chunk-ECODQ7II.js';
43
+ import './chunk-JBJTC3UU.js';
44
+ import './chunk-OGFGZQA3.js';
42
45
  import './chunk-F7CU5ABH.js';
43
46
  import './chunk-BKO6JEZI.js';
44
- import './chunk-3NSNIIBE.js';
45
- import './chunk-WUYTWNMA.js';
46
- import './chunk-JXYVA45C.js';
47
- import './chunk-4KSQKQXE.js';
48
- import './chunk-N6LURUEF.js';
49
- import './chunk-YRYMNBGQ.js';
50
- import './chunk-GQD22KKN.js';
47
+ import './chunk-BMYGAGBJ.js';
48
+ import './chunk-NACDBXUG.js';
49
+ import './chunk-GOSFARMS.js';
50
+ import './chunk-ANPNT6PM.js';
51
+ import './chunk-T2Q7ISPE.js';
51
52
  import './chunk-WZBHBH3J.js';
52
53
  import './chunk-5QRP3MVS.js';
53
- import './chunk-YZ5F4PIS.js';
54
- import './chunk-WTE3MQML.js';
55
- import './chunk-C5Y5ZJJZ.js';
56
- import './chunk-ZJSNLVCE.js';
57
- import './chunk-YO4PSLVB.js';
58
- import './chunk-BYT5O5RV.js';
59
- import './chunk-POJMEEJJ.js';
60
- import './chunk-OHVJA253.js';
61
- import './chunk-PLMTLGYH.js';
62
- import './chunk-J5M7BSJQ.js';
54
+ import './chunk-W5VPCONO.js';
55
+ import './chunk-LXAY4A2G.js';
56
+ import './chunk-T4Y6SCG3.js';
57
+ import './chunk-ZRL6HKBY.js';
58
+ import './chunk-52NC2FIU.js';
59
+ import './chunk-MNTSH4CL.js';
60
+ import './chunk-X5N6KC6V.js';
61
+ import './chunk-N3CUDFCW.js';
63
62
  import './chunk-EABW6AJQ.js';
64
63
  import './chunk-RA3O54FC.js';
65
- import './chunk-V7NIVOFD.js';
66
- import './chunk-ZM2IMMYN.js';
67
- import './chunk-BWQ66M6N.js';
64
+ import './chunk-M2ZWWTWZ.js';
65
+ import './chunk-N2PXGQRL.js';
66
+ import './chunk-BQXFBI7T.js';
67
+ import './chunk-ULSIJGLS.js';
68
+ import './chunk-G2YNJIGF.js';
68
69
  import './chunk-XCCLFVXM.js';
70
+ import './chunk-ZJSNLVCE.js';
69
71
  import './chunk-BJ3KTMDH.js';
72
+ import './chunk-CRB3POP4.js';
70
73
  import './chunk-VNVZDWO3.js';
71
74
  import './chunk-Z5GEFMRW.js';
72
75
  import { readFileSync } from 'fs';
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { RecipeError, locateRecipe, readRecipe, assertBuildable, writeSanitizedRecipe, classifyProperties, SANITIZED_NAME } from './chunk-QOZKPLVJ.js';
4
- import { startTimeOf, claimPidFile, RunnerAlreadyRunningError, releasePidFile } from './chunk-N5FOE5PS.js';
5
4
  import { CLAUDE_CODE_VERSION, NODE_IMAGE, DEFAULT_BASE_IMAGE, TINI_VERSION, GH_VERSION, GH_SHA256, TINI_SHA256 } from './chunk-CX22S5BA.js';
6
- import { withGitConfig, tokenHeader } from './chunk-BYT5O5RV.js';
7
- import { RUNNER_DIR_MODE, repoCacheDir, imagesDir, attemptStamp, runnerDir, rootfsPathFor, RUNNER_FILE_MODE } from './chunk-ZM2IMMYN.js';
5
+ import { claimPidFile, RunnerAlreadyRunningError, releasePidFile } from './chunk-ECODQ7II.js';
6
+ import { startTimeOf } from './chunk-JBJTC3UU.js';
7
+ import { RUNNER_DIR_MODE, repoCacheDir, imagesDir, attemptStamp, runnerDir, rootfsPathFor, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
8
+ import { withGitConfig, tokenHeader } from './chunk-BQXFBI7T.js';
8
9
  import { mkdirSync, rmSync, existsSync, mkdtempSync, cpSync, readFileSync, writeFileSync, readdirSync, lstatSync, readlinkSync } from 'fs';
9
10
  import { tmpdir } from 'os';
10
11
  import { dirname, join } from 'path';
@@ -36,6 +37,10 @@ function git(cwd, args, timeoutMs, extend = (env) => env) {
36
37
  );
37
38
  });
38
39
  }
40
+ function gitFailureLine(err) {
41
+ const lines = (err instanceof Error ? err.message : String(err)).replace(/^git [\w-]+ failed: /, "").split("\n").map((line) => line.trim()).filter((line) => line !== "");
42
+ return lines.find((line) => !/^warning:/i.test(line)) ?? lines[0] ?? "";
43
+ }
39
44
  function defaultBranchOf(lsRemote) {
40
45
  const match = lsRemote.match(/^ref: refs\/heads\/(\S+)\s+HEAD$/m);
41
46
  return match ? match[1] : null;
@@ -90,7 +95,7 @@ async function readBranchHead(input) {
90
95
  try {
91
96
  out = await git(input.dir, ["ls-remote", "--heads", input.remote, `refs/heads/${input.branch}`], HEAD_TIMEOUT_MS, credential);
92
97
  } catch (err) {
93
- return { kind: "unreadable", reason: (err instanceof Error ? err.message : String(err)).replace(/^git [\w-]+ failed: /, "").split("\n")[0] };
98
+ return { kind: "unreadable", reason: gitFailureLine(err) };
94
99
  }
95
100
  const sha = out.match(/^([0-9a-f]{40}|[0-9a-f]{64})\trefs\/heads\//m)?.[1];
96
101
  return sha === void 0 ? { kind: "absent" } : { kind: "found", sha };
@@ -102,9 +107,10 @@ async function fetchCommit(input) {
102
107
  await git(input.dir, ["init", "--quiet"]);
103
108
  await git(input.dir, ["fetch", "--quiet", "--depth", "1", "--no-tags", input.remote, input.commit], CLONE_TIMEOUT_MS, credential);
104
109
  await git(input.dir, ["checkout", "--quiet", "--detach", "--force", "FETCH_HEAD"]);
110
+ if (input.clean === true) await git(input.dir, ["clean", "-ffdx", "--quiet"]);
105
111
  return { ok: true };
106
112
  } catch (err) {
107
- const detail = (err instanceof Error ? err.message : String(err)).replace(/^git [\w-]+ failed: /, "").split("\n")[0];
113
+ const detail = gitFailureLine(err);
108
114
  return { ok: false, reason: `the fetch of ${input.commit.slice(0, 8)} from ${input.remote} failed: ${detail}` };
109
115
  }
110
116
  }
@@ -122,7 +128,7 @@ async function diffBetween(input) {
122
128
  );
123
129
  return { ok: true };
124
130
  } catch (err) {
125
- const detail = (err instanceof Error ? err.message : String(err)).replace(/^git [\w-]+ failed: /, "").split("\n")[0];
131
+ const detail = gitFailureLine(err);
126
132
  return { ok: false, reason: `the diff of ${input.head.slice(0, 8)} from ${input.base.slice(0, 8)} could not be read from ${input.remote}: ${detail}` };
127
133
  }
128
134
  }
@@ -189,9 +195,9 @@ function toolsDockerfile(parts) {
189
195
  " && chmod 1777 /out/build",
190
196
  ...parts.guestHelper === true ? [
191
197
  "COPY guest/outerlayer-guest /out/opt/outerlayer/bin/outerlayer-guest",
192
- // The guest mounts the build's tmpfs, the kernel's file systems and the run directory over these.
198
+ // The guest mounts the build's tmpfs, the kernel's file systems and the run directory over these. The judge's tmpfs is mounted over its directory when the judge runs.
193
199
  "RUN chmod 0755 /out/opt/outerlayer/bin/outerlayer-guest \\",
194
- " && mkdir -p /out/outerlayer/job /out/run /out/proc /out/sys /out/dev"
200
+ " && mkdir -p /out/outerlayer/job /out/outerlayer/judge /out/run /out/proc /out/sys /out/dev"
195
201
  ] : [],
196
202
  `RUN set -eu \\`,
197
203
  ` && case "$TARGETARCH" in \\`,
@@ -295,6 +301,11 @@ function splitRepository(repository) {
295
301
  }
296
302
  return { full, owner: parts[0], name: parts[1] };
297
303
  }
304
+ async function fetchPinnedCommit(opts) {
305
+ const fetched = await fetchCommit({ remote: opts.remote, dir: opts.dir, commit: opts.commit, token: opts.token, clean: true });
306
+ if (!fetched.ok) throw new RecipeError("repository_unreadable", `cannot read ${opts.repository}: ${fetched.reason}`);
307
+ return { dir: opts.dir, defaultBranch: opts.ref, commit: opts.commit };
308
+ }
298
309
  function metadataOf(image) {
299
310
  try {
300
311
  const parsed = JSON.parse(image.labels["devcontainer.metadata"] ?? "[]");
@@ -345,12 +356,8 @@ async function buildRepositoryImage(opts, ports) {
345
356
  throw err;
346
357
  }
347
358
  try {
348
- const checkout = await fetchDefaultBranch({
349
- remote: opts.remote ?? `https://github.com/${owner}/${name}.git`,
350
- dir: cacheDir,
351
- token: opts.readToken,
352
- repository
353
- });
359
+ const remote = opts.remote ?? `https://github.com/${owner}/${name}.git`;
360
+ const checkout = opts.pinned === void 0 ? await fetchDefaultBranch({ remote, dir: cacheDir, token: opts.readToken, repository }) : await fetchPinnedCommit({ remote, dir: cacheDir, token: opts.readToken, repository, ...opts.pinned });
354
361
  const location = locateRecipe(checkout.dir);
355
362
  const recipe = readRecipe(checkout.dir, location);
356
363
  assertBuildable(checkout.dir, location, recipe);