@outerlayer/cli 0.24.0 → 0.25.1
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 +21 -0
- package/README.md +9 -0
- package/dist/{agent-setup-QQYRBPK2.js → agent-setup-PDIIGMKE.js} +7 -7
- package/dist/{bridge-4ZARDVGS.js → bridge-5KZ36YDG.js} +3 -3
- package/dist/build-YYVAJ75G.js +12 -0
- package/dist/build-info.json +1 -1
- package/dist/{builder-MECDEKXX.js → builder-MNUJS4RG.js} +7 -7
- package/dist/{check-YYKNYFNI.js → check-C6HEFW6R.js} +39 -38
- package/dist/{chunk-BUBCPP3F.js → chunk-23SPSYXZ.js} +3 -3
- package/dist/{chunk-5ECUMU53.js → chunk-24LQ34XL.js} +6 -6
- package/dist/{chunk-BN3CSI7S.js → chunk-2K3TCQHW.js} +1 -1
- package/dist/{chunk-A62QFN2M.js → chunk-2N72GPS2.js} +3 -3
- package/dist/{chunk-TQ6Y7YV6.js → chunk-3FNPTQRH.js} +5 -5
- package/dist/{chunk-F2W2IYNP.js → chunk-3WZ5ECSM.js} +3 -3
- package/dist/{chunk-WH2QV3UL.js → chunk-4S4VBDSO.js} +1 -1
- package/dist/{chunk-IDSHLKQA.js → chunk-5222PA6S.js} +1 -1
- package/dist/{chunk-6GSA2SKT.js → chunk-A6ORKBVJ.js} +213 -59
- package/dist/{chunk-3W333NFO.js → chunk-APBTVIM4.js} +15 -4
- package/dist/{chunk-HHXBOTRO.js → chunk-ATGHVEU4.js} +1 -1
- package/dist/{chunk-D7K446H6.js → chunk-C36EOUUU.js} +5 -5
- package/dist/{chunk-RVYOOYOA.js → chunk-CQRIZNE6.js} +19 -10
- package/dist/{chunk-FWEWFW3F.js → chunk-DEBOL6ON.js} +1 -1
- package/dist/{chunk-GU4PKXN7.js → chunk-ENFBARQP.js} +185 -38
- package/dist/{chunk-H6IUKXXI.js → chunk-F57CLUH7.js} +207 -35
- package/dist/{chunk-E4OUL7ZP.js → chunk-FXUVXSY2.js} +2 -2
- package/dist/{chunk-F7Y2USIM.js → chunk-H6ZFLIX3.js} +3 -3
- package/dist/{chunk-LY2L3O2O.js → chunk-HPOEVC2V.js} +3 -2
- package/dist/{chunk-ZFLOFAUG.js → chunk-I25F6YVP.js} +8 -8
- package/dist/{chunk-DG2ULWM6.js → chunk-IGRRD7PX.js} +11 -7
- package/dist/{chunk-GISNHSYL.js → chunk-JGD5TWQ2.js} +4 -2
- package/dist/{chunk-D7X5ITVT.js → chunk-JWRX5ZTT.js} +6 -2
- package/dist/{chunk-755WXDBI.js → chunk-K5WVK7IC.js} +1 -1
- package/dist/{chunk-FKXGQOF5.js → chunk-M4B6QKNZ.js} +1 -1
- package/dist/{chunk-5XCAPBE2.js → chunk-N3VSI5ZI.js} +6 -6
- package/dist/{chunk-NTQTDCYR.js → chunk-O2WYUIK7.js} +1 -1
- package/dist/{chunk-BOQY756V.js → chunk-OEU4JSDE.js} +8 -7
- package/dist/{chunk-TTLVQZSH.js → chunk-Q435LWVN.js} +5 -5
- package/dist/{chunk-D4AMAEZ7.js → chunk-QE3UQAHK.js} +322 -17
- package/dist/{chunk-VV7ZD5LR.js → chunk-QMQC6JCO.js} +1 -1
- package/dist/{chunk-FQPN5S4Q.js → chunk-QXNJWSTM.js} +4 -4
- package/dist/{chunk-VBEXKEBV.js → chunk-S6AWZKJN.js} +19 -6
- package/dist/{chunk-V5Q3S4NM.js → chunk-SNQR2EYI.js} +2 -2
- package/dist/{chunk-CZUH2SLQ.js → chunk-UNF7MWEL.js} +1 -1
- package/dist/{chunk-W7O4LA4E.js → chunk-VAMUWK55.js} +3 -3
- package/dist/{chunk-PDIM5T65.js → chunk-XGJUNNXL.js} +1 -1
- package/dist/{chunk-NGZID7UI.js → chunk-XRYUJTAT.js} +8 -1
- package/dist/{chunk-LBCZXXOX.js → chunk-ZGMQQWCV.js} +2 -2
- package/dist/{chunk-KF37SUDM.js → chunk-ZI2ZVWKT.js} +1 -1
- package/dist/{chunk-PVRBE7S4.js → chunk-ZODVSFI4.js} +1 -1
- package/dist/chunk-ZVB57WI6.js +19 -0
- package/dist/{claude-launcher-JCPSHDZQ.js → claude-launcher-WGOCLTG6.js} +1 -1
- package/dist/{cli-ZTBH3FBG.js → cli-YMTNHR4W.js} +107 -102
- package/dist/command-DKYZC7PH.js +533 -0
- package/dist/{config-7Z5DHSGY.js → config-JJ3EO7SB.js} +3 -3
- package/dist/{connect-cmd-NY5LIKVC.js → connect-cmd-F7T4LNKX.js} +7 -7
- package/dist/{container-start-OHBUZEJJ.js → container-start-AX7QXJMR.js} +45 -36
- package/dist/{control-plane-launch-GKGI6HJA.js → control-plane-launch-ZFT6SI4N.js} +6 -6
- package/dist/{dist-2APO44JG.js → dist-QPHZE47F.js} +1 -1
- package/dist/{docker-RKGBJESN.js → docker-5EC5TE3Y.js} +7 -7
- package/dist/{doctor-DOAFZV4O.js → doctor-S6YCZGUU.js} +79 -33
- package/dist/{emit-artifact-cmd-VZHIDPXQ.js → emit-artifact-cmd-DJO475VZ.js} +11 -11
- package/dist/{emit-criteria-cmd-SYLBCWHW.js → emit-criteria-cmd-EULQ2MLI.js} +8 -8
- package/dist/{emit-finding-cmd-52M43NPC.js → emit-finding-cmd-QIIKMITO.js} +8 -8
- package/dist/{emit-result-cmd-BTMTGDAV.js → emit-result-cmd-NMCLTA47.js} +11 -11
- package/dist/{emit-step-cmd-6XTJITZT.js → emit-step-cmd-72OX5P6M.js} +9 -9
- package/dist/{exec-client-CKPK62K2.js → exec-client-KH33DICR.js} +4 -4
- package/dist/{governing-source-GWN7GVEN.js → governing-source-JNQ6PX2A.js} +11 -11
- package/dist/{guest-init-ZBL5CN7Y.js → guest-init-TOSKPGPF.js} +5 -5
- package/dist/{hook-fast-3JL4PXLG.js → hook-fast-NEELST6G.js} +1 -1
- package/dist/host-key-ICJEQBWH.js +9 -0
- package/dist/{image-tag-AO4RBAKW.js → image-tag-6KJOGBQK.js} +4 -4
- package/dist/index.js +4 -4
- package/dist/{init-TSQ3EOQW.js → init-624F4JIP.js} +25 -23
- package/dist/{init-EQTR7AEF.js → init-G7XC5WWL.js} +25 -23
- package/dist/{init-cmd-AF2MH36A.js → init-cmd-UUYA57VO.js} +11 -11
- package/dist/{init-update-SHISHMXV.js → init-update-MMV33PLM.js} +9 -9
- package/dist/{install-ORQC26ZE.js → install-MPEJJ7X6.js} +5 -5
- package/dist/{install-cmd-4LA3UJZ4.js → install-cmd-SE6NCTJK.js} +6 -6
- package/dist/job-state-format-WJQGQB6F.js +6 -0
- package/dist/{logs-5EPHIPZB.js → logs-T4ERSOQ4.js} +3 -3
- package/dist/loop-K5B2A3VW.js +78 -0
- package/dist/{machine-6UNLIPLE.js → machine-J4IFVIKU.js} +21 -19
- package/dist/{mcp-serve-cmd-KMWEKM7C.js → mcp-serve-cmd-7M4VLNI4.js} +5 -5
- package/dist/{paths-XY5ADO32.js → paths-2KGM2LZV.js} +3 -3
- package/dist/pending-BGLMTB5Q.js +9 -0
- package/dist/{pidfile-OJ7RP4Q2.js → pidfile-VYBH3IMN.js} +4 -4
- package/dist/{record-BEJB4J7N.js → record-GNOHDJ2O.js} +4 -4
- package/dist/{relay-PSZ4LGMW.js → relay-GFPPD6GF.js} +1 -1
- package/dist/relay-protocol-HELO5SNH.js +6 -0
- package/dist/{runner-env-ZJWJOJKQ.js → runner-env-GUFV544G.js} +6 -6
- package/dist/{runner-identity-2OOUJSFJ.js → runner-identity-HZ6CBM2R.js} +7 -7
- package/dist/{runner-key-WDFBSJRX.js → runner-key-FFVZUEHE.js} +25 -23
- package/dist/{session-sender-X3BBQZMF.js → session-sender-3SUWNNVP.js} +12 -12
- package/dist/{spec-cmd-QRF5YXKK.js → spec-cmd-VZDE6FFH.js} +9 -9
- package/dist/{status-ZCAAF6MD.js → status-GXTD44DX.js} +35 -29
- package/dist/{sync-cmd-UQK3RYAC.js → sync-cmd-VFB3NEJ6.js} +11 -11
- package/dist/{watch-MOQ3GQTE.js → watch-LWMTDD3L.js} +11 -11
- package/dist/{work-claim-cmd-RT343CLA.js → work-claim-cmd-FOBTDQVR.js} +12 -12
- package/dist/{work-cmd-APXSER2D.js → work-cmd-6HARIBMW.js} +9 -9
- package/dist/{work-comment-cmd-AT5NUYUU.js → work-comment-cmd-BITPALHR.js} +9 -9
- package/dist/{work-logs-cmd-Z5DMNEJP.js → work-logs-cmd-VGB3O2LZ.js} +9 -9
- package/dist/{work-open-pr-cmd-ZTS6MJHL.js → work-open-pr-cmd-SVZCNOIM.js} +10 -10
- package/dist/{work-pr-cmd-IWZCC3WH.js → work-pr-cmd-SJT46GN4.js} +9 -9
- package/dist/{work-stop-cmd-DCAWFDZC.js → work-stop-cmd-WXKVVA4S.js} +9 -9
- package/package.json +2 -2
- package/skill-pack/maintained/outerlayer-build/SKILL.md +1 -1
- package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +3 -2
- package/skill-pack/maintained/outerlayer-build/references/review-briefs.md +3 -1
- package/dist/build-OVZIT2G2.js +0 -12
- package/dist/command-DO4TERRT.js +0 -208
- package/dist/host-key-W2DLZGZ7.js +0 -9
- package/dist/loop-4WUCS5JP.js +0 -77
- package/dist/pending-35J3ZPLR.js +0 -9
- package/dist/relay-protocol-K7KP2SPI.js +0 -6
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { runRunnerInstall, launcherSummary, restartNote } from './chunk-QXNJWSTM.js';
|
|
4
|
+
import './chunk-ATGHVEU4.js';
|
|
5
|
+
import { currentLink, execStartCommand } from './chunk-QMQC6JCO.js';
|
|
6
|
+
import { detectMachine } from './chunk-S6AWZKJN.js';
|
|
7
|
+
import { helperSocketPath, ensureFirecrackerAndJailer } from './chunk-ENFBARQP.js';
|
|
8
|
+
import './chunk-5222PA6S.js';
|
|
9
|
+
import './chunk-TQMI335S.js';
|
|
10
|
+
import { DEFAULT_UNIT_NAME, installService, uninstallService, realTaskScheduler, UNIT_MARKER } from './chunk-IGRRD7PX.js';
|
|
11
|
+
import './chunk-Q435LWVN.js';
|
|
12
|
+
import './chunk-DEBOL6ON.js';
|
|
13
|
+
import './chunk-JBJTC3UU.js';
|
|
14
|
+
import './chunk-OGFGZQA3.js';
|
|
15
|
+
import { readJobFile } from './chunk-N3VSI5ZI.js';
|
|
16
|
+
import { firecrackerArch, MICROVM_ARCHES, FIRECRACKER_VERSION, FIRECRACKER_BINARY_SHA256, JAILER_BINARY_SHA256, HOST_HELPER_SHA256, HOST_HELPER_BASE_URL, HOST_HELPER_ASSETS_VERSION, hostHelperPinned } from './chunk-APBTVIM4.js';
|
|
17
|
+
import './chunk-HPOEVC2V.js';
|
|
18
|
+
import './chunk-XGJUNNXL.js';
|
|
19
|
+
import './chunk-3FNPTQRH.js';
|
|
20
|
+
import './chunk-CQRIZNE6.js';
|
|
21
|
+
import './chunk-3WZ5ECSM.js';
|
|
22
|
+
import './chunk-SNQR2EYI.js';
|
|
23
|
+
import './chunk-BUP5N3X6.js';
|
|
24
|
+
import './chunk-XSPA5ODY.js';
|
|
25
|
+
import './chunk-GOSFARMS.js';
|
|
26
|
+
import { runnerVmOf, loadRunnerConfig, builtinKind } from './chunk-JWRX5ZTT.js';
|
|
27
|
+
import './chunk-UXYLWVTQ.js';
|
|
28
|
+
import './chunk-7RQ73DLO.js';
|
|
29
|
+
import { realLima } from './chunk-77MM5RYD.js';
|
|
30
|
+
import { writeLaunchAgent, launchAgentPath } from './chunk-LF6MLJCY.js';
|
|
31
|
+
import './chunk-FXUVXSY2.js';
|
|
32
|
+
import './chunk-MQ743JX3.js';
|
|
33
|
+
import './chunk-M4B6QKNZ.js';
|
|
34
|
+
import './chunk-ZJSNLVCE.js';
|
|
35
|
+
import './chunk-VPEGE3QZ.js';
|
|
36
|
+
import './chunk-HCVLP7XA.js';
|
|
37
|
+
import './chunk-BJ3KTMDH.js';
|
|
38
|
+
import './chunk-QE3UQAHK.js';
|
|
39
|
+
import './chunk-ANPNT6PM.js';
|
|
40
|
+
import './chunk-EABW6AJQ.js';
|
|
41
|
+
import './chunk-JKNYTNYD.js';
|
|
42
|
+
import './chunk-HBISTTG3.js';
|
|
43
|
+
import './chunk-WZBHBH3J.js';
|
|
44
|
+
import './chunk-CRB3POP4.js';
|
|
45
|
+
import './chunk-YQR6E6OV.js';
|
|
46
|
+
import './chunk-RKOTJQVG.js';
|
|
47
|
+
import './chunk-QZBXLLTV.js';
|
|
48
|
+
import './chunk-VNVZDWO3.js';
|
|
49
|
+
import './chunk-RA3O54FC.js';
|
|
50
|
+
import './chunk-ZODVSFI4.js';
|
|
51
|
+
import { runnerDir } from './chunk-ZI2ZVWKT.js';
|
|
52
|
+
import './chunk-2K3TCQHW.js';
|
|
53
|
+
import './chunk-JGD5TWQ2.js';
|
|
54
|
+
import './chunk-Z5GEFMRW.js';
|
|
55
|
+
import { userInfo, totalmem, tmpdir } from 'os';
|
|
56
|
+
import { join, dirname } from 'path';
|
|
57
|
+
import { createHash } from 'crypto';
|
|
58
|
+
import { rmSync, existsSync, readdirSync, mkdtempSync, writeFileSync, readFileSync, statSync, lstatSync } from 'fs';
|
|
59
|
+
import { spawnSync } from 'child_process';
|
|
60
|
+
|
|
61
|
+
createRequire(import.meta.url);
|
|
62
|
+
var LIBEXEC = "/usr/local/libexec/outerlayer";
|
|
63
|
+
var ETC = "/etc/outerlayer";
|
|
64
|
+
var UID_BASE = 2e9;
|
|
65
|
+
var UID_COUNT = 256;
|
|
66
|
+
var UID_ATTEMPTS = 8;
|
|
67
|
+
function helperUnitFor(unitName) {
|
|
68
|
+
return `${unitName}-helper`;
|
|
69
|
+
}
|
|
70
|
+
function helperDirFor(unitName) {
|
|
71
|
+
return `${LIBEXEC}/${helperUnitFor(unitName)}`;
|
|
72
|
+
}
|
|
73
|
+
function helperSocketFor(unitName) {
|
|
74
|
+
return helperSocketPath(unitName);
|
|
75
|
+
}
|
|
76
|
+
function helperConfigPathFor(unitName) {
|
|
77
|
+
return `${ETC}/${helperUnitFor(unitName)}.json`;
|
|
78
|
+
}
|
|
79
|
+
function helperUnitPathFor(unitName) {
|
|
80
|
+
return `/etc/systemd/system/${helperUnitFor(unitName)}.service`;
|
|
81
|
+
}
|
|
82
|
+
function sha256Of(bytes) {
|
|
83
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
84
|
+
}
|
|
85
|
+
function helperUnitText(unitName) {
|
|
86
|
+
const unit = helperUnitFor(unitName);
|
|
87
|
+
return `${UNIT_MARKER}
|
|
88
|
+
[Unit]
|
|
89
|
+
Description=OuterLayer root helper: starts microVM builds under Firecracker's jailer
|
|
90
|
+
After=local-fs.target
|
|
91
|
+
|
|
92
|
+
[Service]
|
|
93
|
+
ExecStart=${helperDirFor(unitName)}/outerlayer-host-helper --config ${helperConfigPathFor(unitName)}
|
|
94
|
+
RuntimeDirectory=${unit}
|
|
95
|
+
RuntimeDirectoryMode=0755
|
|
96
|
+
RuntimeDirectoryPreserve=yes
|
|
97
|
+
Restart=on-failure
|
|
98
|
+
RestartSec=5
|
|
99
|
+
KillMode=process
|
|
100
|
+
|
|
101
|
+
[Install]
|
|
102
|
+
WantedBy=multi-user.target
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
function helperConfigText(input) {
|
|
106
|
+
const dir = helperDirFor(input.unitName);
|
|
107
|
+
return `${JSON.stringify(
|
|
108
|
+
{
|
|
109
|
+
runnerUid: input.uid,
|
|
110
|
+
runnerGid: input.gid,
|
|
111
|
+
buildsRoot: input.buildsRoot,
|
|
112
|
+
jailBase: input.jailBase,
|
|
113
|
+
stateDir: `/run/${helperUnitFor(input.unitName)}/state`,
|
|
114
|
+
socket: helperSocketFor(input.unitName),
|
|
115
|
+
uidBase: input.uidBase,
|
|
116
|
+
uidCount: UID_COUNT,
|
|
117
|
+
jailer: { path: `${dir}/jailer`, sha256: input.pins.jailer },
|
|
118
|
+
firecracker: { path: `${dir}/firecracker`, sha256: input.pins.firecracker },
|
|
119
|
+
firecrackerVersion: input.pins.firecrackerVersion
|
|
120
|
+
},
|
|
121
|
+
null,
|
|
122
|
+
2
|
|
123
|
+
)}
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
function notInstalled(ok, lines) {
|
|
127
|
+
return { ok, installed: false, lines };
|
|
128
|
+
}
|
|
129
|
+
async function installHelper(request, deps) {
|
|
130
|
+
const { helper } = deps;
|
|
131
|
+
const lines = [];
|
|
132
|
+
const say = deps.say ?? ((line) => void lines.push(line));
|
|
133
|
+
const unit = helperUnitFor(request.unitName);
|
|
134
|
+
const dir = helperDirFor(request.unitName);
|
|
135
|
+
const configFile = helperConfigPathFor(request.unitName);
|
|
136
|
+
const without = "microVM builds run Firecracker as the runner's account, as they did before";
|
|
137
|
+
if (!deps.systemd.running()) return notInstalled(true, [`systemd is not running, so the root helper is not installed: ${without}`]);
|
|
138
|
+
if (helper.pins.helper === void 0) {
|
|
139
|
+
return notInstalled(true, [`this release of the CLI pins no root helper, so none is installed: ${without}`]);
|
|
140
|
+
}
|
|
141
|
+
const identity = helper.identity(request.user);
|
|
142
|
+
if (identity === void 0) return notInstalled(false, [`the account ${request.user} was not found, so the root helper was not installed`]);
|
|
143
|
+
const runner = runnerDir(request.configPath);
|
|
144
|
+
const buildsRoot = join(runner, "builds");
|
|
145
|
+
const jailBase = helper.jailBase(buildsRoot, request.unitName);
|
|
146
|
+
if (jailBase === void 0) {
|
|
147
|
+
return notInstalled(true, [
|
|
148
|
+
`no directory that only root can write, below only such directories, is on the same file system as ${buildsRoot}, so the root helper was not installed: it links each build's files into its jail, and a link cannot cross file systems. ${without}`
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
let uidBase = UID_BASE;
|
|
152
|
+
for (let attempt = 0; attempt < UID_ATTEMPTS && !helper.uidRangeFree(uidBase, UID_COUNT); attempt++) uidBase += 65536;
|
|
153
|
+
if (!helper.uidRangeFree(uidBase, UID_COUNT)) return notInstalled(true, [`every range of ${UID_COUNT} user ids that was tried is used by an account or a group, so the root helper was not installed: ${without}`]);
|
|
154
|
+
let assets;
|
|
155
|
+
let helperBytes;
|
|
156
|
+
try {
|
|
157
|
+
assets = await helper.assets(runner);
|
|
158
|
+
helperBytes = await helper.fetchHelper();
|
|
159
|
+
} catch (err) {
|
|
160
|
+
return notInstalled(false, [`the files for the root helper could not be had: ${err instanceof Error ? err.message : String(err)}`]);
|
|
161
|
+
}
|
|
162
|
+
if (sha256Of(helperBytes) !== helper.pins.helper) {
|
|
163
|
+
return notInstalled(false, [`the root helper that was downloaded has sha256 ${sha256Of(helperBytes)}, not the ${helper.pins.helper} this release pins, so it was not installed`]);
|
|
164
|
+
}
|
|
165
|
+
const config = helperConfigText({ unitName: request.unitName, uid: identity.uid, gid: identity.gid, buildsRoot, jailBase, uidBase, pins: helper.pins });
|
|
166
|
+
const unitPath = helperUnitPathFor(request.unitName);
|
|
167
|
+
const existed = deps.systemd.read(unitPath) !== void 0;
|
|
168
|
+
const staged = helper.stage({ "outerlayer-host-helper": helperBytes, "helper.json": config });
|
|
169
|
+
const root = (argv) => {
|
|
170
|
+
say(`sudo ${argv.join(" ")}`);
|
|
171
|
+
const result = helper.root(argv);
|
|
172
|
+
if (result.status !== 0) lines.push(`sudo ${argv.join(" ")} failed with exit status ${result.status}`);
|
|
173
|
+
return result.status === 0;
|
|
174
|
+
};
|
|
175
|
+
const systemctl = (args) => {
|
|
176
|
+
say(`sudo systemctl ${args.join(" ")}`);
|
|
177
|
+
return deps.systemd.systemctl(args, { sudo: true }).status === 0;
|
|
178
|
+
};
|
|
179
|
+
const removeFiles = () => {
|
|
180
|
+
helper.root(["rm", "-rf", dir]);
|
|
181
|
+
helper.root(["rm", "-f", configFile]);
|
|
182
|
+
};
|
|
183
|
+
const discard = () => {
|
|
184
|
+
if (existed) systemctl(["disable", "--now", unit]);
|
|
185
|
+
if (deps.systemd.read(unitPath) !== void 0) {
|
|
186
|
+
deps.systemd.remove(unitPath);
|
|
187
|
+
systemctl(["daemon-reload"]);
|
|
188
|
+
}
|
|
189
|
+
removeFiles();
|
|
190
|
+
};
|
|
191
|
+
try {
|
|
192
|
+
const copies = [
|
|
193
|
+
{ from: join(staged.dir, "outerlayer-host-helper"), to: `${dir}/outerlayer-host-helper`, pin: helper.pins.helper, what: "helper" },
|
|
194
|
+
{ from: assets.jailer, to: `${dir}/jailer`, pin: helper.pins.jailer, what: "jailer" },
|
|
195
|
+
{ from: assets.firecracker, to: `${dir}/firecracker`, pin: helper.pins.firecracker, what: "Firecracker" }
|
|
196
|
+
];
|
|
197
|
+
const ok = root(["install", "-d", "-o", "root", "-g", "root", "-m", "0755", dir]) && root(["install", "-d", "-o", "root", "-g", "root", "-m", "0755", ETC]) && root(["install", "-d", "-o", "root", "-g", "root", "-m", "0755", jailBase]) && copies.every((copy) => root(["install", "-o", "root", "-g", "root", "-m", "0755", copy.from, copy.to])) && root(["install", "-o", "root", "-g", "root", "-m", "0644", join(staged.dir, "helper.json"), configFile]);
|
|
198
|
+
if (!ok) {
|
|
199
|
+
if (existed) lines.push(`the root helper ${unit} is installed, so its files were left in place`);
|
|
200
|
+
else removeFiles();
|
|
201
|
+
return notInstalled(false, lines);
|
|
202
|
+
}
|
|
203
|
+
for (const copy of copies) {
|
|
204
|
+
const bytes = helper.readFile(copy.to);
|
|
205
|
+
if (bytes === void 0 || sha256Of(bytes) !== copy.pin) {
|
|
206
|
+
discard();
|
|
207
|
+
return notInstalled(false, [...lines, `the ${copy.what} copied to ${copy.to} is not the file this release pins, so the root helper was not installed`]);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (helper.readFile(configFile)?.toString("utf8") !== config) {
|
|
211
|
+
discard();
|
|
212
|
+
return notInstalled(false, [...lines, `the config copied to ${configFile} is not the one the installer wrote, so the root helper was not installed`]);
|
|
213
|
+
}
|
|
214
|
+
const writable = deps.accountCan === void 0 ? void 0 : [dir, ...copies.map((copy) => copy.to), configFile, ETC].find((path) => deps.accountCan(request.user, "-w", path));
|
|
215
|
+
if (writable !== void 0) {
|
|
216
|
+
discard();
|
|
217
|
+
return notInstalled(false, [...lines, `the account ${request.user} can write ${writable}, which root runs or reads, so the root helper was not installed`]);
|
|
218
|
+
}
|
|
219
|
+
} finally {
|
|
220
|
+
staged.remove();
|
|
221
|
+
}
|
|
222
|
+
say(`sudo tee ${unitPath}`);
|
|
223
|
+
try {
|
|
224
|
+
deps.systemd.write(unitPath, helperUnitText(request.unitName));
|
|
225
|
+
} catch (err) {
|
|
226
|
+
if (!existed) removeFiles();
|
|
227
|
+
return notInstalled(false, [...lines, err instanceof Error ? err.message : String(err)]);
|
|
228
|
+
}
|
|
229
|
+
if (!systemctl(["daemon-reload"]) || !systemctl(["enable", "--now", unit]) || existed && !systemctl(["restart", unit])) {
|
|
230
|
+
if (!existed) discard();
|
|
231
|
+
lines.push(`the unit ${unit} did not start, so the root helper is not running: ${without}`);
|
|
232
|
+
return notInstalled(false, lines);
|
|
233
|
+
}
|
|
234
|
+
lines.push(`installed and started the root helper ${unit}: it runs as root, starts each microVM build under Firecracker's jailer and does nothing else`);
|
|
235
|
+
return { ok: true, installed: true, lines };
|
|
236
|
+
}
|
|
237
|
+
function uninstallHelper(request, deps) {
|
|
238
|
+
const lines = [];
|
|
239
|
+
const say = deps.say ?? ((line) => void lines.push(line));
|
|
240
|
+
const unit = helperUnitFor(request.unitName);
|
|
241
|
+
const unitPath = helperUnitPathFor(request.unitName);
|
|
242
|
+
const configFile = helperConfigPathFor(request.unitName);
|
|
243
|
+
const dir = helperDirFor(request.unitName);
|
|
244
|
+
const config = deps.helper.readFile(configFile);
|
|
245
|
+
let jailBase;
|
|
246
|
+
if (config !== void 0) {
|
|
247
|
+
try {
|
|
248
|
+
jailBase = JSON.parse(config.toString("utf8")).jailBase;
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const systemctl = (args) => {
|
|
253
|
+
say(`sudo systemctl ${args.join(" ")}`);
|
|
254
|
+
deps.systemd.systemctl(args, { sudo: true });
|
|
255
|
+
};
|
|
256
|
+
const root = (argv) => {
|
|
257
|
+
say(`sudo ${argv.join(" ")}`);
|
|
258
|
+
deps.helper.root(argv);
|
|
259
|
+
};
|
|
260
|
+
const installed = deps.systemd.read(unitPath) !== void 0 || config !== void 0;
|
|
261
|
+
if (!installed) return { ok: true, installed: false, lines };
|
|
262
|
+
systemctl(["disable", "--now", unit]);
|
|
263
|
+
if (deps.systemd.read(unitPath) !== void 0) {
|
|
264
|
+
say(`sudo rm ${unitPath}`);
|
|
265
|
+
deps.systemd.remove(unitPath);
|
|
266
|
+
systemctl(["daemon-reload"]);
|
|
267
|
+
}
|
|
268
|
+
root(["rm", "-rf", dir]);
|
|
269
|
+
root(["rm", "-f", configFile]);
|
|
270
|
+
if (jailBase !== void 0) root(["rmdir", `${jailBase}/firecracker`, jailBase]);
|
|
271
|
+
lines.push(`removed the root helper ${unit}`);
|
|
272
|
+
return { ok: true, installed: false, lines };
|
|
273
|
+
}
|
|
274
|
+
async function serviceInVm(lima, instance, action, options) {
|
|
275
|
+
const limactl = lima.locate();
|
|
276
|
+
if (limactl === void 0) {
|
|
277
|
+
return { ok: false, lines: ["limactl is not installed, and the runner's service lives in the Linux VM it manages. Install Lima with `brew install lima`."] };
|
|
278
|
+
}
|
|
279
|
+
const ran = await lima.shell(instance, ["outerlayer", "runner", action, "--service", ...options.extraArgs ?? []]);
|
|
280
|
+
const lines = [...ran.stdout.split("\n"), ...ran.stderr.split("\n")].map((line) => line.trim()).filter((line) => line !== "");
|
|
281
|
+
if (ran.status !== 0) return { ok: false, lines: lines.length > 0 ? lines : [`outerlayer runner ${action} --service failed in the VM ${instance} with exit status ${ran.status}`] };
|
|
282
|
+
if (action === "install") {
|
|
283
|
+
const path = writeLaunchAgent(options.home, limactl, instance);
|
|
284
|
+
lines.push(`the VM ${instance} starts at login through ${path}`);
|
|
285
|
+
} else {
|
|
286
|
+
rmSync(launchAgentPath(options.home), { force: true });
|
|
287
|
+
lines.push("removed the launch agent that started the VM at login");
|
|
288
|
+
}
|
|
289
|
+
return { ok: true, lines };
|
|
290
|
+
}
|
|
291
|
+
var WSL_CONF = "/etc/wsl.conf";
|
|
292
|
+
function readText(path) {
|
|
293
|
+
try {
|
|
294
|
+
return readFileSync(path, "utf8");
|
|
295
|
+
} catch {
|
|
296
|
+
return void 0;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function sudoWrite(path, text) {
|
|
300
|
+
const result = spawnSync("sudo", ["tee", path], { input: text, stdio: ["pipe", "ignore", "inherit"] });
|
|
301
|
+
if (result.status !== 0) throw new Error(`sudo tee ${path} failed with exit status ${result.status}`);
|
|
302
|
+
}
|
|
303
|
+
function realSystemd() {
|
|
304
|
+
return {
|
|
305
|
+
running: () => existsSync("/run/systemd/system"),
|
|
306
|
+
read: readText,
|
|
307
|
+
write: sudoWrite,
|
|
308
|
+
remove: (path) => {
|
|
309
|
+
spawnSync("sudo", ["rm", "-f", path], { stdio: ["inherit", "ignore", "inherit"] });
|
|
310
|
+
},
|
|
311
|
+
systemctl: (args, options) => {
|
|
312
|
+
const result = options?.sudo === true ? spawnSync("sudo", ["systemctl", ...args], { encoding: "utf8", stdio: ["inherit", "pipe", "inherit"] }) : spawnSync("systemctl", args, { encoding: "utf8" });
|
|
313
|
+
return { status: result.status ?? -1, stdout: result.stdout ?? "" };
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function realWslConf() {
|
|
318
|
+
return { read: () => readText(WSL_CONF), write: (text) => sudoWrite(WSL_CONF, text) };
|
|
319
|
+
}
|
|
320
|
+
function buildsRunningIn(runnerDirPath) {
|
|
321
|
+
const jobs = join(runnerDirPath, "jobs");
|
|
322
|
+
if (!existsSync(jobs)) return false;
|
|
323
|
+
try {
|
|
324
|
+
return readdirSync(jobs, { withFileTypes: true }).some((entry) => {
|
|
325
|
+
if (!entry.isDirectory()) return false;
|
|
326
|
+
const job = readJobFile(join(jobs, entry.name, "job.json"));
|
|
327
|
+
return job === null || job.outcome === void 0 && job.endedAt === void 0;
|
|
328
|
+
});
|
|
329
|
+
} catch {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function rootOnlyChain(path) {
|
|
334
|
+
let current = "/";
|
|
335
|
+
const parts = path.split("/").filter(Boolean);
|
|
336
|
+
for (const part of ["", ...parts]) {
|
|
337
|
+
current = join(current, part);
|
|
338
|
+
try {
|
|
339
|
+
const info = lstatSync(current);
|
|
340
|
+
if (!info.isDirectory() || info.uid !== 0 || (info.mode & 18) !== 0) return false;
|
|
341
|
+
} catch {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
function deviceOf(path) {
|
|
348
|
+
for (let current = path; ; current = dirname(current)) {
|
|
349
|
+
try {
|
|
350
|
+
return statSync(current).dev;
|
|
351
|
+
} catch {
|
|
352
|
+
if (dirname(current) === current) return void 0;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function findJailBase(buildsDir, unitName) {
|
|
357
|
+
const dev = deviceOf(buildsDir);
|
|
358
|
+
if (dev === void 0) return void 0;
|
|
359
|
+
const name = `${unitName}-jail`;
|
|
360
|
+
const candidates = [`/var/lib/outerlayer/${name}`];
|
|
361
|
+
for (let ancestor = dirname(buildsDir); dirname(ancestor) !== ancestor; ancestor = dirname(ancestor)) candidates.push(join(ancestor, `.${name}`));
|
|
362
|
+
return candidates.find((candidate) => {
|
|
363
|
+
const parent = candidate.startsWith("/var/lib/outerlayer/") ? "/var/lib" : dirname(candidate);
|
|
364
|
+
if (!rootOnlyChain(parent) || deviceOf(parent) !== dev) return false;
|
|
365
|
+
return !existsSync(candidate) || rootOnlyChain(candidate) && deviceOf(candidate) === dev;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function overlaps(start, length, base, count) {
|
|
369
|
+
return length > 0 && start < base + count && start + length > base;
|
|
370
|
+
}
|
|
371
|
+
function idRangeFree(base, count) {
|
|
372
|
+
for (const file of ["/etc/passwd", "/etc/group"]) {
|
|
373
|
+
const text = readText(file);
|
|
374
|
+
if (text === void 0) return false;
|
|
375
|
+
for (const line of text.split("\n")) {
|
|
376
|
+
const fields = line.split(":");
|
|
377
|
+
if (overlaps(Number(fields[2]), 1, base, count)) return false;
|
|
378
|
+
if (file === "/etc/passwd" && overlaps(Number(fields[3]), 1, base, count)) return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
for (const file of ["/etc/subuid", "/etc/subgid"]) {
|
|
382
|
+
for (const line of (readText(file) ?? "").split("\n")) {
|
|
383
|
+
const fields = line.split(":");
|
|
384
|
+
if (overlaps(Number(fields[1]), Number(fields[2]), base, count)) return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
function idOf(flag, account) {
|
|
390
|
+
const result = spawnSync("id", [flag, account], { encoding: "utf8" });
|
|
391
|
+
const id = Number(result.stdout);
|
|
392
|
+
return result.status === 0 && Number.isInteger(id) ? id : void 0;
|
|
393
|
+
}
|
|
394
|
+
function realHelperDeps() {
|
|
395
|
+
const arch = firecrackerArch(process.arch);
|
|
396
|
+
const pinnedArch = MICROVM_ARCHES.includes(arch) ? arch : void 0;
|
|
397
|
+
return {
|
|
398
|
+
pins: {
|
|
399
|
+
helper: pinnedArch !== void 0 && hostHelperPinned(pinnedArch) ? HOST_HELPER_SHA256[pinnedArch] : void 0,
|
|
400
|
+
jailer: JAILER_BINARY_SHA256[pinnedArch ?? "x86_64"],
|
|
401
|
+
firecracker: FIRECRACKER_BINARY_SHA256[pinnedArch ?? "x86_64"],
|
|
402
|
+
firecrackerVersion: FIRECRACKER_VERSION
|
|
403
|
+
},
|
|
404
|
+
assets: (runner) => ensureFirecrackerAndJailer({ runnerDir: runner }),
|
|
405
|
+
fetchHelper: async () => {
|
|
406
|
+
const url = `${HOST_HELPER_BASE_URL}/outerlayer-host-helper-${arch}`;
|
|
407
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(10 * 6e4) });
|
|
408
|
+
if (!response.ok) throw new Error(`the root helper could not be downloaded from ${url}: the server answered ${response.status}; the root helper is published in the release guest-${HOST_HELPER_ASSETS_VERSION}`);
|
|
409
|
+
return Buffer.from(await response.arrayBuffer());
|
|
410
|
+
},
|
|
411
|
+
root: (argv) => {
|
|
412
|
+
const result = spawnSync("sudo", argv, { stdio: ["inherit", "ignore", "inherit"] });
|
|
413
|
+
return { status: result.status ?? -1 };
|
|
414
|
+
},
|
|
415
|
+
readFile: (path) => {
|
|
416
|
+
try {
|
|
417
|
+
return readFileSync(path);
|
|
418
|
+
} catch {
|
|
419
|
+
return void 0;
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
identity: (account) => {
|
|
423
|
+
const uid = account === userInfo().username ? userInfo().uid : idOf("-u", account);
|
|
424
|
+
const gid = account === userInfo().username ? userInfo().gid : idOf("-g", account);
|
|
425
|
+
return uid === void 0 || gid === void 0 || uid < 0 || gid < 0 ? void 0 : { uid, gid };
|
|
426
|
+
},
|
|
427
|
+
jailBase: findJailBase,
|
|
428
|
+
uidRangeFree: idRangeFree,
|
|
429
|
+
stage: (files) => {
|
|
430
|
+
const dir = mkdtempSync(join(tmpdir(), "outerlayer-helper-"));
|
|
431
|
+
for (const [name, content] of Object.entries(files)) writeFileSync(join(dir, name), content, { mode: 493 });
|
|
432
|
+
return { dir, remove: () => rmSync(dir, { recursive: true, force: true }) };
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function realServiceDeps() {
|
|
437
|
+
const platform = detectMachine().platform;
|
|
438
|
+
return {
|
|
439
|
+
platform,
|
|
440
|
+
say: (line) => process.stdout.write(`running: ${line}
|
|
441
|
+
`),
|
|
442
|
+
systemd: realSystemd(),
|
|
443
|
+
...platform === "wsl2" ? { tasks: realTaskScheduler(), wslConf: realWslConf(), distro: process.env.WSL_DISTRO_NAME } : {},
|
|
444
|
+
usableMemoryBytes: totalmem(),
|
|
445
|
+
buildsRunning: buildsRunningIn,
|
|
446
|
+
...platform === "linux" || platform === "wsl2" ? { helper: realHelperDeps() } : {},
|
|
447
|
+
// Asked as the account, through sudo, which the unit's own install needs anyway.
|
|
448
|
+
accountCan: (account, flag, path) => spawnSync("sudo", ["-n", "-u", account, "test", flag, path], { stdio: "ignore" }).status === 0
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/runner/service/command.ts
|
|
453
|
+
function accountCannotStart(account, nodePath, entry, can) {
|
|
454
|
+
if (!can(account, "-x", nodePath)) {
|
|
455
|
+
return `\u2717 the service would run as ${account}, which cannot execute ${nodePath}, the Node this install runs on. Nothing is set up: run the install as ${account} with a Node it can execute, or install Node where ${account} can reach it`;
|
|
456
|
+
}
|
|
457
|
+
if (!can(account, "-r", entry)) {
|
|
458
|
+
return `\u2717 the service would run as ${account}, which cannot read ${entry}. Nothing is set up: put the runner's config where ${account} can read it, or run the install as ${account}`;
|
|
459
|
+
}
|
|
460
|
+
return void 0;
|
|
461
|
+
}
|
|
462
|
+
function vmArgs(input) {
|
|
463
|
+
return [...input.print === true ? ["--print"] : [], ...input.replace === true ? ["--replace"] : [], ...input.allowDowngrade === true ? ["--allow-downgrade"] : [], ...input.user === void 0 ? [] : ["--user", input.user], ...input.unitName === void 0 ? [] : ["--unit-name", input.unitName]];
|
|
464
|
+
}
|
|
465
|
+
async function installServiceCommand(input, deps = {}) {
|
|
466
|
+
const vm = runnerVmOf(input.configPath);
|
|
467
|
+
if (vm !== void 0) {
|
|
468
|
+
const result = await serviceInVm((deps.lima ?? realLima)(), vm.instance, "install", { home: input.home, extraArgs: vmArgs(input) });
|
|
469
|
+
return { ok: result.ok, state: "vm", lines: result.lines };
|
|
470
|
+
}
|
|
471
|
+
const config = loadRunnerConfig(input.configPath);
|
|
472
|
+
let launcherLines = [];
|
|
473
|
+
let launcherNotes = [];
|
|
474
|
+
let restartLine;
|
|
475
|
+
if (input.print !== true && input.layoutInstalled !== true) {
|
|
476
|
+
const installed = runRunnerInstall({
|
|
477
|
+
configPath: input.configPath,
|
|
478
|
+
entryPath: input.entryPath,
|
|
479
|
+
nodePath: input.nodePath,
|
|
480
|
+
home: input.home,
|
|
481
|
+
PATH: process.env.PATH,
|
|
482
|
+
replace: input.replace,
|
|
483
|
+
allowDowngrade: input.allowDowngrade,
|
|
484
|
+
command: "runner install --service"
|
|
485
|
+
});
|
|
486
|
+
launcherLines = [launcherSummary(installed.launcher)].filter((line) => line !== void 0);
|
|
487
|
+
launcherNotes = installed.launcher.notes;
|
|
488
|
+
restartLine = restartNote(installed);
|
|
489
|
+
}
|
|
490
|
+
const account = input.user ?? userInfo().username;
|
|
491
|
+
const serviceDeps = (deps.service ?? realServiceDeps)();
|
|
492
|
+
if (input.print !== true && account !== userInfo().username && serviceDeps.accountCan !== void 0) {
|
|
493
|
+
const entry = join(currentLink(input.configPath), "node_modules", "@outerlayer", "cli", "dist", "index.js");
|
|
494
|
+
const problem = accountCannotStart(account, input.nodePath, entry, serviceDeps.accountCan);
|
|
495
|
+
if (problem !== void 0) return { ok: false, state: "refused", lines: [problem] };
|
|
496
|
+
}
|
|
497
|
+
const unitName = input.unitName ?? DEFAULT_UNIT_NAME;
|
|
498
|
+
const usesVm = builtinKind(config.hooks.provision) === "vm";
|
|
499
|
+
const helper = input.print !== true && usesVm && serviceDeps.helper !== void 0 && serviceDeps.systemd.running() ? await installHelper({ configPath: input.configPath, unitName, user: account }, { ...serviceDeps, helper: serviceDeps.helper }) : void 0;
|
|
500
|
+
if (helper !== void 0 && !helper.ok) return { ok: false, state: "refused", lines: helper.lines };
|
|
501
|
+
const outcome = installService(
|
|
502
|
+
{
|
|
503
|
+
configPath: input.configPath,
|
|
504
|
+
hooks: config.hooks,
|
|
505
|
+
concurrency: config.concurrency,
|
|
506
|
+
buildMemory: config.build?.memory ?? "8g",
|
|
507
|
+
timeLimitMinutes: config.timeLimitMinutes,
|
|
508
|
+
execStart: execStartCommand(input.configPath, input.nodePath),
|
|
509
|
+
user: account,
|
|
510
|
+
unitName: input.unitName,
|
|
511
|
+
print: input.print,
|
|
512
|
+
replace: input.replace,
|
|
513
|
+
restart: input.restart,
|
|
514
|
+
...helper?.installed === true ? { helperSocket: helperSocketFor(unitName), helperUnit: helperUnitFor(unitName) } : {}
|
|
515
|
+
},
|
|
516
|
+
serviceDeps
|
|
517
|
+
);
|
|
518
|
+
const restartLines = restartLine !== void 0 && (outcome.state === "current" || outcome.state === "pending-restart") ? [restartLine] : [];
|
|
519
|
+
return { ok: outcome.ok, state: outcome.state, lines: [...helper?.lines ?? [], ...outcome.lines, ...outcome.ok ? [...restartLines, ...launcherLines] : []], unit: outcome.unit, ...launcherNotes.length > 0 ? { notes: launcherNotes } : {} };
|
|
520
|
+
}
|
|
521
|
+
async function uninstallServiceCommand(input, deps = {}) {
|
|
522
|
+
const vm = runnerVmOf(input.configPath);
|
|
523
|
+
if (vm !== void 0) {
|
|
524
|
+
const result = await serviceInVm((deps.lima ?? realLima)(), vm.instance, "uninstall", { home: input.home, extraArgs: input.unitName === void 0 ? [] : ["--unit-name", input.unitName] });
|
|
525
|
+
return { ok: result.ok, state: "vm", lines: result.lines };
|
|
526
|
+
}
|
|
527
|
+
const serviceDeps = (deps.service ?? realServiceDeps)();
|
|
528
|
+
const outcome = uninstallService({ configPath: input.configPath, unitName: input.unitName }, serviceDeps);
|
|
529
|
+
const helper = outcome.ok && serviceDeps.helper !== void 0 && serviceDeps.systemd.running() ? uninstallHelper({ configPath: input.configPath, unitName: input.unitName ?? DEFAULT_UNIT_NAME }, { ...serviceDeps, helper: serviceDeps.helper }) : void 0;
|
|
530
|
+
return { ok: outcome.ok, state: outcome.state, lines: [...outcome.lines, ...helper?.lines ?? []] };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export { installServiceCommand, uninstallServiceCommand };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { DEFAULT_CHECK_TIME_LIMIT_MINUTES, DEFAULT_UPDATE_MAX_WAIT_HOURS, RunnerConfigError, builtinKind, checkHooks, defaultRunnerConfigPath, hasRunnerBlock, isBuiltinContainer, isBuiltinProcess, isBuiltinVm, loadRunnerConfig, resolveBuild, resolveHousekeeping, runnerCredentialProblem, runnerVmOf } from './chunk-
|
|
3
|
+
export { DEFAULT_CHECK_TIME_LIMIT_MINUTES, DEFAULT_UPDATE_MAX_WAIT_HOURS, RunnerConfigError, builtinKind, checkHooks, defaultRunnerConfigPath, hasRunnerBlock, isBuiltinContainer, isBuiltinProcess, isBuiltinVm, loadRunnerConfig, resolveBuild, resolveHousekeeping, runnerCredentialProblem, runnerVmOf } from './chunk-JWRX5ZTT.js';
|
|
4
4
|
import './chunk-UXYLWVTQ.js';
|
|
5
5
|
import './chunk-7RQ73DLO.js';
|
|
6
6
|
import './chunk-VNVZDWO3.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
7
|
+
import './chunk-2K3TCQHW.js';
|
|
8
|
+
import './chunk-JGD5TWQ2.js';
|
|
9
9
|
import './chunk-Z5GEFMRW.js';
|
|
10
10
|
|
|
11
11
|
createRequire(import.meta.url);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { AGENTS_LAYOUT_COMMIT_LINE, COMMIT_LINE, autoConnectedLine, commitLineFor, listText as factoryListText, slug as factorySlug, fetchFactories, hasUncommittedPolicy, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory } from './chunk-
|
|
3
|
+
export { AGENTS_LAYOUT_COMMIT_LINE, COMMIT_LINE, autoConnectedLine, commitLineFor, listText as factoryListText, slug as factorySlug, fetchFactories, hasUncommittedPolicy, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory } from './chunk-SNQR2EYI.js';
|
|
4
4
|
import './chunk-BUP5N3X6.js';
|
|
5
5
|
import './chunk-XSPA5ODY.js';
|
|
6
6
|
import './chunk-GOSFARMS.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-M4B6QKNZ.js';
|
|
8
8
|
import './chunk-BJ3KTMDH.js';
|
|
9
|
-
import './chunk-
|
|
9
|
+
import './chunk-QE3UQAHK.js';
|
|
10
10
|
import './chunk-ANPNT6PM.js';
|
|
11
11
|
import './chunk-EABW6AJQ.js';
|
|
12
12
|
import './chunk-JKNYTNYD.js';
|
|
@@ -16,10 +16,10 @@ import './chunk-RKOTJQVG.js';
|
|
|
16
16
|
import './chunk-QZBXLLTV.js';
|
|
17
17
|
import './chunk-VNVZDWO3.js';
|
|
18
18
|
import './chunk-RA3O54FC.js';
|
|
19
|
-
import './chunk-
|
|
20
|
-
import './chunk-
|
|
21
|
-
import './chunk-
|
|
22
|
-
import './chunk-
|
|
19
|
+
import './chunk-ZODVSFI4.js';
|
|
20
|
+
import './chunk-ZI2ZVWKT.js';
|
|
21
|
+
import './chunk-2K3TCQHW.js';
|
|
22
|
+
import './chunk-JGD5TWQ2.js';
|
|
23
23
|
import './chunk-Z5GEFMRW.js';
|
|
24
24
|
|
|
25
25
|
createRequire(import.meta.url);
|