@sagentlab/navarch-runtime 0.1.61 → 0.1.63
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 +14 -8
- package/dist/cli.cjs +41 -6
- package/dist/config.cjs +27 -8
- package/dist/machine-store.cjs +5 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ machine.
|
|
|
8
8
|
|
|
9
9
|
The machine operator selects **Claude Code**, **OpenAI Codex**, **Google
|
|
10
10
|
Gemini CLI**, **OpenCode**, or an **Agent Client Protocol (ACP)** agent when connecting a worker. Any selected agent can
|
|
11
|
-
run any project task; task eligibility depends on capabilities and
|
|
12
|
-
gates
|
|
11
|
+
run any unpinned project task; task eligibility depends on capabilities and
|
|
12
|
+
project gates. A task pinned to a runtime waits for a worker that advertises
|
|
13
|
+
that adapter and runs on it — see "Choosing an agent" below.
|
|
13
14
|
|
|
14
15
|
See [`docs/agent-platform-project-plan.md`](../docs/agent-platform-project-plan.md)
|
|
15
16
|
§3.8/§3.9/§3.11 and [`docs/navarch/implementation-plan.md`](../docs/navarch/implementation-plan.md)
|
|
@@ -29,7 +30,7 @@ Before generating the command, prepare the machine:
|
|
|
29
30
|
- install Node.js 20 or later (the standard installation includes `npm` and
|
|
30
31
|
`npx`) and Git;
|
|
31
32
|
- install the coding-agent CLI selected in Navarch — `claude`, `codex`,
|
|
32
|
-
`gemini`, `opencode`,
|
|
33
|
+
`gemini`, `opencode`, `dsh` for the default ACP integration, or `qoder` — and complete its normal authentication flow; and
|
|
33
34
|
- for Docker-backed sessions, install and start Docker and use an image that
|
|
34
35
|
contains the selected agent CLI and the repository toolchain, with provider
|
|
35
36
|
credentials supplied through the approved machine or project configuration.
|
|
@@ -44,7 +45,7 @@ node --version # 20 or later
|
|
|
44
45
|
npm --version
|
|
45
46
|
npx --version
|
|
46
47
|
git --version
|
|
47
|
-
codex --version # or: claude / gemini / opencode / dsh --version
|
|
48
|
+
codex --version # or: claude / gemini / opencode / qoder / dsh --version
|
|
48
49
|
```
|
|
49
50
|
|
|
50
51
|
Every command above must succeed before the long-running worker starts. See
|
|
@@ -156,7 +157,7 @@ The from-source flow — `git clone` + `./install.sh` + `node bin/navarch.cjs
|
|
|
156
157
|
| `connect --token <t> --name <n> [--agent claude-code\|codex\|gemini\|opencode\|acp\|qoder] [--project <id>] […]` | Connects this machine to one project, saves its local agent choice, and prints the token once. |
|
|
157
158
|
| `start [--agent claude-code\|codex\|gemini\|opencode\|acp\|qoder]` | Runs the daemon. A start-time agent choice overrides the saved choice. |
|
|
158
159
|
| `supervise [--agent claude-code\|codex\|gemini\|opencode\|acp\|qoder]` | Runs the daemon under the update supervisor, enabling drain-safe automatic updates and rollback. |
|
|
159
|
-
| `doctor` | Prints resolved config + Docker/registration status; no side effects. |
|
|
160
|
+
| `doctor [--agent claude-code\|codex\|gemini\|opencode\|acp\|qoder]` | Prints resolved config + Docker/registration status; no side effects. |
|
|
160
161
|
|
|
161
162
|
### Running multiple agents on one machine
|
|
162
163
|
|
|
@@ -369,7 +370,7 @@ unchanged across the deployment.
|
|
|
369
370
|
| `NAVARCH_SANDBOX_EGRESS_NETWORK` | _(unset)_ | Docker network that enforces a profile's egress allowlist. Docker cannot filter by domain itself, so an allowlist profile without this fails closed to `--network=none` and records the denial. |
|
|
370
371
|
| `NAVARCH_DOCKER_IMAGE` | `ghcr.io/sagentlab/navarch-sandbox-agent:0.1.0` | Version-pinned per-session image with Node 20, git, GitHub CLI, ripgrep, jq, SSH, and Claude Code 2.1.218. Override with an image tag or digest you control. |
|
|
371
372
|
| `NAVARCH_AGENT` | saved choice, then `claude-code` | Local choice of agent adapter: `claude-code`, `codex`, `gemini`, `opencode`, `acp`, or `qoder`. Overrides the choice saved by `connect`/`register`; `start --agent` has highest priority. |
|
|
372
|
-
| `NAVARCH_RUNTIMES` | resolved local agent choice | Comma list of installed/authenticated adapters advertised to dispatch.
|
|
373
|
+
| `NAVARCH_RUNTIMES` | resolved local agent choice | Comma list of installed/authenticated adapters advertised to dispatch. Unpinned tasks run on the preferred agent; a task runtime pin selects the matching adapter. Unrecognized ids are dropped with a warning that names them, so a typo cannot silently shrink the advertised set. |
|
|
373
374
|
| `NAVARCH_UPDATE_CHANNEL` | `stable` | Release channel advertised by the worker (`stable` or `canary`); the server-managed machine channel remains authoritative. |
|
|
374
375
|
| `NAVARCH_AUTO_UPDATE` | on under `supervise` | Set `off`, `false`, or `0` to report releases without staging or activating them. Automatic activation is always off under plain `start`. |
|
|
375
376
|
| `NAVARCH_CLAUDE_BIN` | `claude` | Path/name of the Claude Code CLI binary. |
|
|
@@ -530,8 +531,13 @@ export NAVARCH_RUNTIMES=claude-code,codex,gemini,opencode,acp,qoder
|
|
|
530
531
|
For the legacy single-runtime setting, priority is `start --agent` →
|
|
531
532
|
`NAVARCH_AGENT` → the locally saved choice → `claude-code`.
|
|
532
533
|
`NAVARCH_RUNTIMES` expands what the worker advertises. For normal projects,
|
|
533
|
-
the locally selected `NAVARCH_AGENT` handles every
|
|
534
|
-
|
|
534
|
+
the locally selected `NAVARCH_AGENT` handles every unpinned task. A task with a
|
|
535
|
+
runtime override (for example `gemini`) is claimed only by a worker that
|
|
536
|
+
advertises that adapter, and the claim returns it as the session runtime.
|
|
537
|
+
Sandbox projects remain constrained to Claude Code, so they claim only unpinned
|
|
538
|
+
or `claude-code`-pinned tasks. List only adapters this worker can really run:
|
|
539
|
+
in Docker mode that means CLIs installed in `NAVARCH_DOCKER_IMAGE`, otherwise
|
|
540
|
+
pinned tasks for a missing adapter are claimed and then fail.
|
|
535
541
|
|
|
536
542
|
All five BYO adapters implement the same `AgentAdapter` interface
|
|
537
543
|
(`src/adapters/types.cts`) and run either directly on the host or via
|
package/dist/cli.cjs
CHANGED
|
@@ -20,6 +20,8 @@ const supervisor_cjs_1 = require("./supervisor.cjs");
|
|
|
20
20
|
const worktree_janitor_cjs_1 = require("./worktree-janitor.cjs");
|
|
21
21
|
const log = (0, logger_cjs_1.createLogger)("cli");
|
|
22
22
|
const PACKAGE_NAME = "@sagentlab/navarch-runtime";
|
|
23
|
+
/** Accepted `--agent` ids as usage metavariables, generated from one source of truth. */
|
|
24
|
+
const AGENT_TYPE_USAGE = config_cjs_1.RUNTIME_AGENT_TYPES.join("|");
|
|
23
25
|
/**
|
|
24
26
|
* Exit code for "this machine's identity is gone". Deliberately outside the
|
|
25
27
|
* supervisor's restart codes (75 update, 76 remote restart): respawning cannot
|
|
@@ -78,10 +80,32 @@ function agentFromFlag(flags) {
|
|
|
78
80
|
if (value === undefined)
|
|
79
81
|
return undefined;
|
|
80
82
|
if (!(0, config_cjs_1.isRuntimeAgentType)(value)) {
|
|
81
|
-
throw new Error(
|
|
83
|
+
throw new Error(`--agent must be one of ${formatChoices(config_cjs_1.RUNTIME_AGENT_TYPES)}.`);
|
|
82
84
|
}
|
|
83
85
|
return value;
|
|
84
86
|
}
|
|
87
|
+
/** `'a', 'b', or 'c'` — one prose list for every place the accepted ids are shown. */
|
|
88
|
+
function formatChoices(values) {
|
|
89
|
+
const quoted = values.map((value) => `'${value}'`);
|
|
90
|
+
const last = quoted.at(-1) ?? "";
|
|
91
|
+
if (quoted.length < 2)
|
|
92
|
+
return last;
|
|
93
|
+
return `${quoted.slice(0, -1).join(", ")}, or ${last}`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A typo in NAVARCH_RUNTIMES must not silently shrink the advertised adapter
|
|
97
|
+
* set, so name every dropped id on stderr. Runs once per top-level command (not
|
|
98
|
+
* per config load) to avoid duplicate lines when start/supervise/doctor resolve
|
|
99
|
+
* the identity and reload config. A supervised worker inherits NAVARCH_RUNTIMES
|
|
100
|
+
* from the `supervise` parent that already warned, so it stays quiet.
|
|
101
|
+
*/
|
|
102
|
+
function warnUnknownRuntimes(config) {
|
|
103
|
+
const unknown = config.unknownRuntimes;
|
|
104
|
+
if (config.supervised || unknown.length === 0)
|
|
105
|
+
return;
|
|
106
|
+
log.warn(`NAVARCH_RUNTIMES ignores unrecognized adapter id(s): ${unknown.join(", ")}. ` +
|
|
107
|
+
`Known adapters: ${config_cjs_1.RUNTIME_AGENT_TYPES.join(", ")}.`);
|
|
108
|
+
}
|
|
85
109
|
/** Saved pins only apply to the adapter they were selected for. */
|
|
86
110
|
function modelFromFlags(flags, agentType, identity) {
|
|
87
111
|
const model = flags.model ?? (identity?.agent_type === agentType ? identity.model : undefined);
|
|
@@ -116,6 +140,7 @@ function parseArgs(argv) {
|
|
|
116
140
|
*/
|
|
117
141
|
async function registerCommand(flags) {
|
|
118
142
|
const config = configFromFlags(flags);
|
|
143
|
+
warnUnknownRuntimes(config);
|
|
119
144
|
const apiBase = flags["api-base"] ?? config.apiBase;
|
|
120
145
|
const enrollmentToken = flags.token ?? process.env.NAVARCH_ENROLLMENT_TOKEN;
|
|
121
146
|
const name = flags.name ?? process.env.NAVARCH_MACHINE_NAME;
|
|
@@ -166,6 +191,7 @@ async function registerCommand(flags) {
|
|
|
166
191
|
*/
|
|
167
192
|
async function connectCommand(flags) {
|
|
168
193
|
const config = configFromFlags(flags);
|
|
194
|
+
warnUnknownRuntimes(config);
|
|
169
195
|
const apiBase = flags["api-base"] ?? config.apiBase;
|
|
170
196
|
const enrollmentToken = flags.token ?? process.env.NAVARCH_ENROLLMENT_TOKEN;
|
|
171
197
|
const name = flags.name ?? process.env.NAVARCH_MACHINE_NAME;
|
|
@@ -209,6 +235,7 @@ async function startCommand(flags) {
|
|
|
209
235
|
const baseConfig = configFromFlags(flags);
|
|
210
236
|
const identity = await (0, machine_store_cjs_1.resolveMachineIdentity)(baseConfig.configDir, baseConfig.apiBase);
|
|
211
237
|
const config = configFromFlags(flags, identity);
|
|
238
|
+
warnUnknownRuntimes(config);
|
|
212
239
|
const api = new api_cjs_1.NavarchApiClient({ baseUrl: identity.api_base, token: identity.token });
|
|
213
240
|
const capacity = new capacity_cjs_1.CapacityTracker(config.maxSessions);
|
|
214
241
|
const runtimeShutdown = new AbortController();
|
|
@@ -287,6 +314,7 @@ async function superviseCommand(flags) {
|
|
|
287
314
|
const baseConfig = configFromFlags(flags);
|
|
288
315
|
const identity = await (0, machine_store_cjs_1.resolveMachineIdentity)(baseConfig.configDir, baseConfig.apiBase);
|
|
289
316
|
const config = configFromFlags(flags, identity);
|
|
317
|
+
warnUnknownRuntimes(config);
|
|
290
318
|
// Resolve and pin the adapter before spawning the worker. The supervisor
|
|
291
319
|
// passes machine credentials through the environment, so the child no
|
|
292
320
|
// longer reads machine.json for identity fields (including agent_type).
|
|
@@ -325,8 +353,15 @@ async function doctorCommand(flags) {
|
|
|
325
353
|
}
|
|
326
354
|
if (identity)
|
|
327
355
|
config = configFromFlags(flags, identity);
|
|
356
|
+
warnUnknownRuntimes(config);
|
|
328
357
|
}
|
|
329
358
|
catch (err) {
|
|
359
|
+
// The typo may be why the config is unusable (e.g. `opencode,gemni` on a
|
|
360
|
+
// guarded host leaves only OpenCode), so still name it.
|
|
361
|
+
warnUnknownRuntimes({
|
|
362
|
+
supervised: process.env.NAVARCH_SUPERVISED === "1",
|
|
363
|
+
unknownRuntimes: (0, config_cjs_1.unknownRuntimeIds)(process.env),
|
|
364
|
+
});
|
|
330
365
|
console.log(`config: UNUSABLE — ${err instanceof Error ? err.message : String(err)}`);
|
|
331
366
|
process.exitCode = 1;
|
|
332
367
|
return;
|
|
@@ -353,12 +388,12 @@ function helpText() {
|
|
|
353
388
|
|
|
354
389
|
Usage:
|
|
355
390
|
navarch-runtime register --token <enrollment-token> --name <machine-name> \\
|
|
356
|
-
[--config-dir <path>] [--agent
|
|
391
|
+
[--config-dir <path>] [--agent ${AGENT_TYPE_USAGE}] [--model <model>] [--capabilities a,b] [--max-sessions N] [--owner-zone z] [--api-base url]
|
|
357
392
|
navarch-runtime connect --token <enrollment-token> --name <machine-name> \\
|
|
358
|
-
[--config-dir <path>] [--agent
|
|
359
|
-
navarch-runtime start [--config-dir <path>] [--agent
|
|
360
|
-
navarch-runtime supervise [--config-dir <path>] [--agent
|
|
361
|
-
navarch-runtime doctor [--config-dir <path>]
|
|
393
|
+
[--config-dir <path>] [--agent ${AGENT_TYPE_USAGE}] [--model <model>] [--project <project-id>] [--capabilities a,b] [--max-sessions N] [--api-base url]
|
|
394
|
+
navarch-runtime start [--config-dir <path>] [--agent ${AGENT_TYPE_USAGE}] [--model <model>]
|
|
395
|
+
navarch-runtime supervise [--config-dir <path>] [--agent ${AGENT_TYPE_USAGE}] [--model <model>]
|
|
396
|
+
navarch-runtime doctor [--config-dir <path>] [--agent ${AGENT_TYPE_USAGE}]
|
|
362
397
|
navarch-runtime code-graph --query <symbol-or-file> [--mode search|callers|callees|impact] [--commit HEAD] [--depth 1..5] [--repo <path>]
|
|
363
398
|
|
|
364
399
|
Use a different --config-dir (or NAVARCH_CONFIG_DIR) for every agent instance.
|
package/dist/config.cjs
CHANGED
|
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.OPENCODE_HOST_GUARD_MESSAGE = exports.DEFAULT_SANDBOX_IMAGE = void 0;
|
|
6
|
+
exports.OPENCODE_HOST_GUARD_MESSAGE = exports.RUNTIME_AGENT_TYPES = exports.DEFAULT_SANDBOX_IMAGE = void 0;
|
|
7
7
|
exports.isRuntimeAgentType = isRuntimeAgentType;
|
|
8
|
+
exports.unknownRuntimeIds = unknownRuntimeIds;
|
|
8
9
|
exports.opencodeBlockedOnHost = opencodeBlockedOnHost;
|
|
9
10
|
exports.loadRuntimeConfig = loadRuntimeConfig;
|
|
10
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -12,13 +13,26 @@ const node_os_1 = __importDefault(require("node:os"));
|
|
|
12
13
|
const sandbox_profile_cjs_1 = require("./sandbox-profile.cjs");
|
|
13
14
|
/** Published image containing git, GitHub CLI, and the pinned Claude Code CLI. */
|
|
14
15
|
exports.DEFAULT_SANDBOX_IMAGE = "ghcr.io/sagentlab/navarch-sandbox-agent:0.1.0";
|
|
16
|
+
/**
|
|
17
|
+
* Adapter ids the runtime accepts for `NAVARCH_AGENT` / `--agent`, in display
|
|
18
|
+
* order. `NAVARCH_RUNTIMES` is validated against this same list, and the CLI
|
|
19
|
+
* usage/error copy is generated from it so the advertised set cannot drift.
|
|
20
|
+
*/
|
|
21
|
+
exports.RUNTIME_AGENT_TYPES = [
|
|
22
|
+
"claude-code",
|
|
23
|
+
"codex",
|
|
24
|
+
"gemini",
|
|
25
|
+
"opencode",
|
|
26
|
+
"acp",
|
|
27
|
+
"qoder",
|
|
28
|
+
];
|
|
15
29
|
function isRuntimeAgentType(value) {
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
return typeof value === "string" && exports.RUNTIME_AGENT_TYPES.includes(value);
|
|
31
|
+
}
|
|
32
|
+
/** Unrecognized ids in NAVARCH_RUNTIMES, deduplicated, in the order given. */
|
|
33
|
+
function unknownRuntimeIds(env) {
|
|
34
|
+
const ids = envList(env, "NAVARCH_RUNTIMES", []);
|
|
35
|
+
return [...new Set(ids.filter((runtime) => !isRuntimeAgentType(runtime)))];
|
|
22
36
|
}
|
|
23
37
|
function envInt(env, name, fallback) {
|
|
24
38
|
const raw = env[name];
|
|
@@ -82,7 +96,11 @@ function loadRuntimeConfig(env = process.env) {
|
|
|
82
96
|
// Multiple sessions share one machine; keeping each agent inside its own
|
|
83
97
|
// worktree is the safe default, so disabling is the explicit opt-out.
|
|
84
98
|
const worktreeGuard = !["off", "false", "0"].includes(env.NAVARCH_WORKTREE_GUARD ?? "");
|
|
85
|
-
const
|
|
99
|
+
const requestedRuntimeIds = envList(env, "NAVARCH_RUNTIMES", [requestedAgentType]);
|
|
100
|
+
// Keep unknown ids visible so a typo surfaces (CLI warns) instead of the
|
|
101
|
+
// machine quietly shrinking the adapters it advertises.
|
|
102
|
+
const unknownRuntimes = unknownRuntimeIds(env);
|
|
103
|
+
const requestedRuntimes = requestedRuntimeIds.filter(isRuntimeAgentType);
|
|
86
104
|
// OpenCode's CLI cannot express the host worktree boundary, so its adapter
|
|
87
105
|
// fails closed there (adapters/opencode.cts). Advertising it anyway meant
|
|
88
106
|
// the machine claimed OpenCode tasks it could only fail, one lease at a
|
|
@@ -114,6 +132,7 @@ function loadRuntimeConfig(env = process.env) {
|
|
|
114
132
|
worktreeStaleAfterMs: envInt(env, "NAVARCH_WORKTREE_STALE_AFTER_MS", 24 * 60 * 60 * 1000),
|
|
115
133
|
agentType,
|
|
116
134
|
runtimes: runtimes.length > 0 ? runtimes : [agentType],
|
|
135
|
+
unknownRuntimes,
|
|
117
136
|
claudeBin: env.NAVARCH_CLAUDE_BIN ?? "claude",
|
|
118
137
|
claudeExtraArgs: envList(env, "NAVARCH_CLAUDE_EXTRA_ARGS", []),
|
|
119
138
|
codexBin: env.NAVARCH_CODEX_BIN ?? "codex",
|
package/dist/machine-store.cjs
CHANGED
|
@@ -8,6 +8,7 @@ exports.loadMachineIdentity = loadMachineIdentity;
|
|
|
8
8
|
exports.resolveMachineIdentity = resolveMachineIdentity;
|
|
9
9
|
const node_fs_1 = require("node:fs");
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const config_cjs_1 = require("./config.cjs");
|
|
11
12
|
function storePath(configDir) {
|
|
12
13
|
return node_path_1.default.join(configDir, "machine.json");
|
|
13
14
|
}
|
|
@@ -48,12 +49,10 @@ async function resolveMachineIdentity(configDir, apiBaseFallback) {
|
|
|
48
49
|
token: envToken,
|
|
49
50
|
name: process.env.NAVARCH_MACHINE_NAME ?? envId,
|
|
50
51
|
api_base: process.env.NAVARCH_API_BASE ?? apiBaseFallback,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
process.env.NAVARCH_AGENT === "acp" ||
|
|
56
|
-
process.env.NAVARCH_AGENT === "qoder"
|
|
52
|
+
// Validate against the one accepted adapter list so a new adapter cannot
|
|
53
|
+
// be added to `--agent`/NAVARCH_AGENT while this env-based identity path
|
|
54
|
+
// silently drops it.
|
|
55
|
+
agent_type: (0, config_cjs_1.isRuntimeAgentType)(process.env.NAVARCH_AGENT)
|
|
57
56
|
? process.env.NAVARCH_AGENT
|
|
58
57
|
: undefined,
|
|
59
58
|
};
|
package/package.json
CHANGED