@outerlayer/cli 0.33.0-next.20261022195547 → 0.33.0-next.20261023003700

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 (119) hide show
  1. package/README.md +5 -0
  2. package/dist/{agent-setup-RJOVRRHK.js → agent-setup-55ZDEXCS.js} +6 -6
  3. package/dist/{bridge-BCG2EB7F.js → bridge-NBCXFTT4.js} +2 -2
  4. package/dist/{build-GKCVFHF4.js → build-SEAQVLD5.js} +5 -5
  5. package/dist/build-disk-JHTMPRAA.js +16 -0
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-DPNHJXG3.js → builder-Y4P7QARW.js} +5 -6
  8. package/dist/{check-64UX323V.js → check-MRYFTLOO.js} +36 -40
  9. package/dist/{chunk-D3HRAPNF.js → chunk-2EGCI2VW.js} +3424 -2700
  10. package/dist/{chunk-3MXPS7ED.js → chunk-2N67C6IV.js} +5 -4
  11. package/dist/{chunk-ZQOSIMKU.js → chunk-2WMZPJVE.js} +6 -3
  12. package/dist/{chunk-ZXBQ6E72.js → chunk-3RIFVLPO.js} +15 -10
  13. package/dist/{chunk-UOFBHIOZ.js → chunk-57L2YAJA.js} +1 -1
  14. package/dist/{chunk-6NWS455T.js → chunk-5THSC6BD.js} +1 -1
  15. package/dist/{chunk-QL3LPZ67.js → chunk-6LBSAW6I.js} +1 -1
  16. package/dist/{chunk-WPGBDY73.js → chunk-6RKD7YZ6.js} +1 -1
  17. package/dist/{chunk-77B36F5K.js → chunk-6Z4SZHV2.js} +4 -3
  18. package/dist/chunk-7HHNGZS5.js +146 -0
  19. package/dist/{chunk-DETKDTNL.js → chunk-AU346ENF.js} +3 -2
  20. package/dist/chunk-B2JURP6A.js +41 -0
  21. package/dist/{chunk-BCCI32ME.js → chunk-BALIE3BA.js} +36 -7
  22. package/dist/{chunk-BY36DVJV.js → chunk-BKADJZ7F.js} +3 -2
  23. package/dist/{chunk-CUBIZBMF.js → chunk-DISTLL2Q.js} +3 -3
  24. package/dist/{chunk-GN2R5Z7G.js → chunk-DXJTBU7A.js} +3 -3
  25. package/dist/{chunk-WCELNMXT.js → chunk-EUVE2EAE.js} +2 -2
  26. package/dist/{chunk-DDS2ISML.js → chunk-F5UL23I2.js} +1 -1
  27. package/dist/{chunk-43PV5KDB.js → chunk-FR7HWWCF.js} +37 -6
  28. package/dist/{chunk-JEKENLLA.js → chunk-GH246BGV.js} +1 -1
  29. package/dist/{chunk-ZRRUWNJS.js → chunk-HE4FBF4T.js} +4 -4
  30. package/dist/{chunk-W5DOK7BL.js → chunk-HVRQQOMH.js} +3 -3
  31. package/dist/{chunk-6IKSUAIA.js → chunk-HXA5GIHK.js} +61 -3
  32. package/dist/{chunk-2QT4JUW3.js → chunk-IP7BIBXJ.js} +1 -35
  33. package/dist/{chunk-LWTBE5J6.js → chunk-L26V6ILJ.js} +1 -1
  34. package/dist/{chunk-SK4TWCN3.js → chunk-MZBQTVFG.js} +1 -1
  35. package/dist/{chunk-YKYCE4HY.js → chunk-MZYOUIY5.js} +1 -1
  36. package/dist/{chunk-OWDSO3PE.js → chunk-NBZ7XBT6.js} +1 -1
  37. package/dist/{chunk-TGHBOXKJ.js → chunk-NE63JADS.js} +2 -2
  38. package/dist/{chunk-AGZNCIIJ.js → chunk-PA6CK6WQ.js} +1 -1
  39. package/dist/{chunk-L6JFFP3Q.js → chunk-PWH3BEZF.js} +55 -283
  40. package/dist/{chunk-QDMMW5PC.js → chunk-Q2CMEQV7.js} +2 -2
  41. package/dist/{chunk-DJWKUQLO.js → chunk-QPWFVE3X.js} +1 -1
  42. package/dist/{chunk-5BNWAIHN.js → chunk-RQJMN5TJ.js} +47 -7
  43. package/dist/{chunk-H7A3IQH5.js → chunk-SDU2IE22.js} +72 -28
  44. package/dist/{chunk-AA6LYZC4.js → chunk-SOI6K5DY.js} +1 -1
  45. package/dist/{chunk-35IY5HQY.js → chunk-SVDOA4W2.js} +1 -1
  46. package/dist/{chunk-RBJG5MM4.js → chunk-T5REPMNL.js} +5 -5
  47. package/dist/{chunk-6KLPC4U7.js → chunk-ULBNTSAD.js} +3 -2
  48. package/dist/{chunk-CMKY36NV.js → chunk-VT4TTJPG.js} +6 -5
  49. package/dist/chunk-W2AEL4BJ.js +179 -0
  50. package/dist/{chunk-6C2YWM6N.js → chunk-XHHTMFCX.js} +1 -1
  51. package/dist/{chunk-FAZDYI2D.js → chunk-XL2XWWU7.js} +3 -2
  52. package/dist/{chunk-KLXWS5Z7.js → chunk-YXHKCHWG.js} +4 -4
  53. package/dist/{chunk-GWDS42JC.js → chunk-Z5IW4DHH.js} +1 -1
  54. package/dist/{claude-launcher-66GKNIRZ.js → claude-launcher-NTYHJUJM.js} +1 -1
  55. package/dist/{cli-WICFAKFW.js → cli-K6XGL4EZ.js} +126 -102
  56. package/dist/{command-VGR24IPI.js → command-7FAIIQGF.js} +25 -26
  57. package/dist/{config-DUY2PT7K.js → config-QXMUWJAQ.js} +10 -4
  58. package/dist/{connect-cmd-ADRPR6ES.js → connect-cmd-P5GASVAF.js} +5 -5
  59. package/dist/{container-start-QX53HKXW.js → container-start-CVP3NTDG.js} +23 -26
  60. package/dist/context-show-cmd-3EPJ7CJC.js +115 -0
  61. package/dist/{control-plane-launch-SMHL6MWW.js → control-plane-launch-A3YCHQNQ.js} +5 -5
  62. package/dist/{docker-GGRJHHBP.js → docker-ANW76BNW.js} +5 -6
  63. package/dist/{doctor-N3CDJ66I.js → doctor-GJAHI3KU.js} +32 -39
  64. package/dist/{emit-artifact-cmd-73OWUBH6.js → emit-artifact-cmd-FDPJKGOO.js} +11 -10
  65. package/dist/{emit-criteria-cmd-D7OR356Y.js → emit-criteria-cmd-3SVGCMJN.js} +8 -7
  66. package/dist/{emit-demo-cmd-4AV74GMZ.js → emit-demo-cmd-6DF2QIAS.js} +12 -11
  67. package/dist/{emit-finding-cmd-GEPRJ6KO.js → emit-finding-cmd-TLJWBGQE.js} +8 -7
  68. package/dist/{emit-result-cmd-N52IABK6.js → emit-result-cmd-CJNVDV5V.js} +10 -9
  69. package/dist/{emit-step-cmd-CC6MUJ2S.js → emit-step-cmd-347CZO7Y.js} +8 -7
  70. package/dist/{exec-client-KLI262IX.js → exec-client-7PT4W7JR.js} +3 -3
  71. package/dist/{findings-cmd-7I72XX2H.js → findings-cmd-LHTYEHYB.js} +8 -7
  72. package/dist/{fleet-readiness-EZAGL32M.js → fleet-readiness-KGR5AC2J.js} +5 -5
  73. package/dist/{governing-source-M7ZRJCGY.js → governing-source-JZQZUTMA.js} +10 -9
  74. package/dist/{guest-init-ZJIE6MU3.js → guest-init-J3F3AEEY.js} +4 -4
  75. package/dist/{hook-fast-WNKICZ6E.js → hook-fast-6WDMNZG5.js} +1 -1
  76. package/dist/{pending-I5TY6SQH.js → host-key-UERIQRE6.js} +3 -3
  77. package/dist/{image-tag-MORUQ4LF.js → image-tag-ADSLWXBA.js} +3 -3
  78. package/dist/index.js +4 -4
  79. package/dist/{init-VCWDBOT4.js → init-XDOKWBL2.js} +22 -25
  80. package/dist/{init-XG4NRZX4.js → init-ZQ5B3TJZ.js} +22 -25
  81. package/dist/{init-cmd-2CAMWMRP.js → init-cmd-YMGW2WXJ.js} +11 -10
  82. package/dist/{init-update-NCM4GA3S.js → init-update-X7YLZL6H.js} +8 -8
  83. package/dist/install-QPA7DQHO.js +19 -0
  84. package/dist/{install-cmd-HFGINYEE.js → install-cmd-FV7IZ7XF.js} +5 -5
  85. package/dist/{logs-QSKJ4G6M.js → logs-HI46FO6Z.js} +2 -2
  86. package/dist/{loop-PXALY3VY.js → loop-UJL2UCUM.js} +36 -40
  87. package/dist/{machine-AZRL432D.js → machine-2YPAFFCH.js} +22 -21
  88. package/dist/{mcp-serve-cmd-DQSO6MOL.js → mcp-serve-cmd-7ABBV2QE.js} +4 -4
  89. package/dist/{paths-KHDFSBEI.js → paths-7HVTDE6J.js} +2 -2
  90. package/dist/{host-key-REZADWAM.js → pending-5HZACM2V.js} +3 -3
  91. package/dist/{pidfile-BSY63HIC.js → pidfile-5UDLYPMC.js} +3 -3
  92. package/dist/{record-7CNTGRLD.js → record-PPZEXAVA.js} +3 -3
  93. package/dist/runner-env-HOUXKWIJ.js +20 -0
  94. package/dist/{runner-identity-WGH73DTV.js → runner-identity-KPUVTRLS.js} +5 -6
  95. package/dist/{runner-key-6BIULOR4.js → runner-key-FUJD66R6.js} +22 -25
  96. package/dist/{session-sender-MSHKJSBG.js → session-sender-7B3ZDWMC.js} +11 -10
  97. package/dist/{spec-cmd-AWIMO32E.js → spec-cmd-Q26NE22H.js} +9 -8
  98. package/dist/{status-BILERIXB.js → status-2KNTILGQ.js} +29 -28
  99. package/dist/{sync-cmd-BSUZ65CU.js → sync-cmd-SSUYTMLJ.js} +10 -9
  100. package/dist/{watch-UF6XCGSI.js → watch-L5NCO46E.js} +10 -9
  101. package/dist/{work-claim-cmd-4FXVAZWF.js → work-claim-cmd-NJNOQFQE.js} +16 -13
  102. package/dist/{work-cmd-NCP4637R.js → work-cmd-W7WEHMQJ.js} +8 -7
  103. package/dist/{work-comment-cmd-YNQYVHYS.js → work-comment-cmd-SSUOGVDD.js} +8 -7
  104. package/dist/{work-logs-cmd-HHWVYQBG.js → work-logs-cmd-WPMWMDX6.js} +8 -7
  105. package/dist/{work-open-pr-cmd-ALVD7KLY.js → work-open-pr-cmd-NO5YLOXD.js} +9 -8
  106. package/dist/{work-pr-cmd-KBNFVRB4.js → work-pr-cmd-37B5KECR.js} +8 -7
  107. package/dist/{work-stop-cmd-DBWNHZJO.js → work-stop-cmd-3BJLXUJ3.js} +8 -7
  108. package/package.json +1 -1
  109. package/skill-pack/maintained/outerlayer-build/SKILL.md +4 -2
  110. package/dist/build-disk-6QAXMA2J.js +0 -18
  111. package/dist/chunk-DNKUSXQU.js +0 -241
  112. package/dist/chunk-I5LGKZ4M.js +0 -107
  113. package/dist/chunk-P5FC7VUO.js +0 -111
  114. package/dist/chunk-UXYLWVTQ.js +0 -43
  115. package/dist/chunk-WBZJWVT2.js +0 -146
  116. package/dist/chunk-YJLHUKYS.js +0 -38
  117. package/dist/chunk-YYYRBYWG.js +0 -32
  118. package/dist/install-NLVYISAV.js +0 -14
  119. package/dist/runner-env-26NLQI35.js +0 -15
@@ -350,8 +350,10 @@ A session that names a work item holds a lease on it, and review stays closed
350
350
  until the lease is released. In a session this command releases the session's
351
351
  own lease and no one else's. A later tool call takes the lease again, so write
352
352
  the final report as plain text once this has run. Skip this step in a runner
353
- build, whose host releases its own lease. Then end the run with the final
354
- report. The report lists:
353
+ build, whose host releases its own lease. A runner build is one whose
354
+ command environment sets `OUTERLAYER_JOB_DIR`. When that variable is set, skip
355
+ the command above: the gateway refuses it from a runner build. Then end the run
356
+ with the final report. The report lists:
355
357
 
356
358
  - every candidate issue and every assumption;
357
359
  - the team's changes applied, by phase, and each overlap between a change and
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- export { DEFAULT_BUILD_DISK, DOCKER_CACHE_MS, checkDiskFit, realBuildDiskProbe, runDocker, volumeBytes } from './chunk-P5FC7VUO.js';
4
- import './chunk-YYYRBYWG.js';
5
- import './chunk-43PV5KDB.js';
6
- import './chunk-3Z3MPR55.js';
7
- import './chunk-TGHBOXKJ.js';
8
- import './chunk-YJLHUKYS.js';
9
- import './chunk-5DNCFOXA.js';
10
- import './chunk-AA6LYZC4.js';
11
- import './chunk-AGZNCIIJ.js';
12
- import './chunk-BCCI32ME.js';
13
- import './chunk-E6CO3MJE.js';
14
- import './chunk-HACGUL52.js';
15
- import './chunk-MESOOLF4.js';
16
- import './chunk-Z5GEFMRW.js';
17
-
18
- createRequire(import.meta.url);
@@ -1,241 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { isPlaceholderCommand } from './chunk-WBZJWVT2.js';
4
- import { describeCallFailure } from './chunk-RBJG5MM4.js';
5
- import { checkFit } from './chunk-ZRRUWNJS.js';
6
- import { realBuildDiskProbe, checkDiskFit, DEFAULT_BUILD_DISK } from './chunk-P5FC7VUO.js';
7
- import { builderDiskPinned } from './chunk-TGHBOXKJ.js';
8
- import { builtinKind, imageBuildOf } from './chunk-5BNWAIHN.js';
9
- import { WorkCommandError, getJson } from './chunk-CMKY36NV.js';
10
- import { sanitizeTerminal } from './chunk-EWVYQLD3.js';
11
- import { signerFor } from './chunk-AA6LYZC4.js';
12
- import { CLAUDE_CREDENTIAL_VARIABLES, claudeCredential, claudeCredentialVariablesSet } from './chunk-BCCI32ME.js';
13
- import { closeSync, openSync, constants } from 'fs';
14
- import { totalmem } from 'os';
15
-
16
- createRequire(import.meta.url);
17
-
18
- // src/runner/host-setup.ts
19
- function placeholderQueues(config) {
20
- return config.queues.filter((queue) => {
21
- const command = config.commands[queue];
22
- return command !== void 0 && isPlaceholderCommand(command);
23
- });
24
- }
25
- function placeholderProblem(queues) {
26
- const keys = queues.map((queue) => `runner.commands.${queue}`).join(", ");
27
- return `${keys} ${queues.length === 1 ? "is" : "are"} still the placeholder \`runner init\` wrote, which fails every item. Edit ${queues.length === 1 ? "it" : "them"} to start your agent on item $OUTERLAYER_WORK`;
28
- }
29
- var CLAUDE_PERMISSION_MODES = ["acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "manual", "plan"];
30
- var CLAUDE_COMMAND = /(?:^|[;&|(])\s*(?:(?:exec|env|nohup|time)\s+)*(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:\S*\/)?claude\s/;
31
- var PERMISSION_MODE_FLAG = /--permission-mode(?:=|\s+)(?:"([^"]*)"|'([^']*)'|([^\s;&|()]+))/g;
32
- function permissionModeProblems(config) {
33
- const problems = [];
34
- for (const queue of config.queues) {
35
- const command = config.commands[queue];
36
- if (command === void 0 || !CLAUDE_COMMAND.test(command)) continue;
37
- for (const match of command.matchAll(PERMISSION_MODE_FLAG)) {
38
- const value = match[1] ?? match[2] ?? match[3] ?? "";
39
- if (value.includes("$") || value.includes("`") || CLAUDE_PERMISSION_MODES.includes(value)) continue;
40
- problems.push({ queue, command, value });
41
- }
42
- }
43
- return problems;
44
- }
45
- function permissionModeProblem(problems) {
46
- return problems.map(({ queue, command, value }) => `runner.commands.${queue} is \`${command}\`, and \`${value}\` is not a permission mode Claude Code accepts (${CLAUDE_PERMISSION_MODES.join(", ")}). The command would fail only when a build ran it`).join(". ");
47
- }
48
- var FORMER_AMEND_COMMAND = /(^|["'\s])\/amend(?=["'\s]|$)/g;
49
- function currentSkillCommand(command) {
50
- return command.replace(FORMER_AMEND_COMMAND, "$1/outerlayer-amend");
51
- }
52
- function formerSkillQueues(config) {
53
- return config.queues.filter((queue) => {
54
- const command = config.commands[queue];
55
- return command !== void 0 && currentSkillCommand(command) !== command;
56
- });
57
- }
58
- function formerSkillProblem(queues) {
59
- const keys = queues.map((queue) => `runner.commands.${queue}`).join(", ");
60
- return `${keys} ${queues.length === 1 ? "starts" : "start"} /amend, which is now /outerlayer-amend. The runner runs /outerlayer-amend in its place; edit the config to say so`;
61
- }
62
- function needsClaudeCredential(hooks) {
63
- return builtinKind(hooks.provision) !== "own";
64
- }
65
- var CREDENTIAL_FIX = "Run `claude setup-token`, then pipe the token it prints (or an Anthropic API key) to `outerlayer runner init --agent claude`, which stores it in the claude.env beside the config. Or start the runner with CLAUDE_CODE_OAUTH_TOKEN (or ANTHROPIC_API_KEY) set";
66
- function claudeCredentialCheck(env, options = {}) {
67
- const name = "Claude credential";
68
- if (options.service !== void 0) {
69
- const { unit, variables } = options.service;
70
- if (variables.length === 0) {
71
- return {
72
- name,
73
- status: "fail",
74
- detail: `the service ${unit} has no Claude credential: neither ${CLAUDE_CREDENTIAL_VARIABLES.slice(0, 2).join(" nor ")} is set in its claude.env or runner.env, so every build fails at provision as agent_credential_missing`,
75
- fix: `${CREDENTIAL_FIX}, then restart the service: sudo systemctl restart ${unit}.`
76
- };
77
- }
78
- return { name, status: "pass", detail: `${variables[0]} is set in the claude.env or runner.env of the service ${unit}` };
79
- }
80
- const held = claudeCredential(env, { ignoreHeld: options.ignoreHeld === true });
81
- if (held === void 0) {
82
- return {
83
- name,
84
- status: "fail",
85
- detail: `neither ${CLAUDE_CREDENTIAL_VARIABLES.slice(0, 2).join(" nor ")} is set, so every build fails at provision as agent_credential_missing`,
86
- fix: `${CREDENTIAL_FIX}.`
87
- };
88
- }
89
- const sameVariables = options.shell === true ? "; the runner must be started with the same variable" : "";
90
- return { name, status: "pass", detail: `${held.variable} is set${sameVariables}` };
91
- }
92
- function missingPermissionOf(err) {
93
- if (!(err instanceof WorkCommandError) || err.status !== 403) return void 0;
94
- const permission = /missing required permission '([^']+)'/i.exec(err.message)?.[1];
95
- return permission === void 0 ? void 0 : sanitizeTerminal(permission);
96
- }
97
- function missingPermissionFix(permission) {
98
- return `use a key that holds ${permission}: create one with the Runner preset on the factory's API keys page, then run \`outerlayer login\` with it`;
99
- }
100
- async function claimPermissionProblem(config, fetchImpl = fetch) {
101
- const unverified = (what, err) => ({
102
- status: "unverified",
103
- reason: sanitizeTerminal(`${what}: ${err instanceof Error ? describeCallFailure(err) : String(err)}`)
104
- });
105
- let signer;
106
- try {
107
- signer = await signerFor(config.configPath);
108
- } catch (err) {
109
- return unverified("this host's key could not be read, so whether the runner key can claim work was not checked", err);
110
- }
111
- try {
112
- await getJson(config.url, "/v1/runner/host-key", config.apiKey, config.appId, fetchImpl, signer);
113
- return { status: "ok" };
114
- } catch (err) {
115
- const permission = missingPermissionOf(err);
116
- if (permission === void 0) return unverified("the host-key call did not say whether the runner key can claim work", err);
117
- return { status: "lacks", problem: `the runner key lacks ${permission}, which a runner needs to claim work: ${missingPermissionFix(permission)}` };
118
- }
119
- }
120
- function openKvm() {
121
- try {
122
- closeSync(openSync("/dev/kvm", constants.O_RDWR));
123
- return "usable";
124
- } catch (err) {
125
- return err.code === "ENOENT" ? "absent" : "no-permission";
126
- }
127
- }
128
- var sharedBuildDisk;
129
- function realBlockedProbes() {
130
- sharedBuildDisk ??= realBuildDiskProbe();
131
- return { env: process.env, kvm: openKvm, totalMemoryBytes: totalmem, imageBuilder: "unknown", buildDisk: sharedBuildDisk };
132
- }
133
- var DEFAULT_BUILD_MEMORY = "8g";
134
- function managedProblems(facts) {
135
- const problems = [];
136
- if (builtinKind(facts.provision) !== "vm") {
137
- problems.push({
138
- condition: "jailer",
139
- reason: `a managed runner needs builtin:vm hooks, and runner.hooks.provision is ${facts.provision}. Without them builds would run without the jailer. Set runner.hooks.provision and runner.hooks.cleanup to builtin:vm`
140
- });
141
- } else if (facts.jailer === "usable") ; else if (facts.jailer === "unknown") {
142
- problems.push({ condition: "jailer", reason: "the runner has not yet asked the root helper whether builds run under the jailer, so builds would run without the jailer until it answers" });
143
- } else {
144
- const { problem } = facts.jailer;
145
- const advice = problem.includes("pins no helper") || problem.includes("runner install") ? "" : ". Run `outerlayer runner install --service --replace` to install the root helper, then restart the service";
146
- problems.push({ condition: "jailer", reason: `builds would run without the jailer, which a managed runner does not allow: ${problem}${advice}` });
147
- }
148
- if (facts.credentials.has("CLAUDE_CODE_OAUTH_TOKEN")) {
149
- problems.push({
150
- condition: "credential",
151
- reason: "CLAUDE_CODE_OAUTH_TOKEN is set in the runner's environment or credentials directory, and a managed runner accepts only ANTHROPIC_API_KEY. Remove CLAUDE_CODE_OAUTH_TOKEN from the claude.env and runner.env beside the config, store ANTHROPIC_API_KEY, then restart the service"
152
- });
153
- } else if (!facts.credentials.has("ANTHROPIC_API_KEY")) {
154
- problems.push({
155
- condition: "credential",
156
- reason: "there is no Claude credential in the runner's environment, and a managed runner needs ANTHROPIC_API_KEY. Store ANTHROPIC_API_KEY with `outerlayer runner init --agent claude`, which writes the claude.env beside the config, then restart the service"
157
- });
158
- }
159
- if (facts.allowHosts === void 0) {
160
- problems.push({
161
- condition: "allowHosts",
162
- reason: "runner.build.allowHosts is not set, and a managed runner needs it so that a build reaches only the public hosts it lists. List the hosts your builds need; an empty list allows none"
163
- });
164
- }
165
- if (builtinKind(facts.provision) === "vm") {
166
- if (facts.imageBuild === "host") {
167
- problems.push({
168
- condition: "imageBuild",
169
- reason: "runner.build.imageBuild is host, and a managed runner builds its images in a builder microVM, because a recipe step on the host could reach the host's own services and network. Remove runner.build.imageBuild or set it to vm"
170
- });
171
- } else if (!facts.builderDiskPinned) {
172
- problems.push({
173
- condition: "imageBuild",
174
- reason: "this release of the CLI pins no builder root disk, so it cannot build images in a builder microVM, which a managed runner needs for runner.build.imageBuild. Update the CLI to a release that pins one"
175
- });
176
- }
177
- }
178
- return problems;
179
- }
180
- function managedFactsOf(config, probes) {
181
- return {
182
- provision: config.hooks.provision,
183
- jailer: probes.jailer ?? "unknown",
184
- credentials: claudeCredentialVariablesSet(probes.env),
185
- allowHosts: config.build?.allowHosts,
186
- imageBuild: imageBuildOf(config),
187
- builderDiskPinned: probes.builderDiskPinned ?? builderDiskPinned()
188
- };
189
- }
190
- function checkBlocked(config, probes) {
191
- const placeholders = placeholderQueues(config);
192
- if (placeholders.length > 0) return { reason: `${placeholderProblem(placeholders)}. The runner takes work again once the config is edited` };
193
- if (config.managed === true) {
194
- const unmet = managedProblems(managedFactsOf(config, probes))[0];
195
- if (unmet !== void 0) return { reason: unmet.reason };
196
- }
197
- const kind = builtinKind(config.hooks.provision);
198
- if (kind === "container" || kind === "vm") {
199
- const fit = checkFit({
200
- concurrency: config.concurrency,
201
- buildMemory: config.build?.memory ?? DEFAULT_BUILD_MEMORY,
202
- usableBytes: probes.totalMemoryBytes()
203
- });
204
- if (!fit.fits) {
205
- const advice = probes.inImage === true ? "Set OUTERLAYER_BUILD_MEMORY or OUTERLAYER_CONCURRENCY in the env file and recreate the container, or give the machine more memory" : `Lower runner.concurrency or runner.build.memory in ${config.configPath}`;
206
- return { reason: `${fit.message}. ${advice}` };
207
- }
208
- const facts = probes.buildDisk?.(kind, config.configPath);
209
- if (facts !== void 0) {
210
- const diskFit = checkDiskFit({ concurrency: config.concurrency, buildDisk: config.build?.disk ?? DEFAULT_BUILD_DISK, facts });
211
- if (!diskFit.fits) {
212
- const advice = probes.inImage === true ? "Set OUTERLAYER_CONCURRENCY in the env file and recreate the container, or give the machine more disk" : `Lower runner.concurrency or runner.build.disk in ${config.configPath}`;
213
- return { reason: `${diskFit.message}. ${advice}` };
214
- }
215
- }
216
- }
217
- const kvm = kind === "vm" ? probes.kvm() : "usable";
218
- if (kvm === "absent") {
219
- return { reason: "/dev/kvm does not exist on this machine, so builtin:vm cannot start a microVM. Use a host with KVM enabled, or builtin:container hooks" };
220
- }
221
- if (kvm !== "usable") {
222
- return {
223
- reason: "the runner cannot open /dev/kvm, so builtin:vm cannot start a microVM. Add the runner's account to the kvm group, then restart the service, because a service reads its groups only when it starts"
224
- };
225
- }
226
- if (kind === "container" || kind === "vm") {
227
- const builder = probes.imageBuilder;
228
- if (builder === "unknown") {
229
- return { reason: "the runner is still preparing its image builder, the container that limits image builds to runner.build.memory, so it claims nothing yet" };
230
- }
231
- if (builder !== "usable") return { reason: `${builder.problem}. The runner takes work again once its image builder works` };
232
- }
233
- if (kind !== "own" && claudeCredential(probes.env) === void 0) {
234
- return {
235
- reason: "there is no Claude credential in the runner's environment. Store CLAUDE_CODE_OAUTH_TOKEN (from `claude setup-token`) or ANTHROPIC_API_KEY with `outerlayer runner init --agent claude`, which writes the claude.env beside the config, then restart the service"
236
- };
237
- }
238
- return void 0;
239
- }
240
-
241
- export { checkBlocked, claimPermissionProblem, claudeCredentialCheck, currentSkillCommand, formerSkillProblem, formerSkillQueues, managedFactsOf, managedProblems, missingPermissionFix, missingPermissionOf, needsClaudeCredential, permissionModeProblem, permissionModeProblems, placeholderProblem, placeholderQueues, realBlockedProbes };
@@ -1,107 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { MIN_ENGINE_MAJOR } from './chunk-D3HRAPNF.js';
4
- import { runnerImageVersion } from './chunk-SK4TWCN3.js';
5
- import { firecrackerArch, MICROVM_ARCHES, guestAssetsPinned } from './chunk-TGHBOXKJ.js';
6
- import { spawnSync } from 'child_process';
7
- import { existsSync, accessSync, constants, statSync, readFileSync } from 'fs';
8
-
9
- createRequire(import.meta.url);
10
- function groupName(gid) {
11
- try {
12
- for (const line of readFileSync("/etc/group", "utf8").split("\n")) {
13
- const [name, , id] = line.split(":");
14
- if (name !== void 0 && Number(id) === gid) return name;
15
- }
16
- } catch {
17
- }
18
- return String(gid);
19
- }
20
- function detectKvm(device) {
21
- if (!existsSync(device)) return { state: "absent" };
22
- try {
23
- accessSync(device, constants.R_OK | constants.W_OK);
24
- return { state: "usable" };
25
- } catch {
26
- return { state: "no-permission", group: groupName(statSync(device).gid) };
27
- }
28
- }
29
- function readProcVersion() {
30
- try {
31
- return readFileSync("/proc/version", "utf8");
32
- } catch {
33
- return void 0;
34
- }
35
- }
36
- function docker(args) {
37
- const result = spawnSync("docker", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 15e3 });
38
- const out = result.status === 0 ? result.stdout.trim() : "";
39
- return out === "" ? void 0 : out;
40
- }
41
- function dockerFailure() {
42
- const result = spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 });
43
- if (result.error?.code === "ENOENT") return void 0;
44
- return /permission denied/i.test(result.stderr ?? "") ? "permission" : "daemon";
45
- }
46
- function platformOf(probes) {
47
- const platform = probes.platform ?? process.platform;
48
- if (platform === "win32") return "windows";
49
- if (platform === "darwin") return "darwin";
50
- if (platform !== "linux") return "other";
51
- return /microsoft/i.test((probes.procVersion ?? readProcVersion)() ?? "") ? "wsl2" : "linux";
52
- }
53
- function detectMachine(probes = {}) {
54
- const platform = platformOf(probes);
55
- const kvm = (probes.kvm ?? (() => detectKvm(probes.kvmDevice ?? "/dev/kvm")))();
56
- const arch = firecrackerArch(probes.nodeArch ?? process.arch);
57
- const inImage = runnerImageVersion(probes.env ?? process.env) !== void 0 ? { inImage: true } : {};
58
- const version = (probes.dockerVersion ?? (() => docker(["version", "--format", "{{.Server.Version}}"])))();
59
- if (version === void 0) {
60
- const failure = (probes.dockerFailure ?? (probes.dockerVersion === void 0 ? dockerFailure : () => void 0))();
61
- return { platform, ...inImage, docker: failure === void 0 ? { kind: "none" } : { kind: "unreachable", reason: failure }, kvm, arch };
62
- }
63
- const system = (probes.dockerOperatingSystem ?? (() => docker(["info", "--format", "{{.OperatingSystem}}"])))() ?? "";
64
- return { platform, ...inImage, docker: { kind: /docker desktop/i.test(system) ? "desktop" : "engine", version }, kvm, arch };
65
- }
66
- function supportsContainerBuilds(machine) {
67
- if (machine.platform !== "linux" && machine.platform !== "wsl2") return false;
68
- const { kind, version } = machine.docker;
69
- if (kind !== "engine" && !(kind === "desktop" && machine.inImage === true)) return false;
70
- return Number.parseInt(version ?? "", 10) >= MIN_ENGINE_MAJOR;
71
- }
72
- function supportsMicroVmBuilds(machine) {
73
- return machine.platform === "linux" && machine.kvm?.state === "usable" && supportsContainerBuilds(machine) && microVmAssetsPinned(machine);
74
- }
75
- function microVmArchSupported(machine) {
76
- return MICROVM_ARCHES.includes(machine.arch ?? "");
77
- }
78
- function microVmAssetsPinned(machine) {
79
- return microVmArchSupported(machine) && guestAssetsPinned(machine.arch);
80
- }
81
- function reachDockerStep(machine) {
82
- if (machine.docker.kind !== "unreachable") return void 0;
83
- return machine.docker.reason === "permission" ? "give this user access to Docker Engine's socket (add it to the docker group, then log in again)" : "start Docker Engine's daemon (for example, sudo systemctl start docker)";
84
- }
85
- function describeMachineDocker(machine) {
86
- const { kind, version, reason } = machine.docker;
87
- const where = machine.platform === "windows" ? "Windows" : machine.platform === "darwin" ? "macOS" : machine.platform === "wsl2" ? "WSL2" : "Linux";
88
- if (kind === "desktop") {
89
- const engine = version === void 0 ? "" : ` with engine ${version}`;
90
- if (machine.inImage === true && (machine.platform === "linux" || machine.platform === "wsl2")) {
91
- const major = Number.parseInt(version ?? "", 10);
92
- if (Number.isNaN(major)) return `Docker Desktop${engine}, whose engine version is not readable`;
93
- if (major < MIN_ENGINE_MAJOR) return `Docker Desktop${engine}, older than the ${MIN_ENGINE_MAJOR} that container builds need`;
94
- return `Docker Desktop${engine}`;
95
- }
96
- return `Docker Desktop${engine} on ${where}, which a runner accepts only in the runner image`;
97
- }
98
- if (kind === "none") return `no Docker on ${where}`;
99
- if (kind === "unreachable") {
100
- const problem = reason === "permission" ? "this user has no permission on its socket" : "its daemon is not running";
101
- return `a docker command on ${where} that cannot reach Docker Engine (${problem})`;
102
- }
103
- if (machine.platform !== "linux" && machine.platform !== "wsl2") return `Docker Engine ${version ?? ""} on ${where}, which cannot isolate a build`.replace(" ", " ");
104
- return `Docker Engine ${version ?? "of no known version"}, older than the ${MIN_ENGINE_MAJOR} that container builds need`;
105
- }
106
-
107
- export { describeMachineDocker, detectMachine, microVmArchSupported, microVmAssetsPinned, reachDockerStep, supportsContainerBuilds, supportsMicroVmBuilds };
@@ -1,111 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { formatBytes, freeBytes } from './chunk-YYYRBYWG.js';
4
- import { BUILD_LABEL, RUNNER_LABEL, runnerLabelValue } from './chunk-43PV5KDB.js';
5
- import { parseSize } from './chunk-YJLHUKYS.js';
6
- import { buildsDir, rootfsDir, runnerDir } from './chunk-AGZNCIIJ.js';
7
- import { spawnSync } from 'child_process';
8
- import { existsSync, statSync, readdirSync } from 'fs';
9
- import { join } from 'path';
10
-
11
- createRequire(import.meta.url);
12
- function checkDiskFit(input) {
13
- const limit = parseSize(input.buildDisk);
14
- if (limit === void 0) return { fits: true };
15
- const { freeBytes: free, heldBytes: held, rootDiskBytes: root } = input.facts;
16
- const neededBytes = input.concurrency * (limit + root);
17
- const availableBytes = free + held;
18
- if (neededBytes <= availableBytes) return { fits: true };
19
- const oneBuild = root > 0 ? `runner.build.disk ${input.buildDisk} plus a root disk of ${formatBytes(root)}` : `runner.build.disk ${input.buildDisk}`;
20
- return {
21
- fits: false,
22
- neededBytes,
23
- availableBytes,
24
- message: `the builds' disks do not fit: runner.concurrency ${input.concurrency} times the space one build can hold (${oneBuild}) needs ${formatBytes(neededBytes)}, and ${formatBytes(availableBytes)} is available (${formatBytes(free)} free plus ${formatBytes(held)} held by running builds)`
25
- };
26
- }
27
- function allocatedBytes(path) {
28
- try {
29
- return statSync(path).blocks * 512;
30
- } catch {
31
- return 0;
32
- }
33
- }
34
- function listDir(path) {
35
- try {
36
- return readdirSync(path);
37
- } catch {
38
- return void 0;
39
- }
40
- }
41
- function microVmFacts(configPath) {
42
- const builds = buildsDir(configPath);
43
- const free = freeBytes(builds);
44
- if (free === void 0) return void 0;
45
- let held = 0;
46
- if (existsSync(builds)) {
47
- const entries = listDir(builds);
48
- if (entries === void 0) return void 0;
49
- for (const entry of entries) held += allocatedBytes(join(builds, entry, "build.ext4"));
50
- }
51
- let root = 0;
52
- const roots = rootfsDir(runnerDir(configPath));
53
- if (existsSync(roots)) {
54
- const entries = listDir(roots);
55
- if (entries === void 0) return void 0;
56
- for (const entry of entries) {
57
- if (!entry.endsWith(".ext4")) continue;
58
- try {
59
- root = Math.max(root, statSync(join(roots, entry)).size);
60
- } catch {
61
- }
62
- }
63
- }
64
- return { freeBytes: free, heldBytes: held, rootDiskBytes: root };
65
- }
66
- var DOCKER_TIMEOUT_MS = 1e4;
67
- var DEFAULT_BUILD_DISK = "40g";
68
- var DOCKER_CACHE_MS = 6e4;
69
- var DEFAULT_VOLUMES_DIR = "/var/lib/docker/volumes";
70
- function runDocker(args, spawn = spawnSync) {
71
- const result = spawn("docker", args, { encoding: "utf8", timeout: DOCKER_TIMEOUT_MS });
72
- return result.status === 0 ? result.stdout : void 0;
73
- }
74
- var SIZE_UNITS = { b: 1, kb: 1e3, mb: 1e6, gb: 1e9, tb: 1e12 };
75
- function volumeBytes(dfOutput, names) {
76
- let total = 0;
77
- for (const line of dfOutput.split("\n")) {
78
- const [name, , size] = line.trim().split(/\s+/);
79
- if (name === void 0 || size === void 0 || !names.has(name)) continue;
80
- const match = /^([\d.]+)([A-Za-z]+)$/.exec(size);
81
- const unit = match === null ? void 0 : SIZE_UNITS[match[2].toLowerCase()];
82
- if (match !== null && unit !== void 0) total += Number(match[1]) * unit;
83
- }
84
- return total;
85
- }
86
- function containerFacts(cache, configPath, docker, now) {
87
- if (cache.reading === void 0 || cache.reading.configPath !== configPath || now - cache.reading.at > DOCKER_CACHE_MS) {
88
- const root = docker(["info", "--format", "{{.DockerRootDir}}"])?.trim();
89
- const listed = docker(["volume", "ls", "--quiet", "--filter", `label=${BUILD_LABEL}`, "--filter", `label=${RUNNER_LABEL}=${runnerLabelValue(configPath)}`]);
90
- const names = new Set((listed ?? "").split("\n").map((n) => n.trim()).filter((n) => n !== ""));
91
- const df = listed === void 0 || names.size === 0 ? void 0 : docker(["system", "df", "-v"]);
92
- const held = listed === void 0 ? void 0 : names.size === 0 ? 0 : df === void 0 ? void 0 : volumeBytes(df, names);
93
- cache.reading = {
94
- at: now,
95
- configPath,
96
- held,
97
- volumes: root === void 0 || root === "" ? DEFAULT_VOLUMES_DIR : join(root, "volumes")
98
- };
99
- }
100
- if (cache.reading.held === void 0) return void 0;
101
- const free = freeBytes(cache.reading.volumes);
102
- return free === void 0 ? void 0 : { freeBytes: free, heldBytes: cache.reading.held, rootDiskBytes: 0 };
103
- }
104
- function realBuildDiskProbe(deps = {}) {
105
- const cache = {};
106
- const docker = deps.docker ?? ((args) => runDocker(args));
107
- const now = deps.now ?? Date.now;
108
- return (kind, configPath) => kind === "vm" ? microVmFacts(configPath) : containerFacts(cache, configPath, docker, now());
109
- }
110
-
111
- export { DEFAULT_BUILD_DISK, DOCKER_CACHE_MS, checkDiskFit, realBuildDiskProbe, runDocker, volumeBytes };
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
-
4
- createRequire(import.meta.url);
5
-
6
- // src/runner/allow-hosts.ts
7
- var MAX_ALLOW_HOSTS = 500;
8
- var LABEL = /^(?!-)[a-z0-9-]{1,63}(?<!-)$/;
9
- var IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/;
10
- function isAddress(text) {
11
- if (IPV4.test(text)) return true;
12
- try {
13
- new URL(`http://[${text}]/`);
14
- return true;
15
- } catch {
16
- return false;
17
- }
18
- }
19
- function isHostName(text) {
20
- const labels = text.split(".");
21
- return text.length <= 253 && labels.every((label) => LABEL.test(label)) && !/^\d+$/.test(labels.at(-1));
22
- }
23
- function allowHostProblem(entry) {
24
- if (typeof entry !== "string") return "is not a string";
25
- const text = entry.toLowerCase();
26
- if (isAddress(text)) return void 0;
27
- if (text.startsWith("*.")) {
28
- const domain = text.slice(2);
29
- if (!isHostName(domain)) return "is not a host name after *.";
30
- if (!domain.includes(".")) return "is too broad: a pattern needs a domain with at least two labels after *.";
31
- return void 0;
32
- }
33
- return isHostName(text) ? void 0 : "is not a host name, a *. pattern or an IP address";
34
- }
35
- function hostAllowed(host, allowHosts) {
36
- const name = host.toLowerCase().replace(/\.$/, "");
37
- return allowHosts.some((entry) => {
38
- const pattern = entry.toLowerCase();
39
- return pattern.startsWith("*.") ? name.endsWith(pattern.slice(1)) : name === pattern;
40
- });
41
- }
42
-
43
- export { MAX_ALLOW_HOSTS, allowHostProblem, hostAllowed };