agent-relay 1.0.8 → 1.0.11

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 (126) hide show
  1. package/README.md +129 -8
  2. package/bin/.gitkeep +0 -0
  3. package/bin/tmux +0 -0
  4. package/dist/bridge/config.d.ts +41 -0
  5. package/dist/bridge/config.d.ts.map +1 -0
  6. package/dist/bridge/config.js +143 -0
  7. package/dist/bridge/config.js.map +1 -0
  8. package/dist/bridge/index.d.ts +10 -0
  9. package/dist/bridge/index.d.ts.map +1 -0
  10. package/dist/bridge/index.js +10 -0
  11. package/dist/bridge/index.js.map +1 -0
  12. package/dist/bridge/multi-project-client.d.ts +99 -0
  13. package/dist/bridge/multi-project-client.d.ts.map +1 -0
  14. package/dist/bridge/multi-project-client.js +386 -0
  15. package/dist/bridge/multi-project-client.js.map +1 -0
  16. package/dist/bridge/spawner.d.ts +47 -0
  17. package/dist/bridge/spawner.d.ts.map +1 -0
  18. package/dist/bridge/spawner.js +227 -0
  19. package/dist/bridge/spawner.js.map +1 -0
  20. package/dist/bridge/types.d.ts +55 -0
  21. package/dist/bridge/types.d.ts.map +1 -0
  22. package/dist/bridge/types.js +6 -0
  23. package/dist/bridge/types.js.map +1 -0
  24. package/dist/bridge/utils.d.ts +30 -0
  25. package/dist/bridge/utils.d.ts.map +1 -0
  26. package/dist/bridge/utils.js +54 -0
  27. package/dist/bridge/utils.js.map +1 -0
  28. package/dist/cli/index.js +599 -8
  29. package/dist/cli/index.js.map +1 -1
  30. package/dist/daemon/agent-registry.d.ts.map +1 -1
  31. package/dist/daemon/agent-registry.js +6 -1
  32. package/dist/daemon/agent-registry.js.map +1 -1
  33. package/dist/daemon/connection.d.ts +22 -0
  34. package/dist/daemon/connection.d.ts.map +1 -1
  35. package/dist/daemon/connection.js +59 -13
  36. package/dist/daemon/connection.js.map +1 -1
  37. package/dist/daemon/router.d.ts +27 -0
  38. package/dist/daemon/router.d.ts.map +1 -1
  39. package/dist/daemon/router.js +108 -3
  40. package/dist/daemon/router.js.map +1 -1
  41. package/dist/daemon/server.d.ts +8 -0
  42. package/dist/daemon/server.d.ts.map +1 -1
  43. package/dist/daemon/server.js +95 -23
  44. package/dist/daemon/server.js.map +1 -1
  45. package/dist/dashboard/metrics.d.ts +105 -0
  46. package/dist/dashboard/metrics.d.ts.map +1 -0
  47. package/dist/dashboard/metrics.js +192 -0
  48. package/dist/dashboard/metrics.js.map +1 -0
  49. package/dist/dashboard/needs-attention.d.ts +24 -0
  50. package/dist/dashboard/needs-attention.d.ts.map +1 -0
  51. package/dist/dashboard/needs-attention.js +78 -0
  52. package/dist/dashboard/needs-attention.js.map +1 -0
  53. package/dist/dashboard/public/bridge.html +1272 -0
  54. package/dist/dashboard/public/index.html +2017 -879
  55. package/dist/dashboard/public/js/app.js +184 -0
  56. package/dist/dashboard/public/js/app.js.map +7 -0
  57. package/dist/dashboard/public/metrics.html +999 -0
  58. package/dist/dashboard/server.d.ts +13 -0
  59. package/dist/dashboard/server.d.ts.map +1 -1
  60. package/dist/dashboard/server.js +594 -13
  61. package/dist/dashboard/server.js.map +1 -1
  62. package/dist/dashboard/start.js +1 -1
  63. package/dist/dashboard/start.js.map +1 -1
  64. package/dist/dashboard-v2/index.d.ts +10 -0
  65. package/dist/dashboard-v2/index.d.ts.map +1 -0
  66. package/dist/dashboard-v2/index.js +54 -0
  67. package/dist/dashboard-v2/index.js.map +1 -0
  68. package/dist/dashboard-v2/lib/api.d.ts +95 -0
  69. package/dist/dashboard-v2/lib/api.d.ts.map +1 -0
  70. package/dist/dashboard-v2/lib/api.js +270 -0
  71. package/dist/dashboard-v2/lib/api.js.map +1 -0
  72. package/dist/dashboard-v2/lib/colors.d.ts +61 -0
  73. package/dist/dashboard-v2/lib/colors.d.ts.map +1 -0
  74. package/dist/dashboard-v2/lib/colors.js +198 -0
  75. package/dist/dashboard-v2/lib/colors.js.map +1 -0
  76. package/dist/dashboard-v2/lib/hierarchy.d.ts +74 -0
  77. package/dist/dashboard-v2/lib/hierarchy.d.ts.map +1 -0
  78. package/dist/dashboard-v2/lib/hierarchy.js +196 -0
  79. package/dist/dashboard-v2/lib/hierarchy.js.map +1 -0
  80. package/dist/dashboard-v2/types/index.d.ts +154 -0
  81. package/dist/dashboard-v2/types/index.d.ts.map +1 -0
  82. package/dist/dashboard-v2/types/index.js +6 -0
  83. package/dist/dashboard-v2/types/index.js.map +1 -0
  84. package/dist/storage/adapter.d.ts +21 -1
  85. package/dist/storage/adapter.d.ts.map +1 -1
  86. package/dist/storage/adapter.js +36 -0
  87. package/dist/storage/adapter.js.map +1 -1
  88. package/dist/storage/sqlite-adapter.d.ts +34 -0
  89. package/dist/storage/sqlite-adapter.d.ts.map +1 -1
  90. package/dist/storage/sqlite-adapter.js +253 -12
  91. package/dist/storage/sqlite-adapter.js.map +1 -1
  92. package/dist/utils/agent-config.d.ts +45 -0
  93. package/dist/utils/agent-config.d.ts.map +1 -0
  94. package/dist/utils/agent-config.js +118 -0
  95. package/dist/utils/agent-config.js.map +1 -0
  96. package/dist/utils/tmux-resolver.d.ts +55 -0
  97. package/dist/utils/tmux-resolver.d.ts.map +1 -0
  98. package/dist/utils/tmux-resolver.js +175 -0
  99. package/dist/utils/tmux-resolver.js.map +1 -0
  100. package/dist/wrapper/client.d.ts +8 -0
  101. package/dist/wrapper/client.d.ts.map +1 -1
  102. package/dist/wrapper/client.js +26 -0
  103. package/dist/wrapper/client.js.map +1 -1
  104. package/dist/wrapper/parser.d.ts +17 -0
  105. package/dist/wrapper/parser.d.ts.map +1 -1
  106. package/dist/wrapper/parser.js +334 -10
  107. package/dist/wrapper/parser.js.map +1 -1
  108. package/dist/wrapper/tmux-wrapper.d.ts +38 -2
  109. package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
  110. package/dist/wrapper/tmux-wrapper.js +196 -32
  111. package/dist/wrapper/tmux-wrapper.js.map +1 -1
  112. package/docs/AGENTS.md +105 -0
  113. package/docs/ARCHITECTURE_DECISIONS.md +175 -0
  114. package/docs/COMPETITIVE_ANALYSIS.md +897 -0
  115. package/docs/DESIGN_BRIDGE_STAFFING.md +878 -0
  116. package/docs/MONETIZATION.md +1679 -0
  117. package/docs/agent-relay-snippet.md +61 -0
  118. package/docs/dashboard-v2-plan.md +179 -0
  119. package/package.json +8 -3
  120. package/scripts/dev/PUBLIC_RELEASE_PLAN.md +88 -0
  121. package/scripts/dev/dev-team-setup.sh +431 -0
  122. package/scripts/e2e-test.sh +119 -0
  123. package/scripts/games/game-protocol.md +79 -0
  124. package/scripts/games/hearts-setup.sh +264 -0
  125. package/scripts/postinstall.js +225 -0
  126. package/scripts/tictactoe-setup.sh +181 -0
@@ -0,0 +1,264 @@
1
+ #!/bin/bash
2
+ #
3
+ # Hearts - 3 Player Autonomous Agent Game
4
+ # Sets up three agents to play Hearts autonomously via file-based inbox
5
+ #
6
+
7
+ set -e
8
+
9
+ GAME_DIR="${GAME_DIR:-/tmp/agent-relay-hearts}"
10
+ PLAYER_1="Alice"
11
+ PLAYER_2="Bob"
12
+ PLAYER_3="Carol"
13
+
14
+ echo "=== Hearts 3-Player Game Setup ==="
15
+ echo "Game directory: $GAME_DIR"
16
+ echo "Players: $PLAYER_1, $PLAYER_2, $PLAYER_3"
17
+ echo ""
18
+
19
+ # Create directories
20
+ mkdir -p "$GAME_DIR/$PLAYER_1"
21
+ mkdir -p "$GAME_DIR/$PLAYER_2"
22
+ mkdir -p "$GAME_DIR/$PLAYER_3"
23
+
24
+ # Clear any existing inbox
25
+ echo "" > "$GAME_DIR/$PLAYER_1/inbox.md"
26
+ echo "" > "$GAME_DIR/$PLAYER_2/inbox.md"
27
+ echo "" > "$GAME_DIR/$PLAYER_3/inbox.md"
28
+
29
+ # Generate and deal cards
30
+ # For 3 players: remove 2 of diamonds, deal 17 cards each
31
+ CARDS="2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AC 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AH 2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AS 3D 4D 5D 6D 7D 8D 9D TD JD QD KD AD"
32
+
33
+ # Shuffle cards using a simple method
34
+ SHUFFLED=$(echo $CARDS | tr ' ' '\n' | sort -R | tr '\n' ' ')
35
+ CARD_ARRAY=($SHUFFLED)
36
+
37
+ # Deal 17 cards to each player
38
+ HAND_1="${CARD_ARRAY[@]:0:17}"
39
+ HAND_2="${CARD_ARRAY[@]:17:17}"
40
+ HAND_3="${CARD_ARRAY[@]:34:17}"
41
+
42
+ # Create common game rules file
43
+ cat > "$GAME_DIR/GAME_RULES.md" << 'EOF'
44
+ # Hearts - 3 Player Rules
45
+
46
+ ## Overview
47
+ Hearts is a trick-taking card game where you try to AVOID points.
48
+
49
+ ## Card Values
50
+ - Suits: Clubs (C), Diamonds (D), Spades (S), Hearts (H)
51
+ - Ranks: 2-9, T(10), J, Q, K, A (low to high)
52
+ - Card notation: RankSuit (e.g., 2C = 2 of Clubs, QS = Queen of Spades)
53
+
54
+ ## Scoring
55
+ - Each Heart: 1 point
56
+ - Queen of Spades (QS): 13 points
57
+ - **Goal: Get the LOWEST score**
58
+
59
+ ## Special Rule: Shooting the Moon
60
+ If you take ALL hearts AND the Queen of Spades in one round:
61
+ - You score 0 points
62
+ - All opponents get 26 points each
63
+
64
+ ## Gameplay
65
+
66
+ ### 1. Passing Phase
67
+ - Pass 3 cards to the player on your left
68
+ - Round 1: Alice→Bob, Bob→Carol, Carol→Alice
69
+
70
+ ### 2. Trick Phase
71
+ - Player with 2 of Clubs (2C) leads first trick
72
+ - Players must follow suit if able
73
+ - If can't follow suit, can play any card
74
+ - Highest card of the led suit wins the trick
75
+ - Winner leads next trick
76
+
77
+ ### 3. Hearts Breaking
78
+ - Cannot lead hearts until hearts have been "broken"
79
+ - Hearts break when someone plays a heart (because they can't follow suit)
80
+
81
+ ## Turn Order
82
+ Alice → Bob → Carol → Alice → ...
83
+
84
+ ## End of Round
85
+ - Round ends when all 17 tricks are played
86
+ - Count points taken
87
+ - Game ends when someone reaches 100 points
88
+
89
+ ## Commands
90
+
91
+ **Wait for your turn:**
92
+ ```bash
93
+ agent-relay inbox-poll -n YOUR_NAME -d /tmp/agent-relay-hearts --clear
94
+ ```
95
+
96
+ **Play a card (to next player or broadcast):**
97
+ ```bash
98
+ agent-relay inbox-write -t "NEXT_PLAYER" -f YOUR_NAME -m "PLAY: CARD" -d /tmp/agent-relay-hearts
99
+ ```
100
+
101
+ **Broadcast to all:**
102
+ ```bash
103
+ agent-relay inbox-write -t "*" -f YOUR_NAME -m "MESSAGE" -d /tmp/agent-relay-hearts
104
+ ```
105
+ EOF
106
+
107
+ # Create player-specific instruction files
108
+ create_player_instructions() {
109
+ local PLAYER=$1
110
+ local HAND=$2
111
+ local PREV=$3
112
+ local NEXT=$4
113
+ local IS_FIRST=$5
114
+
115
+ cat > "$GAME_DIR/$PLAYER/INSTRUCTIONS.md" << EOFPLAYER
116
+ # Hearts - You are $PLAYER
117
+
118
+ Read the game rules: \`cat /tmp/agent-relay-hearts/GAME_RULES.md\`
119
+
120
+ ## Your Starting Hand (17 cards)
121
+ \`\`\`
122
+ $HAND
123
+ \`\`\`
124
+
125
+ ## Players
126
+ - You: **$PLAYER**
127
+ - To your left (you pass TO): **$NEXT**
128
+ - To your right (you receive FROM): **$PREV**
129
+
130
+ ## Commands
131
+
132
+ **Wait for messages:**
133
+ \`\`\`bash
134
+ agent-relay inbox-poll -n $PLAYER -d /tmp/agent-relay-hearts --clear
135
+ \`\`\`
136
+
137
+ **Send to next player:**
138
+ \`\`\`bash
139
+ agent-relay inbox-write -t "$NEXT" -f $PLAYER -m "YOUR_MESSAGE" -d /tmp/agent-relay-hearts
140
+ \`\`\`
141
+
142
+ **Broadcast to all:**
143
+ \`\`\`bash
144
+ agent-relay inbox-write -t "*" -f $PLAYER -m "YOUR_MESSAGE" -d /tmp/agent-relay-hearts
145
+ \`\`\`
146
+
147
+ ## Game Protocol
148
+
149
+ ### Phase 1: Card Passing
150
+ 1. Choose 3 cards to pass to $NEXT
151
+ 2. Send: \`PASS: card1 card2 card3\`
152
+ 3. Wait to receive 3 cards from $PREV
153
+ 4. Update your hand (remove passed, add received)
154
+
155
+ ### Phase 2: Playing Tricks
156
+ The player with 2C leads the first trick.
157
+
158
+ **When it's your turn to play:**
159
+ 1. Look at what's been played in this trick
160
+ 2. If you have the led suit, you MUST play it
161
+ 3. If you don't have the led suit, play any card
162
+ 4. Send: \`PLAY: CARD\` (e.g., \`PLAY: 7H\`)
163
+ 5. If you're last in trick, also announce winner and next lead
164
+
165
+ **Message format for playing:**
166
+ - \`PLAY: CARD\` - Your card play
167
+ - \`TRICK_WINNER: PLAYER\` - Who won the trick
168
+ - \`POINTS: {Alice: X, Bob: Y, Carol: Z}\` - Point totals
169
+
170
+ ### Tracking State
171
+ Keep track of:
172
+ - Your current hand
173
+ - Cards played this trick
174
+ - Who has played
175
+ - Hearts broken? (true/false)
176
+ - Points taken this round
177
+
178
+ EOFPLAYER
179
+
180
+ if [ "$IS_FIRST" = "true" ]; then
181
+ cat >> "$GAME_DIR/$PLAYER/INSTRUCTIONS.md" << EOFSTART
182
+
183
+ ## You Start!
184
+ Since you are $PLAYER, you coordinate the game start:
185
+
186
+ 1. **First, wait for all pass cards:**
187
+ \`\`\`bash
188
+ agent-relay inbox-poll -n $PLAYER -d /tmp/agent-relay-hearts --clear
189
+ \`\`\`
190
+
191
+ 2. **Send your 3 pass cards to $NEXT:**
192
+ \`\`\`bash
193
+ agent-relay inbox-write -t "$NEXT" -f $PLAYER -m "PASS: [card1] [card2] [card3]" -d /tmp/agent-relay-hearts
194
+ \`\`\`
195
+
196
+ 3. **Wait for pass cards from $PREV**
197
+
198
+ 4. **After everyone has passed, if you have 2C, lead first trick:**
199
+ \`\`\`bash
200
+ agent-relay inbox-write -t "*" -f $PLAYER -m "TRICK 1 - $PLAYER leads: PLAY: 2C" -d /tmp/agent-relay-hearts
201
+ \`\`\`
202
+
203
+ 5. **Wait for responses and continue the game loop**
204
+
205
+ ## START NOW
206
+ Begin by choosing 3 cards to pass and sending them to $NEXT!
207
+ EOFSTART
208
+ else
209
+ cat >> "$GAME_DIR/$PLAYER/INSTRUCTIONS.md" << EOFWAIT
210
+
211
+ ## Waiting for Game Start
212
+ You will receive the first message when it's time to pass cards.
213
+
214
+ 1. **Wait for instruction to pass:**
215
+ \`\`\`bash
216
+ agent-relay inbox-poll -n $PLAYER -d /tmp/agent-relay-hearts --clear
217
+ \`\`\`
218
+
219
+ 2. **When prompted, send your 3 pass cards to $NEXT:**
220
+ \`\`\`bash
221
+ agent-relay inbox-write -t "$NEXT" -f $PLAYER -m "PASS: [card1] [card2] [card3]" -d /tmp/agent-relay-hearts
222
+ \`\`\`
223
+
224
+ 3. **Continue following the game protocol**
225
+
226
+ ## START NOW
227
+ Run the inbox-poll command to wait for the game to begin!
228
+ EOFWAIT
229
+ fi
230
+ }
231
+
232
+ # Create instructions for each player
233
+ create_player_instructions "$PLAYER_1" "$HAND_1" "$PLAYER_3" "$PLAYER_2" "true"
234
+ create_player_instructions "$PLAYER_2" "$HAND_2" "$PLAYER_1" "$PLAYER_3" "false"
235
+ create_player_instructions "$PLAYER_3" "$HAND_3" "$PLAYER_2" "$PLAYER_1" "false"
236
+
237
+ echo "Created game files:"
238
+ echo " - $GAME_DIR/GAME_RULES.md"
239
+ echo " - $GAME_DIR/$PLAYER_1/INSTRUCTIONS.md (Hand: $HAND_1)"
240
+ echo " - $GAME_DIR/$PLAYER_2/INSTRUCTIONS.md (Hand: $HAND_2)"
241
+ echo " - $GAME_DIR/$PLAYER_3/INSTRUCTIONS.md (Hand: $HAND_3)"
242
+ echo ""
243
+ echo "=== TO START THE GAME ==="
244
+ echo ""
245
+ echo "Make sure agent-relay is built:"
246
+ echo " cd $(dirname "$0")/../.."
247
+ echo " npm run build"
248
+ echo ""
249
+ echo "Open THREE terminal windows and run Claude/Codex in each:"
250
+ echo ""
251
+ echo "Terminal 1 ($PLAYER_1 - coordinates start):"
252
+ echo " claude"
253
+ echo " # Say: Read $GAME_DIR/$PLAYER_1/INSTRUCTIONS.md and start the Hearts game"
254
+ echo ""
255
+ echo "Terminal 2 ($PLAYER_2):"
256
+ echo " claude"
257
+ echo " # Say: Read $GAME_DIR/$PLAYER_2/INSTRUCTIONS.md and play Hearts"
258
+ echo ""
259
+ echo "Terminal 3 ($PLAYER_3):"
260
+ echo " claude"
261
+ echo " # Say: Read $GAME_DIR/$PLAYER_3/INSTRUCTIONS.md and play Hearts"
262
+ echo ""
263
+ echo "The three agents will autonomously play Hearts!"
264
+ echo ""
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Postinstall Script for agent-relay
4
+ *
5
+ * This script runs after npm install to:
6
+ * 1. Rebuild native modules (better-sqlite3)
7
+ * 2. Install tmux binary if not available on the system
8
+ *
9
+ * The tmux binary is installed within the package itself (bin/tmux),
10
+ * making it portable and not requiring global installation.
11
+ */
12
+
13
+ import { execSync } from 'node:child_process';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import fs from 'node:fs';
17
+ import https from 'node:https';
18
+ import { fileURLToPath } from 'node:url';
19
+
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = path.dirname(__filename);
22
+
23
+ /** Get package root directory (parent of scripts/) */
24
+ function getPackageRoot() {
25
+ return path.resolve(__dirname, '..');
26
+ }
27
+
28
+ /** Installation directory (within the package) */
29
+ function getInstallDir() {
30
+ return path.join(getPackageRoot(), 'bin');
31
+ }
32
+
33
+ // Colors for console output
34
+ const colors = {
35
+ reset: '\x1b[0m',
36
+ green: '\x1b[32m',
37
+ yellow: '\x1b[33m',
38
+ blue: '\x1b[34m',
39
+ red: '\x1b[31m',
40
+ };
41
+
42
+ function info(msg) {
43
+ console.log(`${colors.blue}[info]${colors.reset} ${msg}`);
44
+ }
45
+
46
+ function success(msg) {
47
+ console.log(`${colors.green}[success]${colors.reset} ${msg}`);
48
+ }
49
+
50
+ function warn(msg) {
51
+ console.log(`${colors.yellow}[warn]${colors.reset} ${msg}`);
52
+ }
53
+
54
+ function error(msg) {
55
+ console.log(`${colors.red}[error]${colors.reset} ${msg}`);
56
+ }
57
+
58
+ /**
59
+ * Check if tmux is available on the system
60
+ */
61
+ function hasSystemTmux() {
62
+ try {
63
+ execSync('which tmux', { stdio: 'pipe' });
64
+ return true;
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Get platform identifier for tmux-builds
72
+ */
73
+ function getPlatformId() {
74
+ const platform = os.platform();
75
+ const arch = os.arch();
76
+
77
+ if (platform === 'darwin') {
78
+ return arch === 'arm64' ? 'macos-arm64' : 'macos-x86_64';
79
+ } else if (platform === 'linux') {
80
+ return arch === 'arm64' ? 'linux-arm64' : 'linux-x86_64';
81
+ }
82
+
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Download file with redirect support
88
+ */
89
+ function downloadFile(url, destPath) {
90
+ return new Promise((resolve, reject) => {
91
+ const file = fs.createWriteStream(destPath);
92
+
93
+ const request = (currentUrl, redirectCount = 0) => {
94
+ if (redirectCount > 5) {
95
+ reject(new Error('Too many redirects'));
96
+ return;
97
+ }
98
+
99
+ const urlObj = new URL(currentUrl);
100
+ const options = {
101
+ hostname: urlObj.hostname,
102
+ path: urlObj.pathname + urlObj.search,
103
+ headers: {
104
+ 'User-Agent': 'agent-relay-installer',
105
+ },
106
+ };
107
+
108
+ https
109
+ .get(options, (response) => {
110
+ if (response.statusCode === 302 || response.statusCode === 301) {
111
+ const location = response.headers.location;
112
+ if (location) {
113
+ request(location, redirectCount + 1);
114
+ return;
115
+ }
116
+ }
117
+
118
+ if (response.statusCode !== 200) {
119
+ reject(new Error(`HTTP ${response.statusCode}`));
120
+ return;
121
+ }
122
+
123
+ response.pipe(file);
124
+ file.on('finish', () => {
125
+ file.close();
126
+ resolve();
127
+ });
128
+ })
129
+ .on('error', reject);
130
+ };
131
+
132
+ request(url);
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Install tmux binary
138
+ */
139
+ async function installTmux() {
140
+ const TMUX_VERSION = '3.6a';
141
+ const INSTALL_DIR = getInstallDir();
142
+ const tmuxPath = path.join(INSTALL_DIR, 'tmux');
143
+
144
+ // Check if already installed
145
+ if (fs.existsSync(tmuxPath)) {
146
+ info('Bundled tmux already installed');
147
+ return true;
148
+ }
149
+
150
+ const platformId = getPlatformId();
151
+ if (!platformId) {
152
+ const platform = os.platform();
153
+ warn(`Unsupported platform: ${platform} ${os.arch()}`);
154
+ if (platform === 'win32') {
155
+ warn('tmux requires WSL (Windows Subsystem for Linux)');
156
+ warn('Install WSL first, then run: sudo apt install tmux');
157
+ } else {
158
+ warn('Please install tmux manually: https://github.com/tmux/tmux/wiki/Installing');
159
+ }
160
+ return false;
161
+ }
162
+
163
+ info(`Installing tmux ${TMUX_VERSION} for ${platformId}...`);
164
+
165
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-relay-tmux-'));
166
+ const archiveName = `tmux-${TMUX_VERSION}-${platformId}.tar.gz`;
167
+ const archivePath = path.join(tmpDir, archiveName);
168
+ const downloadUrl = `https://github.com/tmux/tmux-builds/releases/download/v${TMUX_VERSION}/${archiveName}`;
169
+
170
+ try {
171
+ info('Downloading tmux binary...');
172
+ await downloadFile(downloadUrl, archivePath);
173
+
174
+ info('Extracting...');
175
+ execSync(`tar -xzf "${archivePath}" -C "${tmpDir}"`, { stdio: 'pipe' });
176
+
177
+ const extractedTmux = path.join(tmpDir, 'tmux');
178
+ if (!fs.existsSync(extractedTmux)) {
179
+ throw new Error('tmux binary not found in archive');
180
+ }
181
+
182
+ fs.mkdirSync(INSTALL_DIR, { recursive: true });
183
+ fs.copyFileSync(extractedTmux, tmuxPath);
184
+ fs.chmodSync(tmuxPath, 0o755);
185
+
186
+ success(`Installed tmux to ${tmuxPath}`);
187
+ return true;
188
+ } catch (err) {
189
+ error(`Failed to install tmux: ${err.message}`);
190
+ warn('Please install tmux manually, then reinstall: npm install agent-relay');
191
+ return false;
192
+ } finally {
193
+ try {
194
+ fs.rmSync(tmpDir, { recursive: true, force: true });
195
+ } catch {
196
+ // Ignore
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Main postinstall routine
203
+ */
204
+ async function main() {
205
+ // Skip in CI environments where tmux isn't needed
206
+ if (process.env.CI === 'true') {
207
+ info('Skipping tmux install in CI environment');
208
+ return;
209
+ }
210
+
211
+ // Check if system tmux is available
212
+ if (hasSystemTmux()) {
213
+ info('System tmux found');
214
+ return;
215
+ }
216
+
217
+ // Try to install bundled tmux
218
+ await installTmux();
219
+ }
220
+
221
+ main().catch((err) => {
222
+ // Don't fail the install if tmux installation fails
223
+ // User can still install tmux manually
224
+ warn(`Postinstall warning: ${err.message}`);
225
+ });
@@ -0,0 +1,181 @@
1
+ #!/bin/bash
2
+ #
3
+ # Tic-Tac-Toe Autonomous Agent Test
4
+ # Sets up two agents to play tic-tac-toe autonomously via file-based inbox
5
+ #
6
+
7
+ set -e
8
+
9
+ RELAY_DIR="${AGENT_RELAY_DIR:-/tmp/agent-relay-ttt}"
10
+ PLAYER_X="PlayerX"
11
+ PLAYER_O="PlayerO"
12
+
13
+ echo "=== Tic-Tac-Toe Agent Setup ==="
14
+ echo "Relay directory: $RELAY_DIR"
15
+ echo ""
16
+
17
+ # Create directories
18
+ mkdir -p "$RELAY_DIR/$PLAYER_X"
19
+ mkdir -p "$RELAY_DIR/$PLAYER_O"
20
+
21
+ # Clear any existing inbox
22
+ echo "" > "$RELAY_DIR/$PLAYER_X/inbox.md"
23
+ echo "" > "$RELAY_DIR/$PLAYER_O/inbox.md"
24
+
25
+ # Create game instructions for Player X (goes first)
26
+ cat > "$RELAY_DIR/$PLAYER_X/GAME_INSTRUCTIONS.md" << 'EOF'
27
+ # Tic-Tac-Toe Autonomous Game Protocol
28
+
29
+ You are **PlayerX** (X). You play FIRST. Your opponent is **PlayerO** (O).
30
+
31
+ ## Board Positions
32
+ ```
33
+ 1 | 2 | 3
34
+ -----------
35
+ 4 | 5 | 6
36
+ -----------
37
+ 7 | 8 | 9
38
+ ```
39
+
40
+ ## Commands Available
41
+ You have these `agent-relay` commands to communicate:
42
+
43
+ **Wait for opponent's message (blocking):**
44
+ ```bash
45
+ agent-relay inbox-poll -n PlayerX -d /tmp/agent-relay-ttt --clear
46
+ ```
47
+
48
+ **Send a move to opponent:**
49
+ ```bash
50
+ agent-relay inbox-write -t PlayerO -f PlayerX -m "MOVE: X at position N" -d /tmp/agent-relay-ttt
51
+ ```
52
+
53
+ ## PROTOCOL (follow EXACTLY)
54
+
55
+ ### Since you're X, you go FIRST:
56
+ 1. Make your first move to position 5 (center)
57
+ 2. Send it to opponent:
58
+ ```bash
59
+ agent-relay inbox-write -t PlayerO -f PlayerX -m "MOVE: X at position 5" -d /tmp/agent-relay-ttt
60
+ ```
61
+
62
+ ### Then enter the game loop:
63
+ 1. **WAIT** for opponent's response (this will block until they respond):
64
+ ```bash
65
+ agent-relay inbox-poll -n PlayerX -d /tmp/agent-relay-ttt --clear
66
+ ```
67
+
68
+ 2. **UPDATE** your mental board state with opponent's move
69
+
70
+ 3. **CHECK** for win/draw. If game over, send result and announce:
71
+ ```bash
72
+ agent-relay inbox-write -t PlayerO -f PlayerX -m "GAME OVER: X wins!" -d /tmp/agent-relay-ttt
73
+ ```
74
+
75
+ 4. **MAKE** your next move and send it:
76
+ ```bash
77
+ agent-relay inbox-write -t PlayerO -f PlayerX -m "MOVE: X at position N" -d /tmp/agent-relay-ttt
78
+ ```
79
+
80
+ 5. **REPEAT** from step 1 until game over
81
+
82
+ ## Rules
83
+ - Valid moves: positions 1-9 that are empty
84
+ - Win: 3 in a row (horizontal, vertical, or diagonal)
85
+ - Draw: all 9 positions filled with no winner
86
+
87
+ ## CRITICAL
88
+ - NEVER stop mid-game
89
+ - ALWAYS use the inbox-poll command to wait (it blocks until opponent responds)
90
+ - Keep track of the board state
91
+ - Announce result when game ends
92
+
93
+ ## START NOW
94
+ Make your FIRST MOVE to position 5, then wait for opponent's response.
95
+ EOF
96
+
97
+ # Create game instructions for Player O (waits for X)
98
+ cat > "$RELAY_DIR/$PLAYER_O/GAME_INSTRUCTIONS.md" << 'EOF'
99
+ # Tic-Tac-Toe Autonomous Game Protocol
100
+
101
+ You are **PlayerO** (O). PlayerX plays first, so you WAIT for their move.
102
+
103
+ ## Board Positions
104
+ ```
105
+ 1 | 2 | 3
106
+ -----------
107
+ 4 | 5 | 6
108
+ -----------
109
+ 7 | 8 | 9
110
+ ```
111
+
112
+ ## Commands Available
113
+ You have these `agent-relay` commands to communicate:
114
+
115
+ **Wait for opponent's message (blocking):**
116
+ ```bash
117
+ agent-relay inbox-poll -n PlayerO -d /tmp/agent-relay-ttt --clear
118
+ ```
119
+
120
+ **Send a move to opponent:**
121
+ ```bash
122
+ agent-relay inbox-write -t PlayerX -f PlayerO -m "MOVE: O at position N" -d /tmp/agent-relay-ttt
123
+ ```
124
+
125
+ ## PROTOCOL (follow EXACTLY)
126
+
127
+ ### Since you're O, you go SECOND. Start by waiting:
128
+ 1. **WAIT** for opponent's first move (this will block until they move):
129
+ ```bash
130
+ agent-relay inbox-poll -n PlayerO -d /tmp/agent-relay-ttt --clear
131
+ ```
132
+
133
+ 2. **UPDATE** your mental board state with opponent's move
134
+
135
+ 3. **CHECK** for win/draw. If game over, announce result.
136
+
137
+ 4. **MAKE** your response move and send it:
138
+ ```bash
139
+ agent-relay inbox-write -t PlayerX -f PlayerO -m "MOVE: O at position N" -d /tmp/agent-relay-ttt
140
+ ```
141
+
142
+ 5. **WAIT** for opponent's next move (back to step 1)
143
+
144
+ ## Rules
145
+ - Valid moves: positions 1-9 that are empty
146
+ - Win: 3 in a row (horizontal, vertical, or diagonal)
147
+ - Draw: all 9 positions filled with no winner
148
+
149
+ ## CRITICAL
150
+ - NEVER stop mid-game
151
+ - ALWAYS use the inbox-poll command to wait (it blocks until opponent responds)
152
+ - Keep track of the board state
153
+ - Announce result when game ends
154
+
155
+ ## START NOW
156
+ Run the inbox-poll command to WAIT for PlayerX's first move.
157
+ EOF
158
+
159
+ echo "Created game instructions:"
160
+ echo " - $RELAY_DIR/$PLAYER_X/GAME_INSTRUCTIONS.md"
161
+ echo " - $RELAY_DIR/$PLAYER_O/GAME_INSTRUCTIONS.md"
162
+ echo ""
163
+ echo "=== TO START THE GAME ==="
164
+ echo ""
165
+ echo "Make sure agent-relay is built and in your PATH:"
166
+ echo " cd $(dirname "$0")/.."
167
+ echo " npm run build"
168
+ echo " export PATH=\"\$PATH:\$(pwd)/dist/cli\""
169
+ echo ""
170
+ echo "Open TWO terminal windows and run Claude in each:"
171
+ echo ""
172
+ echo "Terminal 1 (PlayerX - goes first):"
173
+ echo " claude"
174
+ echo " # Then tell Claude: Read $RELAY_DIR/$PLAYER_X/GAME_INSTRUCTIONS.md and start the game"
175
+ echo ""
176
+ echo "Terminal 2 (PlayerO - waits):"
177
+ echo " claude"
178
+ echo " # Then tell Claude: Read $RELAY_DIR/$PLAYER_O/GAME_INSTRUCTIONS.md and start the game"
179
+ echo ""
180
+ echo "Both agents will autonomously play tic-tac-toe!"
181
+ echo ""