@olhapi/maestro 0.1.5-rc.14 → 0.1.5-rc.15
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/README.md
CHANGED
|
@@ -29,7 +29,7 @@ The docs site is organized around the same operator flow the product uses:
|
|
|
29
29
|
|
|
30
30
|
### npm
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Current public npm install on supported platforms:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
npm install -g @olhapi/maestro
|
|
@@ -43,47 +43,19 @@ npm install -g @olhapi/maestro@next
|
|
|
43
43
|
|
|
44
44
|
The installed command name is still `maestro`.
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
launcher that runs Maestro from the published Docker image, so Docker is now a
|
|
48
|
-
first-party runtime requirement for normal CLI use.
|
|
46
|
+
Official npm builds currently cover:
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
| Platform | Arch | Notes |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| macOS | arm64 | native package |
|
|
51
|
+
| macOS | x64 | native package |
|
|
52
|
+
| Linux | x64 | glibc only |
|
|
53
|
+
| Linux | arm64 | glibc only |
|
|
54
|
+
| Windows | x64 | native package |
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
Linux npm packages currently target glibc only. Alpine and other musl-based distros should build from source or use Docker.
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
- the locally pinned image from `~/.maestro/launcher/runtime.json`
|
|
57
|
-
- the npm package version you installed
|
|
58
|
-
|
|
59
|
-
Pull and pin the latest runtime image explicitly:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
maestro self-update
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Pin a specific image version:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
maestro self-update --version 0.117.0
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Validate the local launcher install, Docker access, and runtime pin:
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
maestro doctor install
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Curl Installer
|
|
78
|
-
|
|
79
|
-
If you want the same launcher without npm, install it with the repository
|
|
80
|
-
script:
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
curl -fsSL https://raw.githubusercontent.com/olhapi/maestro/main/scripts/install_maestro.sh | sh
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Docker Runtime
|
|
58
|
+
### Docker
|
|
87
59
|
|
|
88
60
|
Published image:
|
|
89
61
|
|
|
@@ -105,8 +77,7 @@ docker run --rm -v ./repo:/repo -v ./data:/data ghcr.io/olhapi/maestro:latest ru
|
|
|
105
77
|
|
|
106
78
|
### Build From Source
|
|
107
79
|
|
|
108
|
-
For local development
|
|
109
|
-
not the right runtime:
|
|
80
|
+
For local development or unsupported platforms:
|
|
110
81
|
|
|
111
82
|
```bash
|
|
112
83
|
go build -o maestro ./cmd/maestro
|
|
@@ -118,7 +89,7 @@ development package for the standard `make build` / `make test` flow.
|
|
|
118
89
|
Local contributor Docker build:
|
|
119
90
|
|
|
120
91
|
```bash
|
|
121
|
-
docker build -t maestro-local
|
|
92
|
+
docker build -t maestro-local .
|
|
122
93
|
```
|
|
123
94
|
|
|
124
95
|
## Quick Start
|
|
@@ -161,12 +132,6 @@ When `--db` is omitted, Maestro uses `~/.maestro/maestro.db` by default. When `-
|
|
|
161
132
|
|
|
162
133
|
Running `maestro run` without `repo_path` starts the shared daemon for the current database. It does not infer the repo from your shell working directory.
|
|
163
134
|
|
|
164
|
-
Before Docker starts, `maestro run` performs a one-time preflight pass. When a
|
|
165
|
-
database file exists, the launcher reads the discovered workflow files, resolves
|
|
166
|
-
their `workspace.root` values, and mounts the repo and workspace directories up
|
|
167
|
-
front. If the database file does not exist yet, it skips discovery so fresh
|
|
168
|
-
bootstrap flows still work.
|
|
169
|
-
|
|
170
135
|
Issue images are stored next to the active database under `assets/images`. With the default database path, that means `~/.maestro/assets/images`. If you run with `--db /custom/path/maestro.db`, image assets move to `/custom/path/assets/images`.
|
|
171
136
|
|
|
172
137
|
The preview warning on `run` is intentional. Pass `--i-understand-that-this-will-be-running-without-the-usual-guardrails` only when unattended Codex execution is actually what you want.
|
|
@@ -417,10 +382,9 @@ Repo-managed Git hooks stay targeted:
|
|
|
417
382
|
- staged website changes run Astro checks and website tests
|
|
418
383
|
- staged workspace and hook changes run the full `pnpm verify` suite
|
|
419
384
|
- `pnpm verify` runs the JS lint/test/check/smoke flow, npm packaging unit test, and Go build/test/coverage/race gates
|
|
420
|
-
- `pnpm run verify:pre-push` adds
|
|
421
|
-
- `pnpm run verify:ci` is the lean GitHub Actions gate: web verification, launcher packaging tests, and `go test ./...`
|
|
385
|
+
- `pnpm run verify:pre-push` adds current-host npm packaging smoke, the shared retry stress test, and the full retry-safety harness on top of `pnpm verify`
|
|
422
386
|
- package-scoped root commands such as `pnpm run frontend:test` and `pnpm run website:build` now go through `turbo --filter=...` so they benefit from task caching too
|
|
423
|
-
- `pre-push` now runs `pnpm run verify:pre-push`,
|
|
387
|
+
- `pre-push` now runs `pnpm run verify:pre-push`, leaving GitHub Actions with the cross-platform packaging matrix and registry smoke coverage
|
|
424
388
|
|
|
425
389
|
## License
|
|
426
390
|
|
package/bin/maestro.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
process.stderr.write(`Maestro's npm launcher requires Node 24 or newer; found ${process.versions.node}\n`);
|
|
6
|
-
process.exit(1);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { main } = require("../lib/cli");
|
|
3
|
+
const { spawnSync } = require("node:child_process");
|
|
4
|
+
const { getExePath } = require("../lib/get-exe-path");
|
|
10
5
|
|
|
11
|
-
|
|
6
|
+
let exePath;
|
|
7
|
+
try {
|
|
8
|
+
exePath = getExePath();
|
|
9
|
+
} catch (error) {
|
|
12
10
|
const message = error instanceof Error ? error.message : String(error);
|
|
13
11
|
process.stderr.write(`${message}\n`);
|
|
14
12
|
process.exit(1);
|
|
15
|
-
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const result = spawnSync(exePath, process.argv.slice(2), { stdio: "inherit" });
|
|
16
|
+
if (result.error) {
|
|
17
|
+
process.stderr.write(`${result.error.message}\n`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
if (typeof result.status === "number") {
|
|
21
|
+
process.exit(result.status);
|
|
22
|
+
}
|
|
23
|
+
if (result.signal) {
|
|
24
|
+
process.stderr.write(`maestro terminated with signal ${result.signal}\n`);
|
|
25
|
+
}
|
|
26
|
+
process.exit(1);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const fs = require("node:fs");
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
|
|
4
|
+
const supportedTargets = Object.freeze({
|
|
5
|
+
"darwin:arm64": {
|
|
6
|
+
packageName: "@olhapi/maestro-darwin-arm64",
|
|
7
|
+
label: "darwin/arm64",
|
|
8
|
+
},
|
|
9
|
+
"darwin:x64": {
|
|
10
|
+
packageName: "@olhapi/maestro-darwin-x64",
|
|
11
|
+
label: "darwin/x64",
|
|
12
|
+
},
|
|
13
|
+
"linux:x64": {
|
|
14
|
+
packageName: "@olhapi/maestro-linux-x64-gnu",
|
|
15
|
+
label: "linux/x64 (glibc)",
|
|
16
|
+
},
|
|
17
|
+
"linux:arm64": {
|
|
18
|
+
packageName: "@olhapi/maestro-linux-arm64-gnu",
|
|
19
|
+
label: "linux/arm64 (glibc)",
|
|
20
|
+
},
|
|
21
|
+
"win32:x64": {
|
|
22
|
+
packageName: "@olhapi/maestro-win32-x64",
|
|
23
|
+
label: "win32/x64",
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function resolveTarget(platform, arch) {
|
|
28
|
+
return supportedTargets[`${platform}:${arch}`] ?? null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function supportedTargetSummary() {
|
|
32
|
+
return Object.values(supportedTargets)
|
|
33
|
+
.map((target) => target.label)
|
|
34
|
+
.join(", ");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readProcessReport() {
|
|
38
|
+
if (!process.report || typeof process.report.getReport !== "function") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return process.report.getReport();
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function hasGlibcRuntime(report) {
|
|
49
|
+
const version = report && report.header && report.header.glibcVersionRuntime;
|
|
50
|
+
return typeof version === "string" && version.trim() !== "";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildInstallError(platform, arch, expectedPackageName, report) {
|
|
54
|
+
const parts = [
|
|
55
|
+
`Maestro npm install supports ${supportedTargetSummary()}.`,
|
|
56
|
+
`Could not resolve a packaged binary for ${platform}/${arch}.`,
|
|
57
|
+
];
|
|
58
|
+
if (expectedPackageName) {
|
|
59
|
+
parts.push(`Expected package: ${expectedPackageName}.`);
|
|
60
|
+
}
|
|
61
|
+
if (platform === "linux") {
|
|
62
|
+
if (!hasGlibcRuntime(report)) {
|
|
63
|
+
parts.push("Linux npm packages currently target glibc only. Alpine and other musl-based distros should build from source or use Docker.");
|
|
64
|
+
} else {
|
|
65
|
+
parts.push("If your install is on glibc Linux, reinstalling can restore a missing optional dependency. Alpine and other musl-based distros should build from source or use Docker.");
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
parts.push("If your platform is unsupported, build from source or use Docker.");
|
|
69
|
+
}
|
|
70
|
+
return parts.join(" ");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function resolveExePath(options = {}) {
|
|
74
|
+
const platform = options.platform ?? process.platform;
|
|
75
|
+
const arch = options.arch ?? process.arch;
|
|
76
|
+
const pathModule = options.pathModule ?? path;
|
|
77
|
+
const resolvePackageJson =
|
|
78
|
+
options.resolvePackageJson ??
|
|
79
|
+
((packageName) => require.resolve(`${packageName}/package.json`));
|
|
80
|
+
const existsSync = options.existsSync ?? fs.existsSync;
|
|
81
|
+
const report = options.report ?? readProcessReport();
|
|
82
|
+
|
|
83
|
+
const target = resolveTarget(platform, arch);
|
|
84
|
+
if (!target) {
|
|
85
|
+
throw new Error(buildInstallError(platform, arch, null, report));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let packageJsonPath;
|
|
89
|
+
try {
|
|
90
|
+
packageJsonPath = resolvePackageJson(target.packageName);
|
|
91
|
+
} catch {
|
|
92
|
+
throw new Error(buildInstallError(platform, arch, target.packageName, report));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let exePath = pathModule.join(
|
|
96
|
+
pathModule.dirname(packageJsonPath),
|
|
97
|
+
"lib",
|
|
98
|
+
platform === "win32" ? "maestro.exe" : "maestro",
|
|
99
|
+
);
|
|
100
|
+
if (platform === "win32" && exePath.length >= 248 && !exePath.startsWith("\\\\?\\")) {
|
|
101
|
+
exePath = `\\\\?\\${exePath}`;
|
|
102
|
+
}
|
|
103
|
+
if (!existsSync(exePath)) {
|
|
104
|
+
throw new Error(`Executable not found in ${target.packageName}: ${exePath}`);
|
|
105
|
+
}
|
|
106
|
+
return exePath;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getExePath() {
|
|
110
|
+
return resolveExePath();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
buildInstallError,
|
|
115
|
+
getExePath,
|
|
116
|
+
resolveExePath,
|
|
117
|
+
resolveTarget,
|
|
118
|
+
};
|
package/package.json
CHANGED
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olhapi/maestro",
|
|
3
|
-
"version": "0.1.5-rc.
|
|
4
|
-
"description": "Maestro
|
|
3
|
+
"version": "0.1.5-rc.15",
|
|
4
|
+
"description": "Maestro CLI packaged for global npm installation",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=24"
|
|
8
|
-
},
|
|
9
6
|
"bin": {
|
|
10
|
-
"maestro": "bin/maestro"
|
|
7
|
+
"maestro": "bin/maestro.js"
|
|
11
8
|
},
|
|
12
9
|
"files": [
|
|
13
|
-
"bin/maestro",
|
|
14
|
-
"bin/maestro.cmd",
|
|
15
|
-
"bin/maestro.ps1",
|
|
16
10
|
"bin/maestro.js",
|
|
17
|
-
"lib/
|
|
18
|
-
"lib/cli.js",
|
|
19
|
-
"lib/docker-plan.js",
|
|
20
|
-
"lib/install-skills.js",
|
|
21
|
-
"lib/runtime-state.js",
|
|
22
|
-
"share/skills/maestro",
|
|
11
|
+
"lib/get-exe-path.js",
|
|
23
12
|
"LICENSE",
|
|
24
13
|
"README.md"
|
|
25
14
|
],
|
|
15
|
+
"optionalDependencies": {
|
|
16
|
+
"@olhapi/maestro-darwin-arm64": "0.1.5-rc.15",
|
|
17
|
+
"@olhapi/maestro-darwin-x64": "0.1.5-rc.15",
|
|
18
|
+
"@olhapi/maestro-linux-x64-gnu": "0.1.5-rc.15",
|
|
19
|
+
"@olhapi/maestro-linux-arm64-gnu": "0.1.5-rc.15",
|
|
20
|
+
"@olhapi/maestro-win32-x64": "0.1.5-rc.15"
|
|
21
|
+
},
|
|
26
22
|
"repository": {
|
|
27
23
|
"type": "git",
|
|
28
24
|
"url": "git+https://github.com/olhapi/maestro.git"
|
package/bin/maestro
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env sh
|
|
2
|
-
|
|
3
|
-
set -eu
|
|
4
|
-
|
|
5
|
-
SCRIPT_PATH="$0"
|
|
6
|
-
while [ -L "$SCRIPT_PATH" ]; do
|
|
7
|
-
LINK_TARGET=$(readlink "$SCRIPT_PATH")
|
|
8
|
-
case "$LINK_TARGET" in
|
|
9
|
-
/*) SCRIPT_PATH="$LINK_TARGET" ;;
|
|
10
|
-
*) SCRIPT_PATH=$(dirname "$SCRIPT_PATH")/$LINK_TARGET ;;
|
|
11
|
-
esac
|
|
12
|
-
done
|
|
13
|
-
|
|
14
|
-
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$SCRIPT_PATH")" && pwd)
|
|
15
|
-
NODE_BIN="${MAESTRO_NODE_BIN:-node}"
|
|
16
|
-
exec "$NODE_BIN" "$SCRIPT_DIR/maestro.js" "$@"
|
package/bin/maestro.cmd
DELETED
package/bin/maestro.ps1
DELETED
package/lib/browser.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const { spawn } = require("node:child_process");
|
|
2
|
-
|
|
3
|
-
const DEFAULT_BROWSER_TIMEOUT_MS = 3000;
|
|
4
|
-
const DEFAULT_BROWSER_POLL_INTERVAL_MS = 50;
|
|
5
|
-
|
|
6
|
-
function terminalsInteractive(streams = process) {
|
|
7
|
-
return Boolean(streams.stdout && streams.stdout.isTTY && streams.stderr && streams.stderr.isTTY);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function browserOpenDisabled(env = process.env) {
|
|
11
|
-
const value = env && env.MAESTRO_DISABLE_BROWSER_OPEN;
|
|
12
|
-
return typeof value === "string" && value.trim() !== "";
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function browserCommandFor(platform, url) {
|
|
16
|
-
switch (platform) {
|
|
17
|
-
case "darwin":
|
|
18
|
-
return ["open", [url]];
|
|
19
|
-
case "linux":
|
|
20
|
-
case "freebsd":
|
|
21
|
-
case "openbsd":
|
|
22
|
-
case "netbsd":
|
|
23
|
-
return ["xdg-open", [url]];
|
|
24
|
-
case "win32":
|
|
25
|
-
return ["rundll32", ["url.dll,FileProtocolHandler", url]];
|
|
26
|
-
default:
|
|
27
|
-
throw new Error(`unsupported platform ${platform}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function waitForHealthy(url, options = {}) {
|
|
32
|
-
const timeoutMs = options.timeoutMs || DEFAULT_BROWSER_TIMEOUT_MS;
|
|
33
|
-
const pollIntervalMs = options.pollIntervalMs || DEFAULT_BROWSER_POLL_INTERVAL_MS;
|
|
34
|
-
const fetchImpl = options.fetchImpl || fetch;
|
|
35
|
-
const deadline = Date.now() + timeoutMs;
|
|
36
|
-
let lastError = null;
|
|
37
|
-
|
|
38
|
-
while (Date.now() < deadline) {
|
|
39
|
-
try {
|
|
40
|
-
const response = await fetchImpl(url);
|
|
41
|
-
if (response.ok) {
|
|
42
|
-
await response.arrayBuffer();
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
lastError = new Error(`health returned ${response.status}`);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
lastError = error;
|
|
48
|
-
}
|
|
49
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (lastError) {
|
|
53
|
-
throw lastError;
|
|
54
|
-
}
|
|
55
|
-
throw new Error(`timed out waiting for ${url}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function openDashboardWhenReady(baseURL, options = {}) {
|
|
59
|
-
if (!baseURL || browserOpenDisabled(options.env || process.env) || !terminalsInteractive(options.streams || process)) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const normalizedBaseURL = String(baseURL).replace(/\/+$/, "");
|
|
64
|
-
await waitForHealthy(`${normalizedBaseURL}/health`, options);
|
|
65
|
-
const [command, args] = browserCommandFor(options.platform || process.platform, normalizedBaseURL);
|
|
66
|
-
const child = spawn(command, args, {
|
|
67
|
-
detached: true,
|
|
68
|
-
stdio: "ignore",
|
|
69
|
-
});
|
|
70
|
-
child.unref();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
module.exports = {
|
|
74
|
-
browserOpenDisabled,
|
|
75
|
-
browserCommandFor,
|
|
76
|
-
openDashboardWhenReady,
|
|
77
|
-
terminalsInteractive,
|
|
78
|
-
waitForHealthy,
|
|
79
|
-
};
|