agent-relay 2.1.9 → 2.1.10
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 +33 -17
- package/dist/src/cli/index.d.ts +7 -4
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +110 -182
- package/dist/src/cli/index.js.map +1 -1
- package/install.sh +64 -4
- 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/server.d.ts.map +1 -1
- package/packages/daemon/dist/server.js +10 -2
- package/packages/daemon/dist/server.js.map +1 -1
- package/packages/daemon/dist/spawn-manager.d.ts.map +1 -1
- package/packages/daemon/dist/spawn-manager.js +3 -0
- package/packages/daemon/dist/spawn-manager.js.map +1 -1
- package/packages/daemon/package.json +12 -12
- package/packages/daemon/src/server.ts +9 -2
- package/packages/daemon/src/spawn-manager.ts +3 -0
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/dist/types.d.ts +6 -0
- package/packages/protocol/dist/types.d.ts.map +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/src/types.ts +6 -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 +6 -0
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/package.json +3 -3
- package/packages/sdk/src/client.test.ts +48 -0
- package/packages/sdk/src/client.ts +9 -0
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/dist/adapter.js +1 -1
- package/packages/storage/dist/adapter.js.map +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/storage/src/adapter.ts +1 -1
- 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/logger.js +20 -11
- package/packages/utils/dist/logger.d.ts.map +1 -1
- package/packages/utils/dist/logger.js +24 -14
- package/packages/utils/dist/logger.js.map +1 -1
- package/packages/utils/package.json +3 -3
- package/packages/utils/src/logger.ts +27 -14
- package/packages/wrapper/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -3078,11 +3078,27 @@ var init_dist = __esm({
|
|
|
3078
3078
|
});
|
|
3079
3079
|
|
|
3080
3080
|
// packages/utils/dist/logger.js
|
|
3081
|
+
function getLogFile() {
|
|
3082
|
+
return process.env.AGENT_RELAY_LOG_FILE;
|
|
3083
|
+
}
|
|
3084
|
+
function getLogLevel() {
|
|
3085
|
+
return (process.env.AGENT_RELAY_LOG_LEVEL ?? "INFO").toUpperCase();
|
|
3086
|
+
}
|
|
3087
|
+
function isLogJson() {
|
|
3088
|
+
return process.env.AGENT_RELAY_LOG_JSON === "1";
|
|
3089
|
+
}
|
|
3090
|
+
function ensureLogDir(logFile) {
|
|
3091
|
+
const logDir = import_node_path12.default.dirname(logFile);
|
|
3092
|
+
if (!createdLogDirs.has(logDir) && !import_node_fs9.default.existsSync(logDir)) {
|
|
3093
|
+
import_node_fs9.default.mkdirSync(logDir, { recursive: true });
|
|
3094
|
+
createdLogDirs.add(logDir);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3081
3097
|
function shouldLog(level) {
|
|
3082
|
-
return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[
|
|
3098
|
+
return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[getLogLevel()];
|
|
3083
3099
|
}
|
|
3084
3100
|
function formatMessage(entry) {
|
|
3085
|
-
if (
|
|
3101
|
+
if (isLogJson()) {
|
|
3086
3102
|
return JSON.stringify(entry);
|
|
3087
3103
|
}
|
|
3088
3104
|
const { ts, level, component, msg, ...extra } = entry;
|
|
@@ -3100,8 +3116,10 @@ function log(level, component, msg, extra) {
|
|
|
3100
3116
|
...extra
|
|
3101
3117
|
};
|
|
3102
3118
|
const formatted = formatMessage(entry);
|
|
3103
|
-
|
|
3104
|
-
|
|
3119
|
+
const logFile = getLogFile();
|
|
3120
|
+
if (logFile) {
|
|
3121
|
+
ensureLogDir(logFile);
|
|
3122
|
+
import_node_fs9.default.appendFileSync(logFile, formatted + "\n");
|
|
3105
3123
|
return;
|
|
3106
3124
|
}
|
|
3107
3125
|
if (level === "ERROR" || level === "WARN") {
|
|
@@ -3118,28 +3136,19 @@ function createLogger2(component) {
|
|
|
3118
3136
|
error: (msg, extra) => log("ERROR", component, msg, extra)
|
|
3119
3137
|
};
|
|
3120
3138
|
}
|
|
3121
|
-
var import_node_fs9, import_node_path12,
|
|
3139
|
+
var import_node_fs9, import_node_path12, LEVEL_PRIORITY, createdLogDirs, daemonLog, routerLog, connectionLog;
|
|
3122
3140
|
var init_logger = __esm({
|
|
3123
3141
|
"packages/utils/dist/logger.js"() {
|
|
3124
3142
|
"use strict";
|
|
3125
3143
|
import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
3126
3144
|
import_node_path12 = __toESM(require("node:path"), 1);
|
|
3127
|
-
LOG_FILE = process.env.AGENT_RELAY_LOG_FILE;
|
|
3128
|
-
LOG_LEVEL = (process.env.AGENT_RELAY_LOG_LEVEL ?? "INFO").toUpperCase();
|
|
3129
|
-
LOG_JSON = process.env.AGENT_RELAY_LOG_JSON === "1";
|
|
3130
|
-
_DEBUG = process.env.DEBUG === "1" || LOG_LEVEL === "DEBUG";
|
|
3131
3145
|
LEVEL_PRIORITY = {
|
|
3132
3146
|
DEBUG: 0,
|
|
3133
3147
|
INFO: 1,
|
|
3134
3148
|
WARN: 2,
|
|
3135
3149
|
ERROR: 3
|
|
3136
3150
|
};
|
|
3137
|
-
|
|
3138
|
-
const logDir = import_node_path12.default.dirname(LOG_FILE);
|
|
3139
|
-
if (!import_node_fs9.default.existsSync(logDir)) {
|
|
3140
|
-
import_node_fs9.default.mkdirSync(logDir, { recursive: true });
|
|
3141
|
-
}
|
|
3142
|
-
}
|
|
3151
|
+
createdLogDirs = /* @__PURE__ */ new Set();
|
|
3143
3152
|
daemonLog = createLogger2("daemon");
|
|
3144
3153
|
routerLog = createLogger2("router");
|
|
3145
3154
|
connectionLog = createLogger2("connection");
|
|
@@ -70197,7 +70206,10 @@ var SpawnManager = class {
|
|
|
70197
70206
|
cwd: payload.cwd,
|
|
70198
70207
|
spawnerName: payload.spawnerName ?? spawnerName,
|
|
70199
70208
|
interactive: payload.interactive,
|
|
70209
|
+
shadowMode: payload.shadowMode,
|
|
70200
70210
|
shadowOf: payload.shadowOf,
|
|
70211
|
+
shadowAgent: payload.shadowAgent,
|
|
70212
|
+
shadowTriggers: payload.shadowTriggers,
|
|
70201
70213
|
shadowSpeakOn: payload.shadowSpeakOn,
|
|
70202
70214
|
userId: payload.userId,
|
|
70203
70215
|
includeWorkflowConventions: payload.includeWorkflowConventions
|
|
@@ -70523,7 +70535,6 @@ async function createStorageAdapter(dbPath, config2) {
|
|
|
70523
70535
|
case "jsonl": {
|
|
70524
70536
|
const { JsonlStorageAdapter: JsonlStorageAdapter2 } = await Promise.resolve().then(() => (init_jsonl_adapter(), jsonl_adapter_exports));
|
|
70525
70537
|
const baseDir = import_node_path23.default.dirname(finalConfig.path);
|
|
70526
|
-
console.error("[storage] Using JSONL storage");
|
|
70527
70538
|
const adapter = new JsonlStorageAdapter2({
|
|
70528
70539
|
baseDir,
|
|
70529
70540
|
watchForChanges: finalConfig.watchForChanges
|
|
@@ -72650,7 +72661,12 @@ var Daemon = class _Daemon {
|
|
|
72650
72661
|
this.config.pidFilePath = `${config2.socketPath}.pid`;
|
|
72651
72662
|
}
|
|
72652
72663
|
if (!this.config.teamDir) {
|
|
72653
|
-
|
|
72664
|
+
const socketDir = import_node_path25.default.dirname(this.config.socketPath);
|
|
72665
|
+
if (socketDir === "/tmp" || socketDir === "/private/tmp") {
|
|
72666
|
+
this.config.teamDir = import_node_path25.default.join(socketDir, "agent-relay-state");
|
|
72667
|
+
} else {
|
|
72668
|
+
this.config.teamDir = socketDir;
|
|
72669
|
+
}
|
|
72654
72670
|
}
|
|
72655
72671
|
if (this.config.teamDir) {
|
|
72656
72672
|
this.registry = new AgentRegistry(this.config.teamDir);
|
package/dist/src/cli/index.d.ts
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
* Agent Relay CLI
|
|
4
4
|
*
|
|
5
5
|
* Commands:
|
|
6
|
-
* relay
|
|
7
|
-
* relay
|
|
6
|
+
* relay up - Start daemon
|
|
7
|
+
* relay up --dashboard - Start daemon with web dashboard
|
|
8
8
|
* relay create-agent <cmd> - Wrap agent with real-time messaging
|
|
9
9
|
* relay create-agent -n Name cmd - Wrap with specific agent name
|
|
10
|
-
* relay
|
|
11
|
-
* relay
|
|
10
|
+
* relay spawn <name> <cli> - Spawn a new agent
|
|
11
|
+
* relay release <name> - Release an agent
|
|
12
12
|
* relay agents - List connected agents
|
|
13
13
|
* relay who - Show currently active agents
|
|
14
|
+
* relay read <id> - Read full message by ID
|
|
15
|
+
* relay status - Check daemon status
|
|
16
|
+
* relay down - Stop daemon
|
|
14
17
|
*/
|
|
15
18
|
/**
|
|
16
19
|
* Install agent-relay-snippet to markdown files using prpm.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AA8JH;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqC7H"}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
* Agent Relay CLI
|
|
4
4
|
*
|
|
5
5
|
* Commands:
|
|
6
|
-
* relay
|
|
7
|
-
* relay
|
|
6
|
+
* relay up - Start daemon
|
|
7
|
+
* relay up --dashboard - Start daemon with web dashboard
|
|
8
8
|
* relay create-agent <cmd> - Wrap agent with real-time messaging
|
|
9
9
|
* relay create-agent -n Name cmd - Wrap with specific agent name
|
|
10
|
-
* relay
|
|
11
|
-
* relay
|
|
10
|
+
* relay spawn <name> <cli> - Spawn a new agent
|
|
11
|
+
* relay release <name> - Release an agent
|
|
12
12
|
* relay agents - List connected agents
|
|
13
13
|
* relay who - Show currently active agents
|
|
14
|
+
* relay read <id> - Read full message by ID
|
|
15
|
+
* relay status - Check daemon status
|
|
16
|
+
* relay down - Stop daemon
|
|
14
17
|
*/
|
|
15
18
|
import { Command } from 'commander';
|
|
16
19
|
import { config as dotenvConfig } from 'dotenv';
|
|
@@ -82,6 +85,9 @@ function startDashboardViaNpx(options) {
|
|
|
82
85
|
'--team-dir', options.teamDir,
|
|
83
86
|
'--project-root', options.projectRoot,
|
|
84
87
|
];
|
|
88
|
+
if (options.verbose) {
|
|
89
|
+
args.push('--verbose');
|
|
90
|
+
}
|
|
85
91
|
if (dashboardBinary) {
|
|
86
92
|
console.log(`Starting dashboard using binary: ${dashboardBinary}`);
|
|
87
93
|
dashboardProcess = spawnProcess(dashboardBinary, args, {
|
|
@@ -180,7 +186,7 @@ export async function installRelaySnippets(options) {
|
|
|
180
186
|
}
|
|
181
187
|
return { success: installed.length > 0, installed };
|
|
182
188
|
}
|
|
183
|
-
dotenvConfig();
|
|
189
|
+
dotenvConfig({ quiet: true });
|
|
184
190
|
const DEFAULT_DASHBOARD_PORT = process.env.AGENT_RELAY_DASHBOARD_PORT || '3888';
|
|
185
191
|
// Read version from package.json
|
|
186
192
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -463,6 +469,7 @@ program
|
|
|
463
469
|
.option('--no-spawn', 'Do not auto-spawn agents (just start daemon)')
|
|
464
470
|
.option('--watch', 'Auto-restart daemon on crash (supervisor mode)')
|
|
465
471
|
.option('--max-restarts <n>', 'Max restarts in 60s before giving up (default: 5)', '5')
|
|
472
|
+
.option('--verbose', 'Enable verbose logging (show debug output in console)')
|
|
466
473
|
.action(async (options) => {
|
|
467
474
|
// If --watch is specified, run in supervisor mode
|
|
468
475
|
if (options.watch) {
|
|
@@ -485,6 +492,8 @@ program
|
|
|
485
492
|
args.push('--spawn');
|
|
486
493
|
if (options.spawn === false)
|
|
487
494
|
args.push('--no-spawn');
|
|
495
|
+
if (options.verbose)
|
|
496
|
+
args.push('--verbose');
|
|
488
497
|
console.log(`[supervisor] Starting daemon...`);
|
|
489
498
|
child = spawnProcess(process.execPath, [process.argv[1], ...args], {
|
|
490
499
|
stdio: 'inherit',
|
|
@@ -562,10 +571,15 @@ program
|
|
|
562
571
|
}
|
|
563
572
|
// Set up log file to avoid console output polluting TUI terminals
|
|
564
573
|
// Only set if not already configured via environment
|
|
565
|
-
if (
|
|
574
|
+
// Skip if --verbose is set (logs go to console in verbose mode)
|
|
575
|
+
if (!process.env.AGENT_RELAY_LOG_FILE && !options.verbose) {
|
|
566
576
|
const logFile = path.join(paths.dataDir, 'daemon.log');
|
|
567
577
|
process.env.AGENT_RELAY_LOG_FILE = logFile;
|
|
568
578
|
}
|
|
579
|
+
// In verbose mode, also set DEBUG level for more detailed output
|
|
580
|
+
if (options.verbose && !process.env.AGENT_RELAY_LOG_LEVEL) {
|
|
581
|
+
process.env.AGENT_RELAY_LOG_LEVEL = 'DEBUG';
|
|
582
|
+
}
|
|
569
583
|
console.log(`Project: ${paths.projectRoot}`);
|
|
570
584
|
console.log(`Socket: ${socketPath}`);
|
|
571
585
|
// Load teams.json if present
|
|
@@ -659,6 +673,7 @@ program
|
|
|
659
673
|
enableSpawner: true,
|
|
660
674
|
onMarkSpawning: (name) => daemon.markSpawning(name),
|
|
661
675
|
onClearSpawning: (name) => daemon.clearSpawning(name),
|
|
676
|
+
verbose: options.verbose,
|
|
662
677
|
});
|
|
663
678
|
console.log(`Dashboard: http://localhost:${dashboardPort}`);
|
|
664
679
|
// Hook daemon log output to dashboard WebSocket broadcast
|
|
@@ -671,15 +686,15 @@ program
|
|
|
671
686
|
}
|
|
672
687
|
catch (err) {
|
|
673
688
|
if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND') {
|
|
674
|
-
// Dashboard package not installed
|
|
689
|
+
// Dashboard package not installed as a dependency - use binary or npx fallback
|
|
675
690
|
if (dashboardRequested) {
|
|
676
|
-
// User explicitly asked for dashboard
|
|
677
|
-
console.log('Dashboard package not installed. Starting via npx...');
|
|
691
|
+
// User explicitly asked for dashboard - start via binary or npx
|
|
678
692
|
const { process: dashboardProcess, port: npxPort, ready } = startDashboardViaNpx({
|
|
679
693
|
port,
|
|
680
694
|
dataDir: paths.dataDir,
|
|
681
695
|
teamDir: paths.teamDir,
|
|
682
696
|
projectRoot: paths.projectRoot,
|
|
697
|
+
verbose: options.verbose,
|
|
683
698
|
});
|
|
684
699
|
dashboardPort = npxPort;
|
|
685
700
|
// Clean up dashboard process on exit
|
|
@@ -941,152 +956,6 @@ program
|
|
|
941
956
|
}
|
|
942
957
|
}
|
|
943
958
|
});
|
|
944
|
-
// System prompt for Dashboard agent - plain text to avoid shell escaping issues
|
|
945
|
-
const MEGA_SYSTEM_PROMPT = [
|
|
946
|
-
'You are Dashboard, a lead coordinator in agent-relay.',
|
|
947
|
-
'Your PRIMARY job is to delegate - you should almost NEVER do implementation work yourself.',
|
|
948
|
-
'ALWAYS SPAWN AGENTS: For any non-trivial task, spawn specialized workers.',
|
|
949
|
-
].join(' ');
|
|
950
|
-
// Helper function for starting Dashboard coordinator with a specific provider
|
|
951
|
-
async function startDashboardCoordinator(operator) {
|
|
952
|
-
const paths = getProjectPaths();
|
|
953
|
-
console.log(`Starting Dashboard with ${operator}...`);
|
|
954
|
-
console.log(`Project: ${paths.projectRoot}`);
|
|
955
|
-
// Step 1: Check if daemon is already running, start if needed
|
|
956
|
-
console.log('\n[1/3] Checking daemon...');
|
|
957
|
-
// Check if socket exists (daemon running)
|
|
958
|
-
const socketExists = fs.existsSync(paths.socketPath);
|
|
959
|
-
// Ports to try for dashboard detection
|
|
960
|
-
const portsToTry = [
|
|
961
|
-
parseInt(DEFAULT_DASHBOARD_PORT, 10),
|
|
962
|
-
3889, 3890, 3891,
|
|
963
|
-
];
|
|
964
|
-
// Check if dashboard is responding for THIS project
|
|
965
|
-
let dashboardReady = false;
|
|
966
|
-
let detectedPort;
|
|
967
|
-
// Helper to check health at a port
|
|
968
|
-
const checkPort = async (port) => {
|
|
969
|
-
try {
|
|
970
|
-
const response = await fetch(`http://localhost:${port}/api/health`, {
|
|
971
|
-
signal: AbortSignal.timeout(500),
|
|
972
|
-
});
|
|
973
|
-
if (response.ok) {
|
|
974
|
-
const health = await response.json();
|
|
975
|
-
return health.status === 'healthy';
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
catch {
|
|
979
|
-
// Port not responding
|
|
980
|
-
}
|
|
981
|
-
return false;
|
|
982
|
-
};
|
|
983
|
-
if (socketExists) {
|
|
984
|
-
for (const port of portsToTry) {
|
|
985
|
-
if (await checkPort(port)) {
|
|
986
|
-
dashboardReady = true;
|
|
987
|
-
detectedPort = port;
|
|
988
|
-
break;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (dashboardReady && detectedPort) {
|
|
993
|
-
console.log(`Daemon already running at port ${detectedPort}, reusing...`);
|
|
994
|
-
}
|
|
995
|
-
else {
|
|
996
|
-
console.log('Starting daemon...');
|
|
997
|
-
const daemonProc = spawnProcess(process.execPath, [process.argv[1], 'up', '--dashboard'], {
|
|
998
|
-
stdio: 'ignore',
|
|
999
|
-
detached: true,
|
|
1000
|
-
});
|
|
1001
|
-
daemonProc.unref();
|
|
1002
|
-
// Wait for dashboard to be ready (up to 10 seconds)
|
|
1003
|
-
const maxWait = 10000;
|
|
1004
|
-
const startTime = Date.now();
|
|
1005
|
-
while (Date.now() - startTime < maxWait) {
|
|
1006
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1007
|
-
for (const port of portsToTry) {
|
|
1008
|
-
if (await checkPort(port)) {
|
|
1009
|
-
dashboardReady = true;
|
|
1010
|
-
detectedPort = port;
|
|
1011
|
-
break;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
if (dashboardReady)
|
|
1015
|
-
break;
|
|
1016
|
-
}
|
|
1017
|
-
if (!dashboardReady) {
|
|
1018
|
-
console.error('Warning: Dashboard may not be fully ready. Spawn might not work.');
|
|
1019
|
-
detectedPort = parseInt(DEFAULT_DASHBOARD_PORT, 10); // Fallback
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
const dashboardPort = detectedPort || parseInt(DEFAULT_DASHBOARD_PORT, 10);
|
|
1023
|
-
// Step 2: Install prpm snippet via npx
|
|
1024
|
-
console.log('[2/3] Installing agent-relay snippet...');
|
|
1025
|
-
const prpmArgs = operator.toLowerCase() === 'claude'
|
|
1026
|
-
? ['prpm', 'install', '@agent-relay/agent-relay-snippet', '--location', 'CLAUDE.md']
|
|
1027
|
-
: ['prpm', 'install', '@agent-relay/agent-relay-snippet'];
|
|
1028
|
-
try {
|
|
1029
|
-
await new Promise((resolve, reject) => {
|
|
1030
|
-
const prpmProc = spawnProcess('npx', prpmArgs, {
|
|
1031
|
-
stdio: 'inherit',
|
|
1032
|
-
});
|
|
1033
|
-
prpmProc.on('close', (code) => {
|
|
1034
|
-
if (code === 0)
|
|
1035
|
-
resolve();
|
|
1036
|
-
else
|
|
1037
|
-
reject(new Error(`npx prpm exited with code ${code}`));
|
|
1038
|
-
});
|
|
1039
|
-
prpmProc.on('error', reject);
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
|
-
catch (err) {
|
|
1043
|
-
console.warn(`Warning: prpm install failed: ${err.message}`);
|
|
1044
|
-
console.warn('Continuing without snippet installation...');
|
|
1045
|
-
}
|
|
1046
|
-
// Step 3: Start Dashboard agent with system prompt
|
|
1047
|
-
console.log(`[3/3] Starting Dashboard agent with ${operator}...`);
|
|
1048
|
-
console.log('');
|
|
1049
|
-
const op = operator.toLowerCase();
|
|
1050
|
-
// Build CLI-specific arguments for system prompt
|
|
1051
|
-
// These args go AFTER the operator command, passed through to the CLI
|
|
1052
|
-
let cliArgs = [];
|
|
1053
|
-
if (op === 'claude') {
|
|
1054
|
-
// Claude: --append-system-prompt <content> (takes content directly, not file)
|
|
1055
|
-
cliArgs = ['--append-system-prompt', MEGA_SYSTEM_PROMPT];
|
|
1056
|
-
}
|
|
1057
|
-
else if (op === 'codex') {
|
|
1058
|
-
// Codex: --config developer_instructions="<content>"
|
|
1059
|
-
cliArgs = ['--config', `developer_instructions=${MEGA_SYSTEM_PROMPT}`];
|
|
1060
|
-
}
|
|
1061
|
-
// Use '--' to separate agent-relay options from the command + its args
|
|
1062
|
-
// Format: agent-relay create-agent -n Dashboard --skip-instructions --dashboard-port <port> -- claude --append-system-prompt "..."
|
|
1063
|
-
const agentProc = spawnProcess(process.execPath, [process.argv[1], 'create-agent', '-n', 'Dashboard', '--skip-instructions', '--dashboard-port', String(dashboardPort), '--', operator, ...cliArgs], { stdio: 'inherit' });
|
|
1064
|
-
// Forward signals to agent process
|
|
1065
|
-
process.on('SIGINT', () => {
|
|
1066
|
-
agentProc.kill('SIGINT');
|
|
1067
|
-
});
|
|
1068
|
-
process.on('SIGTERM', () => {
|
|
1069
|
-
agentProc.kill('SIGTERM');
|
|
1070
|
-
});
|
|
1071
|
-
agentProc.on('close', (code) => {
|
|
1072
|
-
process.exit(code ?? 0);
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
// claude - Start daemon and spawn Dashboard coordinator with Claude
|
|
1076
|
-
program
|
|
1077
|
-
.command('claude')
|
|
1078
|
-
.description('Start daemon and Dashboard coordinator with Claude')
|
|
1079
|
-
.action(async () => {
|
|
1080
|
-
await startDashboardCoordinator('claude');
|
|
1081
|
-
});
|
|
1082
|
-
// codex - Start daemon and spawn Dashboard coordinator with Codex
|
|
1083
|
-
program
|
|
1084
|
-
.command('codex')
|
|
1085
|
-
.description('Start daemon and Dashboard coordinator with Codex')
|
|
1086
|
-
.action(async () => {
|
|
1087
|
-
await startDashboardCoordinator('codex');
|
|
1088
|
-
});
|
|
1089
|
-
// status - Check daemon status
|
|
1090
959
|
program
|
|
1091
960
|
.command('status')
|
|
1092
961
|
.description('Check daemon status')
|
|
@@ -2047,7 +1916,7 @@ program
|
|
|
2047
1916
|
// Use this for programmatic spawning from scripts, detached processes, or containers
|
|
2048
1917
|
program
|
|
2049
1918
|
.command('spawn')
|
|
2050
|
-
.description('Spawn an agent via
|
|
1919
|
+
.description('Spawn an agent via daemon (recommended for programmatic use, no TTY or dashboard required)')
|
|
2051
1920
|
.argument('<name>', 'Agent name')
|
|
2052
1921
|
.argument('<cli>', 'CLI to use (claude, codex, gemini, etc.)')
|
|
2053
1922
|
.argument('[task]', 'Task description (can also be piped via stdin)')
|
|
@@ -2110,19 +1979,62 @@ program
|
|
|
2110
1979
|
shadowTriggers: parseTriggers(options.shadowTriggers),
|
|
2111
1980
|
shadowSpeakOn: parseTriggers(options.shadowSpeakOn),
|
|
2112
1981
|
};
|
|
2113
|
-
// Try daemon socket first (preferred
|
|
1982
|
+
// Try daemon socket first (preferred - no dashboard required)
|
|
1983
|
+
const paths = getProjectPaths();
|
|
1984
|
+
let daemonSpawnSucceeded = false;
|
|
2114
1985
|
try {
|
|
2115
|
-
const
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
1986
|
+
const client = new RelayClient({
|
|
1987
|
+
socketPath: paths.socketPath,
|
|
1988
|
+
agentName: options.spawner || '__cli_spawner__',
|
|
1989
|
+
quiet: true,
|
|
1990
|
+
reconnect: false,
|
|
1991
|
+
maxReconnectAttempts: 0,
|
|
1992
|
+
reconnectDelayMs: 0,
|
|
1993
|
+
reconnectMaxDelayMs: 0,
|
|
1994
|
+
});
|
|
1995
|
+
await client.connect();
|
|
1996
|
+
const result = await client.spawn({
|
|
1997
|
+
name: spawnRequest.name,
|
|
1998
|
+
cli: spawnRequest.cli,
|
|
1999
|
+
task: spawnRequest.task,
|
|
2000
|
+
team: spawnRequest.team,
|
|
2001
|
+
interactive: spawnRequest.interactive,
|
|
2002
|
+
cwd: spawnRequest.cwd,
|
|
2003
|
+
shadowMode: spawnRequest.shadowMode,
|
|
2004
|
+
shadowOf: spawnRequest.shadowOf,
|
|
2005
|
+
shadowAgent: spawnRequest.shadowAgent,
|
|
2006
|
+
shadowTriggers: spawnRequest.shadowTriggers,
|
|
2007
|
+
shadowSpeakOn: spawnRequest.shadowSpeakOn,
|
|
2008
|
+
}, 30000);
|
|
2009
|
+
// Set success flag BEFORE disconnect - disconnect errors shouldn't mask spawn success
|
|
2010
|
+
daemonSpawnSucceeded = true;
|
|
2011
|
+
await client.disconnect();
|
|
2012
|
+
if (result.success) {
|
|
2013
|
+
console.log(`Spawned agent: ${name} (pid: ${result.pid})`);
|
|
2014
|
+
process.exit(0);
|
|
2015
|
+
}
|
|
2016
|
+
else {
|
|
2017
|
+
if (result.policyDecision) {
|
|
2018
|
+
console.error(`Policy denied spawn: ${result.policyDecision.reason || 'Policy rejected'}`);
|
|
2019
|
+
}
|
|
2020
|
+
else {
|
|
2021
|
+
console.error(`Failed to spawn ${name}: ${result.error || 'Unknown error'}`);
|
|
2022
|
+
}
|
|
2023
|
+
process.exit(1);
|
|
2024
|
+
}
|
|
2120
2025
|
}
|
|
2121
|
-
catch {
|
|
2122
|
-
//
|
|
2123
|
-
|
|
2026
|
+
catch (daemonErr) {
|
|
2027
|
+
// If daemon connection failed, try HTTP API as fallback
|
|
2028
|
+
if (daemonErr.message?.includes('ENOENT') || daemonErr.message?.includes('ECONNREFUSED') || daemonErr.code === 'ENOENT') {
|
|
2029
|
+
// Socket doesn't exist or daemon not running - try HTTP API
|
|
2030
|
+
}
|
|
2031
|
+
else if (!daemonSpawnSucceeded) {
|
|
2032
|
+
// Other error during spawn - report it
|
|
2033
|
+
console.error(`Failed to spawn ${name}: ${daemonErr.message}`);
|
|
2034
|
+
process.exit(1);
|
|
2035
|
+
}
|
|
2124
2036
|
}
|
|
2125
|
-
// Fall back to HTTP API
|
|
2037
|
+
// Fall back to HTTP API (dashboard) if daemon not available
|
|
2126
2038
|
try {
|
|
2127
2039
|
const response = await fetch(`http://localhost:${port}/api/spawn`, {
|
|
2128
2040
|
method: 'POST',
|
|
@@ -2136,8 +2048,7 @@ program
|
|
|
2136
2048
|
}
|
|
2137
2049
|
else {
|
|
2138
2050
|
if (result.policyDecision) {
|
|
2139
|
-
console.error(`Policy denied spawn: ${result.policyDecision.reason}`);
|
|
2140
|
-
console.error(`Policy source: ${result.policyDecision.policySource}`);
|
|
2051
|
+
console.error(`Policy denied spawn: ${result.policyDecision.reason || 'Policy rejected'}`);
|
|
2141
2052
|
}
|
|
2142
2053
|
else {
|
|
2143
2054
|
console.error(`Failed to spawn ${name}: ${result.error || 'Unknown error'}`);
|
|
@@ -2147,7 +2058,7 @@ program
|
|
|
2147
2058
|
}
|
|
2148
2059
|
catch (err) {
|
|
2149
2060
|
if (err.code === 'ECONNREFUSED') {
|
|
2150
|
-
console.error(`Cannot connect to
|
|
2061
|
+
console.error(`Cannot connect to daemon. Is it running?`);
|
|
2151
2062
|
console.log(`Run 'agent-relay up' to start the daemon.`);
|
|
2152
2063
|
}
|
|
2153
2064
|
else {
|
|
@@ -2164,11 +2075,12 @@ program
|
|
|
2164
2075
|
.option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
|
|
2165
2076
|
.action(async (name, options) => {
|
|
2166
2077
|
const port = options.port || DEFAULT_DASHBOARD_PORT;
|
|
2167
|
-
// Try daemon socket first (preferred
|
|
2078
|
+
// Try daemon socket first (preferred - no dashboard required)
|
|
2079
|
+
const paths = getProjectPaths();
|
|
2080
|
+
let daemonReleaseSucceeded = false;
|
|
2168
2081
|
try {
|
|
2169
|
-
const
|
|
2170
|
-
|
|
2171
|
-
socketPath: _paths.socketPath,
|
|
2082
|
+
const client = new RelayClient({
|
|
2083
|
+
socketPath: paths.socketPath,
|
|
2172
2084
|
agentName: '__cli_releaser__',
|
|
2173
2085
|
quiet: true,
|
|
2174
2086
|
reconnect: false,
|
|
@@ -2176,16 +2088,32 @@ program
|
|
|
2176
2088
|
reconnectDelayMs: 0,
|
|
2177
2089
|
reconnectMaxDelayMs: 0,
|
|
2178
2090
|
});
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
//
|
|
2182
|
-
|
|
2091
|
+
await client.connect();
|
|
2092
|
+
const result = await client.release(name, 10000);
|
|
2093
|
+
// Set success flag BEFORE disconnect - disconnect errors shouldn't mask release success
|
|
2094
|
+
daemonReleaseSucceeded = true;
|
|
2095
|
+
await client.disconnect();
|
|
2096
|
+
if (result.success) {
|
|
2097
|
+
console.log(`Released agent: ${name}`);
|
|
2098
|
+
process.exit(0);
|
|
2099
|
+
}
|
|
2100
|
+
else {
|
|
2101
|
+
console.error(`Failed to release ${name}: ${result.error || 'Unknown error'}`);
|
|
2102
|
+
process.exit(1);
|
|
2103
|
+
}
|
|
2183
2104
|
}
|
|
2184
|
-
catch {
|
|
2185
|
-
//
|
|
2186
|
-
|
|
2105
|
+
catch (daemonErr) {
|
|
2106
|
+
// If daemon connection failed, try HTTP API as fallback
|
|
2107
|
+
if (daemonErr.message?.includes('ENOENT') || daemonErr.message?.includes('ECONNREFUSED') || daemonErr.code === 'ENOENT') {
|
|
2108
|
+
// Socket doesn't exist or daemon not running - try HTTP API
|
|
2109
|
+
}
|
|
2110
|
+
else if (!daemonReleaseSucceeded) {
|
|
2111
|
+
// Other error during release - report it
|
|
2112
|
+
console.error(`Failed to release ${name}: ${daemonErr.message}`);
|
|
2113
|
+
process.exit(1);
|
|
2114
|
+
}
|
|
2187
2115
|
}
|
|
2188
|
-
// Fall back to HTTP API
|
|
2116
|
+
// Fall back to HTTP API (dashboard) if daemon not available
|
|
2189
2117
|
try {
|
|
2190
2118
|
const response = await fetch(`http://localhost:${port}/api/spawned/${encodeURIComponent(name)}`, {
|
|
2191
2119
|
method: 'DELETE',
|
|
@@ -2203,7 +2131,7 @@ program
|
|
|
2203
2131
|
catch (err) {
|
|
2204
2132
|
// If API call fails, try to provide helpful error message
|
|
2205
2133
|
if (err.code === 'ECONNREFUSED') {
|
|
2206
|
-
console.error(`Cannot connect to
|
|
2134
|
+
console.error(`Cannot connect to daemon. Is it running?`);
|
|
2207
2135
|
console.log(`Run 'agent-relay up' to start the daemon.`);
|
|
2208
2136
|
}
|
|
2209
2137
|
else {
|