agent-relay-runner 0.10.5 → 0.10.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-runner",
3
- "version": "0.10.5",
3
+ "version": "0.10.7",
4
4
  "description": "Unified provider lifecycle runner for Agent Relay",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "agent-relay-runner",
3
3
  "description": "Thin Agent Relay runner bridge for Claude Code",
4
- "version": "0.10.5"
4
+ "version": "0.10.7"
5
5
  }
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: disconnect
3
+ description: End the current Agent Relay pair session. Use when the user invokes /disconnect or asks to hang up, unpair, or disconnect from a paired agent.
4
+ argument-hint: "[PAIR_ID]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Disconnect
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /disconnect $ARGUMENTS
14
+ ```
15
+
16
+ If no pair id is supplied, the CLI ends the active pair for this session. Report the result briefly.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: label
3
+ description: Read, set, or clear the current Agent Relay agent label. Use when the user invokes /label or asks to rename this relay agent.
4
+ argument-hint: "[LABEL|--clear]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Label
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /label $ARGUMENTS
14
+ ```
15
+
16
+ Examples:
17
+
18
+ ```bash
19
+ agent-relay /label backend-fixer
20
+ agent-relay /label --clear
21
+ ```
22
+
23
+ Report the new label or current label briefly.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: message
3
+ description: Send a normal Agent Relay message to another agent, label, tag, capability, or broadcast target. Use when the user invokes /message or asks to send a one-off relay message.
4
+ argument-hint: "<target> <message> [--subject TEXT] [--channel NAME]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Message
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /message $ARGUMENTS
14
+ ```
15
+
16
+ Examples:
17
+
18
+ ```bash
19
+ agent-relay /message codex "Can you look at that failing action?"
20
+ agent-relay /message tag:backend "Does anyone see the regression?"
21
+ agent-relay /message broadcast "Standup in five minutes"
22
+ ```
23
+
24
+ Report the sent message id briefly.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: pair
3
+ description: Start, inspect, accept, reject, or send messages in an Agent Relay two-agent pair session. Use when the user invokes /pair or asks to pair this agent with Codex, Claude, or another relay agent.
4
+ argument-hint: "<target|status|accept|reject|send> [args]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Pair
9
+
10
+ Run the Agent Relay CLI with the user's arguments:
11
+
12
+ ```bash
13
+ agent-relay /pair $ARGUMENTS
14
+ ```
15
+
16
+ Use this for pair-session commands such as:
17
+
18
+ ```bash
19
+ agent-relay /pair codex "Debug flaky tests"
20
+ agent-relay /pair status
21
+ agent-relay /pair accept PAIR_ID
22
+ agent-relay /pair reject PAIR_ID
23
+ agent-relay /pair send PAIR_ID "What do you see?"
24
+ ```
25
+
26
+ Report the command output briefly. If the CLI cannot detect this session's agent id, rerun with `--agent AGENT_ID` or `--from AGENT_ID` using the Agent Relay ID shown in session context.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: reply
3
+ description: Reply to an Agent Relay message by ID. Auto-routes to the sender and inherits channel context — no target needed. Use when the user invokes /reply or asks to reply to a specific relay message.
4
+ argument-hint: "<messageId> <message>"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Reply
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /reply $ARGUMENTS
14
+ ```
15
+
16
+ The server auto-routes the reply to the original sender and inherits the channel (Telegram, Slack, etc.) if applicable. No target or channel ID needed.
17
+
18
+ Examples:
19
+
20
+ ```bash
21
+ agent-relay /reply 206 "Sounds good, I'll take a look"
22
+ agent-relay /reply 42 "Done — the fix is in commit abc123"
23
+ ```
24
+
25
+ Report the sent message id and resolved target briefly.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: send-claimable
3
+ description: Send a claimable Agent Relay work item so one matching agent can claim and handle it. Use when the user invokes /send-claimable or wants to enqueue work for another agent.
4
+ argument-hint: "<target> <message> [--subject TEXT] [--channel NAME]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Send Claimable
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /send-claimable $ARGUMENTS
14
+ ```
15
+
16
+ Examples:
17
+
18
+ ```bash
19
+ agent-relay /send-claimable codex "Claim this and inspect the failing action"
20
+ agent-relay /send-claimable tag:backend "Fix the failing API test"
21
+ agent-relay /send-claimable cap:review "Review the migration patch"
22
+ ```
23
+
24
+ Report the sent claimable message id briefly.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: status
3
+ description: Show Agent Relay status for this session, including relay health, current agent id, label, tags, readiness, and active pair state. Use when the user invokes /status or asks for relay connection status.
4
+ argument-hint: "[--json]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Status
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /status $ARGUMENTS
14
+ ```
15
+
16
+ Summarize the current relay connection, agent identity, label, tags, and active pair state.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: tags
3
+ description: List or update Agent Relay tags for the current session. Use when the user invokes /tags or asks to set, add, remove, or inspect relay tags.
4
+ argument-hint: "[TAG ...|--list|--add TAGS|--remove TAGS]"
5
+ allowed-tools: [Bash]
6
+ ---
7
+
8
+ # Agent Relay Tags
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ agent-relay /tags $ARGUMENTS
14
+ ```
15
+
16
+ Examples:
17
+
18
+ ```bash
19
+ agent-relay /tags
20
+ agent-relay /tags backend tests urgent
21
+ agent-relay /tags --add backend,tests
22
+ agent-relay /tags --remove urgent
23
+ ```
24
+
25
+ Report the resulting tags briefly.
package/src/adapter.ts CHANGED
@@ -26,6 +26,7 @@ export interface RunnerSpawnConfig {
26
26
  headless: boolean;
27
27
  approvalMode: string;
28
28
  label?: string;
29
+ rig?: string;
29
30
  prompt?: string;
30
31
  providerArgs: string[];
31
32
  providerConfig: ProviderConfig;
@@ -36,7 +36,10 @@ export class ClaudeAdapter implements ProviderAdapter {
36
36
  buildSpawnArgs(config: RunnerSpawnConfig, providerConfig: ProviderConfig): SpawnArgs {
37
37
  const pluginRoot = resolve(import.meta.dir, "../../plugins/claude");
38
38
  const pluginDirs = [...new Set([pluginRoot, ...providerConfig.pluginDirs])];
39
+ const isClaudeRig = /claude-rig/.test(providerConfig.command);
40
+ const rigPrefix = isClaudeRig && config.rig ? ["launch", config.rig] : [];
39
41
  const args = [
42
+ ...rigPrefix,
40
43
  ...pluginDirs.flatMap((dir) => ["--plugin-dir", dir]),
41
44
  ...providerConfig.defaultArgs,
42
45
  ...config.providerArgs,
package/src/config.ts CHANGED
@@ -24,7 +24,7 @@ function providersDir(home = agentRelayHome()): string {
24
24
  }
25
25
 
26
26
  export function defaultProviderConfig(provider: string): ProviderConfig {
27
- const command = provider === "claude" ? "claude-rig" : provider;
27
+ const command = provider === "claude" ? "claude" : provider;
28
28
  return {
29
29
  command,
30
30
  defaultArgs: provider === "claude" ? ["--dangerously-skip-permissions"] : [],
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { basename } from "node:path";
3
+ import { isatty } from "node:tty";
3
4
  import { ClaudeAdapter } from "./adapters/claude";
4
5
  import { CodexAdapter } from "./adapters/codex";
5
6
  import { AgentRunner } from "./runner";
@@ -8,7 +9,9 @@ import { loadGlobalConfig, loadProviderConfig, resolveCwd, runnerId } from "./co
8
9
  interface CliOptions {
9
10
  provider: "claude" | "codex";
10
11
  headless: boolean;
12
+ interactive: boolean;
11
13
  cwd?: string;
14
+ rig?: string;
12
15
  relayUrl?: string;
13
16
  token?: string;
14
17
  approvalMode?: string;
@@ -25,6 +28,12 @@ export async function main(argv = process.argv): Promise<void> {
25
28
  const cwd = resolveCwd(opts.cwd, globalConfig.defaultCwd);
26
29
  const id = runnerId(opts.provider, cwd, opts.label);
27
30
  const adapter = opts.provider === "claude" ? new ClaudeAdapter() : new CodexAdapter();
31
+
32
+ let exitResolve: ((code: number) => void) | undefined;
33
+ const exitPromise = opts.interactive
34
+ ? new Promise<number>((resolve) => { exitResolve = resolve; })
35
+ : undefined;
36
+
28
37
  const runner = new AgentRunner({
29
38
  provider: opts.provider,
30
39
  runnerId: id,
@@ -36,17 +45,26 @@ export async function main(argv = process.argv): Promise<void> {
36
45
  headless: opts.headless,
37
46
  approvalMode: opts.approvalMode ?? providerConfig.defaultApprovalMode,
38
47
  label: opts.label,
48
+ rig: opts.rig,
39
49
  prompt: opts.prompt,
40
50
  providerArgs: opts.providerArgs,
41
51
  providerConfig,
42
52
  adapter,
53
+ onProviderExit: exitResolve ? (code) => exitResolve!(code ?? 1) : undefined,
43
54
  });
44
55
  await runner.run();
45
- await waitForShutdown(() => runner.stop());
56
+
57
+ if (opts.interactive && exitPromise) {
58
+ const code = await Promise.race([exitPromise, signalPromise()]);
59
+ await runner.stop();
60
+ process.exit(code);
61
+ } else {
62
+ await waitForShutdown(() => runner.stop());
63
+ }
46
64
  }
47
65
 
48
66
  function parseArgs(argv: string[]): CliOptions {
49
- const bin = basename(argv[1] || "");
67
+ const bin = [argv[1], process.env._].map((s) => basename(s || "")).join(" ");
50
68
  let provider: "claude" | "codex" = bin.includes("claude") ? "claude" : "codex";
51
69
  const relayArgs = argv.slice(2);
52
70
  const providerSep = relayArgs.indexOf("--");
@@ -54,6 +72,7 @@ function parseArgs(argv: string[]): CliOptions {
54
72
  const providerArgs = providerSep >= 0 ? relayArgs.slice(providerSep + 1) : [];
55
73
  let headless = false;
56
74
  let cwd: string | undefined;
75
+ let rig: string | undefined;
57
76
  let relayUrl: string | undefined;
58
77
  let token: string | undefined;
59
78
  let approvalMode: string | undefined;
@@ -66,6 +85,7 @@ function parseArgs(argv: string[]): CliOptions {
66
85
  if (arg === "claude" || arg === "codex") provider = arg;
67
86
  else if (arg === "--headless") headless = true;
68
87
  else if (arg === "--cwd" && ownArgs[i + 1]) cwd = ownArgs[++i];
88
+ else if (arg === "--rig" && ownArgs[i + 1]) rig = ownArgs[++i];
69
89
  else if (arg === "--relay-url" && ownArgs[i + 1]) relayUrl = ownArgs[++i];
70
90
  else if (arg === "--token" && ownArgs[i + 1]) token = ownArgs[++i];
71
91
  else if ((arg === "--approval" || arg === "--approval-mode") && ownArgs[i + 1]) approvalMode = ownArgs[++i];
@@ -80,11 +100,19 @@ function parseArgs(argv: string[]): CliOptions {
80
100
  }
81
101
  }
82
102
 
83
- return { provider, headless, cwd, relayUrl, token, approvalMode, label, agentId, prompt, providerArgs };
103
+ const interactive = !headless && isatty(0);
104
+ return { provider, headless, interactive, cwd, rig, relayUrl, token, approvalMode, label, agentId, prompt, providerArgs };
84
105
  }
85
106
 
86
107
  function printHelp(provider: string): void {
87
- console.log(`${provider}-relay [--headless] [--cwd PATH] [--relay-url URL] [--approval MODE] [--label NAME] [--agent-id ID] [-- provider-args...]`);
108
+ console.log(`${provider}-relay [--headless] [--rig NAME] [--cwd PATH] [--relay-url URL] [--approval MODE] [--label NAME] [--agent-id ID] [-- provider-args...]`);
109
+ }
110
+
111
+ function signalPromise(): Promise<number> {
112
+ return new Promise<number>((resolve) => {
113
+ process.on("SIGINT", () => resolve(130));
114
+ process.on("SIGTERM", () => resolve(143));
115
+ });
88
116
  }
89
117
 
90
118
  async function waitForShutdown(stop: () => Promise<void>): Promise<void> {
package/src/runner.ts CHANGED
@@ -16,10 +16,12 @@ interface RunnerOptions {
16
16
  headless: boolean;
17
17
  approvalMode: string;
18
18
  label?: string;
19
+ rig?: string;
19
20
  prompt?: string;
20
21
  providerArgs: string[];
21
22
  providerConfig: ProviderConfig;
22
23
  adapter: ProviderAdapter;
24
+ onProviderExit?: (code: number | null) => void;
23
25
  }
24
26
 
25
27
  export class AgentRunner {
@@ -77,7 +79,10 @@ export class AgentRunner {
77
79
 
78
80
  async run(): Promise<void> {
79
81
  this.control = startControlServer({ onStatus: (status) => this.setProviderStatus(status) });
80
- this.options.adapter.onStatusChange((status) => this.setProviderStatus(status));
82
+ this.options.adapter.onStatusChange((status) => {
83
+ this.setProviderStatus(status);
84
+ if (status === "offline" || status === "error") this.options.onProviderExit?.(status === "offline" ? 0 : 1);
85
+ });
81
86
  this.bus.on("message.new", (message) => this.enqueueMessage(message as Message));
82
87
  this.bus.on("command", (type, params, commandId, command) => {
83
88
  void this.handleCommand(type, params, commandId, command);
@@ -123,6 +128,7 @@ export class AgentRunner {
123
128
  headless: this.options.headless,
124
129
  approvalMode: this.options.approvalMode,
125
130
  ...(this.options.label ? { label: this.options.label } : {}),
131
+ ...(this.options.rig ? { rig: this.options.rig } : {}),
126
132
  ...(this.options.prompt ? { prompt: this.options.prompt } : {}),
127
133
  providerArgs: this.options.providerArgs,
128
134
  providerConfig: this.options.providerConfig,