agent-relay 1.0.8 → 1.0.9
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 +158 -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 +46 -0
- package/dist/bridge/spawner.d.ts.map +1 -0
- package/dist/bridge/spawner.js +223 -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 +564 -5
- 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 +568 -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/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 +37 -2
- package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
- package/dist/wrapper/tmux-wrapper.js +178 -18
- 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 +5 -2
package/README.md
CHANGED
|
@@ -40,6 +40,7 @@ Agents communicate by outputting `->relay:` patterns:
|
|
|
40
40
|
| `agent-relay down` | Stop daemon |
|
|
41
41
|
| `agent-relay status` | Check if running |
|
|
42
42
|
| `agent-relay read <id>` | Read truncated message |
|
|
43
|
+
| `agent-relay bridge <projects...>` | Bridge multiple projects |
|
|
43
44
|
|
|
44
45
|
## How It Works
|
|
45
46
|
|
|
@@ -92,12 +93,121 @@ Long messages are truncated. Use the ID to read full content:
|
|
|
92
93
|
agent-relay read abc123
|
|
93
94
|
```
|
|
94
95
|
|
|
96
|
+
## Agent Roles
|
|
97
|
+
|
|
98
|
+
Agent names automatically match role definitions (case-insensitive):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# If .claude/agents/lead.md exists:
|
|
102
|
+
agent-relay -n Lead claude # matches lead.md
|
|
103
|
+
agent-relay -n LEAD claude # matches lead.md
|
|
104
|
+
agent-relay -n lead claude # matches lead.md
|
|
105
|
+
|
|
106
|
+
# Supported locations:
|
|
107
|
+
# - .claude/agents/<name>.md
|
|
108
|
+
# - .openagents/<name>.md
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Create role agents for your team:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
.claude/agents/
|
|
115
|
+
├── lead.md # Coordinator
|
|
116
|
+
├── implementer.md # Developer
|
|
117
|
+
├── designer.md # UI/UX
|
|
118
|
+
└── reviewer.md # Code review
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Multi-Project Orchestration
|
|
122
|
+
|
|
123
|
+
Bridge multiple projects with a single orchestrator:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Bridge projects (Architect mode)
|
|
127
|
+
agent-relay bridge ~/auth ~/frontend ~/api
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Workflow
|
|
131
|
+
|
|
132
|
+
1. **Start daemons** in each project: `agent-relay up`
|
|
133
|
+
2. **Start agents** in each project: `agent-relay -n Alice claude`
|
|
134
|
+
3. **Bridge** from anywhere: `agent-relay bridge ~/project1 ~/project2`
|
|
135
|
+
|
|
136
|
+
### Cross-Project Messaging
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
->relay:projectId:agent Message to specific agent
|
|
140
|
+
->relay:*:lead Broadcast to all project leads
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Spawn Agents
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
->relay:spawn Dev1 claude "Implement login endpoint"
|
|
147
|
+
->relay:release Dev1
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
See [docs/DESIGN_BRIDGE_STAFFING.md](docs/DESIGN_BRIDGE_STAFFING.md) for full details.
|
|
151
|
+
|
|
152
|
+
## Enabling AI Agents
|
|
153
|
+
|
|
154
|
+
To teach your AI agents how to use agent-relay, you have two options:
|
|
155
|
+
|
|
156
|
+
### Option 1: Install the Skill (Recommended)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
prpm install using-agent-relay
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This installs the `using-agent-relay` skill which provides agents with messaging patterns, coordination workflows, and troubleshooting guidance.
|
|
163
|
+
|
|
164
|
+
### Option 2: Copy AGENTS.md
|
|
165
|
+
|
|
166
|
+
Copy [docs/AGENTS.md](docs/AGENTS.md) to your project's agent instructions file (e.g., `CLAUDE.md`, `AGENTS.md`, or similar). This gives agents the messaging syntax and patterns they need.
|
|
167
|
+
|
|
95
168
|
## Dashboard
|
|
96
169
|
|
|
97
170
|
`agent-relay up` starts a web dashboard at http://localhost:3888
|
|
98
171
|
|
|
99
172
|

|
|
100
173
|
|
|
174
|
+
## REST API for Spawning Agents
|
|
175
|
+
|
|
176
|
+
The dashboard includes a REST API for programmatically spawning and managing agents.
|
|
177
|
+
|
|
178
|
+
### Endpoints
|
|
179
|
+
|
|
180
|
+
| Method | Endpoint | Description |
|
|
181
|
+
|--------|----------|-------------|
|
|
182
|
+
| `POST` | `/api/spawn` | Spawn a new agent |
|
|
183
|
+
| `GET` | `/api/spawned` | List spawned agents |
|
|
184
|
+
| `DELETE` | `/api/spawned/:name` | Release an agent |
|
|
185
|
+
|
|
186
|
+
### Examples
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Spawn an agent
|
|
190
|
+
curl -X POST http://localhost:3888/api/spawn \
|
|
191
|
+
-H "Content-Type: application/json" \
|
|
192
|
+
-d '{"name": "Dev1", "cli": "claude", "task": "Implement login"}'
|
|
193
|
+
|
|
194
|
+
# List spawned agents
|
|
195
|
+
curl http://localhost:3888/api/spawned
|
|
196
|
+
|
|
197
|
+
# Release an agent
|
|
198
|
+
curl -X DELETE http://localhost:3888/api/spawned/Dev1
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Response Format
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"success": true,
|
|
206
|
+
"name": "Dev1",
|
|
207
|
+
"window": "relay-workers:Dev1"
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
101
211
|
## Troubleshooting
|
|
102
212
|
|
|
103
213
|
| Issue | Solution |
|
|
@@ -114,6 +224,54 @@ cd agent-relay
|
|
|
114
224
|
npm install && npm run build
|
|
115
225
|
```
|
|
116
226
|
|
|
227
|
+
## Why agent-relay?
|
|
228
|
+
|
|
229
|
+
### The Composable Approach
|
|
230
|
+
|
|
231
|
+
Most multi-agent tools try to be complete solutions - handling communication, memory, UI, workflows, and orchestration. agent-relay takes a different approach: **do one thing exceptionally well** (real-time messaging) and integrate with best-of-breed tools for everything else.
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
235
|
+
│ Your Agent System │
|
|
236
|
+
├─────────────────────────────────────────────────────────────┤
|
|
237
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
238
|
+
│ │ Mimir │ │ Maestro │ │ Beads │ │
|
|
239
|
+
│ │ (Memory) │ │ (UI) │ │ (Workflows) │ │
|
|
240
|
+
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
|
241
|
+
│ └────────────────┼────────────────┘ │
|
|
242
|
+
│ ┌─────────▼─────────┐ │
|
|
243
|
+
│ │ agent-relay │ ◄── Messaging layer │
|
|
244
|
+
│ │ <5ms P2P │ │
|
|
245
|
+
│ └─────────┬─────────┘ │
|
|
246
|
+
│ ┌────────────────┼────────────────┐ │
|
|
247
|
+
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │
|
|
248
|
+
│ │ Claude │ │ Codex │ │ Gemini │ │
|
|
249
|
+
│ └─────────┘ └─────────┘ └─────────┘ │
|
|
250
|
+
└─────────────────────────────────────────────────────────────┘
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Unix Philosophy
|
|
254
|
+
|
|
255
|
+
- **Do one thing well**: Real-time agent messaging with <5ms latency
|
|
256
|
+
- **Work with others**: Simple `->relay:` pattern, standard I/O
|
|
257
|
+
- **Text streams**: Messages are just text, easy to parse/transform
|
|
258
|
+
- **Composability**: Pipe into other tools, wrap any CLI
|
|
259
|
+
|
|
260
|
+
### When to Use agent-relay
|
|
261
|
+
|
|
262
|
+
| Use Case | agent-relay? |
|
|
263
|
+
|----------|--------------|
|
|
264
|
+
| Quick prototyping with multiple agents | **Yes** - 1 min setup |
|
|
265
|
+
| Real-time agent collaboration | **Yes** - fastest option |
|
|
266
|
+
| CLI-native workflows | **Yes** - no Electron/desktop needed |
|
|
267
|
+
| Need persistent knowledge graph | Combine with Mimir |
|
|
268
|
+
| Need rich desktop UI | Combine with Maestro |
|
|
269
|
+
| Enterprise compliance | Combine with governance layer |
|
|
270
|
+
|
|
271
|
+
See [docs/COMPETITIVE_ANALYSIS.md](docs/COMPETITIVE_ANALYSIS.md) for detailed comparisons with 16 other multi-agent tools.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
117
275
|
## Inspiration
|
|
118
276
|
|
|
119
277
|
This project was inspired by some excellent work in the multi-agent coordination space:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Configuration
|
|
3
|
+
* Handles loading and resolving bridge configuration from files and CLI args.
|
|
4
|
+
*/
|
|
5
|
+
import type { ProjectConfig } from './types.js';
|
|
6
|
+
interface BridgeConfigFile {
|
|
7
|
+
projects?: Record<string, {
|
|
8
|
+
lead?: string;
|
|
9
|
+
cli?: string;
|
|
10
|
+
}>;
|
|
11
|
+
defaultCli?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Load bridge config from file
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadBridgeConfig(): BridgeConfigFile | null;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve project path (expand ~ and make absolute)
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolvePath(p: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Get default lead name from directory name
|
|
23
|
+
*/
|
|
24
|
+
export declare function getDefaultLeadName(projectPath: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve projects from CLI args and/or config file
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveProjects(cliPaths: string[], cliOverride?: string): ProjectConfig[];
|
|
29
|
+
/**
|
|
30
|
+
* Validate that daemons are running for all projects
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateDaemons(projects: ProjectConfig[]): {
|
|
33
|
+
valid: ProjectConfig[];
|
|
34
|
+
missing: ProjectConfig[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Start daemons for missing projects
|
|
38
|
+
*/
|
|
39
|
+
export declare function startMissingDaemons(projects: ProjectConfig[]): Promise<void>;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/bridge/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAC;AAO9D,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,gBAAgB,GAAG,IAAI,CAY1D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,WAAW,CAAC,EAAE,MAAM,GACnB,aAAa,EAAE,CAmDjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG;IAC1D,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B,CAaA;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,aAAa,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Configuration
|
|
3
|
+
* Handles loading and resolving bridge configuration from files and CLI args.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import { getProjectPaths } from '../utils/project-namespace.js';
|
|
9
|
+
const CONFIG_PATHS = [
|
|
10
|
+
path.join(os.homedir(), '.agent-relay', 'bridge.json'),
|
|
11
|
+
path.join(os.homedir(), '.config', 'agent-relay', 'bridge.json'),
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Load bridge config from file
|
|
15
|
+
*/
|
|
16
|
+
export function loadBridgeConfig() {
|
|
17
|
+
for (const configPath of CONFIG_PATHS) {
|
|
18
|
+
if (fs.existsSync(configPath)) {
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
console.error(`[bridge] Failed to parse ${configPath}:`, err);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve project path (expand ~ and make absolute)
|
|
32
|
+
*/
|
|
33
|
+
export function resolvePath(p) {
|
|
34
|
+
if (p.startsWith('~')) {
|
|
35
|
+
p = path.join(os.homedir(), p.slice(1));
|
|
36
|
+
}
|
|
37
|
+
return path.resolve(p);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get default lead name from directory name
|
|
41
|
+
*/
|
|
42
|
+
export function getDefaultLeadName(projectPath) {
|
|
43
|
+
const dirname = path.basename(projectPath);
|
|
44
|
+
// Capitalize first letter
|
|
45
|
+
return dirname.charAt(0).toUpperCase() + dirname.slice(1);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve projects from CLI args and/or config file
|
|
49
|
+
*/
|
|
50
|
+
export function resolveProjects(cliPaths, cliOverride) {
|
|
51
|
+
const config = loadBridgeConfig();
|
|
52
|
+
const projects = [];
|
|
53
|
+
// If CLI paths provided, use those
|
|
54
|
+
if (cliPaths.length > 0) {
|
|
55
|
+
for (const p of cliPaths) {
|
|
56
|
+
const projectPath = resolvePath(p);
|
|
57
|
+
if (!fs.existsSync(projectPath)) {
|
|
58
|
+
console.error(`[bridge] Project path does not exist: ${projectPath}`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const paths = getProjectPaths(projectPath);
|
|
62
|
+
// Check for project-specific config
|
|
63
|
+
const projectConfig = config?.projects?.[p] || config?.projects?.[projectPath];
|
|
64
|
+
projects.push({
|
|
65
|
+
path: projectPath,
|
|
66
|
+
id: paths.projectId,
|
|
67
|
+
socketPath: paths.socketPath,
|
|
68
|
+
leadName: projectConfig?.lead || getDefaultLeadName(projectPath),
|
|
69
|
+
cli: cliOverride || projectConfig?.cli || config?.defaultCli || 'claude',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Otherwise use config file
|
|
74
|
+
else if (config?.projects) {
|
|
75
|
+
for (const [p, projectConfig] of Object.entries(config.projects)) {
|
|
76
|
+
const projectPath = resolvePath(p);
|
|
77
|
+
if (!fs.existsSync(projectPath)) {
|
|
78
|
+
console.error(`[bridge] Project path does not exist: ${projectPath}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const paths = getProjectPaths(projectPath);
|
|
82
|
+
projects.push({
|
|
83
|
+
path: projectPath,
|
|
84
|
+
id: paths.projectId,
|
|
85
|
+
socketPath: paths.socketPath,
|
|
86
|
+
leadName: projectConfig.lead || getDefaultLeadName(projectPath),
|
|
87
|
+
cli: cliOverride || projectConfig.cli || config.defaultCli || 'claude',
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return projects;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Validate that daemons are running for all projects
|
|
95
|
+
*/
|
|
96
|
+
export function validateDaemons(projects) {
|
|
97
|
+
const valid = [];
|
|
98
|
+
const missing = [];
|
|
99
|
+
for (const project of projects) {
|
|
100
|
+
if (fs.existsSync(project.socketPath)) {
|
|
101
|
+
valid.push(project);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
missing.push(project);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { valid, missing };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Start daemons for missing projects
|
|
111
|
+
*/
|
|
112
|
+
export async function startMissingDaemons(projects) {
|
|
113
|
+
const { execAsync } = await import('./utils.js');
|
|
114
|
+
for (const project of projects) {
|
|
115
|
+
console.log(`[bridge] Starting daemon for ${project.id}...`);
|
|
116
|
+
try {
|
|
117
|
+
// Start daemon in background
|
|
118
|
+
await execAsync(`cd "${project.path}" && agent-relay up &`, {
|
|
119
|
+
timeout: 5000,
|
|
120
|
+
});
|
|
121
|
+
// Wait for socket to appear
|
|
122
|
+
await waitForSocket(project.socketPath, 10000);
|
|
123
|
+
console.log(`[bridge] Daemon started for ${project.id}`);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
console.error(`[bridge] Failed to start daemon for ${project.id}:`, err);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Wait for socket file to exist
|
|
132
|
+
*/
|
|
133
|
+
async function waitForSocket(socketPath, timeoutMs) {
|
|
134
|
+
const startTime = Date.now();
|
|
135
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
136
|
+
if (fs.existsSync(socketPath)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
await new Promise(r => setTimeout(r, 200));
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`Timeout waiting for socket: ${socketPath}`);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/bridge/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Module
|
|
3
|
+
* Multi-project orchestration for agent-relay
|
|
4
|
+
*/
|
|
5
|
+
export * from './types.js';
|
|
6
|
+
export * from './config.js';
|
|
7
|
+
export * from './multi-project-client.js';
|
|
8
|
+
export * from './spawner.js';
|
|
9
|
+
export * from './utils.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Module
|
|
3
|
+
* Multi-project orchestration for agent-relay
|
|
4
|
+
*/
|
|
5
|
+
export * from './types.js';
|
|
6
|
+
export * from './config.js';
|
|
7
|
+
export * from './multi-project-client.js';
|
|
8
|
+
export * from './spawner.js';
|
|
9
|
+
export * from './utils.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MultiProjectClient
|
|
3
|
+
* Connects to multiple project daemons simultaneously for cross-project orchestration.
|
|
4
|
+
*/
|
|
5
|
+
import { type SendPayload } from '../protocol/types.js';
|
|
6
|
+
import type { ProjectConfig } from './types.js';
|
|
7
|
+
interface MultiProjectClientOptions {
|
|
8
|
+
/** Agent name to register as (default: '__BridgeClient'). Must be unique per daemon. */
|
|
9
|
+
agentName?: string;
|
|
10
|
+
/** Enable automatic reconnection on disconnect (default: true) */
|
|
11
|
+
reconnect?: boolean;
|
|
12
|
+
/** Initial reconnection delay in ms (default: 1000) */
|
|
13
|
+
reconnectDelay?: number;
|
|
14
|
+
/** Maximum reconnection delay in ms (default: 30000) */
|
|
15
|
+
maxReconnectDelay?: number;
|
|
16
|
+
/** Maximum reconnection attempts before giving up (default: Infinity) */
|
|
17
|
+
maxReconnectAttempts?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class MultiProjectClient {
|
|
20
|
+
private projects;
|
|
21
|
+
private connections;
|
|
22
|
+
private leads;
|
|
23
|
+
private options;
|
|
24
|
+
private shuttingDown;
|
|
25
|
+
/** Handler for incoming messages */
|
|
26
|
+
onMessage?: (projectId: string, from: string, payload: SendPayload, messageId: string) => void;
|
|
27
|
+
/** Handler for connection state changes */
|
|
28
|
+
onProjectStateChange?: (projectId: string, connected: boolean) => void;
|
|
29
|
+
constructor(projects: ProjectConfig[], options?: MultiProjectClientOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Connect to all project daemons
|
|
32
|
+
*/
|
|
33
|
+
connect(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Connect to a single project daemon
|
|
36
|
+
*/
|
|
37
|
+
private connectToProject;
|
|
38
|
+
/**
|
|
39
|
+
* Send HELLO to a project daemon
|
|
40
|
+
*/
|
|
41
|
+
private sendHello;
|
|
42
|
+
/**
|
|
43
|
+
* Handle incoming data from a project connection
|
|
44
|
+
*/
|
|
45
|
+
private handleData;
|
|
46
|
+
/**
|
|
47
|
+
* Process a frame from a project daemon
|
|
48
|
+
*/
|
|
49
|
+
private processFrame;
|
|
50
|
+
/**
|
|
51
|
+
* Handle delivered message from a project
|
|
52
|
+
*/
|
|
53
|
+
private handleDeliver;
|
|
54
|
+
/**
|
|
55
|
+
* Send envelope to a project daemon
|
|
56
|
+
*/
|
|
57
|
+
private send;
|
|
58
|
+
/**
|
|
59
|
+
* Send message to a project
|
|
60
|
+
* @param projectId - Target project ID
|
|
61
|
+
* @param to - Agent name within the project (or '*' for broadcast, 'lead' for project lead)
|
|
62
|
+
* @param body - Message body
|
|
63
|
+
*/
|
|
64
|
+
sendToProject(projectId: string, to: string, body: string): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Broadcast to all leads
|
|
67
|
+
*/
|
|
68
|
+
broadcastToLeads(body: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* Broadcast to all agents in all projects
|
|
71
|
+
*/
|
|
72
|
+
broadcastAll(body: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Register a lead for a project
|
|
75
|
+
*/
|
|
76
|
+
registerLead(projectId: string, leadName: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Get all connected projects
|
|
79
|
+
*/
|
|
80
|
+
getConnectedProjects(): string[];
|
|
81
|
+
/**
|
|
82
|
+
* Get project connection info
|
|
83
|
+
*/
|
|
84
|
+
getProject(projectId: string): ProjectConfig | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Schedule a reconnection attempt with exponential backoff
|
|
87
|
+
*/
|
|
88
|
+
private scheduleReconnect;
|
|
89
|
+
/**
|
|
90
|
+
* Attempt to reconnect to a project daemon
|
|
91
|
+
*/
|
|
92
|
+
private attemptReconnect;
|
|
93
|
+
/**
|
|
94
|
+
* Disconnect from all projects
|
|
95
|
+
*/
|
|
96
|
+
disconnect(): void;
|
|
97
|
+
}
|
|
98
|
+
export {};
|
|
99
|
+
//# sourceMappingURL=multi-project-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-project-client.d.ts","sourceRoot":"","sources":["../../src/bridge/multi-project-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAIL,KAAK,WAAW,EAGjB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AAa1D,UAAU,yBAAyB;IACjC,wFAAwF;IACxF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,kBAAkB;IAYjB,OAAO,CAAC,QAAQ;IAX5B,OAAO,CAAC,WAAW,CAA6C;IAChE,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,OAAO,CAAiF;IAChG,OAAO,CAAC,YAAY,CAAS;IAE7B,oCAAoC;IACpC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAE/F,2CAA2C;IAC3C,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;gBAEnD,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,GAAE,yBAA8B;IAUtF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA8DxB;;OAEG;IACH,OAAO,CAAC,SAAS;IAqBjB;;OAEG;IACH,OAAO,CAAC,UAAU;IAWlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAwBpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAmBrB;;OAEG;IACH,OAAO,CAAC,IAAI;IAaZ;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAkCnE;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMpC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmBhC;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQvD;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAMhC;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIxD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmExB;;OAEG;IACH,UAAU,IAAI,IAAI;CAyBnB"}
|