agentgui 1.0.428 → 1.0.430

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/database.js CHANGED
@@ -329,7 +329,7 @@ try {
329
329
  const result = db.prepare("PRAGMA table_info(conversations)").all();
330
330
  const columnNames = result.map(r => r.name);
331
331
  const requiredColumns = {
332
- agentType: 'TEXT DEFAULT "claude-code"',
332
+ agentType: 'TEXT',
333
333
  source: 'TEXT DEFAULT "gui"',
334
334
  externalId: 'TEXT',
335
335
  firstPrompt: 'TEXT',
@@ -939,54 +939,54 @@ export const queries = {
939
939
  return true;
940
940
  },
941
941
 
942
- deleteClaudeSessionFile(sessionId) {
943
- try {
944
- const claudeDir = path.join(os.homedir(), '.claude');
945
- const projectsDir = path.join(claudeDir, 'projects');
946
-
947
- if (!fs.existsSync(projectsDir)) {
948
- return false;
949
- }
950
-
951
- // Search for session file in all project directories
952
- const projects = fs.readdirSync(projectsDir);
953
- for (const project of projects) {
954
- const projectPath = path.join(projectsDir, project);
955
- const sessionFile = path.join(projectPath, `${sessionId}.jsonl`);
956
-
957
- if (fs.existsSync(sessionFile)) {
958
- fs.unlinkSync(sessionFile);
959
- console.log(`[deleteClaudeSessionFile] Deleted Claude session file: ${sessionFile}`);
960
-
961
- // Also remove the entry from sessions-index.json if it exists
962
- const indexPath = path.join(projectPath, 'sessions-index.json');
963
- if (fs.existsSync(indexPath)) {
964
- try {
965
- const indexContent = fs.readFileSync(indexPath, 'utf8');
966
- const index = JSON.parse(indexContent);
967
- if (index.entries && Array.isArray(index.entries)) {
968
- const originalLength = index.entries.length;
969
- index.entries = index.entries.filter(entry => entry.sessionId !== sessionId);
970
- if (index.entries.length < originalLength) {
971
- fs.writeFileSync(indexPath, JSON.stringify(index, null, 2), { encoding: 'utf8' });
972
- console.log(`[deleteClaudeSessionFile] Removed session ${sessionId} from sessions-index.json in ${projectPath}`);
973
- }
974
- }
975
- } catch (indexErr) {
976
- console.error(`[deleteClaudeSessionFile] Failed to update sessions-index.json in ${projectPath}:`, indexErr.message);
977
- }
978
- }
979
-
980
- return true;
981
- }
982
- }
983
-
984
- return false;
985
- } catch (err) {
986
- console.error(`[deleteClaudeSessionFile] Error deleting session ${sessionId}:`, err.message);
987
- return false;
988
- }
989
- },
942
+ deleteClaudeSessionFile(sessionId) {
943
+ try {
944
+ const claudeDir = path.join(os.homedir(), '.claude');
945
+ const projectsDir = path.join(claudeDir, 'projects');
946
+
947
+ if (!fs.existsSync(projectsDir)) {
948
+ return false;
949
+ }
950
+
951
+ // Search for session file in all project directories
952
+ const projects = fs.readdirSync(projectsDir);
953
+ for (const project of projects) {
954
+ const projectPath = path.join(projectsDir, project);
955
+ const sessionFile = path.join(projectPath, `${sessionId}.jsonl`);
956
+
957
+ if (fs.existsSync(sessionFile)) {
958
+ fs.unlinkSync(sessionFile);
959
+ console.log(`[deleteClaudeSessionFile] Deleted Claude session file: ${sessionFile}`);
960
+
961
+ // Also remove the entry from sessions-index.json if it exists
962
+ const indexPath = path.join(projectPath, 'sessions-index.json');
963
+ if (fs.existsSync(indexPath)) {
964
+ try {
965
+ const indexContent = fs.readFileSync(indexPath, 'utf8');
966
+ const index = JSON.parse(indexContent);
967
+ if (index.entries && Array.isArray(index.entries)) {
968
+ const originalLength = index.entries.length;
969
+ index.entries = index.entries.filter(entry => entry.sessionId !== sessionId);
970
+ if (index.entries.length < originalLength) {
971
+ fs.writeFileSync(indexPath, JSON.stringify(index, null, 2), { encoding: 'utf8' });
972
+ console.log(`[deleteClaudeSessionFile] Removed session ${sessionId} from sessions-index.json in ${projectPath}`);
973
+ }
974
+ }
975
+ } catch (indexErr) {
976
+ console.error(`[deleteClaudeSessionFile] Failed to update sessions-index.json in ${projectPath}:`, indexErr.message);
977
+ }
978
+ }
979
+
980
+ return true;
981
+ }
982
+ }
983
+
984
+ return false;
985
+ } catch (err) {
986
+ console.error(`[deleteClaudeSessionFile] Error deleting session ${sessionId}:`, err.message);
987
+ return false;
988
+ }
989
+ },
990
990
 
991
991
  cleanup() {
992
992
  const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
@@ -10,6 +10,25 @@ function getSpawnOptions(cwd, additionalOptions = {}) {
10
10
  return options;
11
11
  }
12
12
 
13
+ function resolveCommand(command, npxPackage) {
14
+ const whichCmd = isWindows ? 'where' : 'which';
15
+ const check = spawnSync(whichCmd, [command], { encoding: 'utf-8', timeout: 3000 });
16
+ if (check.status === 0 && (check.stdout || '').trim()) {
17
+ return { cmd: command, prefixArgs: [] };
18
+ }
19
+ if (npxPackage) {
20
+ const npxCheck = spawnSync(whichCmd, ['npx'], { encoding: 'utf-8', timeout: 3000 });
21
+ if (npxCheck.status === 0) {
22
+ return { cmd: 'npx', prefixArgs: ['--yes', npxPackage] };
23
+ }
24
+ const bunxCheck = spawnSync(whichCmd, ['bunx'], { encoding: 'utf-8', timeout: 3000 });
25
+ if (bunxCheck.status === 0) {
26
+ return { cmd: 'bunx', prefixArgs: [npxPackage] };
27
+ }
28
+ }
29
+ return { cmd: command, prefixArgs: [] };
30
+ }
31
+
13
32
  /**
14
33
  * Agent Framework
15
34
  * Extensible registry for AI agent CLI integrations
@@ -30,6 +49,7 @@ class AgentRunner {
30
49
  this.requiresAdapter = config.requiresAdapter || false;
31
50
  this.adapterCommand = config.adapterCommand || null;
32
51
  this.adapterArgs = config.adapterArgs || [];
52
+ this.npxPackage = config.npxPackage || null;
33
53
  }
34
54
 
35
55
  defaultBuildArgs(prompt, config) {
@@ -226,9 +246,15 @@ class AgentRunner {
226
246
  onError = null
227
247
  } = config;
228
248
 
229
- const cmd = this.requiresAdapter && this.adapterCommand ? this.adapterCommand : this.command;
230
- const baseArgs = this.requiresAdapter && this.adapterCommand ? this.adapterArgs : this.buildArgs(prompt, config);
231
- const args = [...baseArgs];
249
+ let cmd, args;
250
+ if (this.requiresAdapter && this.adapterCommand) {
251
+ cmd = this.adapterCommand;
252
+ args = [...this.adapterArgs];
253
+ } else {
254
+ const resolved = resolveCommand(this.command, this.npxPackage);
255
+ cmd = resolved.cmd;
256
+ args = [...resolved.prefixArgs, ...this.buildArgs(prompt, config)];
257
+ }
232
258
 
233
259
  const proc = spawn(cmd, args, getSpawnOptions(cwd));
234
260
 
@@ -494,7 +520,8 @@ class AgentRegistry {
494
520
  command: a.command,
495
521
  protocol: a.protocol,
496
522
  requiresAdapter: a.requiresAdapter,
497
- supportedFeatures: a.supportedFeatures
523
+ supportedFeatures: a.supportedFeatures,
524
+ npxPackage: a.npxPackage
498
525
  }));
499
526
  }
500
527
 
@@ -503,11 +530,21 @@ class AgentRegistry {
503
530
  try {
504
531
  const whichCmd = isWindows ? 'where' : 'which';
505
532
  const which = spawnSync(whichCmd, [agent.command], { encoding: 'utf-8', timeout: 3000 });
506
- if (which.status !== 0) return false;
507
- const binPath = (which.stdout || '').trim().split('\n')[0].trim();
508
- if (!binPath) return false;
509
- const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000, shell: isWindows });
510
- return check.status === 0 && (check.stdout || '').trim().length > 0;
533
+ if (which.status === 0) {
534
+ const binPath = (which.stdout || '').trim().split('\n')[0].trim();
535
+ if (binPath) {
536
+ const check = spawnSync(binPath, ['--version'], { encoding: 'utf-8', timeout: 10000, shell: isWindows });
537
+ if (check.status === 0 && (check.stdout || '').trim().length > 0) return true;
538
+ }
539
+ }
540
+ const a = this.agents.get(agent.id);
541
+ if (a && a.npxPackage) {
542
+ const npxCheck = spawnSync(whichCmd, ['npx'], { encoding: 'utf-8', timeout: 3000 });
543
+ if (npxCheck.status === 0) return true;
544
+ const bunxCheck = spawnSync(whichCmd, ['bunx'], { encoding: 'utf-8', timeout: 3000 });
545
+ if (bunxCheck.status === 0) return true;
546
+ }
547
+ return false;
511
548
  } catch {
512
549
  return false;
513
550
  }
@@ -571,6 +608,7 @@ registry.register({
571
608
  command: 'opencode',
572
609
  protocol: 'acp',
573
610
  supportsStdin: false,
611
+ npxPackage: 'opencode-ai',
574
612
  supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
575
613
 
576
614
  buildArgs(prompt, config) {
@@ -923,6 +961,7 @@ registry.register({
923
961
  command: 'gemini',
924
962
  protocol: 'acp',
925
963
  supportsStdin: false,
964
+ npxPackage: '@google/gemini-cli',
926
965
  supportedFeatures: ['streaming', 'resume', 'acp-protocol'],
927
966
  buildArgs(prompt, config) {
928
967
  const args = ['--experimental-acp', '--yolo'];
@@ -1085,6 +1124,7 @@ registry.register({
1085
1124
  command: 'kilo',
1086
1125
  protocol: 'acp',
1087
1126
  supportsStdin: false,
1127
+ npxPackage: '@kilocode/cli',
1088
1128
  supportedFeatures: ['streaming', 'resume', 'acp-protocol', 'models'],
1089
1129
 
1090
1130
  buildArgs(prompt, config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.428",
3
+ "version": "1.0.430",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -384,9 +384,9 @@ function discoverAgents() {
384
384
  const agents = [];
385
385
  const binaries = [
386
386
  { cmd: 'claude', id: 'claude-code', name: 'Claude Code', icon: 'C', protocol: 'cli' },
387
- { cmd: 'opencode', id: 'opencode', name: 'OpenCode', icon: 'O', protocol: 'acp' },
388
- { cmd: 'gemini', id: 'gemini', name: 'Gemini CLI', icon: 'G', protocol: 'acp' },
389
- { cmd: 'kilo', id: 'kilo', name: 'Kilo Code', icon: 'K', protocol: 'acp' },
387
+ { cmd: 'opencode', id: 'opencode', name: 'OpenCode', icon: 'O', protocol: 'acp', npxPackage: 'opencode-ai' },
388
+ { cmd: 'gemini', id: 'gemini', name: 'Gemini CLI', icon: 'G', protocol: 'acp', npxPackage: '@google/gemini-cli' },
389
+ { cmd: 'kilo', id: 'kilo', name: 'Kilo Code', icon: 'K', protocol: 'acp', npxPackage: '@kilocode/cli' },
390
390
  { cmd: 'goose', id: 'goose', name: 'Goose', icon: 'g', protocol: 'acp' },
391
391
  { cmd: 'openhands', id: 'openhands', name: 'OpenHands', icon: 'H', protocol: 'acp' },
392
392
  { cmd: 'augment', id: 'augment', name: 'Augment Code', icon: 'A', protocol: 'acp' },
@@ -400,13 +400,11 @@ function discoverAgents() {
400
400
  ];
401
401
  for (const bin of binaries) {
402
402
  const result = findCommand(bin.cmd);
403
- if (result) agents.push({
404
- id: bin.id,
405
- name: bin.name,
406
- icon: bin.icon,
407
- path: result,
408
- protocol: bin.protocol
409
- });
403
+ if (result) {
404
+ agents.push({ id: bin.id, name: bin.name, icon: bin.icon, path: result, protocol: bin.protocol });
405
+ } else if (bin.npxPackage) {
406
+ agents.push({ id: bin.id, name: bin.name, icon: bin.icon, path: null, protocol: bin.protocol, npxPackage: bin.npxPackage, npxLaunchable: true });
407
+ }
410
408
  }
411
409
  return agents;
412
410
  }
@@ -462,11 +460,7 @@ async function fetchClaudeModelsFromAPI() {
462
460
  const data = JSON.parse(body);
463
461
  const items = (data.data || []).filter(m => m.id && m.id.startsWith('claude-'));
464
462
  if (items.length === 0) return resolve(null);
465
- const models = [{ id: '', label: 'Default' }];
466
- for (const m of items) {
467
- const label = m.display_name || modelIdToLabel(m.id);
468
- models.push({ id: m.id, label });
469
- }
463
+ const models = items.map(m => ({ id: m.id, label: m.display_name || modelIdToLabel(m.id) }));
470
464
  resolve(models);
471
465
  } catch { resolve(null); }
472
466
  });
@@ -497,12 +491,10 @@ async function fetchGeminiModelsFromAPI() {
497
491
  const data = JSON.parse(body);
498
492
  const items = (data.models || []).filter(m => m.name && m.name.includes('gemini'));
499
493
  if (items.length === 0) return resolve(null);
500
- const models = [{ id: '', label: 'Default' }];
501
- for (const m of items) {
494
+ const models = items.map(m => {
502
495
  const modelId = m.name.replace(/^models\//, '');
503
- const label = modelId.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
504
- models.push({ id: modelId, label });
505
- }
496
+ return { id: modelId, label: modelId.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()) };
497
+ });
506
498
  resolve(models);
507
499
  } catch { resolve(null); }
508
500
  });
@@ -1260,7 +1260,7 @@ class AgentGUIClient {
1260
1260
  const prompt = this.ui.messageInput?.value || '';
1261
1261
  const conv = this.state.currentConversation;
1262
1262
  const isNewConversation = conv && !conv.messageCount && !this.state.streamingConversations.has(conv.id);
1263
- const agentId = (isNewConversation ? this.getCurrentAgent() : null) || conv?.agentType || this.getCurrentAgent() || 'claude-code';
1263
+ const agentId = (isNewConversation ? this.getCurrentAgent() : null) || conv?.agentType || this.getCurrentAgent();
1264
1264
  const model = this.ui.modelSelector?.value || null;
1265
1265
 
1266
1266
  if (!prompt.trim()) {
@@ -1970,7 +1970,7 @@ class AgentGUIClient {
1970
1970
  * Consolidates duplicate logic for cached and fresh conversation loads
1971
1971
  */
1972
1972
  applyAgentAndModelSelection(conversation, hasActivity) {
1973
- const agentId = conversation.agentId || conversation.agentType || 'claude-code';
1973
+ const agentId = conversation.agentId || conversation.agentType || null;
1974
1974
  const model = conversation.model || null;
1975
1975
 
1976
1976
  if (hasActivity) {
@@ -1980,7 +1980,8 @@ class AgentGUIClient {
1980
1980
  this.unlockAgentAndModel();
1981
1981
  this._setCliSelectorToAgent(agentId);
1982
1982
 
1983
- this.loadModelsForAgent(agentId).then(() => {
1983
+ const effectiveAgentId = agentId || this.getEffectiveAgentId();
1984
+ this.loadModelsForAgent(effectiveAgentId).then(() => {
1984
1985
  if (model && this.ui.modelSelector) {
1985
1986
  this.ui.modelSelector.value = model;
1986
1987
  }
@@ -2185,7 +2186,7 @@ class AgentGUIClient {
2185
2186
  */
2186
2187
  async createNewConversation(workingDirectory, title) {
2187
2188
  try {
2188
- const agentId = this.ui.agentSelector?.value || 'claude-code';
2189
+ const agentId = this.getEffectiveAgentId();
2189
2190
  const model = this.ui.modelSelector?.value || null;
2190
2191
  const convTitle = title || 'New Conversation';
2191
2192
  const body = { agentId, title: convTitle };
@@ -2461,7 +2462,7 @@ class AgentGUIClient {
2461
2462
  this.state.currentSession = {
2462
2463
  id: latestSession.id,
2463
2464
  conversationId: conversationId,
2464
- agentId: conversation.agentType || 'claude-code',
2465
+ agentId: conversation.agentType || null,
2465
2466
  startTime: latestSession.created_at
2466
2467
  };
2467
2468
 
@@ -2564,7 +2565,7 @@ class AgentGUIClient {
2564
2565
  if (this.ui.agentSelector?.value && this.ui.agentSelector.style.display !== 'none') {
2565
2566
  return this.ui.agentSelector.value;
2566
2567
  }
2567
- return this.ui.cliSelector?.value || 'claude-code';
2568
+ return this.ui.cliSelector?.value || null;
2568
2569
  }
2569
2570
 
2570
2571
  getCurrentAgent() {