@outerlayer/cli 0.20.0 → 0.22.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.
- package/CHANGELOG.md +26 -0
- package/README.md +15 -5
- package/dist/{agent-setup-AM42SA2D.js → agent-setup-XAJH6MPW.js} +13 -12
- package/dist/build-GTMEADQD.js +12 -0
- package/dist/build-command-ND2ENDBS.js +50 -0
- package/dist/build-info.json +1 -1
- package/dist/{builder-C4QNTYMS.js → builder-OAUSTZHL.js} +7 -5
- package/dist/{check-BR5D27CX.js → check-3YHMJQ3P.js} +48 -50
- package/dist/{chunk-AD3EYI7P.js → chunk-22DYXLU7.js} +259 -56
- package/dist/{chunk-P53VEAOF.js → chunk-2CMJLYV6.js} +1 -1
- package/dist/{chunk-FBTGMSQF.js → chunk-2HT2XGJX.js} +16 -9
- package/dist/{chunk-S5PCA3SN.js → chunk-2J5JGLW5.js} +1 -1
- package/dist/{chunk-R22NZSGA.js → chunk-34XORKFD.js} +9 -9
- package/dist/{chunk-QOZKPLVJ.js → chunk-3W333NFO.js} +40 -1
- package/dist/{chunk-HOKXGFDR.js → chunk-4JHVPFH6.js} +22 -16
- package/dist/{chunk-AMFWYESY.js → chunk-4NM3I3VV.js} +1 -1
- package/dist/{chunk-PIZRPNKR.js → chunk-4QKLMNI3.js} +5 -5
- package/dist/{chunk-NNLA7LLQ.js → chunk-5OCIHFGE.js} +29 -5
- package/dist/{chunk-PSN33ERW.js → chunk-6IO62VJS.js} +3 -3
- package/dist/{chunk-7YP7T6GV.js → chunk-7V7KG3YM.js} +2 -2
- package/dist/{chunk-QNLX477Q.js → chunk-AEKSX4EY.js} +165 -72
- package/dist/{chunk-JHGEBPLE.js → chunk-ATRIVTRE.js} +3 -3
- package/dist/{chunk-X5H2WYMB.js → chunk-BLW6GPBZ.js} +1 -1
- package/dist/{chunk-MLAAT4S6.js → chunk-C3HKR67W.js} +3 -3
- package/dist/{chunk-XZ4H4X5F.js → chunk-C3OVGKVJ.js} +15 -8
- package/dist/{chunk-BM63HB2M.js → chunk-EAQSOE62.js} +2 -2
- package/dist/{chunk-LW7G5TJB.js → chunk-EXV37PKS.js} +2 -2
- package/dist/{chunk-B6SCN5NY.js → chunk-FGW2774C.js} +175 -44
- package/dist/{chunk-KYS3TQAG.js → chunk-G2WME4RG.js} +4 -4
- package/dist/{chunk-LRG3ZMZD.js → chunk-G6DZCKA6.js} +4 -4
- package/dist/chunk-GISNHSYL.js +41 -0
- package/dist/{chunk-G2YNJIGF.js → chunk-HCVLP7XA.js} +10 -1
- package/dist/{chunk-QEFKA2QD.js → chunk-I66MQDXH.js} +2 -2
- package/dist/{chunk-3CWUOFV6.js → chunk-IRBNIRQJ.js} +12 -7
- package/dist/{chunk-CG36IONK.js → chunk-JRCSET55.js} +2 -2
- package/dist/{chunk-CGGPS7SI.js → chunk-JVB63NIB.js} +5 -5
- package/dist/{chunk-M2ZWWTWZ.js → chunk-KDHYLBRR.js} +1 -1
- package/dist/{chunk-N2PXGQRL.js → chunk-KIGSGZBB.js} +1 -1
- package/dist/{chunk-EAEELQVQ.js → chunk-KOQELWQ6.js} +5 -5
- package/dist/{chunk-MTP2QEVO.js → chunk-KPBQYEND.js} +1 -1
- package/dist/{chunk-VYAL7PUE.js → chunk-LOB2SUM3.js} +1 -1
- package/dist/{chunk-GGOMT6KF.js → chunk-PHHBYAL6.js} +1 -1
- package/dist/{chunk-IF2OSI5T.js → chunk-QOALB6ZD.js} +2 -2
- package/dist/{chunk-ZX4I2MEK.js → chunk-TPKYTORP.js} +1 -1
- package/dist/{chunk-XNGMQ27R.js → chunk-UD3EXMKB.js} +2 -2
- package/dist/{chunk-7UWVLZXD.js → chunk-USWVXQIH.js} +1 -1
- package/dist/{chunk-BQXFBI7T.js → chunk-V7MQKOZY.js} +32 -7
- package/dist/{chunk-6X4SQ5MY.js → chunk-V7SAQ645.js} +1 -1
- package/dist/{chunk-TWF3RICI.js → chunk-VSUXCMMH.js} +110 -11
- package/dist/{chunk-FVMYKL6L.js → chunk-VWLOQ6FI.js} +1 -1
- package/dist/{chunk-3ZR7Y23Y.js → chunk-VX74ND77.js} +650 -70
- package/dist/{chunk-Z7K3L4FC.js → chunk-W3SWJ2TD.js} +2 -2
- package/dist/chunk-WERZMIKA.js +718 -0
- package/dist/{chunk-GEMQLBMW.js → chunk-WMHYIBJW.js} +6 -6
- package/dist/{chunk-5VML45HH.js → chunk-XCRZTXRL.js} +2 -2
- package/dist/{chunk-ECODQ7II.js → chunk-ZFLOGMUC.js} +1 -1
- package/dist/chunk-ZNPE7FW5.js +137 -0
- package/dist/claude-launcher-4BQNXYAF.js +267 -0
- package/dist/{cli-MKF7TU7X.js → cli-NMGVZQPB.js} +161 -120
- package/dist/{command-ZQNEPDS6.js → command-GE62AJZY.js} +32 -34
- package/dist/{config-CLSGABD5.js → config-7Q52COZ3.js} +3 -2
- package/dist/{connect-cmd-UNYKGDAL.js → connect-cmd-ZFOK6HEL.js} +5 -5
- package/dist/{context-cleanup-CHEWNYU6.js → context-cleanup-DSA3HGQU.js} +1 -1
- package/dist/{control-plane-launch-34LNRJWR.js → control-plane-launch-SZTE4TUS.js} +62 -28
- package/dist/{dist-WO7NOJNG.js → dist-7IH56ELA.js} +1 -1
- package/dist/{docker-BFU3AQGY.js → docker-2OVBKVRK.js} +7 -7
- package/dist/{doctor-DHUM5DBB.js → doctor-3SQGZVYP.js} +35 -36
- package/dist/{emit-artifact-cmd-XBHM647X.js → emit-artifact-cmd-R42BE6ID.js} +19 -18
- package/dist/{emit-cmd-W55AEBCA.js → emit-cmd-3W5IO5ET.js} +3 -3
- package/dist/{emit-criteria-cmd-UNMWHOUY.js → emit-criteria-cmd-MQZE7W4Y.js} +13 -12
- package/dist/{emit-finding-cmd-7JHVRYOP.js → emit-finding-cmd-ZS5JEGGM.js} +13 -12
- package/dist/{emit-result-cmd-5NZMLCJK.js → emit-result-cmd-FUE3DXBW.js} +19 -18
- package/dist/{emit-step-cmd-347XNGPQ.js → emit-step-cmd-T7PRA44X.js} +14 -13
- package/dist/{exec-client-7UMESIE2.js → exec-client-YIDTWXMZ.js} +4 -3
- package/dist/{governing-source-HAA4OW57.js → governing-source-TORXL4I4.js} +19 -18
- package/dist/{guest-init-KPBQOFE5.js → guest-init-TO6HAWIT.js} +4 -3
- package/dist/{hook-fast-RL5E5OXE.js → hook-fast-WFB2ZMRB.js} +2 -2
- package/dist/host-key-2LXQDSBO.js +9 -0
- package/dist/{import-capture-cmd-TK4XY7RD.js → import-capture-cmd-Q56DDZVO.js} +1 -1
- package/dist/index.js +5 -5
- package/dist/init-2CRAVIUU.js +52 -0
- package/dist/{init-V6FOMD2V.js → init-AHDZCMDC.js} +32 -33
- package/dist/{init-cmd-Z4O4PPLZ.js → init-cmd-IXDL2ZSL.js} +25 -23
- package/dist/{init-update-7DVAKWW3.js → init-update-YB3PODDH.js} +69 -24
- package/dist/{install-4SEFIIW2.js → install-CZUIW2AF.js} +5 -4
- package/dist/{install-cmd-QDOTR4OM.js → install-cmd-Q7RJGFUO.js} +6 -5
- package/dist/{login-browser-DX35MARZ.js → login-browser-BN5UKPHS.js} +3 -3
- package/dist/{logout-cmd-5V5MMBSY.js → logout-cmd-RZFWTNYD.js} +2 -2
- package/dist/{logs-AMLKC3VP.js → logs-RJPYTVQE.js} +3 -2
- package/dist/loop-ZDW6TRAA.js +75 -0
- package/dist/machine-JCOHLASP.js +47 -0
- package/dist/{mcp-install-cmd-GGWB3JJ2.js → mcp-install-cmd-GD4QUP7Z.js} +2 -2
- package/dist/{mcp-serve-cmd-N3UTY6EE.js → mcp-serve-cmd-IULQPVHL.js} +6 -5
- package/dist/{paths-7XP63OAX.js → paths-N3LU4O2Z.js} +3 -2
- package/dist/pending-GRCV3ZR4.js +9 -0
- package/dist/{pidfile-3DM4OBKO.js → pidfile-IF3TCL5A.js} +4 -3
- package/dist/receive-files-T2BIUBQL.js +254 -0
- package/dist/{record-3WP6V2K5.js → record-73PQE77B.js} +4 -3
- package/dist/relay-PSZ4LGMW.js +210 -0
- package/dist/relay-protocol-K7KP2SPI.js +6 -0
- package/dist/{runner-env-FRZFFHDF.js → runner-env-LDOBJESN.js} +6 -5
- package/dist/runner-identity-RWCBTY2A.js +14 -0
- package/dist/{runner-key-5FOWCW7J.js → runner-key-HMYLP6WN.js} +32 -33
- package/dist/{session-sender-U2BBUWNO.js → session-sender-2G25JYHI.js} +20 -19
- package/dist/{spec-cmd-FVLJOFGC.js → spec-cmd-LBVXM6XS.js} +13 -12
- package/dist/{starter-pack-6LQVLBIA.js → starter-pack-5EQYGSJF.js} +2 -2
- package/dist/{status-BINH7MBG.js → status-QZB2GWXJ.js} +36 -38
- package/dist/{statusline-fast-KN3BX67H.js → statusline-fast-2OK3DVAA.js} +2 -2
- package/dist/{sync-cmd-VXOUFS4I.js → sync-cmd-TQQIR4PN.js} +19 -18
- package/dist/{watch-OH645CV2.js → watch-4JES4PCS.js} +19 -18
- package/dist/{work-claim-cmd-DRQCHCOK.js → work-claim-cmd-XG6O7B63.js} +17 -16
- package/dist/{work-cmd-5I3J2XQQ.js → work-cmd-L6WMPAA2.js} +13 -12
- package/dist/{work-comment-cmd-UCCPWUSR.js → work-comment-cmd-SNTDCPGH.js} +13 -12
- package/dist/{work-logs-cmd-7352CJPG.js → work-logs-cmd-3S7IAVII.js} +13 -12
- package/dist/{work-open-pr-cmd-LSH4VHJM.js → work-open-pr-cmd-E3WMO5XT.js} +15 -14
- package/dist/{work-pr-cmd-H4OQR26N.js → work-pr-cmd-22T6FG4T.js} +14 -13
- package/dist/{work-stop-cmd-CRDHXQVW.js → work-stop-cmd-WR7ESS4Z.js} +13 -12
- package/package.json +2 -2
- package/skill-pack/maintained/outerlayer-build/SKILL.md +347 -0
- package/skill-pack/{template/build → maintained/outerlayer-build}/references/evidence.md +2 -2
- package/skill-pack/{template/build → maintained/outerlayer-build}/references/release.md +4 -4
- package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-loop.md +3 -1
- package/skill-pack/shipped.json +2 -0
- package/skill-pack/template/build/SKILL.md +4 -253
- package/skill-pack/validators/acceptance-criteria.yaml +1 -1
- package/dist/build-TQ6X5PYN.js +0 -12
- package/dist/chunk-3UZTIRLF.js +0 -320
- package/dist/chunk-CX22S5BA.js +0 -45
- package/dist/chunk-LLM3I5YU.js +0 -89
- package/dist/chunk-SADUQSO4.js +0 -50
- package/dist/chunk-VMJPFQNE.js +0 -261
- package/dist/claude-launcher-J5M44PFS.js +0 -115
- package/dist/host-key-U4B5QETR.js +0 -8
- package/dist/init-XG47KCI4.js +0 -53
- package/dist/loop-EAZQMAE2.js +0 -77
- package/dist/machine-TRHBT5NE.js +0 -48
- package/dist/pending-532ABZYC.js +0 -8
- package/dist/relay-L76HDX72.js +0 -46
- package/dist/{chunk-YVZJ6GKF.js → chunk-DIB2WLBL.js} +1 -1
- package/dist/{chunk-GOSFARMS.js → chunk-F35VMF5M.js} +1 -1
- package/dist/{chunk-DSF2FWAZ.js → chunk-IZSVXRDR.js} +1 -1
- /package/skill-pack/{template/build → maintained/outerlayer-build}/references/agent-briefs.md +0 -0
- /package/skill-pack/{template/build → maintained/outerlayer-build}/references/criteria-judge.md +0 -0
- /package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-briefs.md +0 -0
- /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/criterion-citations.mjs +0 -0
- /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/record-criteria.mjs +0 -0
|
@@ -1,260 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build
|
|
3
|
-
description: >
|
|
4
|
-
Build one approved issue end to end: implement it, review it with a sized panel
|
|
5
|
-
of agents, run the repository's own checks, open the pull request, and attach
|
|
6
|
-
the review and criteria reports as evidence. Use when a work item exists for an
|
|
7
|
-
issue and you want it built. Invoke with OUTERLAYER_WORK=<number> claude "/build".
|
|
3
|
+
description: Build one approved issue end to end. Invoke with OUTERLAYER_WORK=<n> claude "/build".
|
|
8
4
|
disable-model-invocation: true
|
|
9
5
|
---
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
Read ../outerlayer-build/SKILL.md, relative to this skill's folder, and follow it from start to finish. Apply the changes below for this repository.
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
approval for the issue. This skill builds it. It never writes the spec.
|
|
9
|
+
## Changes for this repository
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
phase reads its own reference on entry, never before:
|
|
18
|
-
|
|
19
|
-
- [references/review-loop.md](references/review-loop.md): the review phase.
|
|
20
|
-
- [references/review-briefs.md](references/review-briefs.md): the reviewer, refuter and mutation briefs.
|
|
21
|
-
- [references/agent-briefs.md](references/agent-briefs.md): the briefs for every other agent.
|
|
22
|
-
- [references/release.md](references/release.md): sync, pull request, CI.
|
|
23
|
-
- [references/criteria-judge.md](references/criteria-judge.md): the brief that judges each criterion.
|
|
24
|
-
- [references/evidence.md](references/evidence.md): manual test and evidence.
|
|
25
|
-
|
|
26
|
-
Paste a brief verbatim into the agent that runs it. Add only the run's own
|
|
27
|
-
values, such as paths, the branch and the item number.
|
|
28
|
-
|
|
29
|
-
Every text a person will read follows the writing rule in the repository's
|
|
30
|
-
instructions file, if it has one. Otherwise write for a reader who was not in
|
|
31
|
-
the session: short sentences, the outcome first, and plain words. Paste that
|
|
32
|
-
rule into every agent that writes prose.
|
|
33
|
-
|
|
34
|
-
## Arguments
|
|
35
|
-
|
|
36
|
-
`/build` takes no issue number. It builds the work item named by
|
|
37
|
-
`OUTERLAYER_WORK`, the item's number. The launch is:
|
|
38
|
-
|
|
39
|
-
OUTERLAYER_WORK=<number> claude "/build"
|
|
40
|
-
|
|
41
|
-
The item exists because someone ran `outerlayer work build --issue <reference>`.
|
|
42
|
-
Given a request instead of a work item, stop and say:
|
|
43
|
-
|
|
44
|
-
Spec it first: /spec <the request as given>
|
|
45
|
-
|
|
46
|
-
Optional flag: `--unattended` means no person is present and nothing wakes
|
|
47
|
-
the session after a turn ends. Spawn every agent in the foreground and wait
|
|
48
|
-
for it in the same turn. Run the gate in the foreground with the maximum
|
|
49
|
-
timeout. End the turn only at the final report.
|
|
50
|
-
|
|
51
|
-
## State rules
|
|
52
|
-
|
|
53
|
-
These bind the orchestrator in every phase. Rule 5 also binds every spawned agent.
|
|
54
|
-
|
|
55
|
-
1. **Never end a turn waiting on nothing.** End a turn while work is in
|
|
56
|
-
flight only when something live will wake the session: a spawned agent or
|
|
57
|
-
a background command. Before saying "waiting on X", confirm X is live.
|
|
58
|
-
Work that is not live did not happen: redo it once.
|
|
59
|
-
2. **One redo per piece of work.** A second failure of the same work means
|
|
60
|
-
the orchestrator takes it over. It reads what the agent left, finishes the
|
|
61
|
-
brief itself in the foreground, and names the takeover in its status line.
|
|
62
|
-
If the gate still cannot go green, escalate.
|
|
63
|
-
3. **The gate runs in the foreground, one heavy command at a time.** The gate
|
|
64
|
-
is the repository's own pre-push checks and tests, as its instructions
|
|
65
|
-
file names them. Never run it in the background. Never start a suite while
|
|
66
|
-
an agent runs one. Never bypass a hook: no `--no-verify`, no skipped hook,
|
|
67
|
-
even when a hook fails. Fix what the hook reports.
|
|
68
|
-
4. **Checkpoint and re-orient.** Before phase 1, write a state file at
|
|
69
|
-
`"$(git rev-parse --absolute-git-dir)/build-state.json"`, replacing any
|
|
70
|
-
earlier one. Record the phase, the review round, the spawned agents, the
|
|
71
|
-
agent count, the issue reference, the pull request number, the branch, and
|
|
72
|
-
from phase 4 the tier verdict. Overwrite it at every phase change. On
|
|
73
|
-
entering a phase, after any wake, and after any compaction, read the state
|
|
74
|
-
file, `git status`, the branch, the live agent list, and the issue or pull
|
|
75
|
-
request when the phase uses them. Live sources win over the file. Treat the
|
|
76
|
-
file as absent when its branch does not match the current branch.
|
|
77
|
-
When you overwrite the file, keep its `criteria` entry: phase 2 writes it
|
|
78
|
-
and the judge reads it.
|
|
79
|
-
Beside it, create `"$(git rev-parse --absolute-git-dir)/build-reports/"`,
|
|
80
|
-
emptied of any earlier run's files. Every spawned agent writes its full
|
|
81
|
-
report there and returns a summary of at most ten lines. Give each agent
|
|
82
|
-
the absolute path. Reports never land in the working tree, so review never
|
|
83
|
-
reads them as product code. Read summaries and pass file paths, never
|
|
84
|
-
report bodies. Delete both at the end of phase 6.
|
|
85
|
-
Once a pull request exists, read `outerlayer work threads --item
|
|
86
|
-
"$OUTERLAYER_WORK" --json`. Each thread with `waitingOn` of `agent` holds a
|
|
87
|
-
person's comment. Answer each before the run ends, as the `outerlayer-amend` skill does.
|
|
88
|
-
5. **A session never records a pass or fail on an artifact.** It emits
|
|
89
|
-
artifacts. A person decides pass or fail. A build records one result, the
|
|
90
|
-
verdict of its own review, on the `code-review` check. The
|
|
91
|
-
`acceptance-criteria` check is judged and recorded by the factory host. When
|
|
92
|
-
the item holds no criteria, no judge runs and the host records a fail
|
|
93
|
-
saying so.
|
|
94
|
-
6. **Observed status only.** Every status claim in the final report (a gate
|
|
95
|
-
result, a CI conclusion, mergeability) quotes command output observed
|
|
96
|
-
after the last change it describes. No quoted output means unknown, never
|
|
97
|
-
green. Quoted output goes in the report to the user. Pull request bodies
|
|
98
|
-
carry curated links, never raw output.
|
|
99
|
-
7. **Files no issue.** The build files no issue anywhere, and no agent does.
|
|
100
|
-
A defect outside the change, or a follow-up the fix pass deferred, becomes a
|
|
101
|
-
candidate issue in a report: a title, a body and a target repository. The
|
|
102
|
-
final report lists every candidate for the user to file with `/spec`.
|
|
103
|
-
8. **Reader pass.** No text reaches the git host as the session wrote it.
|
|
104
|
-
The pull request title and body, and every comment, go through one cold
|
|
105
|
-
rewrite agent. Its only inputs are the draft and the writing rule. It
|
|
106
|
-
returns the rewrite and the terms it cut or explained. Check that every
|
|
107
|
-
path, identifier, number, criterion id and link survived, and restore any
|
|
108
|
-
that did not.
|
|
109
|
-
9. **Run budget.** Spawn at most sixty agents in a run. Keep the count in the
|
|
110
|
-
state file. Past three quarters, say where the count stands in the status
|
|
111
|
-
line. A run that would exceed the budget stops and lists what is left
|
|
112
|
-
unverified. The review phase also holds a limit on agents in flight.
|
|
113
|
-
10. **Factory problems are findings.** Every agent records the problems it
|
|
114
|
-
hit outside the change with the `outerlayer-findings` skill, as its brief
|
|
115
|
-
says. The orchestrator records only the ones it hit itself. The final
|
|
116
|
-
report lists every finding by id.
|
|
117
|
-
|
|
118
|
-
## Phases
|
|
119
|
-
|
|
120
|
-
Run them in order.
|
|
121
|
-
|
|
122
|
-
1. **Intake.** Read `OUTERLAYER_WORK`. If it is missing or does not parse,
|
|
123
|
-
stop and hand back:
|
|
124
|
-
|
|
125
|
-
outerlayer work build --issue <reference> # once; prints the item number
|
|
126
|
-
OUTERLAYER_WORK=<number> claude "/build"
|
|
127
|
-
|
|
128
|
-
Run `outerlayer work status --item "$OUTERLAYER_WORK" --json` and read the
|
|
129
|
-
item's tracker key. It is a GitHub `#n`, or a Linear or Jira key. Read the
|
|
130
|
-
issue from the same JSON: `title`, and `issue`, which holds the issue as
|
|
131
|
-
OuterLayer last copied it from the tracker. `issue.body` is the
|
|
132
|
-
description in Markdown, and `url`, `state` and `labels` come with it. This
|
|
133
|
-
copy works for every tracker. A build often holds no Linear or Jira
|
|
134
|
-
credential, so do not depend on a tracker tool. Use one only to add what
|
|
135
|
-
the copy lacks, such as the issue's comments. When `issue.syncStatus` is
|
|
136
|
-
`unreadable`, the copy is from an earlier read: say so in the intake
|
|
137
|
-
summary. When it is `not_found`, or `issue.syncedAt` is null and no tracker
|
|
138
|
-
tool can read the issue, stop: there is no issue to build from.
|
|
139
|
-
Write the issue's title, URL and body to
|
|
140
|
-
`"$(git rev-parse --absolute-git-dir)/build-reports/issue.md"`. The issue
|
|
141
|
-
is the source of truth for the whole run. Every later agent is given that
|
|
142
|
-
file's path, so no agent needs a tracker tool to read it.
|
|
143
|
-
Restate the task in one or two sentences and confirm the issue is still
|
|
144
|
-
open (`issue.state`) and unclaimed. If the item shows a live claim by
|
|
145
|
-
another runner that has not expired, stop and name it.
|
|
146
|
-
Phase 2 finds the issue's criteria. If it finds some, they are the
|
|
147
|
-
definition of done, and each declares a proof form or a test. If it finds
|
|
148
|
-
none, the build drafts them from the issue's description, and the drafted
|
|
149
|
-
criteria are the definition of done in the same way. An issue is never
|
|
150
|
-
sent back for lacking criteria.
|
|
151
|
-
Ask nothing from here until the final report. An agent that needs a ruling
|
|
152
|
-
states its assumption in its report and continues. The final report lists
|
|
153
|
-
every assumption.
|
|
154
|
-
2. **Read the criteria.** Record the issue's criteria on the item, so the
|
|
155
|
-
Criteria tab, the item's status and the judge hold the pull request to one
|
|
156
|
-
list. Read the whole issue and find its acceptance criteria in whatever
|
|
157
|
-
form they are written: under a heading of any wording, as a checklist or
|
|
158
|
-
numbered items, as "done when" prose, with ids or without. There is no
|
|
159
|
-
fixed shape. Keep each criterion's text exactly as the author wrote it.
|
|
160
|
-
Never reword one. A criterion you think is wrong becomes a note in the
|
|
161
|
-
final report, never an edit.
|
|
162
|
-
|
|
163
|
-
Write them, in the order the issue lists them, to a file:
|
|
164
|
-
|
|
165
|
-
{ "criteria": [ { "id": "<the id, if the issue gives one>", "text": "<verbatim>", "proof": null } ] }
|
|
166
|
-
|
|
167
|
-
Give `proof` an artifact kind (`video`, `screenshot`, `report`, `log`,
|
|
168
|
-
`test` or `file`) only when the issue states that proof explicitly, as in
|
|
169
|
-
`(proof: screenshot)`. Never infer a proof kind from the words. Then run:
|
|
170
|
-
|
|
171
|
-
node .outerlayer/skills/build/scripts/record-criteria.mjs --item "$OUTERLAYER_WORK" --criteria-file <file>
|
|
172
|
-
|
|
173
|
-
The script keeps the issue's ids only when every criterion carries one
|
|
174
|
-
that fits the id grammar. Otherwise, a partly numbered list included, it
|
|
175
|
-
numbers every criterion `AC-<item number>-NN` in order, and the state file
|
|
176
|
-
says why. The final report says the criteria were numbered and from what.
|
|
177
|
-
A file the script cannot use exits 2 with the reason. Fix the file and
|
|
178
|
-
run it again.
|
|
179
|
-
|
|
180
|
-
When the issue has no criteria anywhere, draft them from the issue's
|
|
181
|
-
description. Each is one observable behavior the description asks for, in
|
|
182
|
-
its words, adding no scope it does not state. Write them to the same kind
|
|
183
|
-
of file without ids, set `proof` only when the description asks for that
|
|
184
|
-
proof, and run the script with `--drafted` added. It numbers the draft
|
|
185
|
-
`AC-<item number>-NN` and records it with `drafted: true`, so the Criteria
|
|
186
|
-
tab says the build drafted the list.
|
|
187
|
-
|
|
188
|
-
The script writes the list to
|
|
189
|
-
`"$(git rev-parse --absolute-git-dir)/build-reports/criteria.json"` and runs
|
|
190
|
-
`outerlayer emit criteria` on it. The gateway decides whether a list may be
|
|
191
|
-
recorded. A 409 means the item already has a recorded list. That list
|
|
192
|
-
stands, and nothing is recorded. No command returns the item's list, so the
|
|
193
|
-
build cannot read it: it holds the work to its own reading of the criteria
|
|
194
|
-
and says so in the final report. Any other refusal is written to the state
|
|
195
|
-
file with its message, and the build continues. The script writes the
|
|
196
|
-
outcome under `criteria` in the state file: `source` (`issue`, `drafted`,
|
|
197
|
-
`item`, or `none` when even a draft holds no criterion), `recorded`,
|
|
198
|
-
`count`, `list` and `numbered`. On a 409, `list` is empty, and the build's
|
|
199
|
-
reading of the criteria goes under `issueReading`.
|
|
200
|
-
|
|
201
|
-
Drafted criteria are tiered, proven and judged like any others. A drafted
|
|
202
|
-
list stands like any recorded list. A later build's record
|
|
203
|
-
answers 409 until a person replaces the list with
|
|
204
|
-
`outerlayer emit criteria`, even after criteria are added to the issue. The
|
|
205
|
-
final report says the criteria were drafted and how to replace them.
|
|
206
|
-
|
|
207
|
-
Change nothing in the issue. The intake summary names how many criteria
|
|
208
|
-
were recorded, whether they kept the issue's ids or were numbered, and
|
|
209
|
-
whether they were drafted.
|
|
210
|
-
3. **Implement.** When `OUTERLAYER_BRANCH` is set, as it is in a host's
|
|
211
|
-
build, work on that branch, checking it out if it is not current, and
|
|
212
|
-
push only to it: the host refuses a push to any other branch. Otherwise
|
|
213
|
-
branch `feat/<slug>` from the default branch. Spawn the implementer with the Implementer brief from
|
|
214
|
-
[references/agent-briefs.md](references/agent-briefs.md), the issue, the
|
|
215
|
-
drafted criteria with their ids when the build drafted them, the branch
|
|
216
|
-
and the instructions-file pointer. The phase ends when the
|
|
217
|
-
repository's own pre-push checks and tests pass on the branch. Review
|
|
218
|
-
never opens on a red branch. A branch that cannot go green escalates.
|
|
219
|
-
4. **Review.** Read [references/review-loop.md](references/review-loop.md) on
|
|
220
|
-
entry and run it. It sizes the panel to the finished diff: one generalist
|
|
221
|
-
for a small diff, the generalist and one focused reviewer for a medium
|
|
222
|
-
one, the generalist and up to three for a large or risky one. Findings are
|
|
223
|
-
merged into classes, checked by a refuter, fixed, and rechecked once. Then
|
|
224
|
-
write the review report as an HTML file and emit it:
|
|
225
|
-
|
|
226
|
-
outerlayer emit artifact <report>.html --caption "Review of the change and what it found"
|
|
227
|
-
|
|
228
|
-
Its verdict is recorded on the `code-review` check once the pull request
|
|
229
|
-
is open, as release.md says.
|
|
230
|
-
|
|
231
|
-
5. **Sync and pull request.** Read [references/release.md](references/release.md)
|
|
232
|
-
on entry and run it. A release agent rebases, gates and pushes. Open the
|
|
233
|
-
pull request as release.md says: a runner build with `outerlayer work open-pr`,
|
|
234
|
-
which links it, and a local session with `gh pr create` and then
|
|
235
|
-
`outerlayer work pr <number>`. When the build recorded criteria, from the issue or drafted, a fresh agent judges them with
|
|
236
|
-
[references/criteria-judge.md](references/criteria-judge.md), and the
|
|
237
|
-
judge's HTML report is linked to its tests and emitted:
|
|
238
|
-
|
|
239
|
-
node .outerlayer/skills/build/scripts/criterion-citations.mjs --report <judge-report>.html
|
|
240
|
-
outerlayer emit artifact <judge-report>.html --for acceptance-criteria --caption "Each criterion judged against its test"
|
|
241
|
-
|
|
242
|
-
The build does not record that verdict: the factory host judges the
|
|
243
|
-
criteria itself and records the `acceptance-criteria` check, as release.md
|
|
244
|
-
says. When the state file holds no criteria, no judge runs.
|
|
245
|
-
Watch CI until every check has concluded.
|
|
246
|
-
6. **Manual test and evidence.** Read [references/evidence.md](references/evidence.md)
|
|
247
|
-
when the pull request opens, and run it. Capture the proof each criterion
|
|
248
|
-
declares, emit it. Then release the lease.
|
|
249
|
-
7. **Release the lease.** Run this last, after the pull request is open and
|
|
250
|
-
the evidence is emitted, and run no other tool call after it:
|
|
251
|
-
|
|
252
|
-
outerlayer work release --item "$OUTERLAYER_WORK"
|
|
253
|
-
|
|
254
|
-
A session that names a work item holds a lease on it, and review stays
|
|
255
|
-
closed until the lease is released. In a session this command releases the
|
|
256
|
-
session's own lease and no one else's. A later tool call takes the lease
|
|
257
|
-
again, so write the final report as plain text once this has run. Skip this
|
|
258
|
-
step in a runner build, whose host releases its own lease. Then end the run
|
|
259
|
-
with the final report. The report lists every candidate issue and every
|
|
260
|
-
assumption.
|
|
11
|
+
None yet. Add a change under the name of the phase it applies to: Intake, Criteria, Implement, Review, Pull request, Evidence.
|
package/dist/build-TQ6X5PYN.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
export { buildRepositoryImage } from './chunk-3CWUOFV6.js';
|
|
4
|
-
export { RecipeError } from './chunk-QOZKPLVJ.js';
|
|
5
|
-
import './chunk-CX22S5BA.js';
|
|
6
|
-
import './chunk-ECODQ7II.js';
|
|
7
|
-
import './chunk-JBJTC3UU.js';
|
|
8
|
-
import './chunk-N2PXGQRL.js';
|
|
9
|
-
import './chunk-BQXFBI7T.js';
|
|
10
|
-
import './chunk-Z5GEFMRW.js';
|
|
11
|
-
|
|
12
|
-
createRequire(import.meta.url);
|
package/dist/chunk-3UZTIRLF.js
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import { parseSize } from './chunk-7RQ73DLO.js';
|
|
4
|
-
import { BUILDKIT_IMAGE } from './chunk-CX22S5BA.js';
|
|
5
|
-
import { compareVersions } from './chunk-QNLX477Q.js';
|
|
6
|
-
import { runnerDir } from './chunk-N2PXGQRL.js';
|
|
7
|
-
import { CLAUDE_PORT, JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-BQXFBI7T.js';
|
|
8
|
-
import { createHash } from 'crypto';
|
|
9
|
-
import { realpathSync } from 'fs';
|
|
10
|
-
import { join, dirname, resolve } from 'path';
|
|
11
|
-
|
|
12
|
-
createRequire(import.meta.url);
|
|
13
|
-
|
|
14
|
-
// src/runner/judge-command.ts
|
|
15
|
-
var JUDGE_DIR = "/outerlayer/judge";
|
|
16
|
-
var JUDGE_HOME = `${JUDGE_DIR}/home`;
|
|
17
|
-
var JUDGE_TREE = `${JUDGE_DIR}/tree`;
|
|
18
|
-
var JUDGE_REPORT = `${JUDGE_DIR}/report.html`;
|
|
19
|
-
var JUDGE_PROGRAM = "/opt/outerlayer/claude/bin/claude";
|
|
20
|
-
var MAX_REPORT_BYTES = 5 * 1024 * 1024;
|
|
21
|
-
var JUDGE_MAX_TURNS = 60;
|
|
22
|
-
var JUDGE_PATH = "/opt/outerlayer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
23
|
-
var JUDGE_TOOLS = "Read,Grep,Glob,Write";
|
|
24
|
-
function judgeCommand(input) {
|
|
25
|
-
const env = {
|
|
26
|
-
HOME: JUDGE_HOME,
|
|
27
|
-
TMPDIR: `${JUDGE_HOME}/tmp`,
|
|
28
|
-
PATH: JUDGE_PATH,
|
|
29
|
-
ANTHROPIC_BASE_URL: `http://127.0.0.1:${CLAUDE_PORT}`,
|
|
30
|
-
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
|
|
31
|
-
DISABLE_AUTOUPDATER: "1",
|
|
32
|
-
...input.credential === void 0 ? {} : { [input.credential.variable]: input.credential.placeholder }
|
|
33
|
-
};
|
|
34
|
-
const argv = [
|
|
35
|
-
JUDGE_PROGRAM,
|
|
36
|
-
"-p",
|
|
37
|
-
"--output-format",
|
|
38
|
-
"json",
|
|
39
|
-
"--setting-sources",
|
|
40
|
-
"user",
|
|
41
|
-
"--strict-mcp-config",
|
|
42
|
-
"--disable-slash-commands",
|
|
43
|
-
"--no-session-persistence",
|
|
44
|
-
"--tools",
|
|
45
|
-
JUDGE_TOOLS,
|
|
46
|
-
"--allowedTools",
|
|
47
|
-
// A path that starts with two slashes is absolute in a permission rule.
|
|
48
|
-
`Read(/${JUDGE_DIR}/**),Edit(/${JUDGE_REPORT})`,
|
|
49
|
-
"--add-dir",
|
|
50
|
-
JUDGE_TREE,
|
|
51
|
-
"--permission-mode",
|
|
52
|
-
"dontAsk",
|
|
53
|
-
"--max-turns",
|
|
54
|
-
String(JUDGE_MAX_TURNS),
|
|
55
|
-
// After the separator, so a brief that starts with a dash is not read as an option.
|
|
56
|
-
"--",
|
|
57
|
-
input.brief
|
|
58
|
-
];
|
|
59
|
-
return { argv, env, cwd: JUDGE_DIR };
|
|
60
|
-
}
|
|
61
|
-
var HASH_SCRIPT = 'const fs=require("fs"),c=require("crypto");const p=fs.realpathSync(process.argv[1]);process.stdout.write(c.createHash("sha256").update(fs.readFileSync(p)).digest("hex")+" "+p+"\\n")';
|
|
62
|
-
var HASH_ARGV = ["/opt/outerlayer/bin/node", "-e", HASH_SCRIPT, JUDGE_PROGRAM];
|
|
63
|
-
function parseProgramHash(stdout) {
|
|
64
|
-
return /^([0-9a-f]{64}) /.exec(stdout.trim())?.[1];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// src/runner/container/run-args.ts
|
|
68
|
-
var BUILD_LABEL = "ai.outerlayer.build";
|
|
69
|
-
var RUNNER_LABEL = "ai.outerlayer.runner";
|
|
70
|
-
function resolvedRunnerDir(configPath) {
|
|
71
|
-
try {
|
|
72
|
-
return realpathSync(runnerDir(configPath));
|
|
73
|
-
} catch {
|
|
74
|
-
try {
|
|
75
|
-
return join(realpathSync(dirname(resolve(configPath))), "runner");
|
|
76
|
-
} catch {
|
|
77
|
-
return resolve(runnerDir(configPath));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function runnerLabelValue(configPath) {
|
|
82
|
-
return createHash("sha256").update(resolvedRunnerDir(configPath)).digest("hex").slice(0, 12);
|
|
83
|
-
}
|
|
84
|
-
function hardened(input) {
|
|
85
|
-
const { memory, cpus, pids, cpuset } = input.limits;
|
|
86
|
-
return [
|
|
87
|
-
"--label",
|
|
88
|
-
`${BUILD_LABEL}=${input.buildId}`,
|
|
89
|
-
"--label",
|
|
90
|
-
`${RUNNER_LABEL}=${input.runnerId}`,
|
|
91
|
-
"--network",
|
|
92
|
-
"none",
|
|
93
|
-
"--cap-drop",
|
|
94
|
-
"ALL",
|
|
95
|
-
"--security-opt",
|
|
96
|
-
"no-new-privileges",
|
|
97
|
-
"--read-only",
|
|
98
|
-
"--user",
|
|
99
|
-
input.user,
|
|
100
|
-
// The same figure for swap as for memory leaves the container none.
|
|
101
|
-
"--memory",
|
|
102
|
-
memory,
|
|
103
|
-
"--memory-swap",
|
|
104
|
-
memory,
|
|
105
|
-
"--cpus",
|
|
106
|
-
String(cpus),
|
|
107
|
-
...cpuset === void 0 ? [] : ["--cpuset-cpus", cpuset],
|
|
108
|
-
"--pids-limit",
|
|
109
|
-
String(pids)
|
|
110
|
-
];
|
|
111
|
-
}
|
|
112
|
-
function mountPath(path) {
|
|
113
|
-
if (/[",]/.test(path)) throw new Error(`${path} holds a comma or a quote, which a Docker mount cannot carry; move the runner's config file`);
|
|
114
|
-
return path;
|
|
115
|
-
}
|
|
116
|
-
function containerRunArgs(input) {
|
|
117
|
-
return [
|
|
118
|
-
"--detach",
|
|
119
|
-
"--name",
|
|
120
|
-
input.container,
|
|
121
|
-
...hardened(input),
|
|
122
|
-
"--mount",
|
|
123
|
-
`type=volume,src=${input.volume},dst=/build`,
|
|
124
|
-
// `/tmp` is a directory of the same volume, so it is measured and limited with the rest of the build.
|
|
125
|
-
"--mount",
|
|
126
|
-
`type=volume,src=${input.volume},dst=/tmp,volume-subpath=tmp`,
|
|
127
|
-
"--mount",
|
|
128
|
-
`type=bind,src=${mountPath(input.buildDir)},dst=${JOB_MOUNT},readonly`,
|
|
129
|
-
...input.judgeDir === void 0 ? [] : ["--mount", `type=bind,src=${mountPath(input.judgeDir)},dst=${JUDGE_DIR}`],
|
|
130
|
-
"--entrypoint",
|
|
131
|
-
"/opt/outerlayer/bin/tini",
|
|
132
|
-
input.image,
|
|
133
|
-
"--",
|
|
134
|
-
"/opt/outerlayer/bin/node",
|
|
135
|
-
"/opt/outerlayer/cli/dist/index.js",
|
|
136
|
-
"broker-relay",
|
|
137
|
-
"--port",
|
|
138
|
-
String(RELAY_PORT),
|
|
139
|
-
"--socket",
|
|
140
|
-
`${JOB_MOUNT}/tunnel.sock`,
|
|
141
|
-
...Array.from({ length: input.destinations ?? 0 }, (_unused, index) => [
|
|
142
|
-
"--forward",
|
|
143
|
-
`${DESTINATION_BASE_PORT + index}=${JOB_MOUNT}/dest-${index}.sock`
|
|
144
|
-
]).flat(),
|
|
145
|
-
...input.builtIns === true ? [
|
|
146
|
-
"--forward",
|
|
147
|
-
`${GATEWAY_PORT}=${JOB_MOUNT}/${GATEWAY_SOCKET}`,
|
|
148
|
-
"--forward",
|
|
149
|
-
`${CLAUDE_PORT}=${JOB_MOUNT}/${CLAUDE_SOCKET}`
|
|
150
|
-
] : []
|
|
151
|
-
];
|
|
152
|
-
}
|
|
153
|
-
function prepareRunArgs(input) {
|
|
154
|
-
return [
|
|
155
|
-
"--rm",
|
|
156
|
-
...hardened(input),
|
|
157
|
-
"--mount",
|
|
158
|
-
`type=volume,src=${input.volume},dst=/build`,
|
|
159
|
-
"--entrypoint",
|
|
160
|
-
"mkdir",
|
|
161
|
-
input.image,
|
|
162
|
-
"-p",
|
|
163
|
-
"-m",
|
|
164
|
-
"1777",
|
|
165
|
-
"/build/tmp",
|
|
166
|
-
"/build/home",
|
|
167
|
-
"/build/work"
|
|
168
|
-
];
|
|
169
|
-
}
|
|
170
|
-
function containerExecArgs(input) {
|
|
171
|
-
const literals = Object.keys(input.env.literals).sort().flatMap((name) => ["-e", `${name}=${input.env.literals[name]}`]);
|
|
172
|
-
const passed = Object.keys(input.env.passed).filter((name) => input.env.passed[name] !== void 0).sort().flatMap((name) => ["-e", name]);
|
|
173
|
-
return [
|
|
174
|
-
"-u",
|
|
175
|
-
input.user,
|
|
176
|
-
...input.workdir === void 0 ? [] : ["-w", input.workdir],
|
|
177
|
-
...literals,
|
|
178
|
-
...passed,
|
|
179
|
-
input.container,
|
|
180
|
-
...input.argv
|
|
181
|
-
];
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/runner/image/builder.ts
|
|
185
|
-
var MIN_BUILDX_VERSION = "0.18.0";
|
|
186
|
-
var INSTALL_HINT = "install Docker's Buildx plugin (docker-buildx-plugin on Debian and Ubuntu with Docker's apt repository, docker-buildx on Ubuntu's own packages)";
|
|
187
|
-
function builderName(configPath) {
|
|
188
|
-
return `outerlayer-${runnerLabelValue(configPath)}`;
|
|
189
|
-
}
|
|
190
|
-
function proxyEnvironment(env) {
|
|
191
|
-
const found = {};
|
|
192
|
-
for (const name of ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy"]) {
|
|
193
|
-
const value = env[name];
|
|
194
|
-
if (value !== void 0 && value !== "") found[name] = value;
|
|
195
|
-
}
|
|
196
|
-
return found;
|
|
197
|
-
}
|
|
198
|
-
function builderSpec(configPath, memory, env) {
|
|
199
|
-
return { name: builderName(configPath), memory, env: proxyEnvironment(env) };
|
|
200
|
-
}
|
|
201
|
-
function driverOpt(pair) {
|
|
202
|
-
return /[",]/.test(pair) ? `"${pair.replace(/"/g, '""')}"` : pair;
|
|
203
|
-
}
|
|
204
|
-
async function buildxState(run) {
|
|
205
|
-
const result = await run("docker", ["buildx", "version"]);
|
|
206
|
-
if (result.status !== 0) {
|
|
207
|
-
const said = (result.stderr.trim() || result.stdout.trim()).split("\n")[0] ?? "";
|
|
208
|
-
return { problem: `docker buildx is not available${said === "" ? "" : ` (${said})`}, so image builds cannot be limited; ${INSTALL_HINT}` };
|
|
209
|
-
}
|
|
210
|
-
const version = /\bv?(\d+\.\d+\.\d+)/.exec(result.stdout)?.[1];
|
|
211
|
-
if (version !== void 0 && compareVersions(version, MIN_BUILDX_VERSION) < 0) {
|
|
212
|
-
return { problem: `docker buildx ${version} is too old: the runner's image builder needs Buildx ${MIN_BUILDX_VERSION} or later; update ${INSTALL_HINT}` };
|
|
213
|
-
}
|
|
214
|
-
return "usable";
|
|
215
|
-
}
|
|
216
|
-
function isOutOfMemory(output) {
|
|
217
|
-
if (/cannot allocate memory/i.test(output)) return true;
|
|
218
|
-
if (/did not complete successfully: (exit code: 137|signal: killed)/i.test(output)) return true;
|
|
219
|
-
return /ResourceExhausted/i.test(output) && !/larger than max|message size|too large/i.test(output);
|
|
220
|
-
}
|
|
221
|
-
var running = 0;
|
|
222
|
-
async function trackImageBuild(work) {
|
|
223
|
-
running++;
|
|
224
|
-
try {
|
|
225
|
-
return await work();
|
|
226
|
-
} finally {
|
|
227
|
-
running--;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
var queue = Promise.resolve();
|
|
231
|
-
function serialized(work) {
|
|
232
|
-
const next = queue.then(work, work);
|
|
233
|
-
queue = next.catch(() => void 0);
|
|
234
|
-
return next;
|
|
235
|
-
}
|
|
236
|
-
function readExisting(inspectOutput) {
|
|
237
|
-
const options = /^Driver Options:\s*(.*)$/m.exec(inspectOutput)?.[1] ?? "";
|
|
238
|
-
const option = (key) => new RegExp(`(?:^|\\s)${key}="([^"]*)"`).exec(options)?.[1];
|
|
239
|
-
return { driver: /^Driver:\s*(\S+)/m.exec(inspectOutput)?.[1], memory: option("memory"), image: option("image") };
|
|
240
|
-
}
|
|
241
|
-
function sameMemory(found, wanted) {
|
|
242
|
-
return (parseSize(found) ?? found) === (parseSize(wanted) ?? wanted);
|
|
243
|
-
}
|
|
244
|
-
var IDLE_POLL_MS = 1e3;
|
|
245
|
-
var failures = 0;
|
|
246
|
-
function ensureFailureCount() {
|
|
247
|
-
return failures;
|
|
248
|
-
}
|
|
249
|
-
function ensureBuilder(rawRun, spec, options = {}) {
|
|
250
|
-
const run = (command, args, opts) => rawRun(command, args, { ...opts, timeoutMs: args.includes("--bootstrap") ? 15 * 6e4 : 2 * 6e4 });
|
|
251
|
-
const result = serialized(async () => {
|
|
252
|
-
const state = await buildxState(run);
|
|
253
|
-
if (state !== "usable") return { ok: false, problem: state.problem };
|
|
254
|
-
const sleep = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
|
|
255
|
-
const inspected = await run("docker", ["buildx", "inspect", spec.name]);
|
|
256
|
-
let create = inspected.status !== 0;
|
|
257
|
-
if (!create) {
|
|
258
|
-
const found = readExisting(inspected.stdout);
|
|
259
|
-
const current = found.driver === "docker-container" && sameMemory(found.memory ?? "", spec.memory) && found.image === BUILDKIT_IMAGE;
|
|
260
|
-
if (!current && options.replaceStale === false) {
|
|
261
|
-
return {
|
|
262
|
-
ok: false,
|
|
263
|
-
problem: `the image builder ${spec.name} was made with other settings than runner.build.memory (${spec.memory}) and the pinned BuildKit image; the runner service replaces it when no build is running, or remove it with docker buildx rm ${spec.name}`
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
if (!current) {
|
|
267
|
-
if (options.waitForIdle === true) while (running > 0) await sleep(IDLE_POLL_MS);
|
|
268
|
-
if (running === 0) {
|
|
269
|
-
const removed = await run("docker", ["buildx", "rm", spec.name]);
|
|
270
|
-
if (removed.status !== 0) return { ok: false, problem: `could not replace the image builder ${spec.name}: ${removed.stderr.trim() || `docker exited ${removed.status}`}` };
|
|
271
|
-
create = true;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (create) {
|
|
276
|
-
const opts = [
|
|
277
|
-
`memory=${spec.memory}`,
|
|
278
|
-
`memory-swap=${spec.memory}`,
|
|
279
|
-
`image=${BUILDKIT_IMAGE}`,
|
|
280
|
-
...Object.entries(spec.env ?? {}).map(([name, value]) => `env.${name}=${value}`),
|
|
281
|
-
...spec.driverOpts ?? []
|
|
282
|
-
];
|
|
283
|
-
const created = await run("docker", [
|
|
284
|
-
"buildx",
|
|
285
|
-
"create",
|
|
286
|
-
"--name",
|
|
287
|
-
spec.name,
|
|
288
|
-
"--driver",
|
|
289
|
-
"docker-container",
|
|
290
|
-
...opts.flatMap((opt) => ["--driver-opt", driverOpt(opt)])
|
|
291
|
-
]);
|
|
292
|
-
if (created.status !== 0) {
|
|
293
|
-
const said = created.stderr.trim() || `docker exited ${created.status}`;
|
|
294
|
-
if (/failed to find driver/i.test(said)) {
|
|
295
|
-
return { ok: false, problem: `this Docker's Buildx has no docker-container driver, so image builds cannot be limited; ${INSTALL_HINT}` };
|
|
296
|
-
}
|
|
297
|
-
return { ok: false, problem: `could not create the image builder ${spec.name}: ${said}` };
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
if (options.bootstrap === true) {
|
|
301
|
-
const started = await run("docker", ["buildx", "inspect", "--bootstrap", spec.name]);
|
|
302
|
-
if (started.status !== 0) {
|
|
303
|
-
return { ok: false, problem: `the image builder ${spec.name} did not start: ${started.stderr.trim() || `docker exited ${started.status}`}` };
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return { ok: true, changed: create };
|
|
307
|
-
});
|
|
308
|
-
return result.then(
|
|
309
|
-
(outcome) => {
|
|
310
|
-
if (!outcome.ok) failures++;
|
|
311
|
-
return outcome;
|
|
312
|
-
},
|
|
313
|
-
(err) => {
|
|
314
|
-
failures++;
|
|
315
|
-
throw err;
|
|
316
|
-
}
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
export { BUILD_LABEL, HASH_ARGV, JUDGE_DIR, JUDGE_MAX_TURNS, JUDGE_PROGRAM, MAX_REPORT_BYTES, MIN_BUILDX_VERSION, RUNNER_LABEL, builderName, builderSpec, buildxState, containerExecArgs, containerRunArgs, ensureBuilder, ensureFailureCount, isOutOfMemory, judgeCommand, parseProgramHash, prepareRunArgs, proxyEnvironment, runnerLabelValue, trackImageBuild };
|
package/dist/chunk-CX22S5BA.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
|
|
4
|
-
createRequire(import.meta.url);
|
|
5
|
-
|
|
6
|
-
// src/runner/image/pins.ts
|
|
7
|
-
var CLAUDE_CODE_VERSION = "2.1.284";
|
|
8
|
-
var DEFAULT_BASE_IMAGE = "ubuntu:24.04@sha256:008173c23f95b170204355c12626cb5a965d779a7e1283b09e9cffbb1bf33ca3";
|
|
9
|
-
var NODE_IMAGE = "node:22-bookworm-slim@sha256:43ac6c60b8f89723f746e8a92ce91abd5017e627ce1ddfe4238355d3a30b772c";
|
|
10
|
-
var BUILDKIT_IMAGE = "moby/buildkit:v0.33.1@sha256:cec9f139f45e93c5c69c60f8b07cfad9f43f4ef6b6a6cd917527fea5ff2e3dea";
|
|
11
|
-
var GH_VERSION = "2.101.0";
|
|
12
|
-
var GH_SHA256 = {
|
|
13
|
-
amd64: "9bca2d1c16825f109907a23307628a2f0698fbf99662b73a5cf0b020293072b8",
|
|
14
|
-
arm64: "b57e8063f18862647c9d22727c32e9da1b963f8bf9db648fe123a6975695640f"
|
|
15
|
-
};
|
|
16
|
-
var TINI_VERSION = "0.19.0";
|
|
17
|
-
var TINI_SHA256 = {
|
|
18
|
-
amd64: "c5b0666b4cb676901f90dfcb37106783c5fe2077b04590973b885950611b30ee",
|
|
19
|
-
arm64: "eae1d3aa50c48fb23b8cbdf4e369d0910dfc538566bfd09df89a774aa84a48b9"
|
|
20
|
-
};
|
|
21
|
-
var MICROVM_ARCHES = ["x86_64"];
|
|
22
|
-
function firecrackerArch(nodeArch) {
|
|
23
|
-
return nodeArch === "x64" ? "x86_64" : nodeArch === "arm64" ? "aarch64" : nodeArch;
|
|
24
|
-
}
|
|
25
|
-
var FIRECRACKER_VERSION = "1.13.1";
|
|
26
|
-
var FIRECRACKER_SHA256 = {
|
|
27
|
-
x86_64: "59450b9171ff2ebdf2f9a25be3a248a7ba79fb6371aec51a9d6d8eefca7b4faf"
|
|
28
|
-
};
|
|
29
|
-
var FIRECRACKER_BINARY_SHA256 = {
|
|
30
|
-
x86_64: "7d3924e0c8761edafbf85cb2a94c268ffad249644a40fd02d4e15cde4c206f6e"
|
|
31
|
-
};
|
|
32
|
-
var GUEST_ASSETS_VERSION = "1";
|
|
33
|
-
var GUEST_ASSETS_BASE_URL = `https://github.com/outerlayerai/guest-assets/releases/download/guest-${GUEST_ASSETS_VERSION}`;
|
|
34
|
-
var GUEST_KERNEL_SHA256 = {
|
|
35
|
-
x86_64: "5a2d716d301615c69fefc2f9574954e838269f14d5e8b0d1bad88b680cd372ee"
|
|
36
|
-
};
|
|
37
|
-
var GUEST_HELPER_SHA256 = {
|
|
38
|
-
x86_64: "4175e89ae8cb633113b5f69ef8b6e206093954411fe53edf86357bc1b7e822f9"
|
|
39
|
-
};
|
|
40
|
-
function guestAssetsPinned(arch) {
|
|
41
|
-
const zero = "0".repeat(64);
|
|
42
|
-
return GUEST_KERNEL_SHA256[arch] !== zero && GUEST_HELPER_SHA256[arch] !== zero;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export { BUILDKIT_IMAGE, CLAUDE_CODE_VERSION, DEFAULT_BASE_IMAGE, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, FIRECRACKER_VERSION, GH_SHA256, GH_VERSION, GUEST_ASSETS_BASE_URL, GUEST_ASSETS_VERSION, GUEST_HELPER_SHA256, GUEST_KERNEL_SHA256, MICROVM_ARCHES, NODE_IMAGE, TINI_SHA256, TINI_VERSION, firecrackerArch, guestAssetsPinned };
|