agent-relay-server 0.32.4 → 0.33.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.
Files changed (101) hide show
  1. package/package.json +2 -2
  2. package/public/assets/{activity-DT1JGHnp.js → activity-B0_uE6Yh.js} +2 -2
  3. package/public/assets/{activity-DT1JGHnp.js.map → activity-B0_uE6Yh.js.map} +1 -1
  4. package/public/assets/{agent-profiles-CrMemMkZ.js → agent-profiles-Rwxrcf9F.js} +2 -2
  5. package/public/assets/{agent-profiles-CrMemMkZ.js.map → agent-profiles-Rwxrcf9F.js.map} +1 -1
  6. package/public/assets/{agents-Bl-rrgOy.js → agents-Dp1EXJc8.js} +2 -2
  7. package/public/assets/{agents-Bl-rrgOy.js.map → agents-Dp1EXJc8.js.map} +1 -1
  8. package/public/assets/{analytics-a663ak56.js → analytics-D5OT5ajj.js} +2 -2
  9. package/public/assets/{analytics-a663ak56.js.map → analytics-D5OT5ajj.js.map} +1 -1
  10. package/public/assets/automation-Dm6rXNxK.js +2 -0
  11. package/public/assets/{automation-CiaLThdO.js.map → automation-Dm6rXNxK.js.map} +1 -1
  12. package/public/assets/{branch-state-badge-D4ur3m3_.js → branch-state-badge-FX5Yww2s.js} +2 -2
  13. package/public/assets/{branch-state-badge-D4ur3m3_.js.map → branch-state-badge-FX5Yww2s.js.map} +1 -1
  14. package/public/assets/{channels-o9KLTHoK.js → channels--rdAiX17.js} +2 -2
  15. package/public/assets/{channels-o9KLTHoK.js.map → channels--rdAiX17.js.map} +1 -1
  16. package/public/assets/chat-JZAEDGfX.js +2 -0
  17. package/public/assets/chat-JZAEDGfX.js.map +1 -0
  18. package/public/assets/{connectors-CdC806mA.js → connectors-Bx4gzvNf.js} +2 -2
  19. package/public/assets/{connectors-CdC806mA.js.map → connectors-Bx4gzvNf.js.map} +1 -1
  20. package/public/assets/display-Bebqs1qu.js +3 -0
  21. package/public/assets/display-Bebqs1qu.js.map +1 -0
  22. package/public/assets/{formatted-body-impl-Ca74OAEH.js → formatted-body-impl-CVq4qHix.js} +2 -2
  23. package/public/assets/{formatted-body-impl-Ca74OAEH.js.map → formatted-body-impl-CVq4qHix.js.map} +1 -1
  24. package/public/assets/{index-C_33ymaw.js → index-BHRtR4q7.js} +8 -8
  25. package/public/assets/{index-C_33ymaw.js.map → index-BHRtR4q7.js.map} +1 -1
  26. package/public/assets/{insights-ClI68s39.js → insights-yJFgCa3o.js} +2 -2
  27. package/public/assets/{insights-ClI68s39.js.map → insights-yJFgCa3o.js.map} +1 -1
  28. package/public/assets/{integrations-1nxMizDY.js → integrations-k1HIONjo.js} +2 -2
  29. package/public/assets/{integrations-1nxMizDY.js.map → integrations-k1HIONjo.js.map} +1 -1
  30. package/public/assets/maintenance-CsoOFBXx.js +2 -0
  31. package/public/assets/{maintenance-DiFNzNPN.js.map → maintenance-CsoOFBXx.js.map} +1 -1
  32. package/public/assets/{managed-agents-Do3dKvfj.js → managed-agents-Q3HuVjGg.js} +2 -2
  33. package/public/assets/{managed-agents-Do3dKvfj.js.map → managed-agents-Q3HuVjGg.js.map} +1 -1
  34. package/public/assets/{markdown-preview-impl-CLA0J255.js → markdown-preview-impl-CnsMjrnu.js} +2 -2
  35. package/public/assets/{markdown-preview-impl-CLA0J255.js.map → markdown-preview-impl-CnsMjrnu.js.map} +1 -1
  36. package/public/assets/{memory-IjwqFzBd.js → memory-D3-K5eJS.js} +2 -2
  37. package/public/assets/{memory-IjwqFzBd.js.map → memory-D3-K5eJS.js.map} +1 -1
  38. package/public/assets/{messages-DjvWqHyn.js → messages-B4lCP5rS.js} +2 -2
  39. package/public/assets/{messages-DjvWqHyn.js.map → messages-B4lCP5rS.js.map} +1 -1
  40. package/public/assets/{orchestrators-D2IqDxDT.js → orchestrators-CRoZtLeQ.js} +2 -2
  41. package/public/assets/{orchestrators-D2IqDxDT.js.map → orchestrators-CRoZtLeQ.js.map} +1 -1
  42. package/public/assets/{overview-DKC3TbAh.js → overview-CxCU2fOF.js} +2 -2
  43. package/public/assets/{overview-DKC3TbAh.js.map → overview-CxCU2fOF.js.map} +1 -1
  44. package/public/assets/pairs-unqjPlmq.js +2 -0
  45. package/public/assets/{pairs-WpKCPE1n.js.map → pairs-unqjPlmq.js.map} +1 -1
  46. package/public/assets/{security-BF7ZtPQe.js → security-B7HhSYNy.js} +2 -2
  47. package/public/assets/{security-BF7ZtPQe.js.map → security-B7HhSYNy.js.map} +1 -1
  48. package/public/assets/{settings-CQnjrTa-.js → settings-B9NDhsAb.js} +2 -2
  49. package/public/assets/{settings-CQnjrTa-.js.map → settings-B9NDhsAb.js.map} +1 -1
  50. package/public/assets/store-DiSzYHj9.js +9 -0
  51. package/public/assets/{store-C9VcSo05.js.map → store-DiSzYHj9.js.map} +1 -1
  52. package/public/assets/{tasks-CbN_GSSb.js → tasks-CIQolvNm.js} +2 -2
  53. package/public/assets/{tasks-CbN_GSSb.js.map → tasks-CIQolvNm.js.map} +1 -1
  54. package/public/assets/{terminal-viewer-impl-BJRohThT.js → terminal-viewer-impl-DCifVqFR.js} +2 -2
  55. package/public/assets/{terminal-viewer-impl-BJRohThT.js.map → terminal-viewer-impl-DCifVqFR.js.map} +1 -1
  56. package/public/assets/{work-queue-C5xLBLmm.js → work-queue-Dr3c1V6O.js} +2 -2
  57. package/public/assets/{work-queue-C5xLBLmm.js.map → work-queue-Dr3c1V6O.js.map} +1 -1
  58. package/public/assets/{workspaces-D91H3wDX.js → workspaces-B1Jxop7h.js} +3 -3
  59. package/public/assets/{workspaces-D91H3wDX.js.map → workspaces-B1Jxop7h.js.map} +1 -1
  60. package/public/index.html +3 -3
  61. package/runner/src/adapter.ts +1 -1
  62. package/src/agent-lifecycle-events.ts +137 -0
  63. package/src/artifact-storage.ts +3 -5
  64. package/src/cli/_shared.ts +80 -0
  65. package/src/cli/agent-detect.ts +188 -0
  66. package/src/cli/agent-meta.ts +95 -0
  67. package/src/cli/context-probe.ts +88 -0
  68. package/src/cli/daemon.ts +111 -0
  69. package/src/cli/dev.ts +173 -0
  70. package/src/cli/index.ts +361 -0
  71. package/src/cli/introspect.ts +73 -0
  72. package/src/cli/memory.ts +37 -0
  73. package/src/cli/message.ts +201 -0
  74. package/src/cli/orchestrator.ts +227 -0
  75. package/src/cli/pair.ts +125 -0
  76. package/src/cli/provider.ts +209 -0
  77. package/src/cli/recipe.ts +110 -0
  78. package/src/cli/reply.ts +141 -0
  79. package/src/cli/setup.ts +57 -0
  80. package/src/cli/steward.ts +59 -0
  81. package/src/cli/token.ts +81 -0
  82. package/src/cli/upgrade.ts +193 -0
  83. package/src/cli/workspace.ts +215 -0
  84. package/src/cli.ts +4 -2718
  85. package/src/config-store.ts +10 -6
  86. package/src/maintenance.ts +4 -0
  87. package/src/mcp-errors.ts +7 -0
  88. package/src/mcp.ts +32 -34
  89. package/src/routes/agents-spawn.ts +9 -1
  90. package/src/routes/agents.ts +5 -0
  91. package/src/routes/commands.ts +15 -0
  92. package/src/spawn-targets.ts +159 -0
  93. package/src/utils.ts +16 -1
  94. package/public/assets/automation-CiaLThdO.js +0 -2
  95. package/public/assets/chat-5hvHZcAe.js +0 -2
  96. package/public/assets/chat-5hvHZcAe.js.map +0 -1
  97. package/public/assets/display-JI19Vc7L.js +0 -3
  98. package/public/assets/display-JI19Vc7L.js.map +0 -1
  99. package/public/assets/maintenance-DiFNzNPN.js +0 -2
  100. package/public/assets/pairs-WpKCPE1n.js +0 -2
  101. package/public/assets/store-C9VcSo05.js +0 -9
@@ -0,0 +1,111 @@
1
+ // Daemon command — auto-split from cli.ts (#294). Installs/manages the relay
2
+ // server as a user/system service.
3
+ import {
4
+ createDaemonPlan,
5
+ detectDaemonEnvironment,
6
+ executeDaemonPlan,
7
+ formatDaemonPlan,
8
+ type DaemonAction,
9
+ type DaemonScope,
10
+ } from "../daemon";
11
+ import { createSetupPlan, executeSetupPlan, pathExists } from "../setup";
12
+ import { confirm } from "./_shared";
13
+
14
+ const DAEMON_ACTIONS = new Set<DaemonAction>([
15
+ "install",
16
+ "uninstall",
17
+ "start",
18
+ "stop",
19
+ "restart",
20
+ "enable",
21
+ "disable",
22
+ "status",
23
+ "logs",
24
+ ]);
25
+
26
+ export async function handleDaemonCommand(args: string[]): Promise<void> {
27
+ const action = parseDaemonAction(args[0]);
28
+ let name: string | undefined;
29
+ let envFile: string | undefined;
30
+ let port: number | undefined;
31
+ let host: string | undefined;
32
+ let scope: DaemonScope | undefined;
33
+ let binaryPath: string | undefined;
34
+ let runtimePrefix: string | undefined;
35
+ const pathPrefix: string[] = [];
36
+ let start = false;
37
+ let enable = false;
38
+ let dryRun = false;
39
+ let force = false;
40
+ let yes = false;
41
+ let json = false;
42
+
43
+ for (let i = 1; i < args.length; i++) {
44
+ const arg = args[i];
45
+ if (arg === "--name" && i + 1 < args.length) name = args[++i];
46
+ else if (arg === "--env-file" && i + 1 < args.length) envFile = args[++i];
47
+ else if (arg === "--port" && i + 1 < args.length) port = parseInt(args[++i]!, 10);
48
+ else if (arg === "--host" && i + 1 < args.length) host = args[++i];
49
+ else if (arg === "--user") scope = "user";
50
+ else if (arg === "--system") scope = "system";
51
+ else if (arg === "--binary" && i + 1 < args.length) binaryPath = args[++i];
52
+ else if (arg === "--runtime-prefix" && i + 1 < args.length) runtimePrefix = args[++i];
53
+ else if (arg === "--path-prefix" && i + 1 < args.length) pathPrefix.push(args[++i]!);
54
+ else if (arg === "--start") start = true;
55
+ else if (arg === "--enable") enable = true;
56
+ else if (arg === "--dry-run") dryRun = true;
57
+ else if (arg === "--force") force = true;
58
+ else if (arg === "--yes") yes = true;
59
+ else if (arg === "--json") json = true;
60
+ else throw new Error(`Unknown daemon option "${arg}"`);
61
+ }
62
+
63
+ if (action === "install" && !dryRun && !envFile && !(await pathExists(createSetupPlan().envFile))) {
64
+ const setupPlan = createSetupPlan({
65
+ ...(host ? { host } : {}),
66
+ ...(port !== undefined ? { port } : {}),
67
+ ...(runtimePrefix ? { runtimePrefix } : {}),
68
+ });
69
+ const ok = yes || await confirm(`Create daemon env file at ${setupPlan.envFile}?`);
70
+ if (!ok) throw new Error("Daemon install needs an env file. Run `agent-relay setup` first.");
71
+ console.log(await executeSetupPlan(setupPlan, { force }));
72
+ }
73
+
74
+ const env = await detectDaemonEnvironment();
75
+ const plan = createDaemonPlan({
76
+ action,
77
+ ...(name ? { name } : {}),
78
+ ...(envFile ? { envFile } : {}),
79
+ ...(port !== undefined ? { port } : {}),
80
+ ...(host ? { host } : {}),
81
+ ...(scope ? { scope } : {}),
82
+ ...(binaryPath ? { binaryPath } : {}),
83
+ ...(runtimePrefix ? { runtimePrefix } : {}),
84
+ ...(pathPrefix.length ? { pathPrefix } : {}),
85
+ start,
86
+ enable,
87
+ }, env);
88
+
89
+ if (!dryRun && !json && (action === "install" || action === "uninstall") && !yes) {
90
+ const ok = await confirm(
91
+ action === "install"
92
+ ? `Install ${plan.kind} ${plan.scope} daemon "${plan.name}"?`
93
+ : `Uninstall daemon "${plan.name}"?`,
94
+ );
95
+ if (!ok) {
96
+ console.log("Daemon command cancelled.");
97
+ return;
98
+ }
99
+ }
100
+
101
+ const result = await executeDaemonPlan(plan, { dryRun, force });
102
+ if (json) console.log(JSON.stringify({ plan: result.plan, output: result.output }, null, 2));
103
+ else console.log(dryRun ? formatDaemonPlan(plan) : result.output);
104
+ }
105
+
106
+ function parseDaemonAction(value: string | undefined): DaemonAction {
107
+ if (!value || !DAEMON_ACTIONS.has(value as DaemonAction)) {
108
+ throw new Error("Usage: agent-relay daemon <install|uninstall|start|stop|restart|enable|disable|status|logs> [options]");
109
+ }
110
+ return value as DaemonAction;
111
+ }
package/src/cli/dev.ts ADDED
@@ -0,0 +1,173 @@
1
+ // Dev commands — auto-split from cli.ts (#294). Local pack/install/service/smoke
2
+ // harness for testing relay packages without an npm publish.
3
+ import {
4
+ createDevInstallPlan,
5
+ createDevPackPlan,
6
+ createDevServicePlan,
7
+ defaultDevRoot,
8
+ executeDevInstallPlan,
9
+ executeDevPackPlan,
10
+ executeDevServicePlan,
11
+ executeDevSmoke,
12
+ formatDevInstallPlan,
13
+ formatDevPackPlan,
14
+ formatDevServicePlan,
15
+ parseDevPackages,
16
+ type DevServiceAction,
17
+ } from "../dev";
18
+ import { confirm } from "./_shared";
19
+
20
+ export async function handleDevCommand(args: string[]): Promise<void> {
21
+ const action = args[0];
22
+ if (!action) throw new Error("Usage: agent-relay dev <pack|install|service|smoke> [options]");
23
+ if (action === "pack") {
24
+ let packages: string | undefined;
25
+ let outDir: string | undefined;
26
+ let dryRun = false;
27
+ let json = false;
28
+ for (let i = 1; i < args.length; i++) {
29
+ const arg = args[i];
30
+ if (arg === "--packages" && i + 1 < args.length) packages = args[++i];
31
+ else if (arg === "--out" && i + 1 < args.length) outDir = args[++i];
32
+ else if (arg === "--dry-run") dryRun = true;
33
+ else if (arg === "--json") json = true;
34
+ else throw new Error(`Unknown dev pack option "${arg}"`);
35
+ }
36
+ const plan = createDevPackPlan({
37
+ ...(packages ? { packages: parseDevPackages(packages) } : {}),
38
+ ...(outDir ? { outDir } : {}),
39
+ });
40
+ const result = await executeDevPackPlan(plan, { dryRun });
41
+ if (json) console.log(JSON.stringify(result, null, 2));
42
+ else console.log(dryRun ? formatDevPackPlan(plan) : result.output);
43
+ return;
44
+ }
45
+
46
+ if (action === "install") {
47
+ let packages: string | undefined;
48
+ let outDir: string | undefined;
49
+ let prefix: string | undefined;
50
+ let dryRun = false;
51
+ let json = false;
52
+ for (let i = 1; i < args.length; i++) {
53
+ const arg = args[i];
54
+ if (arg === "--packages" && i + 1 < args.length) packages = args[++i];
55
+ else if (arg === "--out" && i + 1 < args.length) outDir = args[++i];
56
+ else if (arg === "--prefix" && i + 1 < args.length) prefix = args[++i];
57
+ else if (arg === "--dry-run") dryRun = true;
58
+ else if (arg === "--json") json = true;
59
+ else throw new Error(`Unknown dev install option "${arg}"`);
60
+ }
61
+ const plan = createDevInstallPlan({
62
+ ...(packages ? { packages: parseDevPackages(packages) } : {}),
63
+ ...(outDir ? { outDir } : {}),
64
+ ...(prefix ? { prefix } : {}),
65
+ });
66
+ const result = await executeDevInstallPlan(plan, { dryRun });
67
+ if (json) console.log(JSON.stringify(result, null, 2));
68
+ else console.log(dryRun ? formatDevInstallPlan(plan) : result.output);
69
+ return;
70
+ }
71
+
72
+ if (action === "service") {
73
+ await handleDevServiceCommand(args.slice(1));
74
+ return;
75
+ }
76
+
77
+ if (action === "smoke") {
78
+ let rootDir: string | undefined;
79
+ let providers: string | undefined;
80
+ let cwd: string | undefined;
81
+ let orchestratorId: string | undefined;
82
+ let timeoutMs: number | undefined;
83
+ for (let i = 1; i < args.length; i++) {
84
+ const arg = args[i];
85
+ if (arg === "--root" && i + 1 < args.length) rootDir = args[++i];
86
+ else if (arg === "--providers" && i + 1 < args.length) providers = args[++i];
87
+ else if (arg === "--cwd" && i + 1 < args.length) cwd = args[++i];
88
+ else if (arg === "--orchestrator" && i + 1 < args.length) orchestratorId = args[++i];
89
+ else if (arg === "--timeout" && i + 1 < args.length) timeoutMs = parseInt(args[++i]!, 10);
90
+ else throw new Error(`Unknown dev smoke option "${arg}"`);
91
+ }
92
+ const result = await executeDevSmoke({
93
+ ...(rootDir ? { rootDir } : {}),
94
+ ...(providers ? { providers } : {}),
95
+ ...(cwd ? { cwd } : {}),
96
+ ...(orchestratorId ? { orchestratorId } : {}),
97
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
98
+ });
99
+ console.log(result.output);
100
+ return;
101
+ }
102
+
103
+ throw new Error("Usage: agent-relay dev <pack|install|service|smoke> [options]");
104
+ }
105
+
106
+ async function handleDevServiceCommand(args: string[]): Promise<void> {
107
+ const action = parseDevServiceAction(args[0]);
108
+ let prefix: string | undefined;
109
+ let rootDir: string | undefined;
110
+ let port: number | undefined;
111
+ let apiPort: number | undefined;
112
+ let baseDir: string | undefined;
113
+ let orchestratorId: string | undefined;
114
+ let token: string | undefined;
115
+ let start = false;
116
+ let enable = false;
117
+ let dryRun = false;
118
+ let force = false;
119
+ let yes = false;
120
+ let json = false;
121
+
122
+ for (let i = 1; i < args.length; i++) {
123
+ const arg = args[i];
124
+ if (arg === "--prefix" && i + 1 < args.length) prefix = args[++i];
125
+ else if (arg === "--root" && i + 1 < args.length) rootDir = args[++i];
126
+ else if (arg === "--port" && i + 1 < args.length) port = parseInt(args[++i]!, 10);
127
+ else if (arg === "--api-port" && i + 1 < args.length) apiPort = parseInt(args[++i]!, 10);
128
+ else if (arg === "--base-dir" && i + 1 < args.length) baseDir = args[++i];
129
+ else if (arg === "--orchestrator-id" && i + 1 < args.length) orchestratorId = args[++i];
130
+ else if (arg === "--token" && i + 1 < args.length) token = args[++i];
131
+ else if (arg === "--start") start = true;
132
+ else if (arg === "--enable") enable = true;
133
+ else if (arg === "--dry-run") dryRun = true;
134
+ else if (arg === "--force") force = true;
135
+ else if (arg === "--yes") yes = true;
136
+ else if (arg === "--json") json = true;
137
+ else throw new Error(`Unknown dev service option "${arg}"`);
138
+ }
139
+
140
+ const root = rootDir ?? defaultDevRoot();
141
+ const plan = createDevServicePlan({
142
+ action,
143
+ ...(prefix ? { prefix } : {}),
144
+ rootDir: root,
145
+ ...(port !== undefined ? { port } : {}),
146
+ ...(apiPort !== undefined ? { apiPort } : {}),
147
+ ...(baseDir ? { baseDir } : {}),
148
+ ...(orchestratorId ? { orchestratorId } : {}),
149
+ ...(token ? { token } : {}),
150
+ start,
151
+ enable,
152
+ });
153
+
154
+ if (!dryRun && !json && (action === "install" || action === "uninstall") && !yes) {
155
+ const ok = await confirm(action === "install" ? `Install dev service profile under ${root}?` : `Uninstall dev service profile under ${root}?`);
156
+ if (!ok) {
157
+ console.log("Dev service command cancelled.");
158
+ return;
159
+ }
160
+ }
161
+
162
+ const result = await executeDevServicePlan(plan, { dryRun, force });
163
+ if (json) console.log(JSON.stringify({ plan: result.plan, output: result.output }, null, 2));
164
+ else console.log(dryRun ? formatDevServicePlan(plan) : result.output);
165
+ }
166
+
167
+ function parseDevServiceAction(value: string | undefined): DevServiceAction {
168
+ const allowed = new Set<DevServiceAction>(["install", "uninstall", "start", "stop", "restart", "status", "logs"]);
169
+ if (!value || !allowed.has(value as DevServiceAction)) {
170
+ throw new Error("Usage: agent-relay dev service <install|uninstall|start|stop|restart|status|logs> [options]");
171
+ }
172
+ return value as DevServiceAction;
173
+ }
@@ -0,0 +1,361 @@
1
+ // CLI dispatcher — auto-split from cli.ts (#294). handleCli() is a thin switch
2
+ // over the per-domain command modules in this directory; the usage/guide strings
3
+ // live here too. Each command's logic lives in its own module (upgrade.ts,
4
+ // message.ts, workspace.ts, …). Re-exports WORKSPACE_USAGE and
5
+ // removeLegacyCodexSessionStartHookToml for the legacy "./cli" import surface.
6
+ import { VERSION } from "../config";
7
+ import { handleUpgradeCommand } from "./upgrade";
8
+ import { handleProviderCommand } from "./provider";
9
+ import { handleContextProbeCommand } from "./context-probe";
10
+ import { handleSetupCommand } from "./setup";
11
+ import { handleDaemonCommand } from "./daemon";
12
+ import { handleOrchestratorCommand } from "./orchestrator";
13
+ import { handleDevCommand } from "./dev";
14
+ import { handleMemoryCommand } from "./memory";
15
+ import { handleSlashOrPairCommand } from "./pair";
16
+ import { handleWorkspaceCommand } from "./workspace";
17
+ import { handleStewardCommand } from "./steward";
18
+ import { handleMessageCommand, handleGetMessageCommand, handleReactCommand } from "./message";
19
+ import { handleReplyCommand } from "./reply";
20
+ import { handleIntrospectCommand } from "./introspect";
21
+ import { handleStatusCommand, handleLabelCommand, handleTagsCommand } from "./agent-meta";
22
+ import { handleRecipeCommand } from "./recipe";
23
+ import { handleTokenCommand } from "./token";
24
+
25
+ export { WORKSPACE_USAGE } from "./workspace";
26
+ export { removeLegacyCodexSessionStartHookToml } from "./provider";
27
+
28
+ const HELP = `
29
+ agent-relay ${VERSION}
30
+
31
+ Usage:
32
+ agent-relay [start]
33
+ agent-relay setup [--yes] [--dry-run] [--force] [--env-file PATH] [--runtime-prefix DIR] [--host HOST] [--port PORT] [--db-path PATH] [--token TOKEN|--no-token]
34
+ agent-relay upgrade [--dry-run] [--version VERSION] [--runtime-prefix DIR] [--providers auto|all|codex|claude|orchestrator] [--no-restart] [--yes]
35
+ agent-relay upgrade --host ID [--host ID2 ...] [--version VERSION] [--providers ...] (upgrade remote orchestrator hosts over the relay)
36
+ agent-relay upgrade --all-hosts [...] (upgrade this host, then every behind remote host)
37
+ agent-relay setup upgrade [same options as upgrade]
38
+ agent-relay daemon <install|uninstall|start|stop|restart|enable|disable|status|logs> [options]
39
+ agent-relay orchestrator install [options]
40
+ agent-relay dev <pack|install|service|smoke> [options]
41
+ agent-relay memory broker smoke [options]
42
+ agent-relay recipe <list|show|start|stop|status> [options]
43
+ agent-relay provider <wrap|unwrap> <claude|codex>
44
+ agent-relay context-probe [print-status-line] [--wrap COMMAND] [--agent-id ID] [--state-dir DIR] [--standalone]
45
+ agent-relay token <create|list|revoke|verify> [options]
46
+ agent-relay pair <target|create|status|accept|reject|hangup|send> [options]
47
+ agent-relay workspace <status|diagnostics|ready|land|claim|release|list|cleanup-stale|deps> [--id ID] [--strategy ...] [--purpose TEXT] [--repo PATH] [--wait] [--timeout SECONDS] [--check] [--execute] [--json]
48
+ agent-relay steward <queue|inspect|checks> [WORKSPACE_ID] [--repo PATH] [--json]
49
+ agent-relay message <target> <body> [options]
50
+ agent-relay get-message <messageId> [--json|--body]
51
+ agent-relay /pair <target|accept|reject|send|status> [...]
52
+ agent-relay /message <target> <body>
53
+ agent-relay /reply <messageId> <body|--stdin|--body-file PATH> [--format text|markdown|markdownv2]
54
+ agent-relay /react <messageId> <emoji> [--remove]
55
+ agent-relay /send-claimable <target> <body>
56
+ agent-relay /disconnect [PAIR_ID]
57
+ agent-relay /status
58
+ agent-relay /guide
59
+ agent-relay /label [LABEL]
60
+ agent-relay /tags [TAG ...]
61
+ agent-relay /introspect [--thin TEXT] [--worked-around TEXT] [--would-have-helped TEXT] [--stdin]
62
+ agent-relay --help
63
+
64
+ Pair examples:
65
+ agent-relay pair codex --objective "Debug flaky tests"
66
+ agent-relay /pair codex "Debug flaky tests"
67
+ agent-relay pair status
68
+ agent-relay pair accept PAIR_ID --agent AGENT_ID
69
+ agent-relay pair send PAIR_ID --from AGENT_ID --body "What do you see?"
70
+ agent-relay /message codex "Can you look at that failing action?"
71
+ agent-relay /reply 206 "Sounds good, I'll take a look"
72
+ agent-relay /react 206 👍
73
+ agent-relay /reply 206 --stdin < result.md
74
+ agent-relay get-message 206 --json
75
+ agent-relay /reply 206 --format markdown "Here is **formatted** text"
76
+ agent-relay /send-claimable tag:backend "Please claim and fix the failing API test"
77
+ agent-relay /disconnect
78
+ agent-relay /status
79
+ agent-relay /guide
80
+ agent-relay /label backend-fixer
81
+ agent-relay /tags backend tests urgent
82
+
83
+ Daemon options:
84
+ --env-file PATH Env file sourced by the daemon (default: platform user config dir)
85
+ --runtime-prefix DIR Isolated Agent Relay npm prefix (default: ~/.agent-relay/runtime)
86
+ --binary PATH Stable agent-relay binary/script path for the service
87
+ --path-prefix DIR Prepend a directory to daemon PATH; repeatable
88
+ --name NAME Service name (default: agent-relay)
89
+ --host HOST Display/listen host for generated plan (default: 127.0.0.1)
90
+ --port PORT Display/listen port for generated plan (default: 4850)
91
+ --user|--system User service by default, system service when explicitly requested
92
+ --enable Enable service at login/boot during install
93
+ --start Start service after install
94
+ --dry-run Print the plan without writing files or running service commands
95
+ --yes Skip confirmation prompts
96
+ --force Overwrite/remove managed-file guardrails
97
+ --json Print structured output
98
+
99
+ Orchestrator install options:
100
+ --relay-url URL Agent Relay server URL reachable from this host
101
+ --token TOKEN Scoped runtime orchestrator token
102
+ --bootstrap-token TOKEN Short-lived dashboard bootstrap token to exchange during install
103
+ --id ID Orchestrator id (default: sanitized hostname)
104
+ --base-dir PATH Base directory for agent working directories (default: ~/projects)
105
+ --providers LIST Providers to probe/enable (default: claude,codex)
106
+ --api-port PORT Orchestrator local API port (default: 4860)
107
+ --runtime-prefix DIR Isolated npm prefix (default: ~/.agent-relay/runtime)
108
+ --path-prefix DIR Prepend a directory to daemon PATH; repeatable
109
+ --version VERSION Package version to install (default: this CLI version)
110
+ --dry-run Print the plan without writing files, installing, or starting
111
+ --yes Skip confirmation prompts
112
+
113
+ Upgrade options:
114
+ --version VERSION Target version (default: latest published server version)
115
+ --runtime-prefix DIR Isolated Agent Relay npm prefix (default: ~/.agent-relay/runtime)
116
+ --providers LIST Provider integrations to upgrade: auto, all, codex, claude, orchestrator
117
+ --host ID Upgrade a remote orchestrator host over the relay (repeatable). Skips the local upgrade
118
+ --all-hosts Upgrade this host, then fan out to every connected remote host that is behind
119
+ --no-restart Do not restart agent-relay.service (warns you to restart it manually)
120
+ --restart-deferred Like --no-restart, but the caller restarts the services itself; suppresses the manual-restart warning (used by the release script)
121
+ --dry-run Print detected state and planned commands
122
+ --yes Skip confirmation prompts
123
+
124
+ Dev options:
125
+ agent-relay dev pack [--packages LIST] [--out DIR]
126
+ agent-relay dev install [--packages LIST] [--prefix DIR] [--out DIR] [--dry-run] [--json]
127
+ agent-relay dev service <install|uninstall|start|stop|restart|status|logs> [--prefix DIR] [--root DIR] [--port PORT] [--api-port PORT] [--base-dir DIR] [--enable] [--start] [--dry-run] [--yes] [--force] [--json]
128
+ agent-relay dev smoke [--root DIR] [--providers LIST] [--cwd DIR] [--timeout MS]
129
+
130
+ Memory options:
131
+ agent-relay memory broker smoke [--relay-url URL] [--token TOKEN] [--agent-id ID] [--scope SCOPE] [--tag TAG] [--no-cleanup] [--json]
132
+
133
+ Recipe examples:
134
+ agent-relay recipe list
135
+ agent-relay recipe start code-review --cwd /repo --orchestrator local
136
+ agent-relay recipe status
137
+ agent-relay recipe stop INSTANCE_ID
138
+
139
+ Token examples:
140
+ agent-relay token create --role orchestrator --sub macmini --ttl 86400
141
+ agent-relay token list
142
+ agent-relay token revoke JTI
143
+
144
+ Context probe examples:
145
+ agent-relay context-probe print-status-line --wrap 'ccstatusline'
146
+ agent-relay context-probe --wrap 'ccstatusline'
147
+ agent-relay context-probe --standalone
148
+ `.trim();
149
+
150
+ const AGENT_GUIDE = `
151
+ Agent Relay guide for coding agents
152
+
153
+ Agent Relay is a message bus between local or managed agents. Use the
154
+ agent-relay CLI for relay communication.
155
+
156
+ Current session
157
+ agent-relay /status --json
158
+ Shows your relay agent id, label, tags, health, and active pair state.
159
+
160
+ Replying
161
+ agent-relay /reply <messageId> "<response>"
162
+ agent-relay /reply <messageId> --stdin < response.md
163
+ agent-relay /reply <messageId> --body-file response.md
164
+ Reply to the sender of a relay message. Prefer this over /message when
165
+ handling an incoming relay message because the server keeps the routing
166
+ and channel context. Large replies are uploaded as an artifact
167
+ automatically and sent as a concise attached reply.
168
+
169
+ Reactions
170
+ agent-relay /react <messageId> <emoji>
171
+ agent-relay /react <messageId> <emoji> --remove
172
+ Use reactions for lightweight acknowledgement, approval, thanks, or
173
+ "good job" when no text response is needed. Do not use reactions when the
174
+ sender asked a question, gave a new task, or needs a result in text.
175
+
176
+ Reading full messages
177
+ agent-relay get-message <messageId>
178
+ agent-relay read-message <messageId> --json
179
+ agent-relay get-message <messageId> --body
180
+ Fetch the full message body, attachments, metadata, and thread context.
181
+
182
+ Sending messages
183
+ agent-relay /message <target> "<message>"
184
+ Send a direct one-off relay message.
185
+
186
+ agent-relay /send-claimable <target> "<work item>"
187
+ Queue work that one matching agent can claim and handle.
188
+
189
+ Targets
190
+ <agent-id> A specific live agent id.
191
+ <label> A registered agent label.
192
+ tag:<tag> Any agent with that tag.
193
+ cap:<capability> Any agent with that capability.
194
+ policy:<name> A managed policy target that can survive restarts.
195
+ broadcast All reachable agents.
196
+
197
+ Pair sessions
198
+ agent-relay /pair <target> "<objective>"
199
+ agent-relay /pair status
200
+ agent-relay /pair accept <pairId>
201
+ agent-relay /pair reject <pairId>
202
+ agent-relay /pair send <pairId> "<message>"
203
+ agent-relay /disconnect [pairId]
204
+
205
+ Labels and tags
206
+ agent-relay /label [LABEL]
207
+ agent-relay /tags [TAG ...]
208
+
209
+ Isolated workspaces
210
+ If you are working in an isolated workspace (a git worktree on an agent
211
+ branch, not the main checkout), you do NOT rebase, merge, or push yourself —
212
+ Relay does. Just commit your work in the worktree, then:
213
+ agent-relay workspace ready Hand off: Relay rebases onto the latest base,
214
+ lands your work, and pushes.
215
+ agent-relay workspace status Show your workspace's state + what to do next.
216
+ agent-relay workspace status --wait
217
+ Block until your branch lands (returns the
218
+ moment the auto-merge completes).
219
+ After "ready", status is "review_requested" — this is NORMAL, not an
220
+ escalation. Relay auto-merges clean rebases ~every 2 min; a steward agent is
221
+ spawned only if it can't land deterministically, so no steward = healthy. On
222
+ landing you move onto a fresh rebased branch (name gains a "--N" suffix).
223
+ The base branch will move as other agents land in parallel — that is normal,
224
+ let the merge handle it. Never push, merge, resolve conflicts, or touch the
225
+ main checkout yourself; it is local-only and Relay (and the steward) own that.
226
+ If typecheck/build fails on a missing module (a dep added to the base after
227
+ your worktree was created), do NOT run a clean install — it mutates the shared
228
+ node_modules. Instead refresh your worktree's deps in isolation:
229
+ agent-relay workspace deps Re-provision deps that have gone stale.
230
+ agent-relay workspace deps --check Report staleness without installing.
231
+
232
+ Rules of thumb
233
+ If you are handling relay message #123, reply with:
234
+ agent-relay /reply 123 "<response>"
235
+
236
+ If the delivered preview says it was truncated, fetch the full message with:
237
+ agent-relay get-message 123
238
+
239
+ If your reply is long, avoid shell quoting and use:
240
+ agent-relay /reply 123 --stdin < response.md
241
+
242
+ If you need to know who you are in Relay, run:
243
+ agent-relay /status --json
244
+
245
+ Recording session friction (optional, helps improve your standing context)
246
+ agent-relay /introspect --thin "..." --worked-around "..." --would-have-helped "..."
247
+ When a session involved real work, you can record a short 3-field note about
248
+ where context was thin, what tooling/instruction gaps you routed around, and
249
+ what would have saved the read-up. Keep each field to a sentence or two. This
250
+ feeds the relay's self-improvement signal so the operator can close the gaps —
251
+ it is not a reply and needs no message id. Skip it for trivial sessions.
252
+
253
+ Use the HTTP API for integrations and debugging. For normal agent-to-agent
254
+ communication, use the CLI commands above.
255
+ `.trim();
256
+
257
+ export async function handleCli(args: string[]): Promise<"start" | "handled"> {
258
+ const command = args[0];
259
+ if (!command || command === "start") return "start";
260
+ if (command === "--help" || command === "-h" || command === "help") {
261
+ console.log(HELP);
262
+ return "handled";
263
+ }
264
+ if (command === "--version" || command === "-v") {
265
+ console.log(VERSION);
266
+ return "handled";
267
+ }
268
+ if (command === "guide" || command === "/guide" || command === "agent-guide" || command === "/agent-guide") {
269
+ console.log(AGENT_GUIDE);
270
+ return "handled";
271
+ }
272
+ if (command === "upgrade" || (command === "setup" && args[1] === "upgrade")) {
273
+ await handleUpgradeCommand(command === "setup" ? args.slice(2) : args.slice(1));
274
+ return "handled";
275
+ }
276
+ if (command === "setup" || command === "init") {
277
+ await handleSetupCommand(args.slice(1));
278
+ return "handled";
279
+ }
280
+ if (command === "daemon") {
281
+ await handleDaemonCommand(args.slice(1));
282
+ return "handled";
283
+ }
284
+ if (command === "orchestrator" || command === "orchestrators") {
285
+ await handleOrchestratorCommand(args.slice(1));
286
+ return "handled";
287
+ }
288
+ if (command === "dev") {
289
+ await handleDevCommand(args.slice(1));
290
+ return "handled";
291
+ }
292
+ if (command === "memory") {
293
+ await handleMemoryCommand(args.slice(1));
294
+ return "handled";
295
+ }
296
+ if (command === "recipe" || command === "recipes") {
297
+ await handleRecipeCommand(args.slice(1));
298
+ return "handled";
299
+ }
300
+ if (command === "provider" || command === "providers") {
301
+ await handleProviderCommand(args.slice(1));
302
+ return "handled";
303
+ }
304
+ if (command === "context-probe") {
305
+ await handleContextProbeCommand(args.slice(1));
306
+ return "handled";
307
+ }
308
+ if (command === "token" || command === "tokens") {
309
+ await handleTokenCommand(args.slice(1));
310
+ return "handled";
311
+ }
312
+ if (command === "pair" || command === "/pair" || command === "/disconnect") {
313
+ await handleSlashOrPairCommand(command, args.slice(1));
314
+ return "handled";
315
+ }
316
+ if (command === "message" || command === "send" || command === "/message" || command === "/send" || command === "/send-claimable") {
317
+ await handleMessageCommand(args.slice(1), { claimable: command === "/send-claimable" });
318
+ return "handled";
319
+ }
320
+ if (command === "get-message" || command === "read-message" || command === "/get-message" || command === "/read-message") {
321
+ await handleGetMessageCommand(args.slice(1));
322
+ return "handled";
323
+ }
324
+ if (command === "reply" || command === "/reply") {
325
+ await handleReplyCommand(args.slice(1));
326
+ return "handled";
327
+ }
328
+ if (command === "react" || command === "/react" || command === "reaction" || command === "/reaction") {
329
+ await handleReactCommand(args.slice(1));
330
+ return "handled";
331
+ }
332
+ if (command === "introspect" || command === "/introspect") {
333
+ await handleIntrospectCommand(args.slice(1));
334
+ return "handled";
335
+ }
336
+ if (command === "/status" || command === "status") {
337
+ await handleStatusCommand(args.slice(1));
338
+ return "handled";
339
+ }
340
+ if (command === "/label" || command === "label") {
341
+ await handleLabelCommand(args.slice(1));
342
+ return "handled";
343
+ }
344
+ if (command === "/tags" || command === "tags") {
345
+ await handleTagsCommand(args.slice(1));
346
+ return "handled";
347
+ }
348
+ if (command === "workspace" || command === "workspaces") {
349
+ await handleWorkspaceCommand(args.slice(1));
350
+ return "handled";
351
+ }
352
+ if (command === "steward" || command === "stewards") {
353
+ await handleStewardCommand(args.slice(1));
354
+ return "handled";
355
+ }
356
+ if (command === "/reconnect") {
357
+ console.log("Reconnect is handled automatically by provider runners; use `agent-relay pair status` to inspect current pair state.");
358
+ return "handled";
359
+ }
360
+ throw new Error(`Unknown command "${command}". Run agent-relay --help.`);
361
+ }