@tetsuo-ai/agenc 0.1.0 → 0.2.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/bin/agenc +4 -0
- package/generated/.gitkeep +0 -1
- package/generated/agenc-runtime-manifest.json +52 -14
- package/lib/runtime-manager.mjs +169 -0
- package/package.json +13 -21
- package/scripts/build-runtime-tarball.mjs +201 -0
- package/scripts/gen-manifest.mjs +91 -0
- package/scripts/postinstall.mjs +19 -0
- package/src/launcher.mjs +246 -0
- package/README.md +0 -90
- package/bin/agenc-runtime.js +0 -5
- package/bin/agenc.js +0 -5
- package/generated/agenc-runtime-manifest.json.sig +0 -1
- package/generated/agenc-runtime-public-key.pem +0 -3
- package/generated/agenc-runtime-trust-policy.json +0 -9
- package/lib/cli.js +0 -187
- package/lib/runtime-manager.js +0 -831
- package/scripts/postinstall.js +0 -6
package/src/launcher.mjs
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_READY_TIMEOUT_MS = 2000;
|
|
9
|
+
const DEFAULT_POLL_MS = 25;
|
|
10
|
+
const READY_TIMEOUT_ENV = "AGENC_DAEMON_READY_TIMEOUT_MS";
|
|
11
|
+
const AUTOSTART_ENV = "AGENC_DAEMON_AUTOSTART";
|
|
12
|
+
|
|
13
|
+
const requireFromLauncher = createRequire(import.meta.url);
|
|
14
|
+
|
|
15
|
+
export function shouldAutostartDaemon(env = process.env) {
|
|
16
|
+
const raw = env[AUTOSTART_ENV]?.trim().toLowerCase();
|
|
17
|
+
if (raw === undefined || raw.length === 0) return true;
|
|
18
|
+
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolveReadyTimeoutMs(env = process.env) {
|
|
22
|
+
const raw = env[READY_TIMEOUT_ENV]?.trim();
|
|
23
|
+
if (raw === undefined || raw.length === 0) return DEFAULT_READY_TIMEOUT_MS;
|
|
24
|
+
const parsed = Number.parseInt(raw, 10);
|
|
25
|
+
if (!Number.isInteger(parsed) || String(parsed) !== raw || parsed <= 0) {
|
|
26
|
+
throw new Error(`${READY_TIMEOUT_ENV} must be a positive integer`);
|
|
27
|
+
}
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function resolveAgenCHome(env = process.env, userHome = homedir()) {
|
|
32
|
+
const configured = env.AGENC_HOME?.trim();
|
|
33
|
+
return configured && configured.length > 0
|
|
34
|
+
? configured
|
|
35
|
+
: join(userHome, ".agenc");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function resolveDaemonPidPath(env = process.env, userHome = homedir()) {
|
|
39
|
+
return join(resolveAgenCHome(env, userHome), "daemon.pid");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function resolveDaemonCookiePath(env = process.env, userHome = homedir()) {
|
|
43
|
+
return join(resolveAgenCHome(env, userHome), "daemon.cookie");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function readDaemonPid(pidPath, readText = readFile) {
|
|
47
|
+
try {
|
|
48
|
+
const raw = (await readText(pidPath, "utf8")).trim();
|
|
49
|
+
if (!/^\d+$/.test(raw)) return null;
|
|
50
|
+
const pid = Number.parseInt(raw, 10);
|
|
51
|
+
return pid > 0 ? pid : null;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error?.code === "ENOENT") return null;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isPidRunning(pid, signalPid = process.kill) {
|
|
59
|
+
try {
|
|
60
|
+
signalPid(pid, 0);
|
|
61
|
+
return true;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return error?.code === "EPERM";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isDaemonCommand(argv) {
|
|
68
|
+
return argv[0] === "daemon";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Dev path: the `file:`-linked @tetsuo-ai/runtime resolves locally. Returns
|
|
72
|
+
// null in a published install where runtime is NOT an npm dependency (it's the
|
|
73
|
+
// downloaded GitHub-Releases artifact instead).
|
|
74
|
+
export function resolveRuntimeBin(requireFn = requireFromLauncher) {
|
|
75
|
+
try {
|
|
76
|
+
const runtimeEntry = requireFn.resolve("@tetsuo-ai/runtime");
|
|
77
|
+
return resolve(dirname(runtimeEntry), "../bin/agenc");
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (
|
|
80
|
+
error?.code === "MODULE_NOT_FOUND" ||
|
|
81
|
+
error?.code === "ERR_MODULE_NOT_FOUND"
|
|
82
|
+
) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Resolve the runtime entry for either mode: prefer the dev file:-link, else
|
|
90
|
+
// ensure (download + verify + extract) the published per-platform runtime.
|
|
91
|
+
export async function resolveRuntimeBinAsync({
|
|
92
|
+
requireFn = requireFromLauncher,
|
|
93
|
+
ensureFn,
|
|
94
|
+
} = {}) {
|
|
95
|
+
const dev = resolveRuntimeBin(requireFn);
|
|
96
|
+
if (dev !== null) return dev;
|
|
97
|
+
const ensureRuntime =
|
|
98
|
+
ensureFn ?? (await import("../lib/runtime-manager.mjs")).ensureRuntime;
|
|
99
|
+
return ensureRuntime();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function spawnNodeScript(
|
|
103
|
+
scriptPath,
|
|
104
|
+
args,
|
|
105
|
+
{
|
|
106
|
+
env = process.env,
|
|
107
|
+
cwd = process.cwd(),
|
|
108
|
+
stdio = "inherit",
|
|
109
|
+
spawnFn = spawn,
|
|
110
|
+
} = {},
|
|
111
|
+
) {
|
|
112
|
+
return new Promise((resolveExit, reject) => {
|
|
113
|
+
const child = spawnFn(process.execPath, [scriptPath, ...args], {
|
|
114
|
+
cwd,
|
|
115
|
+
env,
|
|
116
|
+
stdio,
|
|
117
|
+
});
|
|
118
|
+
child.once("error", reject);
|
|
119
|
+
child.once("exit", (code, signal) => {
|
|
120
|
+
if (signal !== null) {
|
|
121
|
+
reject(new Error(`agenc runtime exited from signal ${signal}`));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
resolveExit(code ?? 1);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function spawnDaemon(runtimeBin, options = {}) {
|
|
130
|
+
const exitCode = await spawnNodeScript(runtimeBin, ["daemon", "start"], {
|
|
131
|
+
...options,
|
|
132
|
+
stdio: ["ignore", "ignore", "inherit"],
|
|
133
|
+
});
|
|
134
|
+
if (exitCode !== 0) {
|
|
135
|
+
throw new Error(`AgenC daemon start failed with exit code ${exitCode}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function isDaemonReady(
|
|
140
|
+
{
|
|
141
|
+
env = process.env,
|
|
142
|
+
userHome = homedir(),
|
|
143
|
+
readText = readFile,
|
|
144
|
+
signalPid = process.kill,
|
|
145
|
+
} = {},
|
|
146
|
+
) {
|
|
147
|
+
const pidPath = resolveDaemonPidPath(env, userHome);
|
|
148
|
+
const cookiePath = resolveDaemonCookiePath(env, userHome);
|
|
149
|
+
const pid = await readDaemonPid(pidPath, readText);
|
|
150
|
+
if (pid === null || !isPidRunning(pid, signalPid)) return false;
|
|
151
|
+
try {
|
|
152
|
+
return (await readText(cookiePath, "utf8")).trim().length > 0;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error?.code === "ENOENT") return false;
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function waitForDaemonReady(options = {}) {
|
|
160
|
+
const timeoutMs = options.timeoutMs ?? resolveReadyTimeoutMs(options.env);
|
|
161
|
+
const pollMs = options.pollMs ?? DEFAULT_POLL_MS;
|
|
162
|
+
const startedAt = Date.now();
|
|
163
|
+
const sleep = options.sleep ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
164
|
+
|
|
165
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
166
|
+
if (await isDaemonReady(options)) return true;
|
|
167
|
+
await sleep(pollMs);
|
|
168
|
+
}
|
|
169
|
+
return isDaemonReady(options);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function ensureDaemonForLaunch({
|
|
173
|
+
argv = process.argv.slice(2),
|
|
174
|
+
env = process.env,
|
|
175
|
+
cwd = process.cwd(),
|
|
176
|
+
runtimeBin = resolveRuntimeBin(),
|
|
177
|
+
userHome = homedir(),
|
|
178
|
+
readText = readFile,
|
|
179
|
+
signalPid = process.kill,
|
|
180
|
+
spawnDaemonFn = spawnDaemon,
|
|
181
|
+
waitForReadyFn = waitForDaemonReady,
|
|
182
|
+
} = {}) {
|
|
183
|
+
if (isDaemonCommand(argv)) return { status: "skipped-daemon-command" };
|
|
184
|
+
if (!shouldAutostartDaemon(env)) return { status: "disabled" };
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
await waitForReadyFn({
|
|
188
|
+
env,
|
|
189
|
+
userHome,
|
|
190
|
+
readText,
|
|
191
|
+
signalPid,
|
|
192
|
+
timeoutMs: 1,
|
|
193
|
+
pollMs: 1,
|
|
194
|
+
sleep: async () => {},
|
|
195
|
+
})
|
|
196
|
+
) {
|
|
197
|
+
return { status: "already-running" };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
await spawnDaemonFn(runtimeBin, { env, cwd });
|
|
201
|
+
const ready = await waitForReadyFn({ env, userHome, readText, signalPid });
|
|
202
|
+
if (!ready) {
|
|
203
|
+
throw new Error("AgenC daemon did not become ready before timeout");
|
|
204
|
+
}
|
|
205
|
+
return { status: "started" };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export async function main(
|
|
209
|
+
argv = process.argv.slice(2),
|
|
210
|
+
{
|
|
211
|
+
env = process.env,
|
|
212
|
+
cwd = process.cwd(),
|
|
213
|
+
runtimeBin,
|
|
214
|
+
userHome = homedir(),
|
|
215
|
+
} = {},
|
|
216
|
+
) {
|
|
217
|
+
// Resolve (and, in a published install, download + verify) the runtime before
|
|
218
|
+
// anything tries to spawn it. Sync default is avoided: it returns null when
|
|
219
|
+
// runtime isn't an npm dep, which is the normal published case.
|
|
220
|
+
let resolvedBin = runtimeBin;
|
|
221
|
+
try {
|
|
222
|
+
resolvedBin ??= await resolveRuntimeBinAsync();
|
|
223
|
+
} catch (error) {
|
|
224
|
+
process.stderr.write(
|
|
225
|
+
`agenc: could not obtain runtime: ${
|
|
226
|
+
error instanceof Error ? error.message : String(error)
|
|
227
|
+
}\n`,
|
|
228
|
+
);
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
await ensureDaemonForLaunch({ argv, env, cwd, runtimeBin: resolvedBin, userHome });
|
|
233
|
+
} catch (error) {
|
|
234
|
+
process.stderr.write(
|
|
235
|
+
`agenc: daemon autostart failed: ${
|
|
236
|
+
error instanceof Error ? error.message : String(error)
|
|
237
|
+
}\n`,
|
|
238
|
+
);
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
return spawnNodeScript(resolvedBin, argv, { env, cwd, stdio: "inherit" });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
245
|
+
process.exitCode = await main();
|
|
246
|
+
}
|
package/README.md
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# agenc
|
|
2
|
-
|
|
3
|
-
Public CLI and launcher for the AgenC framework.
|
|
4
|
-
|
|
5
|
-
This package owns the user-facing global install surface:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install -g @tetsuo-ai/agenc
|
|
9
|
-
agenc onboard
|
|
10
|
-
agenc start
|
|
11
|
-
agenc
|
|
12
|
-
agenc ui
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
It does not expose the runtime source tree directly. Instead, it installs and
|
|
16
|
-
launches the matching AgenC runtime artifact for the current supported
|
|
17
|
-
platform.
|
|
18
|
-
|
|
19
|
-
The supported npm install identity is `@tetsuo-ai/agenc`. The unscoped
|
|
20
|
-
`agenc` package name is not part of the supported public release contract.
|
|
21
|
-
|
|
22
|
-
Current public support is intentionally narrow:
|
|
23
|
-
|
|
24
|
-
- Linux `x64`
|
|
25
|
-
- Node `>=18.0.0`
|
|
26
|
-
|
|
27
|
-
Current validated release-gate lanes:
|
|
28
|
-
|
|
29
|
-
- Node `18` minimum floor
|
|
30
|
-
- Node `20` mainline lane
|
|
31
|
-
|
|
32
|
-
Production release channel:
|
|
33
|
-
|
|
34
|
-
- npm package: `@tetsuo-ai/agenc`
|
|
35
|
-
- runtime artifact host: GitHub Releases on `tetsuo-ai/agenc-core`
|
|
36
|
-
- trust: embedded signed manifest + embedded public key + embedded trust policy
|
|
37
|
-
|
|
38
|
-
After the matching runtime artifact is installed, `agenc` can continue to run
|
|
39
|
-
offline against the local install. The npm package name is scoped, but the CLI
|
|
40
|
-
binary remains `agenc`.
|
|
41
|
-
|
|
42
|
-
`agenc` exposes two primary local operator surfaces against the same daemon:
|
|
43
|
-
|
|
44
|
-
- `agenc` attaches the terminal operator console
|
|
45
|
-
- `agenc ui` opens or prints the local dashboard URL on `/ui/`
|
|
46
|
-
|
|
47
|
-
For automation or remote shells, use:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
agenc ui --no-open
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## First-party connector lifecycle
|
|
54
|
-
|
|
55
|
-
The first V1 connector is Telegram. It is managed through the same daemon as the
|
|
56
|
-
CLI and dashboard; there is no separate connector service to start.
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
agenc connector list
|
|
60
|
-
agenc connector status telegram
|
|
61
|
-
agenc connector add telegram --bot-token-env TELEGRAM_BOT_TOKEN
|
|
62
|
-
agenc connector remove telegram
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
For non-interactive shells or secret managers, you can pipe the bot token on
|
|
66
|
-
stdin instead:
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
printf '%s' "$TELEGRAM_BOT_TOKEN" | agenc connector add telegram --bot-token-stdin
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Connector health and pending-restart state are exposed through both:
|
|
73
|
-
|
|
74
|
-
- `agenc connector status telegram`
|
|
75
|
-
- `agenc ui` on the dashboard status view
|
|
76
|
-
|
|
77
|
-
## Wrapper-local runtime management
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
agenc runtime where
|
|
81
|
-
agenc runtime install
|
|
82
|
-
agenc runtime update
|
|
83
|
-
agenc runtime uninstall
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Development
|
|
87
|
-
|
|
88
|
-
The embedded runtime manifest in `generated/` is produced by the `agenc-core`
|
|
89
|
-
artifact preparation scripts. Local smoke tests use the same packaged manifest
|
|
90
|
-
flow as publish/release preparation.
|
package/bin/agenc-runtime.js
DELETED
package/bin/agenc.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
iFOPHEatEGfaMVQhLsENy9CEenablWaZLG6G5V2u37hN44hvIwTtgoK6ihiHQL3aIJXmBEM2VRdSPInlJBtMAg==
|
package/lib/cli.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import process from "node:process";
|
|
2
|
-
import {
|
|
3
|
-
describeRuntimeInstall,
|
|
4
|
-
ensureRuntimeInstalled,
|
|
5
|
-
RuntimeInstallError,
|
|
6
|
-
spawnInstalledRuntimeBin,
|
|
7
|
-
uninstallRuntime,
|
|
8
|
-
} from "./runtime-manager.js";
|
|
9
|
-
|
|
10
|
-
function writeLine(stream, value) {
|
|
11
|
-
stream.write(`${value}\n`);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function buildAgencHelp() {
|
|
15
|
-
return [
|
|
16
|
-
"agenc [runtime-command] [options]",
|
|
17
|
-
"agenc runtime <where|install|update|uninstall>",
|
|
18
|
-
"",
|
|
19
|
-
"Examples:",
|
|
20
|
-
" agenc onboard",
|
|
21
|
-
" agenc ui",
|
|
22
|
-
" agenc start",
|
|
23
|
-
" agenc status",
|
|
24
|
-
" agenc logs",
|
|
25
|
-
" agenc runtime where",
|
|
26
|
-
].join("\n");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function buildAgencRuntimeHelp() {
|
|
30
|
-
return [
|
|
31
|
-
"agenc-runtime [runtime-command] [options]",
|
|
32
|
-
"",
|
|
33
|
-
"Compatibility alias for the installed AgenC runtime CLI.",
|
|
34
|
-
].join("\n");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function runRuntimeAdmin(argv, io, deps, runtimeOptions) {
|
|
38
|
-
const command = argv[0];
|
|
39
|
-
const force = argv.includes("--force");
|
|
40
|
-
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
41
|
-
writeLine(
|
|
42
|
-
io.stdout,
|
|
43
|
-
"agenc runtime <where|install|update|uninstall> [--force]",
|
|
44
|
-
);
|
|
45
|
-
return 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (command === "where") {
|
|
49
|
-
const description = await deps.describeRuntimeInstall(runtimeOptions);
|
|
50
|
-
writeLine(
|
|
51
|
-
io.stdout,
|
|
52
|
-
JSON.stringify(
|
|
53
|
-
{
|
|
54
|
-
runtimeHome: description.runtimeHome,
|
|
55
|
-
installed: description.installed,
|
|
56
|
-
releaseDir: description.releaseDir,
|
|
57
|
-
currentDir: description.currentDir,
|
|
58
|
-
manifestSource: description.manifestSource,
|
|
59
|
-
manifestDigest: description.manifestDigest,
|
|
60
|
-
trustPolicy: description.trustPolicy
|
|
61
|
-
? {
|
|
62
|
-
wrapperVersion: description.trustPolicy.wrapperVersion,
|
|
63
|
-
keyId: description.trustPolicy.keyId,
|
|
64
|
-
releaseChannel: description.trustPolicy.releaseChannel ?? null,
|
|
65
|
-
releaseRepository:
|
|
66
|
-
description.trustPolicy.releaseRepository ?? null,
|
|
67
|
-
releaseTag: description.trustPolicy.releaseTag ?? null,
|
|
68
|
-
revokedManifestDigests:
|
|
69
|
-
description.trustPolicy.revokedManifestDigests,
|
|
70
|
-
revokedRuntimeVersions:
|
|
71
|
-
description.trustPolicy.revokedRuntimeVersions,
|
|
72
|
-
}
|
|
73
|
-
: null,
|
|
74
|
-
selectedArtifact: description.selectedArtifact
|
|
75
|
-
? {
|
|
76
|
-
runtimeVersion: description.selectedArtifact.runtimeVersion,
|
|
77
|
-
platform: description.selectedArtifact.platform,
|
|
78
|
-
arch: description.selectedArtifact.arch,
|
|
79
|
-
nodeRange: description.selectedArtifact.nodeRange,
|
|
80
|
-
}
|
|
81
|
-
: null,
|
|
82
|
-
},
|
|
83
|
-
null,
|
|
84
|
-
2,
|
|
85
|
-
),
|
|
86
|
-
);
|
|
87
|
-
return 0;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (command === "install" || command === "update") {
|
|
91
|
-
const installation = await deps.ensureRuntimeInstalled({
|
|
92
|
-
...runtimeOptions,
|
|
93
|
-
force: command === "update",
|
|
94
|
-
});
|
|
95
|
-
writeLine(
|
|
96
|
-
io.stdout,
|
|
97
|
-
`Installed AgenC runtime ${installation.selectedArtifact.runtimeVersion} at ${installation.releaseDir}`,
|
|
98
|
-
);
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (command === "uninstall") {
|
|
103
|
-
const result = await deps.uninstallRuntime({ ...runtimeOptions, force });
|
|
104
|
-
writeLine(
|
|
105
|
-
io.stdout,
|
|
106
|
-
result.removed
|
|
107
|
-
? `Removed AgenC runtime at ${result.releaseDir}\nPreserved: ${result.preservedPaths.join(", ")}`
|
|
108
|
-
: "No installed AgenC runtime found for the current platform",
|
|
109
|
-
);
|
|
110
|
-
return 0;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
writeLine(io.stderr, `Unknown agenc runtime command: ${command}`);
|
|
114
|
-
return 2;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const DEFAULT_DEPS = {
|
|
118
|
-
ensureRuntimeInstalled,
|
|
119
|
-
describeRuntimeInstall,
|
|
120
|
-
uninstallRuntime,
|
|
121
|
-
spawnInstalledRuntimeBin,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
function formatRuntimeInstallError(error) {
|
|
125
|
-
if (error instanceof RuntimeInstallError) {
|
|
126
|
-
return error.message;
|
|
127
|
-
}
|
|
128
|
-
return error instanceof Error ? error.message : String(error);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export async function runAgencWrapper(options = {}, deps = DEFAULT_DEPS) {
|
|
132
|
-
const argv = options.argv ?? process.argv.slice(2);
|
|
133
|
-
const stdout = options.stdout ?? process.stdout;
|
|
134
|
-
const stderr = options.stderr ?? process.stderr;
|
|
135
|
-
const runtimeOptions = {
|
|
136
|
-
env: options.env ?? process.env,
|
|
137
|
-
cwd: options.cwd ?? process.cwd(),
|
|
138
|
-
homeDir: options.homeDir,
|
|
139
|
-
packageRoot: options.packageRoot,
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
if (argv[0] === "runtime") {
|
|
144
|
-
return await runRuntimeAdmin(
|
|
145
|
-
argv.slice(1),
|
|
146
|
-
{ stdout, stderr },
|
|
147
|
-
deps,
|
|
148
|
-
runtimeOptions,
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
if (argv[0] === "--help" || argv[0] === "-h" || argv[0] === "help") {
|
|
152
|
-
writeLine(stdout, buildAgencHelp());
|
|
153
|
-
return 0;
|
|
154
|
-
}
|
|
155
|
-
return await deps.spawnInstalledRuntimeBin("agenc", argv, runtimeOptions);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
writeLine(stderr, formatRuntimeInstallError(error));
|
|
158
|
-
return 1;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export async function runAgencRuntimeWrapper(options = {}, deps = DEFAULT_DEPS) {
|
|
163
|
-
const argv = options.argv ?? process.argv.slice(2);
|
|
164
|
-
const stdout = options.stdout ?? process.stdout;
|
|
165
|
-
const stderr = options.stderr ?? process.stderr;
|
|
166
|
-
const runtimeOptions = {
|
|
167
|
-
env: options.env ?? process.env,
|
|
168
|
-
cwd: options.cwd ?? process.cwd(),
|
|
169
|
-
homeDir: options.homeDir,
|
|
170
|
-
packageRoot: options.packageRoot,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
if (argv[0] === "--help" || argv[0] === "-h" || argv[0] === "help") {
|
|
175
|
-
writeLine(stdout, buildAgencRuntimeHelp());
|
|
176
|
-
return 0;
|
|
177
|
-
}
|
|
178
|
-
return await deps.spawnInstalledRuntimeBin(
|
|
179
|
-
"agenc-runtime",
|
|
180
|
-
argv,
|
|
181
|
-
runtimeOptions,
|
|
182
|
-
);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
writeLine(stderr, formatRuntimeInstallError(error));
|
|
185
|
-
return 1;
|
|
186
|
-
}
|
|
187
|
-
}
|