@jungjaehoon/mama-os 0.9.0 → 0.9.2
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/CHANGELOG.md +30 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +37 -9
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/config/types.d.ts +17 -0
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js.map +1 -1
- package/dist/gateways/discord.d.ts +4 -0
- package/dist/gateways/discord.d.ts.map +1 -1
- package/dist/gateways/discord.js +48 -2
- package/dist/gateways/discord.js.map +1 -1
- package/dist/gateways/image-analyzer.d.ts.map +1 -1
- package/dist/gateways/image-analyzer.js +10 -1
- package/dist/gateways/image-analyzer.js.map +1 -1
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +3 -0
- package/dist/gateways/slack.js.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +10 -0
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +36 -2
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/agent-process-pool.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-pool.js +32 -4
- package/dist/multi-agent/agent-process-pool.js.map +1 -1
- package/dist/multi-agent/multi-agent-base.d.ts +19 -0
- package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-base.js +96 -0
- package/dist/multi-agent/multi-agent-base.js.map +1 -1
- package/dist/multi-agent/multi-agent-discord.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-discord.js +36 -0
- package/dist/multi-agent/multi-agent-discord.js.map +1 -1
- package/dist/multi-agent/multi-agent-slack.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-slack.js +38 -2
- package/dist/multi-agent/multi-agent-slack.js.map +1 -1
- package/dist/multi-agent/pr-review-poller.d.ts +16 -0
- package/dist/multi-agent/pr-review-poller.d.ts.map +1 -1
- package/dist/multi-agent/pr-review-poller.js +38 -0
- package/dist/multi-agent/pr-review-poller.js.map +1 -1
- package/dist/multi-agent/types.d.ts +18 -2
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/multi-agent/workflow-engine.d.ts +80 -0
- package/dist/multi-agent/workflow-engine.d.ts.map +1 -0
- package/dist/multi-agent/workflow-engine.js +395 -0
- package/dist/multi-agent/workflow-engine.js.map +1 -0
- package/dist/multi-agent/workflow-types.d.ts +111 -0
- package/dist/multi-agent/workflow-types.d.ts.map +1 -0
- package/dist/multi-agent/workflow-types.js +9 -0
- package/dist/multi-agent/workflow-types.js.map +1 -0
- package/dist/setup/setup-prompt.d.ts +1 -1
- package/dist/setup/setup-prompt.d.ts.map +1 -1
- package/dist/setup/setup-prompt.js +25 -0
- package/dist/setup/setup-prompt.js.map +1 -1
- package/package.json +1 -1
- package/public/viewer/js/modules/chat.js +30 -14
- package/public/viewer/js/utils/dom.js +15 -15
- package/public/viewer/src/modules/chat.ts +32 -20
- package/public/viewer/src/utils/dom.ts +16 -16
- package/public/viewer/viewer.css +45 -2
- package/public/viewer/viewer.html +19 -8
- package/templates/personas/sisyphus.md +8 -0
|
@@ -43,6 +43,7 @@ export class ChatModule {
|
|
|
43
43
|
history = [];
|
|
44
44
|
historyPrefix = 'mama_chat_history_';
|
|
45
45
|
maxHistoryMessages = 50;
|
|
46
|
+
maxDomMessages = 100; // Limit DOM elements for performance
|
|
46
47
|
historyExpiryMs = 24 * 60 * 60 * 1000;
|
|
47
48
|
checkpointCooldown = false;
|
|
48
49
|
COOLDOWN_MS = 60 * 1000;
|
|
@@ -1361,7 +1362,7 @@ export class ChatModule {
|
|
|
1361
1362
|
}
|
|
1362
1363
|
}
|
|
1363
1364
|
/**
|
|
1364
|
-
* Restore chat history
|
|
1365
|
+
* Restore chat history (optimized with DocumentFragment)
|
|
1365
1366
|
*/
|
|
1366
1367
|
restoreHistory(sessionId) {
|
|
1367
1368
|
const history = this.loadHistory(sessionId);
|
|
@@ -1374,7 +1375,11 @@ export class ChatModule {
|
|
|
1374
1375
|
return false;
|
|
1375
1376
|
}
|
|
1376
1377
|
this.removePlaceholder();
|
|
1377
|
-
|
|
1378
|
+
// Use DocumentFragment for batch DOM insertion
|
|
1379
|
+
const fragment = document.createDocumentFragment();
|
|
1380
|
+
// Limit to last N messages for DOM performance
|
|
1381
|
+
const messagesToRender = history.slice(-this.maxDomMessages);
|
|
1382
|
+
messagesToRender.forEach((msg) => {
|
|
1378
1383
|
const msgEl = document.createElement('div');
|
|
1379
1384
|
msgEl.className = `chat-message ${msg.role}`;
|
|
1380
1385
|
if (msg.role === 'user') {
|
|
@@ -1407,14 +1412,15 @@ export class ChatModule {
|
|
|
1407
1412
|
<div class="message-content">${escapeHtml(msg.content)}</div>
|
|
1408
1413
|
`;
|
|
1409
1414
|
}
|
|
1410
|
-
|
|
1415
|
+
fragment.appendChild(msgEl);
|
|
1411
1416
|
});
|
|
1417
|
+
container.appendChild(fragment);
|
|
1412
1418
|
scrollToBottom(container);
|
|
1413
1419
|
showToast('Previous conversation restored');
|
|
1414
1420
|
return true;
|
|
1415
1421
|
}
|
|
1416
1422
|
/**
|
|
1417
|
-
* Display history received from server
|
|
1423
|
+
* Display history received from server (optimized with DocumentFragment)
|
|
1418
1424
|
*/
|
|
1419
1425
|
displayHistory(messages) {
|
|
1420
1426
|
const container = getElementByIdOrNull('chat-messages');
|
|
@@ -1427,8 +1433,12 @@ export class ChatModule {
|
|
|
1427
1433
|
return;
|
|
1428
1434
|
}
|
|
1429
1435
|
container.innerHTML = '';
|
|
1430
|
-
this.history =
|
|
1431
|
-
|
|
1436
|
+
this.history = messages;
|
|
1437
|
+
// Use DocumentFragment for batch DOM insertion
|
|
1438
|
+
const fragment = document.createDocumentFragment();
|
|
1439
|
+
// Limit to last N messages for DOM performance
|
|
1440
|
+
const messagesToRender = messages.slice(-this.maxDomMessages);
|
|
1441
|
+
messagesToRender.forEach((msg) => {
|
|
1432
1442
|
const msgEl = document.createElement('div');
|
|
1433
1443
|
msgEl.className = `chat-message ${msg.role}`;
|
|
1434
1444
|
const timestamp = msg.timestamp ? new Date(msg.timestamp) : new Date();
|
|
@@ -1449,10 +1459,11 @@ export class ChatModule {
|
|
|
1449
1459
|
<div class="message-content">${escapeHtml(msg.content)}</div>
|
|
1450
1460
|
`;
|
|
1451
1461
|
}
|
|
1452
|
-
|
|
1462
|
+
fragment.appendChild(msgEl);
|
|
1453
1463
|
});
|
|
1464
|
+
container.appendChild(fragment);
|
|
1454
1465
|
scrollToBottom(container);
|
|
1455
|
-
logger.info('Displayed',
|
|
1466
|
+
logger.info('Displayed', messagesToRender.length, 'history messages');
|
|
1456
1467
|
}
|
|
1457
1468
|
/**
|
|
1458
1469
|
* Clear chat history
|
|
@@ -1737,10 +1748,15 @@ export class ChatModule {
|
|
|
1737
1748
|
if (!panel) {
|
|
1738
1749
|
return;
|
|
1739
1750
|
}
|
|
1740
|
-
const
|
|
1751
|
+
const isClosed = panel.classList.contains('chat-panel-closed');
|
|
1752
|
+
const shouldOpen = forceState !== undefined ? forceState : isClosed;
|
|
1741
1753
|
if (shouldOpen) {
|
|
1742
|
-
|
|
1743
|
-
|
|
1754
|
+
// Lazy session init on first open
|
|
1755
|
+
if (!this.ws) {
|
|
1756
|
+
this.initSession();
|
|
1757
|
+
}
|
|
1758
|
+
panel.classList.remove('chat-panel-closed');
|
|
1759
|
+
panel.classList.add('chat-panel-open', 'animate-slide-up');
|
|
1744
1760
|
this.restorePanelState(panel);
|
|
1745
1761
|
if (bubble) {
|
|
1746
1762
|
bubble.classList.add('scale-0');
|
|
@@ -1758,8 +1774,8 @@ export class ChatModule {
|
|
|
1758
1774
|
}
|
|
1759
1775
|
}
|
|
1760
1776
|
else {
|
|
1761
|
-
panel.classList.add('
|
|
1762
|
-
panel.classList.remove('animate-slide-up');
|
|
1777
|
+
panel.classList.add('chat-panel-closed');
|
|
1778
|
+
panel.classList.remove('chat-panel-open', 'animate-slide-up');
|
|
1763
1779
|
if (bubble) {
|
|
1764
1780
|
bubble.classList.remove('scale-0');
|
|
1765
1781
|
}
|
|
@@ -1814,7 +1830,7 @@ export class ChatModule {
|
|
|
1814
1830
|
*/
|
|
1815
1831
|
isFloatingOpen() {
|
|
1816
1832
|
const panel = getElementByIdOrNull('chat-panel');
|
|
1817
|
-
return Boolean(panel &&
|
|
1833
|
+
return Boolean(panel && panel.classList.contains('chat-panel-open'));
|
|
1818
1834
|
}
|
|
1819
1835
|
/**
|
|
1820
1836
|
* Show unread badge on bubble when panel is closed
|
|
@@ -97,15 +97,11 @@ export function showToast(message, duration = 3000) {
|
|
|
97
97
|
* @param {HTMLElement} container - Container to scroll
|
|
98
98
|
*/
|
|
99
99
|
export function scrollToBottom(container) {
|
|
100
|
-
// Use
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
setTimeout(doScroll, 50);
|
|
108
|
-
requestAnimationFrame(doScroll);
|
|
100
|
+
// Use requestAnimationFrame to batch layout read/write and avoid forced reflow
|
|
101
|
+
requestAnimationFrame(() => {
|
|
102
|
+
const scrollHeight = container.scrollHeight; // Single read
|
|
103
|
+
container.scrollTop = scrollHeight; // Single write
|
|
104
|
+
});
|
|
109
105
|
}
|
|
110
106
|
/**
|
|
111
107
|
* Auto-resize textarea to fit content
|
|
@@ -113,10 +109,14 @@ export function scrollToBottom(container) {
|
|
|
113
109
|
* @param {number} maxRows - Maximum number of rows (default: 5)
|
|
114
110
|
*/
|
|
115
111
|
export function autoResizeTextarea(textarea, maxRows = 5) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
// Use requestAnimationFrame to defer resize to the next frame, avoiding layout thrash from rapid input events
|
|
113
|
+
requestAnimationFrame(() => {
|
|
114
|
+
textarea.style.height = 'auto'; // Reset height before measuring
|
|
115
|
+
const computedLineHeight = Number.parseFloat(getComputedStyle(textarea).lineHeight); // Forces reflow (unavoidable)
|
|
116
|
+
const scrollHeight = textarea.scrollHeight;
|
|
117
|
+
const lineHeight = Number.isFinite(computedLineHeight) && computedLineHeight > 0 ? computedLineHeight : 20;
|
|
118
|
+
const maxHeight = lineHeight * maxRows;
|
|
119
|
+
const newHeight = Math.min(scrollHeight, maxHeight);
|
|
120
|
+
textarea.style.height = newHeight + 'px';
|
|
121
|
+
});
|
|
122
122
|
}
|
|
@@ -66,12 +66,6 @@ type CheckpointRecord = {
|
|
|
66
66
|
summary: string;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
// Reserved for future use - attachment message handling
|
|
70
|
-
type _ChatMessageWithAttachment = {
|
|
71
|
-
id?: string;
|
|
72
|
-
[key: string]: unknown;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
69
|
/**
|
|
76
70
|
* Chat Module Class
|
|
77
71
|
*/
|
|
@@ -104,6 +98,7 @@ export class ChatModule {
|
|
|
104
98
|
history: ChatHistoryMessage[] = [];
|
|
105
99
|
historyPrefix = 'mama_chat_history_';
|
|
106
100
|
maxHistoryMessages = 50;
|
|
101
|
+
maxDomMessages = 100; // Limit DOM elements for performance
|
|
107
102
|
historyExpiryMs = 24 * 60 * 60 * 1000;
|
|
108
103
|
checkpointCooldown = false;
|
|
109
104
|
COOLDOWN_MS = 60 * 1000;
|
|
@@ -1666,7 +1661,7 @@ export class ChatModule {
|
|
|
1666
1661
|
}
|
|
1667
1662
|
|
|
1668
1663
|
/**
|
|
1669
|
-
* Restore chat history
|
|
1664
|
+
* Restore chat history (optimized with DocumentFragment)
|
|
1670
1665
|
*/
|
|
1671
1666
|
restoreHistory(sessionId: string): boolean {
|
|
1672
1667
|
const history = this.loadHistory(sessionId);
|
|
@@ -1683,7 +1678,12 @@ export class ChatModule {
|
|
|
1683
1678
|
|
|
1684
1679
|
this.removePlaceholder();
|
|
1685
1680
|
|
|
1686
|
-
|
|
1681
|
+
// Use DocumentFragment for batch DOM insertion
|
|
1682
|
+
const fragment = document.createDocumentFragment();
|
|
1683
|
+
// Limit to last N messages for DOM performance
|
|
1684
|
+
const messagesToRender = history.slice(-this.maxDomMessages);
|
|
1685
|
+
|
|
1686
|
+
messagesToRender.forEach((msg) => {
|
|
1687
1687
|
const msgEl = document.createElement('div');
|
|
1688
1688
|
msgEl.className = `chat-message ${msg.role}`;
|
|
1689
1689
|
|
|
@@ -1715,9 +1715,10 @@ export class ChatModule {
|
|
|
1715
1715
|
`;
|
|
1716
1716
|
}
|
|
1717
1717
|
|
|
1718
|
-
|
|
1718
|
+
fragment.appendChild(msgEl);
|
|
1719
1719
|
});
|
|
1720
1720
|
|
|
1721
|
+
container.appendChild(fragment);
|
|
1721
1722
|
scrollToBottom(container);
|
|
1722
1723
|
showToast('Previous conversation restored');
|
|
1723
1724
|
|
|
@@ -1725,7 +1726,7 @@ export class ChatModule {
|
|
|
1725
1726
|
}
|
|
1726
1727
|
|
|
1727
1728
|
/**
|
|
1728
|
-
* Display history received from server
|
|
1729
|
+
* Display history received from server (optimized with DocumentFragment)
|
|
1729
1730
|
*/
|
|
1730
1731
|
displayHistory(messages: ChatHistoryMessage[]): void {
|
|
1731
1732
|
const container = getElementByIdOrNull<HTMLDivElement>('chat-messages');
|
|
@@ -1740,9 +1741,14 @@ export class ChatModule {
|
|
|
1740
1741
|
}
|
|
1741
1742
|
|
|
1742
1743
|
container.innerHTML = '';
|
|
1743
|
-
this.history =
|
|
1744
|
+
this.history = messages;
|
|
1745
|
+
|
|
1746
|
+
// Use DocumentFragment for batch DOM insertion
|
|
1747
|
+
const fragment = document.createDocumentFragment();
|
|
1748
|
+
// Limit to last N messages for DOM performance
|
|
1749
|
+
const messagesToRender = messages.slice(-this.maxDomMessages);
|
|
1744
1750
|
|
|
1745
|
-
|
|
1751
|
+
messagesToRender.forEach((msg) => {
|
|
1746
1752
|
const msgEl = document.createElement('div');
|
|
1747
1753
|
msgEl.className = `chat-message ${msg.role}`;
|
|
1748
1754
|
|
|
@@ -1764,11 +1770,12 @@ export class ChatModule {
|
|
|
1764
1770
|
`;
|
|
1765
1771
|
}
|
|
1766
1772
|
|
|
1767
|
-
|
|
1773
|
+
fragment.appendChild(msgEl);
|
|
1768
1774
|
});
|
|
1769
1775
|
|
|
1776
|
+
container.appendChild(fragment);
|
|
1770
1777
|
scrollToBottom(container);
|
|
1771
|
-
logger.info('Displayed',
|
|
1778
|
+
logger.info('Displayed', messagesToRender.length, 'history messages');
|
|
1772
1779
|
}
|
|
1773
1780
|
|
|
1774
1781
|
/**
|
|
@@ -2088,11 +2095,16 @@ export class ChatModule {
|
|
|
2088
2095
|
return;
|
|
2089
2096
|
}
|
|
2090
2097
|
|
|
2091
|
-
const
|
|
2098
|
+
const isClosed = panel.classList.contains('chat-panel-closed');
|
|
2099
|
+
const shouldOpen = forceState !== undefined ? forceState : isClosed;
|
|
2092
2100
|
|
|
2093
2101
|
if (shouldOpen) {
|
|
2094
|
-
|
|
2095
|
-
|
|
2102
|
+
// Lazy session init on first open
|
|
2103
|
+
if (!this.ws) {
|
|
2104
|
+
this.initSession();
|
|
2105
|
+
}
|
|
2106
|
+
panel.classList.remove('chat-panel-closed');
|
|
2107
|
+
panel.classList.add('chat-panel-open', 'animate-slide-up');
|
|
2096
2108
|
this.restorePanelState(panel);
|
|
2097
2109
|
if (bubble) {
|
|
2098
2110
|
bubble.classList.add('scale-0');
|
|
@@ -2109,8 +2121,8 @@ export class ChatModule {
|
|
|
2109
2121
|
messages.scrollTop = messages.scrollHeight;
|
|
2110
2122
|
}
|
|
2111
2123
|
} else {
|
|
2112
|
-
panel.classList.add('
|
|
2113
|
-
panel.classList.remove('animate-slide-up');
|
|
2124
|
+
panel.classList.add('chat-panel-closed');
|
|
2125
|
+
panel.classList.remove('chat-panel-open', 'animate-slide-up');
|
|
2114
2126
|
if (bubble) {
|
|
2115
2127
|
bubble.classList.remove('scale-0');
|
|
2116
2128
|
}
|
|
@@ -2166,7 +2178,7 @@ export class ChatModule {
|
|
|
2166
2178
|
*/
|
|
2167
2179
|
isFloatingOpen(): boolean {
|
|
2168
2180
|
const panel = getElementByIdOrNull<HTMLDivElement>('chat-panel');
|
|
2169
|
-
return Boolean(panel &&
|
|
2181
|
+
return Boolean(panel && panel.classList.contains('chat-panel-open'));
|
|
2170
2182
|
}
|
|
2171
2183
|
|
|
2172
2184
|
/**
|
|
@@ -111,15 +111,11 @@ export function showToast(message: string, duration = 3000): void {
|
|
|
111
111
|
* @param {HTMLElement} container - Container to scroll
|
|
112
112
|
*/
|
|
113
113
|
export function scrollToBottom(container: HTMLElement): void {
|
|
114
|
-
// Use
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
setTimeout(doScroll, 50);
|
|
122
|
-
requestAnimationFrame(doScroll);
|
|
114
|
+
// Use requestAnimationFrame to batch layout read/write and avoid forced reflow
|
|
115
|
+
requestAnimationFrame(() => {
|
|
116
|
+
const scrollHeight = container.scrollHeight; // Single read
|
|
117
|
+
container.scrollTop = scrollHeight; // Single write
|
|
118
|
+
});
|
|
123
119
|
}
|
|
124
120
|
|
|
125
121
|
/**
|
|
@@ -128,11 +124,15 @@ export function scrollToBottom(container: HTMLElement): void {
|
|
|
128
124
|
* @param {number} maxRows - Maximum number of rows (default: 5)
|
|
129
125
|
*/
|
|
130
126
|
export function autoResizeTextarea(textarea: HTMLTextAreaElement, maxRows = 5): void {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Number.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
127
|
+
// Use requestAnimationFrame to defer resize to the next frame, avoiding layout thrash from rapid input events
|
|
128
|
+
requestAnimationFrame(() => {
|
|
129
|
+
textarea.style.height = 'auto'; // Reset height before measuring
|
|
130
|
+
const computedLineHeight = Number.parseFloat(getComputedStyle(textarea).lineHeight); // Forces reflow (unavoidable)
|
|
131
|
+
const scrollHeight = textarea.scrollHeight;
|
|
132
|
+
const lineHeight =
|
|
133
|
+
Number.isFinite(computedLineHeight) && computedLineHeight > 0 ? computedLineHeight : 20;
|
|
134
|
+
const maxHeight = lineHeight * maxRows;
|
|
135
|
+
const newHeight = Math.min(scrollHeight, maxHeight);
|
|
136
|
+
textarea.style.height = newHeight + 'px';
|
|
137
|
+
});
|
|
138
138
|
}
|
package/public/viewer/viewer.css
CHANGED
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
Typography: Fredoka (display) + Nunito (body)
|
|
5
5
|
============================================================================ */
|
|
6
6
|
|
|
7
|
+
/* ============================================================================
|
|
8
|
+
CRITICAL CSS - Prevent CLS before Tailwind loads
|
|
9
|
+
============================================================================ */
|
|
10
|
+
|
|
11
|
+
header {
|
|
12
|
+
min-height: 56px;
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main {
|
|
18
|
+
min-height: calc(100vh - 56px);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[data-tab] {
|
|
22
|
+
min-width: 80px;
|
|
23
|
+
min-height: 36px;
|
|
24
|
+
}
|
|
25
|
+
|
|
7
26
|
/* ============================================================================
|
|
8
27
|
ANIMATIONS
|
|
9
28
|
============================================================================ */
|
|
@@ -68,6 +87,19 @@
|
|
|
68
87
|
min-height: 320px;
|
|
69
88
|
max-width: 96vw;
|
|
70
89
|
max-height: 85vh;
|
|
90
|
+
/* GPU compositing for smooth toggle */
|
|
91
|
+
transform: translateZ(0);
|
|
92
|
+
will-change: opacity;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#chat-panel.chat-panel-closed {
|
|
96
|
+
opacity: 0;
|
|
97
|
+
pointer-events: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#chat-panel.chat-panel-open {
|
|
101
|
+
opacity: 1;
|
|
102
|
+
pointer-events: auto;
|
|
71
103
|
}
|
|
72
104
|
.chat-panel-draggable {
|
|
73
105
|
position: fixed !important;
|
|
@@ -461,6 +493,7 @@
|
|
|
461
493
|
/* Tab visibility */
|
|
462
494
|
.tab-content {
|
|
463
495
|
display: none;
|
|
496
|
+
content-visibility: hidden;
|
|
464
497
|
}
|
|
465
498
|
.tab-content.active {
|
|
466
499
|
display: flex;
|
|
@@ -468,6 +501,12 @@
|
|
|
468
501
|
flex: 1;
|
|
469
502
|
height: 100%;
|
|
470
503
|
min-height: 0;
|
|
504
|
+
content-visibility: visible;
|
|
505
|
+
}
|
|
506
|
+
/* Memory tab needs visible content-visibility for checkpoint details elements */
|
|
507
|
+
#tab-memory,
|
|
508
|
+
#tab-memory.active {
|
|
509
|
+
content-visibility: visible;
|
|
471
510
|
}
|
|
472
511
|
|
|
473
512
|
/* Modal visibility */
|
|
@@ -634,8 +673,12 @@
|
|
|
634
673
|
background: #FFCE00;
|
|
635
674
|
}
|
|
636
675
|
|
|
637
|
-
/* Firefox scrollbar */
|
|
638
|
-
|
|
676
|
+
/* Firefox scrollbar - scoped to scrollable containers */
|
|
677
|
+
body,
|
|
678
|
+
.tab-content,
|
|
679
|
+
#chat-messages,
|
|
680
|
+
.overflow-y-auto,
|
|
681
|
+
.overflow-auto {
|
|
639
682
|
scrollbar-width: thin;
|
|
640
683
|
scrollbar-color: #D4C4E0 transparent;
|
|
641
684
|
}
|
|
@@ -18,17 +18,29 @@
|
|
|
18
18
|
<link rel="icon" type="image/svg+xml" href="/viewer/icons/mama-icon.svg" />
|
|
19
19
|
<link rel="icon" type="image/png" sizes="192x192" href="/viewer/icons/icon-192.png" />
|
|
20
20
|
|
|
21
|
+
<!-- Preconnect to CDN origins -->
|
|
21
22
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
22
23
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
24
|
+
<link rel="preconnect" href="https://cdn.tailwindcss.com" />
|
|
25
|
+
<link rel="preconnect" href="https://unpkg.com" />
|
|
26
|
+
<link rel="preconnect" href="https://cdn.jsdelivr.net" />
|
|
27
|
+
|
|
28
|
+
<!-- Preload critical resources -->
|
|
29
|
+
<link rel="preload" href="https://cdn.tailwindcss.com" as="script" />
|
|
30
|
+
<link rel="preload" href="/viewer/viewer.css" as="style" />
|
|
31
|
+
|
|
32
|
+
<!-- Fonts with reduced weights -->
|
|
23
33
|
<link
|
|
24
|
-
href="https://fonts.googleapis.com/css2?family=Fredoka:wght@
|
|
34
|
+
href="https://fonts.googleapis.com/css2?family=Fredoka:wght@500;700&family=Nunito:wght@400;600&display=swap"
|
|
25
35
|
rel="stylesheet"
|
|
26
36
|
/>
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
<script src="https://unpkg.com/
|
|
30
|
-
<script src="https://
|
|
31
|
-
<script src="https://
|
|
38
|
+
<!-- External libraries with defer -->
|
|
39
|
+
<script defer src="https://unpkg.com/vis-network@9/dist/vis-network.min.js"></script>
|
|
40
|
+
<script defer src="https://unpkg.com/lucide@0.460.0"></script>
|
|
41
|
+
<script defer src="https://cdn.jsdelivr.net/npm/marked@11/marked.min.js"></script>
|
|
42
|
+
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js"></script>
|
|
43
|
+
<!-- Tailwind must load synchronously -->
|
|
32
44
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
33
45
|
<script>
|
|
34
46
|
tailwind.config = {
|
|
@@ -1002,7 +1014,7 @@
|
|
|
1002
1014
|
<span id="chat-badge" class="hidden absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full border-2 border-white animate-pulse"></span>
|
|
1003
1015
|
</button>
|
|
1004
1016
|
|
|
1005
|
-
<div id="chat-panel" class="
|
|
1017
|
+
<div id="chat-panel" class="chat-panel-closed absolute bottom-[4.5rem] right-0 w-[400px] h-[560px] bg-white rounded-2xl shadow-float border border-mama-lavender-dark flex flex-col overflow-hidden">
|
|
1006
1018
|
<!-- Header -->
|
|
1007
1019
|
<div id="chat-header" class="h-12 bg-mama-yellow/20 flex items-center px-4 border-b border-mama-lavender-dark shrink-0">
|
|
1008
1020
|
<svg class="w-5 h-5 text-mama-black mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -2059,9 +2071,8 @@
|
|
|
2059
2071
|
document.documentElement.lang = userLang.split('-')[0];
|
|
2060
2072
|
|
|
2061
2073
|
initTheme();
|
|
2062
|
-
// Initialize floating chat (
|
|
2074
|
+
// Initialize floating chat panel bindings (session init is lazy, on first open)
|
|
2063
2075
|
chat.initFloating();
|
|
2064
|
-
chat.initSession();
|
|
2065
2076
|
// Default to dashboard tab
|
|
2066
2077
|
switchTab('dashboard');
|
|
2067
2078
|
});
|
|
@@ -94,6 +94,14 @@ CONTEXT:
|
|
|
94
94
|
- Prior analysis: {sub-agent result summary or file path}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
**Discord note (delegation trigger):**
|
|
98
|
+
|
|
99
|
+
- `DELEGATE::...` text is only parsed if the Discord gateway processes the message.
|
|
100
|
+
- If the guild/channel is configured with `requireMention: true`, normal messages without an @mention are ignored.
|
|
101
|
+
- Delegation commands are treated as explicit triggers: if any line starts with `DELEGATE::` / `DELEGATE_BG::`, it will still be processed (even without an @mention).
|
|
102
|
+
- Including the bot mention (example: `<@BOT_ID> DELEGATE::developer::...`) is still OK and makes intent obvious.
|
|
103
|
+
- For low-friction delegation, prefer a dedicated swarm channel with `requireMention: false`.
|
|
104
|
+
|
|
97
105
|
#### Asynchronous Delegation (background — do not wait for result)
|
|
98
106
|
|
|
99
107
|
Use when assigning **independent tasks** to another agent while continuing your own work:
|