agent-relay-server 0.6.0 → 0.7.0
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/package.json +3 -1
- package/public/dashboard/actions.js +819 -0
- package/public/dashboard/api.js +336 -0
- package/public/dashboard/app.js +34 -0
- package/public/dashboard/charts.js +128 -0
- package/public/dashboard/computed.js +693 -0
- package/public/dashboard/constants.js +28 -0
- package/public/dashboard/display.js +345 -0
- package/public/dashboard/state.js +129 -0
- package/public/dashboard/utils.js +207 -0
- package/public/index.html +61 -41
- package/scripts/orchestrator-spawn-smoke.ts +140 -0
- package/src/cli.ts +5 -4
- package/src/config.ts +1 -0
- package/src/db.ts +205 -23
- package/src/routes.ts +74 -48
- package/src/types.ts +33 -0
- package/src/upgrade.ts +80 -7
- package/public/dashboard.js +0 -3019
package/src/upgrade.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { VERSION } from "./config";
|
|
5
5
|
|
|
6
|
-
export type UpgradeProvider = "auto" | "all" | "codex" | "claude";
|
|
6
|
+
export type UpgradeProvider = "auto" | "all" | "codex" | "claude" | "orchestrator";
|
|
7
7
|
|
|
8
8
|
type UpgradeOptions = {
|
|
9
9
|
targetVersion?: string;
|
|
@@ -28,12 +28,16 @@ export type UpgradeSnapshot = {
|
|
|
28
28
|
targetVersion: string;
|
|
29
29
|
serverPackage?: InstalledPackage;
|
|
30
30
|
codexPackage?: InstalledPackage;
|
|
31
|
+
orchestratorPackage?: InstalledPackage;
|
|
31
32
|
codexCopiedPackage?: InstalledPackage;
|
|
32
33
|
claudePluginInstalls: ClaudePluginInstall[];
|
|
33
34
|
hasCodexCommand: boolean;
|
|
35
|
+
hasOrchestratorCommand: boolean;
|
|
34
36
|
hasClaudeCommand: boolean;
|
|
35
37
|
hasSystemdUserService: boolean;
|
|
38
|
+
hasSystemdUserOrchestratorService: boolean;
|
|
36
39
|
runningServerVersion?: string;
|
|
40
|
+
runningOrchestrators?: Array<{ id: string; version?: string; protocolVersion?: number; health?: { status?: string; restartRequired?: boolean } }>;
|
|
37
41
|
packageManager: "bun" | "npm" | "none";
|
|
38
42
|
};
|
|
39
43
|
|
|
@@ -46,7 +50,7 @@ type UpgradeAction = {
|
|
|
46
50
|
|
|
47
51
|
type UpgradePlan = {
|
|
48
52
|
targetVersion: string;
|
|
49
|
-
providers: { codex: boolean; claude: boolean };
|
|
53
|
+
providers: { codex: boolean; claude: boolean; orchestrator: boolean };
|
|
50
54
|
snapshot: UpgradeSnapshot;
|
|
51
55
|
actions: UpgradeAction[];
|
|
52
56
|
warnings: string[];
|
|
@@ -67,9 +71,9 @@ export async function detectUpgradeSnapshot(options: UpgradeOptions = {}): Promi
|
|
|
67
71
|
const codexCopiedPackage = readPackageVersion(join(homeDir(), ".agent-relay", "codex", "package", "package.json"));
|
|
68
72
|
const claudePluginInstalls = readClaudePluginInstalls(join(homeDir(), ".claude", "plugins", "installed_plugins.json"));
|
|
69
73
|
|
|
70
|
-
const packageManager = bunPackages.has("agent-relay-server") || bunPackages.has("agent-relay-codex")
|
|
74
|
+
const packageManager = bunPackages.has("agent-relay-server") || bunPackages.has("agent-relay-codex") || bunPackages.has("agent-relay-orchestrator")
|
|
71
75
|
? "bun"
|
|
72
|
-
: npmPackages.has("agent-relay-server") || npmPackages.has("agent-relay-codex")
|
|
76
|
+
: npmPackages.has("agent-relay-server") || npmPackages.has("agent-relay-codex") || npmPackages.has("agent-relay-orchestrator")
|
|
73
77
|
? "npm"
|
|
74
78
|
: commandExists("bun")
|
|
75
79
|
? "bun"
|
|
@@ -81,14 +85,18 @@ export async function detectUpgradeSnapshot(options: UpgradeOptions = {}): Promi
|
|
|
81
85
|
targetVersion,
|
|
82
86
|
serverPackage: installedPackage("agent-relay-server", bunPackages, npmPackages),
|
|
83
87
|
codexPackage: installedPackage("agent-relay-codex", bunPackages, npmPackages),
|
|
88
|
+
orchestratorPackage: installedPackage("agent-relay-orchestrator", bunPackages, npmPackages),
|
|
84
89
|
codexCopiedPackage: codexCopiedPackage
|
|
85
90
|
? { version: codexCopiedPackage, source: "copied", path: join(homeDir(), ".agent-relay", "codex", "package") }
|
|
86
91
|
: undefined,
|
|
87
92
|
claudePluginInstalls,
|
|
88
93
|
hasCodexCommand: commandExists("agent-relay-codex") || commandExists("codex-relay") || existsSync(join(homeDir(), ".agent-relay", "codex", "package")),
|
|
94
|
+
hasOrchestratorCommand: commandExists("agent-relay-orchestrator"),
|
|
89
95
|
hasClaudeCommand: commandExists("claude"),
|
|
90
96
|
hasSystemdUserService: hasSystemdUserService("agent-relay.service"),
|
|
97
|
+
hasSystemdUserOrchestratorService: hasSystemdUserService("agent-relay-orchestrator.service"),
|
|
91
98
|
runningServerVersion: await runningServerVersion(),
|
|
99
|
+
runningOrchestrators: await runningOrchestrators(),
|
|
92
100
|
packageManager,
|
|
93
101
|
};
|
|
94
102
|
}
|
|
@@ -99,6 +107,7 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
99
107
|
const providerSet = new Set(requestedProviders);
|
|
100
108
|
const codexRequested = providerSet.has("all") || providerSet.has("codex") || (providerSet.has("auto") && isCodexDetected(snapshot));
|
|
101
109
|
const claudeRequested = providerSet.has("all") || providerSet.has("claude") || (providerSet.has("auto") && isClaudeRelayDetected(snapshot));
|
|
110
|
+
const orchestratorRequested = providerSet.has("all") || providerSet.has("orchestrator") || (providerSet.has("auto") && isOrchestratorDetected(snapshot));
|
|
102
111
|
const actions: UpgradeAction[] = [];
|
|
103
112
|
const warnings: string[] = [];
|
|
104
113
|
|
|
@@ -107,13 +116,14 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
107
116
|
} else {
|
|
108
117
|
const packages = [`agent-relay-server@${targetVersion}`];
|
|
109
118
|
if (codexRequested) packages.push(`agent-relay-codex@${targetVersion}`);
|
|
119
|
+
if (orchestratorRequested) packages.push(`agent-relay-orchestrator@${targetVersion}`);
|
|
110
120
|
const command = snapshot.packageManager === "bun"
|
|
111
121
|
? ["bun", "add", "-g", ...packages]
|
|
112
122
|
: ["npm", "install", "-g", ...packages];
|
|
113
123
|
actions.push({
|
|
114
124
|
label: "Upgrade global packages",
|
|
115
125
|
command,
|
|
116
|
-
reason: `Update server${codexRequested ? "
|
|
126
|
+
reason: `Update server${codexRequested ? ", Codex integration" : ""}${orchestratorRequested ? ", and orchestrator" : ""} packages to ${targetVersion}.`,
|
|
117
127
|
mutates: true,
|
|
118
128
|
});
|
|
119
129
|
}
|
|
@@ -148,6 +158,10 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
148
158
|
warnings.push("Claude Agent Relay plugin not detected; skipping Claude plugin upgrade.");
|
|
149
159
|
}
|
|
150
160
|
|
|
161
|
+
if (!orchestratorRequested && providerSet.has("auto") && !isOrchestratorDetected(snapshot)) {
|
|
162
|
+
warnings.push("Agent Relay orchestrator not detected; skipping orchestrator package upgrade.");
|
|
163
|
+
}
|
|
164
|
+
|
|
151
165
|
if (snapshot.hasSystemdUserService) {
|
|
152
166
|
if (options.noRestart) {
|
|
153
167
|
warnings.push("agent-relay.service detected but --no-restart was set; restart manually to run the upgraded server.");
|
|
@@ -163,9 +177,24 @@ export function createUpgradePlan(snapshot: UpgradeSnapshot, options: UpgradeOpt
|
|
|
163
177
|
warnings.push("No systemd user service detected; restart any manually running Agent Relay server yourself.");
|
|
164
178
|
}
|
|
165
179
|
|
|
180
|
+
if (snapshot.hasSystemdUserOrchestratorService) {
|
|
181
|
+
if (options.noRestart) {
|
|
182
|
+
warnings.push("agent-relay-orchestrator.service detected but --no-restart was set; restart manually to run the upgraded orchestrator.");
|
|
183
|
+
} else {
|
|
184
|
+
actions.push({
|
|
185
|
+
label: "Restart Agent Relay orchestrator service",
|
|
186
|
+
command: ["systemctl", "--user", "restart", "agent-relay-orchestrator.service"],
|
|
187
|
+
reason: "Restart orchestrator daemon so host lifecycle control uses the upgraded protocol.",
|
|
188
|
+
mutates: true,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
} else if (orchestratorRequested) {
|
|
192
|
+
warnings.push("No agent-relay-orchestrator.service detected; restart any manually running orchestrator yourself.");
|
|
193
|
+
}
|
|
194
|
+
|
|
166
195
|
return {
|
|
167
196
|
targetVersion,
|
|
168
|
-
providers: { codex: codexRequested, claude: claudeRequested },
|
|
197
|
+
providers: { codex: codexRequested, claude: claudeRequested, orchestrator: orchestratorRequested },
|
|
169
198
|
snapshot: { ...snapshot, targetVersion },
|
|
170
199
|
actions,
|
|
171
200
|
warnings,
|
|
@@ -194,6 +223,15 @@ export async function executeUpgradePlan(plan: UpgradePlan, options: { dryRun?:
|
|
|
194
223
|
}
|
|
195
224
|
if (serverVersion) lines.push(`Running server: ${serverVersion}`);
|
|
196
225
|
}
|
|
226
|
+
if (plan.actions.some((action) => action.command.join(" ") === "systemctl --user restart agent-relay-orchestrator.service")) {
|
|
227
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
228
|
+
const orchestrators = await runningOrchestrators() ?? [];
|
|
229
|
+
const mismatched = orchestrators.filter((orch) => orch.version && orch.version !== plan.targetVersion);
|
|
230
|
+
if (mismatched.length > 0) {
|
|
231
|
+
throw new Error(`agent-relay-orchestrator.service restarted but ${mismatched.map((orch) => `${orch.id} reports ${orch.version}`).join(", ")}, expected ${plan.targetVersion}`);
|
|
232
|
+
}
|
|
233
|
+
if (orchestrators.length > 0) lines.push(`Running orchestrator(s): ${orchestrators.map((orch) => `${orch.id}${orch.version ? ` ${orch.version}` : ""}`).join(", ")}`);
|
|
234
|
+
}
|
|
197
235
|
lines.push("\nUpgrade commands completed.");
|
|
198
236
|
if (plan.warnings.length > 0) {
|
|
199
237
|
lines.push("\nWarnings:");
|
|
@@ -211,11 +249,14 @@ export function formatUpgradePlan(plan: UpgradePlan, options: { dryRun?: boolean
|
|
|
211
249
|
`- running server: ${plan.snapshot.runningServerVersion ?? "unknown"}`,
|
|
212
250
|
`- codex package: ${formatPackage(plan.snapshot.codexPackage)}`,
|
|
213
251
|
`- codex copied package: ${formatPackage(plan.snapshot.codexCopiedPackage)}`,
|
|
252
|
+
`- orchestrator package: ${formatPackage(plan.snapshot.orchestratorPackage)}`,
|
|
253
|
+
`- running orchestrators: ${formatRunningOrchestrators(plan.snapshot.runningOrchestrators)}`,
|
|
214
254
|
`- claude command: ${plan.snapshot.hasClaudeCommand ? "yes" : "no"}`,
|
|
215
255
|
`- claude agent-relay plugin: ${formatClaudePlugins(plan.snapshot.claudePluginInstalls)}`,
|
|
216
256
|
`- systemd user service: ${plan.snapshot.hasSystemdUserService ? "yes" : "no"}`,
|
|
257
|
+
`- orchestrator systemd user service: ${plan.snapshot.hasSystemdUserOrchestratorService ? "yes" : "no"}`,
|
|
217
258
|
"",
|
|
218
|
-
`Providers: codex=${plan.providers.codex ? "yes" : "no"}, claude=${plan.providers.claude ? "yes" : "no"}`,
|
|
259
|
+
`Providers: codex=${plan.providers.codex ? "yes" : "no"}, claude=${plan.providers.claude ? "yes" : "no"}, orchestrator=${plan.providers.orchestrator ? "yes" : "no"}`,
|
|
219
260
|
"",
|
|
220
261
|
"Actions:",
|
|
221
262
|
];
|
|
@@ -239,6 +280,10 @@ function isClaudeRelayDetected(snapshot: UpgradeSnapshot): boolean {
|
|
|
239
280
|
return snapshot.claudePluginInstalls.length > 0;
|
|
240
281
|
}
|
|
241
282
|
|
|
283
|
+
function isOrchestratorDetected(snapshot: UpgradeSnapshot): boolean {
|
|
284
|
+
return Boolean(snapshot.orchestratorPackage || snapshot.hasOrchestratorCommand || snapshot.hasSystemdUserOrchestratorService || (snapshot.runningOrchestrators?.length ?? 0) > 0);
|
|
285
|
+
}
|
|
286
|
+
|
|
242
287
|
function installedPackage(name: string, bunPackages: Map<string, string>, npmPackages: Map<string, string>): InstalledPackage | undefined {
|
|
243
288
|
const bunVersion = bunPackages.get(name);
|
|
244
289
|
if (bunVersion) return { version: bunVersion, source: "bun" };
|
|
@@ -292,6 +337,27 @@ async function runningServerVersion(): Promise<string | undefined> {
|
|
|
292
337
|
}
|
|
293
338
|
}
|
|
294
339
|
|
|
340
|
+
async function runningOrchestrators(): Promise<UpgradeSnapshot["runningOrchestrators"]> {
|
|
341
|
+
try {
|
|
342
|
+
const headers: Record<string, string> = {};
|
|
343
|
+
if (process.env.AGENT_RELAY_TOKEN) headers["X-Agent-Relay-Token"] = process.env.AGENT_RELAY_TOKEN;
|
|
344
|
+
const relayUrl = (process.env.AGENT_RELAY_URL || "http://127.0.0.1:4850").replace(/\/+$/, "");
|
|
345
|
+
const response = await fetch(`${relayUrl}/api/orchestrators`, { headers });
|
|
346
|
+
if (!response.ok) return [];
|
|
347
|
+
const payload = await response.json() as Array<{ id?: string; version?: string; protocolVersion?: number; health?: { status?: string; restartRequired?: boolean } }>;
|
|
348
|
+
return payload
|
|
349
|
+
.filter((orch) => typeof orch.id === "string")
|
|
350
|
+
.map((orch) => ({
|
|
351
|
+
id: orch.id!,
|
|
352
|
+
version: orch.version,
|
|
353
|
+
protocolVersion: orch.protocolVersion,
|
|
354
|
+
health: orch.health,
|
|
355
|
+
}));
|
|
356
|
+
} catch {
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
295
361
|
function hasSystemdUserService(name: string): boolean {
|
|
296
362
|
if (!commandExists("systemctl")) return false;
|
|
297
363
|
const result = runCommand(["systemctl", "--user", "status", name, "--no-pager"]);
|
|
@@ -372,6 +438,13 @@ function formatClaudePlugins(installs: ClaudePluginInstall[]): string {
|
|
|
372
438
|
return installs.map((install) => `${install.version ?? "unknown"} (${install.scope ?? "user"})`).join(", ");
|
|
373
439
|
}
|
|
374
440
|
|
|
441
|
+
function formatRunningOrchestrators(orchestrators: UpgradeSnapshot["runningOrchestrators"]): string {
|
|
442
|
+
if (!orchestrators?.length) return "not detected";
|
|
443
|
+
return orchestrators
|
|
444
|
+
.map((orch) => `${orch.id}: ${orch.version ?? "unknown"}${orch.health?.restartRequired ? " (restart required)" : ""}`)
|
|
445
|
+
.join(", ");
|
|
446
|
+
}
|
|
447
|
+
|
|
375
448
|
function shellQuote(value: string): string {
|
|
376
449
|
if (/^[a-zA-Z0-9_@%+=:,./-]+$/.test(value)) return value;
|
|
377
450
|
return `'${value.replaceAll("'", "'\\''")}'`;
|