watercooler 0.0.4 → 0.0.6
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/package.json +1 -1
- package/public/app.js +853 -228
- package/public/index.html +29 -9
- package/server.ts +64 -2
package/public/index.html
CHANGED
|
@@ -199,6 +199,23 @@
|
|
|
199
199
|
opacity: 1;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
.mark-all-read-btn {
|
|
203
|
+
background: rgba(255, 255, 255, 0.1);
|
|
204
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
205
|
+
color: rgba(255, 255, 255, 0.8);
|
|
206
|
+
font-size: 0.75rem;
|
|
207
|
+
padding: 4px 10px;
|
|
208
|
+
border-radius: 4px;
|
|
209
|
+
cursor: pointer;
|
|
210
|
+
transition: all 0.2s;
|
|
211
|
+
white-space: nowrap;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.mark-all-read-btn:hover {
|
|
215
|
+
background: rgba(255, 255, 255, 0.2);
|
|
216
|
+
color: white;
|
|
217
|
+
}
|
|
218
|
+
|
|
202
219
|
.messages-container {
|
|
203
220
|
flex: 1;
|
|
204
221
|
overflow-y: auto;
|
|
@@ -303,7 +320,7 @@
|
|
|
303
320
|
}
|
|
304
321
|
|
|
305
322
|
.message-text li {
|
|
306
|
-
margin:
|
|
323
|
+
margin: 2px 0;
|
|
307
324
|
}
|
|
308
325
|
|
|
309
326
|
/* Toggle Messages Button */
|
|
@@ -521,7 +538,7 @@
|
|
|
521
538
|
transform: translateY(-50%) translateY(0);
|
|
522
539
|
}
|
|
523
540
|
|
|
524
|
-
/*
|
|
541
|
+
/* Desk dialog - full screen on mobile */
|
|
525
542
|
.house-dialog-content {
|
|
526
543
|
width: 100%;
|
|
527
544
|
max-width: 100%;
|
|
@@ -615,7 +632,7 @@
|
|
|
615
632
|
}
|
|
616
633
|
}
|
|
617
634
|
|
|
618
|
-
/*
|
|
635
|
+
/* Desk Dialog */
|
|
619
636
|
.house-dialog {
|
|
620
637
|
display: none;
|
|
621
638
|
position: fixed;
|
|
@@ -633,7 +650,7 @@
|
|
|
633
650
|
display: flex;
|
|
634
651
|
}
|
|
635
652
|
|
|
636
|
-
/* Desktop override for
|
|
653
|
+
/* Desktop override for desk dialog */
|
|
637
654
|
@media (min-width: 769px) {
|
|
638
655
|
.house-dialog {
|
|
639
656
|
align-items: center;
|
|
@@ -648,7 +665,7 @@
|
|
|
648
665
|
}
|
|
649
666
|
}
|
|
650
667
|
|
|
651
|
-
/* Desktop
|
|
668
|
+
/* Desktop desk dialog styles */
|
|
652
669
|
@media (min-width: 769px) {
|
|
653
670
|
.house-dialog-content {
|
|
654
671
|
background: rgba(255, 255, 255, 0.15);
|
|
@@ -664,7 +681,7 @@
|
|
|
664
681
|
}
|
|
665
682
|
}
|
|
666
683
|
|
|
667
|
-
/* Base
|
|
684
|
+
/* Base desk dialog styles (shared) */
|
|
668
685
|
.house-dialog-content {
|
|
669
686
|
background: rgba(255, 255, 255, 0.15);
|
|
670
687
|
backdrop-filter: blur(20px);
|
|
@@ -790,7 +807,10 @@
|
|
|
790
807
|
<div class="messages-panel" id="messages-panel">
|
|
791
808
|
<div class="messages-header">
|
|
792
809
|
<h2>📨 Message History</h2>
|
|
793
|
-
<
|
|
810
|
+
<div style="display: flex; gap: 8px; align-items: center;">
|
|
811
|
+
<button class="mark-all-read-btn" onclick="markAllAsRead()">Mark all as read</button>
|
|
812
|
+
<button class="close-btn" onclick="toggleMessagesPanel()">×</button>
|
|
813
|
+
</div>
|
|
794
814
|
</div>
|
|
795
815
|
<div class="messages-container" id="messages-container">
|
|
796
816
|
<div class="empty-state">
|
|
@@ -800,12 +820,12 @@
|
|
|
800
820
|
</div>
|
|
801
821
|
</div>
|
|
802
822
|
|
|
803
|
-
<!--
|
|
823
|
+
<!-- Desk Dialog - Shows messages with specific agent -->
|
|
804
824
|
<div class="house-dialog" id="house-dialog">
|
|
805
825
|
<div class="house-dialog-content">
|
|
806
826
|
<div class="house-dialog-header">
|
|
807
827
|
<h2 id="house-dialog-title">Messages</h2>
|
|
808
|
-
<button class="close-btn" onclick="
|
|
828
|
+
<button class="close-btn" onclick="closeDeskDialog()">×</button>
|
|
809
829
|
</div>
|
|
810
830
|
<div class="house-dialog-tabs">
|
|
811
831
|
<button class="tab-btn active" id="tab-received" onclick="switchTab('received')">
|
package/server.ts
CHANGED
|
@@ -13,6 +13,7 @@ const args = process.argv.slice(2);
|
|
|
13
13
|
let user: string | null = null;
|
|
14
14
|
let mailboxPath: string | null = null;
|
|
15
15
|
let coworkerPath: string | null = null;
|
|
16
|
+
let avatarPath: string | null = null;
|
|
16
17
|
let port: number = parseInt(process.env.PORT || '3000', 10);
|
|
17
18
|
let host: string = process.env.HOST || '0.0.0.0';
|
|
18
19
|
|
|
@@ -23,6 +24,8 @@ for (let i = 0; i < args.length; i++) {
|
|
|
23
24
|
mailboxPath = args[++i];
|
|
24
25
|
} else if (args[i] === '--coworkers' || args[i] === '-c') {
|
|
25
26
|
coworkerPath = args[++i];
|
|
27
|
+
} else if (args[i] === '--avatars' || args[i] === '-a') {
|
|
28
|
+
avatarPath = args[++i];
|
|
26
29
|
} else if (args[i] === '--port' || args[i] === '-p') {
|
|
27
30
|
const p = parseInt(args[++i], 10);
|
|
28
31
|
if (!isNaN(p)) port = p;
|
|
@@ -32,7 +35,7 @@ for (let i = 0; i < args.length; i++) {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
if (!user || !mailboxPath) {
|
|
35
|
-
console.error('Usage: watercooler --user <name> --mailbox <path> [--coworkers <path>] [--port <number>] [--host <address>]');
|
|
38
|
+
console.error('Usage: watercooler --user <name> --mailbox <path> [--coworkers <path>] [--avatars <path>] [--port <number>] [--host <address>]');
|
|
36
39
|
process.exit(1);
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -41,11 +44,15 @@ console.log(` Mailbox: ${mailboxPath}`);
|
|
|
41
44
|
if (coworkerPath) {
|
|
42
45
|
console.log(` Coworker DB: ${coworkerPath}`);
|
|
43
46
|
}
|
|
47
|
+
if (avatarPath) {
|
|
48
|
+
console.log(` Avatar DB: ${avatarPath}`);
|
|
49
|
+
}
|
|
44
50
|
console.log(` URL: http://${host}:${port}`);
|
|
45
51
|
|
|
46
52
|
// Databases
|
|
47
53
|
let db: Database.Database | null = null;
|
|
48
54
|
let coworkerDb: Database.Database | null = null;
|
|
55
|
+
let avatarDb: Database.Database | null = null;
|
|
49
56
|
|
|
50
57
|
try {
|
|
51
58
|
db = new Database(mailboxPath);
|
|
@@ -64,6 +71,15 @@ if (coworkerPath) {
|
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
73
|
|
|
74
|
+
if (avatarPath) {
|
|
75
|
+
try {
|
|
76
|
+
avatarDb = new Database(avatarPath);
|
|
77
|
+
console.log(' Avatar DB: connected');
|
|
78
|
+
} catch (err: any) {
|
|
79
|
+
console.warn(' Avatar DB error:', err.message);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
67
83
|
// Helper: Check if table exists
|
|
68
84
|
function tableExists(database: Database.Database | null, tableName: string): boolean {
|
|
69
85
|
if (!database) return false;
|
|
@@ -231,9 +247,55 @@ app.post('/api/messages/:id/read', (req, res) => {
|
|
|
231
247
|
}
|
|
232
248
|
});
|
|
233
249
|
|
|
250
|
+
// API: Get avatar states (latest tool usage per coworker)
|
|
251
|
+
app.get('/api/avatars', (req, res) => {
|
|
252
|
+
try {
|
|
253
|
+
if (!avatarDb) {
|
|
254
|
+
res.json({});
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Check if latest_tool_usage table exists
|
|
259
|
+
const tableCheck = avatarDb.prepare(`
|
|
260
|
+
SELECT name FROM sqlite_master
|
|
261
|
+
WHERE type='table' AND name='latest_tool_usage'
|
|
262
|
+
`).get();
|
|
263
|
+
|
|
264
|
+
if (!tableCheck) {
|
|
265
|
+
res.json({});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Get latest tool usage per name
|
|
270
|
+
const stmt = avatarDb.prepare(`
|
|
271
|
+
SELECT name, tool_name, timestamp
|
|
272
|
+
FROM latest_tool_usage
|
|
273
|
+
ORDER BY timestamp DESC
|
|
274
|
+
`);
|
|
275
|
+
|
|
276
|
+
const rows = stmt.all() as Array<{name: string; tool_name: string; timestamp: number}>;
|
|
277
|
+
|
|
278
|
+
// Build map of name -> latest tool (first occurrence is latest due to ORDER BY)
|
|
279
|
+
const avatarStates: Record<string, {tool_name: string; timestamp: number}> = {};
|
|
280
|
+
for (const row of rows) {
|
|
281
|
+
if (!avatarStates[row.name]) {
|
|
282
|
+
avatarStates[row.name] = {
|
|
283
|
+
tool_name: row.tool_name,
|
|
284
|
+
timestamp: row.timestamp
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
res.json(avatarStates);
|
|
290
|
+
} catch (err: any) {
|
|
291
|
+
console.error('Error in /api/avatars:', err.message);
|
|
292
|
+
res.status(500).json({ error: err.message });
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
234
296
|
// Config endpoint
|
|
235
297
|
app.get('/api/config', (req, res) => {
|
|
236
|
-
res.json({ user, mailbox: mailboxPath, coworker: coworkerPath });
|
|
298
|
+
res.json({ user, mailbox: mailboxPath, coworker: coworkerPath, avatar: avatarPath });
|
|
237
299
|
});
|
|
238
300
|
|
|
239
301
|
app.listen(port, host, () => {
|