@openagents-org/agent-launcher 0.1.10 → 0.1.12
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/tui.js +141 -119
package/package.json
CHANGED
package/src/tui.js
CHANGED
|
@@ -203,18 +203,19 @@ function createTUI() {
|
|
|
203
203
|
style: { fg: 'white' },
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
-
// ── Footer ──
|
|
207
|
-
const
|
|
206
|
+
// ── Footer (clickable buttons) ──
|
|
207
|
+
const footerBar = blessed.box({
|
|
208
208
|
bottom: 0, left: 0, width: '100%', height: 1,
|
|
209
209
|
tags: true,
|
|
210
210
|
style: { bg: COLORS.footerBg, fg: COLORS.footerFg },
|
|
211
211
|
});
|
|
212
|
+
let footerButtons = [];
|
|
212
213
|
|
|
213
214
|
screen.append(header);
|
|
214
215
|
screen.append(titleBox);
|
|
215
216
|
screen.append(agentPanel);
|
|
216
217
|
screen.append(logPanel);
|
|
217
|
-
screen.append(
|
|
218
|
+
screen.append(footerBar);
|
|
218
219
|
|
|
219
220
|
// ── Log helper ──
|
|
220
221
|
function log(msg) {
|
|
@@ -223,36 +224,60 @@ function createTUI() {
|
|
|
223
224
|
screen.render();
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
// ── Footer rendering (context-aware) ──
|
|
227
|
+
// ── Footer rendering (context-aware, clickable) ──
|
|
227
228
|
function updateFooter() {
|
|
228
229
|
const agent = agentRows[agentList.selected];
|
|
229
|
-
const
|
|
230
|
+
const items = [];
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
|
|
232
|
+
items.push({ key: 'i', label: 'Install' });
|
|
233
|
+
items.push({ key: 'n', label: 'New' });
|
|
233
234
|
|
|
234
235
|
if (agent && agent.configured) {
|
|
235
236
|
const isRunning = ['running', 'online', 'starting', 'reconnecting'].includes(agent.state);
|
|
236
237
|
const isStopped = ['stopped', 'error'].includes(agent.state);
|
|
237
238
|
|
|
238
|
-
if (isStopped)
|
|
239
|
-
if (isRunning)
|
|
239
|
+
if (isStopped) items.push({ key: 's', label: 'Start' });
|
|
240
|
+
if (isRunning) items.push({ key: 'x', label: 'Stop' });
|
|
240
241
|
|
|
241
242
|
const envFields = connector.registry.getEnvFields(agent.type);
|
|
242
|
-
if (envFields && envFields.length > 0)
|
|
243
|
+
if (envFields && envFields.length > 0) items.push({ key: 'e', label: 'Configure' });
|
|
243
244
|
|
|
244
|
-
if (!agent.workspace)
|
|
245
|
-
if (agent.workspace)
|
|
246
|
-
if (agent.workspace)
|
|
245
|
+
if (!agent.workspace) items.push({ key: 'c', label: 'Connect' });
|
|
246
|
+
if (agent.workspace) items.push({ key: 'd', label: 'Disconnect' });
|
|
247
|
+
if (agent.workspace) items.push({ key: 'w', label: 'Workspace' });
|
|
247
248
|
|
|
248
|
-
|
|
249
|
+
items.push({ key: 'Del', label: 'Remove' });
|
|
249
250
|
}
|
|
250
251
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
items.push({ key: 'u', label: 'Daemon' });
|
|
253
|
+
items.push({ key: 'r', label: 'Refresh' });
|
|
254
|
+
items.push({ key: 'q', label: 'Quit' });
|
|
255
|
+
|
|
256
|
+
// Remove old buttons
|
|
257
|
+
for (const btn of footerButtons) { footerBar.remove(btn); btn.destroy(); }
|
|
258
|
+
footerButtons = [];
|
|
259
|
+
|
|
260
|
+
let left = 1;
|
|
261
|
+
for (const item of items) {
|
|
262
|
+
const text = `${item.key} ${item.label}`;
|
|
263
|
+
const btn = blessed.box({
|
|
264
|
+
parent: footerBar,
|
|
265
|
+
left, top: 0, height: 1,
|
|
266
|
+
width: text.length + 2,
|
|
267
|
+
tags: true,
|
|
268
|
+
mouse: true,
|
|
269
|
+
clickable: true,
|
|
270
|
+
content: `{cyan-fg}${item.key}{/cyan-fg} ${item.label}`,
|
|
271
|
+
style: { bg: COLORS.footerBg, fg: COLORS.footerFg, hover: { bg: 'cyan', fg: 'black' } },
|
|
272
|
+
});
|
|
273
|
+
const action = footerActions[item.label];
|
|
274
|
+
if (action) {
|
|
275
|
+
btn.on('click', () => action());
|
|
276
|
+
}
|
|
277
|
+
footerButtons.push(btn);
|
|
278
|
+
left += text.length + 2;
|
|
279
|
+
}
|
|
254
280
|
|
|
255
|
-
footer.setContent(' ' + parts.join(' '));
|
|
256
281
|
screen.render();
|
|
257
282
|
}
|
|
258
283
|
|
|
@@ -1188,115 +1213,112 @@ function createTUI() {
|
|
|
1188
1213
|
// Key bindings
|
|
1189
1214
|
// ────────────────────────────────────────────────────────────────────────
|
|
1190
1215
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
signalDaemonReload();
|
|
1216
|
+
// ── Action handlers (shared by keys and clickable footer) ──
|
|
1217
|
+
const footerActions = {
|
|
1218
|
+
Install() { if (currentView === 'main') showInstallScreen(); },
|
|
1219
|
+
New() {
|
|
1220
|
+
if (currentView !== 'main') return;
|
|
1221
|
+
showSelectAgentTypeScreen((type) => {
|
|
1222
|
+
showStartAgentScreen(type, (result) => {
|
|
1223
|
+
try {
|
|
1224
|
+
connector.addAgent({ name: result.name, type: result.type, path: result.path });
|
|
1225
|
+
log(`{green-fg}\u2713{/green-fg} Created agent {cyan-fg}${result.name}{/cyan-fg} (${result.type})`);
|
|
1226
|
+
const pid = connector.getDaemonPid();
|
|
1227
|
+
if (!pid) {
|
|
1228
|
+
connector.startDaemon();
|
|
1229
|
+
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1230
|
+
} else {
|
|
1231
|
+
signalDaemonReload();
|
|
1232
|
+
}
|
|
1233
|
+
} catch (e) {
|
|
1234
|
+
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1211
1235
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1215
|
-
setTimeout(refreshAgentTable, 3000);
|
|
1236
|
+
setTimeout(refreshAgentTable, 3000);
|
|
1237
|
+
});
|
|
1216
1238
|
});
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1239
|
+
},
|
|
1240
|
+
Start() {
|
|
1241
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1242
|
+
const a = agentRows[agentList.selected];
|
|
1243
|
+
if (a.configured) doStart(a.name);
|
|
1244
|
+
},
|
|
1245
|
+
Stop() {
|
|
1246
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1247
|
+
const a = agentRows[agentList.selected];
|
|
1248
|
+
if (a.configured) doStop(a.name);
|
|
1249
|
+
},
|
|
1250
|
+
Configure() {
|
|
1251
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1252
|
+
const a = agentRows[agentList.selected];
|
|
1253
|
+
if (a.configured) showConfigureScreen(a);
|
|
1254
|
+
},
|
|
1255
|
+
Connect() {
|
|
1256
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1257
|
+
const a = agentRows[agentList.selected];
|
|
1258
|
+
if (a.configured && !a.workspace) showConnectWorkspaceScreen(a.name);
|
|
1259
|
+
},
|
|
1260
|
+
Disconnect() {
|
|
1261
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1262
|
+
const a = agentRows[agentList.selected];
|
|
1263
|
+
if (a.configured && a.workspace) doDisconnect(a.name);
|
|
1264
|
+
},
|
|
1265
|
+
Workspace() {
|
|
1266
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1267
|
+
const a = agentRows[agentList.selected];
|
|
1268
|
+
if (a.configured && a.workspace) doOpenWorkspace(a);
|
|
1269
|
+
},
|
|
1270
|
+
Remove() {
|
|
1271
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1272
|
+
const a = agentRows[agentList.selected];
|
|
1273
|
+
if (a.configured) doRemove(a.name);
|
|
1274
|
+
},
|
|
1275
|
+
Daemon() {
|
|
1276
|
+
if (currentView !== 'main') return;
|
|
1277
|
+
const pid = connector.getDaemonPid();
|
|
1278
|
+
if (pid) {
|
|
1279
|
+
showConfirmDialog('Stop daemon? This will disconnect ALL agents.', (yes) => {
|
|
1280
|
+
if (!yes) { log('{gray-fg}Cancelled{/gray-fg}'); return; }
|
|
1281
|
+
try {
|
|
1282
|
+
connector.stopDaemon();
|
|
1283
|
+
log('{green-fg}\u2713{/green-fg} Daemon stopped');
|
|
1284
|
+
} catch (e) {
|
|
1285
|
+
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1286
|
+
}
|
|
1287
|
+
setTimeout(refreshAgentTable, 1000);
|
|
1288
|
+
});
|
|
1289
|
+
} else {
|
|
1247
1290
|
try {
|
|
1248
|
-
connector.
|
|
1249
|
-
log('{green-fg}\u2713{/green-fg} Daemon
|
|
1291
|
+
connector.startDaemon();
|
|
1292
|
+
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1250
1293
|
} catch (e) {
|
|
1251
1294
|
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1252
1295
|
}
|
|
1253
|
-
setTimeout(refreshAgentTable,
|
|
1254
|
-
});
|
|
1255
|
-
} else {
|
|
1256
|
-
try {
|
|
1257
|
-
connector.startDaemon();
|
|
1258
|
-
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1259
|
-
} catch (e) {
|
|
1260
|
-
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1296
|
+
setTimeout(refreshAgentTable, 3000);
|
|
1261
1297
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
if (
|
|
1270
|
-
|
|
1271
|
-
});
|
|
1272
|
-
|
|
1273
|
-
screen.key('d', () => {
|
|
1274
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1275
|
-
const a = agentRows[agentList.selected];
|
|
1276
|
-
if (!a.configured || !a.workspace) return;
|
|
1277
|
-
doDisconnect(a.name);
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
screen.key('w', () => {
|
|
1281
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1282
|
-
const a = agentRows[agentList.selected];
|
|
1283
|
-
if (!a.configured || !a.workspace) return;
|
|
1284
|
-
doOpenWorkspace(a);
|
|
1285
|
-
});
|
|
1286
|
-
|
|
1287
|
-
screen.key('e', () => {
|
|
1288
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1289
|
-
const a = agentRows[agentList.selected];
|
|
1290
|
-
if (!a.configured) return;
|
|
1291
|
-
showConfigureScreen(a);
|
|
1292
|
-
});
|
|
1298
|
+
},
|
|
1299
|
+
Refresh() {
|
|
1300
|
+
if (currentView === 'main') {
|
|
1301
|
+
refreshAgentTable();
|
|
1302
|
+
log('{green-fg}\u2713{/green-fg} Refreshed');
|
|
1303
|
+
}
|
|
1304
|
+
},
|
|
1305
|
+
Quit() { if (currentView === 'main') process.exit(0); },
|
|
1306
|
+
};
|
|
1293
1307
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1308
|
+
// Bind keyboard shortcuts
|
|
1309
|
+
screen.key('q', footerActions.Quit);
|
|
1310
|
+
screen.key('C-c', () => process.exit(0));
|
|
1311
|
+
screen.key('i', footerActions.Install);
|
|
1312
|
+
screen.key('n', footerActions.New);
|
|
1313
|
+
screen.key('r', footerActions.Refresh);
|
|
1314
|
+
screen.key('s', footerActions.Start);
|
|
1315
|
+
screen.key('x', footerActions.Stop);
|
|
1316
|
+
screen.key('u', footerActions.Daemon);
|
|
1317
|
+
screen.key('c', footerActions.Connect);
|
|
1318
|
+
screen.key('d', footerActions.Disconnect);
|
|
1319
|
+
screen.key('w', footerActions.Workspace);
|
|
1320
|
+
screen.key('e', footerActions.Configure);
|
|
1321
|
+
screen.key('delete', footerActions.Remove);
|
|
1300
1322
|
|
|
1301
1323
|
// ── Init ──
|
|
1302
1324
|
agentList.focus();
|