agent-relay 2.0.18 → 2.0.20

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 (165) 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-x64 +0 -0
  4. package/dist/dashboard/out/404.html +1 -1
  5. package/dist/dashboard/out/_next/static/chunks/320-a6304232cd0ee2ce.js +1 -0
  6. package/dist/dashboard/out/_next/static/chunks/631-16b905e5920f9b59.js +1 -0
  7. package/dist/dashboard/out/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +1 -0
  8. package/dist/dashboard/out/_next/static/css/{45361ce86b2847c4.css → 6892f8422896ef7a.css} +1 -1
  9. package/dist/dashboard/out/app/onboarding.html +1 -1
  10. package/dist/dashboard/out/app/onboarding.txt +1 -1
  11. package/dist/dashboard/out/app.html +1 -1
  12. package/dist/dashboard/out/app.txt +2 -2
  13. package/dist/dashboard/out/cloud/link.html +1 -1
  14. package/dist/dashboard/out/cloud/link.txt +1 -1
  15. package/dist/dashboard/out/complete-profile.html +2 -2
  16. package/dist/dashboard/out/complete-profile.txt +1 -1
  17. package/dist/dashboard/out/connect-repos.html +1 -1
  18. package/dist/dashboard/out/connect-repos.txt +1 -1
  19. package/dist/dashboard/out/history.html +1 -1
  20. package/dist/dashboard/out/history.txt +1 -1
  21. package/dist/dashboard/out/index.html +1 -1
  22. package/dist/dashboard/out/index.txt +2 -2
  23. package/dist/dashboard/out/login.html +2 -2
  24. package/dist/dashboard/out/login.txt +1 -1
  25. package/dist/dashboard/out/metrics.html +1 -1
  26. package/dist/dashboard/out/metrics.txt +1 -1
  27. package/dist/dashboard/out/pricing.html +2 -2
  28. package/dist/dashboard/out/pricing.txt +1 -1
  29. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  30. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  31. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  32. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  33. package/dist/dashboard/out/providers/setup/cursor.html +1 -1
  34. package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
  35. package/dist/dashboard/out/providers.html +1 -1
  36. package/dist/dashboard/out/providers.txt +2 -2
  37. package/dist/dashboard/out/signup.html +2 -2
  38. package/dist/dashboard/out/signup.txt +1 -1
  39. package/package.json +23 -17
  40. package/packages/api-types/package.json +2 -2
  41. package/packages/bridge/dist/spawner.d.ts +2 -0
  42. package/packages/bridge/dist/spawner.js +75 -23
  43. package/packages/bridge/package.json +8 -8
  44. package/packages/cli-tester/README.md +277 -0
  45. package/packages/cli-tester/dist/index.d.ts +21 -0
  46. package/packages/cli-tester/dist/index.js +21 -0
  47. package/packages/cli-tester/dist/utils/credential-check.d.ts +56 -0
  48. package/packages/cli-tester/dist/utils/credential-check.js +230 -0
  49. package/packages/cli-tester/dist/utils/socket-client.d.ts +76 -0
  50. package/packages/cli-tester/dist/utils/socket-client.js +153 -0
  51. package/packages/cli-tester/docker/entrypoint.sh +58 -0
  52. package/packages/cli-tester/package.json +32 -0
  53. package/packages/cli-tester/scripts/clear-auth.sh +101 -0
  54. package/packages/cli-tester/scripts/inject-message.sh +42 -0
  55. package/packages/cli-tester/scripts/start.sh +71 -0
  56. package/packages/cli-tester/scripts/test-cli.sh +56 -0
  57. package/packages/cli-tester/scripts/test-full-spawn.sh +238 -0
  58. package/packages/cli-tester/scripts/test-registration.sh +182 -0
  59. package/packages/cli-tester/scripts/test-setup-flow.sh +202 -0
  60. package/packages/cli-tester/scripts/test-spawn.sh +140 -0
  61. package/packages/cli-tester/scripts/test-with-daemon.sh +247 -0
  62. package/packages/cli-tester/scripts/verify-auth.sh +112 -0
  63. package/packages/cloud/dist/api/cli-pty-runner.js +9 -6
  64. package/packages/cloud/package.json +6 -6
  65. package/packages/config/dist/cli-auth-config.js +75 -0
  66. package/packages/config/package.json +2 -2
  67. package/packages/continuity/package.json +1 -1
  68. package/packages/daemon/dist/cli-auth.js +5 -1
  69. package/packages/daemon/dist/router.js +4 -4
  70. package/packages/daemon/dist/server.js +38 -19
  71. package/packages/daemon/dist/spawn-manager.d.ts +4 -0
  72. package/packages/daemon/dist/spawn-manager.js +2 -0
  73. package/packages/daemon/package.json +12 -12
  74. package/packages/dashboard/dist/server.js +4 -0
  75. package/packages/dashboard/package.json +14 -14
  76. package/packages/dashboard/ui/app/providers/page.tsx +2 -2
  77. package/packages/dashboard/ui/react-components/ProviderConnectionList.tsx +23 -8
  78. package/packages/dashboard/ui/react-components/SpawnModal.tsx +16 -6
  79. package/packages/dashboard/ui/react-components/settings/WorkspaceSettingsPanel.tsx +22 -6
  80. package/packages/dashboard/ui-dist/404.html +1 -1
  81. package/packages/dashboard/ui-dist/_next/static/chunks/320-a6304232cd0ee2ce.js +1 -0
  82. package/packages/dashboard/ui-dist/_next/static/chunks/631-16b905e5920f9b59.js +1 -0
  83. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +1 -0
  84. package/packages/dashboard/ui-dist/_next/static/css/{45361ce86b2847c4.css → 6892f8422896ef7a.css} +1 -1
  85. package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
  86. package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
  87. package/packages/dashboard/ui-dist/app.html +1 -1
  88. package/packages/dashboard/ui-dist/app.txt +2 -2
  89. package/packages/dashboard/ui-dist/cloud/link.html +1 -1
  90. package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
  91. package/packages/dashboard/ui-dist/complete-profile.html +2 -2
  92. package/packages/dashboard/ui-dist/complete-profile.txt +1 -1
  93. package/packages/dashboard/ui-dist/connect-repos.html +1 -1
  94. package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
  95. package/packages/dashboard/ui-dist/history.html +1 -1
  96. package/packages/dashboard/ui-dist/history.txt +1 -1
  97. package/packages/dashboard/ui-dist/index.html +1 -1
  98. package/packages/dashboard/ui-dist/index.txt +2 -2
  99. package/packages/dashboard/ui-dist/login.html +2 -2
  100. package/packages/dashboard/ui-dist/login.txt +1 -1
  101. package/packages/dashboard/ui-dist/metrics.html +1 -1
  102. package/packages/dashboard/ui-dist/metrics.txt +1 -1
  103. package/packages/dashboard/ui-dist/pricing.html +2 -2
  104. package/packages/dashboard/ui-dist/pricing.txt +1 -1
  105. package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
  106. package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
  107. package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
  108. package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
  109. package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
  110. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
  111. package/packages/dashboard/ui-dist/providers.html +1 -1
  112. package/packages/dashboard/ui-dist/providers.txt +2 -2
  113. package/packages/dashboard/ui-dist/signup.html +2 -2
  114. package/packages/dashboard/ui-dist/signup.txt +1 -1
  115. package/packages/dashboard-server/dist/server.js +4 -0
  116. package/packages/dashboard-server/package.json +12 -12
  117. package/packages/hooks/package.json +4 -4
  118. package/packages/mcp/package.json +2 -2
  119. package/packages/memory/package.json +2 -2
  120. package/packages/policy/package.json +2 -2
  121. package/packages/protocol/package.json +1 -1
  122. package/packages/resiliency/package.json +1 -1
  123. package/packages/sdk/README.md +512 -58
  124. package/packages/sdk/dist/client.d.ts +135 -1
  125. package/packages/sdk/dist/client.js +338 -0
  126. package/packages/sdk/dist/index.d.ts +2 -1
  127. package/packages/sdk/dist/index.js +2 -0
  128. package/packages/sdk/dist/logs.d.ts +61 -0
  129. package/packages/sdk/dist/logs.js +95 -0
  130. package/packages/sdk/dist/protocol/index.d.ts +1 -1
  131. package/packages/sdk/dist/protocol/types.d.ts +186 -1
  132. package/packages/sdk/package.json +3 -3
  133. package/packages/spawner/package.json +2 -2
  134. package/packages/state/package.json +1 -1
  135. package/packages/storage/dist/sqlite-adapter.js +2 -0
  136. package/packages/storage/package.json +2 -2
  137. package/packages/telemetry/package.json +1 -1
  138. package/packages/trajectory/package.json +2 -2
  139. package/packages/user-directory/package.json +2 -2
  140. package/packages/utils/package.json +1 -1
  141. package/packages/wrapper/dist/base-wrapper.js +27 -10
  142. package/packages/wrapper/dist/idle-detector.d.ts +4 -0
  143. package/packages/wrapper/dist/idle-detector.js +21 -8
  144. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +5 -0
  145. package/packages/wrapper/dist/relay-pty-orchestrator.js +60 -5
  146. package/packages/wrapper/dist/tmux-wrapper.js +16 -0
  147. package/packages/wrapper/package.json +7 -7
  148. package/scripts/hooks/install.sh +16 -0
  149. package/scripts/hooks/pre-commit +60 -0
  150. package/scripts/postinstall.js +41 -1
  151. package/specs/PRIMITIVES_ROADMAP.md +2154 -0
  152. package/dist/dashboard/out/_next/static/chunks/320-402ffc8646b31da1.js +0 -1
  153. package/dist/dashboard/out/_next/static/chunks/631-af51bad94027527a.js +0 -1
  154. package/dist/dashboard/out/_next/static/chunks/app/providers/page-bcf46064ac4474ce.js +0 -1
  155. package/packages/dashboard/ui-dist/_next/static/chunks/320-402ffc8646b31da1.js +0 -1
  156. package/packages/dashboard/ui-dist/_next/static/chunks/631-af51bad94027527a.js +0 -1
  157. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-bcf46064ac4474ce.js +0 -1
  158. /package/dist/dashboard/out/_next/static/{JIjqkuDKNeoSg7KaMMuhx → PwtT8u1tFMW_S1HUv0i5S}/_buildManifest.js +0 -0
  159. /package/dist/dashboard/out/_next/static/{JIjqkuDKNeoSg7KaMMuhx → PwtT8u1tFMW_S1HUv0i5S}/_ssgManifest.js +0 -0
  160. /package/packages/dashboard/ui-dist/_next/static/{JIjqkuDKNeoSg7KaMMuhx → 52xh7eSCZzG97BVf5zzLY}/_buildManifest.js +0 -0
  161. /package/packages/dashboard/ui-dist/_next/static/{JIjqkuDKNeoSg7KaMMuhx → 52xh7eSCZzG97BVf5zzLY}/_ssgManifest.js +0 -0
  162. /package/packages/dashboard/ui-dist/_next/static/{nmkOi7bqeDmLMoWBih8lz → NN1eZ4W4r5XU6mkmJWV2-}/_buildManifest.js +0 -0
  163. /package/packages/dashboard/ui-dist/_next/static/{nmkOi7bqeDmLMoWBih8lz → NN1eZ4W4r5XU6mkmJWV2-}/_ssgManifest.js +0 -0
  164. /package/packages/dashboard/ui-dist/_next/static/{wk_gKRNSPpWE-ZhGL6UMl → PwtT8u1tFMW_S1HUv0i5S}/_buildManifest.js +0 -0
  165. /package/packages/dashboard/ui-dist/_next/static/{wk_gKRNSPpWE-ZhGL6UMl → PwtT8u1tFMW_S1HUv0i5S}/_ssgManifest.js +0 -0
@@ -87,6 +87,8 @@ export class RelayPtyOrchestrator extends BaseWrapper {
87
87
  sessionStartTime = 0;
88
88
  // Track if agent is being gracefully stopped (vs crashed)
89
89
  isGracefulStop = false;
90
+ // Track early process exit for better error messages
91
+ earlyExitInfo;
90
92
  // Memory/CPU monitoring
91
93
  memoryMonitor;
92
94
  memoryAlertHandler = null;
@@ -383,7 +385,13 @@ export class RelayPtyOrchestrator extends BaseWrapper {
383
385
  throw new Error('relay-pty binary not found. Build with: cd relay-pty && cargo build --release');
384
386
  }
385
387
  this.log(` Using binary: ${binaryPath}`);
386
- // Connect to relay daemon first
388
+ // Spawn relay-pty process FIRST (before connecting to daemon)
389
+ // This ensures the CLI is actually running before we register with the daemon
390
+ await this.spawnRelayPty(binaryPath);
391
+ // Wait for socket to become available and connect
392
+ await this.connectToSocket();
393
+ // Connect to relay daemon AFTER CLI is spawned
394
+ // This prevents the spawner from seeing us as "registered" before the CLI runs
387
395
  try {
388
396
  await this.client.connect();
389
397
  this.log(` Relay daemon connected`);
@@ -391,10 +399,6 @@ export class RelayPtyOrchestrator extends BaseWrapper {
391
399
  catch (err) {
392
400
  this.logError(` Relay connect failed: ${err.message}`);
393
401
  }
394
- // Spawn relay-pty process
395
- await this.spawnRelayPty(binaryPath);
396
- // Wait for socket to become available and connect
397
- await this.connectToSocket();
398
402
  this.running = true;
399
403
  // DON'T set readyForMessages yet - wait for CLI to be ready first
400
404
  // This prevents messages from being injected during CLI startup
@@ -540,6 +544,8 @@ export class RelayPtyOrchestrator extends BaseWrapper {
540
544
  ...(this.config.args ?? []),
541
545
  ];
542
546
  this.log(` Spawning: ${binaryPath} ${args.join(' ')}`);
547
+ // Reset early exit info from any previous spawn attempt
548
+ this.earlyExitInfo = undefined;
543
549
  // For interactive mode, let Rust directly inherit stdin/stdout from the terminal
544
550
  // This is more robust than manual forwarding through pipes
545
551
  // We still pipe stderr to capture JSON parsed commands
@@ -566,10 +572,14 @@ export class RelayPtyOrchestrator extends BaseWrapper {
566
572
  this.handleOutput(text);
567
573
  });
568
574
  }
575
+ // Capture stderr for early exit diagnosis
576
+ let stderrBuffer = '';
569
577
  // Handle stderr (relay-pty logs and JSON output) - always needed
578
+ // Also captures to buffer for error diagnostics if process dies early
570
579
  if (proc.stderr) {
571
580
  proc.stderr.on('data', (data) => {
572
581
  const text = data.toString();
582
+ stderrBuffer += text;
573
583
  this.handleStderr(text);
574
584
  });
575
585
  }
@@ -577,6 +587,10 @@ export class RelayPtyOrchestrator extends BaseWrapper {
577
587
  proc.on('exit', (code, signal) => {
578
588
  const exitCode = code ?? (signal === 'SIGKILL' ? 137 : 1);
579
589
  this.log(` Process exited: code=${exitCode} signal=${signal}`);
590
+ // Capture early exit info for better error messages if socket not yet connected
591
+ if (!this.socketConnected) {
592
+ this.earlyExitInfo = { code, signal, stderr: stderrBuffer };
593
+ }
580
594
  this.running = false;
581
595
  // Get crash context before unregistering from memory monitor
582
596
  const crashContext = this.memoryMonitor.getCrashContext(this.config.name);
@@ -942,6 +956,22 @@ export class RelayPtyOrchestrator extends BaseWrapper {
942
956
  // =========================================================================
943
957
  // Socket communication
944
958
  // =========================================================================
959
+ /**
960
+ * Check if the relay-pty process is still alive
961
+ */
962
+ isProcessAlive() {
963
+ if (!this.relayPtyProcess || this.relayPtyProcess.exitCode !== null) {
964
+ return false;
965
+ }
966
+ try {
967
+ // Signal 0 checks if process exists without killing it
968
+ process.kill(this.relayPtyProcess.pid, 0);
969
+ return true;
970
+ }
971
+ catch {
972
+ return false;
973
+ }
974
+ }
945
975
  /**
946
976
  * Connect to the relay-pty socket
947
977
  */
@@ -949,6 +979,20 @@ export class RelayPtyOrchestrator extends BaseWrapper {
949
979
  const timeout = this.config.socketConnectTimeoutMs ?? 5000;
950
980
  const maxAttempts = this.config.socketReconnectAttempts ?? 3;
951
981
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
982
+ // Check if relay-pty process died before attempting connection
983
+ if (!this.isProcessAlive()) {
984
+ const exitInfo = this.earlyExitInfo;
985
+ if (exitInfo) {
986
+ const exitReason = exitInfo.signal
987
+ ? `signal ${exitInfo.signal}`
988
+ : `code ${exitInfo.code ?? 'unknown'}`;
989
+ const stderrHint = exitInfo.stderr
990
+ ? `\n stderr: ${exitInfo.stderr.trim().slice(0, 500)}`
991
+ : '';
992
+ throw new Error(`relay-pty process died early (${exitReason}).${stderrHint}`);
993
+ }
994
+ throw new Error('relay-pty process died before socket could be created');
995
+ }
952
996
  try {
953
997
  await this.attemptSocketConnection(timeout);
954
998
  this.log(` Socket connected`);
@@ -961,6 +1005,17 @@ export class RelayPtyOrchestrator extends BaseWrapper {
961
1005
  }
962
1006
  }
963
1007
  }
1008
+ // Final check for process death after all attempts
1009
+ if (!this.isProcessAlive() && this.earlyExitInfo) {
1010
+ const exitInfo = this.earlyExitInfo;
1011
+ const exitReason = exitInfo.signal
1012
+ ? `signal ${exitInfo.signal}`
1013
+ : `code ${exitInfo.code ?? 'unknown'}`;
1014
+ const stderrHint = exitInfo.stderr
1015
+ ? `\n stderr: ${exitInfo.stderr.trim().slice(0, 500)}`
1016
+ : '';
1017
+ throw new Error(`relay-pty process died during socket connection (${exitReason}).${stderrHint}`);
1018
+ }
964
1019
  throw new Error(`Failed to connect to socket after ${maxAttempts} attempts`);
965
1020
  }
966
1021
  /**
@@ -805,6 +805,22 @@ export class TmuxWrapper extends BaseWrapper {
805
805
  requires_ack: cmd.meta.ackRequired,
806
806
  };
807
807
  }
808
+ // Check if target is a channel (starts with #)
809
+ if (cmd.to.startsWith('#')) {
810
+ // Use CHANNEL_MESSAGE protocol for channel targets
811
+ this.logStderr(`→ [channel] ${cmd.to}: ${cmd.body.substring(0, Math.min(RELAY_LOG_TRUNCATE_LENGTH, cmd.body.length))}...`);
812
+ const success = this.client.sendChannelMessage(cmd.to, cmd.body, {
813
+ thread: cmd.thread,
814
+ data: cmd.data,
815
+ });
816
+ if (success) {
817
+ this.sentMessageHashes.add(msgHash);
818
+ this.queuedMessageHashes.delete(msgHash);
819
+ this.trajectory?.message('sent', this.config.name, cmd.to, cmd.body);
820
+ }
821
+ return;
822
+ }
823
+ // Use SEND protocol for direct messages and broadcasts
808
824
  if (cmd.sync?.blocking) {
809
825
  this.client.sendAndWait(cmd.to, cmd.body, {
810
826
  timeoutMs: cmd.sync.timeoutMs,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/wrapper",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "CLI agent wrappers for Agent Relay - tmux, pty integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,11 +30,11 @@
30
30
  "clean": "rm -rf dist"
31
31
  },
32
32
  "dependencies": {
33
- "@agent-relay/api-types": "2.0.18",
34
- "@agent-relay/protocol": "2.0.18",
35
- "@agent-relay/config": "2.0.18",
36
- "@agent-relay/continuity": "2.0.18",
37
- "@agent-relay/resiliency": "2.0.18"
33
+ "@agent-relay/api-types": "2.0.20",
34
+ "@agent-relay/protocol": "2.0.20",
35
+ "@agent-relay/config": "2.0.20",
36
+ "@agent-relay/continuity": "2.0.20",
37
+ "@agent-relay/resiliency": "2.0.20"
38
38
  },
39
39
  "devDependencies": {
40
40
  "typescript": "^5.9.3",
@@ -59,5 +59,5 @@
59
59
  "url": "git+https://github.com/AgentWorkforce/relay.git",
60
60
  "directory": "packages/wrapper"
61
61
  },
62
- "license": "MIT"
62
+ "license": "Apache-2.0"
63
63
  }
@@ -0,0 +1,16 @@
1
+ #!/bin/sh
2
+ # Install git hooks for agent-relay
3
+ # Usage: ./scripts/hooks/install.sh
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7
+ HOOKS_DIR="$REPO_ROOT/.git/hooks"
8
+
9
+ echo "Installing git hooks..."
10
+
11
+ # Install pre-commit hook
12
+ cp "$SCRIPT_DIR/pre-commit" "$HOOKS_DIR/pre-commit"
13
+ chmod +x "$HOOKS_DIR/pre-commit"
14
+ echo " Installed pre-commit hook"
15
+
16
+ echo "Done! Git hooks installed."
@@ -0,0 +1,60 @@
1
+ #!/bin/sh
2
+ # Pre-commit hook for agent-relay
3
+ # Handles Rust formatting and bd (beads) sync
4
+ #
5
+ # Install: cp scripts/hooks/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
6
+ # Or run: npm run hooks:install
7
+
8
+ # ============================================================
9
+ # Rust formatting (auto-format staged .rs files)
10
+ # ============================================================
11
+ RUST_STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '\.rs$' || true)
12
+ if [ -n "$RUST_STAGED" ]; then
13
+ if command -v rustfmt >/dev/null 2>&1; then
14
+ echo "Formatting Rust files..."
15
+ for file in $RUST_STAGED; do
16
+ if [ -f "$file" ]; then
17
+ rustfmt "$file" 2>/dev/null || true
18
+ git add "$file"
19
+ fi
20
+ done
21
+ else
22
+ echo "Warning: rustfmt not found, skipping Rust formatting" >&2
23
+ echo "Install with: rustup component add rustfmt" >&2
24
+ fi
25
+ fi
26
+
27
+ # ============================================================
28
+ # bd (beads) sync - flush pending changes before commit
29
+ # ============================================================
30
+ # Check if bd is available
31
+ if ! command -v bd >/dev/null 2>&1; then
32
+ exit 0
33
+ fi
34
+
35
+ # Check if we're in a bd workspace
36
+ if [ ! -d .beads ]; then
37
+ exit 0
38
+ fi
39
+
40
+ # Check if sync-branch is configured (if so, .beads goes to separate branch)
41
+ SYNC_BRANCH="${BEADS_SYNC_BRANCH:-}"
42
+ if [ -z "$SYNC_BRANCH" ] && [ -f .beads/config.yaml ]; then
43
+ SYNC_BRANCH=$(grep -E '^sync-branch:' .beads/config.yaml 2>/dev/null | head -1 | sed 's/^sync-branch:[[:space:]]*//' | sed 's/^["'"'"']//' | sed 's/["'"'"']$//')
44
+ fi
45
+ if [ -n "$SYNC_BRANCH" ]; then
46
+ exit 0
47
+ fi
48
+
49
+ # Flush pending changes
50
+ if ! bd sync --flush-only >/dev/null 2>&1; then
51
+ echo "Error: Failed to flush bd changes" >&2
52
+ exit 1
53
+ fi
54
+
55
+ # Stage JSONL files
56
+ for f in .beads/beads.jsonl .beads/issues.jsonl .beads/deletions.jsonl; do
57
+ [ -f "$f" ] && git add "$f" 2>/dev/null || true
58
+ done
59
+
60
+ exit 0
@@ -73,6 +73,36 @@ function getRelayPtyBinaryName() {
73
73
  return `relay-pty-${targetPlatform}-${targetArch}`;
74
74
  }
75
75
 
76
+ /**
77
+ * Re-sign a binary with ad-hoc signature on macOS.
78
+ * This is required because macOS code signature validation can fail
79
+ * when binaries are copied/downloaded, causing SIGKILL on execution.
80
+ *
81
+ * The codesign tool is always available on macOS (part of the system).
82
+ * This is a common solution for npm packages distributing native binaries.
83
+ * Similar approach is used by esbuild, swc, and other Rust/Go tools.
84
+ *
85
+ * @param {string} binaryPath - Path to the binary to sign
86
+ * @returns {boolean} - Whether signing succeeded
87
+ */
88
+ function resignBinaryForMacOS(binaryPath) {
89
+ if (os.platform() !== 'darwin') {
90
+ return true; // Only needed on macOS
91
+ }
92
+
93
+ try {
94
+ // codesign is always available on macOS as a system utility
95
+ execSync(`codesign --force --sign - "${binaryPath}"`, { stdio: 'pipe' });
96
+ return true;
97
+ } catch (err) {
98
+ // This shouldn't happen on a normal macOS system, but handle gracefully
99
+ warn(`Failed to re-sign binary: ${err.message}`);
100
+ warn('The binary may fail to execute due to code signature issues.');
101
+ warn('You can manually fix this by running: codesign --force --sign - ' + binaryPath);
102
+ return false;
103
+ }
104
+ }
105
+
76
106
  /**
77
107
  * Install the relay-pty binary for the current platform
78
108
  */
@@ -103,6 +133,9 @@ function installRelayPtyBinary() {
103
133
  const sourceStats = fs.statSync(sourcePath);
104
134
  const targetStats = fs.statSync(targetPath);
105
135
  if (sourceStats.size === targetStats.size) {
136
+ // Re-sign even if already installed to ensure signature is valid
137
+ // This fixes issues where previous installs have invalid signatures
138
+ resignBinaryForMacOS(targetPath);
106
139
  info('relay-pty binary already installed');
107
140
  return true;
108
141
  }
@@ -115,7 +148,14 @@ function installRelayPtyBinary() {
115
148
  try {
116
149
  fs.copyFileSync(sourcePath, targetPath);
117
150
  fs.chmodSync(targetPath, 0o755);
118
- success(`Installed relay-pty binary for ${os.platform()}-${os.arch()}`);
151
+
152
+ // Re-sign the binary on macOS to prevent code signature validation failures
153
+ // Without this, macOS may SIGKILL the process immediately on execution
154
+ if (resignBinaryForMacOS(targetPath)) {
155
+ success(`Installed relay-pty binary for ${os.platform()}-${os.arch()}`);
156
+ } else {
157
+ warn(`Installed relay-pty binary but signing failed - may not work on macOS`);
158
+ }
119
159
  return true;
120
160
  } catch (err) {
121
161
  warn(`Failed to install relay-pty binary: ${err.message}`);