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.
- package/README.md +129 -8
- package/bin/.gitkeep +0 -0
- package/bin/tmux +0 -0
- package/dist/bridge/config.d.ts +41 -0
- package/dist/bridge/config.d.ts.map +1 -0
- package/dist/bridge/config.js +143 -0
- package/dist/bridge/config.js.map +1 -0
- package/dist/bridge/index.d.ts +10 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +10 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/multi-project-client.d.ts +99 -0
- package/dist/bridge/multi-project-client.d.ts.map +1 -0
- package/dist/bridge/multi-project-client.js +386 -0
- package/dist/bridge/multi-project-client.js.map +1 -0
- package/dist/bridge/spawner.d.ts +47 -0
- package/dist/bridge/spawner.d.ts.map +1 -0
- package/dist/bridge/spawner.js +227 -0
- package/dist/bridge/spawner.js.map +1 -0
- package/dist/bridge/types.d.ts +55 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +6 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/bridge/utils.d.ts +30 -0
- package/dist/bridge/utils.d.ts.map +1 -0
- package/dist/bridge/utils.js +54 -0
- package/dist/bridge/utils.js.map +1 -0
- package/dist/cli/index.js +599 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/agent-registry.d.ts.map +1 -1
- package/dist/daemon/agent-registry.js +6 -1
- package/dist/daemon/agent-registry.js.map +1 -1
- package/dist/daemon/connection.d.ts +22 -0
- package/dist/daemon/connection.d.ts.map +1 -1
- package/dist/daemon/connection.js +59 -13
- package/dist/daemon/connection.js.map +1 -1
- package/dist/daemon/router.d.ts +27 -0
- package/dist/daemon/router.d.ts.map +1 -1
- package/dist/daemon/router.js +108 -3
- package/dist/daemon/router.js.map +1 -1
- package/dist/daemon/server.d.ts +8 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +95 -23
- package/dist/daemon/server.js.map +1 -1
- package/dist/dashboard/metrics.d.ts +105 -0
- package/dist/dashboard/metrics.d.ts.map +1 -0
- package/dist/dashboard/metrics.js +192 -0
- package/dist/dashboard/metrics.js.map +1 -0
- package/dist/dashboard/needs-attention.d.ts +24 -0
- package/dist/dashboard/needs-attention.d.ts.map +1 -0
- package/dist/dashboard/needs-attention.js +78 -0
- package/dist/dashboard/needs-attention.js.map +1 -0
- package/dist/dashboard/public/bridge.html +1272 -0
- package/dist/dashboard/public/index.html +2017 -879
- package/dist/dashboard/public/js/app.js +184 -0
- package/dist/dashboard/public/js/app.js.map +7 -0
- package/dist/dashboard/public/metrics.html +999 -0
- package/dist/dashboard/server.d.ts +13 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +594 -13
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/start.js +1 -1
- package/dist/dashboard/start.js.map +1 -1
- package/dist/dashboard-v2/index.d.ts +10 -0
- package/dist/dashboard-v2/index.d.ts.map +1 -0
- package/dist/dashboard-v2/index.js +54 -0
- package/dist/dashboard-v2/index.js.map +1 -0
- package/dist/dashboard-v2/lib/api.d.ts +95 -0
- package/dist/dashboard-v2/lib/api.d.ts.map +1 -0
- package/dist/dashboard-v2/lib/api.js +270 -0
- package/dist/dashboard-v2/lib/api.js.map +1 -0
- package/dist/dashboard-v2/lib/colors.d.ts +61 -0
- package/dist/dashboard-v2/lib/colors.d.ts.map +1 -0
- package/dist/dashboard-v2/lib/colors.js +198 -0
- package/dist/dashboard-v2/lib/colors.js.map +1 -0
- package/dist/dashboard-v2/lib/hierarchy.d.ts +74 -0
- package/dist/dashboard-v2/lib/hierarchy.d.ts.map +1 -0
- package/dist/dashboard-v2/lib/hierarchy.js +196 -0
- package/dist/dashboard-v2/lib/hierarchy.js.map +1 -0
- package/dist/dashboard-v2/types/index.d.ts +154 -0
- package/dist/dashboard-v2/types/index.d.ts.map +1 -0
- package/dist/dashboard-v2/types/index.js +6 -0
- package/dist/dashboard-v2/types/index.js.map +1 -0
- package/dist/storage/adapter.d.ts +21 -1
- package/dist/storage/adapter.d.ts.map +1 -1
- package/dist/storage/adapter.js +36 -0
- package/dist/storage/adapter.js.map +1 -1
- package/dist/storage/sqlite-adapter.d.ts +34 -0
- package/dist/storage/sqlite-adapter.d.ts.map +1 -1
- package/dist/storage/sqlite-adapter.js +253 -12
- package/dist/storage/sqlite-adapter.js.map +1 -1
- package/dist/utils/agent-config.d.ts +45 -0
- package/dist/utils/agent-config.d.ts.map +1 -0
- package/dist/utils/agent-config.js +118 -0
- package/dist/utils/agent-config.js.map +1 -0
- package/dist/utils/tmux-resolver.d.ts +55 -0
- package/dist/utils/tmux-resolver.d.ts.map +1 -0
- package/dist/utils/tmux-resolver.js +175 -0
- package/dist/utils/tmux-resolver.js.map +1 -0
- package/dist/wrapper/client.d.ts +8 -0
- package/dist/wrapper/client.d.ts.map +1 -1
- package/dist/wrapper/client.js +26 -0
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/parser.d.ts +17 -0
- package/dist/wrapper/parser.d.ts.map +1 -1
- package/dist/wrapper/parser.js +334 -10
- package/dist/wrapper/parser.js.map +1 -1
- package/dist/wrapper/tmux-wrapper.d.ts +38 -2
- package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
- package/dist/wrapper/tmux-wrapper.js +196 -32
- package/dist/wrapper/tmux-wrapper.js.map +1 -1
- package/docs/AGENTS.md +105 -0
- package/docs/ARCHITECTURE_DECISIONS.md +175 -0
- package/docs/COMPETITIVE_ANALYSIS.md +897 -0
- package/docs/DESIGN_BRIDGE_STAFFING.md +878 -0
- package/docs/MONETIZATION.md +1679 -0
- package/docs/agent-relay-snippet.md +61 -0
- package/docs/dashboard-v2-plan.md +179 -0
- package/package.json +8 -3
- package/scripts/dev/PUBLIC_RELEASE_PLAN.md +88 -0
- package/scripts/dev/dev-team-setup.sh +431 -0
- package/scripts/e2e-test.sh +119 -0
- package/scripts/games/game-protocol.md +79 -0
- package/scripts/games/hearts-setup.sh +264 -0
- package/scripts/postinstall.js +225 -0
- 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 ""
|