@olhapi/maestro 0.1.5-rc.14 → 0.1.5-rc.16
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/README.md +15 -51
- package/bin/maestro.js +20 -9
- package/lib/get-exe-path.js +118 -0
- package/package.json +11 -15
- package/bin/maestro +0 -16
- package/bin/maestro.cmd +0 -8
- package/bin/maestro.ps1 +0 -4
- package/lib/browser.js +0 -79
- package/lib/cli.js +0 -306
- package/lib/docker-plan.js +0 -941
- package/lib/install-skills.js +0 -110
- package/lib/runtime-state.js +0 -82
- package/share/skills/maestro/SKILL.md +0 -38
- package/share/skills/maestro/references/operations.md +0 -21
- package/share/skills/maestro/references/project-work.md +0 -44
- package/share/skills/maestro/references/readiness.md +0 -18
- package/share/skills/maestro/references/setup.md +0 -45
package/lib/cli.js
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
const fs = require("node:fs");
|
|
2
|
-
const os = require("node:os");
|
|
3
|
-
const path = require("node:path");
|
|
4
|
-
const { spawn, spawnSync } = require("node:child_process");
|
|
5
|
-
|
|
6
|
-
const { browserOpenDisabled, openDashboardWhenReady } = require("./browser");
|
|
7
|
-
const { planDockerInvocation } = require("./docker-plan");
|
|
8
|
-
const { installBundledSkills } = require("./install-skills");
|
|
9
|
-
const {
|
|
10
|
-
DEFAULT_IMAGE_REPOSITORY,
|
|
11
|
-
imageRefForVersion,
|
|
12
|
-
resolveImageRef,
|
|
13
|
-
sanitizeVersion,
|
|
14
|
-
writeRuntimeState,
|
|
15
|
-
} = require("./runtime-state");
|
|
16
|
-
|
|
17
|
-
const MINIMUM_LAUNCHER_NODE_MAJOR = 24;
|
|
18
|
-
|
|
19
|
-
function packageVersion() {
|
|
20
|
-
const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
21
|
-
return packageJSON.version;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function ensureSupportedNodeVersion(nodeVersion = process.versions.node) {
|
|
25
|
-
const major = Number.parseInt(String(nodeVersion || "").split(".")[0], 10);
|
|
26
|
-
if (!Number.isInteger(major) || major < MINIMUM_LAUNCHER_NODE_MAJOR) {
|
|
27
|
-
throw new Error(`Maestro's npm launcher requires Node ${MINIMUM_LAUNCHER_NODE_MAJOR} or newer; found ${nodeVersion}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function main(argv = process.argv.slice(2), options = {}) {
|
|
32
|
-
ensureSupportedNodeVersion();
|
|
33
|
-
const deps = createDeps(options);
|
|
34
|
-
if (argv[0] === "self-update") {
|
|
35
|
-
return handleSelfUpdate(argv.slice(1), deps);
|
|
36
|
-
}
|
|
37
|
-
if (argv[0] === "doctor" && argv[1] === "install") {
|
|
38
|
-
return handleDoctorInstall(argv.slice(2), deps);
|
|
39
|
-
}
|
|
40
|
-
if (argv[0] === "install" && argv.includes("--skills") && !argv.includes("--help") && !argv.includes("-h")) {
|
|
41
|
-
return handleInstallSkills(deps);
|
|
42
|
-
}
|
|
43
|
-
return runContainerized(argv, deps);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function createDeps(options) {
|
|
47
|
-
return {
|
|
48
|
-
cwd: options.cwd || process.cwd(),
|
|
49
|
-
env: options.env || process.env,
|
|
50
|
-
fs: options.fs || fs,
|
|
51
|
-
gid: options.gid ?? (typeof process.getgid === "function" ? process.getgid() : undefined),
|
|
52
|
-
baseDir: options.baseDir || path.join(__dirname, ".."),
|
|
53
|
-
homeDir: options.homeDir || os.homedir(),
|
|
54
|
-
packageVersion: options.packageVersion || packageVersion(),
|
|
55
|
-
platform: options.platform || process.platform,
|
|
56
|
-
spawn: options.spawn || spawn,
|
|
57
|
-
spawnSync: options.spawnSync || spawnSync,
|
|
58
|
-
stdout: options.stdout || process.stdout,
|
|
59
|
-
stderr: options.stderr || process.stderr,
|
|
60
|
-
uid: options.uid ?? (typeof process.getuid === "function" ? process.getuid() : undefined),
|
|
61
|
-
exit: options.exit || ((code) => process.exit(code)),
|
|
62
|
-
openDashboardWhenReady: options.openDashboardWhenReady || openDashboardWhenReady,
|
|
63
|
-
planDockerInvocation: options.planDockerInvocation || planDockerInvocation,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function dockerBinary(env) {
|
|
68
|
-
if (typeof env.MAESTRO_DOCKER_BIN === "string" && env.MAESTRO_DOCKER_BIN.trim() !== "") {
|
|
69
|
-
return env.MAESTRO_DOCKER_BIN.trim();
|
|
70
|
-
}
|
|
71
|
-
return "docker";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ensureDockerAvailable(deps) {
|
|
75
|
-
const result = deps.spawnSync(dockerBinary(deps.env), ["version", "--format", "{{.Server.Version}}"], {
|
|
76
|
-
encoding: "utf8",
|
|
77
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
78
|
-
});
|
|
79
|
-
if (result.error) {
|
|
80
|
-
throw new Error(`failed to start docker: ${result.error.message}`);
|
|
81
|
-
}
|
|
82
|
-
if (result.status !== 0) {
|
|
83
|
-
const stderr = String(result.stderr || "").trim();
|
|
84
|
-
throw new Error(stderr || "docker is required to run the Maestro launcher");
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function ensureImageAvailable(imageRef, deps) {
|
|
89
|
-
const inspect = deps.spawnSync(dockerBinary(deps.env), ["image", "inspect", imageRef], {
|
|
90
|
-
encoding: "utf8",
|
|
91
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
92
|
-
});
|
|
93
|
-
if (inspect.error) {
|
|
94
|
-
throw new Error(`failed to inspect docker image ${imageRef}: ${inspect.error.message}`);
|
|
95
|
-
}
|
|
96
|
-
if (inspect.status === 0) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const pull = deps.spawnSync(dockerBinary(deps.env), ["pull", imageRef], {
|
|
101
|
-
encoding: "utf8",
|
|
102
|
-
stdio: "inherit",
|
|
103
|
-
});
|
|
104
|
-
if (pull.error) {
|
|
105
|
-
throw new Error(`failed to pull docker image ${imageRef}: ${pull.error.message}`);
|
|
106
|
-
}
|
|
107
|
-
if (pull.status !== 0) {
|
|
108
|
-
throw new Error(`docker pull ${imageRef} failed`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function runContainerized(argv, deps) {
|
|
113
|
-
ensureDockerAvailable(deps);
|
|
114
|
-
const imageRef = resolveImageRef({
|
|
115
|
-
env: deps.env,
|
|
116
|
-
homeDir: deps.homeDir,
|
|
117
|
-
packageVersion: deps.packageVersion,
|
|
118
|
-
});
|
|
119
|
-
ensureImageAvailable(imageRef, deps);
|
|
120
|
-
|
|
121
|
-
const plan = await deps.planDockerInvocation(argv, {
|
|
122
|
-
cwd: deps.cwd,
|
|
123
|
-
env: deps.env,
|
|
124
|
-
fs: deps.fs,
|
|
125
|
-
gid: deps.gid,
|
|
126
|
-
homeDir: deps.homeDir,
|
|
127
|
-
imageRef,
|
|
128
|
-
platform: deps.platform,
|
|
129
|
-
uid: deps.uid,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const child = deps.spawn(dockerBinary(deps.env), plan.dockerArgs, {
|
|
133
|
-
cwd: deps.cwd,
|
|
134
|
-
stdio: "inherit",
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
let browserPromise = Promise.resolve();
|
|
138
|
-
if (plan.commandPath[0] === "run" && plan.hostBaseURL && !browserOpenDisabled(deps.env)) {
|
|
139
|
-
browserPromise = deps.openDashboardWhenReady(plan.hostBaseURL, {
|
|
140
|
-
env: deps.env,
|
|
141
|
-
streams: { stdout: deps.stdout, stderr: deps.stderr },
|
|
142
|
-
platform: deps.platform,
|
|
143
|
-
}).catch(() => {});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const signalHandlers = [];
|
|
147
|
-
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
148
|
-
const handler = () => {
|
|
149
|
-
if (!child.killed) {
|
|
150
|
-
child.kill(signal);
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
process.on(signal, handler);
|
|
154
|
-
signalHandlers.push([signal, handler]);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const exitCode = await new Promise((resolve, reject) => {
|
|
158
|
-
child.on("error", reject);
|
|
159
|
-
child.on("exit", (code, signal) => {
|
|
160
|
-
if (signal) {
|
|
161
|
-
deps.stderr.write(`maestro terminated with signal ${signal}\n`);
|
|
162
|
-
resolve(1);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
resolve(typeof code === "number" ? code : 1);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
for (const [signal, handler] of signalHandlers) {
|
|
170
|
-
process.off(signal, handler);
|
|
171
|
-
}
|
|
172
|
-
await browserPromise;
|
|
173
|
-
deps.exit(exitCode);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function printInstalledTargets(targets, stdout) {
|
|
177
|
-
stdout.write("Installed Maestro skill bundle:\n");
|
|
178
|
-
for (const target of targets) {
|
|
179
|
-
stdout.write(` - ${target}\n`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function handleInstallSkills(deps) {
|
|
184
|
-
const targets = installBundledSkills({
|
|
185
|
-
baseDir: deps.baseDir,
|
|
186
|
-
fs: deps.fs,
|
|
187
|
-
homeDir: deps.homeDir,
|
|
188
|
-
});
|
|
189
|
-
printInstalledTargets(targets, deps.stdout);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function parseSelfUpdateArgs(argv) {
|
|
193
|
-
let version = "";
|
|
194
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
195
|
-
const token = argv[i];
|
|
196
|
-
if (token === "--help" || token === "-h") {
|
|
197
|
-
return { help: true, version: "" };
|
|
198
|
-
}
|
|
199
|
-
if (token === "--version" && typeof argv[i + 1] === "string") {
|
|
200
|
-
version = argv[i + 1];
|
|
201
|
-
i += 1;
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
if (token.startsWith("--version=")) {
|
|
205
|
-
version = token.slice("--version=".length);
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
throw new Error(`unknown argument for self-update: ${token}`);
|
|
209
|
-
}
|
|
210
|
-
return { help: false, version };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function handleSelfUpdate(argv, deps) {
|
|
214
|
-
const parsed = parseSelfUpdateArgs(argv);
|
|
215
|
-
if (parsed.help) {
|
|
216
|
-
deps.stdout.write("Usage: maestro self-update [--version <tag>]\n");
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
ensureDockerAvailable(deps);
|
|
221
|
-
const selectedRef = parsed.version
|
|
222
|
-
? imageRefForVersion(parsed.version, DEFAULT_IMAGE_REPOSITORY)
|
|
223
|
-
: `${DEFAULT_IMAGE_REPOSITORY}:latest`;
|
|
224
|
-
const pull = deps.spawnSync(dockerBinary(deps.env), ["pull", selectedRef], {
|
|
225
|
-
encoding: "utf8",
|
|
226
|
-
stdio: "inherit",
|
|
227
|
-
});
|
|
228
|
-
if (pull.error) {
|
|
229
|
-
throw new Error(`failed to pull docker image ${selectedRef}: ${pull.error.message}`);
|
|
230
|
-
}
|
|
231
|
-
if (pull.status !== 0) {
|
|
232
|
-
throw new Error(`docker pull ${selectedRef} failed`);
|
|
233
|
-
}
|
|
234
|
-
writeRuntimeState(selectedRef, {
|
|
235
|
-
fs: deps.fs,
|
|
236
|
-
homeDir: deps.homeDir,
|
|
237
|
-
});
|
|
238
|
-
deps.stdout.write(`Pinned Maestro runtime image to ${selectedRef}\n`);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function handleDoctorInstall(argv, deps) {
|
|
242
|
-
if (argv.some((arg) => arg === "--help" || arg === "-h")) {
|
|
243
|
-
deps.stdout.write("Usage: maestro doctor install [--json]\n");
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
const jsonMode = argv.includes("--json");
|
|
247
|
-
const checks = [];
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
ensureDockerAvailable(deps);
|
|
251
|
-
checks.push({ name: "docker", status: "ok" });
|
|
252
|
-
} catch (error) {
|
|
253
|
-
checks.push({ name: "docker", status: "fail", detail: error.message });
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const homeDir = deps.homeDir;
|
|
257
|
-
const runtimeImage = resolveImageRef({
|
|
258
|
-
env: deps.env,
|
|
259
|
-
homeDir,
|
|
260
|
-
packageVersion: deps.packageVersion,
|
|
261
|
-
});
|
|
262
|
-
checks.push({ name: "runtime_image", status: "ok", detail: runtimeImage });
|
|
263
|
-
|
|
264
|
-
const codexConfigDir = path.join(homeDir, ".codex");
|
|
265
|
-
checks.push({
|
|
266
|
-
name: "codex_config",
|
|
267
|
-
status: deps.fs.existsSync(codexConfigDir) ? "ok" : "warn",
|
|
268
|
-
detail: codexConfigDir,
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
const daemonRegistryDir = path.join(homeDir, ".maestro", "launcher", "daemons");
|
|
272
|
-
checks.push({
|
|
273
|
-
name: "daemon_registry",
|
|
274
|
-
status: "ok",
|
|
275
|
-
detail: daemonRegistryDir,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
if (jsonMode) {
|
|
279
|
-
deps.stdout.write(`${JSON.stringify({ checks }, null, 2)}\n`);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
deps.stdout.write("INSTALL DOCTOR\n");
|
|
284
|
-
for (const check of checks) {
|
|
285
|
-
deps.stdout.write(`${check.name}:\t${check.status}`);
|
|
286
|
-
if (check.detail) {
|
|
287
|
-
deps.stdout.write(`\t${check.detail}`);
|
|
288
|
-
}
|
|
289
|
-
deps.stdout.write("\n");
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
module.exports = {
|
|
294
|
-
createDeps,
|
|
295
|
-
dockerBinary,
|
|
296
|
-
ensureDockerAvailable,
|
|
297
|
-
ensureImageAvailable,
|
|
298
|
-
ensureSupportedNodeVersion,
|
|
299
|
-
handleDoctorInstall,
|
|
300
|
-
handleInstallSkills,
|
|
301
|
-
handleSelfUpdate,
|
|
302
|
-
main,
|
|
303
|
-
parseSelfUpdateArgs,
|
|
304
|
-
printInstalledTargets,
|
|
305
|
-
runContainerized,
|
|
306
|
-
};
|