@outerlayer/cli 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +15 -5
  3. package/dist/{agent-setup-USZ2SAXC.js → agent-setup-C7PLRXZO.js} +7 -6
  4. package/dist/{build-PAEKVYVK.js → build-MS34XEGN.js} +3 -1
  5. package/dist/build-info.json +1 -1
  6. package/dist/builder-G52A6GW2.js +13 -0
  7. package/dist/{check-CCVPBN7A.js → check-FOF3PUKI.js} +35 -26
  8. package/dist/{chunk-ZILGTTY6.js → chunk-3S4P55NE.js} +3 -3
  9. package/dist/{chunk-MIGEDH5P.js → chunk-4A5E2G4E.js} +9 -9
  10. package/dist/chunk-4ACZCY4I.js +39 -0
  11. package/dist/{chunk-OIRNH6UO.js → chunk-5FWNEQNZ.js} +3 -3
  12. package/dist/{chunk-BNMCXPG7.js → chunk-5QLNZGAQ.js} +12 -3
  13. package/dist/chunk-5TNS3PL7.js +263 -0
  14. package/dist/chunk-7RQ73DLO.js +23 -0
  15. package/dist/{chunk-VMJ3MMBX.js → chunk-7VNURP6M.js} +538 -46
  16. package/dist/{chunk-EMY4I27X.js → chunk-7ZR5UPMB.js} +555 -5
  17. package/dist/{chunk-UMFWVGJO.js → chunk-AIL2R4SI.js} +4 -3
  18. package/dist/{chunk-NQXFAGHU.js → chunk-AX23QKHS.js} +7 -3
  19. package/dist/{chunk-RZSF5B46.js → chunk-CM5QTKM4.js} +152 -158
  20. package/dist/chunk-CX22S5BA.js +45 -0
  21. package/dist/{chunk-H5NCNVDA.js → chunk-EV3M3EH7.js} +2 -2
  22. package/dist/{chunk-ANK2B36Y.js → chunk-GAYWY4GI.js} +6190 -28615
  23. package/dist/chunk-HKMPVPO7.js +55 -0
  24. package/dist/{chunk-43J3M6KB.js → chunk-IJBVPLZZ.js} +91 -39
  25. package/dist/{chunk-PMAMOSTP.js → chunk-ILEA3YHM.js} +85 -25
  26. package/dist/{chunk-MXB5VB4Y.js → chunk-IRCBTGWF.js} +6 -6
  27. package/dist/{chunk-OUUINEYB.js → chunk-JKIWMRFH.js} +1 -1
  28. package/dist/{chunk-FA2BOX4O.js → chunk-JPR2WHHF.js} +1 -1
  29. package/dist/{chunk-IASWYRVG.js → chunk-K35RW5HP.js} +4 -1
  30. package/dist/{chunk-ZMYPLFG3.js → chunk-M3SQ4YGD.js} +1 -1
  31. package/dist/{chunk-4NLKY4WR.js → chunk-NALVDFIS.js} +2 -2
  32. package/dist/{chunk-AUFG23AA.js → chunk-OD2VTIHN.js} +19 -47
  33. package/dist/{chunk-JWOQNNN2.js → chunk-OEK4JEB3.js} +33 -4
  34. package/dist/chunk-PTW6W5NR.js +127 -0
  35. package/dist/{chunk-3DD6AOWC.js → chunk-PWBILI5P.js} +28 -3
  36. package/dist/{chunk-B2G7JHHB.js → chunk-R7STSBLC.js} +1 -1
  37. package/dist/{chunk-YYYXRJUW.js → chunk-TI7B7UEO.js} +1 -1
  38. package/dist/{chunk-Z62HNKEJ.js → chunk-TTNFGMHO.js} +72 -54
  39. package/dist/{chunk-RBOMWNOG.js → chunk-TUUMW4TC.js} +2 -2
  40. package/dist/{chunk-774HEQL6.js → chunk-U3GOI2B4.js} +91 -8
  41. package/dist/{chunk-F6GFZXZ3.js → chunk-UXYLWVTQ.js} +1 -18
  42. package/dist/{chunk-WO2BXCTQ.js → chunk-VXLJORHL.js} +1 -1
  43. package/dist/{chunk-CBPPJSAR.js → chunk-WVGSB3Z2.js} +2 -2
  44. package/dist/chunk-YNJEOGDL.js +22434 -0
  45. package/dist/{chunk-W4SQCOZU.js → chunk-ZOAEPWGL.js} +1 -1
  46. package/dist/{chunk-3DEVYTNQ.js → chunk-ZYHKJKSU.js} +1 -1
  47. package/dist/{chunk-WIOZAJ2W.js → chunk-ZZXLM64C.js} +1 -1
  48. package/dist/{cli-7WCNPBYC.js → cli-AOJPAVFX.js} +109 -81
  49. package/dist/{command-ARFK3OYF.js → command-SY3SVLAI.js} +67 -27
  50. package/dist/config-Z3USDBLU.js +11 -0
  51. package/dist/{connect-cmd-PCESZLTR.js → connect-cmd-PNZ6IJLJ.js} +4 -4
  52. package/dist/{context-adopt-G5JAELE7.js → context-adopt-CE4KDXS3.js} +5 -4
  53. package/dist/{context-materialize-3HLPZAF6.js → context-materialize-QL33HDJN.js} +5 -4
  54. package/dist/{dist-RDLP4GGJ.js → dist-3ZTZF2TP.js} +2 -1
  55. package/dist/docker-676FD3CQ.js +15 -0
  56. package/dist/{doctor-VOMYOHQU.js → doctor-WR6TRPSU.js} +49 -19
  57. package/dist/{emit-artifact-cmd-TBF46VXZ.js → emit-artifact-cmd-AVM4YXMQ.js} +11 -4
  58. package/dist/{emit-cmd-DCERAU27.js → emit-cmd-2QRMYPYO.js} +4 -3
  59. package/dist/{emit-criteria-cmd-3427XKFW.js → emit-criteria-cmd-LDBE4YDS.js} +10 -1
  60. package/dist/{emit-finding-cmd-GSI75K36.js → emit-finding-cmd-6R5WBPCH.js} +12 -1
  61. package/dist/{emit-result-cmd-3PRQKB55.js → emit-result-cmd-2DMN6O6U.js} +13 -6
  62. package/dist/{exec-client-4XGXV3XN.js → exec-client-NPYNUAF3.js} +4 -3
  63. package/dist/{guest-init-GENRHNP7.js → guest-init-JWNNAH2H.js} +4 -3
  64. package/dist/{hook-fast-NJBBZQ5Q.js → hook-fast-XBOZ3N6L.js} +1 -1
  65. package/dist/{import-capture-cmd-AVZ4VIVJ.js → import-capture-cmd-T4556ELW.js} +3 -2
  66. package/dist/{import-ruler-cmd-GUHL6IY5.js → import-ruler-cmd-SG3UVGI7.js} +2 -1
  67. package/dist/index.js +3 -3
  68. package/dist/init-KDK5QLQZ.js +46 -0
  69. package/dist/{init-OHYFIKZD.js → init-R2FJ5KNS.js} +35 -21
  70. package/dist/{init-cmd-HMFNIFPI.js → init-cmd-BYZYAJ5P.js} +10 -9
  71. package/dist/{install-DSUZE2TJ.js → install-FHTVJZS6.js} +7 -5
  72. package/dist/{install-cmd-453C7IZT.js → install-cmd-DCF7TVXD.js} +3 -2
  73. package/dist/{logs-7RYUH5A6.js → logs-H55NWW4H.js} +1 -0
  74. package/dist/{loop-UAJB34KA.js → loop-AG3PLXPO.js} +35 -26
  75. package/dist/machine-LV6WBRRK.js +45 -0
  76. package/dist/{session-sender-ED26V45B.js → session-sender-Q5HAMOL2.js} +6 -5
  77. package/dist/{starter-pack-LIZYMKYQ.js → starter-pack-MUXMAU4S.js} +4 -3
  78. package/dist/{status-6WNXX2O7.js → status-HH4OSOHR.js} +29 -20
  79. package/dist/{sync-cmd-YONVGUYS.js → sync-cmd-CAEPJR7B.js} +5 -4
  80. package/dist/{watch-HHKAF26L.js → watch-LAAZFBHH.js} +5 -4
  81. package/dist/{work-claim-cmd-LXBZTMJA.js → work-claim-cmd-ARIYZARE.js} +15 -7
  82. package/dist/{work-cmd-OVNF44FY.js → work-cmd-B3FOXZAL.js} +9 -3
  83. package/dist/{work-comment-cmd-6DGQNTAH.js → work-comment-cmd-O5WGRI6K.js} +9 -3
  84. package/dist/{work-open-pr-cmd-FCZHFHZS.js → work-open-pr-cmd-M6CQW7KW.js} +10 -4
  85. package/dist/{work-pr-cmd-QJJVHZDC.js → work-pr-cmd-C4YEGKD6.js} +9 -2
  86. package/package.json +1 -1
  87. package/skill-pack/template/build/scripts/record-criteria.mjs +2 -1
  88. package/dist/chunk-7DBI6SNT.js +0 -55
  89. package/dist/config-HL2AIR3K.js +0 -9
  90. package/dist/docker-NEGDLU6D.js +0 -7
  91. package/dist/init-WVR4BZQ4.js +0 -36
  92. package/dist/machine-2JOWGRSZ.js +0 -35
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { BUILDKIT_IMAGE } from './chunk-CX22S5BA.js';
4
+ import { compareVersions } from './chunk-GAYWY4GI.js';
5
+ import { parseSize } from './chunk-7RQ73DLO.js';
6
+ import { JOB_MOUNT, GATEWAY_PORT, GATEWAY_SOCKET, CLAUDE_PORT, CLAUDE_SOCKET, RELAY_PORT, DESTINATION_BASE_PORT } from './chunk-OD2VTIHN.js';
7
+ import { runnerDir } from './chunk-ZM2IMMYN.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
+ var BUILD_LABEL = "ai.outerlayer.build";
14
+ var RUNNER_LABEL = "ai.outerlayer.runner";
15
+ function resolvedRunnerDir(configPath) {
16
+ try {
17
+ return realpathSync(runnerDir(configPath));
18
+ } catch {
19
+ try {
20
+ return join(realpathSync(dirname(resolve(configPath))), "runner");
21
+ } catch {
22
+ return resolve(runnerDir(configPath));
23
+ }
24
+ }
25
+ }
26
+ function runnerLabelValue(configPath) {
27
+ return createHash("sha256").update(resolvedRunnerDir(configPath)).digest("hex").slice(0, 12);
28
+ }
29
+ function hardened(input) {
30
+ const { memory, cpus, pids } = input.limits;
31
+ return [
32
+ "--label",
33
+ `${BUILD_LABEL}=${input.buildId}`,
34
+ "--label",
35
+ `${RUNNER_LABEL}=${input.runnerId}`,
36
+ "--network",
37
+ "none",
38
+ "--cap-drop",
39
+ "ALL",
40
+ "--security-opt",
41
+ "no-new-privileges",
42
+ "--read-only",
43
+ "--user",
44
+ input.user,
45
+ // The same figure for swap as for memory leaves the container none.
46
+ "--memory",
47
+ memory,
48
+ "--memory-swap",
49
+ memory,
50
+ "--cpus",
51
+ String(cpus),
52
+ "--pids-limit",
53
+ String(pids)
54
+ ];
55
+ }
56
+ function mountPath(path) {
57
+ 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`);
58
+ return path;
59
+ }
60
+ function containerRunArgs(input) {
61
+ return [
62
+ "--detach",
63
+ "--name",
64
+ input.container,
65
+ ...hardened(input),
66
+ "--mount",
67
+ `type=volume,src=${input.volume},dst=/build`,
68
+ // `/tmp` is a directory of the same volume, so it is measured and limited with the rest of the build.
69
+ "--mount",
70
+ `type=volume,src=${input.volume},dst=/tmp,volume-subpath=tmp`,
71
+ "--mount",
72
+ `type=bind,src=${mountPath(input.buildDir)},dst=${JOB_MOUNT},readonly`,
73
+ "--entrypoint",
74
+ "/opt/outerlayer/bin/tini",
75
+ input.image,
76
+ "--",
77
+ "/opt/outerlayer/bin/node",
78
+ "/opt/outerlayer/cli/dist/index.js",
79
+ "broker-relay",
80
+ "--port",
81
+ String(RELAY_PORT),
82
+ "--socket",
83
+ `${JOB_MOUNT}/tunnel.sock`,
84
+ ...Array.from({ length: input.destinations ?? 0 }, (_unused, index) => [
85
+ "--forward",
86
+ `${DESTINATION_BASE_PORT + index}=${JOB_MOUNT}/dest-${index}.sock`
87
+ ]).flat(),
88
+ ...input.builtIns === true ? [
89
+ "--forward",
90
+ `${GATEWAY_PORT}=${JOB_MOUNT}/${GATEWAY_SOCKET}`,
91
+ "--forward",
92
+ `${CLAUDE_PORT}=${JOB_MOUNT}/${CLAUDE_SOCKET}`
93
+ ] : []
94
+ ];
95
+ }
96
+ function prepareRunArgs(input) {
97
+ return [
98
+ "--rm",
99
+ ...hardened(input),
100
+ "--mount",
101
+ `type=volume,src=${input.volume},dst=/build`,
102
+ "--entrypoint",
103
+ "mkdir",
104
+ input.image,
105
+ "-p",
106
+ "-m",
107
+ "1777",
108
+ "/build/tmp",
109
+ "/build/home",
110
+ "/build/work"
111
+ ];
112
+ }
113
+ function containerExecArgs(input) {
114
+ const literals = Object.keys(input.env.literals).sort().flatMap((name) => ["-e", `${name}=${input.env.literals[name]}`]);
115
+ const passed = Object.keys(input.env.passed).filter((name) => input.env.passed[name] !== void 0).sort().flatMap((name) => ["-e", name]);
116
+ return [
117
+ "-u",
118
+ input.user,
119
+ ...input.workdir === void 0 ? [] : ["-w", input.workdir],
120
+ ...literals,
121
+ ...passed,
122
+ input.container,
123
+ ...input.argv
124
+ ];
125
+ }
126
+
127
+ // src/runner/image/builder.ts
128
+ var MIN_BUILDX_VERSION = "0.18.0";
129
+ 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)";
130
+ function builderName(configPath) {
131
+ return `outerlayer-${runnerLabelValue(configPath)}`;
132
+ }
133
+ function proxyEnvironment(env) {
134
+ const found = {};
135
+ for (const name of ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy"]) {
136
+ const value = env[name];
137
+ if (value !== void 0 && value !== "") found[name] = value;
138
+ }
139
+ return found;
140
+ }
141
+ function builderSpec(configPath, memory, env) {
142
+ return { name: builderName(configPath), memory, env: proxyEnvironment(env) };
143
+ }
144
+ function driverOpt(pair) {
145
+ return /[",]/.test(pair) ? `"${pair.replace(/"/g, '""')}"` : pair;
146
+ }
147
+ async function buildxState(run) {
148
+ const result = await run("docker", ["buildx", "version"]);
149
+ if (result.status !== 0) {
150
+ const said = (result.stderr.trim() || result.stdout.trim()).split("\n")[0] ?? "";
151
+ return { problem: `docker buildx is not available${said === "" ? "" : ` (${said})`}, so image builds cannot be limited; ${INSTALL_HINT}` };
152
+ }
153
+ const version = /\bv?(\d+\.\d+\.\d+)/.exec(result.stdout)?.[1];
154
+ if (version !== void 0 && compareVersions(version, MIN_BUILDX_VERSION) < 0) {
155
+ return { problem: `docker buildx ${version} is too old: the runner's image builder needs Buildx ${MIN_BUILDX_VERSION} or later; update ${INSTALL_HINT}` };
156
+ }
157
+ return "usable";
158
+ }
159
+ function isOutOfMemory(output) {
160
+ if (/cannot allocate memory/i.test(output)) return true;
161
+ if (/did not complete successfully: (exit code: 137|signal: killed)/i.test(output)) return true;
162
+ return /ResourceExhausted/i.test(output) && !/larger than max|message size|too large/i.test(output);
163
+ }
164
+ var running = 0;
165
+ async function trackImageBuild(work) {
166
+ running++;
167
+ try {
168
+ return await work();
169
+ } finally {
170
+ running--;
171
+ }
172
+ }
173
+ var queue = Promise.resolve();
174
+ function serialized(work) {
175
+ const next = queue.then(work, work);
176
+ queue = next.catch(() => void 0);
177
+ return next;
178
+ }
179
+ function readExisting(inspectOutput) {
180
+ const options = /^Driver Options:\s*(.*)$/m.exec(inspectOutput)?.[1] ?? "";
181
+ const option = (key) => new RegExp(`(?:^|\\s)${key}="([^"]*)"`).exec(options)?.[1];
182
+ return { driver: /^Driver:\s*(\S+)/m.exec(inspectOutput)?.[1], memory: option("memory"), image: option("image") };
183
+ }
184
+ function sameMemory(found, wanted) {
185
+ return (parseSize(found) ?? found) === (parseSize(wanted) ?? wanted);
186
+ }
187
+ var IDLE_POLL_MS = 1e3;
188
+ var failures = 0;
189
+ function ensureFailureCount() {
190
+ return failures;
191
+ }
192
+ function ensureBuilder(rawRun, spec, options = {}) {
193
+ const run = (command, args, opts) => rawRun(command, args, { ...opts, timeoutMs: args.includes("--bootstrap") ? 15 * 6e4 : 2 * 6e4 });
194
+ const result = serialized(async () => {
195
+ const state = await buildxState(run);
196
+ if (state !== "usable") return { ok: false, problem: state.problem };
197
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
198
+ const inspected = await run("docker", ["buildx", "inspect", spec.name]);
199
+ let create = inspected.status !== 0;
200
+ if (!create) {
201
+ const found = readExisting(inspected.stdout);
202
+ const current = found.driver === "docker-container" && sameMemory(found.memory ?? "", spec.memory) && found.image === BUILDKIT_IMAGE;
203
+ if (!current && options.replaceStale === false) {
204
+ return {
205
+ ok: false,
206
+ 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}`
207
+ };
208
+ }
209
+ if (!current) {
210
+ if (options.waitForIdle === true) while (running > 0) await sleep(IDLE_POLL_MS);
211
+ if (running === 0) {
212
+ const removed = await run("docker", ["buildx", "rm", spec.name]);
213
+ if (removed.status !== 0) return { ok: false, problem: `could not replace the image builder ${spec.name}: ${removed.stderr.trim() || `docker exited ${removed.status}`}` };
214
+ create = true;
215
+ }
216
+ }
217
+ }
218
+ if (create) {
219
+ const opts = [
220
+ `memory=${spec.memory}`,
221
+ `memory-swap=${spec.memory}`,
222
+ `image=${BUILDKIT_IMAGE}`,
223
+ ...Object.entries(spec.env ?? {}).map(([name, value]) => `env.${name}=${value}`),
224
+ ...spec.driverOpts ?? []
225
+ ];
226
+ const created = await run("docker", [
227
+ "buildx",
228
+ "create",
229
+ "--name",
230
+ spec.name,
231
+ "--driver",
232
+ "docker-container",
233
+ ...opts.flatMap((opt) => ["--driver-opt", driverOpt(opt)])
234
+ ]);
235
+ if (created.status !== 0) {
236
+ const said = created.stderr.trim() || `docker exited ${created.status}`;
237
+ if (/failed to find driver/i.test(said)) {
238
+ return { ok: false, problem: `this Docker's Buildx has no docker-container driver, so image builds cannot be limited; ${INSTALL_HINT}` };
239
+ }
240
+ return { ok: false, problem: `could not create the image builder ${spec.name}: ${said}` };
241
+ }
242
+ }
243
+ if (options.bootstrap === true) {
244
+ const started = await run("docker", ["buildx", "inspect", "--bootstrap", spec.name]);
245
+ if (started.status !== 0) {
246
+ return { ok: false, problem: `the image builder ${spec.name} did not start: ${started.stderr.trim() || `docker exited ${started.status}`}` };
247
+ }
248
+ }
249
+ return { ok: true, changed: create };
250
+ });
251
+ return result.then(
252
+ (outcome) => {
253
+ if (!outcome.ok) failures++;
254
+ return outcome;
255
+ },
256
+ (err) => {
257
+ failures++;
258
+ throw err;
259
+ }
260
+ );
261
+ }
262
+
263
+ export { BUILD_LABEL, MIN_BUILDX_VERSION, RUNNER_LABEL, builderName, builderSpec, buildxState, containerExecArgs, containerRunArgs, ensureBuilder, ensureFailureCount, isOutOfMemory, prepareRunArgs, proxyEnvironment, runnerLabelValue, trackImageBuild };
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/runner/container/disk.ts
7
+ var UNITS = { "": 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3 };
8
+ function parseSize(text) {
9
+ const match = /^(\d+(?:\.\d+)?)([kKmMgG]?)$/.exec(text);
10
+ if (match === null) return void 0;
11
+ const bytes = Number(match[1]) * UNITS[match[2].toLowerCase()];
12
+ return bytes > 0 ? bytes : void 0;
13
+ }
14
+ function parseDuKilobytes(output) {
15
+ const match = /^(\d+)\s/.exec(output);
16
+ return match === null ? void 0 : Number(match[1]);
17
+ }
18
+ function exceedsDisk(usedKilobytes, limit) {
19
+ const bytes = parseSize(limit);
20
+ return usedKilobytes * 1024 > (bytes ?? Number.POSITIVE_INFINITY);
21
+ }
22
+
23
+ export { exceedsDisk, parseDuKilobytes, parseSize };