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 +49 -49
- package/lib/claude-runner.js +49 -9
- package/package.json +1 -1
- package/server.js +12 -20
- package/static/js/client.js +7 -6
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
|
|
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);
|
package/lib/claude-runner.js
CHANGED
|
@@ -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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
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)
|
|
404
|
-
id: bin.id,
|
|
405
|
-
|
|
406
|
-
icon: bin.icon,
|
|
407
|
-
|
|
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 =
|
|
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 =
|
|
501
|
-
for (const m of items) {
|
|
494
|
+
const models = items.map(m => {
|
|
502
495
|
const modelId = m.name.replace(/^models\//, '');
|
|
503
|
-
|
|
504
|
-
|
|
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
|
});
|
package/static/js/client.js
CHANGED
|
@@ -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()
|
|
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 ||
|
|
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.
|
|
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.
|
|
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 ||
|
|
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 ||
|
|
2568
|
+
return this.ui.cliSelector?.value || null;
|
|
2568
2569
|
}
|
|
2569
2570
|
|
|
2570
2571
|
getCurrentAgent() {
|