executor 2.0.0-beta.4 → 2.0.0-beta.40
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 +101 -28
- package/bin/executor +2 -0
- package/bin/package.json +1 -0
- package/bin.mjs +243 -13
- package/package.json +11 -9
package/README.md
CHANGED
|
@@ -1,27 +1,62 @@
|
|
|
1
1
|
# Executor 2 beta
|
|
2
2
|
|
|
3
|
-
Install with `npm i -g executor@beta
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
Install with npm, `npm i -g executor@beta`, on Node 14.18 or newer. Without Node, run `curl -fsSL https://executor.sh/docs/install.sh | sh`
|
|
4
|
+
on macOS or Linux, or `irm https://executor.sh/docs/install.ps1 | iex` in
|
|
5
|
+
PowerShell on Windows. Each release also attaches its archives and `SHA256SUMS`.
|
|
6
|
+
Run `executor` to start the background Executor, or join the one already
|
|
7
|
+
running, and open the dashboard. The background Executor keeps running until
|
|
8
|
+
`executor service stop`; nothing starts it with the OS. `executor` checks npm
|
|
9
|
+
daily for a newer release and suggests `executor upgrade`; set
|
|
10
|
+
`EXECUTOR_NO_UPDATE_CHECK=1` to skip it. Use `executor service start` to start it
|
|
11
|
+
without a browser, `executor serve` to run it in the foreground, and
|
|
12
|
+
`executor pair` to get a new browser connection link.
|
|
13
|
+
`executor upgrade` installs the newest release on your channel the way Executor
|
|
14
|
+
was installed: an install-script copy downloads and checks the release and keeps
|
|
15
|
+
the previous version for `executor upgrade --rollback`; an npm, pnpm, Bun or
|
|
16
|
+
Yarn install runs its package manager. Either way it stops the background
|
|
17
|
+
Executor before replacing its files and starts it again on the new version; a
|
|
18
|
+
release from before the background service, which a rollback can return to, has
|
|
19
|
+
no `executor service`, so run `executor serve` there instead.
|
|
20
|
+
|
|
21
|
+
Executor is one executable, built with Bun, with the files it runs or reads
|
|
22
|
+
beside it: the dashboard, the app framework and compiler references, workerd,
|
|
23
|
+
Git, the native credential-store binding and the Motel collector. It needs no
|
|
24
|
+
source checkout, Node, Bun or 1Password on the user machine. The `executor` npm
|
|
25
|
+
package is a launcher. The first time a version starts, it downloads that
|
|
26
|
+
release's archive for the platform, for macOS (Apple Silicon and Intel), Linux
|
|
27
|
+
(arm64 and x64, glibc) or Windows (x64), from the public GitHub release, checks it
|
|
28
|
+
against the SHA-256 the package records, and keeps it in
|
|
29
|
+
`~/.executor/v2/launcher/<version>` with the version before it. The same archive
|
|
30
|
+
is the release download the install scripts and Homebrew use.
|
|
31
|
+
`EXECUTOR_DOWNLOAD_URL` names a mirror of the releases for all of them.
|
|
11
32
|
|
|
12
33
|
Beta uses `~/.executor/v2/cli` for its data. This path stays the same at the
|
|
13
|
-
stable release. It is separate from Executor 1 data.
|
|
14
|
-
|
|
15
|
-
`EXECUTOR_PORT`
|
|
34
|
+
stable release. It is separate from Executor 1 data. One server runs per data
|
|
35
|
+
directory; its `.server.lock` stops a second. `EXECUTOR_DATA_DIR` selects another
|
|
36
|
+
directory, and `EXECUTOR_PORT` or `executor service set port` changes the default
|
|
37
|
+
port of 4312. The desktop app uses the same directory and background Executor.
|
|
38
|
+
Its first launch moves the data of a desktop release from before the background
|
|
39
|
+
service into that directory, once. CLI data already there moves to
|
|
40
|
+
`~/.executor/v2/backups/cli-data-<time>`, which the desktop app names; nothing
|
|
41
|
+
is merged or deleted. The CLI's settings carry over, except its port and the
|
|
42
|
+
`env` variables that belong to its data.
|
|
16
43
|
|
|
17
44
|
On first launch, Executor saves its API and encryption keys in the OS credential
|
|
18
45
|
store: macOS Keychain, Windows Credential Manager, or Linux Secret Service.
|
|
19
|
-
Linux
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
46
|
+
Linux uses a persistent Secret Service such as GNOME Keyring. If there is no
|
|
47
|
+
store on a directory's first start, the keys are saved to `keys.json` in the
|
|
48
|
+
data directory (mode `0600`) and the path is printed to stderr. If a store exists
|
|
49
|
+
but access is denied or it is locked, startup stops without a key file and the
|
|
50
|
+
next start asks again. Over SSH, unlock the store first, or set
|
|
51
|
+
`EXECUTOR_KEY_STORAGE=file` before a directory's first start to use `keys.json`
|
|
52
|
+
(`os` requires the store instead). A directory that already uses the OS store stops when it
|
|
53
|
+
is locked or unavailable. A missing or
|
|
54
|
+
invalid credential or key file stops startup; existing installations never
|
|
55
|
+
receive replacement keys.
|
|
56
|
+
|
|
57
|
+
Back up the data directory, including `installation.json` and any `keys.json`,
|
|
58
|
+
and the matching OS credential (`com.usefulsoftware.executor.v2`, account ID
|
|
59
|
+
from that file) when the directory uses one.
|
|
25
60
|
Copying only the data directory to another machine is not enough to recover it.
|
|
26
61
|
For a new headless install, supply both `EXECUTOR_API_KEY` (32+ characters) and
|
|
27
62
|
`EXECUTOR_ENCRYPTION_KEY` (64 hexadecimal characters) through a secret manager.
|
|
@@ -38,29 +73,67 @@ version publishes to `latest` only through an explicitly selected stable release
|
|
|
38
73
|
|
|
39
74
|
```sh
|
|
40
75
|
bun install --frozen-lockfile
|
|
41
|
-
bun run release:cli
|
|
76
|
+
EXECUTOR_BUN_RUNTIME=/path/to/locked-down/bun bun run release:cli
|
|
42
77
|
bun run release:wrapper
|
|
43
78
|
```
|
|
44
79
|
|
|
45
80
|
Native artifacts are under `.local/releases/<version>-<platform>-<arch>/`.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
81
|
+
`release:cli` bundles the runtime twice. `package/` holds the JavaScript runtime
|
|
82
|
+
the desktop app runs with its own Node. `standalone/` holds the release install:
|
|
83
|
+
the `executor` executable (`bun build --compile`) and the files beside it, which
|
|
84
|
+
`executor-<version>-<platform>-<arch>.tgz` packs as the platform's release
|
|
85
|
+
archive. The executable takes `runtime/cli.mjs` in its install directory as
|
|
86
|
+
every module's location, so resources, `require` and `import.meta.resolve` find
|
|
87
|
+
the same files beside it wherever the archive is unpacked, through any launcher
|
|
88
|
+
symlink. Packages that must stay on disk load from
|
|
89
|
+
`runtime/node_modules`; Git is in `runtime/git`.
|
|
90
|
+
The npm launcher is under `.local/releases/<version>/wrapper/`. Its
|
|
91
|
+
package.json records the SHA-256 of each platform archive found under
|
|
92
|
+
`.local/releases/<version>-<platform>-<arch>/`, or under the directory
|
|
93
|
+
`release:wrapper` is given; publishing requires all five. The runtimes are never
|
|
94
|
+
published to npm. Through 2.0.0-beta.36 each was published as a version of the
|
|
95
|
+
`executor` package, such as `2.0.0-beta.36-win32-x64`, which semver ranks above
|
|
96
|
+
the launcher, so a range update such as `bun update -g` replaced the launcher
|
|
97
|
+
with a runtime. Those versions are deprecated so package managers skip them.
|
|
98
|
+
These build commands do not publish anything.
|
|
99
|
+
The app compiler and framework are prepared for workerd at build time, so the
|
|
100
|
+
executable downloads nothing more. Most of each archive is the executable,
|
|
101
|
+
workerd and the bundled Git, which keeps only what the runtime runs (`keptGit`
|
|
102
|
+
in `runtime-bundle.ts`).
|
|
53
103
|
External source maps stay in the separate CI artifact for release diagnostics.
|
|
54
104
|
|
|
105
|
+
Stock Bun lets any local process run its own code inside a compiled executable,
|
|
106
|
+
through `BUN_OPTIONS`, `BUN_BE_BUN`, `BUN_INSPECT` and similar variables that
|
|
107
|
+
Bun reads before the executable's first line. The release executable is built
|
|
108
|
+
on a Bun runtime patched to ignore them, from
|
|
109
|
+
[`bun-runtime/`](bun-runtime/README.md). `EXECUTOR_BUN_RUNTIME` names it; CI and
|
|
110
|
+
publishing builds refuse stock Bun, and a local build without it prints that it
|
|
111
|
+
is a development build. The release workflow fetches the runtime from the
|
|
112
|
+
`bun-runtime-<bun version>-<patch hash>` release, building it first when the
|
|
113
|
+
patch changed.
|
|
114
|
+
|
|
115
|
+
The install scripts are `apps/docs/public/install.sh` and `install.ps1`, served
|
|
116
|
+
at `https://executor.sh/docs/`. The publish job writes the Homebrew formula
|
|
117
|
+
(`scripts/releases/homebrew.ts`) to the tap named by the `HOMEBREW_TAP`
|
|
118
|
+
repository variable once it is set.
|
|
119
|
+
|
|
55
120
|
The prepared packages retain dependency licenses. Public releases also include
|
|
56
121
|
checksum-pinned source archives for the bundled Git distribution.
|
|
57
122
|
|
|
58
123
|
## macOS signing
|
|
59
124
|
|
|
60
|
-
`node scripts/releases/desktop.ts <version>`
|
|
61
|
-
development build: Gatekeeper rejects it
|
|
125
|
+
`node scripts/releases/desktop.ts <version>` and `node scripts/releases/package.ts`
|
|
126
|
+
are unsigned by default, which is a development build: Gatekeeper rejects it
|
|
127
|
+
until someone overrides it by hand.
|
|
62
128
|
Add `--sign` to sign with a Developer ID Application identity, or `--notarize`
|
|
63
|
-
to sign and submit the result to Apple.
|
|
129
|
+
to sign and submit the result to Apple. A publishing build of the CLI on macOS
|
|
130
|
+
(`EXECUTOR_RELEASE_PUBLISH=true`) fails unless it notarizes. For the CLI, every
|
|
131
|
+
Mach-O file in the install is signed with the hardened runtime, the executable
|
|
132
|
+
last as `com.usefulsoftware.executor.v2.cli` with
|
|
133
|
+
`entitlements.standalone.plist`: JIT for Bun and workerd, and library validation
|
|
134
|
+
left on, so it loads only libraries signed with the same identity. The whole
|
|
135
|
+
install is notarized as one archive; a bare executable cannot hold a stapled
|
|
136
|
+
ticket, so Gatekeeper checks it online. Both modes keep electron-builder's
|
|
64
137
|
identity auto-discovery off, so a build never picks up a stray keychain identity.
|
|
65
138
|
|
|
66
139
|
Signing accepts these environment variables and keeps plaintext keys off ordinary disk:
|
package/bin/executor
ADDED
package/bin/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
package/bin.mjs
CHANGED
|
@@ -1,15 +1,245 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
// The `executor` npm package's command. The package holds no runtime: on first use of a version it
|
|
3
|
+
// downloads that release's archive for this platform from the public GitHub release, checks it
|
|
4
|
+
// against the SHA-256 this package's package.json records, and unpacks it into
|
|
5
|
+
// ~/.executor/v2/launcher/<version>. It then starts the Executor executable there, passes signals
|
|
6
|
+
// on, and exits as it exits.
|
|
7
|
+
//
|
|
8
|
+
// npm, Bun, pnpm and Yarn resolve `executor` alone, so an update can only ever land on another
|
|
9
|
+
// launcher; the running executable lives outside node_modules, so an update never has to replace a
|
|
10
|
+
// file in use. The executable carries its own runtime, so this file uses only what every Node since
|
|
11
|
+
// 14 has.
|
|
12
|
+
import { spawn, spawnSync } from "child_process";
|
|
13
|
+
import { createHash, randomBytes } from "crypto";
|
|
14
|
+
import {
|
|
15
|
+
createWriteStream,
|
|
16
|
+
existsSync,
|
|
17
|
+
mkdirSync,
|
|
18
|
+
readdirSync,
|
|
19
|
+
renameSync,
|
|
20
|
+
rmSync,
|
|
21
|
+
statSync,
|
|
22
|
+
utimesSync,
|
|
23
|
+
} from "fs";
|
|
24
|
+
import { request as httpRequest } from "http";
|
|
25
|
+
import { request as httpsRequest } from "https";
|
|
26
|
+
import { createRequire } from "module";
|
|
27
|
+
import { homedir } from "os";
|
|
28
|
+
import { join } from "path";
|
|
29
|
+
import { fileURLToPath } from "url";
|
|
30
|
+
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const manifest = require("./package.json");
|
|
33
|
+
const version = manifest.version;
|
|
34
|
+
const target = process.platform + "-" + process.arch;
|
|
35
|
+
const digest = (manifest.runtimes || {})[target];
|
|
36
|
+
const channel = version.indexOf("-beta.") === -1 ? "" : "@beta";
|
|
37
|
+
const executableName = process.platform === "win32" ? "executor.exe" : "executor";
|
|
38
|
+
const archive = "executor-" + version + "-" + target + ".tgz";
|
|
39
|
+
// The same mirror setting the install scripts and `executor upgrade` read.
|
|
40
|
+
const downloads = (
|
|
41
|
+
process.env.EXECUTOR_DOWNLOAD_URL ||
|
|
42
|
+
"https://github.com/UsefulSoftwareCo/executor/releases/download"
|
|
43
|
+
).replace(/\/+$/, "");
|
|
44
|
+
const url = downloads + "/executor@" + version + "/" + archive;
|
|
45
|
+
const root = join(homedir(), ".executor", "v2", "launcher");
|
|
46
|
+
const installed = join(root, version);
|
|
47
|
+
const executable = join(installed, executableName);
|
|
48
|
+
|
|
49
|
+
const fail = (lines) => {
|
|
50
|
+
for (const line of lines) console.error(line);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (typeof digest !== "string")
|
|
55
|
+
fail(["Executor does not support " + process.platform + "/" + process.arch + "."]);
|
|
56
|
+
|
|
57
|
+
/** GET `address`, following redirects; resolves to the response of the final location. */
|
|
58
|
+
const get = (address, redirects) =>
|
|
59
|
+
new Promise((resolve, reject) => {
|
|
60
|
+
const request = (address.startsWith("http:") ? httpRequest : httpsRequest)(
|
|
61
|
+
address,
|
|
62
|
+
{ headers: { "user-agent": "executor-launcher/" + version } },
|
|
63
|
+
(response) => {
|
|
64
|
+
const status = response.statusCode || 0;
|
|
65
|
+
if (status >= 300 && status < 400 && response.headers.location) {
|
|
66
|
+
response.resume();
|
|
67
|
+
if (redirects >= 10) return reject(new Error("too many redirects"));
|
|
68
|
+
return resolve(get(new URL(response.headers.location, address).href, redirects + 1));
|
|
69
|
+
}
|
|
70
|
+
if (status !== 200) {
|
|
71
|
+
response.resume();
|
|
72
|
+
return reject(new Error("HTTP " + status));
|
|
73
|
+
}
|
|
74
|
+
resolve(response);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
// A connection that stops sending for a minute is not coming back.
|
|
78
|
+
request.setTimeout(60000, () => request.destroy(new Error("the connection stalled")));
|
|
79
|
+
request.on("error", reject);
|
|
80
|
+
request.end();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/** Download the archive to `file`, hashing it as it arrives; resolves to its SHA-256. */
|
|
84
|
+
const download = async (file) => {
|
|
85
|
+
const response = await get(url, 0);
|
|
86
|
+
const total = Number(response.headers["content-length"]) || 0;
|
|
87
|
+
const hash = createHash("sha256");
|
|
88
|
+
const out = createWriteStream(file);
|
|
89
|
+
const tty = process.stderr.isTTY;
|
|
90
|
+
let received = 0;
|
|
91
|
+
let shown = -1;
|
|
92
|
+
const label = "Downloading Executor " + version + " for " + target;
|
|
93
|
+
if (!tty) console.error(label + " (first run of this version)");
|
|
94
|
+
await new Promise((resolve, reject) => {
|
|
95
|
+
response.on("data", (chunk) => {
|
|
96
|
+
hash.update(chunk);
|
|
97
|
+
received += chunk.length;
|
|
98
|
+
const step = total ? Math.floor((received * 100) / total) : Math.floor(received / 1048576);
|
|
99
|
+
if (tty && step !== shown) {
|
|
100
|
+
shown = step;
|
|
101
|
+
const amount = (received / 1048576).toFixed(1) + " MB";
|
|
102
|
+
process.stderr.write(
|
|
103
|
+
"\r\x1b[2K" + label + (total ? " " + step + "%" : "") + " (" + amount + ")",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
response.on("error", reject);
|
|
108
|
+
out.on("error", reject);
|
|
109
|
+
out.on("finish", resolve);
|
|
110
|
+
response.pipe(out);
|
|
111
|
+
});
|
|
112
|
+
if (tty) process.stderr.write("\r\x1b[2K");
|
|
113
|
+
return hash.digest("hex");
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Keep this version and the most recently installed other one, which a background Executor started
|
|
118
|
+
* before an update may still run from, as the install scripts keep `previous`. Downloads that
|
|
119
|
+
* stopped part way are removed after a day. Anything in use, which Windows refuses to delete, stays
|
|
120
|
+
* for a later download to remove.
|
|
121
|
+
*/
|
|
122
|
+
const prune = () => {
|
|
123
|
+
const day = 24 * 60 * 60 * 1000;
|
|
124
|
+
const entries = readdirSync(root)
|
|
125
|
+
.filter((name) => name !== version)
|
|
126
|
+
.map((name) => ({ name, time: statSync(join(root, name)).mtimeMs }));
|
|
127
|
+
const versions = entries.filter((entry) => !entry.name.startsWith("."));
|
|
128
|
+
versions.sort((left, right) => right.time - left.time);
|
|
129
|
+
const stale = versions
|
|
130
|
+
.slice(1)
|
|
131
|
+
.concat(entries.filter((entry) => entry.name.startsWith(".") && Date.now() - entry.time > day));
|
|
132
|
+
for (const entry of stale) {
|
|
133
|
+
try {
|
|
134
|
+
rmSync(join(root, entry.name), { recursive: true, force: true });
|
|
135
|
+
} catch {
|
|
136
|
+
// In use; a later download removes it.
|
|
137
|
+
}
|
|
13
138
|
}
|
|
14
|
-
|
|
15
|
-
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const install = async () => {
|
|
142
|
+
mkdirSync(root, { recursive: true });
|
|
143
|
+
const staging = join(root, ".download-" + process.pid + "-" + randomBytes(4).toString("hex"));
|
|
144
|
+
mkdirSync(staging);
|
|
145
|
+
// `fail` exits at once, without running `finally`.
|
|
146
|
+
const cleanup = () => rmSync(staging, { recursive: true, force: true });
|
|
147
|
+
process.on("exit", cleanup);
|
|
148
|
+
try {
|
|
149
|
+
let actual;
|
|
150
|
+
try {
|
|
151
|
+
actual = await download(join(staging, archive));
|
|
152
|
+
} catch (error) {
|
|
153
|
+
fail([
|
|
154
|
+
"Executor could not download its runtime from " + url + ": " + error.message + ".",
|
|
155
|
+
"Check your connection and try again. EXECUTOR_DOWNLOAD_URL names a mirror of the releases.",
|
|
156
|
+
]);
|
|
157
|
+
}
|
|
158
|
+
if (actual !== digest)
|
|
159
|
+
fail([
|
|
160
|
+
archive +
|
|
161
|
+
" does not match the SHA-256 this package records (expected " +
|
|
162
|
+
digest +
|
|
163
|
+
", got " +
|
|
164
|
+
actual +
|
|
165
|
+
").",
|
|
166
|
+
"Nothing was installed. Check EXECUTOR_DOWNLOAD_URL, or reinstall with: npm i -g executor" +
|
|
167
|
+
channel,
|
|
168
|
+
]);
|
|
169
|
+
// The system's tar, as the install scripts use: Windows' own bsdtar, since Git's GNU tar on
|
|
170
|
+
// PATH reads a drive letter as a remote host. The archive path is relative for the same reason.
|
|
171
|
+
const tar =
|
|
172
|
+
process.platform === "win32"
|
|
173
|
+
? join(process.env.SystemRoot || "C:\\Windows", "System32", "tar.exe")
|
|
174
|
+
: "tar";
|
|
175
|
+
// Nothing reaches stdout, which an MCP client starting `executor mcp` reads as the protocol.
|
|
176
|
+
const unpacked = spawnSync(tar, ["-xzf", archive], {
|
|
177
|
+
cwd: staging,
|
|
178
|
+
stdio: ["ignore", "ignore", "inherit"],
|
|
179
|
+
});
|
|
180
|
+
if (unpacked.status !== 0)
|
|
181
|
+
fail([
|
|
182
|
+
"Executor could not unpack " +
|
|
183
|
+
archive +
|
|
184
|
+
" with " +
|
|
185
|
+
tar +
|
|
186
|
+
(unpacked.error ? ": " + unpacked.error.message : "."),
|
|
187
|
+
]);
|
|
188
|
+
try {
|
|
189
|
+
renameSync(join(staging, "package"), installed);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// Another `executor` command installed this version first.
|
|
192
|
+
if (!existsSync(executable))
|
|
193
|
+
fail([
|
|
194
|
+
"Executor could not install its runtime in " + installed + ": " + error.message,
|
|
195
|
+
"Remove " + installed + " and try again.",
|
|
196
|
+
]);
|
|
197
|
+
}
|
|
198
|
+
// The version's time orders it for pruning; the archive's own times are from 1985.
|
|
199
|
+
const now = new Date();
|
|
200
|
+
utimesSync(installed, now, now);
|
|
201
|
+
} finally {
|
|
202
|
+
process.removeListener("exit", cleanup);
|
|
203
|
+
cleanup();
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
prune();
|
|
207
|
+
} catch {
|
|
208
|
+
// Pruning never stops Executor from starting.
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
if (!existsSync(executable)) await install();
|
|
213
|
+
|
|
214
|
+
const child = spawn(executable, process.argv.slice(2), {
|
|
215
|
+
stdio: "inherit",
|
|
216
|
+
env: Object.assign({}, process.env, {
|
|
217
|
+
// How Executor was installed, for `executor upgrade` and its update notice.
|
|
218
|
+
EXECUTOR_LAUNCHER: fileURLToPath(import.meta.url),
|
|
219
|
+
EXECUTOR_LAUNCHER_NODE: process.versions.node,
|
|
220
|
+
}),
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// A terminal's Ctrl-C already reaches the whole process group, and on Windows every process on
|
|
224
|
+
// the console. A service manager signals only this process, so the signal is passed on. Windows
|
|
225
|
+
// has no signals to pass: killing the child there would end it at once, before its shutdown.
|
|
226
|
+
const signals =
|
|
227
|
+
process.platform === "win32" ? ["SIGINT", "SIGBREAK"] : ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
228
|
+
const forward = (signal) => {
|
|
229
|
+
if (process.platform !== "win32" && child.exitCode === null && child.signalCode === null)
|
|
230
|
+
child.kill(signal);
|
|
231
|
+
};
|
|
232
|
+
for (const signal of signals) process.on(signal, forward);
|
|
233
|
+
|
|
234
|
+
child.on("error", (error) =>
|
|
235
|
+
fail([
|
|
236
|
+
"Executor could not start " + executable + ": " + error.message,
|
|
237
|
+
"Remove " + installed + " to download it again.",
|
|
238
|
+
]),
|
|
239
|
+
);
|
|
240
|
+
child.on("exit", (code, signal) => {
|
|
241
|
+
for (const name of signals) process.removeListener(name, forward);
|
|
242
|
+
// Ending by the same signal tells the shell what stopped Executor.
|
|
243
|
+
if (signal !== null) process.kill(process.pid, signal);
|
|
244
|
+
else process.exit(code === null ? 1 : code);
|
|
245
|
+
});
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "executor",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.40",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Run Executor locally and connect your agents to your apps.",
|
|
6
|
-
"homepage": "https://
|
|
6
|
+
"homepage": "https://executor.sh",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -11,13 +11,15 @@
|
|
|
11
11
|
},
|
|
12
12
|
"type": "module",
|
|
13
13
|
"engines": {
|
|
14
|
-
"node": ">=
|
|
14
|
+
"node": ">=14.18.0"
|
|
15
15
|
},
|
|
16
16
|
"bin": {
|
|
17
17
|
"executor": "bin.mjs"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"bin.mjs",
|
|
21
|
+
"bin/executor",
|
|
22
|
+
"bin/package.json",
|
|
21
23
|
"README.md",
|
|
22
24
|
"LICENSE"
|
|
23
25
|
],
|
|
@@ -25,11 +27,11 @@
|
|
|
25
27
|
"access": "public",
|
|
26
28
|
"tag": "beta"
|
|
27
29
|
},
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
30
|
+
"runtimes": {
|
|
31
|
+
"darwin-arm64": "85ae709121e94e10216e3a8e7b6e547fa2fb1f40077507d3e6c2fa21776da07a",
|
|
32
|
+
"darwin-x64": "6ec9505e1aeae66bb13370577a1446fbabdaf7ad7a3947f377de0513e44c8bc5",
|
|
33
|
+
"linux-x64": "ee4e11927b3067e80948f1ffb9187ad52f9bb39fee2ae7c22fa39933d8aa0cac",
|
|
34
|
+
"linux-arm64": "23791582608c449cd070668cebe024df2dbb11b914a32aec4abbd2abb7c0e080",
|
|
35
|
+
"win32-x64": "cd7802407951ed968aa150f301a0727763697f13fcf4f512f62e2eac15e7ab19"
|
|
34
36
|
}
|
|
35
37
|
}
|