agent-relay 2.1.0 → 2.1.2
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/dist/index.cjs +193 -63
- package/dist/src/cli/index.d.ts +11 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +112 -110
- package/dist/src/cli/index.js.map +1 -1
- package/package.json +18 -18
- package/packages/api-types/package.json +1 -1
- package/packages/benchmark/package.json +4 -4
- package/packages/bridge/package.json +8 -8
- package/packages/cli-tester/package.json +1 -1
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +2 -2
- package/packages/daemon/dist/connection.d.ts +5 -0
- package/packages/daemon/dist/connection.d.ts.map +1 -1
- package/packages/daemon/dist/connection.js +19 -1
- package/packages/daemon/dist/connection.js.map +1 -1
- package/packages/daemon/dist/server.js +2 -2
- package/packages/daemon/dist/server.js.map +1 -1
- package/packages/daemon/package.json +12 -12
- package/packages/daemon/src/connection.ts +22 -1
- package/packages/daemon/src/router.test.ts +32 -0
- package/packages/daemon/src/server.ts +2 -2
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +3 -3
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/dist/types.d.ts +5 -0
- package/packages/protocol/dist/types.d.ts.map +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/src/types.ts +5 -0
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/dist/client.d.ts +6 -0
- package/packages/sdk/dist/client.d.ts.map +1 -1
- package/packages/sdk/dist/client.js +1 -0
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/client.ts +7 -0
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/dist/cjs/relay-pty-path.js +111 -55
- package/packages/utils/dist/relay-pty-path.d.ts +17 -12
- package/packages/utils/dist/relay-pty-path.d.ts.map +1 -1
- package/packages/utils/dist/relay-pty-path.js +144 -94
- package/packages/utils/dist/relay-pty-path.js.map +1 -1
- package/packages/utils/package.json +2 -2
- package/packages/utils/src/relay-pty-path.test.ts +373 -0
- package/packages/utils/src/relay-pty-path.ts +182 -91
- package/packages/wrapper/dist/base-wrapper.d.ts +5 -0
- package/packages/wrapper/dist/base-wrapper.d.ts.map +1 -1
- package/packages/wrapper/dist/base-wrapper.js +14 -1
- package/packages/wrapper/dist/base-wrapper.js.map +1 -1
- package/packages/wrapper/dist/shared.d.ts +36 -0
- package/packages/wrapper/dist/shared.d.ts.map +1 -1
- package/packages/wrapper/dist/shared.js +123 -2
- package/packages/wrapper/dist/shared.js.map +1 -1
- package/packages/wrapper/dist/tmux-wrapper.js +1 -1
- package/packages/wrapper/dist/tmux-wrapper.js.map +1 -1
- package/packages/wrapper/package.json +6 -6
- package/packages/wrapper/src/base-wrapper.ts +15 -0
- package/packages/wrapper/src/shared.test.ts +156 -11
- package/packages/wrapper/src/shared.ts +154 -2
- package/packages/wrapper/src/tmux-wrapper.ts +1 -1
package/dist/src/cli/index.js
CHANGED
|
@@ -29,59 +29,9 @@ import readline from 'node:readline';
|
|
|
29
29
|
import { promisify } from 'node:util';
|
|
30
30
|
import { exec, spawn as spawnProcess } from 'node:child_process';
|
|
31
31
|
import { fileURLToPath } from 'node:url';
|
|
32
|
-
const RELAY_DASHBOARD_REPO = 'https://github.com/AgentWorkforce/relay-dashboard';
|
|
33
|
-
/**
|
|
34
|
-
* Prompt user to choose how to handle missing dashboard package.
|
|
35
|
-
* Returns: 'npx' | 'install' | 'skip'
|
|
36
|
-
*/
|
|
37
|
-
async function promptDashboardInstall() {
|
|
38
|
-
const rl = readline.createInterface({
|
|
39
|
-
input: process.stdin,
|
|
40
|
-
output: process.stdout,
|
|
41
|
-
});
|
|
42
|
-
console.log(`
|
|
43
|
-
The web dashboard requires @agent-relay/dashboard-server package.
|
|
44
|
-
|
|
45
|
-
How would you like to proceed?
|
|
46
|
-
1. Start with npx (recommended - auto-installs temporarily)
|
|
47
|
-
2. View installation instructions
|
|
48
|
-
3. Skip and continue without dashboard
|
|
49
|
-
`);
|
|
50
|
-
return new Promise((resolve) => {
|
|
51
|
-
rl.question('Choose [1/2/3]: ', (answer) => {
|
|
52
|
-
rl.close();
|
|
53
|
-
const choice = answer.trim();
|
|
54
|
-
if (choice === '1') {
|
|
55
|
-
resolve('npx');
|
|
56
|
-
}
|
|
57
|
-
else if (choice === '2') {
|
|
58
|
-
resolve('install');
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
resolve('skip');
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Show instructions for installing the external dashboard package.
|
|
68
|
-
*/
|
|
69
|
-
function showDashboardInstallInstructions() {
|
|
70
|
-
console.log(`
|
|
71
|
-
To install the dashboard, run:
|
|
72
|
-
|
|
73
|
-
npm install @agent-relay/dashboard-server @agent-relay/dashboard
|
|
74
|
-
|
|
75
|
-
Then restart with:
|
|
76
|
-
|
|
77
|
-
agent-relay up --dashboard
|
|
78
|
-
|
|
79
|
-
For more options, see: ${RELAY_DASHBOARD_REPO}
|
|
80
|
-
`);
|
|
81
|
-
}
|
|
82
32
|
/**
|
|
83
33
|
* Start dashboard via npx (downloads and runs if not installed).
|
|
84
|
-
* Returns the spawned child process and
|
|
34
|
+
* Returns the spawned child process, port, and a promise that resolves when ready.
|
|
85
35
|
*/
|
|
86
36
|
function startDashboardViaNpx(options) {
|
|
87
37
|
console.log('Starting dashboard via npx (this may take a moment on first run)...');
|
|
@@ -100,10 +50,21 @@ function startDashboardViaNpx(options) {
|
|
|
100
50
|
// Pass any additional env vars needed
|
|
101
51
|
},
|
|
102
52
|
});
|
|
53
|
+
// Promise that resolves when dashboard is ready (or after timeout)
|
|
54
|
+
let resolveReady;
|
|
55
|
+
const ready = new Promise((resolve) => {
|
|
56
|
+
resolveReady = resolve;
|
|
57
|
+
// Fallback timeout in case we miss the ready signal
|
|
58
|
+
setTimeout(resolve, 30000);
|
|
59
|
+
});
|
|
103
60
|
// Forward dashboard output with prefix
|
|
104
61
|
dashboardProcess.stdout?.on('data', (data) => {
|
|
105
62
|
const lines = data.toString().split('\n').filter(Boolean);
|
|
106
63
|
for (const line of lines) {
|
|
64
|
+
// Detect when dashboard is ready (listening message)
|
|
65
|
+
if (line.includes('Dashboard:') || line.includes('listening') || line.includes('ready')) {
|
|
66
|
+
resolveReady();
|
|
67
|
+
}
|
|
107
68
|
// Don't duplicate the "Dashboard:" line
|
|
108
69
|
if (!line.includes('Dashboard:')) {
|
|
109
70
|
console.log(`[dashboard] ${line}`);
|
|
@@ -118,13 +79,56 @@ function startDashboardViaNpx(options) {
|
|
|
118
79
|
});
|
|
119
80
|
dashboardProcess.on('error', (err) => {
|
|
120
81
|
console.error('Failed to start dashboard via npx:', err.message);
|
|
82
|
+
resolveReady(); // Resolve to not block forever
|
|
121
83
|
});
|
|
122
84
|
dashboardProcess.on('exit', (code) => {
|
|
85
|
+
resolveReady(); // Resolve on exit to not block forever
|
|
123
86
|
if (code !== 0 && code !== null) {
|
|
124
87
|
console.error(`Dashboard process exited with code ${code}`);
|
|
125
88
|
}
|
|
126
89
|
});
|
|
127
|
-
return { process: dashboardProcess, port: options.port };
|
|
90
|
+
return { process: dashboardProcess, port: options.port, ready };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Install agent-relay-snippet to markdown files using prpm.
|
|
94
|
+
* Installs to CLAUDE.md, GEMINI.md, and AGENTS.md.
|
|
95
|
+
* prpm handles idempotency - won't duplicate if already installed.
|
|
96
|
+
*/
|
|
97
|
+
export async function installRelaySnippets(options) {
|
|
98
|
+
const execAsync = promisify(exec);
|
|
99
|
+
const installed = [];
|
|
100
|
+
const targets = [
|
|
101
|
+
{ location: 'CLAUDE.md', name: 'CLAUDE.md' },
|
|
102
|
+
{ location: 'GEMINI.md', name: 'GEMINI.md' },
|
|
103
|
+
{ location: undefined, name: 'AGENTS.md' }, // Default location
|
|
104
|
+
];
|
|
105
|
+
for (const target of targets) {
|
|
106
|
+
try {
|
|
107
|
+
const args = ['npx', 'prpm', 'install', '@agent-relay/agent-relay-snippet'];
|
|
108
|
+
if (target.location) {
|
|
109
|
+
args.push('--location', target.location);
|
|
110
|
+
}
|
|
111
|
+
await execAsync(args.join(' '), { timeout: 60000 });
|
|
112
|
+
installed.push(target.name);
|
|
113
|
+
if (!options?.silent) {
|
|
114
|
+
console.log(` ✓ Installed to ${target.name}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
// prpm exits with error if already installed or other issues
|
|
119
|
+
// Check if it's an "already exists" situation by looking at stderr
|
|
120
|
+
if (err.stderr?.includes('already') || err.stdout?.includes('already')) {
|
|
121
|
+
if (!options?.silent) {
|
|
122
|
+
console.log(` ✓ ${target.name} (already installed)`);
|
|
123
|
+
}
|
|
124
|
+
installed.push(target.name);
|
|
125
|
+
}
|
|
126
|
+
else if (!options?.silent) {
|
|
127
|
+
console.error(` ⚠ Failed to install to ${target.name}: ${err.message}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { success: installed.length > 0, installed };
|
|
128
132
|
}
|
|
129
133
|
dotenvConfig();
|
|
130
134
|
const DEFAULT_DASHBOARD_PORT = process.env.AGENT_RELAY_DASHBOARD_PORT || '3888';
|
|
@@ -465,6 +469,36 @@ program
|
|
|
465
469
|
const socketPath = paths.socketPath;
|
|
466
470
|
const dbPath = paths.dbPath;
|
|
467
471
|
const pidFilePath = pidFilePathForSocket(socketPath);
|
|
472
|
+
// Auto-install relay protocol snippets if not already present
|
|
473
|
+
// Check if the snippet marker exists in any of the target files
|
|
474
|
+
const snippetTargets = ['CLAUDE.md', 'GEMINI.md', 'AGENTS.md'];
|
|
475
|
+
const snippetMarker = '<!-- prpm:snippet:start @agent-relay/agent-relay-snippet';
|
|
476
|
+
const hasSnippetInstalled = snippetTargets.some(file => {
|
|
477
|
+
const filePath = path.join(paths.projectRoot, file);
|
|
478
|
+
if (!fs.existsSync(filePath))
|
|
479
|
+
return false;
|
|
480
|
+
try {
|
|
481
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
482
|
+
return content.includes(snippetMarker);
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
if (!hasSnippetInstalled) {
|
|
489
|
+
console.log('Installing relay protocol snippets...');
|
|
490
|
+
try {
|
|
491
|
+
const result = await installRelaySnippets({ silent: false });
|
|
492
|
+
if (result.success) {
|
|
493
|
+
console.log(`Installed snippets to: ${result.installed.join(', ')}`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
catch (err) {
|
|
497
|
+
// Non-fatal - continue even if snippet install fails
|
|
498
|
+
console.log(`Note: Could not auto-install snippets: ${err.message}`);
|
|
499
|
+
}
|
|
500
|
+
console.log('');
|
|
501
|
+
}
|
|
468
502
|
// Set up log file to avoid console output polluting TUI terminals
|
|
469
503
|
// Only set if not already configured via environment
|
|
470
504
|
if (!process.env.AGENT_RELAY_LOG_FILE) {
|
|
@@ -578,60 +612,27 @@ program
|
|
|
578
612
|
if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND') {
|
|
579
613
|
// Dashboard package not installed
|
|
580
614
|
if (dashboardRequested) {
|
|
581
|
-
// User explicitly asked for dashboard but it's not installed
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
dashboardPort = npxPort;
|
|
595
|
-
// Clean up dashboard process on exit
|
|
596
|
-
const cleanupDashboard = () => {
|
|
597
|
-
if (dashboardProcess && !dashboardProcess.killed) {
|
|
598
|
-
dashboardProcess.kill('SIGTERM');
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
process.on('SIGINT', cleanupDashboard);
|
|
602
|
-
process.on('SIGTERM', cleanupDashboard);
|
|
603
|
-
process.on('exit', cleanupDashboard);
|
|
604
|
-
// Wait a moment for dashboard to start
|
|
605
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
606
|
-
console.log(`Dashboard: http://localhost:${dashboardPort}`);
|
|
615
|
+
// User explicitly asked for dashboard but it's not installed - start via npx
|
|
616
|
+
console.log('Dashboard package not installed. Starting via npx...');
|
|
617
|
+
const { process: dashboardProcess, port: npxPort, ready } = startDashboardViaNpx({
|
|
618
|
+
port,
|
|
619
|
+
dataDir: paths.dataDir,
|
|
620
|
+
teamDir: paths.teamDir,
|
|
621
|
+
projectRoot: paths.projectRoot,
|
|
622
|
+
});
|
|
623
|
+
dashboardPort = npxPort;
|
|
624
|
+
// Clean up dashboard process on exit
|
|
625
|
+
const cleanupDashboard = () => {
|
|
626
|
+
if (dashboardProcess && !dashboardProcess.killed) {
|
|
627
|
+
dashboardProcess.kill('SIGTERM');
|
|
607
628
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const { process: dashboardProcess, port: npxPort } = startDashboardViaNpx({
|
|
616
|
-
port,
|
|
617
|
-
dataDir: paths.dataDir,
|
|
618
|
-
teamDir: paths.teamDir,
|
|
619
|
-
projectRoot: paths.projectRoot,
|
|
620
|
-
});
|
|
621
|
-
dashboardPort = npxPort;
|
|
622
|
-
// Clean up dashboard process on exit
|
|
623
|
-
const cleanupDashboard = () => {
|
|
624
|
-
if (dashboardProcess && !dashboardProcess.killed) {
|
|
625
|
-
dashboardProcess.kill('SIGTERM');
|
|
626
|
-
}
|
|
627
|
-
};
|
|
628
|
-
process.on('SIGINT', cleanupDashboard);
|
|
629
|
-
process.on('SIGTERM', cleanupDashboard);
|
|
630
|
-
process.on('exit', cleanupDashboard);
|
|
631
|
-
// Wait a moment for dashboard to start
|
|
632
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
633
|
-
console.log(`Dashboard: http://localhost:${dashboardPort}`);
|
|
634
|
-
}
|
|
629
|
+
};
|
|
630
|
+
process.on('SIGINT', cleanupDashboard);
|
|
631
|
+
process.on('SIGTERM', cleanupDashboard);
|
|
632
|
+
process.on('exit', cleanupDashboard);
|
|
633
|
+
// Wait for dashboard to be ready
|
|
634
|
+
await ready;
|
|
635
|
+
console.log(`Dashboard: http://localhost:${dashboardPort}`);
|
|
635
636
|
}
|
|
636
637
|
// Silent if user didn't explicitly request dashboard
|
|
637
638
|
}
|
|
@@ -3155,10 +3156,11 @@ async function runInit(options) {
|
|
|
3155
3156
|
console.log(' ○ Daemon is not running');
|
|
3156
3157
|
}
|
|
3157
3158
|
console.log('');
|
|
3158
|
-
// Step
|
|
3159
|
+
// Step 1: Install MCP for editors (only if RELAY_MCP_AUTO_INSTALL=1)
|
|
3159
3160
|
let mcpInstalled = false;
|
|
3160
|
-
|
|
3161
|
-
|
|
3161
|
+
const mcpAutoInstallEnabled = process.env.RELAY_MCP_AUTO_INSTALL === '1';
|
|
3162
|
+
if (!options.skipMcp && mcpAutoInstallEnabled) {
|
|
3163
|
+
console.log(' ┌─ MCP Server for AI Editors ───────────────────────────────┐');
|
|
3162
3164
|
console.log(' │ │');
|
|
3163
3165
|
console.log(' │ MCP (Model Context Protocol) gives AI editors native │');
|
|
3164
3166
|
console.log(' │ tools for agent communication: │');
|
|
@@ -3193,9 +3195,9 @@ async function runInit(options) {
|
|
|
3193
3195
|
console.log('');
|
|
3194
3196
|
}
|
|
3195
3197
|
}
|
|
3196
|
-
//
|
|
3198
|
+
// Start daemon
|
|
3197
3199
|
if (!daemonRunning && !options.skipDaemon) {
|
|
3198
|
-
console.log(' ┌─
|
|
3200
|
+
console.log(' ┌─ Start the Relay Daemon ──────────────────────────────────┐');
|
|
3199
3201
|
console.log(' │ │');
|
|
3200
3202
|
console.log(' │ The daemon manages agent connections and message │');
|
|
3201
3203
|
console.log(' │ routing. It runs in the background. │');
|