agentgui 1.0.743 → 1.0.744

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
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.743",
3
+ "version": "1.0.744",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
package/server.js CHANGED
@@ -2107,6 +2107,15 @@ 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
+
2110
2119
  if (pathOnly === '/api/debug/machines' && req.method === 'GET' && process.env.DEBUG) {
2111
2120
  const toolSnap = {};
2112
2121
  for (const [id, actor] of toolInstallMachine.getMachineActors()) {
@@ -914,6 +914,16 @@ class AgentGUIClient {
914
914
  this.scrollToBottom(true);
915
915
  }
916
916
 
917
+ this._streamStartedAt = Date.now();
918
+ if (this._elapsedTimer) clearInterval(this._elapsedTimer);
919
+ this._elapsedTimer = setInterval(() => {
920
+ const label = streamingDiv?.querySelector('.streaming-indicator-label');
921
+ if (label) {
922
+ const sec = ((Date.now() - this._streamStartedAt) / 1000) | 0;
923
+ label.textContent = sec < 60 ? sec + 's' : Math.floor(sec / 60) + 'm ' + (sec % 60) + 's';
924
+ }
925
+ }, 1000);
926
+
917
927
  // Reset rendered block seq tracker for this session
918
928
  this._renderedSeqs[data.sessionId] = new Set();
919
929
 
@@ -1116,6 +1126,7 @@ class AgentGUIClient {
1116
1126
  console.error('Streaming error:', data);
1117
1127
  if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
1118
1128
  this._clearThinkingCountdown();
1129
+ if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
1119
1130
 
1120
1131
  // Hide stop and inject buttons on error
1121
1132
  if (this.ui.stopButton) this.ui.stopButton.classList.remove('visible');
@@ -1194,6 +1205,7 @@ class AgentGUIClient {
1194
1205
  this._dbg('Streaming completed:', data);
1195
1206
  if (window.promptMachineAPI) window.promptMachineAPI.send({ type: 'READY' });
1196
1207
  this._clearThinkingCountdown();
1208
+ if (this._elapsedTimer) { clearInterval(this._elapsedTimer); this._elapsedTimer = null; }
1197
1209
 
1198
1210
  const conversationId = data.conversationId || this.state.currentSession?.conversationId;
1199
1211
  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 currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
57
- const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
58
- this.setTheme(newTheme);
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