agent-relay 2.1.3 → 2.1.5

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 (58) hide show
  1. package/bin/relay-pty-darwin-arm64 +0 -0
  2. package/bin/relay-pty-darwin-x64 +0 -0
  3. package/bin/relay-pty-linux-arm64 +0 -0
  4. package/bin/relay-pty-linux-x64 +0 -0
  5. package/dist/index.cjs +420 -184
  6. package/package.json +19 -19
  7. package/packages/api-types/package.json +1 -1
  8. package/packages/benchmark/package.json +4 -4
  9. package/packages/bridge/dist/cli-resolution.d.ts +32 -0
  10. package/packages/bridge/dist/cli-resolution.d.ts.map +1 -0
  11. package/packages/bridge/dist/cli-resolution.js +88 -0
  12. package/packages/bridge/dist/cli-resolution.js.map +1 -0
  13. package/packages/bridge/dist/index.d.ts +1 -0
  14. package/packages/bridge/dist/index.d.ts.map +1 -1
  15. package/packages/bridge/dist/index.js +2 -0
  16. package/packages/bridge/dist/index.js.map +1 -1
  17. package/packages/bridge/dist/spawner.d.ts.map +1 -1
  18. package/packages/bridge/dist/spawner.js +43 -17
  19. package/packages/bridge/dist/spawner.js.map +1 -1
  20. package/packages/bridge/package.json +8 -8
  21. package/packages/bridge/src/cli-resolution.test.ts +225 -0
  22. package/packages/bridge/src/cli-resolution.ts +100 -0
  23. package/packages/bridge/src/index.ts +9 -0
  24. package/packages/bridge/src/spawner.ts +44 -18
  25. package/packages/cli-tester/package.json +1 -1
  26. package/packages/config/package.json +2 -2
  27. package/packages/continuity/package.json +2 -2
  28. package/packages/daemon/package.json +12 -12
  29. package/packages/hooks/package.json +4 -4
  30. package/packages/mcp/package.json +3 -3
  31. package/packages/memory/package.json +2 -2
  32. package/packages/policy/package.json +2 -2
  33. package/packages/protocol/package.json +1 -1
  34. package/packages/resiliency/package.json +1 -1
  35. package/packages/sdk/package.json +2 -2
  36. package/packages/spawner/package.json +1 -1
  37. package/packages/state/package.json +1 -1
  38. package/packages/storage/package.json +2 -2
  39. package/packages/telemetry/package.json +1 -1
  40. package/packages/trajectory/package.json +2 -2
  41. package/packages/user-directory/package.json +2 -2
  42. package/packages/utils/package.json +2 -2
  43. package/packages/wrapper/dist/opencode-wrapper.d.ts +6 -2
  44. package/packages/wrapper/dist/opencode-wrapper.d.ts.map +1 -1
  45. package/packages/wrapper/dist/opencode-wrapper.js +34 -10
  46. package/packages/wrapper/dist/opencode-wrapper.js.map +1 -1
  47. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +22 -2
  48. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts.map +1 -1
  49. package/packages/wrapper/dist/relay-pty-orchestrator.js +174 -4
  50. package/packages/wrapper/dist/relay-pty-orchestrator.js.map +1 -1
  51. package/packages/wrapper/dist/shared.d.ts.map +1 -1
  52. package/packages/wrapper/dist/shared.js +5 -0
  53. package/packages/wrapper/dist/shared.js.map +1 -1
  54. package/packages/wrapper/package.json +6 -6
  55. package/packages/wrapper/src/opencode-wrapper.ts +37 -9
  56. package/packages/wrapper/src/relay-pty-orchestrator.ts +197 -4
  57. package/packages/wrapper/src/shared.ts +5 -0
  58. package/relay-snippets/agent-relay-snippet.md +17 -5
package/dist/index.cjs CHANGED
@@ -3147,13 +3147,13 @@ var init_logger = __esm({
3147
3147
  });
3148
3148
 
3149
3149
  // packages/config/dist/bridge-utils.js
3150
- var import_node_child_process8, import_node_util3, execAsync2;
3150
+ var import_node_child_process9, import_node_util3, execAsync2;
3151
3151
  var init_bridge_utils = __esm({
3152
3152
  "packages/config/dist/bridge-utils.js"() {
3153
3153
  "use strict";
3154
- import_node_child_process8 = require("node:child_process");
3154
+ import_node_child_process9 = require("node:child_process");
3155
3155
  import_node_util3 = require("node:util");
3156
- execAsync2 = (0, import_node_util3.promisify)(import_node_child_process8.exec);
3156
+ execAsync2 = (0, import_node_util3.promisify)(import_node_child_process9.exec);
3157
3157
  }
3158
3158
  });
3159
3159
 
@@ -7441,11 +7441,11 @@ var require_core = __commonJS({
7441
7441
  Ajv2.ValidationError = validation_error_1.default;
7442
7442
  Ajv2.MissingRefError = ref_error_1.default;
7443
7443
  exports2.default = Ajv2;
7444
- function checkOptions(checkOpts, options, msg, log7 = "error") {
7444
+ function checkOptions(checkOpts, options, msg, log8 = "error") {
7445
7445
  for (const key in checkOpts) {
7446
7446
  const opt = key;
7447
7447
  if (opt in options)
7448
- this.logger[log7](`${msg}: option ${key}. ${checkOpts[opt]}`);
7448
+ this.logger[log8](`${msg}: option ${key}. ${checkOpts[opt]}`);
7449
7449
  }
7450
7450
  }
7451
7451
  function getSchEnv(keyRef) {
@@ -20852,7 +20852,7 @@ var require_node = __commonJS({
20852
20852
  var tty = require("tty");
20853
20853
  var util2 = require("util");
20854
20854
  exports2.init = init;
20855
- exports2.log = log7;
20855
+ exports2.log = log8;
20856
20856
  exports2.formatArgs = formatArgs;
20857
20857
  exports2.save = save;
20858
20858
  exports2.load = load;
@@ -20987,7 +20987,7 @@ var require_node = __commonJS({
20987
20987
  }
20988
20988
  return (/* @__PURE__ */ new Date()).toISOString() + " ";
20989
20989
  }
20990
- function log7(...args) {
20990
+ function log8(...args) {
20991
20991
  return process.stderr.write(util2.formatWithOptions(exports2.inspectOpts, ...args) + "\n");
20992
20992
  }
20993
20993
  function save(namespaces) {
@@ -31619,13 +31619,13 @@ var channel_membership_store_exports = {};
31619
31619
  __export(channel_membership_store_exports, {
31620
31620
  CloudChannelMembershipStore: () => CloudChannelMembershipStore
31621
31621
  });
31622
- var log6, CloudChannelMembershipStore;
31622
+ var log7, CloudChannelMembershipStore;
31623
31623
  var init_channel_membership_store = __esm({
31624
31624
  "packages/daemon/dist/channel-membership-store.js"() {
31625
31625
  "use strict";
31626
31626
  init_esm();
31627
31627
  init_logger();
31628
- log6 = createLogger2("channel-membership-store");
31628
+ log7 = createLogger2("channel-membership-store");
31629
31629
  CloudChannelMembershipStore = class {
31630
31630
  workspaceId;
31631
31631
  pool;
@@ -31655,7 +31655,7 @@ var init_channel_membership_store = __esm({
31655
31655
  member: row.member_id
31656
31656
  })).filter((row) => Boolean(row.channel && row.member));
31657
31657
  } catch (err) {
31658
- log6.error("Failed to load channel memberships from cloud DB", {
31658
+ log7.error("Failed to load channel memberships from cloud DB", {
31659
31659
  error: err instanceof Error ? err.message : String(err)
31660
31660
  });
31661
31661
  return [];
@@ -31678,7 +31678,7 @@ var init_channel_membership_store = __esm({
31678
31678
  member: row.member_id
31679
31679
  })).filter((row) => Boolean(row.channel && row.member));
31680
31680
  } catch (err) {
31681
- log6.error("Failed to load channel memberships for agent from cloud DB", {
31681
+ log7.error("Failed to load channel memberships for agent from cloud DB", {
31682
31682
  memberName,
31683
31683
  error: err instanceof Error ? err.message : String(err)
31684
31684
  });
@@ -31704,7 +31704,7 @@ var init_channel_membership_store = __esm({
31704
31704
  ON CONFLICT (channel_id, member_id) DO NOTHING
31705
31705
  `, [channelRowId, member]);
31706
31706
  } catch (err) {
31707
- log6.error("Failed to add channel member in cloud DB", {
31707
+ log7.error("Failed to add channel member in cloud DB", {
31708
31708
  channel: normalized,
31709
31709
  member,
31710
31710
  error: err instanceof Error ? err.message : String(err)
@@ -31726,7 +31726,7 @@ var init_channel_membership_store = __esm({
31726
31726
  try {
31727
31727
  await this.pool.query("DELETE FROM channel_members WHERE channel_id = $1 AND member_id = $2", [channelRowId, member]);
31728
31728
  } catch (err) {
31729
- log6.error("Failed to remove channel member in cloud DB", {
31729
+ log7.error("Failed to remove channel member in cloud DB", {
31730
31730
  channel: normalized,
31731
31731
  member,
31732
31732
  error: err instanceof Error ? err.message : String(err)
@@ -31766,7 +31766,7 @@ var init_channel_membership_store = __esm({
31766
31766
  LIMIT 1
31767
31767
  `, [this.workspaceId, channelId]);
31768
31768
  if (!result.rows[0]?.id) {
31769
- log6.warn("Channel not found in cloud DB for membership update", {
31769
+ log7.warn("Channel not found in cloud DB for membership update", {
31770
31770
  workspaceId: this.workspaceId,
31771
31771
  channelId
31772
31772
  });
@@ -31774,7 +31774,7 @@ var init_channel_membership_store = __esm({
31774
31774
  }
31775
31775
  return result.rows[0].id;
31776
31776
  } catch (err) {
31777
- log6.error("Failed to look up channel row in cloud DB", {
31777
+ log7.error("Failed to look up channel row in cloud DB", {
31778
31778
  channelId,
31779
31779
  error: err instanceof Error ? err.message : String(err)
31780
31780
  });
@@ -37398,6 +37398,7 @@ function createInjectionMetrics() {
37398
37398
  }
37399
37399
  function detectCliType(command) {
37400
37400
  const cmdLower = command.toLowerCase();
37401
+ const cmdName = cmdLower.split(/[\s/\\]/).pop() || cmdLower;
37401
37402
  if (cmdLower.includes("gemini"))
37402
37403
  return "gemini";
37403
37404
  if (cmdLower.includes("codex"))
@@ -37410,6 +37411,8 @@ function detectCliType(command) {
37410
37411
  return "opencode";
37411
37412
  if (cmdLower.includes("cursor"))
37412
37413
  return "cursor";
37414
+ if (cmdName === "agent" || cmdName === "cursor-agent")
37415
+ return "cursor";
37413
37416
  return "other";
37414
37417
  }
37415
37418
  function getDefaultRelayPrefix() {
@@ -43430,9 +43433,9 @@ var AgentHealthMonitor = class extends import_events.EventEmitter {
43430
43433
  * Get memory and CPU usage for a process
43431
43434
  */
43432
43435
  async getProcessUsage(pid) {
43433
- const { execSync: execSync9 } = await import("child_process");
43436
+ const { execSync: execSync10 } = await import("child_process");
43434
43437
  try {
43435
- const output = execSync9(`ps -o rss=,pcpu= -p ${pid}`, { encoding: "utf8" }).trim();
43438
+ const output = execSync10(`ps -o rss=,pcpu= -p ${pid}`, { encoding: "utf8" }).trim();
43436
43439
  const [rss, cpu] = output.split(/\s+/);
43437
43440
  return {
43438
43441
  memory: parseInt(rss, 10) * 1024,
@@ -46306,6 +46309,54 @@ var __filename2 = (0, import_node_url2.fileURLToPath)(import_meta_url);
46306
46309
  var __dirname2 = (0, import_node_path11.dirname)(__filename2);
46307
46310
  var MAX_SOCKET_PATH_LENGTH = 107;
46308
46311
  var MAX_OUTPUT_BUFFER_SIZE = 10 * 1024 * 1024;
46312
+ var ACTIVITY_VERIFICATION = {
46313
+ /** Time to wait for activity patterns after injection (ms) */
46314
+ TIMEOUT_MS: 5e3,
46315
+ /** How often to check for activity patterns (ms) */
46316
+ POLL_INTERVAL_MS: 200,
46317
+ /** Maximum retries when no activity is detected */
46318
+ MAX_RETRIES: 3,
46319
+ /** Delay between retries (ms) */
46320
+ RETRY_DELAY_MS: 500,
46321
+ /**
46322
+ * Patterns indicating the task was received and displayed.
46323
+ * These are the primary verification patterns.
46324
+ */
46325
+ TASK_RECEIVED_PATTERNS: [
46326
+ /\[Pasted text #\d+/,
46327
+ // Claude Code shows "[Pasted text #1 +95 lines]"
46328
+ /› Relay message from/,
46329
+ // Codex shows "› Relay message from"
46330
+ /Relay message from \w+ \[[\w-]+\]/
46331
+ // Droid/Gemini shows "Relay message from Agent [id]:"
46332
+ ],
46333
+ /**
46334
+ * Patterns indicating the CLI is thinking/processing.
46335
+ * Secondary verification - proves the CLI is active.
46336
+ */
46337
+ THINKING_PATTERNS: [
46338
+ /\(.*esc to (?:interrupt|stop)\)/i,
46339
+ // All CLIs: "(esc to interrupt)" or "(Press ESC to stop)"
46340
+ /[✻✶✳✢·✽⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/,
46341
+ // Spinner characters (Claude + Droid)
46342
+ /Thinking\.\.\./,
46343
+ // Droid: "Thinking..."
46344
+ /Working/,
46345
+ // Codex: "Working"
46346
+ /Forming|Noodling|Manifesting/i
46347
+ // Claude Code thinking states
46348
+ ],
46349
+ /**
46350
+ * Patterns indicating tool execution started.
46351
+ * Tertiary verification - proves the CLI is working.
46352
+ */
46353
+ TOOL_EXECUTION_PATTERNS: [
46354
+ /⏺\s*(Bash|Read|Write|Edit|Glob|Grep|Task|WebFetch)/,
46355
+ // Claude Code tool markers
46356
+ /•\s*Running/
46357
+ // Codex: "• Running: command"
46358
+ ]
46359
+ };
46309
46360
  function hashWorkspaceId(workspaceId) {
46310
46361
  return (0, import_node_crypto9.createHash)("sha256").update(workspaceId).digest("hex").slice(0, 12);
46311
46362
  }
@@ -46328,6 +46379,7 @@ var RelayPtyOrchestrator = class extends BaseWrapper {
46328
46379
  outputBuffer = "";
46329
46380
  rawBuffer = "";
46330
46381
  lastParsedLength = 0;
46382
+ bufferTrimCount = 0;
46331
46383
  // Interactive mode (show output to terminal)
46332
46384
  isInteractive = false;
46333
46385
  // Injection state
@@ -46876,13 +46928,19 @@ Stderr: ${stderrBuffer.slice(0, 500)}` : "";
46876
46928
  this.rawBuffer += data;
46877
46929
  this.outputBuffer += data;
46878
46930
  this.hasReceivedOutput = true;
46931
+ let buffersTrimmed = false;
46879
46932
  if (this.rawBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
46880
46933
  const trimAmount = this.rawBuffer.length - MAX_OUTPUT_BUFFER_SIZE;
46881
46934
  this.rawBuffer = this.rawBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
46882
46935
  this.lastParsedLength = Math.max(0, this.lastParsedLength - trimAmount);
46936
+ buffersTrimmed = true;
46883
46937
  }
46884
46938
  if (this.outputBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
46885
46939
  this.outputBuffer = this.outputBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
46940
+ buffersTrimmed = true;
46941
+ }
46942
+ if (buffersTrimmed) {
46943
+ this.bufferTrimCount += 1;
46886
46944
  }
46887
46945
  this.feedIdleDetectorOutput(data);
46888
46946
  const indicator = this.formatUnreadIndicator();
@@ -48126,14 +48184,103 @@ Then output: \`->relay-file:spawn\`
48126
48184
  this.relayPtyProcess.stdin.write(buffer);
48127
48185
  }
48128
48186
  /**
48129
- * Inject a task using the socket-based injection system with verification.
48187
+ * Verify that the CLI shows activity after task injection.
48188
+ * Checks output for patterns indicating the task was received and processing started.
48189
+ *
48190
+ * This catches the race condition where PTY write succeeds but CLI wasn't ready
48191
+ * (the T-003 failure scenario where CLI showed bell characters instead of processing).
48192
+ *
48193
+ * @param outputBefore The output buffer content before injection
48194
+ * @returns Promise resolving to true if activity detected, false otherwise
48195
+ */
48196
+ async verifyActivityAfterInjection(outputBefore) {
48197
+ const startTime = Date.now();
48198
+ const { TIMEOUT_MS, POLL_INTERVAL_MS, TASK_RECEIVED_PATTERNS, THINKING_PATTERNS, TOOL_EXECUTION_PATTERNS } = ACTIVITY_VERIFICATION;
48199
+ const trimCountBefore = this.bufferTrimCount;
48200
+ while (Date.now() - startTime < TIMEOUT_MS) {
48201
+ if (this.bufferTrimCount !== trimCountBefore) {
48202
+ this.log(` Activity verified: output buffer trimmed during verification (large output)`);
48203
+ return true;
48204
+ }
48205
+ const currentOutput = this.outputBuffer;
48206
+ const newOutput = currentOutput.slice(outputBefore.length);
48207
+ if (newOutput.length > 0) {
48208
+ const belCount = (newOutput.match(/\x07/g) || []).length;
48209
+ if (belCount > 10) {
48210
+ this.logError(` Input rejected: CLI produced ${belCount} BEL characters`);
48211
+ return false;
48212
+ }
48213
+ for (const pattern of TASK_RECEIVED_PATTERNS) {
48214
+ if (pattern.test(newOutput)) {
48215
+ this.log(` Activity verified: task received pattern matched`);
48216
+ return true;
48217
+ }
48218
+ }
48219
+ for (const pattern of THINKING_PATTERNS) {
48220
+ if (pattern.test(newOutput)) {
48221
+ this.log(` Activity verified: thinking pattern matched`);
48222
+ return true;
48223
+ }
48224
+ }
48225
+ for (const pattern of TOOL_EXECUTION_PATTERNS) {
48226
+ if (pattern.test(newOutput)) {
48227
+ this.log(` Activity verified: tool execution pattern matched`);
48228
+ return true;
48229
+ }
48230
+ }
48231
+ const meaningfulOutput = newOutput.replace(/[\x00-\x1f]/g, "");
48232
+ if (meaningfulOutput.length > 100) {
48233
+ this.log(` Activity verified: significant output growth (${meaningfulOutput.length} meaningful chars)`);
48234
+ return true;
48235
+ }
48236
+ }
48237
+ await sleep(POLL_INTERVAL_MS);
48238
+ }
48239
+ this.log(` No activity detected within ${TIMEOUT_MS}ms`);
48240
+ return false;
48241
+ }
48242
+ /**
48243
+ * Inject a task using the socket-based injection system with activity verification.
48130
48244
  * This is the preferred method for spawned agent task delivery.
48131
48245
  *
48246
+ * After socket confirms delivery, verifies the CLI shows activity (task received,
48247
+ * thinking indicators, or tool execution). Retries if no activity is detected.
48248
+ *
48132
48249
  * @param task The task text to inject
48133
48250
  * @param from The sender name (default: "spawner")
48134
- * @returns Promise resolving to true if injection succeeded, false otherwise
48251
+ * @returns Promise resolving to true if task was delivered AND activity verified, false otherwise
48135
48252
  */
48136
48253
  async injectTask(task, from = "spawner") {
48254
+ const { MAX_RETRIES, RETRY_DELAY_MS } = ACTIVITY_VERIFICATION;
48255
+ const STABILIZATION_DELAY_MS = 1500;
48256
+ this.log(` Waiting ${STABILIZATION_DELAY_MS}ms for CLI stabilization before task injection`);
48257
+ await sleep(STABILIZATION_DELAY_MS);
48258
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
48259
+ if (attempt > 0) {
48260
+ this.log(` Retry ${attempt}/${MAX_RETRIES} - waiting ${RETRY_DELAY_MS}ms before retry`);
48261
+ await sleep(RETRY_DELAY_MS);
48262
+ }
48263
+ const outputBefore = this.outputBuffer;
48264
+ const delivered = await this.performTaskInjection(task, from);
48265
+ if (!delivered) {
48266
+ this.logError(` Task delivery failed on attempt ${attempt + 1}`);
48267
+ continue;
48268
+ }
48269
+ const activityVerified = await this.verifyActivityAfterInjection(outputBefore);
48270
+ if (activityVerified) {
48271
+ this.log(` Task delivered and activity verified successfully`);
48272
+ return true;
48273
+ }
48274
+ this.logError(` Task delivered but no activity detected (attempt ${attempt + 1})`);
48275
+ }
48276
+ this.logError(` Task injection failed after ${MAX_RETRIES + 1} attempts - no CLI activity detected`);
48277
+ return false;
48278
+ }
48279
+ /**
48280
+ * Perform a single task injection attempt (without retry logic).
48281
+ * @returns true if the injection was sent successfully, false otherwise
48282
+ */
48283
+ async performTaskInjection(task, from) {
48137
48284
  if (!this.socket || !this.socketConnected) {
48138
48285
  this.log(` Socket not connected for task injection, falling back to stdin write`);
48139
48286
  try {
@@ -48386,6 +48533,12 @@ var openCodeApi = new OpenCodeApi();
48386
48533
 
48387
48534
  // packages/wrapper/dist/opencode-wrapper.js
48388
48535
  var import_node_child_process4 = require("node:child_process");
48536
+ var TASK_INJECTION = {
48537
+ /** Maximum retries when injection fails */
48538
+ MAX_RETRIES: 3,
48539
+ /** Delay between retries (ms) */
48540
+ RETRY_DELAY_MS: 500
48541
+ };
48389
48542
  var OpenCodeWrapper = class extends BaseWrapper {
48390
48543
  config;
48391
48544
  // OpenCode API client
@@ -48641,19 +48794,32 @@ var OpenCodeWrapper = class extends BaseWrapper {
48641
48794
  }
48642
48795
  }
48643
48796
  /**
48644
- * Inject a task into the agent
48797
+ * Inject a task into the agent with retry logic.
48798
+ *
48799
+ * Retries on transient failures to match RelayPtyOrchestrator behavior.
48800
+ * This ensures consistent reliability across all wrapper types.
48801
+ *
48645
48802
  * @param task - The task description to inject
48646
48803
  * @param _from - The sender name (used for formatting)
48647
- * @returns true if injection succeeded
48804
+ * @returns true if injection succeeded, false otherwise
48648
48805
  */
48649
48806
  async injectTask(task, _from) {
48650
- try {
48651
- await this.performInjection(task);
48652
- return true;
48653
- } catch (error2) {
48654
- console.error("[OpenCodeWrapper] Task injection failed:", error2);
48655
- return false;
48807
+ const { MAX_RETRIES, RETRY_DELAY_MS } = TASK_INJECTION;
48808
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
48809
+ if (attempt > 0) {
48810
+ console.log(`[OpenCodeWrapper] Retry ${attempt}/${MAX_RETRIES} - waiting ${RETRY_DELAY_MS}ms before retry`);
48811
+ await sleep(RETRY_DELAY_MS);
48812
+ }
48813
+ try {
48814
+ await this.performInjection(task);
48815
+ console.log(`[OpenCodeWrapper] Task delivered successfully${attempt > 0 ? ` (attempt ${attempt + 1})` : ""}`);
48816
+ return true;
48817
+ } catch (error2) {
48818
+ console.error(`[OpenCodeWrapper] Task delivery failed (attempt ${attempt + 1}/${MAX_RETRIES + 1}):`, error2);
48819
+ }
48656
48820
  }
48821
+ console.error(`[OpenCodeWrapper] Task injection failed after ${MAX_RETRIES + 1} attempts`);
48822
+ return false;
48657
48823
  }
48658
48824
  /**
48659
48825
  * Get output lines (for compatibility with spawner)
@@ -55172,9 +55338,55 @@ async function selectShadowCli(primaryCli, options) {
55172
55338
  throw new Error("No shadow-capable CLI authenticated. Install Claude or OpenCode (codex) and try again.");
55173
55339
  }
55174
55340
 
55341
+ // packages/bridge/dist/cli-resolution.js
55342
+ var import_node_child_process8 = require("node:child_process");
55343
+ init_logger();
55344
+ var log2 = createLogger2("cli-resolution");
55345
+ function commandExists2(cmd) {
55346
+ try {
55347
+ const whichCmd = process.platform === "win32" ? "where" : "which";
55348
+ (0, import_node_child_process8.execSync)(`${whichCmd} ${cmd}`, { stdio: "ignore" });
55349
+ return true;
55350
+ } catch {
55351
+ return false;
55352
+ }
55353
+ }
55354
+ var detectedCursorCli = null;
55355
+ function detectCursorCli() {
55356
+ if (detectedCursorCli !== null) {
55357
+ return detectedCursorCli;
55358
+ }
55359
+ if (commandExists2("agent")) {
55360
+ detectedCursorCli = "agent";
55361
+ log2.debug("Detected Cursor CLI: agent (newer version)");
55362
+ return "agent";
55363
+ }
55364
+ if (commandExists2("cursor-agent")) {
55365
+ detectedCursorCli = "cursor-agent";
55366
+ log2.debug("Detected Cursor CLI: cursor-agent (older version)");
55367
+ return "cursor-agent";
55368
+ }
55369
+ log2.debug("Cursor CLI not found (neither agent nor cursor-agent)");
55370
+ return null;
55371
+ }
55372
+ function resolveCli(rawCommand) {
55373
+ const cmdLower = rawCommand.toLowerCase();
55374
+ if (cmdLower === "cursor" || cmdLower === "cursor-agent") {
55375
+ const cursorCli = detectCursorCli();
55376
+ if (cursorCli) {
55377
+ return cursorCli;
55378
+ }
55379
+ return "agent";
55380
+ }
55381
+ if (cmdLower === "google") {
55382
+ return "gemini";
55383
+ }
55384
+ return rawCommand;
55385
+ }
55386
+
55175
55387
  // packages/bridge/dist/spawner.js
55176
55388
  var import_node_fs14 = __toESM(require("node:fs"), 1);
55177
- var import_node_child_process11 = require("node:child_process");
55389
+ var import_node_child_process12 = require("node:child_process");
55178
55390
  var import_node_path17 = __toESM(require("node:path"), 1);
55179
55391
  var import_node_url3 = require("node:url");
55180
55392
 
@@ -63297,8 +63509,8 @@ var relayStatusSchema = external_exports.object({});
63297
63509
 
63298
63510
  // packages/mcp/dist/tools/relay-logs.js
63299
63511
  var import_node_util4 = require("node:util");
63300
- var import_node_child_process9 = require("node:child_process");
63301
- var execAsync3 = (0, import_node_util4.promisify)(import_node_child_process9.exec);
63512
+ var import_node_child_process10 = require("node:child_process");
63513
+ var execAsync3 = (0, import_node_util4.promisify)(import_node_child_process10.exec);
63302
63514
  var relayLogsSchema = external_exports.object({
63303
63515
  agent: external_exports.string().describe("Name of the agent to get logs for"),
63304
63516
  lines: external_exports.number().optional().default(50).describe("Number of lines to retrieve (default: 50)")
@@ -63393,7 +63605,7 @@ var relayVoteSchema = external_exports.object({
63393
63605
  var import_node_fs13 = require("node:fs");
63394
63606
  var import_node_path16 = require("node:path");
63395
63607
  var import_node_os9 = require("node:os");
63396
- var import_node_child_process10 = require("node:child_process");
63608
+ var import_node_child_process11 = require("node:child_process");
63397
63609
 
63398
63610
  // node_modules/smol-toml/dist/error.js
63399
63611
  function getLineColFromPtr(string3, ptr) {
@@ -64301,7 +64513,7 @@ function getConfigPaths() {
64301
64513
  }
64302
64514
  function isUsingNvm() {
64303
64515
  try {
64304
- const nodePath = (0, import_node_child_process10.execSync)("which node", { encoding: "utf-8" }).trim();
64516
+ const nodePath = (0, import_node_child_process11.execSync)("which node", { encoding: "utf-8" }).trim();
64305
64517
  return nodePath.includes(".nvm");
64306
64518
  } catch {
64307
64519
  return false;
@@ -64309,14 +64521,14 @@ function isUsingNvm() {
64309
64521
  }
64310
64522
  function getNodePath() {
64311
64523
  try {
64312
- return (0, import_node_child_process10.execSync)("which node", { encoding: "utf-8" }).trim();
64524
+ return (0, import_node_child_process11.execSync)("which node", { encoding: "utf-8" }).trim();
64313
64525
  } catch {
64314
64526
  return null;
64315
64527
  }
64316
64528
  }
64317
64529
  function getGlobalMcpBinPath() {
64318
64530
  try {
64319
- const npmPrefix = (0, import_node_child_process10.execSync)("npm prefix -g", { encoding: "utf-8" }).trim();
64531
+ const npmPrefix = (0, import_node_child_process11.execSync)("npm prefix -g", { encoding: "utf-8" }).trim();
64320
64532
  const binPath = (0, import_node_path16.join)(npmPrefix, "lib", "node_modules", "@agent-relay", "mcp", "dist", "bin.js");
64321
64533
  if ((0, import_node_fs13.existsSync)(binPath)) {
64322
64534
  return binPath;
@@ -64544,14 +64756,7 @@ function installMcpConfig(configPath, options = {}) {
64544
64756
  // packages/bridge/dist/spawner.js
64545
64757
  var __filename3 = (0, import_node_url3.fileURLToPath)(import_meta_url);
64546
64758
  var __dirname3 = import_node_path17.default.dirname(__filename3);
64547
- var log2 = createLogger2("spawner");
64548
- var CLI_COMMAND_MAP = {
64549
- cursor: "agent",
64550
- // Cursor CLI installs as 'agent'
64551
- google: "gemini"
64552
- // Google provider uses 'gemini' CLI
64553
- // Other providers use their name as the command (claude, codex, etc.)
64554
- };
64759
+ var log3 = createLogger2("spawner");
64555
64760
  function extractGhTokenFromHosts(content) {
64556
64761
  const lines = content.split(/\r?\n/);
64557
64762
  let inGithubSection = false;
@@ -64614,7 +64819,7 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
64614
64819
  const config2 = configMap[effectiveCli];
64615
64820
  if (!config2) {
64616
64821
  if (debug)
64617
- log2.debug(`CLI ${cliType} uses flag-based permissions, skipping config setup`);
64822
+ log3.debug(`CLI ${cliType} uses flag-based permissions, skipping config setup`);
64618
64823
  return;
64619
64824
  }
64620
64825
  const settingsPath = import_node_path17.default.join(config2.settingsDir, config2.settingsFile);
@@ -64634,7 +64839,7 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
64634
64839
  if (config2.enableAllKey && settings[config2.enableAllKey] !== true) {
64635
64840
  settings[config2.enableAllKey] = true;
64636
64841
  if (debug)
64637
- log2.debug(`Setting ${config2.enableAllKey}: true`);
64842
+ log3.debug(`Setting ${config2.enableAllKey}: true`);
64638
64843
  }
64639
64844
  if (config2.permissionKey) {
64640
64845
  const keyParts = config2.permissionKey.split(".");
@@ -64655,14 +64860,14 @@ function ensureMcpPermissions(projectRoot, cliType, debug = false) {
64655
64860
  if (!allowList.includes(agentRelayPermission)) {
64656
64861
  allowList.push(agentRelayPermission);
64657
64862
  if (debug)
64658
- log2.debug(`Added MCP permission: ${agentRelayPermission}`);
64863
+ log3.debug(`Added MCP permission: ${agentRelayPermission}`);
64659
64864
  }
64660
64865
  }
64661
64866
  import_node_fs14.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
64662
64867
  if (debug)
64663
- log2.debug(`MCP permissions configured at ${settingsPath}`);
64868
+ log3.debug(`MCP permissions configured at ${settingsPath}`);
64664
64869
  } catch (err) {
64665
- log2.warn("Failed to pre-configure MCP permissions", {
64870
+ log3.warn("Failed to pre-configure MCP permissions", {
64666
64871
  cli: cliType,
64667
64872
  error: err instanceof Error ? err.message : String(err)
64668
64873
  });
@@ -64712,9 +64917,9 @@ function hasRelayPtyBinary2() {
64712
64917
  relayPtyBinaryChecked = true;
64713
64918
  if (process.env.DEBUG_SPAWN === "1") {
64714
64919
  if (relayPtyBinaryPath) {
64715
- log2.debug(`relay-pty binary found: ${relayPtyBinaryPath}`);
64920
+ log3.debug(`relay-pty binary found: ${relayPtyBinaryPath}`);
64716
64921
  } else {
64717
- log2.debug("relay-pty binary not found, will use PtyWrapper fallback");
64922
+ log3.debug("relay-pty binary not found, will use PtyWrapper fallback");
64718
64923
  }
64719
64924
  }
64720
64925
  }
@@ -64743,7 +64948,7 @@ var AgentSpawner = class _AgentSpawner {
64743
64948
  const effectiveTeamDir = options.teamDir ?? paths.teamDir;
64744
64949
  this.agentsPath = import_node_path17.default.join(effectiveTeamDir, "connected-agents.json");
64745
64950
  this.registryPath = import_node_path17.default.join(effectiveTeamDir, "agents.json");
64746
- log2.info(`AgentSpawner paths: projectRoot=${this.projectRoot} teamDir=${effectiveTeamDir} (explicit=${!!options.teamDir}) agentsPath=${this.agentsPath}`);
64951
+ log3.info(`AgentSpawner paths: projectRoot=${this.projectRoot} teamDir=${effectiveTeamDir} (explicit=${!!options.teamDir}) agentsPath=${this.agentsPath}`);
64747
64952
  this.socketPath = options.socketPath ?? paths.socketPath;
64748
64953
  this.logsDir = import_node_path17.default.join(effectiveTeamDir, "worker-logs");
64749
64954
  this.workersPath = import_node_path17.default.join(effectiveTeamDir, "workers.json");
@@ -64758,7 +64963,7 @@ var AgentSpawner = class _AgentSpawner {
64758
64963
  workspaceId: process.env.WORKSPACE_ID,
64759
64964
  strictMode: process.env.AGENT_POLICY_STRICT === "1"
64760
64965
  });
64761
- log2.info("Policy enforcement enabled");
64966
+ log3.info("Policy enforcement enabled");
64762
64967
  }
64763
64968
  }
64764
64969
  /**
@@ -64800,7 +65005,7 @@ var AgentSpawner = class _AgentSpawner {
64800
65005
  });
64801
65006
  clearTimeout(timeoutId);
64802
65007
  if (!response.ok) {
64803
- log2.warn(`Failed to fetch GH token from cloud: ${response.status} ${response.statusText}`);
65008
+ log3.warn(`Failed to fetch GH token from cloud: ${response.status} ${response.statusText}`);
64804
65009
  return null;
64805
65010
  }
64806
65011
  const data = await response.json();
@@ -64808,9 +65013,9 @@ var AgentSpawner = class _AgentSpawner {
64808
65013
  } catch (err) {
64809
65014
  const message = err instanceof Error ? err.message : String(err);
64810
65015
  if (message.includes("abort")) {
64811
- log2.info("Cloud API timeout (5s) - using local auth");
65016
+ log3.info("Cloud API timeout (5s) - using local auth");
64812
65017
  } else {
64813
- log2.warn("Failed to fetch GH token from cloud", { error: message });
65018
+ log3.warn("Failed to fetch GH token from cloud", { error: message });
64814
65019
  }
64815
65020
  return null;
64816
65021
  }
@@ -64857,7 +65062,7 @@ var AgentSpawner = class _AgentSpawner {
64857
65062
  return null;
64858
65063
  }
64859
65064
  return await new Promise((resolve5) => {
64860
- (0, import_node_child_process11.execFile)(ghPath, ["auth", "token", "--hostname", "github.com"], { timeout: 5e3 }, (err, stdout) => {
65065
+ (0, import_node_child_process12.execFile)(ghPath, ["auth", "token", "--hostname", "github.com"], { timeout: 5e3 }, (err, stdout) => {
64861
65066
  if (err) {
64862
65067
  resolve5(null);
64863
65068
  return;
@@ -64901,7 +65106,7 @@ var AgentSpawner = class _AgentSpawner {
64901
65106
  * Called after the dashboard server starts and we know the actual port.
64902
65107
  */
64903
65108
  setDashboardPort(port) {
64904
- log2.info(`Dashboard port set to ${port} - nested spawns now enabled`);
65109
+ log3.info(`Dashboard port set to ${port} - nested spawns now enabled`);
64905
65110
  this.dashboardPort = port;
64906
65111
  }
64907
65112
  /**
@@ -64920,7 +65125,7 @@ var AgentSpawner = class _AgentSpawner {
64920
65125
  */
64921
65126
  setCloudPersistence(handler) {
64922
65127
  this.cloudPersistence = handler;
64923
- log2.info("Cloud persistence handler set");
65128
+ log3.info("Cloud persistence handler set");
64924
65129
  }
64925
65130
  /**
64926
65131
  * Bind cloud persistence event handlers to a RelayPtyOrchestrator.
@@ -64933,14 +65138,14 @@ var AgentSpawner = class _AgentSpawner {
64933
65138
  try {
64934
65139
  await this.cloudPersistence.onSummary(name, event);
64935
65140
  } catch (err) {
64936
- log2.error(`Cloud persistence summary error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
65141
+ log3.error(`Cloud persistence summary error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
64937
65142
  }
64938
65143
  };
64939
65144
  const sessionEndListener = async (event) => {
64940
65145
  try {
64941
65146
  await this.cloudPersistence.onSessionEnd(name, event);
64942
65147
  } catch (err) {
64943
- log2.error(`Cloud persistence session-end error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
65148
+ log3.error(`Cloud persistence session-end error for ${name}`, { error: err instanceof Error ? err.message : String(err) });
64944
65149
  }
64945
65150
  };
64946
65151
  pty.on("summary", summaryListener);
@@ -64993,7 +65198,7 @@ var AgentSpawner = class _AgentSpawner {
64993
65198
  const maxAgents = parseInt(process.env.MAX_AGENTS ?? "", 10) || 1e4;
64994
65199
  const currentAgentCount = this.activeWorkers.size;
64995
65200
  if (currentAgentCount >= maxAgents) {
64996
- log2.warn(`Agent limit reached: ${currentAgentCount}/${maxAgents}`);
65201
+ log3.warn(`Agent limit reached: ${currentAgentCount}/${maxAgents}`);
64997
65202
  return {
64998
65203
  success: false,
64999
65204
  name,
@@ -65003,7 +65208,7 @@ var AgentSpawner = class _AgentSpawner {
65003
65208
  if (this.policyEnforcementEnabled && this.policyService && spawnerName) {
65004
65209
  const decision = await this.policyService.canSpawn(spawnerName, name, cli);
65005
65210
  if (!decision.allowed) {
65006
- log2.warn(`Policy blocked spawn: ${spawnerName} -> ${name}: ${decision.reason}`);
65211
+ log3.warn(`Policy blocked spawn: ${spawnerName} -> ${name}: ${decision.reason}`);
65007
65212
  return {
65008
65213
  success: false,
65009
65214
  name,
@@ -65012,26 +65217,26 @@ var AgentSpawner = class _AgentSpawner {
65012
65217
  };
65013
65218
  }
65014
65219
  if (debug) {
65015
- log2.debug(`Policy allowed spawn: ${spawnerName} -> ${name} (source: ${decision.policySource})`);
65220
+ log3.debug(`Policy allowed spawn: ${spawnerName} -> ${name} (source: ${decision.policySource})`);
65016
65221
  }
65017
65222
  }
65018
65223
  try {
65019
65224
  const cliParts = cli.split(" ");
65020
65225
  const rawCommandName = cliParts[0];
65021
- const commandName = CLI_COMMAND_MAP[rawCommandName] || rawCommandName;
65226
+ const commandName = resolveCli(rawCommandName);
65022
65227
  const args = cliParts.slice(1);
65023
65228
  if (commandName !== rawCommandName && debug) {
65024
- log2.debug(`Mapped CLI '${rawCommandName}' -> '${commandName}'`);
65229
+ log3.debug(`Mapped CLI '${rawCommandName}' -> '${commandName}'`);
65025
65230
  }
65026
65231
  const command = resolveCommand(commandName);
65027
65232
  if (debug)
65028
- log2.debug(`Resolved '${commandName}' -> '${command}'`);
65233
+ log3.debug(`Resolved '${commandName}' -> '${command}'`);
65029
65234
  if (command === commandName && !commandName.startsWith("/")) {
65030
- log2.warn(`Could not resolve path for '${commandName}', spawn may fail`);
65235
+ log3.warn(`Could not resolve path for '${commandName}', spawn may fail`);
65031
65236
  }
65032
65237
  ensureMcpPermissions(this.projectRoot, commandName, debug);
65033
65238
  const isClaudeCli = commandName.startsWith("claude");
65034
- const isCursorCli = commandName === "agent" || rawCommandName === "cursor";
65239
+ const isCursorCli = commandName === "agent" || rawCommandName === "cursor" || rawCommandName === "cursor-agent";
65035
65240
  if (!interactive) {
65036
65241
  if (isClaudeCli && !args.includes("--dangerously-skip-permissions")) {
65037
65242
  args.push("--dangerously-skip-permissions");
@@ -65041,7 +65246,7 @@ var AgentSpawner = class _AgentSpawner {
65041
65246
  }
65042
65247
  } else {
65043
65248
  if (debug)
65044
- log2.debug(`Interactive mode: skipping auto-accept flags for ${name}`);
65249
+ log3.debug(`Interactive mode: skipping auto-accept flags for ${name}`);
65045
65250
  }
65046
65251
  if (isClaudeCli) {
65047
65252
  const agentConfig = findAgentConfig(name, this.projectRoot);
@@ -65051,9 +65256,9 @@ var AgentSpawner = class _AgentSpawner {
65051
65256
  const configuredArgs = buildClaudeArgs(name, args, this.projectRoot);
65052
65257
  args.length = 0;
65053
65258
  args.push(...configuredArgs);
65054
- log2.info(`Agent ${name}: model=${effectiveModel}, cli=${cli}, variant=${cliVariant}`);
65259
+ log3.info(`Agent ${name}: model=${effectiveModel}, cli=${cli}, variant=${cliVariant}`);
65055
65260
  if (debug)
65056
- log2.debug(`Applied agent config for ${name}: ${args.join(" ")}`);
65261
+ log3.debug(`Applied agent config for ${name}: ${args.join(" ")}`);
65057
65262
  }
65058
65263
  const isCodexCli = commandName.startsWith("codex");
65059
65264
  const isGeminiCli = commandName === "gemini";
@@ -65079,12 +65284,12 @@ var AgentSpawner = class _AgentSpawner {
65079
65284
  });
65080
65285
  if (result.success) {
65081
65286
  if (debug)
65082
- log2.debug(`Auto-installed MCP config at ${projectMcpConfigPath}`);
65287
+ log3.debug(`Auto-installed MCP config at ${projectMcpConfigPath}`);
65083
65288
  } else {
65084
- log2.warn(`Failed to auto-install MCP config: ${result.error}`);
65289
+ log3.warn(`Failed to auto-install MCP config: ${result.error}`);
65085
65290
  }
65086
65291
  } catch (err) {
65087
- log2.warn("Failed to auto-install MCP config", {
65292
+ log3.warn("Failed to auto-install MCP config", {
65088
65293
  error: err instanceof Error ? err.message : String(err)
65089
65294
  });
65090
65295
  }
@@ -65099,7 +65304,7 @@ var AgentSpawner = class _AgentSpawner {
65099
65304
  }
65100
65305
  }
65101
65306
  if (debug && hasMcp)
65102
- log2.debug(`MCP tools available for ${name} (MCP config found, socket ${relaySocket})`);
65307
+ log3.debug(`MCP tools available for ${name} (MCP config found, socket ${relaySocket})`);
65103
65308
  let relayInstructions = getRelayInstructions(name, { hasMcp, includeWorkflowConventions });
65104
65309
  const agentConfigForRole = isClaudeCli ? findAgentConfig(name, this.projectRoot) : null;
65105
65310
  if (agentConfigForRole?.role) {
@@ -65115,10 +65320,10 @@ var AgentSpawner = class _AgentSpawner {
65115
65320
 
65116
65321
  ${relayInstructions}`;
65117
65322
  if (debug)
65118
- log2.debug(`Composed role prompt for ${name} (role: ${role})`);
65323
+ log3.debug(`Composed role prompt for ${name} (role: ${role})`);
65119
65324
  }
65120
65325
  } catch (err) {
65121
- log2.warn(`Failed to compose role prompt for ${name}: ${err.message}`);
65326
+ log3.warn(`Failed to compose role prompt for ${name}: ${err.message}`);
65122
65327
  }
65123
65328
  }
65124
65329
  }
@@ -65135,7 +65340,7 @@ ${relayInstructions}`;
65135
65340
  args.unshift("login");
65136
65341
  }
65137
65342
  if (debug)
65138
- log2.debug(`Spawning ${name} with: ${command} ${args.join(" ")}`);
65343
+ log3.debug(`Spawning ${name} with: ${command} ${args.join(" ")}`);
65139
65344
  let agentCwd;
65140
65345
  if (request.cwd && typeof request.cwd === "string") {
65141
65346
  const resolvedCwd = import_node_path17.default.resolve(this.projectRoot, request.cwd);
@@ -65152,14 +65357,14 @@ ${relayInstructions}`;
65152
65357
  } else {
65153
65358
  agentCwd = this.projectRoot;
65154
65359
  }
65155
- log2.info(`Spawning ${name}: dashboardPort=${this.dashboardPort || "none"} (${this.dashboardPort ? "nested spawns enabled" : "nested spawns disabled"})`);
65360
+ log3.info(`Spawning ${name}: dashboardPort=${this.dashboardPort || "none"} (${this.dashboardPort ? "nested spawns enabled" : "nested spawns disabled"})`);
65156
65361
  let userEnv;
65157
65362
  if (userId) {
65158
65363
  try {
65159
65364
  const userDirService = getUserDirectoryService();
65160
65365
  userEnv = userDirService.getUserEnvironment(userId);
65161
65366
  } catch (err) {
65162
- log2.warn("Failed to resolve user environment, using default", {
65367
+ log3.warn("Failed to resolve user environment, using default", {
65163
65368
  userId,
65164
65369
  error: err instanceof Error ? err.message : String(err)
65165
65370
  });
@@ -65176,7 +65381,7 @@ ${relayInstructions}`;
65176
65381
  userEnv = mergedUserEnv;
65177
65382
  }
65178
65383
  if (debug)
65179
- log2.debug(`Socket path for ${name}: ${this.socketPath ?? "undefined"}`);
65384
+ log3.debug(`Socket path for ${name}: ${this.socketPath ?? "undefined"}`);
65180
65385
  if (!hasRelayPtyBinary2()) {
65181
65386
  const checkedPaths = getLastSearchPaths();
65182
65387
  const tracedError = createTraceableError("relay-pty binary not found", {
@@ -65188,10 +65393,10 @@ ${relayInstructions}`;
65188
65393
  totalPathsChecked: checkedPaths.length,
65189
65394
  hint: "Set RELAY_PTY_BINARY env var to override, or reinstall: npm install agent-relay"
65190
65395
  });
65191
- log2.error(tracedError.logMessage);
65396
+ log3.error(tracedError.logMessage);
65192
65397
  if (debug) {
65193
- log2.debug("All paths checked for relay-pty binary:");
65194
- checkedPaths.forEach((p, i) => log2.debug(` ${i + 1}. ${p}`));
65398
+ log3.debug("All paths checked for relay-pty binary:");
65399
+ checkedPaths.forEach((p, i) => log3.debug(` ${i + 1}. ${p}`));
65195
65400
  }
65196
65401
  return {
65197
65402
  success: false,
@@ -65202,7 +65407,7 @@ ${relayInstructions}`;
65202
65407
  }
65203
65408
  const onExitHandler = (code) => {
65204
65409
  if (debug)
65205
- log2.debug(`Worker ${name} exited with code ${code}`);
65410
+ log3.debug(`Worker ${name} exited with code ${code}`);
65206
65411
  const worker = this.activeWorkers.get(name);
65207
65412
  const agentId = worker?.pty?.getAgentId?.();
65208
65413
  if (worker?.listeners) {
@@ -65212,7 +65417,7 @@ ${relayInstructions}`;
65212
65417
  try {
65213
65418
  this.saveWorkersMetadata();
65214
65419
  } catch (err) {
65215
- log2.error("Failed to save metadata on exit", { error: err instanceof Error ? err.message : String(err) });
65420
+ log3.error("Failed to save metadata on exit", { error: err instanceof Error ? err.message : String(err) });
65216
65421
  }
65217
65422
  if (code !== 0 && code !== null && this.onAgentDeath) {
65218
65423
  const crashError = createTraceableError("Agent crashed unexpectedly", {
@@ -65221,7 +65426,7 @@ ${relayInstructions}`;
65221
65426
  cli,
65222
65427
  agentId
65223
65428
  });
65224
- log2.error(crashError.logMessage);
65429
+ log3.error(crashError.logMessage);
65225
65430
  this.onAgentDeath({
65226
65431
  name,
65227
65432
  exitCode: code,
@@ -65233,7 +65438,7 @@ ${relayInstructions}`;
65233
65438
  };
65234
65439
  const onSpawnHandler = this.dashboardPort ? void 0 : async (workerName, workerCli, workerTask) => {
65235
65440
  if (debug)
65236
- log2.debug(`Nested spawn: ${workerName}`);
65441
+ log3.debug(`Nested spawn: ${workerName}`);
65237
65442
  await this.spawn({
65238
65443
  name: workerName,
65239
65444
  cli: workerCli,
@@ -65243,7 +65448,7 @@ ${relayInstructions}`;
65243
65448
  };
65244
65449
  const onReleaseHandler = this.dashboardPort ? void 0 : async (workerName) => {
65245
65450
  if (debug)
65246
- log2.debug(`Release request: ${workerName}`);
65451
+ log3.debug(`Release request: ${workerName}`);
65247
65452
  await this.release(workerName);
65248
65453
  };
65249
65454
  if (isOpenCodeCli) {
@@ -65253,7 +65458,7 @@ ${relayInstructions}`;
65253
65458
  const shouldUseHttpApi = serveAvailable || isCloudWorkspace2;
65254
65459
  if (shouldUseHttpApi) {
65255
65460
  if (debug)
65256
- log2.debug(`OpenCode: serve=${serveAvailable ? "available" : "will-auto-start"}, cloud=${isCloudWorkspace2}, using OpenCodeWrapper for ${name}`);
65461
+ log3.debug(`OpenCode: serve=${serveAvailable ? "available" : "will-auto-start"}, cloud=${isCloudWorkspace2}, using OpenCodeWrapper for ${name}`);
65257
65462
  const openCodeConfig = {
65258
65463
  name,
65259
65464
  command,
@@ -65295,11 +65500,11 @@ ${relayInstructions}`;
65295
65500
  if (this.onMarkSpawning) {
65296
65501
  this.onMarkSpawning(name);
65297
65502
  if (debug)
65298
- log2.debug(`Marked ${name} as spawning`);
65503
+ log3.debug(`Marked ${name} as spawning`);
65299
65504
  }
65300
65505
  await openCodeWrapper.start();
65301
65506
  if (debug)
65302
- log2.debug(`OpenCodeWrapper started for ${name}, HTTP mode: ${openCodeWrapper.isHttpApiMode}`);
65507
+ log3.debug(`OpenCodeWrapper started for ${name}, HTTP mode: ${openCodeWrapper.isHttpApiMode}`);
65303
65508
  const registered2 = await this.waitForAgentRegistration(name, 3e4, 500);
65304
65509
  if (!registered2) {
65305
65510
  const tracedError = createTraceableError("Agent registration timeout", {
@@ -65308,7 +65513,7 @@ ${relayInstructions}`;
65308
65513
  pid: openCodeWrapper.pid,
65309
65514
  timeoutMs: 3e4
65310
65515
  });
65311
- log2.error(tracedError.logMessage);
65516
+ log3.error(tracedError.logMessage);
65312
65517
  if (this.onClearSpawning) {
65313
65518
  this.onClearSpawning(name);
65314
65519
  }
@@ -65322,15 +65527,35 @@ ${relayInstructions}`;
65322
65527
  }
65323
65528
  if (task && task.trim()) {
65324
65529
  const ready = await openCodeWrapper.waitUntilReadyForMessages(2e4, 100);
65530
+ let taskSent = false;
65325
65531
  if (ready) {
65326
- const taskSent = await openCodeWrapper.injectTask(task, spawnerName || "spawner");
65532
+ taskSent = await openCodeWrapper.injectTask(task, spawnerName || "spawner");
65327
65533
  if (!taskSent) {
65328
- log2.warn(`Failed to inject task for ${name} via OpenCodeWrapper`);
65534
+ log3.warn(`Failed to inject task for ${name} via OpenCodeWrapper`);
65329
65535
  } else if (debug) {
65330
- log2.debug(`Task injected to ${name} via OpenCodeWrapper`);
65536
+ log3.debug(`Task injected to ${name} via OpenCodeWrapper`);
65331
65537
  }
65332
65538
  } else {
65333
- log2.warn(`OpenCodeWrapper ${name} not ready for task injection`);
65539
+ log3.warn(`OpenCodeWrapper ${name} not ready for task injection`);
65540
+ }
65541
+ if (!taskSent) {
65542
+ const tracedError = createTraceableError("Task injection failed", {
65543
+ agentName: name,
65544
+ cli,
65545
+ taskLength: task.length,
65546
+ ready
65547
+ });
65548
+ log3.error(`CRITICAL: ${tracedError.logMessage}`);
65549
+ await openCodeWrapper.stop();
65550
+ if (this.onClearSpawning) {
65551
+ this.onClearSpawning(name);
65552
+ }
65553
+ return {
65554
+ success: false,
65555
+ name,
65556
+ error: tracedError.userMessage,
65557
+ errorId: tracedError.errorId
65558
+ };
65334
65559
  }
65335
65560
  }
65336
65561
  const workerInfo2 = {
@@ -65349,7 +65574,7 @@ ${relayInstructions}`;
65349
65574
  this.saveWorkersMetadata();
65350
65575
  const teamInfo2 = team ? ` [team: ${team}]` : "";
65351
65576
  const shadowInfo2 = request.shadowOf ? ` [shadow of: ${request.shadowOf}]` : "";
65352
- log2.info(`Spawned ${name} (${cli}) via OpenCodeWrapper${teamInfo2}${shadowInfo2} [HTTP mode: ${openCodeWrapper.isHttpApiMode}]`);
65577
+ log3.info(`Spawned ${name} (${cli}) via OpenCodeWrapper${teamInfo2}${shadowInfo2} [HTTP mode: ${openCodeWrapper.isHttpApiMode}]`);
65353
65578
  return {
65354
65579
  success: true,
65355
65580
  name,
@@ -65357,7 +65582,7 @@ ${relayInstructions}`;
65357
65582
  };
65358
65583
  }
65359
65584
  if (debug)
65360
- log2.debug(`OpenCode: serve not available, not cloud workspace, falling back to RelayPtyOrchestrator for ${name}`);
65585
+ log3.debug(`OpenCode: serve not available, not cloud workspace, falling back to RelayPtyOrchestrator for ${name}`);
65361
65586
  }
65362
65587
  const ptyConfig = {
65363
65588
  name,
@@ -65391,7 +65616,7 @@ ${relayInstructions}`;
65391
65616
  };
65392
65617
  const pty = new RelayPtyOrchestrator(ptyConfig);
65393
65618
  if (debug)
65394
- log2.debug(`Using RelayPtyOrchestrator for ${name}`);
65619
+ log3.debug(`Using RelayPtyOrchestrator for ${name}`);
65395
65620
  const listeners = {};
65396
65621
  const outputListener = (data) => {
65397
65622
  const broadcast = global.__broadcastLogOutput;
@@ -65409,19 +65634,19 @@ ${relayInstructions}`;
65409
65634
  if (this.onMarkSpawning) {
65410
65635
  this.onMarkSpawning(name);
65411
65636
  if (debug)
65412
- log2.debug(`Marked ${name} as spawning`);
65637
+ log3.debug(`Marked ${name} as spawning`);
65413
65638
  }
65414
65639
  await pty.start();
65415
65640
  if (debug)
65416
- log2.debug(`PTY started, pid: ${pty.pid}`);
65641
+ log3.debug(`PTY started, pid: ${pty.pid}`);
65417
65642
  if (isCursorCli && interactive) {
65418
65643
  await sleep2(1500);
65419
65644
  if (debug)
65420
- log2.debug(`Sending initial keystroke for Cursor setup to bypass "Press any key" prompt`);
65645
+ log3.debug(`Sending initial keystroke for Cursor setup to bypass "Press any key" prompt`);
65421
65646
  try {
65422
65647
  await pty.write("\r");
65423
65648
  } catch (err) {
65424
- log2.warn(`Failed to send initial keystroke for Cursor: ${err}`);
65649
+ log3.warn(`Failed to send initial keystroke for Cursor: ${err}`);
65425
65650
  }
65426
65651
  }
65427
65652
  const registered = await this.waitForAgentRegistration(name, 3e4, 500);
@@ -65432,7 +65657,7 @@ ${relayInstructions}`;
65432
65657
  pid: pty.pid,
65433
65658
  timeoutMs: 3e4
65434
65659
  });
65435
- log2.error(tracedError.logMessage);
65660
+ log3.error(tracedError.logMessage);
65436
65661
  if (this.onClearSpawning) {
65437
65662
  this.onClearSpawning(name);
65438
65663
  }
@@ -65454,12 +65679,12 @@ ${relayInstructions}`;
65454
65679
  const orchestrator = pty;
65455
65680
  const ready = await orchestrator.waitUntilReadyForMessages(2e4, 100);
65456
65681
  if (!ready) {
65457
- log2.debug(`Attempt ${attempt}/${maxRetries}: ${name} not ready for messages within timeout`);
65682
+ log3.debug(`Attempt ${attempt}/${maxRetries}: ${name} not ready for messages within timeout`);
65458
65683
  if (attempt < maxRetries) {
65459
65684
  await sleep2(retryDelayMs);
65460
65685
  continue;
65461
65686
  }
65462
- log2.error(`${name} failed to become ready after ${maxRetries} attempts - task may be lost`);
65687
+ log3.error(`${name} failed to become ready after ${maxRetries} attempts - task may be lost`);
65463
65688
  break;
65464
65689
  }
65465
65690
  } else if ("waitUntilCliReady" in pty) {
@@ -65469,13 +65694,13 @@ ${relayInstructions}`;
65469
65694
  if (success) {
65470
65695
  taskSent = true;
65471
65696
  if (debug)
65472
- log2.debug(`Task injected to ${name} (attempt ${attempt})`);
65697
+ log3.debug(`Task injected to ${name} (attempt ${attempt})`);
65473
65698
  break;
65474
65699
  } else {
65475
- throw new Error("Task injection returned false");
65700
+ throw new Error("Task injection returned false - delivery failed");
65476
65701
  }
65477
65702
  } catch (err) {
65478
- log2.debug(`Attempt ${attempt}/${maxRetries}: Error injecting task for ${name}: ${err.message}`);
65703
+ log3.debug(`Attempt ${attempt}/${maxRetries}: Error injecting task for ${name}: ${err.message}`);
65479
65704
  if (attempt < maxRetries) {
65480
65705
  await sleep2(retryDelayMs);
65481
65706
  }
@@ -65488,7 +65713,18 @@ ${relayInstructions}`;
65488
65713
  attempts: maxRetries,
65489
65714
  taskLength: task.length
65490
65715
  });
65491
- log2.error(`CRITICAL: ${tracedError.logMessage}`);
65716
+ log3.error(`CRITICAL: ${tracedError.logMessage}`);
65717
+ await pty.stop();
65718
+ this.activeWorkers.delete(name);
65719
+ if (this.onClearSpawning) {
65720
+ this.onClearSpawning(name);
65721
+ }
65722
+ return {
65723
+ success: false,
65724
+ name,
65725
+ error: tracedError.userMessage,
65726
+ errorId: tracedError.errorId
65727
+ };
65492
65728
  }
65493
65729
  }
65494
65730
  const workerInfo = {
@@ -65508,7 +65744,7 @@ ${relayInstructions}`;
65508
65744
  this.saveWorkersMetadata();
65509
65745
  const teamInfo = team ? ` [team: ${team}]` : "";
65510
65746
  const shadowInfo = request.shadowOf ? ` [shadow of: ${request.shadowOf}]` : "";
65511
- log2.info(`Spawned ${name} (${cli})${teamInfo}${shadowInfo} [pid: ${pty.pid}]`);
65747
+ log3.info(`Spawned ${name} (${cli})${teamInfo}${shadowInfo} [pid: ${pty.pid}]`);
65512
65748
  return {
65513
65749
  success: true,
65514
65750
  name,
@@ -65520,9 +65756,9 @@ ${relayInstructions}`;
65520
65756
  cli,
65521
65757
  task: task?.substring(0, 100)
65522
65758
  }, err instanceof Error ? err : void 0);
65523
- log2.error(tracedError.logMessage);
65759
+ log3.error(tracedError.logMessage);
65524
65760
  if (debug)
65525
- log2.debug("Full error", { error: err?.stack || String(err) });
65761
+ log3.debug("Full error", { error: err?.stack || String(err) });
65526
65762
  if (this.onClearSpawning) {
65527
65763
  this.onClearSpawning(name);
65528
65764
  }
@@ -65569,12 +65805,12 @@ ${relayInstructions}`;
65569
65805
  preferredShadowCli: shadow.command
65570
65806
  });
65571
65807
  } catch (err) {
65572
- log2.warn(`Shadow CLI selection failed for ${shadow.name}: ${err.message}`);
65808
+ log3.warn(`Shadow CLI selection failed for ${shadow.name}: ${err.message}`);
65573
65809
  }
65574
65810
  if (debug) {
65575
65811
  const mode = shadowSelection?.mode ?? "unknown";
65576
65812
  const cli = shadowSelection?.command ?? shadow.command ?? primary.command ?? "claude";
65577
- log2.debug(`spawnWithShadow: primary=${primary.name}, shadow=${shadow.name}, mode=${mode}, cli=${cli}, speakOn=${speakOn.join(",")}`);
65813
+ log3.debug(`spawnWithShadow: primary=${primary.name}, shadow=${shadow.name}, mode=${mode}, cli=${cli}, speakOn=${speakOn.join(",")}`);
65578
65814
  }
65579
65815
  const primaryResult = await this.spawn({
65580
65816
  name: primary.name,
@@ -65591,7 +65827,7 @@ ${relayInstructions}`;
65591
65827
  }
65592
65828
  await sleep2(1e3);
65593
65829
  if (shadowSelection?.mode === "subagent") {
65594
- log2.info(`Shadow ${shadow.name} will run as ${shadowSelection.cli} subagent inside ${primary.name} (no separate process)`);
65830
+ log3.info(`Shadow ${shadow.name} will run as ${shadowSelection.cli} subagent inside ${primary.name} (no separate process)`);
65595
65831
  return {
65596
65832
  success: true,
65597
65833
  primary: primaryResult,
@@ -65602,7 +65838,7 @@ ${relayInstructions}`;
65602
65838
  };
65603
65839
  }
65604
65840
  if (!shadowSelection) {
65605
- log2.warn(`No authenticated shadow CLI available; ${primary.name} will run without a shadow`);
65841
+ log3.warn(`No authenticated shadow CLI available; ${primary.name} will run without a shadow`);
65606
65842
  return {
65607
65843
  success: true,
65608
65844
  primary: primaryResult,
@@ -65618,7 +65854,7 @@ ${relayInstructions}`;
65618
65854
  shadowSpeakOn: speakOn
65619
65855
  });
65620
65856
  if (!shadowResult.success) {
65621
- log2.warn(`Shadow agent ${shadow.name} failed to spawn, primary ${primary.name} continues without shadow`);
65857
+ log3.warn(`Shadow agent ${shadow.name} failed to spawn, primary ${primary.name} continues without shadow`);
65622
65858
  return {
65623
65859
  success: true,
65624
65860
  // Primary succeeded, overall operation is partial success
@@ -65627,7 +65863,7 @@ ${relayInstructions}`;
65627
65863
  error: `Shadow spawn failed: ${shadowResult.error}`
65628
65864
  };
65629
65865
  }
65630
- log2.info(`Spawned pair: ${primary.name} with shadow ${shadow.name} (speakOn: ${speakOn.join(",")})`);
65866
+ log3.info(`Spawned pair: ${primary.name} with shadow ${shadow.name} (speakOn: ${speakOn.join(",")})`);
65631
65867
  return {
65632
65868
  success: true,
65633
65869
  primary: primaryResult,
@@ -65640,7 +65876,7 @@ ${relayInstructions}`;
65640
65876
  async release(name) {
65641
65877
  const worker = this.activeWorkers.get(name);
65642
65878
  if (!worker) {
65643
- log2.debug(`Worker ${name} not found`);
65879
+ log3.debug(`Worker ${name} not found`);
65644
65880
  return false;
65645
65881
  }
65646
65882
  try {
@@ -65651,10 +65887,10 @@ ${relayInstructions}`;
65651
65887
  }
65652
65888
  this.activeWorkers.delete(name);
65653
65889
  this.saveWorkersMetadata();
65654
- log2.info(`Released ${name}`);
65890
+ log3.info(`Released ${name}`);
65655
65891
  return true;
65656
65892
  } catch (err) {
65657
- log2.error(`Failed to release ${name}: ${err.message}`);
65893
+ log3.error(`Failed to release ${name}: ${err.message}`);
65658
65894
  this.unbindListeners(worker.pty, worker.listeners);
65659
65895
  this.activeWorkers.delete(name);
65660
65896
  this.saveWorkersMetadata();
@@ -65747,15 +65983,15 @@ ${relayInstructions}`;
65747
65983
  const connected = this.isAgentConnected(name);
65748
65984
  const recentlySeen = this.isAgentRecentlySeen(name);
65749
65985
  if (pollCount <= 3 || pollCount % 10 === 0) {
65750
- log2.info(`Registration poll #${pollCount} for ${name}: connected=${connected} recentlySeen=${recentlySeen} agentsPath=${this.agentsPath}`);
65986
+ log3.info(`Registration poll #${pollCount} for ${name}: connected=${connected} recentlySeen=${recentlySeen} agentsPath=${this.agentsPath}`);
65751
65987
  }
65752
65988
  if (connected && recentlySeen) {
65753
- log2.info(`Agent ${name} registered after ${pollCount} polls`);
65989
+ log3.info(`Agent ${name} registered after ${pollCount} polls`);
65754
65990
  return true;
65755
65991
  }
65756
65992
  await sleep2(pollIntervalMs);
65757
65993
  }
65758
- log2.info(`Registration timeout for ${name} after ${pollCount} polls`);
65994
+ log3.info(`Registration timeout for ${name} after ${pollCount} polls`);
65759
65995
  return false;
65760
65996
  }
65761
65997
  isAgentRegistered(name) {
@@ -65765,12 +66001,12 @@ ${relayInstructions}`;
65765
66001
  const debug = process.env.DEBUG_SPAWN === "1";
65766
66002
  if (!this.agentsPath) {
65767
66003
  if (debug)
65768
- log2.debug(`isAgentConnected(${name}): no agentsPath`);
66004
+ log3.debug(`isAgentConnected(${name}): no agentsPath`);
65769
66005
  return false;
65770
66006
  }
65771
66007
  if (!import_node_fs14.default.existsSync(this.agentsPath)) {
65772
66008
  if (debug)
65773
- log2.debug(`isAgentConnected(${name}): file not found: ${this.agentsPath}`);
66009
+ log3.debug(`isAgentConnected(${name}): file not found: ${this.agentsPath}`);
65774
66010
  return false;
65775
66011
  }
65776
66012
  try {
@@ -65779,14 +66015,14 @@ ${relayInstructions}`;
65779
66015
  const updatedAt = typeof raw?.updatedAt === "number" ? raw.updatedAt : 0;
65780
66016
  const isFresh = Date.now() - updatedAt <= _AgentSpawner.ONLINE_THRESHOLD_MS;
65781
66017
  if (debug) {
65782
- log2.debug(`isAgentConnected(${name}): path=${this.agentsPath} agents=${agents.join(",")} updatedAt=${updatedAt} isFresh=${isFresh}`);
66018
+ log3.debug(`isAgentConnected(${name}): path=${this.agentsPath} agents=${agents.join(",")} updatedAt=${updatedAt} isFresh=${isFresh}`);
65783
66019
  }
65784
66020
  if (!isFresh)
65785
66021
  return false;
65786
66022
  const lowerName = name.toLowerCase();
65787
66023
  return agents.some((a) => typeof a === "string" && a.toLowerCase() === lowerName);
65788
66024
  } catch (err) {
65789
- log2.error("Failed to read connected-agents.json", { error: err.message, path: this.agentsPath });
66025
+ log3.error("Failed to read connected-agents.json", { error: err.message, path: this.agentsPath });
65790
66026
  return false;
65791
66027
  }
65792
66028
  }
@@ -65804,7 +66040,7 @@ ${relayInstructions}`;
65804
66040
  return false;
65805
66041
  return Date.now() - new Date(agent.lastSeen).getTime() <= _AgentSpawner.ONLINE_THRESHOLD_MS;
65806
66042
  } catch (err) {
65807
- log2.error("Failed to read agents.json", { error: err.message });
66043
+ log3.error("Failed to read agents.json", { error: err.message });
65808
66044
  return false;
65809
66045
  }
65810
66046
  }
@@ -65825,7 +66061,7 @@ ${relayInstructions}`;
65825
66061
  }));
65826
66062
  import_node_fs14.default.writeFileSync(this.workersPath, JSON.stringify({ workers }, null, 2));
65827
66063
  } catch (err) {
65828
- log2.error("Failed to save workers metadata", { error: err.message });
66064
+ log3.error("Failed to save workers metadata", { error: err.message });
65829
66065
  }
65830
66066
  }
65831
66067
  /**
@@ -70262,7 +70498,7 @@ async function createStorageAdapter(dbPath, config2) {
70262
70498
  var import_node_fs21 = __toESM(require("node:fs"), 1);
70263
70499
  var import_node_path24 = __toESM(require("node:path"), 1);
70264
70500
  init_logger();
70265
- var log3 = createLogger2("registry");
70501
+ var log4 = createLogger2("registry");
70266
70502
  var AgentRegistry = class {
70267
70503
  registryPath;
70268
70504
  agents = /* @__PURE__ */ new Map();
@@ -70385,7 +70621,7 @@ var AgentRegistry = class {
70385
70621
  if (lastSeenTime < cutoff) {
70386
70622
  this.agents.delete(name);
70387
70623
  removed++;
70388
- log3.info("Pruned stale agent", { name, lastSeen: record2.lastSeen });
70624
+ log4.info("Pruned stale agent", { name, lastSeen: record2.lastSeen });
70389
70625
  }
70390
70626
  }
70391
70627
  if (removed > 0) {
@@ -70442,7 +70678,7 @@ var AgentRegistry = class {
70442
70678
  this.agents.set(record2.name, record2);
70443
70679
  }
70444
70680
  } catch (err) {
70445
- log3.error("Failed to load agents.json", { error: String(err) });
70681
+ log4.error("Failed to load agents.json", { error: String(err) });
70446
70682
  }
70447
70683
  }
70448
70684
  save() {
@@ -70452,7 +70688,7 @@ var AgentRegistry = class {
70452
70688
  import_node_fs21.default.writeFileSync(tempPath, data, "utf-8");
70453
70689
  import_node_fs21.default.renameSync(tempPath, this.registryPath);
70454
70690
  } catch (err) {
70455
- log3.error("Failed to write agents.json", { error: String(err) });
70691
+ log4.error("Failed to write agents.json", { error: String(err) });
70456
70692
  }
70457
70693
  }
70458
70694
  };
@@ -70476,7 +70712,7 @@ var import_node_zlib = require("node:zlib");
70476
70712
  var import_node_util5 = require("node:util");
70477
70713
  init_logger();
70478
70714
  var gzipAsync = (0, import_node_util5.promisify)(import_node_zlib.gzip);
70479
- var log4 = createLogger2("sync-queue");
70715
+ var log5 = createLogger2("sync-queue");
70480
70716
  var DEFAULT_SYNC_QUEUE_CONFIG = {
70481
70717
  cloudUrl: "https://agent-relay.com",
70482
70718
  apiKey: "",
@@ -70532,7 +70768,7 @@ var SyncQueue = class {
70532
70768
  } else if (!this.flushTimer) {
70533
70769
  this.flushTimer = setTimeout(() => {
70534
70770
  this.flush().catch((err) => {
70535
- log4.error("Timer flush failed", { error: String(err) });
70771
+ log5.error("Timer flush failed", { error: String(err) });
70536
70772
  });
70537
70773
  }, this.config.batchDelayMs);
70538
70774
  }
@@ -70594,7 +70830,7 @@ var SyncQueue = class {
70594
70830
  if (attempt < this.config.maxRetries - 1) {
70595
70831
  const delay = this.config.retryDelayMs * Math.pow(2, attempt);
70596
70832
  if (this.config.verbose) {
70597
- log4.warn(`Sync attempt ${attempt + 1} failed, retrying in ${delay}ms`, {
70833
+ log5.warn(`Sync attempt ${attempt + 1} failed, retrying in ${delay}ms`, {
70598
70834
  error: lastError.message
70599
70835
  });
70600
70836
  }
@@ -70602,7 +70838,7 @@ var SyncQueue = class {
70602
70838
  }
70603
70839
  }
70604
70840
  }
70605
- log4.error("Sync failed after retries, spilling to disk", {
70841
+ log5.error("Sync failed after retries, spilling to disk", {
70606
70842
  count: messages.length,
70607
70843
  error: lastError?.message
70608
70844
  });
@@ -70646,7 +70882,7 @@ var SyncQueue = class {
70646
70882
  contentEncoding = "gzip";
70647
70883
  if (this.config.verbose) {
70648
70884
  const ratio = ((1 - body.length / payloadBytes) * 100).toFixed(1);
70649
- log4.info(`Compressed ${payloadBytes} \u2192 ${body.length} bytes (${ratio}% reduction)`);
70885
+ log5.info(`Compressed ${payloadBytes} \u2192 ${body.length} bytes (${ratio}% reduction)`);
70650
70886
  }
70651
70887
  } else {
70652
70888
  body = payloadJson;
@@ -70687,11 +70923,11 @@ var SyncQueue = class {
70687
70923
  await fs25.writeFile(filepath, JSON.stringify(messages));
70688
70924
  this.stats.spilledFiles++;
70689
70925
  if (this.config.verbose) {
70690
- log4.info(`Spilled ${messages.length} messages to ${filename}`);
70926
+ log5.info(`Spilled ${messages.length} messages to ${filename}`);
70691
70927
  }
70692
70928
  await this.cleanupSpillFiles();
70693
70929
  } catch (err) {
70694
- log4.error("Failed to spill to disk", { error: String(err) });
70930
+ log5.error("Failed to spill to disk", { error: String(err) });
70695
70931
  }
70696
70932
  }
70697
70933
  /**
@@ -70715,23 +70951,23 @@ var SyncQueue = class {
70715
70951
  recovered += messages.length;
70716
70952
  this.stats.spilledFiles = Math.max(0, this.stats.spilledFiles - 1);
70717
70953
  if (this.config.verbose) {
70718
- log4.info(`Recovered ${messages.length} messages from ${file}`);
70954
+ log5.info(`Recovered ${messages.length} messages from ${file}`);
70719
70955
  }
70720
70956
  } else {
70721
70957
  failed += messages.length;
70722
70958
  }
70723
70959
  } catch (err) {
70724
- log4.warn(`Failed to recover ${file}`, { error: String(err) });
70960
+ log5.warn(`Failed to recover ${file}`, { error: String(err) });
70725
70961
  failed++;
70726
70962
  }
70727
70963
  }
70728
70964
  } catch (err) {
70729
70965
  if (err.code !== "ENOENT") {
70730
- log4.error("Failed to scan spill directory", { error: String(err) });
70966
+ log5.error("Failed to scan spill directory", { error: String(err) });
70731
70967
  }
70732
70968
  }
70733
70969
  if (recovered > 0) {
70734
- log4.info(`Recovered ${recovered} messages from spill files`);
70970
+ log5.info(`Recovered ${recovered} messages from spill files`);
70735
70971
  }
70736
70972
  return { recovered, failed };
70737
70973
  }
@@ -70749,7 +70985,7 @@ var SyncQueue = class {
70749
70985
  });
70750
70986
  }
70751
70987
  if (this.config.verbose) {
70752
- log4.info(`Cleaned up ${toDelete.length} old spill files`);
70988
+ log5.info(`Cleaned up ${toDelete.length} old spill files`);
70753
70989
  }
70754
70990
  }
70755
70991
  } catch {
@@ -70799,7 +71035,7 @@ var SyncQueue = class {
70799
71035
  // packages/utils/dist/git-remote.js
70800
71036
  var fs26 = __toESM(require("node:fs"), 1);
70801
71037
  var path27 = __toESM(require("node:path"), 1);
70802
- var import_node_child_process12 = require("node:child_process");
71038
+ var import_node_child_process13 = require("node:child_process");
70803
71039
  function parseGitRemoteUrl(url) {
70804
71040
  if (!url)
70805
71041
  return null;
@@ -70819,7 +71055,7 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
70819
71055
  if (!fs26.existsSync(gitDir)) {
70820
71056
  return null;
70821
71057
  }
70822
- const result = (0, import_node_child_process12.execSync)(`git remote get-url ${remoteName}`, {
71058
+ const result = (0, import_node_child_process13.execSync)(`git remote get-url ${remoteName}`, {
70823
71059
  cwd: workingDirectory,
70824
71060
  encoding: "utf-8",
70825
71061
  timeout: 5e3,
@@ -70872,7 +71108,7 @@ function getRepoFullNameFromPath(workingDirectory) {
70872
71108
  }
70873
71109
 
70874
71110
  // packages/daemon/dist/cloud-sync.js
70875
- var log5 = createLogger2("cloud-sync");
71111
+ var log6 = createLogger2("cloud-sync");
70876
71112
  var CloudSyncService = class extends import_events7.EventEmitter {
70877
71113
  config;
70878
71114
  heartbeatTimer;
@@ -70907,7 +71143,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
70907
71143
  this.projectDirectory = this.config.projectDirectory || process.cwd();
70908
71144
  this.repoFullName = getRepoFullNameFromPath(this.projectDirectory);
70909
71145
  if (this.repoFullName) {
70910
- log5.info("Detected git repository", { repoFullName: this.repoFullName });
71146
+ log6.info("Detected git repository", { repoFullName: this.repoFullName });
70911
71147
  }
70912
71148
  if (this.config.useOptimizedSync && this.config.apiKey) {
70913
71149
  this.syncQueue = new SyncQueue({
@@ -70940,19 +71176,19 @@ var CloudSyncService = class extends import_events7.EventEmitter {
70940
71176
  */
70941
71177
  async start() {
70942
71178
  if (!this.config.enabled || !this.config.apiKey) {
70943
- log5.info("Disabled (no API key configured)");
70944
- log5.info("Run `agent-relay cloud link` to connect to cloud");
71179
+ log6.info("Disabled (no API key configured)");
71180
+ log6.info("Run `agent-relay cloud link` to connect to cloud");
70945
71181
  return;
70946
71182
  }
70947
- log5.info("Starting cloud sync", { url: this.config.cloudUrl });
71183
+ log6.info("Starting cloud sync", { url: this.config.cloudUrl });
70948
71184
  if (this.syncQueue) {
70949
71185
  const { recovered, failed } = await this.syncQueue.recoverSpilledMessages();
70950
71186
  if (recovered > 0 || failed > 0) {
70951
- log5.info("Recovered spilled messages", { recovered, failed });
71187
+ log6.info("Recovered spilled messages", { recovered, failed });
70952
71188
  }
70953
71189
  }
70954
71190
  await this.sendHeartbeat();
70955
- this.heartbeatTimer = setInterval(() => this.sendHeartbeat().catch((err) => log5.error("Heartbeat failed", { error: String(err) })), this.config.heartbeatInterval);
71191
+ this.heartbeatTimer = setInterval(() => this.sendHeartbeat().catch((err) => log6.error("Heartbeat failed", { error: String(err) })), this.config.heartbeatInterval);
70956
71192
  this.connected = true;
70957
71193
  this.emit("connected");
70958
71194
  }
@@ -70979,7 +71215,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
70979
71215
  this.localAgents.set(agent.name, agent);
70980
71216
  }
70981
71217
  if (this.connected) {
70982
- this.syncAgents().catch((err) => log5.error("Agent sync failed", { error: String(err) }));
71218
+ this.syncAgents().catch((err) => log6.error("Agent sync failed", { error: String(err) }));
70983
71219
  }
70984
71220
  }
70985
71221
  /**
@@ -71046,7 +71282,7 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71046
71282
  }).finally(() => clearTimeout(timeoutId));
71047
71283
  if (!response.ok) {
71048
71284
  if (response.status === 401) {
71049
- log5.error("Invalid API key. Run `agent-relay cloud link` to re-authenticate.");
71285
+ log6.error("Invalid API key. Run `agent-relay cloud link` to re-authenticate.");
71050
71286
  this.stop();
71051
71287
  return;
71052
71288
  }
@@ -71067,18 +71303,18 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71067
71303
  } catch (error2) {
71068
71304
  const errorMessage = String(error2);
71069
71305
  if (error2 instanceof Error && error2.name === "AbortError") {
71070
- log5.error("Heartbeat timeout (10s)", { url: this.config.cloudUrl });
71306
+ log6.error("Heartbeat timeout (10s)", { url: this.config.cloudUrl });
71071
71307
  } else if (errorMessage.includes("fetch failed") || errorMessage.includes("ECONNREFUSED")) {
71072
- log5.error("Heartbeat network error - cloud server unreachable", {
71308
+ log6.error("Heartbeat network error - cloud server unreachable", {
71073
71309
  url: this.config.cloudUrl,
71074
71310
  error: errorMessage
71075
71311
  });
71076
71312
  } else if (errorMessage.includes("ENOTFOUND") || errorMessage.includes("getaddrinfo")) {
71077
- log5.error("Heartbeat DNS error - cannot resolve cloud server", {
71313
+ log6.error("Heartbeat DNS error - cannot resolve cloud server", {
71078
71314
  url: this.config.cloudUrl
71079
71315
  });
71080
71316
  } else {
71081
- log5.error("Heartbeat error", { error: errorMessage });
71317
+ log6.error("Heartbeat error", { error: errorMessage });
71082
71318
  }
71083
71319
  this.emit("error", error2);
71084
71320
  }
@@ -71168,14 +71404,14 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71168
71404
  */
71169
71405
  setStorage(storage) {
71170
71406
  this.storage = storage;
71171
- log5.info("Storage adapter configured for message sync");
71407
+ log6.info("Storage adapter configured for message sync");
71172
71408
  }
71173
71409
  /**
71174
71410
  * Set the metrics provider for agent metrics sync
71175
71411
  */
71176
71412
  setMetricsProvider(provider) {
71177
71413
  this.metricsProvider = provider;
71178
- log5.info("Metrics provider configured for agent metrics sync");
71414
+ log6.info("Metrics provider configured for agent metrics sync");
71179
71415
  }
71180
71416
  /**
71181
71417
  * Push agent metrics to cloud monitoring API.
@@ -71222,11 +71458,11 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71222
71458
  }
71223
71459
  const result = await response.json();
71224
71460
  if (result.recorded > 0) {
71225
- log5.info(`Pushed ${result.recorded} agent metrics to cloud`);
71461
+ log6.info(`Pushed ${result.recorded} agent metrics to cloud`);
71226
71462
  }
71227
71463
  return { recorded: result.recorded };
71228
71464
  } catch (error2) {
71229
- log5.error("Failed to push agent metrics", { error: String(error2) });
71465
+ log6.error("Failed to push agent metrics", { error: String(error2) });
71230
71466
  return null;
71231
71467
  }
71232
71468
  }
@@ -71257,10 +71493,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71257
71493
  throw new Error(`Session create failed: ${response.status}`);
71258
71494
  }
71259
71495
  const result = await response.json();
71260
- log5.info(`Created session ${result.sessionId.substring(0, 8)} for ${agentName}`);
71496
+ log6.info(`Created session ${result.sessionId.substring(0, 8)} for ${agentName}`);
71261
71497
  return result.sessionId;
71262
71498
  } catch (error2) {
71263
- log5.error("Failed to create session", { agentName, error: String(error2) });
71499
+ log6.error("Failed to create session", { agentName, error: String(error2) });
71264
71500
  return null;
71265
71501
  }
71266
71502
  }
@@ -71288,10 +71524,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71288
71524
  throw new Error(`Summary add failed: ${response.status}`);
71289
71525
  }
71290
71526
  const result = await response.json();
71291
- log5.info(`Added summary for ${agentName}: ${summary.currentTask || "no task"}`);
71527
+ log6.info(`Added summary for ${agentName}: ${summary.currentTask || "no task"}`);
71292
71528
  return result.summaryId;
71293
71529
  } catch (error2) {
71294
- log5.error("Failed to add summary", { sessionId, agentName, error: String(error2) });
71530
+ log6.error("Failed to add summary", { sessionId, agentName, error: String(error2) });
71295
71531
  return null;
71296
71532
  }
71297
71533
  }
@@ -71317,10 +71553,10 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71317
71553
  if (!response.ok) {
71318
71554
  throw new Error(`Session end failed: ${response.status}`);
71319
71555
  }
71320
- log5.info(`Ended session ${sessionId.substring(0, 8)}: ${endMarker?.summary || "no summary"}`);
71556
+ log6.info(`Ended session ${sessionId.substring(0, 8)}: ${endMarker?.summary || "no summary"}`);
71321
71557
  return true;
71322
71558
  } catch (error2) {
71323
- log5.error("Failed to end session", { sessionId, error: String(error2) });
71559
+ log6.error("Failed to end session", { sessionId, error: String(error2) });
71324
71560
  return false;
71325
71561
  }
71326
71562
  }
@@ -71409,11 +71645,11 @@ var CloudSyncService = class extends import_events7.EventEmitter {
71409
71645
  this.lastMessageSyncTs = Math.max(...messages.map((m) => m.ts));
71410
71646
  }
71411
71647
  if (result.synced > 0) {
71412
- log5.info(`Synced ${result.synced} messages to cloud`, { duplicates: result.duplicates });
71648
+ log6.info(`Synced ${result.synced} messages to cloud`, { duplicates: result.duplicates });
71413
71649
  }
71414
71650
  return result;
71415
71651
  } catch (error2) {
71416
- log5.error("Message sync error", { error: String(error2) });
71652
+ log6.error("Message sync error", { error: String(error2) });
71417
71653
  return { synced: 0, duplicates: 0 };
71418
71654
  } finally {
71419
71655
  this.messageSyncInProgress = false;
@@ -71438,7 +71674,7 @@ function createCloudPersistenceHandler(cloudSync, workspaceId) {
71438
71674
  sessionId = newSessionId;
71439
71675
  agentSessions.set(agentName, sessionId);
71440
71676
  } else {
71441
- log5.warn(`Failed to create session for ${agentName}, skipping summary`);
71677
+ log6.warn(`Failed to create session for ${agentName}, skipping summary`);
71442
71678
  return;
71443
71679
  }
71444
71680
  }
@@ -71450,7 +71686,7 @@ function createCloudPersistenceHandler(cloudSync, workspaceId) {
71450
71686
  await cloudSync.endSession(sessionId, event.marker);
71451
71687
  agentSessions.delete(agentName);
71452
71688
  } else {
71453
- log5.warn(`No session found for ${agentName} on session-end`);
71689
+ log6.warn(`No session found for ${agentName} on session-end`);
71454
71690
  }
71455
71691
  },
71456
71692
  destroy() {
@@ -74347,15 +74583,15 @@ var Orchestrator = class extends import_events8.EventEmitter {
74347
74583
  */
74348
74584
  getGitInfo(workspacePath) {
74349
74585
  try {
74350
- const { execSync: execSync9 } = require("child_process");
74351
- const branch = execSync9("git branch --show-current", {
74586
+ const { execSync: execSync10 } = require("child_process");
74587
+ const branch = execSync10("git branch --show-current", {
74352
74588
  cwd: workspacePath,
74353
74589
  encoding: "utf8",
74354
74590
  stdio: ["pipe", "pipe", "pipe"]
74355
74591
  }).trim();
74356
74592
  let remote;
74357
74593
  try {
74358
- remote = execSync9("git remote get-url origin", {
74594
+ remote = execSync10("git remote get-url origin", {
74359
74595
  cwd: workspacePath,
74360
74596
  encoding: "utf8",
74361
74597
  stdio: ["pipe", "pipe", "pipe"]
@@ -76839,7 +77075,7 @@ function manageContext(compactor, messages) {
76839
77075
  }
76840
77076
 
76841
77077
  // packages/daemon/dist/cli-auth.js
76842
- var import_node_child_process13 = require("node:child_process");
77078
+ var import_node_child_process14 = require("node:child_process");
76843
77079
  var fs33 = __toESM(require("fs/promises"), 1);
76844
77080
  var os15 = __toESM(require("os"), 1);
76845
77081
  var import_node_path27 = require("node:path");
@@ -76956,7 +77192,7 @@ async function startCLIAuth(provider, options = {}) {
76956
77192
  config2.command,
76957
77193
  ...args
76958
77194
  ];
76959
- const proc = (0, import_node_child_process13.spawn)(relayPtyPath, relayArgs, {
77195
+ const proc = (0, import_node_child_process14.spawn)(relayPtyPath, relayArgs, {
76960
77196
  cwd: process.cwd(),
76961
77197
  env: {
76962
77198
  ...process.env,
@@ -78198,11 +78434,11 @@ var HookRegistry = class {
78198
78434
  };
78199
78435
 
78200
78436
  // packages/trajectory/dist/integration.js
78201
- var import_node_child_process14 = require("node:child_process");
78437
+ var import_node_child_process15 = require("node:child_process");
78202
78438
  async function runTrail2(args) {
78203
78439
  return new Promise((resolve5) => {
78204
78440
  const trajectoryEnv = getTrajectoryEnvVars();
78205
- const proc = (0, import_node_child_process14.spawn)("trail", args, {
78441
+ const proc = (0, import_node_child_process15.spawn)("trail", args, {
78206
78442
  cwd: getProjectPaths().projectRoot,
78207
78443
  env: { ...process.env, ...trajectoryEnv },
78208
78444
  stdio: ["pipe", "pipe", "pipe"]
@@ -78473,7 +78709,7 @@ var TrajectoryIntegration2 = class {
78473
78709
  */
78474
78710
  isTrailInstalledSync() {
78475
78711
  try {
78476
- (0, import_node_child_process14.execSync)("which trail", { stdio: "pipe" });
78712
+ (0, import_node_child_process15.execSync)("which trail", { stdio: "pipe" });
78477
78713
  return true;
78478
78714
  } catch {
78479
78715
  return false;