agent-office 0.0.13 → 0.0.14
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.
|
@@ -59,11 +59,12 @@ function renderMessage(msg, humanName, spacingClass) {
|
|
|
59
59
|
const isMine = msg.from_name === humanName;
|
|
60
60
|
const bubbleClass = isMine ? "bubble bubble-mine" : "bubble bubble-theirs";
|
|
61
61
|
const wrapClass = `msg-wrap ${isMine ? "msg-wrap-mine" : "msg-wrap-theirs"} ${spacingClass}`;
|
|
62
|
-
|
|
62
|
+
// Base64 encode to preserve newlines and special chars reliably
|
|
63
|
+
const bodyEncoded = Buffer.from(msg.body).toString('base64');
|
|
63
64
|
const unreadDot = !isMine && !msg.read ? `<span class="unread-dot"></span>` : "";
|
|
64
65
|
return `<div class="${wrapClass}" data-id="${msg.id}">
|
|
65
66
|
<div class="${bubbleClass}">
|
|
66
|
-
<div class="bubble-body"
|
|
67
|
+
<div class="bubble-body markdown-body" data-markdown-b64="${bodyEncoded}"></div>
|
|
67
68
|
<div class="bubble-time">${unreadDot}${formatTime(msg.created_at)}</div>
|
|
68
69
|
</div>
|
|
69
70
|
</div>`;
|
|
@@ -91,6 +92,9 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
91
92
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
92
93
|
<title>${escapeHtml(coworker)} — agent-office</title>
|
|
93
94
|
<script src="https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js"></script>
|
|
95
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js"></script>
|
|
96
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.5.1/github-markdown-light.min.css" media="(prefers-color-scheme: light)">
|
|
97
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.5.1/github-markdown-dark.min.css" media="(prefers-color-scheme: dark)">
|
|
94
98
|
<style>
|
|
95
99
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
96
100
|
|
|
@@ -264,6 +268,66 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
264
268
|
}
|
|
265
269
|
|
|
266
270
|
.bubble-body { font-size: 14.5px; }
|
|
271
|
+
.bubble-body.markdown-body {
|
|
272
|
+
background: transparent;
|
|
273
|
+
color: inherit;
|
|
274
|
+
font-size: 14px;
|
|
275
|
+
line-height: 1.5;
|
|
276
|
+
}
|
|
277
|
+
.bubble-body.markdown-body p { margin: 0 0 8px 0; }
|
|
278
|
+
.bubble-body.markdown-body p:last-child { margin-bottom: 0; }
|
|
279
|
+
.bubble-body.markdown-body pre {
|
|
280
|
+
background: rgba(0,0,0,0.3);
|
|
281
|
+
border-radius: 6px;
|
|
282
|
+
padding: 8px 12px;
|
|
283
|
+
overflow-x: auto;
|
|
284
|
+
margin: 8px 0;
|
|
285
|
+
}
|
|
286
|
+
.bubble-body.markdown-body code {
|
|
287
|
+
background: rgba(0,0,0,0.2);
|
|
288
|
+
padding: 2px 5px;
|
|
289
|
+
border-radius: 3px;
|
|
290
|
+
font-size: 13px;
|
|
291
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
|
292
|
+
}
|
|
293
|
+
.bubble-body.markdown-body pre code {
|
|
294
|
+
background: transparent;
|
|
295
|
+
padding: 0;
|
|
296
|
+
}
|
|
297
|
+
.bubble-body.markdown-body ul, .bubble-body.markdown-body ol {
|
|
298
|
+
margin: 8px 0;
|
|
299
|
+
padding-left: 20px;
|
|
300
|
+
}
|
|
301
|
+
.bubble-body.markdown-body li { margin: 4px 0; }
|
|
302
|
+
.bubble-body.markdown-body blockquote {
|
|
303
|
+
border-left: 3px solid var(--accent);
|
|
304
|
+
margin: 8px 0;
|
|
305
|
+
padding-left: 12px;
|
|
306
|
+
color: var(--text-dim);
|
|
307
|
+
}
|
|
308
|
+
.bubble-body.markdown-body h1, .bubble-body.markdown-body h2,
|
|
309
|
+
.bubble-body.markdown-body h3, .bubble-body.markdown-body h4 {
|
|
310
|
+
margin: 12px 0 8px 0;
|
|
311
|
+
font-size: 15px;
|
|
312
|
+
font-weight: 600;
|
|
313
|
+
}
|
|
314
|
+
.bubble-body.markdown-body table {
|
|
315
|
+
border-collapse: collapse;
|
|
316
|
+
margin: 8px 0;
|
|
317
|
+
font-size: 13px;
|
|
318
|
+
}
|
|
319
|
+
.bubble-body.markdown-body th, .bubble-body.markdown-body td {
|
|
320
|
+
border: 1px solid var(--border);
|
|
321
|
+
padding: 6px 10px;
|
|
322
|
+
}
|
|
323
|
+
.bubble-body.markdown-body th {
|
|
324
|
+
background: var(--surface2);
|
|
325
|
+
}
|
|
326
|
+
.bubble-body.markdown-body strong,
|
|
327
|
+
.bubble-body.markdown-body b {
|
|
328
|
+
color: #ffffff;
|
|
329
|
+
font-weight: 600;
|
|
330
|
+
}
|
|
267
331
|
.bubble-time {
|
|
268
332
|
font-size: 10px;
|
|
269
333
|
color: var(--text-dim);
|
|
@@ -498,6 +562,28 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
498
562
|
clearTimeout(el._hideTimer)
|
|
499
563
|
el._hideTimer = setTimeout(() => el.classList.remove('visible'), 3000)
|
|
500
564
|
}
|
|
565
|
+
|
|
566
|
+
// Render markdown in chat bubbles
|
|
567
|
+
function renderMarkdown() {
|
|
568
|
+
if (typeof marked === 'undefined') return
|
|
569
|
+
document.querySelectorAll('.markdown-body[data-markdown-b64]').forEach(el => {
|
|
570
|
+
const b64 = el.getAttribute('data-markdown-b64')
|
|
571
|
+
if (b64 && !el.hasAttribute('data-rendered')) {
|
|
572
|
+
// Decode base64 to get original text with preserved newlines
|
|
573
|
+
const text = atob(b64)
|
|
574
|
+
el.innerHTML = marked.parse(text)
|
|
575
|
+
el.setAttribute('data-rendered', 'true')
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Initial render
|
|
581
|
+
renderMarkdown()
|
|
582
|
+
|
|
583
|
+
// Re-render after HTMX swaps new content
|
|
584
|
+
document.addEventListener('htmx:afterSwap', () => {
|
|
585
|
+
renderMarkdown()
|
|
586
|
+
})
|
|
501
587
|
</script>
|
|
502
588
|
</body>
|
|
503
589
|
</html>`;
|
|
@@ -609,10 +695,19 @@ export async function communicatorWeb(coworker, options) {
|
|
|
609
695
|
app.get("/ping", (_req, res) => {
|
|
610
696
|
res.status(204).end();
|
|
611
697
|
});
|
|
612
|
-
app.listen(port, host, () => {
|
|
698
|
+
const server = app.listen(port, host, () => {
|
|
613
699
|
console.log(`Communicator running at http://${host}:${port}`);
|
|
614
700
|
console.log(`Press Ctrl+C to stop.`);
|
|
615
701
|
});
|
|
702
|
+
server.on('error', (err) => {
|
|
703
|
+
if (err.code === 'EADDRINUSE') {
|
|
704
|
+
console.error(`Error: Port ${port} is already in use. Is another instance running?`);
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
console.error(`Error: ${err.message}`);
|
|
708
|
+
}
|
|
709
|
+
process.exit(1);
|
|
710
|
+
});
|
|
616
711
|
// Keep process alive
|
|
617
712
|
await new Promise(() => { });
|
|
618
713
|
}
|