agent-relay 3.2.2 → 3.2.3

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 (35) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/dist/index.cjs +1093 -833
  6. package/dist/src/cli/commands/agent-management.d.ts +2 -2
  7. package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
  8. package/dist/src/cli/commands/agent-management.js +41 -240
  9. package/dist/src/cli/commands/agent-management.js.map +1 -1
  10. package/dist/src/cli/commands/messaging.d.ts +1 -1
  11. package/dist/src/cli/commands/messaging.d.ts.map +1 -1
  12. package/dist/src/cli/commands/messaging.js +14 -5
  13. package/dist/src/cli/commands/messaging.js.map +1 -1
  14. package/dist/src/cli/lib/agent-management-listing.d.ts +4 -1
  15. package/dist/src/cli/lib/agent-management-listing.d.ts.map +1 -1
  16. package/dist/src/cli/lib/agent-management-listing.js +27 -2
  17. package/dist/src/cli/lib/agent-management-listing.js.map +1 -1
  18. package/package.json +8 -8
  19. package/packages/acp-bridge/package.json +2 -2
  20. package/packages/config/package.json +1 -1
  21. package/packages/hooks/package.json +4 -4
  22. package/packages/memory/package.json +2 -2
  23. package/packages/openclaw/package.json +2 -2
  24. package/packages/policy/package.json +2 -2
  25. package/packages/sdk/dist/client.d.ts +66 -0
  26. package/packages/sdk/dist/client.d.ts.map +1 -1
  27. package/packages/sdk/dist/client.js +230 -0
  28. package/packages/sdk/dist/client.js.map +1 -1
  29. package/packages/sdk/package.json +2 -2
  30. package/packages/sdk/src/client.ts +301 -0
  31. package/packages/sdk-py/pyproject.toml +1 -1
  32. package/packages/telemetry/package.json +1 -1
  33. package/packages/trajectory/package.json +2 -2
  34. package/packages/user-directory/package.json +2 -2
  35. package/packages/utils/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -35,13 +35,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
37
  // packages/config/src/bridge-utils.ts
38
- var import_node_child_process2, import_node_util, execAsync;
38
+ var import_node_child_process, import_node_util, execAsync;
39
39
  var init_bridge_utils = __esm({
40
40
  "packages/config/src/bridge-utils.ts"() {
41
41
  "use strict";
42
- import_node_child_process2 = require("node:child_process");
42
+ import_node_child_process = require("node:child_process");
43
43
  import_node_util = require("node:util");
44
- execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
44
+ execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
45
45
  }
46
46
  });
47
47
 
@@ -6885,14 +6885,14 @@ var require_parser = __commonJS({
6885
6885
  case "scalar":
6886
6886
  case "single-quoted-scalar":
6887
6887
  case "double-quoted-scalar": {
6888
- const fs9 = this.flowScalar(this.type);
6888
+ const fs10 = this.flowScalar(this.type);
6889
6889
  if (atNextItem || it.value) {
6890
- map2.items.push({ start, key: fs9, sep: [] });
6890
+ map2.items.push({ start, key: fs10, sep: [] });
6891
6891
  this.onKeyLine = true;
6892
6892
  } else if (it.sep) {
6893
- this.stack.push(fs9);
6893
+ this.stack.push(fs10);
6894
6894
  } else {
6895
- Object.assign(it, { key: fs9, sep: [] });
6895
+ Object.assign(it, { key: fs10, sep: [] });
6896
6896
  this.onKeyLine = true;
6897
6897
  }
6898
6898
  return;
@@ -7020,13 +7020,13 @@ var require_parser = __commonJS({
7020
7020
  case "scalar":
7021
7021
  case "single-quoted-scalar":
7022
7022
  case "double-quoted-scalar": {
7023
- const fs9 = this.flowScalar(this.type);
7023
+ const fs10 = this.flowScalar(this.type);
7024
7024
  if (!it || it.value)
7025
- fc.items.push({ start: [], key: fs9, sep: [] });
7025
+ fc.items.push({ start: [], key: fs10, sep: [] });
7026
7026
  else if (it.sep)
7027
- this.stack.push(fs9);
7027
+ this.stack.push(fs10);
7028
7028
  else
7029
- Object.assign(it, { key: fs9, sep: [] });
7029
+ Object.assign(it, { key: fs10, sep: [] });
7030
7030
  return;
7031
7031
  }
7032
7032
  case "flow-map-end":
@@ -7467,11 +7467,11 @@ var init_types = __esm({
7467
7467
  });
7468
7468
 
7469
7469
  // packages/memory/dist/adapters/inmemory.js
7470
- var import_node_crypto10, InMemoryAdapter;
7470
+ var import_node_crypto11, InMemoryAdapter;
7471
7471
  var init_inmemory = __esm({
7472
7472
  "packages/memory/dist/adapters/inmemory.js"() {
7473
7473
  "use strict";
7474
- import_node_crypto10 = require("node:crypto");
7474
+ import_node_crypto11 = require("node:crypto");
7475
7475
  InMemoryAdapter = class {
7476
7476
  type = "inmemory";
7477
7477
  memories = /* @__PURE__ */ new Map();
@@ -7486,7 +7486,7 @@ var init_inmemory = __esm({
7486
7486
  async init() {
7487
7487
  }
7488
7488
  async add(content, options) {
7489
- const id = (0, import_node_crypto10.randomUUID)();
7489
+ const id = (0, import_node_crypto11.randomUUID)();
7490
7490
  const now = Date.now();
7491
7491
  const entry = {
7492
7492
  id,
@@ -8825,6 +8825,7 @@ __export(index_exports, {
8825
8825
  HOOK_ABI_VERSION: () => HOOK_ABI_VERSION,
8826
8826
  HookEmitter: () => HookEmitter,
8827
8827
  HookRegistry: () => HookRegistry,
8828
+ HttpAgentRelayClient: () => HttpAgentRelayClient,
8828
8829
  InMemoryAdapter: () => InMemoryAdapter,
8829
8830
  InMemoryWorkflowDb: () => InMemoryWorkflowDb,
8830
8831
  JsonFileWorkflowDb: () => JsonFileWorkflowDb,
@@ -8951,623 +8952,12 @@ var PROTOCOL_VERSION = 1;
8951
8952
 
8952
8953
  // packages/sdk/dist/client.js
8953
8954
  var import_node_events = require("node:events");
8954
- var import_node_child_process = require("node:child_process");
8955
+ var import_node_child_process2 = require("node:child_process");
8955
8956
  var import_node_readline = require("node:readline");
8956
- var import_node_fs = __toESM(require("node:fs"), 1);
8957
- var import_node_os = __toESM(require("node:os"), 1);
8958
- var import_node_path = __toESM(require("node:path"), 1);
8957
+ var import_node_fs2 = __toESM(require("node:fs"), 1);
8958
+ var import_node_os3 = __toESM(require("node:os"), 1);
8959
+ var import_node_path3 = __toESM(require("node:path"), 1);
8959
8960
  var import_node_url = require("node:url");
8960
- var AgentRelayProtocolError = class extends Error {
8961
- code;
8962
- retryable;
8963
- data;
8964
- constructor(payload) {
8965
- super(payload.message);
8966
- this.name = "AgentRelayProtocolError";
8967
- this.code = payload.code;
8968
- this.retryable = payload.retryable;
8969
- this.data = payload.data;
8970
- }
8971
- };
8972
- var AgentRelayProcessError = class extends Error {
8973
- constructor(message) {
8974
- super(message);
8975
- this.name = "AgentRelayProcessError";
8976
- }
8977
- };
8978
- function isHeadlessProvider(value) {
8979
- return value === "claude" || value === "opencode";
8980
- }
8981
- var AgentRelayClient = class _AgentRelayClient {
8982
- options;
8983
- child;
8984
- stdoutRl;
8985
- stderrRl;
8986
- lastStderrLine;
8987
- requestSeq = 0;
8988
- pending = /* @__PURE__ */ new Map();
8989
- startingPromise;
8990
- eventListeners = /* @__PURE__ */ new Set();
8991
- stderrListeners = /* @__PURE__ */ new Set();
8992
- eventBuffer = [];
8993
- maxBufferSize = 1e3;
8994
- exitPromise;
8995
- /** The workspace key returned by the broker in its hello_ack response. */
8996
- workspaceKey;
8997
- constructor(options = {}) {
8998
- this.options = {
8999
- binaryPath: options.binaryPath ?? resolveDefaultBinaryPath(),
9000
- binaryArgs: options.binaryArgs ?? [],
9001
- brokerName: options.brokerName ?? (import_node_path.default.basename(options.cwd ?? process.cwd()) || "project"),
9002
- channels: options.channels ?? ["general"],
9003
- cwd: options.cwd ?? process.cwd(),
9004
- env: options.env ?? process.env,
9005
- requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
9006
- shutdownTimeoutMs: options.shutdownTimeoutMs ?? 3e3,
9007
- clientName: options.clientName ?? "@agent-relay/sdk",
9008
- clientVersion: options.clientVersion ?? "0.1.0"
9009
- };
9010
- }
9011
- static async start(options = {}) {
9012
- const client = new _AgentRelayClient(options);
9013
- await client.start();
9014
- return client;
9015
- }
9016
- onEvent(listener) {
9017
- this.eventListeners.add(listener);
9018
- return () => {
9019
- this.eventListeners.delete(listener);
9020
- };
9021
- }
9022
- queryEvents(filter) {
9023
- let events = [...this.eventBuffer];
9024
- if (filter?.kind) {
9025
- events = events.filter((event) => event.kind === filter.kind);
9026
- }
9027
- if (filter?.name) {
9028
- events = events.filter((event) => "name" in event && event.name === filter.name);
9029
- }
9030
- const since = filter?.since;
9031
- if (since !== void 0) {
9032
- events = events.filter((event) => "timestamp" in event && typeof event.timestamp === "number" && event.timestamp >= since);
9033
- }
9034
- const limit = filter?.limit;
9035
- if (limit !== void 0) {
9036
- events = events.slice(-limit);
9037
- }
9038
- return events;
9039
- }
9040
- getLastEvent(kind, name) {
9041
- for (let i = this.eventBuffer.length - 1; i >= 0; i -= 1) {
9042
- const event = this.eventBuffer[i];
9043
- if (event.kind === kind && (!name || "name" in event && event.name === name)) {
9044
- return event;
9045
- }
9046
- }
9047
- return void 0;
9048
- }
9049
- onBrokerStderr(listener) {
9050
- this.stderrListeners.add(listener);
9051
- return () => {
9052
- this.stderrListeners.delete(listener);
9053
- };
9054
- }
9055
- get brokerPid() {
9056
- return this.child?.pid;
9057
- }
9058
- async start() {
9059
- if (this.child) {
9060
- return;
9061
- }
9062
- if (this.startingPromise) {
9063
- return this.startingPromise;
9064
- }
9065
- this.startingPromise = this.startInternal();
9066
- try {
9067
- await this.startingPromise;
9068
- } finally {
9069
- this.startingPromise = void 0;
9070
- }
9071
- }
9072
- /**
9073
- * Pre-register a batch of agents with Relaycast before their steps execute.
9074
- * The broker warms its token cache in parallel; subsequent spawn_agent calls
9075
- * hit the cache rather than waiting on individual HTTP registrations.
9076
- * Fire-and-forget from the caller's perspective — broker responds immediately
9077
- * and registers in the background.
9078
- */
9079
- async preflightAgents(agents) {
9080
- if (agents.length === 0)
9081
- return;
9082
- await this.start();
9083
- await this.requestOk("preflight_agents", { agents });
9084
- }
9085
- async spawnPty(input) {
9086
- await this.start();
9087
- const args = buildPtyArgsWithModel(input.cli, input.args ?? [], input.model);
9088
- const agent = {
9089
- name: input.name,
9090
- runtime: "pty",
9091
- cli: input.cli,
9092
- args,
9093
- channels: input.channels ?? [],
9094
- model: input.model,
9095
- cwd: input.cwd ?? this.options.cwd,
9096
- team: input.team,
9097
- shadow_of: input.shadowOf,
9098
- shadow_mode: input.shadowMode,
9099
- restart_policy: input.restartPolicy
9100
- };
9101
- const result = await this.requestOk("spawn_agent", {
9102
- agent,
9103
- ...input.task != null ? { initial_task: input.task } : {},
9104
- ...input.idleThresholdSecs != null ? { idle_threshold_secs: input.idleThresholdSecs } : {},
9105
- ...input.continueFrom != null ? { continue_from: input.continueFrom } : {},
9106
- ...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
9107
- });
9108
- return result;
9109
- }
9110
- async spawnHeadless(input) {
9111
- await this.start();
9112
- const agent = {
9113
- name: input.name,
9114
- runtime: "headless",
9115
- provider: input.provider,
9116
- args: input.args ?? [],
9117
- channels: input.channels ?? []
9118
- };
9119
- const result = await this.requestOk("spawn_agent", {
9120
- agent,
9121
- ...input.task != null ? { initial_task: input.task } : {},
9122
- ...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
9123
- });
9124
- return result;
9125
- }
9126
- async spawnProvider(input) {
9127
- const transport = input.transport ?? (input.provider === "opencode" ? "headless" : "pty");
9128
- if (transport === "headless") {
9129
- if (!isHeadlessProvider(input.provider)) {
9130
- throw new AgentRelayProcessError(`provider '${input.provider}' does not support headless transport (supported: claude, opencode)`);
9131
- }
9132
- return this.spawnHeadless({
9133
- name: input.name,
9134
- provider: input.provider,
9135
- args: input.args,
9136
- channels: input.channels,
9137
- task: input.task,
9138
- skipRelayPrompt: input.skipRelayPrompt
9139
- });
9140
- }
9141
- return this.spawnPty({
9142
- name: input.name,
9143
- cli: input.provider,
9144
- args: input.args,
9145
- channels: input.channels,
9146
- task: input.task,
9147
- model: input.model,
9148
- cwd: input.cwd,
9149
- team: input.team,
9150
- shadowOf: input.shadowOf,
9151
- shadowMode: input.shadowMode,
9152
- idleThresholdSecs: input.idleThresholdSecs,
9153
- restartPolicy: input.restartPolicy,
9154
- continueFrom: input.continueFrom,
9155
- skipRelayPrompt: input.skipRelayPrompt
9156
- });
9157
- }
9158
- async spawnClaude(input) {
9159
- return this.spawnProvider({ ...input, provider: "claude" });
9160
- }
9161
- async spawnOpencode(input) {
9162
- return this.spawnProvider({ ...input, provider: "opencode" });
9163
- }
9164
- async release(name, reason) {
9165
- await this.start();
9166
- return this.requestOk("release_agent", { name, reason });
9167
- }
9168
- async sendInput(name, data) {
9169
- await this.start();
9170
- return this.requestOk("send_input", { name, data });
9171
- }
9172
- async setModel(name, model, opts) {
9173
- await this.start();
9174
- return this.requestOk("set_model", {
9175
- name,
9176
- model,
9177
- timeout_ms: opts?.timeoutMs
9178
- });
9179
- }
9180
- async getMetrics(agent) {
9181
- await this.start();
9182
- return this.requestOk("get_metrics", { agent });
9183
- }
9184
- async getCrashInsights() {
9185
- await this.start();
9186
- return this.requestOk("get_crash_insights", {});
9187
- }
9188
- async sendMessage(input) {
9189
- await this.start();
9190
- try {
9191
- return await this.requestOk("send_message", {
9192
- to: input.to,
9193
- text: input.text,
9194
- from: input.from,
9195
- thread_id: input.threadId,
9196
- workspace_id: input.workspaceId,
9197
- workspace_alias: input.workspaceAlias,
9198
- priority: input.priority,
9199
- data: input.data
9200
- });
9201
- } catch (error48) {
9202
- if (error48 instanceof AgentRelayProtocolError && error48.code === "unsupported_operation") {
9203
- return { event_id: "unsupported_operation", targets: [] };
9204
- }
9205
- throw error48;
9206
- }
9207
- }
9208
- async listAgents() {
9209
- await this.start();
9210
- const result = await this.requestOk("list_agents", {});
9211
- return result.agents;
9212
- }
9213
- async getStatus() {
9214
- await this.start();
9215
- return this.requestOk("get_status", {});
9216
- }
9217
- async shutdown() {
9218
- if (!this.child) {
9219
- return;
9220
- }
9221
- void this.requestOk("shutdown", {}).catch(() => {
9222
- });
9223
- const child = this.child;
9224
- const wait = this.exitPromise ?? Promise.resolve();
9225
- const waitForExit = async (timeoutMs) => {
9226
- let timer;
9227
- const result = await Promise.race([
9228
- wait.then(() => true),
9229
- new Promise((resolve3) => {
9230
- timer = setTimeout(() => resolve3(false), timeoutMs);
9231
- })
9232
- ]);
9233
- if (timer !== void 0)
9234
- clearTimeout(timer);
9235
- return result;
9236
- };
9237
- if (await waitForExit(this.options.shutdownTimeoutMs)) {
9238
- return;
9239
- }
9240
- if (child.exitCode === null && child.signalCode === null) {
9241
- child.kill("SIGTERM");
9242
- }
9243
- if (await waitForExit(1e3)) {
9244
- return;
9245
- }
9246
- if (child.exitCode === null && child.signalCode === null) {
9247
- child.kill("SIGKILL");
9248
- }
9249
- await waitForExit(1e3);
9250
- }
9251
- async waitForExit() {
9252
- if (!this.child) {
9253
- return;
9254
- }
9255
- await this.exitPromise;
9256
- }
9257
- async startInternal() {
9258
- const resolvedBinary = expandTilde(this.options.binaryPath);
9259
- if (isExplicitPath(this.options.binaryPath) && !import_node_fs.default.existsSync(resolvedBinary)) {
9260
- throw new AgentRelayProcessError(`broker binary not found: ${this.options.binaryPath}`);
9261
- }
9262
- this.lastStderrLine = void 0;
9263
- const args = [
9264
- "init",
9265
- "--name",
9266
- this.options.brokerName,
9267
- ...this.options.channels.length > 0 ? ["--channels", this.options.channels.join(",")] : [],
9268
- ...this.options.binaryArgs
9269
- ];
9270
- const env = { ...this.options.env };
9271
- if (isExplicitPath(this.options.binaryPath)) {
9272
- const binDir = import_node_path.default.dirname(import_node_path.default.resolve(resolvedBinary));
9273
- const currentPath = env.PATH ?? env.Path ?? "";
9274
- if (!currentPath.split(import_node_path.default.delimiter).includes(binDir)) {
9275
- env.PATH = `${binDir}${import_node_path.default.delimiter}${currentPath}`;
9276
- }
9277
- }
9278
- console.error(`[broker] Starting: ${resolvedBinary} ${args.join(" ")}`);
9279
- const child = (0, import_node_child_process.spawn)(resolvedBinary, args, {
9280
- cwd: this.options.cwd,
9281
- env,
9282
- stdio: "pipe"
9283
- });
9284
- this.child = child;
9285
- this.stdoutRl = (0, import_node_readline.createInterface)({ input: child.stdout, crlfDelay: Infinity });
9286
- this.stderrRl = (0, import_node_readline.createInterface)({ input: child.stderr, crlfDelay: Infinity });
9287
- this.stdoutRl.on("line", (line) => {
9288
- this.handleStdoutLine(line);
9289
- });
9290
- this.stderrRl.on("line", (line) => {
9291
- const trimmed = line.trim();
9292
- if (trimmed) {
9293
- this.lastStderrLine = trimmed;
9294
- }
9295
- for (const listener of this.stderrListeners) {
9296
- listener(line);
9297
- }
9298
- });
9299
- this.exitPromise = new Promise((resolve3) => {
9300
- child.once("close", (code, signal) => {
9301
- const detail = this.lastStderrLine ? `: ${this.lastStderrLine}` : "";
9302
- const error48 = new AgentRelayProcessError(`broker exited (code=${code ?? "null"}, signal=${signal ?? "null"})${detail}`);
9303
- this.failAllPending(error48);
9304
- this.disposeProcessHandles();
9305
- resolve3();
9306
- });
9307
- child.once("error", (error48) => {
9308
- this.failAllPending(error48);
9309
- this.disposeProcessHandles();
9310
- resolve3();
9311
- });
9312
- });
9313
- const helloAck = await this.requestHello();
9314
- console.error("[broker] Broker ready (hello handshake complete)");
9315
- if (helloAck.workspace_key) {
9316
- this.workspaceKey = helloAck.workspace_key;
9317
- }
9318
- }
9319
- disposeProcessHandles() {
9320
- this.stdoutRl?.close();
9321
- this.stderrRl?.close();
9322
- this.stdoutRl = void 0;
9323
- this.stderrRl = void 0;
9324
- this.lastStderrLine = void 0;
9325
- this.child = void 0;
9326
- this.exitPromise = void 0;
9327
- }
9328
- failAllPending(error48) {
9329
- for (const pending of this.pending.values()) {
9330
- clearTimeout(pending.timeout);
9331
- pending.reject(error48);
9332
- }
9333
- this.pending.clear();
9334
- }
9335
- handleStdoutLine(line) {
9336
- let parsed;
9337
- try {
9338
- parsed = JSON.parse(line);
9339
- } catch {
9340
- return;
9341
- }
9342
- if (!parsed || typeof parsed !== "object") {
9343
- return;
9344
- }
9345
- if (parsed.v !== PROTOCOL_VERSION || typeof parsed.type !== "string") {
9346
- return;
9347
- }
9348
- const envelope = {
9349
- v: parsed.v,
9350
- type: parsed.type,
9351
- request_id: parsed.request_id,
9352
- payload: parsed.payload
9353
- };
9354
- if (envelope.type === "event") {
9355
- const payload = envelope.payload;
9356
- this.eventBuffer.push(payload);
9357
- if (this.eventBuffer.length > this.maxBufferSize) {
9358
- this.eventBuffer.shift();
9359
- }
9360
- for (const listener of this.eventListeners) {
9361
- listener(payload);
9362
- }
9363
- return;
9364
- }
9365
- if (!envelope.request_id) {
9366
- return;
9367
- }
9368
- const pending = this.pending.get(envelope.request_id);
9369
- if (!pending) {
9370
- return;
9371
- }
9372
- if (envelope.type === "error") {
9373
- clearTimeout(pending.timeout);
9374
- this.pending.delete(envelope.request_id);
9375
- pending.reject(new AgentRelayProtocolError(envelope.payload));
9376
- return;
9377
- }
9378
- if (envelope.type !== pending.expectedType) {
9379
- clearTimeout(pending.timeout);
9380
- this.pending.delete(envelope.request_id);
9381
- pending.reject(new AgentRelayProcessError(`unexpected response type '${envelope.type}' for request '${envelope.request_id}' (expected '${pending.expectedType}')`));
9382
- return;
9383
- }
9384
- clearTimeout(pending.timeout);
9385
- this.pending.delete(envelope.request_id);
9386
- pending.resolve(envelope);
9387
- }
9388
- async requestHello() {
9389
- const payload = {
9390
- client_name: this.options.clientName,
9391
- client_version: this.options.clientVersion
9392
- };
9393
- const frame = await this.sendRequest("hello", payload, "hello_ack");
9394
- return frame.payload;
9395
- }
9396
- async requestOk(type, payload) {
9397
- const frame = await this.sendRequest(type, payload, "ok");
9398
- const result = frame.payload;
9399
- return result.result;
9400
- }
9401
- async sendRequest(type, payload, expectedType) {
9402
- if (!this.child) {
9403
- throw new AgentRelayProcessError("broker is not running");
9404
- }
9405
- const requestId = `req_${++this.requestSeq}`;
9406
- const message = {
9407
- v: PROTOCOL_VERSION,
9408
- type,
9409
- request_id: requestId,
9410
- payload
9411
- };
9412
- const responsePromise = new Promise((resolve3, reject) => {
9413
- const timeout = setTimeout(() => {
9414
- this.pending.delete(requestId);
9415
- reject(new AgentRelayProcessError(`request timed out after ${this.options.requestTimeoutMs}ms (type='${type}', request_id='${requestId}')`));
9416
- }, this.options.requestTimeoutMs);
9417
- this.pending.set(requestId, {
9418
- expectedType,
9419
- resolve: resolve3,
9420
- reject,
9421
- timeout
9422
- });
9423
- });
9424
- const line = `${JSON.stringify(message)}
9425
- `;
9426
- if (!this.child.stdin.write(line)) {
9427
- await (0, import_node_events.once)(this.child.stdin, "drain");
9428
- }
9429
- return responsePromise;
9430
- }
9431
- };
9432
- var CLI_MODEL_FLAG_CLIS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "goose", "aider"]);
9433
- var CLI_DEFAULT_ARGS = {
9434
- codex: ["-c", "check_for_update_on_startup=false"]
9435
- };
9436
- function buildPtyArgsWithModel(cli, args, model) {
9437
- const cliName = cli.split(":")[0].trim().toLowerCase();
9438
- const defaultArgs = CLI_DEFAULT_ARGS[cliName] ?? [];
9439
- const baseArgs = [...defaultArgs, ...args];
9440
- if (!model) {
9441
- return baseArgs;
9442
- }
9443
- if (!CLI_MODEL_FLAG_CLIS.has(cliName)) {
9444
- return baseArgs;
9445
- }
9446
- if (hasModelArg(baseArgs)) {
9447
- return baseArgs;
9448
- }
9449
- return ["--model", model, ...baseArgs];
9450
- }
9451
- function hasModelArg(args) {
9452
- for (let i = 0; i < args.length; i += 1) {
9453
- const arg = args[i];
9454
- if (arg === "--model") {
9455
- return true;
9456
- }
9457
- if (arg.startsWith("--model=")) {
9458
- return true;
9459
- }
9460
- }
9461
- return false;
9462
- }
9463
- function expandTilde(p) {
9464
- if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
9465
- const home = import_node_os.default.homedir();
9466
- return import_node_path.default.join(home, p.slice(2));
9467
- }
9468
- return p;
9469
- }
9470
- function isExplicitPath(binaryPath) {
9471
- return binaryPath.includes("/") || binaryPath.includes("\\") || binaryPath.startsWith(".") || binaryPath.startsWith("~");
9472
- }
9473
- function detectPlatformSuffix() {
9474
- const platformMap = {
9475
- darwin: { arm64: "darwin-arm64", x64: "darwin-x64" },
9476
- linux: { arm64: "linux-arm64", x64: "linux-x64" },
9477
- win32: { x64: "win32-x64" }
9478
- };
9479
- return platformMap[process.platform]?.[process.arch] ?? null;
9480
- }
9481
- function getLatestVersionSync() {
9482
- try {
9483
- const result = (0, import_node_child_process.execSync)("curl -fsSL https://api.github.com/repos/AgentWorkforce/relay/releases/latest", {
9484
- timeout: 15e3,
9485
- stdio: ["pipe", "pipe", "pipe"]
9486
- }).toString();
9487
- const match = result.match(/"tag_name"\s*:\s*"([^"]+)"/);
9488
- if (!match?.[1])
9489
- return null;
9490
- return match[1].replace(/^openclaw-/, "").replace(/^v/, "");
9491
- } catch {
9492
- return null;
9493
- }
9494
- }
9495
- function installBrokerBinary() {
9496
- const suffix = detectPlatformSuffix();
9497
- if (!suffix) {
9498
- throw new AgentRelayProcessError(`Unsupported platform: ${process.platform}-${process.arch}`);
9499
- }
9500
- const homeDir = process.env.HOME || process.env.USERPROFILE || "";
9501
- const installDir = import_node_path.default.join(homeDir, ".agent-relay", "bin");
9502
- const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
9503
- const targetPath = import_node_path.default.join(installDir, brokerExe);
9504
- console.log(`[agent-relay] Broker binary not found, installing for ${suffix}...`);
9505
- const version2 = getLatestVersionSync();
9506
- if (!version2) {
9507
- throw new AgentRelayProcessError("Failed to fetch latest agent-relay version from GitHub.\nInstall manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash");
9508
- }
9509
- const binaryName = `agent-relay-broker-${suffix}`;
9510
- const downloadUrl = `https://github.com/AgentWorkforce/relay/releases/download/v${version2}/${binaryName}`;
9511
- console.log(`[agent-relay] Downloading v${version2} from ${downloadUrl}`);
9512
- try {
9513
- import_node_fs.default.mkdirSync(installDir, { recursive: true });
9514
- (0, import_node_child_process.execSync)(`curl -fsSL "${downloadUrl}" -o "${targetPath}"`, {
9515
- timeout: 6e4,
9516
- stdio: ["pipe", "pipe", "pipe"]
9517
- });
9518
- import_node_fs.default.chmodSync(targetPath, 493);
9519
- if (process.platform === "darwin") {
9520
- try {
9521
- (0, import_node_child_process.execSync)(`xattr -d com.apple.quarantine "${targetPath}" 2>/dev/null || true`, {
9522
- timeout: 1e4,
9523
- stdio: ["pipe", "pipe", "pipe"]
9524
- });
9525
- } catch {
9526
- }
9527
- try {
9528
- (0, import_node_child_process.execSync)(`codesign --force --sign - "${targetPath}"`, {
9529
- timeout: 1e4,
9530
- stdio: ["pipe", "pipe", "pipe"]
9531
- });
9532
- } catch {
9533
- }
9534
- }
9535
- (0, import_node_child_process.execSync)(`"${targetPath}" --help`, { timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
9536
- } catch (err) {
9537
- try {
9538
- import_node_fs.default.unlinkSync(targetPath);
9539
- } catch {
9540
- }
9541
- const message = err instanceof Error ? err.message : String(err);
9542
- throw new AgentRelayProcessError(`Failed to install broker binary: ${message}
9543
- Install manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash`);
9544
- }
9545
- console.log(`[agent-relay] Broker installed to ${targetPath}`);
9546
- return targetPath;
9547
- }
9548
- function resolveDefaultBinaryPath() {
9549
- const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
9550
- const moduleDir = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta_url));
9551
- const workspaceRelease = import_node_path.default.resolve(moduleDir, "..", "..", "..", "target", "release", brokerExe);
9552
- if (import_node_fs.default.existsSync(workspaceRelease)) {
9553
- return workspaceRelease;
9554
- }
9555
- const binDir = import_node_path.default.resolve(moduleDir, "..", "bin");
9556
- const suffix = detectPlatformSuffix();
9557
- if (suffix) {
9558
- const ext = process.platform === "win32" ? ".exe" : "";
9559
- const platformBinary = import_node_path.default.join(binDir, `agent-relay-broker-${suffix}${ext}`);
9560
- if (import_node_fs.default.existsSync(platformBinary)) {
9561
- return platformBinary;
9562
- }
9563
- }
9564
- const homeDir = process.env.HOME || process.env.USERPROFILE || "";
9565
- const standaloneBroker = import_node_path.default.join(homeDir, ".agent-relay", "bin", brokerExe);
9566
- if (import_node_fs.default.existsSync(standaloneBroker)) {
9567
- return standaloneBroker;
9568
- }
9569
- return installBrokerBinary();
9570
- }
9571
8961
 
9572
8962
  // packages/config/src/relay-config.ts
9573
8963
  var DEFAULT_CONNECTION_CONFIG = {
@@ -9580,28 +8970,66 @@ var DEFAULT_CONNECTION_CONFIG = {
9580
8970
  };
9581
8971
 
9582
8972
  // packages/config/src/bridge-config.ts
9583
- var import_node_path3 = __toESM(require("node:path"), 1);
9584
- var import_node_os3 = __toESM(require("node:os"), 1);
9585
-
9586
- // packages/config/src/project-namespace.ts
9587
8973
  var import_node_path2 = __toESM(require("node:path"), 1);
9588
8974
  var import_node_os2 = __toESM(require("node:os"), 1);
8975
+
8976
+ // packages/config/src/project-namespace.ts
8977
+ var import_node_crypto = __toESM(require("node:crypto"), 1);
8978
+ var import_node_path = __toESM(require("node:path"), 1);
8979
+ var import_node_fs = __toESM(require("node:fs"), 1);
8980
+ var import_node_os = __toESM(require("node:os"), 1);
9589
8981
  function getGlobalBaseDir() {
9590
8982
  if (process.env.AGENT_RELAY_DATA_DIR) {
9591
8983
  return process.env.AGENT_RELAY_DATA_DIR;
9592
8984
  }
9593
8985
  const xdgDataHome = process.env.XDG_DATA_HOME;
9594
8986
  if (xdgDataHome) {
9595
- return import_node_path2.default.join(xdgDataHome, "agent-relay");
8987
+ return import_node_path.default.join(xdgDataHome, "agent-relay");
9596
8988
  }
9597
- return import_node_path2.default.join(import_node_os2.default.homedir(), ".agent-relay");
8989
+ return import_node_path.default.join(import_node_os.default.homedir(), ".agent-relay");
9598
8990
  }
9599
8991
  var GLOBAL_BASE_DIR = getGlobalBaseDir();
8992
+ var PROJECT_DATA_DIR = ".agent-relay";
8993
+ function hashPath(projectPath) {
8994
+ const normalized = import_node_path.default.resolve(projectPath);
8995
+ const hash2 = import_node_crypto.default.createHash("sha256").update(normalized).digest("hex");
8996
+ return hash2.substring(0, 12);
8997
+ }
8998
+ function findProjectRoot(startDir = process.cwd()) {
8999
+ if (process.env.AGENT_RELAY_PROJECT) {
9000
+ return import_node_path.default.resolve(process.env.AGENT_RELAY_PROJECT);
9001
+ }
9002
+ let current = import_node_path.default.resolve(startDir);
9003
+ const root = import_node_path.default.parse(current).root;
9004
+ const markers = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".agent-relay"];
9005
+ while (current !== root) {
9006
+ for (const marker of markers) {
9007
+ if (import_node_fs.default.existsSync(import_node_path.default.join(current, marker))) {
9008
+ return current;
9009
+ }
9010
+ }
9011
+ current = import_node_path.default.dirname(current);
9012
+ }
9013
+ return import_node_path.default.resolve(startDir);
9014
+ }
9015
+ function getProjectPaths(projectRoot) {
9016
+ const root = projectRoot ?? findProjectRoot();
9017
+ const projectId = hashPath(root);
9018
+ const dataDir = import_node_path.default.join(root, PROJECT_DATA_DIR);
9019
+ return {
9020
+ dataDir,
9021
+ teamDir: import_node_path.default.join(dataDir, "team"),
9022
+ dbPath: import_node_path.default.join(dataDir, "messages.sqlite"),
9023
+ socketPath: import_node_path.default.join(dataDir, "relay.sock"),
9024
+ projectRoot: root,
9025
+ projectId
9026
+ };
9027
+ }
9600
9028
 
9601
9029
  // packages/config/src/bridge-config.ts
9602
9030
  var CONFIG_PATHS = [
9603
- import_node_path3.default.join(import_node_os3.default.homedir(), ".agent-relay", "bridge.json"),
9604
- import_node_path3.default.join(import_node_os3.default.homedir(), ".config", "agent-relay", "bridge.json")
9031
+ import_node_path2.default.join(import_node_os2.default.homedir(), ".agent-relay", "bridge.json"),
9032
+ import_node_path2.default.join(import_node_os2.default.homedir(), ".config", "agent-relay", "bridge.json")
9605
9033
  ];
9606
9034
 
9607
9035
  // packages/config/src/index.ts
@@ -15501,93 +14929,924 @@ var ModelOptions = {
15501
14929
  Droid: DROID_MODEL_OPTIONS,
15502
14930
  Opencode: OPENCODE_MODEL_OPTIONS
15503
14931
  };
15504
- var SwarmPatterns = {
15505
- /** Central coordinator distributes tasks to workers */
15506
- HUB_SPOKE: "hub-spoke",
15507
- /** Directed acyclic graph with dependencies */
15508
- DAG: "dag",
15509
- /** Parallel execution across multiple agents */
15510
- FAN_OUT: "fan-out",
15511
- /** Sequential processing through stages */
15512
- PIPELINE: "pipeline",
15513
- /** Agents reach agreement before proceeding */
15514
- CONSENSUS: "consensus",
15515
- /** Fully connected peer-to-peer communication */
15516
- MESH: "mesh",
15517
- /** Sequential handoff between agents */
15518
- HANDOFF: "handoff",
15519
- /** Cascading delegation */
15520
- CASCADE: "cascade",
15521
- /** Agents debate to reach conclusion */
15522
- DEBATE: "debate",
15523
- /** Tree-structured coordination */
15524
- HIERARCHICAL: "hierarchical"
14932
+ var SwarmPatterns = {
14933
+ /** Central coordinator distributes tasks to workers */
14934
+ HUB_SPOKE: "hub-spoke",
14935
+ /** Directed acyclic graph with dependencies */
14936
+ DAG: "dag",
14937
+ /** Parallel execution across multiple agents */
14938
+ FAN_OUT: "fan-out",
14939
+ /** Sequential processing through stages */
14940
+ PIPELINE: "pipeline",
14941
+ /** Agents reach agreement before proceeding */
14942
+ CONSENSUS: "consensus",
14943
+ /** Fully connected peer-to-peer communication */
14944
+ MESH: "mesh",
14945
+ /** Sequential handoff between agents */
14946
+ HANDOFF: "handoff",
14947
+ /** Cascading delegation */
14948
+ CASCADE: "cascade",
14949
+ /** Agents debate to reach conclusion */
14950
+ DEBATE: "debate",
14951
+ /** Tree-structured coordination */
14952
+ HIERARCHICAL: "hierarchical"
14953
+ };
14954
+ var CLIRegistry = {
14955
+ claude: {
14956
+ name: "Claude Code",
14957
+ package: "@anthropic-ai/claude-code",
14958
+ version: "2.1.72",
14959
+ install: "npm install -g @anthropic-ai/claude-code",
14960
+ npmLink: "https://www.npmjs.com/package/@anthropic-ai"
14961
+ },
14962
+ codex: {
14963
+ name: "Codex CLI",
14964
+ package: "@openai/codex",
14965
+ version: "0.114.0",
14966
+ install: "npm install -g @openai/codex",
14967
+ npmLink: "https://www.npmjs.com/package/@openai/codex"
14968
+ },
14969
+ gemini: {
14970
+ name: "Gemini CLI",
14971
+ package: "@google/gemini-cli",
14972
+ version: "0.33.0",
14973
+ install: "npm install -g @google/gemini-cli",
14974
+ npmLink: "https://www.npmjs.com/package/@google/gemini-cli"
14975
+ },
14976
+ cursor: {
14977
+ name: "Cursor",
14978
+ package: "cursor",
14979
+ version: "2026.02.27-e7d2ef6",
14980
+ install: "Download from cursor.com",
14981
+ npmLink: void 0
14982
+ },
14983
+ droid: {
14984
+ name: "Droid",
14985
+ package: "droid",
14986
+ version: "0.1.0",
14987
+ install: "Download from droid.dev",
14988
+ npmLink: void 0
14989
+ },
14990
+ opencode: {
14991
+ name: "OpenCode",
14992
+ package: "opencode-ai",
14993
+ version: "1.2.24",
14994
+ install: "npm install -g opencode-ai",
14995
+ npmLink: "https://www.npmjs.com/package/opencode-ai"
14996
+ },
14997
+ aider: {
14998
+ name: "Aider",
14999
+ package: "aider-chat",
15000
+ version: "0.72.1",
15001
+ install: "pip install aider-chat",
15002
+ npmLink: void 0
15003
+ },
15004
+ goose: {
15005
+ name: "Goose",
15006
+ package: "goose-ai",
15007
+ version: "1.0.16",
15008
+ install: "pip install goose-ai",
15009
+ npmLink: void 0
15010
+ }
15011
+ };
15012
+ var DefaultModels = {
15013
+ claude: "sonnet",
15014
+ codex: "gpt-5.4",
15015
+ gemini: "gemini-3.1-pro-preview",
15016
+ cursor: "opus-4.6-thinking",
15017
+ droid: "opus-4.6-fast",
15018
+ opencode: "openai/gpt-5.2"
15019
+ };
15020
+
15021
+ // packages/sdk/dist/client.js
15022
+ var AgentRelayProtocolError = class extends Error {
15023
+ code;
15024
+ retryable;
15025
+ data;
15026
+ constructor(payload) {
15027
+ super(payload.message);
15028
+ this.name = "AgentRelayProtocolError";
15029
+ this.code = payload.code;
15030
+ this.retryable = payload.retryable;
15031
+ this.data = payload.data;
15032
+ }
15033
+ };
15034
+ var AgentRelayProcessError = class extends Error {
15035
+ constructor(message) {
15036
+ super(message);
15037
+ this.name = "AgentRelayProcessError";
15038
+ }
15039
+ };
15040
+ function isHeadlessProvider(value) {
15041
+ return value === "claude" || value === "opencode";
15042
+ }
15043
+ var AgentRelayClient = class _AgentRelayClient {
15044
+ options;
15045
+ child;
15046
+ stdoutRl;
15047
+ stderrRl;
15048
+ lastStderrLine;
15049
+ requestSeq = 0;
15050
+ pending = /* @__PURE__ */ new Map();
15051
+ startingPromise;
15052
+ eventListeners = /* @__PURE__ */ new Set();
15053
+ stderrListeners = /* @__PURE__ */ new Set();
15054
+ eventBuffer = [];
15055
+ maxBufferSize = 1e3;
15056
+ exitPromise;
15057
+ /** The workspace key returned by the broker in its hello_ack response. */
15058
+ workspaceKey;
15059
+ constructor(options = {}) {
15060
+ this.options = {
15061
+ binaryPath: options.binaryPath ?? resolveDefaultBinaryPath(),
15062
+ binaryArgs: options.binaryArgs ?? [],
15063
+ brokerName: options.brokerName ?? (import_node_path3.default.basename(options.cwd ?? process.cwd()) || "project"),
15064
+ channels: options.channels ?? ["general"],
15065
+ cwd: options.cwd ?? process.cwd(),
15066
+ env: options.env ?? process.env,
15067
+ requestTimeoutMs: options.requestTimeoutMs ?? 1e4,
15068
+ shutdownTimeoutMs: options.shutdownTimeoutMs ?? 3e3,
15069
+ clientName: options.clientName ?? "@agent-relay/sdk",
15070
+ clientVersion: options.clientVersion ?? "0.1.0"
15071
+ };
15072
+ }
15073
+ static async start(options = {}) {
15074
+ const client = new _AgentRelayClient(options);
15075
+ await client.start();
15076
+ return client;
15077
+ }
15078
+ onEvent(listener) {
15079
+ this.eventListeners.add(listener);
15080
+ return () => {
15081
+ this.eventListeners.delete(listener);
15082
+ };
15083
+ }
15084
+ queryEvents(filter) {
15085
+ let events = [...this.eventBuffer];
15086
+ if (filter?.kind) {
15087
+ events = events.filter((event) => event.kind === filter.kind);
15088
+ }
15089
+ if (filter?.name) {
15090
+ events = events.filter((event) => "name" in event && event.name === filter.name);
15091
+ }
15092
+ const since = filter?.since;
15093
+ if (since !== void 0) {
15094
+ events = events.filter((event) => "timestamp" in event && typeof event.timestamp === "number" && event.timestamp >= since);
15095
+ }
15096
+ const limit = filter?.limit;
15097
+ if (limit !== void 0) {
15098
+ events = events.slice(-limit);
15099
+ }
15100
+ return events;
15101
+ }
15102
+ getLastEvent(kind, name) {
15103
+ for (let i = this.eventBuffer.length - 1; i >= 0; i -= 1) {
15104
+ const event = this.eventBuffer[i];
15105
+ if (event.kind === kind && (!name || "name" in event && event.name === name)) {
15106
+ return event;
15107
+ }
15108
+ }
15109
+ return void 0;
15110
+ }
15111
+ onBrokerStderr(listener) {
15112
+ this.stderrListeners.add(listener);
15113
+ return () => {
15114
+ this.stderrListeners.delete(listener);
15115
+ };
15116
+ }
15117
+ get brokerPid() {
15118
+ return this.child?.pid;
15119
+ }
15120
+ async start() {
15121
+ if (this.child) {
15122
+ return;
15123
+ }
15124
+ if (this.startingPromise) {
15125
+ return this.startingPromise;
15126
+ }
15127
+ this.startingPromise = this.startInternal();
15128
+ try {
15129
+ await this.startingPromise;
15130
+ } finally {
15131
+ this.startingPromise = void 0;
15132
+ }
15133
+ }
15134
+ /**
15135
+ * Pre-register a batch of agents with Relaycast before their steps execute.
15136
+ * The broker warms its token cache in parallel; subsequent spawn_agent calls
15137
+ * hit the cache rather than waiting on individual HTTP registrations.
15138
+ * Fire-and-forget from the caller's perspective — broker responds immediately
15139
+ * and registers in the background.
15140
+ */
15141
+ async preflightAgents(agents) {
15142
+ if (agents.length === 0)
15143
+ return;
15144
+ await this.start();
15145
+ await this.requestOk("preflight_agents", { agents });
15146
+ }
15147
+ async spawnPty(input) {
15148
+ await this.start();
15149
+ const args = buildPtyArgsWithModel(input.cli, input.args ?? [], input.model);
15150
+ const agent = {
15151
+ name: input.name,
15152
+ runtime: "pty",
15153
+ cli: input.cli,
15154
+ args,
15155
+ channels: input.channels ?? [],
15156
+ model: input.model,
15157
+ cwd: input.cwd ?? this.options.cwd,
15158
+ team: input.team,
15159
+ shadow_of: input.shadowOf,
15160
+ shadow_mode: input.shadowMode,
15161
+ restart_policy: input.restartPolicy
15162
+ };
15163
+ const result = await this.requestOk("spawn_agent", {
15164
+ agent,
15165
+ ...input.task != null ? { initial_task: input.task } : {},
15166
+ ...input.idleThresholdSecs != null ? { idle_threshold_secs: input.idleThresholdSecs } : {},
15167
+ ...input.continueFrom != null ? { continue_from: input.continueFrom } : {},
15168
+ ...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
15169
+ });
15170
+ return result;
15171
+ }
15172
+ async spawnHeadless(input) {
15173
+ await this.start();
15174
+ const agent = {
15175
+ name: input.name,
15176
+ runtime: "headless",
15177
+ provider: input.provider,
15178
+ args: input.args ?? [],
15179
+ channels: input.channels ?? []
15180
+ };
15181
+ const result = await this.requestOk("spawn_agent", {
15182
+ agent,
15183
+ ...input.task != null ? { initial_task: input.task } : {},
15184
+ ...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
15185
+ });
15186
+ return result;
15187
+ }
15188
+ async spawnProvider(input) {
15189
+ const transport = input.transport ?? (input.provider === "opencode" ? "headless" : "pty");
15190
+ if (transport === "headless") {
15191
+ if (!isHeadlessProvider(input.provider)) {
15192
+ throw new AgentRelayProcessError(`provider '${input.provider}' does not support headless transport (supported: claude, opencode)`);
15193
+ }
15194
+ return this.spawnHeadless({
15195
+ name: input.name,
15196
+ provider: input.provider,
15197
+ args: input.args,
15198
+ channels: input.channels,
15199
+ task: input.task,
15200
+ skipRelayPrompt: input.skipRelayPrompt
15201
+ });
15202
+ }
15203
+ return this.spawnPty({
15204
+ name: input.name,
15205
+ cli: input.provider,
15206
+ args: input.args,
15207
+ channels: input.channels,
15208
+ task: input.task,
15209
+ model: input.model,
15210
+ cwd: input.cwd,
15211
+ team: input.team,
15212
+ shadowOf: input.shadowOf,
15213
+ shadowMode: input.shadowMode,
15214
+ idleThresholdSecs: input.idleThresholdSecs,
15215
+ restartPolicy: input.restartPolicy,
15216
+ continueFrom: input.continueFrom,
15217
+ skipRelayPrompt: input.skipRelayPrompt
15218
+ });
15219
+ }
15220
+ async spawnClaude(input) {
15221
+ return this.spawnProvider({ ...input, provider: "claude" });
15222
+ }
15223
+ async spawnOpencode(input) {
15224
+ return this.spawnProvider({ ...input, provider: "opencode" });
15225
+ }
15226
+ async release(name, reason) {
15227
+ await this.start();
15228
+ return this.requestOk("release_agent", { name, reason });
15229
+ }
15230
+ async sendInput(name, data) {
15231
+ await this.start();
15232
+ return this.requestOk("send_input", { name, data });
15233
+ }
15234
+ async setModel(name, model, opts) {
15235
+ await this.start();
15236
+ return this.requestOk("set_model", {
15237
+ name,
15238
+ model,
15239
+ timeout_ms: opts?.timeoutMs
15240
+ });
15241
+ }
15242
+ async getMetrics(agent) {
15243
+ await this.start();
15244
+ return this.requestOk("get_metrics", { agent });
15245
+ }
15246
+ async getCrashInsights() {
15247
+ await this.start();
15248
+ return this.requestOk("get_crash_insights", {});
15249
+ }
15250
+ async sendMessage(input) {
15251
+ await this.start();
15252
+ try {
15253
+ return await this.requestOk("send_message", {
15254
+ to: input.to,
15255
+ text: input.text,
15256
+ from: input.from,
15257
+ thread_id: input.threadId,
15258
+ workspace_id: input.workspaceId,
15259
+ workspace_alias: input.workspaceAlias,
15260
+ priority: input.priority,
15261
+ data: input.data
15262
+ });
15263
+ } catch (error48) {
15264
+ if (error48 instanceof AgentRelayProtocolError && error48.code === "unsupported_operation") {
15265
+ return { event_id: "unsupported_operation", targets: [] };
15266
+ }
15267
+ throw error48;
15268
+ }
15269
+ }
15270
+ async listAgents() {
15271
+ await this.start();
15272
+ const result = await this.requestOk("list_agents", {});
15273
+ return result.agents;
15274
+ }
15275
+ async getStatus() {
15276
+ await this.start();
15277
+ return this.requestOk("get_status", {});
15278
+ }
15279
+ async shutdown() {
15280
+ if (!this.child) {
15281
+ return;
15282
+ }
15283
+ void this.requestOk("shutdown", {}).catch(() => {
15284
+ });
15285
+ const child = this.child;
15286
+ const wait = this.exitPromise ?? Promise.resolve();
15287
+ const waitForExit = async (timeoutMs) => {
15288
+ let timer;
15289
+ const result = await Promise.race([
15290
+ wait.then(() => true),
15291
+ new Promise((resolve3) => {
15292
+ timer = setTimeout(() => resolve3(false), timeoutMs);
15293
+ })
15294
+ ]);
15295
+ if (timer !== void 0)
15296
+ clearTimeout(timer);
15297
+ return result;
15298
+ };
15299
+ if (await waitForExit(this.options.shutdownTimeoutMs)) {
15300
+ return;
15301
+ }
15302
+ if (child.exitCode === null && child.signalCode === null) {
15303
+ child.kill("SIGTERM");
15304
+ }
15305
+ if (await waitForExit(1e3)) {
15306
+ return;
15307
+ }
15308
+ if (child.exitCode === null && child.signalCode === null) {
15309
+ child.kill("SIGKILL");
15310
+ }
15311
+ await waitForExit(1e3);
15312
+ }
15313
+ async waitForExit() {
15314
+ if (!this.child) {
15315
+ return;
15316
+ }
15317
+ await this.exitPromise;
15318
+ }
15319
+ async startInternal() {
15320
+ const resolvedBinary = expandTilde(this.options.binaryPath);
15321
+ if (isExplicitPath(this.options.binaryPath) && !import_node_fs2.default.existsSync(resolvedBinary)) {
15322
+ throw new AgentRelayProcessError(`broker binary not found: ${this.options.binaryPath}`);
15323
+ }
15324
+ this.lastStderrLine = void 0;
15325
+ const args = [
15326
+ "init",
15327
+ "--name",
15328
+ this.options.brokerName,
15329
+ ...this.options.channels.length > 0 ? ["--channels", this.options.channels.join(",")] : [],
15330
+ ...this.options.binaryArgs
15331
+ ];
15332
+ const env = { ...this.options.env };
15333
+ if (isExplicitPath(this.options.binaryPath)) {
15334
+ const binDir = import_node_path3.default.dirname(import_node_path3.default.resolve(resolvedBinary));
15335
+ const currentPath = env.PATH ?? env.Path ?? "";
15336
+ if (!currentPath.split(import_node_path3.default.delimiter).includes(binDir)) {
15337
+ env.PATH = `${binDir}${import_node_path3.default.delimiter}${currentPath}`;
15338
+ }
15339
+ }
15340
+ console.error(`[broker] Starting: ${resolvedBinary} ${args.join(" ")}`);
15341
+ const child = (0, import_node_child_process2.spawn)(resolvedBinary, args, {
15342
+ cwd: this.options.cwd,
15343
+ env,
15344
+ stdio: "pipe"
15345
+ });
15346
+ this.child = child;
15347
+ this.stdoutRl = (0, import_node_readline.createInterface)({ input: child.stdout, crlfDelay: Infinity });
15348
+ this.stderrRl = (0, import_node_readline.createInterface)({ input: child.stderr, crlfDelay: Infinity });
15349
+ this.stdoutRl.on("line", (line) => {
15350
+ this.handleStdoutLine(line);
15351
+ });
15352
+ this.stderrRl.on("line", (line) => {
15353
+ const trimmed = line.trim();
15354
+ if (trimmed) {
15355
+ this.lastStderrLine = trimmed;
15356
+ }
15357
+ for (const listener of this.stderrListeners) {
15358
+ listener(line);
15359
+ }
15360
+ });
15361
+ this.exitPromise = new Promise((resolve3) => {
15362
+ child.once("close", (code, signal) => {
15363
+ const detail = this.lastStderrLine ? `: ${this.lastStderrLine}` : "";
15364
+ const error48 = new AgentRelayProcessError(`broker exited (code=${code ?? "null"}, signal=${signal ?? "null"})${detail}`);
15365
+ this.failAllPending(error48);
15366
+ this.disposeProcessHandles();
15367
+ resolve3();
15368
+ });
15369
+ child.once("error", (error48) => {
15370
+ this.failAllPending(error48);
15371
+ this.disposeProcessHandles();
15372
+ resolve3();
15373
+ });
15374
+ });
15375
+ const helloAck = await this.requestHello();
15376
+ console.error("[broker] Broker ready (hello handshake complete)");
15377
+ if (helloAck.workspace_key) {
15378
+ this.workspaceKey = helloAck.workspace_key;
15379
+ }
15380
+ }
15381
+ disposeProcessHandles() {
15382
+ this.stdoutRl?.close();
15383
+ this.stderrRl?.close();
15384
+ this.stdoutRl = void 0;
15385
+ this.stderrRl = void 0;
15386
+ this.lastStderrLine = void 0;
15387
+ this.child = void 0;
15388
+ this.exitPromise = void 0;
15389
+ }
15390
+ failAllPending(error48) {
15391
+ for (const pending of this.pending.values()) {
15392
+ clearTimeout(pending.timeout);
15393
+ pending.reject(error48);
15394
+ }
15395
+ this.pending.clear();
15396
+ }
15397
+ handleStdoutLine(line) {
15398
+ let parsed;
15399
+ try {
15400
+ parsed = JSON.parse(line);
15401
+ } catch {
15402
+ return;
15403
+ }
15404
+ if (!parsed || typeof parsed !== "object") {
15405
+ return;
15406
+ }
15407
+ if (parsed.v !== PROTOCOL_VERSION || typeof parsed.type !== "string") {
15408
+ return;
15409
+ }
15410
+ const envelope = {
15411
+ v: parsed.v,
15412
+ type: parsed.type,
15413
+ request_id: parsed.request_id,
15414
+ payload: parsed.payload
15415
+ };
15416
+ if (envelope.type === "event") {
15417
+ const payload = envelope.payload;
15418
+ this.eventBuffer.push(payload);
15419
+ if (this.eventBuffer.length > this.maxBufferSize) {
15420
+ this.eventBuffer.shift();
15421
+ }
15422
+ for (const listener of this.eventListeners) {
15423
+ listener(payload);
15424
+ }
15425
+ return;
15426
+ }
15427
+ if (!envelope.request_id) {
15428
+ return;
15429
+ }
15430
+ const pending = this.pending.get(envelope.request_id);
15431
+ if (!pending) {
15432
+ return;
15433
+ }
15434
+ if (envelope.type === "error") {
15435
+ clearTimeout(pending.timeout);
15436
+ this.pending.delete(envelope.request_id);
15437
+ pending.reject(new AgentRelayProtocolError(envelope.payload));
15438
+ return;
15439
+ }
15440
+ if (envelope.type !== pending.expectedType) {
15441
+ clearTimeout(pending.timeout);
15442
+ this.pending.delete(envelope.request_id);
15443
+ pending.reject(new AgentRelayProcessError(`unexpected response type '${envelope.type}' for request '${envelope.request_id}' (expected '${pending.expectedType}')`));
15444
+ return;
15445
+ }
15446
+ clearTimeout(pending.timeout);
15447
+ this.pending.delete(envelope.request_id);
15448
+ pending.resolve(envelope);
15449
+ }
15450
+ async requestHello() {
15451
+ const payload = {
15452
+ client_name: this.options.clientName,
15453
+ client_version: this.options.clientVersion
15454
+ };
15455
+ const frame = await this.sendRequest("hello", payload, "hello_ack");
15456
+ return frame.payload;
15457
+ }
15458
+ async requestOk(type, payload) {
15459
+ const frame = await this.sendRequest(type, payload, "ok");
15460
+ const result = frame.payload;
15461
+ return result.result;
15462
+ }
15463
+ async sendRequest(type, payload, expectedType) {
15464
+ if (!this.child) {
15465
+ throw new AgentRelayProcessError("broker is not running");
15466
+ }
15467
+ const requestId = `req_${++this.requestSeq}`;
15468
+ const message = {
15469
+ v: PROTOCOL_VERSION,
15470
+ type,
15471
+ request_id: requestId,
15472
+ payload
15473
+ };
15474
+ const responsePromise = new Promise((resolve3, reject) => {
15475
+ const timeout = setTimeout(() => {
15476
+ this.pending.delete(requestId);
15477
+ reject(new AgentRelayProcessError(`request timed out after ${this.options.requestTimeoutMs}ms (type='${type}', request_id='${requestId}')`));
15478
+ }, this.options.requestTimeoutMs);
15479
+ this.pending.set(requestId, {
15480
+ expectedType,
15481
+ resolve: resolve3,
15482
+ reject,
15483
+ timeout
15484
+ });
15485
+ });
15486
+ const line = `${JSON.stringify(message)}
15487
+ `;
15488
+ if (!this.child.stdin.write(line)) {
15489
+ await (0, import_node_events.once)(this.child.stdin, "drain");
15490
+ }
15491
+ return responsePromise;
15492
+ }
15493
+ };
15494
+ var CLI_MODEL_FLAG_CLIS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "goose", "aider"]);
15495
+ var CLI_DEFAULT_ARGS = {
15496
+ codex: ["-c", "check_for_update_on_startup=false"]
15525
15497
  };
15526
- var CLIRegistry = {
15527
- claude: {
15528
- name: "Claude Code",
15529
- package: "@anthropic-ai/claude-code",
15530
- version: "2.1.72",
15531
- install: "npm install -g @anthropic-ai/claude-code",
15532
- npmLink: "https://www.npmjs.com/package/@anthropic-ai"
15533
- },
15534
- codex: {
15535
- name: "Codex CLI",
15536
- package: "@openai/codex",
15537
- version: "0.114.0",
15538
- install: "npm install -g @openai/codex",
15539
- npmLink: "https://www.npmjs.com/package/@openai/codex"
15540
- },
15541
- gemini: {
15542
- name: "Gemini CLI",
15543
- package: "@google/gemini-cli",
15544
- version: "0.33.0",
15545
- install: "npm install -g @google/gemini-cli",
15546
- npmLink: "https://www.npmjs.com/package/@google/gemini-cli"
15547
- },
15548
- cursor: {
15549
- name: "Cursor",
15550
- package: "cursor",
15551
- version: "2026.02.27-e7d2ef6",
15552
- install: "Download from cursor.com",
15553
- npmLink: void 0
15554
- },
15555
- droid: {
15556
- name: "Droid",
15557
- package: "droid",
15558
- version: "0.1.0",
15559
- install: "Download from droid.dev",
15560
- npmLink: void 0
15561
- },
15562
- opencode: {
15563
- name: "OpenCode",
15564
- package: "opencode-ai",
15565
- version: "1.2.24",
15566
- install: "npm install -g opencode-ai",
15567
- npmLink: "https://www.npmjs.com/package/opencode-ai"
15568
- },
15569
- aider: {
15570
- name: "Aider",
15571
- package: "aider-chat",
15572
- version: "0.72.1",
15573
- install: "pip install aider-chat",
15574
- npmLink: void 0
15575
- },
15576
- goose: {
15577
- name: "Goose",
15578
- package: "goose-ai",
15579
- version: "1.0.16",
15580
- install: "pip install goose-ai",
15581
- npmLink: void 0
15498
+ function buildPtyArgsWithModel(cli, args, model) {
15499
+ const cliName = cli.split(":")[0].trim().toLowerCase();
15500
+ const defaultArgs = CLI_DEFAULT_ARGS[cliName] ?? [];
15501
+ const baseArgs = [...defaultArgs, ...args];
15502
+ if (!model) {
15503
+ return baseArgs;
15504
+ }
15505
+ if (!CLI_MODEL_FLAG_CLIS.has(cliName)) {
15506
+ return baseArgs;
15507
+ }
15508
+ if (hasModelArg(baseArgs)) {
15509
+ return baseArgs;
15510
+ }
15511
+ return ["--model", model, ...baseArgs];
15512
+ }
15513
+ function hasModelArg(args) {
15514
+ for (let i = 0; i < args.length; i += 1) {
15515
+ const arg = args[i];
15516
+ if (arg === "--model") {
15517
+ return true;
15518
+ }
15519
+ if (arg.startsWith("--model=")) {
15520
+ return true;
15521
+ }
15522
+ }
15523
+ return false;
15524
+ }
15525
+ function expandTilde(p) {
15526
+ if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
15527
+ const home = import_node_os3.default.homedir();
15528
+ return import_node_path3.default.join(home, p.slice(2));
15529
+ }
15530
+ return p;
15531
+ }
15532
+ function isExplicitPath(binaryPath) {
15533
+ return binaryPath.includes("/") || binaryPath.includes("\\") || binaryPath.startsWith(".") || binaryPath.startsWith("~");
15534
+ }
15535
+ function detectPlatformSuffix() {
15536
+ const platformMap = {
15537
+ darwin: { arm64: "darwin-arm64", x64: "darwin-x64" },
15538
+ linux: { arm64: "linux-arm64", x64: "linux-x64" },
15539
+ win32: { x64: "win32-x64" }
15540
+ };
15541
+ return platformMap[process.platform]?.[process.arch] ?? null;
15542
+ }
15543
+ function getLatestVersionSync() {
15544
+ try {
15545
+ const result = (0, import_node_child_process2.execSync)("curl -fsSL https://api.github.com/repos/AgentWorkforce/relay/releases/latest", {
15546
+ timeout: 15e3,
15547
+ stdio: ["pipe", "pipe", "pipe"]
15548
+ }).toString();
15549
+ const match = result.match(/"tag_name"\s*:\s*"([^"]+)"/);
15550
+ if (!match?.[1])
15551
+ return null;
15552
+ return match[1].replace(/^openclaw-/, "").replace(/^v/, "");
15553
+ } catch {
15554
+ return null;
15555
+ }
15556
+ }
15557
+ function installBrokerBinary() {
15558
+ const suffix = detectPlatformSuffix();
15559
+ if (!suffix) {
15560
+ throw new AgentRelayProcessError(`Unsupported platform: ${process.platform}-${process.arch}`);
15561
+ }
15562
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
15563
+ const installDir = import_node_path3.default.join(homeDir, ".agent-relay", "bin");
15564
+ const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
15565
+ const targetPath = import_node_path3.default.join(installDir, brokerExe);
15566
+ console.log(`[agent-relay] Broker binary not found, installing for ${suffix}...`);
15567
+ const version2 = getLatestVersionSync();
15568
+ if (!version2) {
15569
+ throw new AgentRelayProcessError("Failed to fetch latest agent-relay version from GitHub.\nInstall manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash");
15570
+ }
15571
+ const binaryName = `agent-relay-broker-${suffix}`;
15572
+ const downloadUrl = `https://github.com/AgentWorkforce/relay/releases/download/v${version2}/${binaryName}`;
15573
+ console.log(`[agent-relay] Downloading v${version2} from ${downloadUrl}`);
15574
+ try {
15575
+ import_node_fs2.default.mkdirSync(installDir, { recursive: true });
15576
+ (0, import_node_child_process2.execSync)(`curl -fsSL "${downloadUrl}" -o "${targetPath}"`, {
15577
+ timeout: 6e4,
15578
+ stdio: ["pipe", "pipe", "pipe"]
15579
+ });
15580
+ import_node_fs2.default.chmodSync(targetPath, 493);
15581
+ if (process.platform === "darwin") {
15582
+ try {
15583
+ (0, import_node_child_process2.execSync)(`xattr -d com.apple.quarantine "${targetPath}" 2>/dev/null || true`, {
15584
+ timeout: 1e4,
15585
+ stdio: ["pipe", "pipe", "pipe"]
15586
+ });
15587
+ } catch {
15588
+ }
15589
+ try {
15590
+ (0, import_node_child_process2.execSync)(`codesign --force --sign - "${targetPath}"`, {
15591
+ timeout: 1e4,
15592
+ stdio: ["pipe", "pipe", "pipe"]
15593
+ });
15594
+ } catch {
15595
+ }
15596
+ }
15597
+ (0, import_node_child_process2.execSync)(`"${targetPath}" --help`, { timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
15598
+ } catch (err) {
15599
+ try {
15600
+ import_node_fs2.default.unlinkSync(targetPath);
15601
+ } catch {
15602
+ }
15603
+ const message = err instanceof Error ? err.message : String(err);
15604
+ throw new AgentRelayProcessError(`Failed to install broker binary: ${message}
15605
+ Install manually: curl -fsSL https://raw.githubusercontent.com/AgentWorkforce/relay/main/install.sh | bash`);
15606
+ }
15607
+ console.log(`[agent-relay] Broker installed to ${targetPath}`);
15608
+ return targetPath;
15609
+ }
15610
+ function resolveDefaultBinaryPath() {
15611
+ const brokerExe = process.platform === "win32" ? "agent-relay-broker.exe" : "agent-relay-broker";
15612
+ const moduleDir = import_node_path3.default.dirname((0, import_node_url.fileURLToPath)(import_meta_url));
15613
+ const workspaceRelease = import_node_path3.default.resolve(moduleDir, "..", "..", "..", "target", "release", brokerExe);
15614
+ if (import_node_fs2.default.existsSync(workspaceRelease)) {
15615
+ return workspaceRelease;
15616
+ }
15617
+ const binDir = import_node_path3.default.resolve(moduleDir, "..", "bin");
15618
+ const suffix = detectPlatformSuffix();
15619
+ if (suffix) {
15620
+ const ext = process.platform === "win32" ? ".exe" : "";
15621
+ const platformBinary = import_node_path3.default.join(binDir, `agent-relay-broker-${suffix}${ext}`);
15622
+ if (import_node_fs2.default.existsSync(platformBinary)) {
15623
+ return platformBinary;
15624
+ }
15625
+ }
15626
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
15627
+ const standaloneBroker = import_node_path3.default.join(homeDir, ".agent-relay", "bin", brokerExe);
15628
+ if (import_node_fs2.default.existsSync(standaloneBroker)) {
15629
+ return standaloneBroker;
15630
+ }
15631
+ return installBrokerBinary();
15632
+ }
15633
+ var DEFAULT_DASHBOARD_PORT = (() => {
15634
+ const envPort = typeof process !== "undefined" ? process.env.AGENT_RELAY_DASHBOARD_PORT : void 0;
15635
+ if (envPort) {
15636
+ const parsed = Number.parseInt(envPort, 10);
15637
+ if (Number.isFinite(parsed) && parsed > 0)
15638
+ return parsed;
15639
+ }
15640
+ return 3888;
15641
+ })();
15642
+ var HTTP_MAX_PORT_SCAN = 25;
15643
+ var HTTP_AUTOSTART_TIMEOUT_MS = 1e4;
15644
+ var HTTP_AUTOSTART_POLL_MS = 250;
15645
+ function sanitizeBrokerName(name) {
15646
+ return name.replace(/[^\p{L}\p{N}-]/gu, "-");
15647
+ }
15648
+ function brokerPidFilename(projectRoot) {
15649
+ const brokerName = import_node_path3.default.basename(projectRoot) || "project";
15650
+ return `broker-${sanitizeBrokerName(brokerName)}.pid`;
15651
+ }
15652
+ var HttpAgentRelayClient = class _HttpAgentRelayClient {
15653
+ port;
15654
+ apiKey;
15655
+ constructor(options) {
15656
+ this.port = options.port;
15657
+ this.apiKey = options.apiKey;
15658
+ }
15659
+ /**
15660
+ * Connect to an already-running broker on the given port.
15661
+ */
15662
+ static async connectHttp(port, options) {
15663
+ const client = new _HttpAgentRelayClient({ port, apiKey: options?.apiKey });
15664
+ await client.healthCheck();
15665
+ return client;
15666
+ }
15667
+ /**
15668
+ * Discover a running broker for the current project and connect to it.
15669
+ * Reads the broker PID file, verifies the process is alive, scans ports
15670
+ * for the HTTP API, and returns a connected client.
15671
+ */
15672
+ static async discoverAndConnect(options) {
15673
+ const cwd = options?.cwd ?? process.cwd();
15674
+ const apiKey = options?.apiKey ?? process.env.RELAY_BROKER_API_KEY?.trim();
15675
+ const autoStart = options?.autoStart ?? false;
15676
+ const paths = getProjectPaths(cwd);
15677
+ const preferredApiPort = DEFAULT_DASHBOARD_PORT + 1;
15678
+ const pidFilePath = import_node_path3.default.join(paths.dataDir, brokerPidFilename(paths.projectRoot));
15679
+ const legacyPidPath = import_node_path3.default.join(paths.dataDir, "broker.pid");
15680
+ let brokerRunning = false;
15681
+ for (const pidPath of [pidFilePath, legacyPidPath]) {
15682
+ if (import_node_fs2.default.existsSync(pidPath)) {
15683
+ const pidStr = import_node_fs2.default.readFileSync(pidPath, "utf-8").trim();
15684
+ const pid = Number.parseInt(pidStr, 10);
15685
+ if (Number.isFinite(pid) && pid > 0) {
15686
+ try {
15687
+ process.kill(pid, 0);
15688
+ brokerRunning = true;
15689
+ break;
15690
+ } catch {
15691
+ }
15692
+ }
15693
+ }
15694
+ }
15695
+ if (brokerRunning) {
15696
+ const port = await _HttpAgentRelayClient.scanForBrokerPort(preferredApiPort);
15697
+ if (port !== null) {
15698
+ return new _HttpAgentRelayClient({ port, apiKey });
15699
+ }
15700
+ throw new AgentRelayProcessError("broker is running for this project, but its local API is unavailable");
15701
+ }
15702
+ if (!autoStart) {
15703
+ throw new AgentRelayProcessError("broker is not running for this project");
15704
+ }
15705
+ const brokerBinary = options?.brokerBinaryPath ?? resolveDefaultBinaryPath();
15706
+ const child = (0, import_node_child_process2.spawn)(brokerBinary, ["init", "--persist", "--api-port", String(preferredApiPort)], {
15707
+ cwd: paths.projectRoot,
15708
+ env: process.env,
15709
+ detached: true,
15710
+ stdio: "ignore"
15711
+ });
15712
+ child.unref();
15713
+ const startedAt = Date.now();
15714
+ while (Date.now() - startedAt < HTTP_AUTOSTART_TIMEOUT_MS) {
15715
+ const port = await _HttpAgentRelayClient.scanForBrokerPort(preferredApiPort);
15716
+ if (port !== null) {
15717
+ return new _HttpAgentRelayClient({ port, apiKey });
15718
+ }
15719
+ await new Promise((resolve3) => setTimeout(resolve3, HTTP_AUTOSTART_POLL_MS));
15720
+ }
15721
+ throw new AgentRelayProcessError(`broker did not become ready within ${HTTP_AUTOSTART_TIMEOUT_MS}ms`);
15722
+ }
15723
+ static async scanForBrokerPort(startPort) {
15724
+ for (let i = 0; i < HTTP_MAX_PORT_SCAN; i++) {
15725
+ const port = startPort + i;
15726
+ try {
15727
+ const res = await fetch(`http://127.0.0.1:${port}/health`);
15728
+ if (!res.ok)
15729
+ continue;
15730
+ const payload = await res.json().catch(() => null);
15731
+ if (payload?.service === "agent-relay-listen") {
15732
+ return port;
15733
+ }
15734
+ } catch {
15735
+ }
15736
+ }
15737
+ return null;
15738
+ }
15739
+ async request(pathname, init) {
15740
+ const headers = new Headers(init?.headers);
15741
+ if (this.apiKey && !headers.has("x-api-key") && !headers.has("authorization")) {
15742
+ headers.set("x-api-key", this.apiKey);
15743
+ }
15744
+ const response = await fetch(`http://127.0.0.1:${this.port}${pathname}`, {
15745
+ ...init,
15746
+ headers
15747
+ });
15748
+ const text = await response.text();
15749
+ let payload;
15750
+ try {
15751
+ payload = text ? JSON.parse(text) : void 0;
15752
+ } catch {
15753
+ payload = text;
15754
+ }
15755
+ if (!response.ok) {
15756
+ const msg = _HttpAgentRelayClient.extractErrorMessage(response, payload);
15757
+ throw new AgentRelayProcessError(msg);
15758
+ }
15759
+ return payload;
15760
+ }
15761
+ static extractErrorMessage(response, payload) {
15762
+ if (typeof payload === "string" && payload.trim())
15763
+ return payload.trim();
15764
+ const p = payload;
15765
+ if (typeof p?.error === "string")
15766
+ return p.error;
15767
+ if (typeof p?.error?.message === "string")
15768
+ return p.error.message;
15769
+ if (typeof p?.message === "string" && p.message.trim())
15770
+ return p.message.trim();
15771
+ return `${response.status} ${response.statusText}`.trim();
15772
+ }
15773
+ async healthCheck() {
15774
+ return this.request("/health");
15775
+ }
15776
+ /** No-op — broker is already running. */
15777
+ async start() {
15778
+ }
15779
+ /** No-op — don't kill an externally-managed broker. */
15780
+ async shutdown() {
15781
+ }
15782
+ async spawnPty(input) {
15783
+ const payload = await this.request("/api/spawn", {
15784
+ method: "POST",
15785
+ headers: { "content-type": "application/json" },
15786
+ body: JSON.stringify({
15787
+ name: input.name,
15788
+ cli: input.cli,
15789
+ model: input.model,
15790
+ args: input.args ?? [],
15791
+ task: input.task,
15792
+ channels: input.channels ?? [],
15793
+ cwd: input.cwd,
15794
+ team: input.team,
15795
+ shadowOf: input.shadowOf,
15796
+ shadowMode: input.shadowMode,
15797
+ continueFrom: input.continueFrom,
15798
+ idleThresholdSecs: input.idleThresholdSecs,
15799
+ restartPolicy: input.restartPolicy,
15800
+ skipRelayPrompt: input.skipRelayPrompt
15801
+ })
15802
+ });
15803
+ return {
15804
+ name: typeof payload?.name === "string" ? payload.name : input.name,
15805
+ runtime: "pty"
15806
+ };
15807
+ }
15808
+ async sendMessage(input) {
15809
+ return this.request("/api/send", {
15810
+ method: "POST",
15811
+ headers: { "content-type": "application/json" },
15812
+ body: JSON.stringify({
15813
+ to: input.to,
15814
+ text: input.text,
15815
+ from: input.from,
15816
+ threadId: input.threadId,
15817
+ workspaceId: input.workspaceId,
15818
+ workspaceAlias: input.workspaceAlias,
15819
+ priority: input.priority,
15820
+ data: input.data
15821
+ })
15822
+ });
15823
+ }
15824
+ async listAgents() {
15825
+ const payload = await this.request("/api/spawned", { method: "GET" });
15826
+ return Array.isArray(payload?.agents) ? payload.agents : [];
15827
+ }
15828
+ async release(name, reason) {
15829
+ const payload = await this.request(`/api/spawned/${encodeURIComponent(name)}`, {
15830
+ method: "DELETE",
15831
+ ...reason ? { headers: { "content-type": "application/json" }, body: JSON.stringify({ reason }) } : {}
15832
+ });
15833
+ return { name: typeof payload?.name === "string" ? payload.name : name };
15834
+ }
15835
+ async setModel(name, model, opts) {
15836
+ const payload = await this.request(`/api/spawned/${encodeURIComponent(name)}/model`, {
15837
+ method: "POST",
15838
+ headers: { "content-type": "application/json" },
15839
+ body: JSON.stringify({ model, timeoutMs: opts?.timeoutMs })
15840
+ });
15841
+ return {
15842
+ name,
15843
+ model: typeof payload?.model === "string" ? payload.model : model,
15844
+ success: payload?.success !== false
15845
+ };
15846
+ }
15847
+ async getConfig() {
15848
+ return this.request("/api/config");
15582
15849
  }
15583
- };
15584
- var DefaultModels = {
15585
- claude: "sonnet",
15586
- codex: "gpt-5.4",
15587
- gemini: "gemini-3.1-pro-preview",
15588
- cursor: "opus-4.6-thinking",
15589
- droid: "opus-4.6-fast",
15590
- opencode: "openai/gpt-5.2"
15591
15850
  };
15592
15851
 
15593
15852
  // node_modules/@relaycast/sdk/dist/version.js
@@ -31425,7 +31684,7 @@ function cleanLines(raw) {
31425
31684
  }
31426
31685
 
31427
31686
  // packages/sdk/dist/relay.js
31428
- var import_node_crypto = require("node:crypto");
31687
+ var import_node_crypto2 = require("node:crypto");
31429
31688
  var import_node_path5 = __toESM(require("node:path"), 1);
31430
31689
 
31431
31690
  // packages/sdk/dist/logs.js
@@ -31843,7 +32102,7 @@ var AgentRelay = class {
31843
32102
  if (result?.event_id === "unsupported_operation") {
31844
32103
  return buildUnsupportedOperationMessage(opts.name, input);
31845
32104
  }
31846
- const eventId = result?.event_id ?? (0, import_node_crypto.randomBytes)(8).toString("hex");
32105
+ const eventId = result?.event_id ?? (0, import_node_crypto2.randomBytes)(8).toString("hex");
31847
32106
  const msg = {
31848
32107
  eventId,
31849
32108
  from: opts.name,
@@ -32505,7 +32764,7 @@ var AgentRelay = class {
32505
32764
  if (result?.event_id === "unsupported_operation") {
32506
32765
  return buildUnsupportedOperationMessage(name, input);
32507
32766
  }
32508
- const eventId = result?.event_id ?? (0, import_node_crypto.randomBytes)(8).toString("hex");
32767
+ const eventId = result?.event_id ?? (0, import_node_crypto2.randomBytes)(8).toString("hex");
32509
32768
  const msg = {
32510
32769
  eventId,
32511
32770
  from: name,
@@ -32622,7 +32881,7 @@ var AgentRelay = class {
32622
32881
  };
32623
32882
 
32624
32883
  // packages/sdk/dist/consensus.js
32625
- var import_node_crypto2 = require("node:crypto");
32884
+ var import_node_crypto3 = require("node:crypto");
32626
32885
  var import_node_events2 = require("node:events");
32627
32886
 
32628
32887
  // packages/sdk/dist/consensus-helpers.js
@@ -32759,7 +33018,7 @@ var ConsensusEngine = class extends import_node_events2.EventEmitter {
32759
33018
  }
32760
33019
  // ── Proposal management ──────────────────────────────────────────────────
32761
33020
  createProposal(options) {
32762
- const id = `prop_${Date.now()}_${(0, import_node_crypto2.randomBytes)(4).toString("hex")}`;
33021
+ const id = `prop_${Date.now()}_${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`;
32763
33022
  const now = Date.now();
32764
33023
  const timeoutMs = options.timeoutMs ?? this.config.defaultTimeoutMs;
32765
33024
  const proposal = {
@@ -33427,8 +33686,8 @@ function isAgentStep(step) {
33427
33686
 
33428
33687
  // packages/sdk/dist/workflows/runner.js
33429
33688
  var import_node_child_process3 = require("node:child_process");
33430
- var import_node_crypto4 = require("node:crypto");
33431
- var import_node_fs4 = require("node:fs");
33689
+ var import_node_crypto5 = require("node:crypto");
33690
+ var import_node_fs5 = require("node:fs");
33432
33691
  var import_promises3 = require("node:fs/promises");
33433
33692
  var import_node_path8 = __toESM(require("node:path"), 1);
33434
33693
  var import_yaml2 = __toESM(require_dist(), 1);
@@ -33559,18 +33818,18 @@ async function spawnFromEnv(options = {}) {
33559
33818
  }
33560
33819
 
33561
33820
  // packages/sdk/dist/workflows/custom-steps.js
33562
- var import_node_fs2 = require("node:fs");
33821
+ var import_node_fs3 = require("node:fs");
33563
33822
  var import_node_path6 = __toESM(require("node:path"), 1);
33564
33823
  var import_yaml = __toESM(require_dist(), 1);
33565
33824
  var CUSTOM_STEPS_FILE = ".relay/steps.yaml";
33566
33825
  function loadCustomSteps(cwd) {
33567
33826
  const stepsPath = import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE);
33568
33827
  const steps = /* @__PURE__ */ new Map();
33569
- if (!(0, import_node_fs2.existsSync)(stepsPath)) {
33828
+ if (!(0, import_node_fs3.existsSync)(stepsPath)) {
33570
33829
  return steps;
33571
33830
  }
33572
33831
  try {
33573
- const content = (0, import_node_fs2.readFileSync)(stepsPath, "utf-8");
33832
+ const content = (0, import_node_fs3.readFileSync)(stepsPath, "utf-8");
33574
33833
  if (!content.trim()) {
33575
33834
  return steps;
33576
33835
  }
@@ -33820,7 +34079,7 @@ function resolveAllCustomSteps(steps, customSteps) {
33820
34079
  return steps.map((step) => resolveCustomStep(step, customSteps));
33821
34080
  }
33822
34081
  function customStepsFileExists(cwd) {
33823
- return (0, import_node_fs2.existsSync)(import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE));
34082
+ return (0, import_node_fs3.existsSync)(import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE));
33824
34083
  }
33825
34084
  function getCustomStepsPath(cwd) {
33826
34085
  return import_node_path6.default.join(cwd, CUSTOM_STEPS_FILE);
@@ -33857,8 +34116,8 @@ var InMemoryWorkflowDb = class {
33857
34116
  };
33858
34117
 
33859
34118
  // packages/sdk/dist/workflows/trajectory.js
33860
- var import_node_crypto3 = require("node:crypto");
33861
- var import_node_fs3 = require("node:fs");
34119
+ var import_node_crypto4 = require("node:crypto");
34120
+ var import_node_fs4 = require("node:fs");
33862
34121
  var import_promises2 = require("node:fs/promises");
33863
34122
  var import_node_path7 = __toESM(require("node:path"), 1);
33864
34123
  function classifyFailure(error48) {
@@ -33921,7 +34180,7 @@ var WorkflowTrajectory = class {
33921
34180
  return;
33922
34181
  this.startTime = Date.now();
33923
34182
  this.swarmPattern = pattern ?? "dag";
33924
- const id = `traj_${Date.now()}_${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`;
34183
+ const id = `traj_${Date.now()}_${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`;
33925
34184
  this.trajectory = {
33926
34185
  id,
33927
34186
  version: 1,
@@ -34264,7 +34523,7 @@ var WorkflowTrajectory = class {
34264
34523
  if (!this.trajectory)
34265
34524
  return;
34266
34525
  const chapter = {
34267
- id: `ch_${(0, import_node_crypto3.randomBytes)(4).toString("hex")}`,
34526
+ id: `ch_${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`,
34268
34527
  title,
34269
34528
  agentName,
34270
34529
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -34337,7 +34596,7 @@ var WorkflowTrajectory = class {
34337
34596
  await (0, import_promises2.mkdir)(completedDir, { recursive: true });
34338
34597
  const activePath = import_node_path7.default.join(activeDir, `${this.trajectory.id}.json`);
34339
34598
  const completedPath = import_node_path7.default.join(completedDir, `${this.trajectory.id}.json`);
34340
- if ((0, import_node_fs3.existsSync)(activePath)) {
34599
+ if ((0, import_node_fs4.existsSync)(activePath)) {
34341
34600
  await (0, import_promises2.rename)(activePath, completedPath);
34342
34601
  }
34343
34602
  } catch {
@@ -34475,7 +34734,7 @@ var WorkflowRunner = class _WorkflowRunner {
34475
34734
  const abs = import_node_path8.default.resolve(baseCwd, expanded);
34476
34735
  resolved.set(pd.name, abs);
34477
34736
  const isRequired = pd.required !== false;
34478
- if (!(0, import_node_fs4.existsSync)(abs)) {
34737
+ if (!(0, import_node_fs5.existsSync)(abs)) {
34479
34738
  if (isRequired) {
34480
34739
  errors.push(`Path "${pd.name}" resolves to "${abs}" which does not exist (required)`);
34481
34740
  } else {
@@ -34809,12 +35068,12 @@ ${next}` : next;
34809
35068
  }
34810
35069
  captureFileSnapshot(root) {
34811
35070
  const snapshot = /* @__PURE__ */ new Map();
34812
- if (!(0, import_node_fs4.existsSync)(root))
35071
+ if (!(0, import_node_fs5.existsSync)(root))
34813
35072
  return snapshot;
34814
35073
  const visit = (currentPath) => {
34815
35074
  let entries;
34816
35075
  try {
34817
- entries = (0, import_node_fs4.readdirSync)(currentPath, { withFileTypes: true });
35076
+ entries = (0, import_node_fs5.readdirSync)(currentPath, { withFileTypes: true });
34818
35077
  } catch {
34819
35078
  return;
34820
35079
  }
@@ -34828,7 +35087,7 @@ ${next}` : next;
34828
35087
  continue;
34829
35088
  }
34830
35089
  try {
34831
- const stats = (0, import_node_fs4.statSync)(fullPath);
35090
+ const stats = (0, import_node_fs5.statSync)(fullPath);
34832
35091
  if (!stats.isFile())
34833
35092
  continue;
34834
35093
  snapshot.set(fullPath, { mtimeMs: stats.mtimeMs, size: stats.size });
@@ -34837,7 +35096,7 @@ ${next}` : next;
34837
35096
  }
34838
35097
  };
34839
35098
  try {
34840
- const stats = (0, import_node_fs4.statSync)(root);
35099
+ const stats = (0, import_node_fs5.statSync)(root);
34841
35100
  if (stats.isFile()) {
34842
35101
  snapshot.set(root, { mtimeMs: stats.mtimeMs, size: stats.size });
34843
35102
  return snapshot;
@@ -34958,7 +35217,7 @@ ${next}` : next;
34958
35217
  this.relayApiKey = envKey;
34959
35218
  return;
34960
35219
  }
34961
- const workspaceName = `relay-${channel}-${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`;
35220
+ const workspaceName = `relay-${channel}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
34962
35221
  const baseUrl = this.relayOptions.env?.RELAYCAST_BASE_URL ?? process.env.RELAYCAST_BASE_URL ?? "https://api.relaycast.dev";
34963
35222
  const res = await fetch(`${baseUrl}/v1/workspaces`, {
34964
35223
  method: "POST",
@@ -35022,7 +35281,7 @@ ${next}` : next;
35022
35281
  } catch (err) {
35023
35282
  if (err instanceof RelayError && err.code === "name_conflict") {
35024
35283
  registration = await rc.agents.register({
35025
- name: `WorkflowRunner-${(0, import_node_crypto4.randomBytes)(4).toString("hex")}`,
35284
+ name: `WorkflowRunner-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`,
35026
35285
  type: "agent"
35027
35286
  });
35028
35287
  } else {
@@ -35239,14 +35498,14 @@ ${err.suggestion}`);
35239
35498
  for (const agent of resolved.agents) {
35240
35499
  if (agent.cwd) {
35241
35500
  const resolvedCwd = import_node_path8.default.resolve(this.cwd, agent.cwd);
35242
- if (!(0, import_node_fs4.existsSync)(resolvedCwd)) {
35501
+ if (!(0, import_node_fs5.existsSync)(resolvedCwd)) {
35243
35502
  warnings.push(`Agent "${agent.name}" cwd "${agent.cwd}" resolves to "${resolvedCwd}" which does not exist`);
35244
35503
  }
35245
35504
  }
35246
35505
  if (agent.additionalPaths) {
35247
35506
  for (const ap of agent.additionalPaths) {
35248
35507
  const resolvedPath = import_node_path8.default.resolve(this.cwd, ap);
35249
- if (!(0, import_node_fs4.existsSync)(resolvedPath)) {
35508
+ if (!(0, import_node_fs5.existsSync)(resolvedPath)) {
35250
35509
  warnings.push(`Agent "${agent.name}" additionalPath "${ap}" resolves to "${resolvedPath}" which does not exist`);
35251
35510
  }
35252
35511
  }
@@ -37672,7 +37931,7 @@ DO NOT:
37672
37931
  const { cmd, args } = _WorkflowRunner.buildNonInteractiveCommand(agentDef.cli, taskWithDeliverable, modelArgs);
37673
37932
  const logsDir = this.getWorkerLogsDir();
37674
37933
  const logPath = import_node_path8.default.join(logsDir, `${agentName}.log`);
37675
- const logStream = (0, import_node_fs4.createWriteStream)(logPath, { flags: "a" });
37934
+ const logStream = (0, import_node_fs5.createWriteStream)(logPath, { flags: "a" });
37676
37935
  this.registerWorker(agentName, agentDef.cli, step.task ?? "", void 0, false);
37677
37936
  let stopHeartbeat;
37678
37937
  if (this.relayApiKey) {
@@ -37808,7 +38067,7 @@ DO NOT:
37808
38067
  const taskWithExit = step.task + (relayRegistrationNote ? "\n\n" + relayRegistrationNote : "") + (delegationGuidance ? "\n\n" + delegationGuidance + "\n" : "") + '\n\n---\nIMPORTANT: When you have fully completed this task, you MUST self-terminate by either: (a) calling remove_agent(name: "<your-agent-name>", reason: "task completed") \u2014 preferred, or (b) outputting the exact text "/exit" on its own line as a fallback. Do not wait for further input \u2014 terminate immediately after finishing. Do NOT spawn sub-agents unless the task explicitly requires it.';
37809
38068
  this.ptyOutputBuffers.set(agentName, []);
37810
38069
  const logsDir = this.getWorkerLogsDir();
37811
- const logStream = (0, import_node_fs4.createWriteStream)(import_node_path8.default.join(logsDir, `${agentName}.log`), { flags: "a" });
38070
+ const logStream = (0, import_node_fs5.createWriteStream)(import_node_path8.default.join(logsDir, `${agentName}.log`), { flags: "a" });
37812
38071
  this.ptyLogStreams.set(agentName, logStream);
37813
38072
  this.ptyListeners.set(agentName, (chunk) => {
37814
38073
  const stripped = _WorkflowRunner.stripAnsi(chunk);
@@ -37850,11 +38109,11 @@ DO NOT:
37850
38109
  oldLogStream.end();
37851
38110
  this.ptyLogStreams.delete(oldName);
37852
38111
  try {
37853
- (0, import_node_fs4.renameSync)(oldLogPath, newLogPath);
38112
+ (0, import_node_fs5.renameSync)(oldLogPath, newLogPath);
37854
38113
  } catch {
37855
38114
  }
37856
38115
  }
37857
- const newLogStream = (0, import_node_fs4.createWriteStream)(newLogPath, { flags: "a" });
38116
+ const newLogStream = (0, import_node_fs5.createWriteStream)(newLogPath, { flags: "a" });
37858
38117
  this.ptyLogStreams.set(agent.name, newLogStream);
37859
38118
  const oldListener = this.ptyListeners.get(oldName);
37860
38119
  if (oldListener) {
@@ -37959,7 +38218,7 @@ DO NOT:
37959
38218
  output = ptyChunks.join("");
37960
38219
  } else {
37961
38220
  const summaryPath = import_node_path8.default.join(this.summaryDir, `${step.name}.md`);
37962
- output = (0, import_node_fs4.existsSync)(summaryPath) ? await (0, import_promises3.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
38221
+ output = (0, import_node_fs5.existsSync)(summaryPath) ? await (0, import_promises3.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
37963
38222
  }
37964
38223
  if (ptyChunks.length === 0) {
37965
38224
  this.captureStepTerminalEvidence(evidenceStepName, { stdout: output, combined: output }, { exitCode: agent?.exitCode, exitSignal: agent?.exitSignal }, {
@@ -38210,7 +38469,7 @@ DO NOT:
38210
38469
  case "exit_code":
38211
38470
  break;
38212
38471
  case "file_exists":
38213
- if (!(0, import_node_fs4.existsSync)(import_node_path8.default.resolve(this.cwd, check2.value))) {
38472
+ if (!(0, import_node_fs5.existsSync)(import_node_path8.default.resolve(this.cwd, check2.value))) {
38214
38473
  return fail(`Verification failed for "${stepName}": file "${check2.value}" does not exist`);
38215
38474
  }
38216
38475
  break;
@@ -38549,10 +38808,10 @@ ${excerpt}` : "";
38549
38808
  }
38550
38809
  // ── ID generation ─────────────────────────────────────────────────────
38551
38810
  generateId() {
38552
- return (0, import_node_crypto4.randomBytes)(12).toString("hex");
38811
+ return (0, import_node_crypto5.randomBytes)(12).toString("hex");
38553
38812
  }
38554
38813
  generateShortId() {
38555
- return (0, import_node_crypto4.randomBytes)(4).toString("hex");
38814
+ return (0, import_node_crypto5.randomBytes)(4).toString("hex");
38556
38815
  }
38557
38816
  /** Strip ANSI escape codes from terminal output — delegates to pty.ts canonical regex. */
38558
38817
  static stripAnsi(text) {
@@ -38653,7 +38912,7 @@ ${excerpt}` : "";
38653
38912
  const outputPath = import_node_path8.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
38654
38913
  try {
38655
38914
  const dir = this.getStepOutputDir(runId);
38656
- (0, import_node_fs4.mkdirSync)(dir, { recursive: true });
38915
+ (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
38657
38916
  const cleaned = _WorkflowRunner.stripAnsi(output);
38658
38917
  await (0, import_promises3.writeFile)(outputPath, cleaned);
38659
38918
  } catch {
@@ -38679,9 +38938,9 @@ ${preview}
38679
38938
  loadStepOutput(runId, stepName) {
38680
38939
  try {
38681
38940
  const filePath = import_node_path8.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
38682
- if (!(0, import_node_fs4.existsSync)(filePath))
38941
+ if (!(0, import_node_fs5.existsSync)(filePath))
38683
38942
  return void 0;
38684
- return (0, import_node_fs4.readFileSync)(filePath, "utf-8");
38943
+ return (0, import_node_fs5.readFileSync)(filePath, "utf-8");
38685
38944
  } catch {
38686
38945
  return void 0;
38687
38946
  }
@@ -38689,7 +38948,7 @@ ${preview}
38689
38948
  /** Get or create the worker logs directory (.agent-relay/team/worker-logs) */
38690
38949
  getWorkerLogsDir() {
38691
38950
  const logsDir = import_node_path8.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
38692
- (0, import_node_fs4.mkdirSync)(logsDir, { recursive: true });
38951
+ (0, import_node_fs5.mkdirSync)(logsDir, { recursive: true });
38693
38952
  return logsDir;
38694
38953
  }
38695
38954
  /** Register a spawned agent in workers.json so `agents:kill` can find it. */
@@ -38705,7 +38964,7 @@ ${preview}
38705
38964
  this.activeWorkers.set(agentName, workerEntry);
38706
38965
  this.workersFileLock = this.workersFileLock.then(() => {
38707
38966
  try {
38708
- (0, import_node_fs4.mkdirSync)(import_node_path8.default.dirname(this.workersPath), { recursive: true });
38967
+ (0, import_node_fs5.mkdirSync)(import_node_path8.default.dirname(this.workersPath), { recursive: true });
38709
38968
  const existing = this.readWorkers().filter((w) => w.name !== agentName);
38710
38969
  existing.push({ name: agentName, ...workerEntry });
38711
38970
  this.writeWorkers(existing);
@@ -38727,21 +38986,21 @@ ${preview}
38727
38986
  }
38728
38987
  readWorkers() {
38729
38988
  try {
38730
- if (!(0, import_node_fs4.existsSync)(this.workersPath))
38989
+ if (!(0, import_node_fs5.existsSync)(this.workersPath))
38731
38990
  return [];
38732
- const raw = JSON.parse((0, import_node_fs4.readFileSync)(this.workersPath, "utf-8"));
38991
+ const raw = JSON.parse((0, import_node_fs5.readFileSync)(this.workersPath, "utf-8"));
38733
38992
  return Array.isArray(raw?.workers) ? raw.workers : [];
38734
38993
  } catch {
38735
38994
  return [];
38736
38995
  }
38737
38996
  }
38738
38997
  writeWorkers(workers) {
38739
- (0, import_node_fs4.writeFileSync)(this.workersPath, JSON.stringify({ workers }, null, 2));
38998
+ (0, import_node_fs5.writeFileSync)(this.workersPath, JSON.stringify({ workers }, null, 2));
38740
38999
  }
38741
39000
  };
38742
39001
 
38743
39002
  // packages/sdk/dist/workflows/file-db.js
38744
- var import_node_fs5 = require("node:fs");
39003
+ var import_node_fs6 = require("node:fs");
38745
39004
  var import_node_path9 = __toESM(require("node:path"), 1);
38746
39005
  var JsonFileWorkflowDb = class {
38747
39006
  filePath;
@@ -38751,7 +39010,7 @@ var JsonFileWorkflowDb = class {
38751
39010
  this.filePath = filePath;
38752
39011
  let writable = false;
38753
39012
  try {
38754
- (0, import_node_fs5.mkdirSync)(import_node_path9.default.dirname(filePath), { recursive: true });
39013
+ (0, import_node_fs6.mkdirSync)(import_node_path9.default.dirname(filePath), { recursive: true });
38755
39014
  writable = true;
38756
39015
  } catch {
38757
39016
  }
@@ -38766,7 +39025,7 @@ var JsonFileWorkflowDb = class {
38766
39025
  if (!this.writable)
38767
39026
  return;
38768
39027
  try {
38769
- (0, import_node_fs5.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", "utf8");
39028
+ (0, import_node_fs6.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", "utf8");
38770
39029
  } catch {
38771
39030
  }
38772
39031
  }
@@ -38776,7 +39035,7 @@ var JsonFileWorkflowDb = class {
38776
39035
  const steps = /* @__PURE__ */ new Map();
38777
39036
  let raw = "";
38778
39037
  try {
38779
- raw = (0, import_node_fs5.readFileSync)(this.filePath, "utf8");
39038
+ raw = (0, import_node_fs6.readFileSync)(this.filePath, "utf8");
38780
39039
  } catch {
38781
39040
  return { runs, steps };
38782
39041
  }
@@ -39088,7 +39347,7 @@ function workflow(name) {
39088
39347
  }
39089
39348
 
39090
39349
  // packages/sdk/dist/workflows/coordinator.js
39091
- var import_node_crypto5 = require("node:crypto");
39350
+ var import_node_crypto6 = require("node:crypto");
39092
39351
  var import_node_events3 = require("node:events");
39093
39352
  var PATTERN_HEURISTICS = [
39094
39353
  // ── Dependency-based patterns (highest priority) ──────────────────────
@@ -39443,7 +39702,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
39443
39702
  }
39444
39703
  // ── Lifecycle: create run ───────────────────────────────────────────────
39445
39704
  async createRun(workspaceId, config2) {
39446
- const id = `run_${Date.now()}_${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
39705
+ const id = `run_${Date.now()}_${(0, import_node_crypto6.randomBytes)(4).toString("hex")}`;
39447
39706
  const pattern = this.selectPattern(config2);
39448
39707
  const now = (/* @__PURE__ */ new Date()).toISOString();
39449
39708
  const { rows } = await this.db.query(`INSERT INTO workflow_runs (id, workspace_id, workflow_name, pattern, status, config, started_at, created_at, updated_at)
@@ -39482,7 +39741,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
39482
39741
  const created = [];
39483
39742
  for (const wf of workflows) {
39484
39743
  for (const step of wf.steps) {
39485
- const id = `step_${Date.now()}_${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
39744
+ const id = `step_${Date.now()}_${(0, import_node_crypto6.randomBytes)(4).toString("hex")}`;
39486
39745
  const now = (/* @__PURE__ */ new Date()).toISOString();
39487
39746
  const { rows } = await this.db.query(`INSERT INTO workflow_steps (id, run_id, step_name, agent_name, status, task, depends_on, created_at, updated_at)
39488
39747
  VALUES ($1, $2, $3, $4, 'pending', $5, $6, $7, $7)
@@ -39659,7 +39918,7 @@ var SwarmCoordinator = class extends import_node_events3.EventEmitter {
39659
39918
  };
39660
39919
 
39661
39920
  // packages/sdk/dist/workflows/barrier.js
39662
- var import_node_crypto6 = require("node:crypto");
39921
+ var import_node_crypto7 = require("node:crypto");
39663
39922
  var import_node_events4 = require("node:events");
39664
39923
  var BarrierManager = class extends import_node_events4.EventEmitter {
39665
39924
  db;
@@ -39675,7 +39934,7 @@ var BarrierManager = class extends import_node_events4.EventEmitter {
39675
39934
  * Create a barrier for a workflow run.
39676
39935
  */
39677
39936
  async createBarrier(runId, definition) {
39678
- const id = `bar_${Date.now()}_${(0, import_node_crypto6.randomBytes)(4).toString("hex")}`;
39937
+ const id = `bar_${Date.now()}_${(0, import_node_crypto7.randomBytes)(4).toString("hex")}`;
39679
39938
  const now = (/* @__PURE__ */ new Date()).toISOString();
39680
39939
  const mode = definition.mode ?? "all";
39681
39940
  const { rows } = await this.db.query(`INSERT INTO workflow_barriers (id, run_id, barrier_name, wait_for, resolved, is_satisfied, timeout_ms, created_at, updated_at)
@@ -39809,7 +40068,7 @@ var BarrierManager = class extends import_node_events4.EventEmitter {
39809
40068
  };
39810
40069
 
39811
40070
  // packages/sdk/dist/workflows/state.js
39812
- var import_node_crypto7 = require("node:crypto");
40071
+ var import_node_crypto8 = require("node:crypto");
39813
40072
  var import_node_events5 = require("node:events");
39814
40073
  var StateStore = class extends import_node_events5.EventEmitter {
39815
40074
  db;
@@ -39852,7 +40111,7 @@ var StateStore = class extends import_node_events5.EventEmitter {
39852
40111
  const namespace = options.namespace ?? this.defaultNamespace;
39853
40112
  const ttlMs = options.ttlMs ?? this.defaultTtlMs;
39854
40113
  const expiresAt = ttlMs ? new Date(Date.now() + ttlMs).toISOString() : null;
39855
- const id = `st_${Date.now()}_${(0, import_node_crypto7.randomBytes)(4).toString("hex")}`;
40114
+ const id = `st_${Date.now()}_${(0, import_node_crypto8.randomBytes)(4).toString("hex")}`;
39856
40115
  const now = (/* @__PURE__ */ new Date()).toISOString();
39857
40116
  const { rows } = await this.db.query(`INSERT INTO swarm_state (id, run_id, namespace, key, value, expires_at, created_at, updated_at)
39858
40117
  VALUES ($1, $2, $3, $4, $5, $6, $7, $7)
@@ -39940,7 +40199,7 @@ var StateStore = class extends import_node_events5.EventEmitter {
39940
40199
  };
39941
40200
 
39942
40201
  // packages/sdk/dist/workflows/templates.js
39943
- var import_node_fs6 = require("node:fs");
40202
+ var import_node_fs7 = require("node:fs");
39944
40203
  var import_node_path10 = __toESM(require("node:path"), 1);
39945
40204
  var import_node_url2 = require("node:url");
39946
40205
  var import_yaml4 = __toESM(require_dist(), 1);
@@ -40044,9 +40303,9 @@ var TemplateRegistry = class {
40044
40303
  throw new Error(`Invalid template name: "${templateName}" contains path separators or traversal sequences`);
40045
40304
  }
40046
40305
  this.validateRelayConfig(parsed, url2);
40047
- await import_node_fs6.promises.mkdir(this.customTemplatesDir, { recursive: true });
40306
+ await import_node_fs7.promises.mkdir(this.customTemplatesDir, { recursive: true });
40048
40307
  const targetPath = import_node_path10.default.join(this.customTemplatesDir, `${templateName}.yaml`);
40049
- await import_node_fs6.promises.writeFile(targetPath, (0, import_yaml4.stringify)(parsed), "utf-8");
40308
+ await import_node_fs7.promises.writeFile(targetPath, (0, import_yaml4.stringify)(parsed), "utf-8");
40050
40309
  return targetPath;
40051
40310
  }
40052
40311
  isTemplateShorthand(input) {
@@ -40075,7 +40334,7 @@ var TemplateRegistry = class {
40075
40334
  import_node_path10.default.resolve(currentDir, "../workflows/builtin-templates")
40076
40335
  ];
40077
40336
  for (const candidate of candidates) {
40078
- if ((0, import_node_fs6.existsSync)(candidate)) {
40337
+ if ((0, import_node_fs7.existsSync)(candidate)) {
40079
40338
  return candidate;
40080
40339
  }
40081
40340
  }
@@ -40097,7 +40356,7 @@ var TemplateRegistry = class {
40097
40356
  for (const ext of YAML_EXTENSIONS) {
40098
40357
  const candidate = import_node_path10.default.join(directory, `${templateName}${ext}`);
40099
40358
  try {
40100
- const stat2 = await import_node_fs6.promises.stat(candidate);
40359
+ const stat2 = await import_node_fs7.promises.stat(candidate);
40101
40360
  if (stat2.isFile()) {
40102
40361
  return candidate;
40103
40362
  }
@@ -40107,7 +40366,7 @@ var TemplateRegistry = class {
40107
40366
  return void 0;
40108
40367
  }
40109
40368
  async readTemplateFile(templatePath) {
40110
- const raw = await import_node_fs6.promises.readFile(templatePath, "utf-8");
40369
+ const raw = await import_node_fs7.promises.readFile(templatePath, "utf-8");
40111
40370
  const parsed = (0, import_yaml4.parse)(raw);
40112
40371
  if (!isRecord(parsed)) {
40113
40372
  throw new Error(`Template at ${templatePath} is not a YAML object`);
@@ -40300,7 +40559,7 @@ var TemplateRegistry = class {
40300
40559
  }
40301
40560
  async safeReadDir(directory) {
40302
40561
  try {
40303
- return await import_node_fs6.promises.readdir(directory);
40562
+ return await import_node_fs7.promises.readdir(directory);
40304
40563
  } catch {
40305
40564
  return [];
40306
40565
  }
@@ -40464,7 +40723,7 @@ function isValidAgentName(name) {
40464
40723
  }
40465
40724
 
40466
40725
  // packages/utils/dist/logger.js
40467
- var import_node_fs7 = __toESM(require("node:fs"), 1);
40726
+ var import_node_fs8 = __toESM(require("node:fs"), 1);
40468
40727
  var import_node_path11 = __toESM(require("node:path"), 1);
40469
40728
  function getLogFile() {
40470
40729
  return process.env.AGENT_RELAY_LOG_FILE;
@@ -40484,8 +40743,8 @@ var LEVEL_PRIORITY = {
40484
40743
  var createdLogDirs = /* @__PURE__ */ new Set();
40485
40744
  function ensureLogDir(logFile) {
40486
40745
  const logDir = import_node_path11.default.dirname(logFile);
40487
- if (!createdLogDirs.has(logDir) && !import_node_fs7.default.existsSync(logDir)) {
40488
- import_node_fs7.default.mkdirSync(logDir, { recursive: true });
40746
+ if (!createdLogDirs.has(logDir) && !import_node_fs8.default.existsSync(logDir)) {
40747
+ import_node_fs8.default.mkdirSync(logDir, { recursive: true });
40489
40748
  createdLogDirs.add(logDir);
40490
40749
  }
40491
40750
  }
@@ -40514,7 +40773,7 @@ function log(level, component, msg, extra) {
40514
40773
  const logFile = getLogFile();
40515
40774
  if (logFile) {
40516
40775
  ensureLogDir(logFile);
40517
- import_node_fs7.default.appendFileSync(logFile, formatted + "\n");
40776
+ import_node_fs8.default.appendFileSync(logFile, formatted + "\n");
40518
40777
  return;
40519
40778
  }
40520
40779
  if (level === "ERROR" || level === "WARN") {
@@ -40785,7 +41044,7 @@ function benchmarkPatterns(iterations = 1e4) {
40785
41044
 
40786
41045
  // packages/utils/dist/command-resolver.js
40787
41046
  var import_node_child_process4 = require("node:child_process");
40788
- var import_node_fs8 = __toESM(require("node:fs"), 1);
41047
+ var import_node_fs9 = __toESM(require("node:fs"), 1);
40789
41048
  function resolveCommand(command) {
40790
41049
  if (command.startsWith("/")) {
40791
41050
  return resolveSymlinks(command);
@@ -40811,7 +41070,7 @@ function resolveCommand(command) {
40811
41070
  }
40812
41071
  function resolveSymlinks(filePath) {
40813
41072
  try {
40814
- const resolved = import_node_fs8.default.realpathSync(filePath);
41073
+ const resolved = import_node_fs9.default.realpathSync(filePath);
40815
41074
  if (resolved !== filePath && process.env.DEBUG_SPAWN === "1") {
40816
41075
  console.log(`[command-resolver] Resolved symlink: ${filePath} -> ${resolved}`);
40817
41076
  }
@@ -40836,7 +41095,7 @@ function commandExists(command) {
40836
41095
  }
40837
41096
 
40838
41097
  // packages/utils/dist/git-remote.js
40839
- var fs5 = __toESM(require("node:fs"), 1);
41098
+ var fs6 = __toESM(require("node:fs"), 1);
40840
41099
  var path11 = __toESM(require("node:path"), 1);
40841
41100
  var import_node_child_process5 = require("node:child_process");
40842
41101
  function parseGitRemoteUrl(url2) {
@@ -40855,7 +41114,7 @@ function parseGitRemoteUrl(url2) {
40855
41114
  function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
40856
41115
  try {
40857
41116
  const gitDir = path11.join(workingDirectory, ".git");
40858
- if (!fs5.existsSync(gitDir)) {
41117
+ if (!fs6.existsSync(gitDir)) {
40859
41118
  return null;
40860
41119
  }
40861
41120
  const result = (0, import_node_child_process5.execSync)(`git remote get-url ${remoteName}`, {
@@ -40868,10 +41127,10 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
40868
41127
  } catch {
40869
41128
  try {
40870
41129
  const configPath = path11.join(workingDirectory, ".git", "config");
40871
- if (!fs5.existsSync(configPath)) {
41130
+ if (!fs6.existsSync(configPath)) {
40872
41131
  return null;
40873
41132
  }
40874
- const config2 = fs5.readFileSync(configPath, "utf-8");
41133
+ const config2 = fs6.readFileSync(configPath, "utf-8");
40875
41134
  const remoteSection = new RegExp(`\\[remote\\s+"${remoteName}"\\][^\\[]*url\\s*=\\s*([^\\n]+)`, "i");
40876
41135
  const match = config2.match(remoteSection);
40877
41136
  return match?.[1]?.trim() || null;
@@ -40891,7 +41150,7 @@ function findGitRoot(startPath) {
40891
41150
  let currentPath = path11.resolve(startPath);
40892
41151
  const root = path11.parse(currentPath).root;
40893
41152
  while (currentPath !== root) {
40894
- if (fs5.existsSync(path11.join(currentPath, ".git"))) {
41153
+ if (fs6.existsSync(path11.join(currentPath, ".git"))) {
40895
41154
  return currentPath;
40896
41155
  }
40897
41156
  currentPath = path11.dirname(currentPath);
@@ -40911,7 +41170,7 @@ function getRepoFullNameFromPath(workingDirectory) {
40911
41170
  }
40912
41171
 
40913
41172
  // packages/utils/dist/update-checker.js
40914
- var import_node_fs9 = __toESM(require("node:fs"), 1);
41173
+ var import_node_fs10 = __toESM(require("node:fs"), 1);
40915
41174
  var import_node_path12 = __toESM(require("node:path"), 1);
40916
41175
  var import_node_https = __toESM(require("node:https"), 1);
40917
41176
  var import_node_os4 = __toESM(require("node:os"), 1);
@@ -40926,9 +41185,9 @@ function getCachePath() {
40926
41185
  function readCache() {
40927
41186
  try {
40928
41187
  const cachePath = getCachePath();
40929
- if (!import_node_fs9.default.existsSync(cachePath))
41188
+ if (!import_node_fs10.default.existsSync(cachePath))
40930
41189
  return null;
40931
- const data = import_node_fs9.default.readFileSync(cachePath, "utf-8");
41190
+ const data = import_node_fs10.default.readFileSync(cachePath, "utf-8");
40932
41191
  return JSON.parse(data);
40933
41192
  } catch {
40934
41193
  return null;
@@ -40938,10 +41197,10 @@ function writeCache(cache) {
40938
41197
  try {
40939
41198
  const cachePath = getCachePath();
40940
41199
  const cacheDir = import_node_path12.default.dirname(cachePath);
40941
- if (!import_node_fs9.default.existsSync(cacheDir)) {
40942
- import_node_fs9.default.mkdirSync(cacheDir, { recursive: true });
41200
+ if (!import_node_fs10.default.existsSync(cacheDir)) {
41201
+ import_node_fs10.default.mkdirSync(cacheDir, { recursive: true });
40943
41202
  }
40944
- import_node_fs9.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
41203
+ import_node_fs10.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
40945
41204
  } catch {
40946
41205
  }
40947
41206
  }
@@ -41059,10 +41318,10 @@ function checkForUpdatesInBackground(currentVersion) {
41059
41318
  }
41060
41319
 
41061
41320
  // packages/utils/dist/error-tracking.js
41062
- var import_node_crypto8 = require("node:crypto");
41321
+ var import_node_crypto9 = require("node:crypto");
41063
41322
  function generateErrorId() {
41064
41323
  const timestamp = Math.floor(Date.now() / 1e3);
41065
- const random = (0, import_node_crypto8.randomBytes)(2).toString("hex");
41324
+ const random = (0, import_node_crypto9.randomBytes)(2).toString("hex");
41066
41325
  return `ERR-${timestamp}-${random}`;
41067
41326
  }
41068
41327
  function createTraceableError(message, context = {}, originalError) {
@@ -41220,7 +41479,7 @@ function validateModelForCli(cli, model) {
41220
41479
  }
41221
41480
 
41222
41481
  // packages/utils/dist/relay-pty-path.js
41223
- var import_node_fs10 = __toESM(require("node:fs"), 1);
41482
+ var import_node_fs11 = __toESM(require("node:fs"), 1);
41224
41483
  var import_node_os5 = __toESM(require("node:os"), 1);
41225
41484
  var import_node_path13 = __toESM(require("node:path"), 1);
41226
41485
  var SUPPORTED_PLATFORMS = {
@@ -41281,12 +41540,12 @@ function findRelayPtyBinary(callerDirname) {
41281
41540
  const home = process.env.HOME || process.env.USERPROFILE || "";
41282
41541
  if (home) {
41283
41542
  const npxCacheBase = import_node_path13.default.join(home, ".npm", "_npx");
41284
- if (import_node_fs10.default.existsSync(npxCacheBase)) {
41543
+ if (import_node_fs11.default.existsSync(npxCacheBase)) {
41285
41544
  try {
41286
- const entries = import_node_fs10.default.readdirSync(npxCacheBase);
41545
+ const entries = import_node_fs11.default.readdirSync(npxCacheBase);
41287
41546
  for (const entry of entries) {
41288
41547
  const npxPackage = import_node_path13.default.join(npxCacheBase, entry, "node_modules", "agent-relay");
41289
- if (import_node_fs10.default.existsSync(npxPackage)) {
41548
+ if (import_node_fs11.default.existsSync(npxPackage)) {
41290
41549
  packageRoots.push(npxPackage);
41291
41550
  }
41292
41551
  }
@@ -41344,7 +41603,7 @@ function findRelayPtyBinary(callerDirname) {
41344
41603
  }
41345
41604
  function isExecutable(filePath) {
41346
41605
  try {
41347
- import_node_fs10.default.accessSync(filePath, import_node_fs10.default.constants.X_OK);
41606
+ import_node_fs11.default.accessSync(filePath, import_node_fs11.default.constants.X_OK);
41348
41607
  return true;
41349
41608
  } catch {
41350
41609
  return false;
@@ -41353,9 +41612,9 @@ function isExecutable(filePath) {
41353
41612
  function isPlatformCompatibleBinary(filePath) {
41354
41613
  let fd;
41355
41614
  try {
41356
- fd = import_node_fs10.default.openSync(filePath, "r");
41615
+ fd = import_node_fs11.default.openSync(filePath, "r");
41357
41616
  const header = Buffer.alloc(4);
41358
- const bytesRead = import_node_fs10.default.readSync(fd, header, 0, 4, 0);
41617
+ const bytesRead = import_node_fs11.default.readSync(fd, header, 0, 4, 0);
41359
41618
  if (bytesRead < 4) {
41360
41619
  return false;
41361
41620
  }
@@ -41373,7 +41632,7 @@ function isPlatformCompatibleBinary(filePath) {
41373
41632
  } finally {
41374
41633
  if (fd !== void 0) {
41375
41634
  try {
41376
- import_node_fs10.default.closeSync(fd);
41635
+ import_node_fs11.default.closeSync(fd);
41377
41636
  } catch {
41378
41637
  }
41379
41638
  }
@@ -41404,7 +41663,7 @@ function clearBinaryCache() {
41404
41663
 
41405
41664
  // packages/utils/dist/client-helpers.js
41406
41665
  var import_node_net = require("node:net");
41407
- var import_node_crypto9 = require("node:crypto");
41666
+ var import_node_crypto10 = require("node:crypto");
41408
41667
 
41409
41668
  // packages/utils/dist/legacy-protocol.js
41410
41669
  var PROTOCOL_VERSION2 = 1;
@@ -41531,14 +41790,14 @@ function createRequestHandler(socketPath, envelope, options) {
41531
41790
  });
41532
41791
  }
41533
41792
  function generateRequestId(prefix = "") {
41534
- return `${prefix}${Date.now().toString(36)}-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
41793
+ return `${prefix}${Date.now().toString(36)}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
41535
41794
  }
41536
41795
 
41537
41796
  // packages/hooks/dist/types.js
41538
41797
  var HOOK_ABI_VERSION = PROTOCOL_VERSION;
41539
41798
 
41540
41799
  // packages/hooks/dist/registry.js
41541
- var import_node_crypto11 = require("node:crypto");
41800
+ var import_node_crypto12 = require("node:crypto");
41542
41801
  var InMemoryHookMemory = class {
41543
41802
  store = /* @__PURE__ */ new Map();
41544
41803
  get(key) {
@@ -41587,8 +41846,8 @@ var HookRegistry = class {
41587
41846
  injectFn;
41588
41847
  sendFn;
41589
41848
  constructor(options = {}) {
41590
- this.sessionId = (0, import_node_crypto11.randomUUID)();
41591
- this.agentId = options.agentId ?? (0, import_node_crypto11.randomUUID)();
41849
+ this.sessionId = (0, import_node_crypto12.randomUUID)();
41850
+ this.agentId = options.agentId ?? (0, import_node_crypto12.randomUUID)();
41592
41851
  this.agentName = options.agentName ?? "agent";
41593
41852
  this.workingDir = options.workingDir ?? process.cwd();
41594
41853
  this.projectId = options.projectId ?? "default";
@@ -41992,9 +42251,9 @@ var HookRegistry = class {
41992
42251
  var import_node_child_process6 = require("node:child_process");
41993
42252
 
41994
42253
  // packages/config/dist/project-namespace.js
41995
- var import_node_crypto12 = __toESM(require("node:crypto"), 1);
42254
+ var import_node_crypto13 = __toESM(require("node:crypto"), 1);
41996
42255
  var import_node_path14 = __toESM(require("node:path"), 1);
41997
- var import_node_fs11 = __toESM(require("node:fs"), 1);
42256
+ var import_node_fs12 = __toESM(require("node:fs"), 1);
41998
42257
  var import_node_os6 = __toESM(require("node:os"), 1);
41999
42258
  function getGlobalBaseDir2() {
42000
42259
  if (process.env.AGENT_RELAY_DATA_DIR) {
@@ -42007,13 +42266,13 @@ function getGlobalBaseDir2() {
42007
42266
  return import_node_path14.default.join(import_node_os6.default.homedir(), ".agent-relay");
42008
42267
  }
42009
42268
  var GLOBAL_BASE_DIR2 = getGlobalBaseDir2();
42010
- var PROJECT_DATA_DIR = ".agent-relay";
42011
- function hashPath(projectPath) {
42269
+ var PROJECT_DATA_DIR2 = ".agent-relay";
42270
+ function hashPath2(projectPath) {
42012
42271
  const normalized = import_node_path14.default.resolve(projectPath);
42013
- const hash2 = import_node_crypto12.default.createHash("sha256").update(normalized).digest("hex");
42272
+ const hash2 = import_node_crypto13.default.createHash("sha256").update(normalized).digest("hex");
42014
42273
  return hash2.substring(0, 12);
42015
42274
  }
42016
- function findProjectRoot(startDir = process.cwd()) {
42275
+ function findProjectRoot2(startDir = process.cwd()) {
42017
42276
  if (process.env.AGENT_RELAY_PROJECT) {
42018
42277
  return import_node_path14.default.resolve(process.env.AGENT_RELAY_PROJECT);
42019
42278
  }
@@ -42022,7 +42281,7 @@ function findProjectRoot(startDir = process.cwd()) {
42022
42281
  const markers = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".agent-relay"];
42023
42282
  while (current !== root) {
42024
42283
  for (const marker of markers) {
42025
- if (import_node_fs11.default.existsSync(import_node_path14.default.join(current, marker))) {
42284
+ if (import_node_fs12.default.existsSync(import_node_path14.default.join(current, marker))) {
42026
42285
  return current;
42027
42286
  }
42028
42287
  }
@@ -42031,9 +42290,9 @@ function findProjectRoot(startDir = process.cwd()) {
42031
42290
  return import_node_path14.default.resolve(startDir);
42032
42291
  }
42033
42292
  function getProjectPaths2(projectRoot) {
42034
- const root = projectRoot ?? findProjectRoot();
42035
- const projectId = hashPath(root);
42036
- const dataDir = import_node_path14.default.join(root, PROJECT_DATA_DIR);
42293
+ const root = projectRoot ?? findProjectRoot2();
42294
+ const projectId = hashPath2(root);
42295
+ const dataDir = import_node_path14.default.join(root, PROJECT_DATA_DIR2);
42037
42296
  return {
42038
42297
  dataDir,
42039
42298
  teamDir: import_node_path14.default.join(dataDir, "team"),
@@ -42045,10 +42304,10 @@ function getProjectPaths2(projectRoot) {
42045
42304
  }
42046
42305
 
42047
42306
  // packages/config/dist/trajectory-config.js
42048
- var import_node_fs12 = require("node:fs");
42307
+ var import_node_fs13 = require("node:fs");
42049
42308
  var import_node_path15 = require("node:path");
42050
42309
  var import_node_os7 = require("node:os");
42051
- var import_node_crypto13 = require("node:crypto");
42310
+ var import_node_crypto14 = require("node:crypto");
42052
42311
  function getAgentRelayConfigDir() {
42053
42312
  return process.env.AGENT_RELAY_CONFIG_DIR ?? (0, import_node_path15.join)((0, import_node_os7.homedir)(), ".config", "agent-relay");
42054
42313
  }
@@ -42060,7 +42319,7 @@ function readRelayConfig(projectRoot) {
42060
42319
  const configPath = getRelayConfigPath(projectRoot);
42061
42320
  if (configCache && configCache.path === configPath) {
42062
42321
  try {
42063
- const stat2 = (0, import_node_fs12.statSync)(configPath);
42322
+ const stat2 = (0, import_node_fs13.statSync)(configPath);
42064
42323
  if (stat2.mtimeMs === configCache.mtime) {
42065
42324
  return configCache.config;
42066
42325
  }
@@ -42068,13 +42327,13 @@ function readRelayConfig(projectRoot) {
42068
42327
  }
42069
42328
  }
42070
42329
  try {
42071
- if (!(0, import_node_fs12.existsSync)(configPath)) {
42330
+ if (!(0, import_node_fs13.existsSync)(configPath)) {
42072
42331
  return {};
42073
42332
  }
42074
- const content = (0, import_node_fs12.readFileSync)(configPath, "utf-8");
42333
+ const content = (0, import_node_fs13.readFileSync)(configPath, "utf-8");
42075
42334
  const config2 = JSON.parse(content);
42076
42335
  try {
42077
- const stat2 = (0, import_node_fs12.statSync)(configPath);
42336
+ const stat2 = (0, import_node_fs13.statSync)(configPath);
42078
42337
  configCache = { path: configPath, config: config2, mtime: stat2.mtimeMs };
42079
42338
  } catch {
42080
42339
  }
@@ -42090,7 +42349,7 @@ function shouldStoreInRepo(projectRoot) {
42090
42349
  }
42091
42350
  function getProjectHash(projectRoot) {
42092
42351
  const root = projectRoot ?? getProjectPaths2().projectRoot;
42093
- return (0, import_node_crypto13.createHash)("sha256").update(root).digest("hex").slice(0, 16);
42352
+ return (0, import_node_crypto14.createHash)("sha256").update(root).digest("hex").slice(0, 16);
42094
42353
  }
42095
42354
  function getUserTrajectoriesDir(projectRoot) {
42096
42355
  const projectHash = getProjectHash(projectRoot);
@@ -42739,7 +42998,7 @@ var HookEmitter = class {
42739
42998
  };
42740
42999
 
42741
43000
  // packages/hooks/dist/inbox-check/utils.js
42742
- var import_node_fs13 = require("node:fs");
43001
+ var import_node_fs14 = require("node:fs");
42743
43002
  var import_node_path16 = require("node:path");
42744
43003
  var DEFAULT_INBOX_DIR = "/tmp/agent-relay";
42745
43004
  function getAgentName() {
@@ -42753,13 +43012,13 @@ function getInboxPath(config2) {
42753
43012
  return (0, import_node_path16.join)(config2.inboxDir, agentName, "inbox.md");
42754
43013
  }
42755
43014
  function inboxExists(inboxPath) {
42756
- return (0, import_node_fs13.existsSync)(inboxPath);
43015
+ return (0, import_node_fs14.existsSync)(inboxPath);
42757
43016
  }
42758
43017
  function readInbox(inboxPath) {
42759
43018
  if (!inboxExists(inboxPath)) {
42760
43019
  return "";
42761
43020
  }
42762
- return (0, import_node_fs13.readFileSync)(inboxPath, "utf-8");
43021
+ return (0, import_node_fs14.readFileSync)(inboxPath, "utf-8");
42763
43022
  }
42764
43023
  function hasUnreadMessages(inboxPath) {
42765
43024
  const content = readInbox(inboxPath);
@@ -42846,6 +43105,7 @@ init_dist();
42846
43105
  HOOK_ABI_VERSION,
42847
43106
  HookEmitter,
42848
43107
  HookRegistry,
43108
+ HttpAgentRelayClient,
42849
43109
  InMemoryAdapter,
42850
43110
  InMemoryWorkflowDb,
42851
43111
  JsonFileWorkflowDb,