@openagents-org/agent-launcher 0.1.17 → 0.2.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/package.json +1 -1
- package/registry.json +50 -0
- package/src/adapters/claude.js +98 -9
- package/src/adapters/cursor.js +22 -0
- package/src/adapters/index.js +10 -1
- package/src/adapters/llm-direct.js +180 -0
- package/src/adapters/nanoclaw.js +22 -0
- package/src/adapters/openclaw.js +0 -9
- package/src/adapters/opencode.js +380 -0
- package/src/adapters/workspace-prompt.js +37 -0
- package/src/daemon.js +16 -2
- package/src/identity.js +113 -0
- package/src/index.js +5 -0
- package/src/tui.js +147 -8
- package/src/workspace-client.js +311 -21
package/src/tui.js
CHANGED
|
@@ -85,6 +85,39 @@ function loadAgentRows(connector) {
|
|
|
85
85
|
workspace = agent.network;
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
// Check if agent type needs configuration (API key etc.)
|
|
89
|
+
let notReadyMsg = '';
|
|
90
|
+
try {
|
|
91
|
+
const agentType = agent.type || 'openclaw';
|
|
92
|
+
const entry = connector.registry.getEntry(agentType);
|
|
93
|
+
if (entry && entry.check_ready) {
|
|
94
|
+
const cr = entry.check_ready;
|
|
95
|
+
let isReady = false;
|
|
96
|
+
// Check saved env
|
|
97
|
+
if (cr.saved_env_key) {
|
|
98
|
+
const saved = connector.env.load(agentType);
|
|
99
|
+
if (saved[cr.saved_env_key]) isReady = true;
|
|
100
|
+
}
|
|
101
|
+
// Check process env vars
|
|
102
|
+
if (!isReady && cr.env_vars) {
|
|
103
|
+
for (const v of cr.env_vars) {
|
|
104
|
+
if (process.env[v]) { isReady = true; break; }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Check creds file (for claude)
|
|
108
|
+
if (!isReady && cr.creds_file) {
|
|
109
|
+
const credsPath = cr.creds_file.replace('~', process.env.HOME || process.env.USERPROFILE || '');
|
|
110
|
+
try {
|
|
111
|
+
if (fs.existsSync(credsPath)) {
|
|
112
|
+
const creds = JSON.parse(fs.readFileSync(credsPath, 'utf-8'));
|
|
113
|
+
if (cr.creds_key && creds[cr.creds_key]) isReady = true;
|
|
114
|
+
}
|
|
115
|
+
} catch {}
|
|
116
|
+
}
|
|
117
|
+
if (!isReady) notReadyMsg = cr.not_ready_message || 'Not configured';
|
|
118
|
+
}
|
|
119
|
+
} catch {}
|
|
120
|
+
|
|
88
121
|
return {
|
|
89
122
|
name: agent.name,
|
|
90
123
|
type: agent.type || 'openclaw',
|
|
@@ -93,6 +126,7 @@ function loadAgentRows(connector) {
|
|
|
93
126
|
path: agent.path || '',
|
|
94
127
|
network: agent.network || '',
|
|
95
128
|
lastError: info.last_error || '',
|
|
129
|
+
notReadyMsg,
|
|
96
130
|
configured: true,
|
|
97
131
|
};
|
|
98
132
|
});
|
|
@@ -148,6 +182,7 @@ function createTUI() {
|
|
|
148
182
|
title: 'OpenAgents',
|
|
149
183
|
fullUnicode: true,
|
|
150
184
|
tags: true,
|
|
185
|
+
style: { bg: 'black', fg: 'white' },
|
|
151
186
|
});
|
|
152
187
|
const connector = getConnector();
|
|
153
188
|
let pkg;
|
|
@@ -168,7 +203,7 @@ function createTUI() {
|
|
|
168
203
|
top: 1, left: 0, width: '100%', height: 1,
|
|
169
204
|
tags: true,
|
|
170
205
|
content: ` {bold}OpenAgents{/bold} {gray-fg}v${pkg.version}{/gray-fg}`,
|
|
171
|
-
style: { fg: 'white' },
|
|
206
|
+
style: { fg: 'white', bg: 'black' },
|
|
172
207
|
});
|
|
173
208
|
|
|
174
209
|
// ── Agent Panel (bordered) ──
|
|
@@ -177,7 +212,7 @@ function createTUI() {
|
|
|
177
212
|
border: { type: 'line' },
|
|
178
213
|
label: ' {bold}Agents{/bold} ',
|
|
179
214
|
tags: true,
|
|
180
|
-
style: { border: { fg: COLORS.panelBorder }, label: { fg: COLORS.accent } },
|
|
215
|
+
style: { bg: 'black', border: { fg: COLORS.panelBorder }, label: { fg: COLORS.accent } },
|
|
181
216
|
});
|
|
182
217
|
|
|
183
218
|
// ── Column Headers ──
|
|
@@ -196,8 +231,9 @@ function createTUI() {
|
|
|
196
231
|
keys: true, vi: true, mouse: true,
|
|
197
232
|
tags: true,
|
|
198
233
|
style: {
|
|
234
|
+
bg: 'black',
|
|
199
235
|
selected: { bg: COLORS.selected.bg, fg: COLORS.selected.fg, bold: true },
|
|
200
|
-
item: { fg: 'white' },
|
|
236
|
+
item: { fg: 'white', bg: 'black' },
|
|
201
237
|
},
|
|
202
238
|
});
|
|
203
239
|
|
|
@@ -207,7 +243,7 @@ function createTUI() {
|
|
|
207
243
|
border: { type: 'line' },
|
|
208
244
|
label: ' {bold}Activity Log{/bold} ',
|
|
209
245
|
tags: true,
|
|
210
|
-
style: { border: { fg: COLORS.logBorder }, label: { fg: COLORS.primary } },
|
|
246
|
+
style: { bg: 'black', border: { fg: COLORS.logBorder }, label: { fg: COLORS.primary } },
|
|
211
247
|
});
|
|
212
248
|
|
|
213
249
|
const logContent = blessed.log({
|
|
@@ -215,7 +251,7 @@ function createTUI() {
|
|
|
215
251
|
top: 0, left: 0, width: '100%-2', height: '100%-2',
|
|
216
252
|
scrollable: true, scrollOnInput: true,
|
|
217
253
|
tags: true,
|
|
218
|
-
style: { fg: 'white' },
|
|
254
|
+
style: { fg: 'white', bg: 'black' },
|
|
219
255
|
});
|
|
220
256
|
|
|
221
257
|
// ── Footer (clickable buttons) ──
|
|
@@ -308,7 +344,8 @@ function createTUI() {
|
|
|
308
344
|
const state = stateMarkup(r.state, !!r.workspace);
|
|
309
345
|
const ws = r.workspace || '{gray-fg}-{/gray-fg}';
|
|
310
346
|
const pathInfo = r.path ? `{gray-fg} ${r.path}{/gray-fg}` : '';
|
|
311
|
-
|
|
347
|
+
const warning = r.notReadyMsg ? ` {yellow-fg}⚠ ${r.notReadyMsg}{/yellow-fg}` : '';
|
|
348
|
+
return ` ${r.name.padEnd(22)} ${r.type.padEnd(14)} ${state.padEnd(30)} ${ws}${pathInfo}${warning}`;
|
|
312
349
|
});
|
|
313
350
|
agentList.setItems(items);
|
|
314
351
|
}
|
|
@@ -328,7 +365,20 @@ function createTUI() {
|
|
|
328
365
|
const dot = pid ? `{green-fg}\u25CF{/green-fg}` : `{gray-fg}\u25CB{/gray-fg}`;
|
|
329
366
|
const state = pid ? 'Daemon running' : 'Daemon idle';
|
|
330
367
|
const count = agentRows.length;
|
|
331
|
-
|
|
368
|
+
|
|
369
|
+
// Show installed runtimes
|
|
370
|
+
let installed = [];
|
|
371
|
+
try {
|
|
372
|
+
const catalog = loadCatalog(connector);
|
|
373
|
+
installed = catalog.filter(e => e.installed).map(e => e.name);
|
|
374
|
+
} catch {}
|
|
375
|
+
const installedStr = installed.length
|
|
376
|
+
? ` {gray-fg}|{/gray-fg} {green-fg}${installed.join(', ')}{/green-fg} installed`
|
|
377
|
+
: '';
|
|
378
|
+
|
|
379
|
+
header.setContent(
|
|
380
|
+
` ${dot} ${state} {gray-fg}|{/gray-fg} ${count} agent${count !== 1 ? 's' : ''} configured${installedStr}`
|
|
381
|
+
);
|
|
332
382
|
}
|
|
333
383
|
|
|
334
384
|
// Update footer when selection changes
|
|
@@ -542,6 +592,8 @@ function createTUI() {
|
|
|
542
592
|
}).then(() => {
|
|
543
593
|
installLog.log('');
|
|
544
594
|
installLog.log(`{green-fg}\u2713 ${entry.name} installed successfully!{/green-fg}`);
|
|
595
|
+
installLog.log('');
|
|
596
|
+
installLog.log(`{cyan-fg}Press c to create a ${entry.name} agent, or Esc to go back.{/cyan-fg}`);
|
|
545
597
|
logPanel.setLabel(` {bold}{green-fg}Install Complete{/green-fg}{/bold} `);
|
|
546
598
|
log(`{green-fg}\u2713{/green-fg} ${entry.name} installed`);
|
|
547
599
|
const idx = catalog.findIndex(c => c.name === entry.name);
|
|
@@ -550,6 +602,36 @@ function createTUI() {
|
|
|
550
602
|
onDone();
|
|
551
603
|
list.focus();
|
|
552
604
|
screen.render();
|
|
605
|
+
|
|
606
|
+
// Listen for 'c' to create agent from just-installed type
|
|
607
|
+
const onCreateKey = (ch) => {
|
|
608
|
+
if (ch === 'c') {
|
|
609
|
+
screen.unkey(['c', 'escape'], onCreateKey);
|
|
610
|
+
// Go back to main and start agent creation flow
|
|
611
|
+
list.emit('keypress', null, { name: 'escape' });
|
|
612
|
+
setTimeout(() => {
|
|
613
|
+
showStartAgentScreen(entry.name, (result) => {
|
|
614
|
+
try {
|
|
615
|
+
connector.addAgent({ name: result.name, type: result.type, path: result.path });
|
|
616
|
+
log(`{green-fg}\u2713{/green-fg} Created agent {cyan-fg}${result.name}{/cyan-fg} (${result.type})`);
|
|
617
|
+
const pid = connector.getDaemonPid();
|
|
618
|
+
if (!pid) {
|
|
619
|
+
connector.startDaemon();
|
|
620
|
+
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
621
|
+
} else {
|
|
622
|
+
signalDaemonReload();
|
|
623
|
+
}
|
|
624
|
+
} catch (e) {
|
|
625
|
+
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
626
|
+
}
|
|
627
|
+
setTimeout(refreshAgentTable, 3000);
|
|
628
|
+
});
|
|
629
|
+
}, 200);
|
|
630
|
+
} else {
|
|
631
|
+
screen.unkey(['c', 'escape'], onCreateKey);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
screen.key(['c', 'escape'], onCreateKey);
|
|
553
635
|
}).catch((e) => {
|
|
554
636
|
installLog.log('');
|
|
555
637
|
installLog.log(`{red-fg}\u2717 Failed: ${e.message}{/red-fg}`);
|
|
@@ -652,6 +734,7 @@ function createTUI() {
|
|
|
652
734
|
const pathInput = blessed.textbox({
|
|
653
735
|
parent: dialog, top: 6, left: 2, width: 50, height: 3,
|
|
654
736
|
border: { type: 'line' }, inputOnFocus: true,
|
|
737
|
+
value: defaultPath,
|
|
655
738
|
style: { fg: 'white', bg: COLORS.surface, focus: { border: { fg: COLORS.accent } }, border: { fg: 'grey' } },
|
|
656
739
|
});
|
|
657
740
|
|
|
@@ -667,6 +750,18 @@ function createTUI() {
|
|
|
667
750
|
nameInput.focus();
|
|
668
751
|
screen.render();
|
|
669
752
|
|
|
753
|
+
// Override _listener on textboxes to intercept Tab before it's inserted
|
|
754
|
+
const origNameListener = nameInput._listener.bind(nameInput);
|
|
755
|
+
nameInput._listener = function(ch, key) {
|
|
756
|
+
if (key.name === 'tab') { nameInput._done(null, nameInput.value); pathInput.focus(); return; }
|
|
757
|
+
return origNameListener(ch, key);
|
|
758
|
+
};
|
|
759
|
+
const origPathListener = pathInput._listener.bind(pathInput);
|
|
760
|
+
pathInput._listener = function(ch, key) {
|
|
761
|
+
if (key.name === 'tab') { pathInput._done(null, pathInput.value); nameInput.focus(); return; }
|
|
762
|
+
return origPathListener(ch, key);
|
|
763
|
+
};
|
|
764
|
+
|
|
670
765
|
const close = () => {
|
|
671
766
|
screen.remove(dialog);
|
|
672
767
|
dialog.destroy();
|
|
@@ -768,7 +863,7 @@ function createTUI() {
|
|
|
768
863
|
parent: box, bottom: 0, left: 0, width: '100%', height: 1,
|
|
769
864
|
tags: true,
|
|
770
865
|
style: { bg: COLORS.footerBg, fg: COLORS.footerFg },
|
|
771
|
-
content: ' {cyan-fg}
|
|
866
|
+
content: ' {cyan-fg}Tab{/cyan-fg} Next {cyan-fg}Ctrl+U{/cyan-fg} Clear {cyan-fg}Ctrl+S{/cyan-fg} Save {cyan-fg}Ctrl+T{/cyan-fg} Test {cyan-fg}Esc{/cyan-fg} Back',
|
|
772
867
|
});
|
|
773
868
|
|
|
774
869
|
screen.append(box);
|
|
@@ -786,6 +881,35 @@ function createTUI() {
|
|
|
786
881
|
});
|
|
787
882
|
}
|
|
788
883
|
|
|
884
|
+
// Override _listener on textboxes to intercept Tab and Escape
|
|
885
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
886
|
+
const orig = inputs[i]._listener.bind(inputs[i]);
|
|
887
|
+
const idx = i;
|
|
888
|
+
inputs[i]._listener = function(ch, key) {
|
|
889
|
+
if (key.name === 'tab' && inputs.length > 1) {
|
|
890
|
+
inputs[idx]._done(null, inputs[idx].value);
|
|
891
|
+
inputs[(idx + 1) % inputs.length].focus();
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (key.name === 'escape') {
|
|
895
|
+
inputs[idx]._done(null, inputs[idx].value);
|
|
896
|
+
closeConfig();
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
// Ctrl+U to clear field
|
|
900
|
+
if (key.ctrl && key.name === 'u') {
|
|
901
|
+
inputs[idx].value = '';
|
|
902
|
+
inputs[idx].setValue('');
|
|
903
|
+
screen.render();
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
// Ctrl+S to save, Ctrl+T to test
|
|
907
|
+
if (key.ctrl && key.name === 's') { inputs[idx]._done(null, inputs[idx].value); doSave(); return; }
|
|
908
|
+
if (key.ctrl && key.name === 't') { inputs[idx]._done(null, inputs[idx].value); doTest(); return; }
|
|
909
|
+
return orig(ch, key);
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
|
|
789
913
|
function gatherEnv() {
|
|
790
914
|
const env = {};
|
|
791
915
|
for (const input of inputs) {
|
|
@@ -1341,6 +1465,21 @@ function createTUI() {
|
|
|
1341
1465
|
agentList.focus();
|
|
1342
1466
|
refreshAgentTable();
|
|
1343
1467
|
log('Welcome to {bold}OpenAgents{/bold}. Press {cyan-fg}i{/cyan-fg} to install agents, {cyan-fg}n{/cyan-fg} to create one.');
|
|
1468
|
+
|
|
1469
|
+
// Show installed runtimes that don't have any agent instances yet
|
|
1470
|
+
try {
|
|
1471
|
+
const catalog = loadCatalog(connector);
|
|
1472
|
+
const installed = catalog.filter(e => e.installed).map(e => e.name);
|
|
1473
|
+
const configuredTypes = new Set(agentRows.map(r => r.type));
|
|
1474
|
+
const unused = installed.filter(t => !configuredTypes.has(t));
|
|
1475
|
+
if (unused.length > 0) {
|
|
1476
|
+
log(`{green-fg}\u2713{/green-fg} Installed: {bold}${unused.join(', ')}{/bold} — press {cyan-fg}n{/cyan-fg} to create an agent`);
|
|
1477
|
+
}
|
|
1478
|
+
if (installed.length === 0) {
|
|
1479
|
+
log('{yellow-fg}!{/yellow-fg} No agent runtimes installed. Press {cyan-fg}i{/cyan-fg} to install one.');
|
|
1480
|
+
}
|
|
1481
|
+
} catch {}
|
|
1482
|
+
|
|
1344
1483
|
setInterval(refreshAgentTable, 5000);
|
|
1345
1484
|
screen.render();
|
|
1346
1485
|
}
|