@openagents-org/agent-launcher 0.1.11 → 0.1.13
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 +6 -0
- package/src/installer.js +12 -0
- package/src/tui.js +111 -113
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -88,6 +88,8 @@
|
|
|
88
88
|
],
|
|
89
89
|
"install": {
|
|
90
90
|
"binary": "code",
|
|
91
|
+
"verify": "code --list-extensions 2>/dev/null | grep -qi claude-dev",
|
|
92
|
+
"verify_win": "code --list-extensions 2>nul | findstr /i claude-dev",
|
|
91
93
|
"macos": "code --install-extension saoudrizwan.claude-dev",
|
|
92
94
|
"linux": "code --install-extension saoudrizwan.claude-dev",
|
|
93
95
|
"windows": "code --install-extension saoudrizwan.claude-dev"
|
|
@@ -166,6 +168,8 @@
|
|
|
166
168
|
],
|
|
167
169
|
"install": {
|
|
168
170
|
"binary": "gh",
|
|
171
|
+
"verify": "gh copilot --version >/dev/null 2>&1",
|
|
172
|
+
"verify_win": "gh copilot --version >nul 2>nul",
|
|
169
173
|
"macos": "gh extension install github/gh-copilot",
|
|
170
174
|
"linux": "gh extension install github/gh-copilot",
|
|
171
175
|
"windows": "gh extension install github/gh-copilot"
|
|
@@ -185,6 +189,8 @@
|
|
|
185
189
|
"builtin": true,
|
|
186
190
|
"install": {
|
|
187
191
|
"binary": "cursor",
|
|
192
|
+
"verify": "cursor --version 2>/dev/null | grep -qi cursor",
|
|
193
|
+
"verify_win": "cursor --version 2>nul | findstr /i cursor",
|
|
188
194
|
"requires": [
|
|
189
195
|
null
|
|
190
196
|
],
|
package/src/installer.js
CHANGED
|
@@ -35,6 +35,18 @@ class Installer {
|
|
|
35
35
|
* Checks binary on PATH first, then marker files.
|
|
36
36
|
*/
|
|
37
37
|
isInstalled(agentType) {
|
|
38
|
+
// Use verify command if available for accurate detection
|
|
39
|
+
const entry = this.registry.getEntry(agentType);
|
|
40
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
41
|
+
const verifyCmd = entry && entry.install
|
|
42
|
+
? (IS_WINDOWS ? entry.install.verify_win : entry.install.verify)
|
|
43
|
+
: null;
|
|
44
|
+
if (verifyCmd) {
|
|
45
|
+
try {
|
|
46
|
+
require('child_process').execSync(verifyCmd, { stdio: 'ignore', timeout: 5000 });
|
|
47
|
+
return true;
|
|
48
|
+
} catch { return false; }
|
|
49
|
+
}
|
|
38
50
|
if (this._whichBinary(agentType)) return true;
|
|
39
51
|
if (this._hasMarker(agentType)) {
|
|
40
52
|
// Marker exists but binary not found — stale marker, clean it up
|
package/src/tui.js
CHANGED
|
@@ -93,10 +93,19 @@ function loadAgentRows(connector) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function loadCatalog(connector) {
|
|
96
|
+
const { execSync } = require('child_process');
|
|
96
97
|
const entries = connector.registry.getCatalogSync();
|
|
97
98
|
return entries.map(e => {
|
|
98
99
|
let installed = false;
|
|
99
|
-
|
|
100
|
+
|
|
101
|
+
// If a verify command exists, use it for accurate detection
|
|
102
|
+
const verifyCmd = IS_WINDOWS ? (e.install && e.install.verify_win) : (e.install && e.install.verify);
|
|
103
|
+
if (verifyCmd) {
|
|
104
|
+
try { execSync(verifyCmd, { stdio: 'ignore', timeout: 5000 }); installed = true; } catch {}
|
|
105
|
+
} else {
|
|
106
|
+
try { const { whichBinary } = require('./paths'); installed = !!whichBinary((e.install && e.install.binary) || e.name); } catch {}
|
|
107
|
+
}
|
|
108
|
+
|
|
100
109
|
if (!installed) {
|
|
101
110
|
try {
|
|
102
111
|
const f = path.join(connector._configDir, 'installed_agents.json');
|
|
@@ -225,14 +234,6 @@ function createTUI() {
|
|
|
225
234
|
}
|
|
226
235
|
|
|
227
236
|
// ── Footer rendering (context-aware, clickable) ──
|
|
228
|
-
// Maps footer action labels to the key they simulate
|
|
229
|
-
const footerKeyMap = {
|
|
230
|
-
'Install': 'i', 'New': 'n', 'Start': 's', 'Stop': 'x',
|
|
231
|
-
'Configure': 'e', 'Connect': 'c', 'Disconnect': 'd',
|
|
232
|
-
'Workspace': 'w', 'Remove': 'delete', 'Daemon': 'u',
|
|
233
|
-
'Refresh': 'r', 'Quit': 'q',
|
|
234
|
-
};
|
|
235
|
-
|
|
236
237
|
function updateFooter() {
|
|
237
238
|
const agent = agentRows[agentList.selected];
|
|
238
239
|
const items = [];
|
|
@@ -278,9 +279,9 @@ function createTUI() {
|
|
|
278
279
|
content: `{cyan-fg}${item.key}{/cyan-fg} ${item.label}`,
|
|
279
280
|
style: { bg: COLORS.footerBg, fg: COLORS.footerFg, hover: { bg: 'cyan', fg: 'black' } },
|
|
280
281
|
});
|
|
281
|
-
const
|
|
282
|
-
if (
|
|
283
|
-
btn.on('click', () =>
|
|
282
|
+
const action = footerActions[item.label];
|
|
283
|
+
if (action) {
|
|
284
|
+
btn.on('click', () => action());
|
|
284
285
|
}
|
|
285
286
|
footerButtons.push(btn);
|
|
286
287
|
left += text.length + 2;
|
|
@@ -1221,115 +1222,112 @@ function createTUI() {
|
|
|
1221
1222
|
// Key bindings
|
|
1222
1223
|
// ────────────────────────────────────────────────────────────────────────
|
|
1223
1224
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
signalDaemonReload();
|
|
1225
|
+
// ── Action handlers (shared by keys and clickable footer) ──
|
|
1226
|
+
const footerActions = {
|
|
1227
|
+
Install() { if (currentView === 'main') showInstallScreen(); },
|
|
1228
|
+
New() {
|
|
1229
|
+
if (currentView !== 'main') return;
|
|
1230
|
+
showSelectAgentTypeScreen((type) => {
|
|
1231
|
+
showStartAgentScreen(type, (result) => {
|
|
1232
|
+
try {
|
|
1233
|
+
connector.addAgent({ name: result.name, type: result.type, path: result.path });
|
|
1234
|
+
log(`{green-fg}\u2713{/green-fg} Created agent {cyan-fg}${result.name}{/cyan-fg} (${result.type})`);
|
|
1235
|
+
const pid = connector.getDaemonPid();
|
|
1236
|
+
if (!pid) {
|
|
1237
|
+
connector.startDaemon();
|
|
1238
|
+
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1239
|
+
} else {
|
|
1240
|
+
signalDaemonReload();
|
|
1241
|
+
}
|
|
1242
|
+
} catch (e) {
|
|
1243
|
+
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1244
1244
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
}
|
|
1248
|
-
setTimeout(refreshAgentTable, 3000);
|
|
1245
|
+
setTimeout(refreshAgentTable, 3000);
|
|
1246
|
+
});
|
|
1249
1247
|
});
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1248
|
+
},
|
|
1249
|
+
Start() {
|
|
1250
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1251
|
+
const a = agentRows[agentList.selected];
|
|
1252
|
+
if (a.configured) doStart(a.name);
|
|
1253
|
+
},
|
|
1254
|
+
Stop() {
|
|
1255
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1256
|
+
const a = agentRows[agentList.selected];
|
|
1257
|
+
if (a.configured) doStop(a.name);
|
|
1258
|
+
},
|
|
1259
|
+
Configure() {
|
|
1260
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1261
|
+
const a = agentRows[agentList.selected];
|
|
1262
|
+
if (a.configured) showConfigureScreen(a);
|
|
1263
|
+
},
|
|
1264
|
+
Connect() {
|
|
1265
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1266
|
+
const a = agentRows[agentList.selected];
|
|
1267
|
+
if (a.configured && !a.workspace) showConnectWorkspaceScreen(a.name);
|
|
1268
|
+
},
|
|
1269
|
+
Disconnect() {
|
|
1270
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1271
|
+
const a = agentRows[agentList.selected];
|
|
1272
|
+
if (a.configured && a.workspace) doDisconnect(a.name);
|
|
1273
|
+
},
|
|
1274
|
+
Workspace() {
|
|
1275
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1276
|
+
const a = agentRows[agentList.selected];
|
|
1277
|
+
if (a.configured && a.workspace) doOpenWorkspace(a);
|
|
1278
|
+
},
|
|
1279
|
+
Remove() {
|
|
1280
|
+
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1281
|
+
const a = agentRows[agentList.selected];
|
|
1282
|
+
if (a.configured) doRemove(a.name);
|
|
1283
|
+
},
|
|
1284
|
+
Daemon() {
|
|
1285
|
+
if (currentView !== 'main') return;
|
|
1286
|
+
const pid = connector.getDaemonPid();
|
|
1287
|
+
if (pid) {
|
|
1288
|
+
showConfirmDialog('Stop daemon? This will disconnect ALL agents.', (yes) => {
|
|
1289
|
+
if (!yes) { log('{gray-fg}Cancelled{/gray-fg}'); return; }
|
|
1290
|
+
try {
|
|
1291
|
+
connector.stopDaemon();
|
|
1292
|
+
log('{green-fg}\u2713{/green-fg} Daemon stopped');
|
|
1293
|
+
} catch (e) {
|
|
1294
|
+
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1295
|
+
}
|
|
1296
|
+
setTimeout(refreshAgentTable, 1000);
|
|
1297
|
+
});
|
|
1298
|
+
} else {
|
|
1280
1299
|
try {
|
|
1281
|
-
connector.
|
|
1282
|
-
log('{green-fg}\u2713{/green-fg} Daemon
|
|
1300
|
+
connector.startDaemon();
|
|
1301
|
+
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1283
1302
|
} catch (e) {
|
|
1284
1303
|
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1285
1304
|
}
|
|
1286
|
-
setTimeout(refreshAgentTable,
|
|
1287
|
-
});
|
|
1288
|
-
} else {
|
|
1289
|
-
try {
|
|
1290
|
-
connector.startDaemon();
|
|
1291
|
-
log('{green-fg}\u2713{/green-fg} Daemon starting...');
|
|
1292
|
-
} catch (e) {
|
|
1293
|
-
log(`{red-fg}\u2717{/red-fg} ${e.message}`);
|
|
1305
|
+
setTimeout(refreshAgentTable, 3000);
|
|
1294
1306
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
if (
|
|
1303
|
-
|
|
1304
|
-
});
|
|
1305
|
-
|
|
1306
|
-
screen.key('d', () => {
|
|
1307
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1308
|
-
const a = agentRows[agentList.selected];
|
|
1309
|
-
if (!a.configured || !a.workspace) return;
|
|
1310
|
-
doDisconnect(a.name);
|
|
1311
|
-
});
|
|
1312
|
-
|
|
1313
|
-
screen.key('w', () => {
|
|
1314
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1315
|
-
const a = agentRows[agentList.selected];
|
|
1316
|
-
if (!a.configured || !a.workspace) return;
|
|
1317
|
-
doOpenWorkspace(a);
|
|
1318
|
-
});
|
|
1319
|
-
|
|
1320
|
-
screen.key('e', () => {
|
|
1321
|
-
if (currentView !== 'main' || !agentRows[agentList.selected]) return;
|
|
1322
|
-
const a = agentRows[agentList.selected];
|
|
1323
|
-
if (!a.configured) return;
|
|
1324
|
-
showConfigureScreen(a);
|
|
1325
|
-
});
|
|
1307
|
+
},
|
|
1308
|
+
Refresh() {
|
|
1309
|
+
if (currentView === 'main') {
|
|
1310
|
+
refreshAgentTable();
|
|
1311
|
+
log('{green-fg}\u2713{/green-fg} Refreshed');
|
|
1312
|
+
}
|
|
1313
|
+
},
|
|
1314
|
+
Quit() { if (currentView === 'main') process.exit(0); },
|
|
1315
|
+
};
|
|
1326
1316
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1317
|
+
// Bind keyboard shortcuts
|
|
1318
|
+
screen.key('q', footerActions.Quit);
|
|
1319
|
+
screen.key('C-c', () => process.exit(0));
|
|
1320
|
+
screen.key('i', footerActions.Install);
|
|
1321
|
+
screen.key('n', footerActions.New);
|
|
1322
|
+
screen.key('r', footerActions.Refresh);
|
|
1323
|
+
screen.key('s', footerActions.Start);
|
|
1324
|
+
screen.key('x', footerActions.Stop);
|
|
1325
|
+
screen.key('u', footerActions.Daemon);
|
|
1326
|
+
screen.key('c', footerActions.Connect);
|
|
1327
|
+
screen.key('d', footerActions.Disconnect);
|
|
1328
|
+
screen.key('w', footerActions.Workspace);
|
|
1329
|
+
screen.key('e', footerActions.Configure);
|
|
1330
|
+
screen.key('delete', footerActions.Remove);
|
|
1333
1331
|
|
|
1334
1332
|
// ── Init ──
|
|
1335
1333
|
agentList.focus();
|