agentgui 1.0.743 → 1.0.745
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 +8 -5
- package/package.json +1 -1
- package/server.js +31 -0
- package/static/js/client.js +18 -0
- package/static/theme.js +7 -4
package/database.js
CHANGED
|
@@ -421,7 +421,8 @@ try {
|
|
|
421
421
|
claudeSessionId: 'TEXT',
|
|
422
422
|
isStreaming: 'INTEGER DEFAULT 0',
|
|
423
423
|
model: 'TEXT',
|
|
424
|
-
subAgent: 'TEXT'
|
|
424
|
+
subAgent: 'TEXT',
|
|
425
|
+
pinned: 'INTEGER DEFAULT 0'
|
|
425
426
|
};
|
|
426
427
|
|
|
427
428
|
let addedColumns = false;
|
|
@@ -644,13 +645,13 @@ export const queries = {
|
|
|
644
645
|
|
|
645
646
|
getConversationsList() {
|
|
646
647
|
const stmt = prep(
|
|
647
|
-
'SELECT id, agentId, title, agentType, created_at, updated_at, messageCount, workingDirectory, isStreaming, model, subAgent FROM conversations WHERE status != ? ORDER BY updated_at DESC'
|
|
648
|
+
'SELECT id, agentId, title, agentType, created_at, updated_at, messageCount, workingDirectory, isStreaming, model, subAgent, pinned FROM conversations WHERE status != ? ORDER BY pinned DESC, updated_at DESC'
|
|
648
649
|
);
|
|
649
650
|
return stmt.all('deleted');
|
|
650
651
|
},
|
|
651
652
|
|
|
652
653
|
getConversations() {
|
|
653
|
-
const stmt = prep('SELECT * FROM conversations WHERE status != ? ORDER BY updated_at DESC');
|
|
654
|
+
const stmt = prep('SELECT * FROM conversations WHERE status != ? ORDER BY pinned DESC, updated_at DESC');
|
|
654
655
|
return stmt.all('deleted');
|
|
655
656
|
},
|
|
656
657
|
|
|
@@ -665,11 +666,12 @@ export const queries = {
|
|
|
665
666
|
const agentType = data.agentType !== undefined ? data.agentType : conv.agentType;
|
|
666
667
|
const model = data.model !== undefined ? data.model : conv.model;
|
|
667
668
|
const subAgent = data.subAgent !== undefined ? data.subAgent : conv.subAgent;
|
|
669
|
+
const pinned = data.pinned !== undefined ? (data.pinned ? 1 : 0) : (conv.pinned || 0);
|
|
668
670
|
|
|
669
671
|
const stmt = prep(
|
|
670
|
-
`UPDATE conversations SET title = ?, status = ?, agentId = ?, agentType = ?, model = ?, subAgent = ?, updated_at = ? WHERE id = ?`
|
|
672
|
+
`UPDATE conversations SET title = ?, status = ?, agentId = ?, agentType = ?, model = ?, subAgent = ?, pinned = ?, updated_at = ? WHERE id = ?`
|
|
671
673
|
);
|
|
672
|
-
stmt.run(title, status, agentId, agentType, model, subAgent, now, id);
|
|
674
|
+
stmt.run(title, status, agentId, agentType, model, subAgent, pinned, now, id);
|
|
673
675
|
|
|
674
676
|
return {
|
|
675
677
|
...conv,
|
|
@@ -679,6 +681,7 @@ export const queries = {
|
|
|
679
681
|
agentType,
|
|
680
682
|
model,
|
|
681
683
|
subAgent,
|
|
684
|
+
pinned,
|
|
682
685
|
updated_at: now
|
|
683
686
|
};
|
|
684
687
|
},
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -2107,6 +2107,37 @@ const server = http.createServer(async (req, res) => {
|
|
|
2107
2107
|
return;
|
|
2108
2108
|
}
|
|
2109
2109
|
|
|
2110
|
+
if (pathOnly === '/api/backup' && req.method === 'GET') {
|
|
2111
|
+
const dbPath = path.join(os.homedir(), '.gmgui', 'data.db');
|
|
2112
|
+
if (!fs.existsSync(dbPath)) { sendJSON(req, res, 404, { error: 'Database not found' }); return; }
|
|
2113
|
+
const stat = fs.statSync(dbPath);
|
|
2114
|
+
res.writeHead(200, { 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="agentgui-backup.db"', 'Content-Length': stat.size });
|
|
2115
|
+
fs.createReadStream(dbPath).pipe(res);
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
if (pathOnly === '/api/restore' && req.method === 'POST') {
|
|
2120
|
+
const dbPath = path.join(os.homedir(), '.gmgui', 'data.db');
|
|
2121
|
+
const backupPath = dbPath + '.bak-' + Date.now();
|
|
2122
|
+
const chunks = [];
|
|
2123
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
2124
|
+
req.on('end', () => {
|
|
2125
|
+
try {
|
|
2126
|
+
const body = Buffer.concat(chunks);
|
|
2127
|
+
if (body.length < 100 || body.slice(0, 16).toString() !== 'SQLite format 3\0') {
|
|
2128
|
+
sendJSON(req, res, 400, { error: 'Invalid SQLite database file' });
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
fs.copyFileSync(dbPath, backupPath);
|
|
2132
|
+
fs.writeFileSync(dbPath, body);
|
|
2133
|
+
sendJSON(req, res, 200, { success: true, backupPath, size: body.length });
|
|
2134
|
+
} catch (e) {
|
|
2135
|
+
sendJSON(req, res, 500, { error: e.message });
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2110
2141
|
if (pathOnly === '/api/debug/machines' && req.method === 'GET' && process.env.DEBUG) {
|
|
2111
2142
|
const toolSnap = {};
|
|
2112
2143
|
for (const [id, actor] of toolInstallMachine.getMachineActors()) {
|
package/static/js/client.js
CHANGED
|
@@ -914,6 +914,18 @@ class AgentGUIClient {
|
|
|
914
914
|
this.scrollToBottom(true);
|
|
915
915
|
}
|
|
916
916
|
|
|
917
|
+
this._streamStartedAt = Date.now();
|
|
918
|
+
this._sessionCost = 0;
|
|
919
|
+
if (this._elapsedTimer) clearInterval(this._elapsedTimer);
|
|
920
|
+
this._elapsedTimer = setInterval(() => {
|
|
921
|
+
const label = streamingDiv?.querySelector('.streaming-indicator-label');
|
|
922
|
+
if (label) {
|
|
923
|
+
const sec = ((Date.now() - this._streamStartedAt) / 1000) | 0;
|
|
924
|
+
const time = sec < 60 ? sec + 's' : Math.floor(sec / 60) + 'm ' + (sec % 60) + 's';
|
|
925
|
+
label.textContent = this._sessionCost > 0 ? time + ' · $' + this._sessionCost.toFixed(4) : time;
|
|
926
|
+
}
|
|
927
|
+
}, 1000);
|
|
928
|
+
|
|
917
929
|
// Reset rendered block seq tracker for this session
|
|
918
930
|
this._renderedSeqs[data.sessionId] = new Set();
|
|
919
931
|
|
|
@@ -1030,6 +1042,10 @@ class AgentGUIClient {
|
|
|
1030
1042
|
return;
|
|
1031
1043
|
}
|
|
1032
1044
|
|
|
1045
|
+
if (block.type === 'result' && block.total_cost_usd) {
|
|
1046
|
+
this._sessionCost = (this._sessionCost || 0) + block.total_cost_usd;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1033
1049
|
const el = this.renderer.renderBlock(block, data, blocksEl);
|
|
1034
1050
|
if (el) {
|
|
1035
1051
|
blocksEl.appendChild(el);
|
|
@@ -1116,6 +1132,7 @@ class AgentGUIClient {
|
|
|
1116
1132
|
console.error('Streaming error:', data);
|
|
1117
1133
|
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
1118
1134
|
this._clearThinkingCountdown();
|
|
1135
|
+
if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
|
|
1119
1136
|
|
|
1120
1137
|
// Hide stop and inject buttons on error
|
|
1121
1138
|
if (this.ui.stopButton) this.ui.stopButton.classList.remove('visible');
|
|
@@ -1194,6 +1211,7 @@ class AgentGUIClient {
|
|
|
1194
1211
|
this._dbg('Streaming completed:', data);
|
|
1195
1212
|
if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
|
|
1196
1213
|
this._clearThinkingCountdown();
|
|
1214
|
+
if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
|
|
1197
1215
|
|
|
1198
1216
|
const conversationId = data.conversationId || this.state.currentSession?.conversationId;
|
|
1199
1217
|
if (conversationId) this.invalidateCache(conversationId);
|
package/static/theme.js
CHANGED
|
@@ -53,15 +53,18 @@ class ThemeManager {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
toggleTheme() {
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
this.setTheme(
|
|
56
|
+
const saved = localStorage.getItem(this.THEME_KEY);
|
|
57
|
+
const current = document.documentElement.getAttribute('data-theme') || 'light';
|
|
58
|
+
if (saved === 'dark') { this.setTheme('light'); }
|
|
59
|
+
else if (saved === 'light') { localStorage.removeItem(this.THEME_KEY); this.setTheme(this.SYSTEM_DARK_MODE.matches ? 'dark' : 'light'); this.updateThemeIcon('auto'); return; }
|
|
60
|
+
else { this.setTheme('dark'); }
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
updateThemeIcon(theme) {
|
|
62
64
|
const icon = document.querySelector('.theme-icon');
|
|
63
65
|
if (icon) {
|
|
64
|
-
icon.textContent = theme === 'dark' ? '☀️' : '🌙';
|
|
66
|
+
icon.textContent = theme === 'auto' ? '⚙️' : theme === 'dark' ? '☀️' : '🌙';
|
|
67
|
+
icon.title = theme === 'auto' ? 'Theme: Auto (follows OS)' : theme === 'dark' ? 'Theme: Dark' : 'Theme: Light';
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|