agentgui 1.0.110 → 1.0.112
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/.prd +281 -0
- package/database.js +87 -0
- package/package.json +2 -2
- package/server.js +25 -2
- package/static/index.html +50 -4
- package/static/js/client.js +14 -7
- package/static/js/conversations.js +41 -2
- package/conversation-importer.js +0 -63
- package/hot-reload-manager.js +0 -186
- package/lib/database-service.ts +0 -640
- package/lib/machines.ts +0 -190
- package/lib/schemas.ts +0 -190
- package/lib/sync-service.ts +0 -615
- package/lib/types.ts +0 -413
package/conversation-importer.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import { queries } from './database.js';
|
|
5
|
-
|
|
6
|
-
export class ConversationImporter {
|
|
7
|
-
static async importClaudeCodeSessions() {
|
|
8
|
-
const projectsDir = path.join(os.homedir(), '.claude', 'projects');
|
|
9
|
-
if (!fs.existsSync(projectsDir)) return [];
|
|
10
|
-
|
|
11
|
-
const imported = [];
|
|
12
|
-
const projects = fs.readdirSync(projectsDir);
|
|
13
|
-
|
|
14
|
-
for (const projectName of projects) {
|
|
15
|
-
const indexPath = path.join(projectsDir, projectName, 'sessions-index.json');
|
|
16
|
-
if (!fs.existsSync(indexPath)) continue;
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const index = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
|
|
20
|
-
const entries = index.entries || [];
|
|
21
|
-
|
|
22
|
-
for (const entry of entries) {
|
|
23
|
-
try {
|
|
24
|
-
const existing = queries.getConversationByExternalId('claude-code', entry.sessionId);
|
|
25
|
-
if (existing) continue;
|
|
26
|
-
|
|
27
|
-
const conversation = {
|
|
28
|
-
externalId: entry.sessionId,
|
|
29
|
-
agentType: 'claude-code',
|
|
30
|
-
title: entry.summary || entry.firstPrompt || `Conversation ${entry.sessionId.slice(0, 8)}`,
|
|
31
|
-
firstPrompt: entry.firstPrompt,
|
|
32
|
-
messageCount: entry.messageCount || 0,
|
|
33
|
-
created: new Date(entry.created).getTime(),
|
|
34
|
-
modified: new Date(entry.modified).getTime(),
|
|
35
|
-
projectPath: entry.projectPath,
|
|
36
|
-
gitBranch: entry.gitBranch,
|
|
37
|
-
sourcePath: entry.fullPath,
|
|
38
|
-
source: 'imported'
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
queries.createImportedConversation(conversation);
|
|
42
|
-
imported.push(conversation);
|
|
43
|
-
} catch (err) {
|
|
44
|
-
console.error(`[Importer] Error importing session ${entry.sessionId}:`, err.message);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} catch (err) {
|
|
48
|
-
console.error(`[Importer] Error reading ${indexPath}:`, err.message);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return imported;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
static async importAll() {
|
|
56
|
-
console.log('[Importer] Starting conversation import...');
|
|
57
|
-
const claudeCode = await this.importClaudeCodeSessions();
|
|
58
|
-
console.log(`[Importer] Imported ${claudeCode.length} Claude Code conversations`);
|
|
59
|
-
return claudeCode;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default ConversationImporter;
|
package/hot-reload-manager.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hot Reload Manager
|
|
3
|
-
* Enables live reloading of client code and graceful server restarts without losing connections
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
|
|
10
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
|
|
12
|
-
export class HotReloadManager {
|
|
13
|
-
constructor(staticDir, options = {}) {
|
|
14
|
-
this.staticDir = staticDir;
|
|
15
|
-
this.watchedFiles = new Map();
|
|
16
|
-
this.hotReloadClients = [];
|
|
17
|
-
this.debounceTimers = new Map();
|
|
18
|
-
this.debounceDelay = options.debounceDelay || 300;
|
|
19
|
-
this.enabled = options.enabled !== false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Start watching files for changes
|
|
24
|
-
*/
|
|
25
|
-
start() {
|
|
26
|
-
if (!this.enabled) return;
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
this.watchDirectory(this.staticDir);
|
|
30
|
-
console.log('[HotReload] Watching for changes:', this.staticDir);
|
|
31
|
-
} catch (e) {
|
|
32
|
-
console.error('[HotReload] Failed to start:', e.message);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Watch directory recursively
|
|
38
|
-
*/
|
|
39
|
-
watchDirectory(dir) {
|
|
40
|
-
try {
|
|
41
|
-
const files = fs.readdirSync(dir, { withFileTypes: true });
|
|
42
|
-
|
|
43
|
-
for (const file of files) {
|
|
44
|
-
const fullPath = path.join(dir, file.name);
|
|
45
|
-
|
|
46
|
-
if (file.isDirectory()) {
|
|
47
|
-
this.watchDirectory(fullPath);
|
|
48
|
-
} else {
|
|
49
|
-
this.watchFile(fullPath);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
console.error('[HotReload] Error watching directory:', e.message);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Watch individual file for changes
|
|
59
|
-
*/
|
|
60
|
-
watchFile(filePath) {
|
|
61
|
-
if (this.watchedFiles.has(filePath)) return;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
fs.watchFile(filePath, { interval: 100 }, (curr, prev) => {
|
|
65
|
-
if (curr.mtime > prev.mtime) {
|
|
66
|
-
this.onFileChanged(filePath);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
this.watchedFiles.set(filePath, true);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
console.error('[HotReload] Error watching file:', e.message);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Handle file change with debouncing
|
|
78
|
-
*/
|
|
79
|
-
onFileChanged(filePath) {
|
|
80
|
-
// Clear existing timer for this file
|
|
81
|
-
if (this.debounceTimers.has(filePath)) {
|
|
82
|
-
clearTimeout(this.debounceTimers.get(filePath));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Set new debounced timer
|
|
86
|
-
const timer = setTimeout(() => {
|
|
87
|
-
this.debounceTimers.delete(filePath);
|
|
88
|
-
const relPath = path.relative(this.staticDir, filePath);
|
|
89
|
-
|
|
90
|
-
console.log(`[HotReload] File changed: ${relPath}`);
|
|
91
|
-
this.broadcastReload();
|
|
92
|
-
}, this.debounceDelay);
|
|
93
|
-
|
|
94
|
-
this.debounceTimers.set(filePath, timer);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Register a WebSocket client for hot reload
|
|
99
|
-
*/
|
|
100
|
-
registerClient(ws) {
|
|
101
|
-
if (!this.enabled) return;
|
|
102
|
-
this.hotReloadClients.push(ws);
|
|
103
|
-
|
|
104
|
-
ws.on('close', () => {
|
|
105
|
-
const idx = this.hotReloadClients.indexOf(ws);
|
|
106
|
-
if (idx > -1) this.hotReloadClients.splice(idx, 1);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Broadcast reload signal to all connected clients
|
|
112
|
-
*/
|
|
113
|
-
broadcastReload() {
|
|
114
|
-
const message = JSON.stringify({ type: 'reload', timestamp: Date.now() });
|
|
115
|
-
|
|
116
|
-
for (const ws of this.hotReloadClients) {
|
|
117
|
-
if (ws.readyState === 1) { // WebSocket.OPEN
|
|
118
|
-
try {
|
|
119
|
-
ws.send(message);
|
|
120
|
-
} catch (e) {
|
|
121
|
-
// Client may have disconnected
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Cleanup watchers
|
|
129
|
-
*/
|
|
130
|
-
stop() {
|
|
131
|
-
for (const filePath of this.watchedFiles.keys()) {
|
|
132
|
-
try {
|
|
133
|
-
fs.unwatchFile(filePath);
|
|
134
|
-
} catch (e) {}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
for (const timer of this.debounceTimers.values()) {
|
|
138
|
-
clearTimeout(timer);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
this.watchedFiles.clear();
|
|
142
|
-
this.debounceTimers.clear();
|
|
143
|
-
this.hotReloadClients = [];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get HTML snippet to inject for hot reload
|
|
148
|
-
*/
|
|
149
|
-
getClientScript(baseUrl = '') {
|
|
150
|
-
if (!this.enabled) return '';
|
|
151
|
-
|
|
152
|
-
return `
|
|
153
|
-
<script>
|
|
154
|
-
(function() {
|
|
155
|
-
const baseUrl = '${baseUrl}';
|
|
156
|
-
const ws = new WebSocket((location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + location.host + baseUrl + '/hot-reload');
|
|
157
|
-
|
|
158
|
-
ws.onmessage = function(event) {
|
|
159
|
-
try {
|
|
160
|
-
const data = JSON.parse(event.data);
|
|
161
|
-
if (data.type === 'reload') {
|
|
162
|
-
console.log('[HotReload] Reloading page...');
|
|
163
|
-
location.reload();
|
|
164
|
-
}
|
|
165
|
-
} catch (e) {
|
|
166
|
-
console.error('[HotReload] Error parsing message:', e);
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
ws.onerror = function(e) {
|
|
171
|
-
console.log('[HotReload] WebSocket error:', e);
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
ws.onclose = function() {
|
|
175
|
-
console.log('[HotReload] Connection closed, will attempt to reconnect...');
|
|
176
|
-
setTimeout(function() {
|
|
177
|
-
location.reload();
|
|
178
|
-
}, 2000);
|
|
179
|
-
};
|
|
180
|
-
})();
|
|
181
|
-
</script>
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export default HotReloadManager;
|