@openagents-org/agent-launcher 0.1.9 → 0.1.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tui.js +52 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-launcher",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/tui.js CHANGED
@@ -129,6 +129,7 @@ function generateAgentName(type) {
129
129
  function createTUI() {
130
130
  const screen = blessed.screen({
131
131
  smartCSR: true,
132
+ mouse: true,
132
133
  title: 'OpenAgents',
133
134
  fullUnicode: true,
134
135
  tags: true,
@@ -202,18 +203,19 @@ function createTUI() {
202
203
  style: { fg: 'white' },
203
204
  });
204
205
 
205
- // ── Footer ──
206
- const footer = blessed.box({
206
+ // ── Footer (clickable buttons) ──
207
+ const footerBar = blessed.box({
207
208
  bottom: 0, left: 0, width: '100%', height: 1,
208
209
  tags: true,
209
210
  style: { bg: COLORS.footerBg, fg: COLORS.footerFg },
210
211
  });
212
+ let footerButtons = [];
211
213
 
212
214
  screen.append(header);
213
215
  screen.append(titleBox);
214
216
  screen.append(agentPanel);
215
217
  screen.append(logPanel);
216
- screen.append(footer);
218
+ screen.append(footerBar);
217
219
 
218
220
  // ── Log helper ──
219
221
  function log(msg) {
@@ -222,36 +224,68 @@ function createTUI() {
222
224
  screen.render();
223
225
  }
224
226
 
225
- // ── Footer rendering (context-aware) ──
227
+ // ── 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
+
226
236
  function updateFooter() {
227
237
  const agent = agentRows[agentList.selected];
228
- const parts = [];
238
+ const items = [];
229
239
 
230
- parts.push('{cyan-fg}i{/cyan-fg} Install');
231
- parts.push('{cyan-fg}n{/cyan-fg} New');
240
+ items.push({ key: 'i', label: 'Install' });
241
+ items.push({ key: 'n', label: 'New' });
232
242
 
233
243
  if (agent && agent.configured) {
234
244
  const isRunning = ['running', 'online', 'starting', 'reconnecting'].includes(agent.state);
235
245
  const isStopped = ['stopped', 'error'].includes(agent.state);
236
246
 
237
- if (isStopped) parts.push('{cyan-fg}s{/cyan-fg} Start');
238
- if (isRunning) parts.push('{cyan-fg}x{/cyan-fg} Stop');
247
+ if (isStopped) items.push({ key: 's', label: 'Start' });
248
+ if (isRunning) items.push({ key: 'x', label: 'Stop' });
239
249
 
240
250
  const envFields = connector.registry.getEnvFields(agent.type);
241
- if (envFields && envFields.length > 0) parts.push('{cyan-fg}e{/cyan-fg} Configure');
251
+ if (envFields && envFields.length > 0) items.push({ key: 'e', label: 'Configure' });
242
252
 
243
- if (!agent.workspace) parts.push('{cyan-fg}c{/cyan-fg} Connect');
244
- if (agent.workspace) parts.push('{cyan-fg}d{/cyan-fg} Disconnect');
245
- if (agent.workspace) parts.push('{cyan-fg}w{/cyan-fg} Workspace');
253
+ if (!agent.workspace) items.push({ key: 'c', label: 'Connect' });
254
+ if (agent.workspace) items.push({ key: 'd', label: 'Disconnect' });
255
+ if (agent.workspace) items.push({ key: 'w', label: 'Workspace' });
246
256
 
247
- parts.push('{cyan-fg}Del{/cyan-fg} Remove');
257
+ items.push({ key: 'Del', label: 'Remove' });
248
258
  }
249
259
 
250
- parts.push('{cyan-fg}u{/cyan-fg} Daemon');
251
- parts.push('{cyan-fg}r{/cyan-fg} Refresh');
252
- parts.push('{cyan-fg}q{/cyan-fg} Quit');
260
+ items.push({ key: 'u', label: 'Daemon' });
261
+ items.push({ key: 'r', label: 'Refresh' });
262
+ items.push({ key: 'q', label: 'Quit' });
263
+
264
+ // Remove old buttons
265
+ for (const btn of footerButtons) { footerBar.remove(btn); btn.destroy(); }
266
+ footerButtons = [];
267
+
268
+ let left = 1;
269
+ for (const item of items) {
270
+ const text = `${item.key} ${item.label}`;
271
+ const btn = blessed.box({
272
+ parent: footerBar,
273
+ left, top: 0, height: 1,
274
+ width: text.length + 2,
275
+ tags: true,
276
+ mouse: true,
277
+ clickable: true,
278
+ content: `{cyan-fg}${item.key}{/cyan-fg} ${item.label}`,
279
+ style: { bg: COLORS.footerBg, fg: COLORS.footerFg, hover: { bg: 'cyan', fg: 'black' } },
280
+ });
281
+ const actionKey = footerKeyMap[item.label];
282
+ if (actionKey) {
283
+ btn.on('click', () => { screen.emit('keypress', null, { full: actionKey, name: actionKey }); });
284
+ }
285
+ footerButtons.push(btn);
286
+ left += text.length + 2;
287
+ }
253
288
 
254
- footer.setContent(' ' + parts.join(' '));
255
289
  screen.render();
256
290
  }
257
291