@openagents-org/agent-launcher 0.1.15 → 0.1.17
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/package.json +1 -1
- package/src/adapters/base.js +14 -1
- package/src/adapters/openclaw.js +5 -1
- package/src/daemon.js +17 -2
- package/src/installer.js +1 -1
- package/src/tui.js +23 -15
package/package.json
CHANGED
package/src/adapters/base.js
CHANGED
|
@@ -31,13 +31,14 @@ class BaseAdapter {
|
|
|
31
31
|
* @param {string} opts.agentName
|
|
32
32
|
* @param {string} [opts.endpoint]
|
|
33
33
|
*/
|
|
34
|
-
constructor({ workspaceId, channelName, token, agentName, endpoint, agentEnv }) {
|
|
34
|
+
constructor({ workspaceId, channelName, token, agentName, endpoint, agentEnv, agentType }) {
|
|
35
35
|
this.workspaceId = workspaceId;
|
|
36
36
|
this.channelName = channelName;
|
|
37
37
|
this.token = token;
|
|
38
38
|
this.agentName = agentName;
|
|
39
39
|
this.endpoint = endpoint || DEFAULT_ENDPOINT;
|
|
40
40
|
this.agentEnv = agentEnv || process.env;
|
|
41
|
+
this.agentType = agentType;
|
|
41
42
|
this.client = new WorkspaceClient(this.endpoint);
|
|
42
43
|
this._lastEventId = null;
|
|
43
44
|
this._running = false;
|
|
@@ -60,6 +61,18 @@ class BaseAdapter {
|
|
|
60
61
|
|
|
61
62
|
async run() {
|
|
62
63
|
this._running = true;
|
|
64
|
+
|
|
65
|
+
// Announce agent to workspace
|
|
66
|
+
try {
|
|
67
|
+
await this.client.joinNetwork(this.agentName, this.token, {
|
|
68
|
+
network: this.workspaceId,
|
|
69
|
+
agentType: this.agentType || 'agent',
|
|
70
|
+
});
|
|
71
|
+
this._log(`Joined workspace ${this.workspaceId}`);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
this._log(`Warning: join failed: ${e.message}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
63
76
|
await this._skipExistingEvents();
|
|
64
77
|
|
|
65
78
|
const heartbeatInterval = setInterval(() => this._heartbeat(), 30000);
|
package/src/adapters/openclaw.js
CHANGED
|
@@ -59,7 +59,8 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
59
59
|
_findOpenclawBinary() {
|
|
60
60
|
try {
|
|
61
61
|
const cmd = IS_WINDOWS ? 'where openclaw' : 'which openclaw';
|
|
62
|
-
const
|
|
62
|
+
const { getEnhancedEnv } = require('../paths');
|
|
63
|
+
const result = execSync(cmd, { encoding: 'utf-8', timeout: 5000, env: getEnhancedEnv() })
|
|
63
64
|
.split(/\r?\n/)[0].trim();
|
|
64
65
|
if (result) return result;
|
|
65
66
|
} catch {}
|
|
@@ -69,6 +70,9 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
69
70
|
if (IS_WINDOWS) {
|
|
70
71
|
const appdata = process.env.APPDATA || '';
|
|
71
72
|
if (appdata) dirs.push(path.join(appdata, 'npm'));
|
|
73
|
+
// Portable Node.js installed by OpenAgents Launcher
|
|
74
|
+
const home = process.env.USERPROFILE || process.env.HOME || '';
|
|
75
|
+
if (home) dirs.push(path.join(home, '.openagents', 'nodejs'));
|
|
72
76
|
} else {
|
|
73
77
|
const home = process.env.HOME || '';
|
|
74
78
|
dirs.push(path.join(home, '.npm-global', 'bin'), '/usr/local/bin');
|
package/src/daemon.js
CHANGED
|
@@ -67,6 +67,8 @@ class Daemon {
|
|
|
67
67
|
|
|
68
68
|
this._writeStatus();
|
|
69
69
|
this._cachedAgentNames = new Set(agents.map(a => a.name));
|
|
70
|
+
this._cachedAgentConfigs = {};
|
|
71
|
+
for (const a of agents) this._cachedAgentConfigs[a.name] = a.network || '';
|
|
70
72
|
this._log(`Daemon started with ${agents.length} agent(s)`);
|
|
71
73
|
|
|
72
74
|
// Block until shutdown
|
|
@@ -260,7 +262,10 @@ class Daemon {
|
|
|
260
262
|
if (network) {
|
|
261
263
|
this._adapterLoop(name, agentCfg, info, network);
|
|
262
264
|
} else {
|
|
263
|
-
|
|
265
|
+
// No workspace connected — agent is ready but not connected
|
|
266
|
+
info.state = 'idle';
|
|
267
|
+
this._writeStatus();
|
|
268
|
+
this._log(`${name} ready (no workspace connected)`);
|
|
264
269
|
}
|
|
265
270
|
}
|
|
266
271
|
|
|
@@ -355,6 +360,7 @@ class Daemon {
|
|
|
355
360
|
token: network.token,
|
|
356
361
|
agentName: name,
|
|
357
362
|
endpoint,
|
|
363
|
+
agentType,
|
|
358
364
|
openclawAgentId: agentCfg.openclaw_agent_id || 'main',
|
|
359
365
|
disabledModules: new Set(),
|
|
360
366
|
agentEnv: this._buildAgentEnv(agentCfg),
|
|
@@ -574,9 +580,12 @@ class Daemon {
|
|
|
574
580
|
_reload() {
|
|
575
581
|
this._log('Reloading config...');
|
|
576
582
|
const oldNames = this._cachedAgentNames || new Set();
|
|
583
|
+
const oldConfigs = this._cachedAgentConfigs || {};
|
|
577
584
|
// Re-read config from disk
|
|
578
585
|
const newAgents = this.config.getAgents();
|
|
579
586
|
const newNames = new Set(newAgents.map(a => a.name));
|
|
587
|
+
const newConfigs = {};
|
|
588
|
+
for (const a of newAgents) newConfigs[a.name] = a.network || '';
|
|
580
589
|
|
|
581
590
|
// Stop removed agents
|
|
582
591
|
for (const name of oldNames) {
|
|
@@ -586,15 +595,21 @@ class Daemon {
|
|
|
586
595
|
}
|
|
587
596
|
}
|
|
588
597
|
|
|
589
|
-
// Start new agents
|
|
598
|
+
// Start new agents or restart agents whose network changed
|
|
590
599
|
for (const agent of newAgents) {
|
|
591
600
|
if (!oldNames.has(agent.name)) {
|
|
592
601
|
this._launchAgent(agent);
|
|
593
602
|
this._log(`Reload: started new agent '${agent.name}'`);
|
|
603
|
+
} else if ((oldConfigs[agent.name] || '') !== (agent.network || '')) {
|
|
604
|
+
// Network config changed — restart agent
|
|
605
|
+
this.stopAgent(agent.name);
|
|
606
|
+
this._launchAgent(agent);
|
|
607
|
+
this._log(`Reload: restarted '${agent.name}' (network changed)`);
|
|
594
608
|
}
|
|
595
609
|
}
|
|
596
610
|
|
|
597
611
|
this._cachedAgentNames = newNames;
|
|
612
|
+
this._cachedAgentConfigs = newConfigs;
|
|
598
613
|
this._writeStatus();
|
|
599
614
|
}
|
|
600
615
|
|
package/src/installer.js
CHANGED
|
@@ -429,7 +429,7 @@ class Installer {
|
|
|
429
429
|
const { spawn: spawnProc } = require('child_process');
|
|
430
430
|
const https = require('https');
|
|
431
431
|
const os = require('os');
|
|
432
|
-
const nodeVersion = 'v22.
|
|
432
|
+
const nodeVersion = 'v22.16.0';
|
|
433
433
|
const plat = Installer.platform();
|
|
434
434
|
|
|
435
435
|
if (onData) onData(`Node.js not found. Installing Node.js ${nodeVersion}...\n\n`);
|
package/src/tui.js
CHANGED
|
@@ -37,18 +37,24 @@ const COLORS = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const STATE_DISPLAY = {
|
|
40
|
-
online: { sym: '\u25CF', color: COLORS.stateRunning },
|
|
41
|
-
running: { sym: '\u25CF', color: COLORS.stateRunning },
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
online: { sym: '\u25CF', color: COLORS.stateRunning, label: 'connected' },
|
|
41
|
+
running: { sym: '\u25CF', color: COLORS.stateRunning, label: 'connected' },
|
|
42
|
+
idle: { sym: '\u25CB', color: COLORS.stateStarting, label: 'ready' },
|
|
43
|
+
starting: { sym: '\u25D0', color: COLORS.stateStarting, label: 'starting' },
|
|
44
|
+
reconnecting: { sym: '\u25D0', color: COLORS.stateStarting, label: 'reconnecting' },
|
|
45
|
+
stopped: { sym: '\u25CB', color: COLORS.stateStopped, label: 'stopped' },
|
|
46
|
+
'not configured': { sym: '\u25CB', color: COLORS.stateStopped, label: 'not configured' },
|
|
47
|
+
error: { sym: '\u2717', color: COLORS.stateError, label: 'error' },
|
|
47
48
|
};
|
|
48
49
|
|
|
49
|
-
function stateMarkup(state) {
|
|
50
|
-
const d = STATE_DISPLAY[state] || { sym: '?', color: 'white' };
|
|
51
|
-
|
|
50
|
+
function stateMarkup(state, hasWorkspace) {
|
|
51
|
+
const d = STATE_DISPLAY[state] || { sym: '?', color: 'white', label: state };
|
|
52
|
+
let label = d.label;
|
|
53
|
+
// For running/connected agents, clarify workspace status
|
|
54
|
+
if ((state === 'running' || state === 'online') && !hasWorkspace) {
|
|
55
|
+
label = 'running';
|
|
56
|
+
}
|
|
57
|
+
return `{${d.color}-fg}${d.sym} ${label}{/${d.color}-fg}`;
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
// ── Data helpers ────────────────────────────────────────────────────────────
|
|
@@ -299,7 +305,7 @@ function createTUI() {
|
|
|
299
305
|
agentList.setItems([' {gray-fg}No agents configured. Press {bold}i{/bold} to install, {bold}n{/bold} to create.{/gray-fg}']);
|
|
300
306
|
} else {
|
|
301
307
|
const items = agentRows.map(r => {
|
|
302
|
-
const state = stateMarkup(r.state);
|
|
308
|
+
const state = stateMarkup(r.state, !!r.workspace);
|
|
303
309
|
const ws = r.workspace || '{gray-fg}-{/gray-fg}';
|
|
304
310
|
const pathInfo = r.path ? `{gray-fg} ${r.path}{/gray-fg}` : '';
|
|
305
311
|
return ` ${r.name.padEnd(22)} ${r.type.padEnd(14)} ${state.padEnd(30)} ${ws}${pathInfo}`;
|
|
@@ -1128,15 +1134,17 @@ function createTUI() {
|
|
|
1128
1134
|
opened = true;
|
|
1129
1135
|
} catch {}
|
|
1130
1136
|
|
|
1131
|
-
// Show URL in a dialog
|
|
1137
|
+
// Show URL in a dialog — full width, auto-height for long URLs
|
|
1138
|
+
const innerW = screen.width - 4;
|
|
1139
|
+
const urlLines = Math.ceil(url.length / innerW);
|
|
1132
1140
|
const dialog = blessed.box({
|
|
1133
|
-
top: 'center', left:
|
|
1134
|
-
width:
|
|
1141
|
+
top: 'center', left: 0,
|
|
1142
|
+
width: '100%', height: 4 + urlLines + 2,
|
|
1135
1143
|
border: { type: 'line' },
|
|
1136
1144
|
tags: true,
|
|
1137
1145
|
label: ' {bold}Workspace URL{/bold} ',
|
|
1138
1146
|
style: { border: { fg: COLORS.accent }, bg: COLORS.surface },
|
|
1139
|
-
content: `\n
|
|
1147
|
+
content: `\n {bold}${url}{/bold}\n\n {gray-fg}${opened ? 'Opened in browser.' : 'Copy the URL above.'} Press Esc to close.{/gray-fg}`,
|
|
1140
1148
|
});
|
|
1141
1149
|
|
|
1142
1150
|
screen.append(dialog);
|