@jungjaehoon/mama-os 0.10.1 → 0.10.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.
Files changed (49) hide show
  1. package/dist/agent/agent-loop.d.ts.map +1 -1
  2. package/dist/agent/agent-loop.js +40 -27
  3. package/dist/agent/agent-loop.js.map +1 -1
  4. package/dist/agent/claude-cli-wrapper.d.ts +1 -0
  5. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
  6. package/dist/agent/claude-cli-wrapper.js +0 -4
  7. package/dist/agent/claude-cli-wrapper.js.map +1 -1
  8. package/dist/agent/code-act/host-bridge.d.ts +1 -0
  9. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  10. package/dist/agent/code-act/host-bridge.js +3 -0
  11. package/dist/agent/code-act/host-bridge.js.map +1 -1
  12. package/dist/agent/codex-mcp-process.d.ts +8 -0
  13. package/dist/agent/codex-mcp-process.d.ts.map +1 -1
  14. package/dist/agent/codex-mcp-process.js +94 -1
  15. package/dist/agent/codex-mcp-process.js.map +1 -1
  16. package/dist/agent/gateway-tool-executor.d.ts +0 -16
  17. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  18. package/dist/agent/gateway-tool-executor.js +7 -115
  19. package/dist/agent/gateway-tool-executor.js.map +1 -1
  20. package/dist/agent/mama-tool-handlers.d.ts +11 -0
  21. package/dist/agent/mama-tool-handlers.d.ts.map +1 -0
  22. package/dist/agent/mama-tool-handlers.js +125 -0
  23. package/dist/agent/mama-tool-handlers.js.map +1 -0
  24. package/dist/agent/mcp-executor.d.ts +0 -16
  25. package/dist/agent/mcp-executor.d.ts.map +1 -1
  26. package/dist/agent/mcp-executor.js +5 -114
  27. package/dist/agent/mcp-executor.js.map +1 -1
  28. package/dist/agent/persistent-cli-process.d.ts +1 -0
  29. package/dist/agent/persistent-cli-process.d.ts.map +1 -1
  30. package/dist/agent/persistent-cli-process.js.map +1 -1
  31. package/dist/agent/types.d.ts +9 -1
  32. package/dist/agent/types.d.ts.map +1 -1
  33. package/dist/cli/commands/start.d.ts.map +1 -1
  34. package/dist/cli/commands/start.js +17 -5
  35. package/dist/cli/commands/start.js.map +1 -1
  36. package/dist/gateways/context-injector.d.ts.map +1 -1
  37. package/dist/gateways/context-injector.js +8 -27
  38. package/dist/gateways/context-injector.js.map +1 -1
  39. package/dist/gateways/message-router.d.ts +1 -0
  40. package/dist/gateways/message-router.d.ts.map +1 -1
  41. package/dist/gateways/message-router.js +38 -55
  42. package/dist/gateways/message-router.js.map +1 -1
  43. package/dist/mcp/code-act-server.js +8 -5
  44. package/dist/mcp/code-act-server.js.map +1 -1
  45. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  46. package/dist/multi-agent/agent-process-manager.js +2 -19
  47. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  48. package/package.json +2 -2
  49. package/templates/playgrounds/mama-log-viewer.html +78 -83
@@ -326,18 +326,17 @@ const WS_RECONNECT_DELAY = 3000;
326
326
  const WS_MAX_RETRIES = 5;
327
327
  const HISTOGRAM_BUCKETS = 30;
328
328
 
329
- const API_BASE = (location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.hostname === '::1')
330
- ? 'http://localhost:3847'
331
- : location.protocol + '//' + location.host;
332
-
333
- const WS_URL = (location.hostname === 'localhost' || location.hostname === '127.0.0.1' || location.hostname === '::1')
329
+ // Use same-origin by default so custom host/IP + non-default port keeps working.
330
+ const API_BASE = location.protocol === 'file:' ? 'http://localhost:3847' : '';
331
+ const WS_URL = location.protocol === 'file:'
334
332
  ? 'ws://localhost:3847/ws'
335
333
  : (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.host + '/ws';
334
+ const POST_MSG_ORIGIN = location.protocol === 'file:' ? '*' : location.origin;
336
335
 
337
336
  const S = {
338
337
  logs: [], autoScroll: true, selected: new Set(), lastClickIdx: -1,
339
- live: false, paused: false, pollTimer: null, lastMtime: 0, lastTotal: 0,
340
- initialized: false, prevCount: 0, rateHistory: [], totalReceived: 0,
338
+ live: false, paused: false, pollTimer: null, lastMtime: 0, lastTotal: 0, lastHadTotal: false,
339
+ initialized: false, prevCount: 0, rateHistory: [],
341
340
  levels: {error: true, warn: true, info: true, debug: true}, showGraph: true,
342
341
  sourceCounts: {}, channelCounts: {},
343
342
  activeSources: null, excludedSources: new Set(),
@@ -354,7 +353,7 @@ const $ = (id) => document.getElementById(id);
354
353
  const logArea = $('logArea');
355
354
  let emptyState = $('emptyState');
356
355
 
357
- function esc(s) { return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
356
+ function esc(s) { return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;'); }
358
357
  function sourceClass(src) { return src ? 'src-' + src.toLowerCase().replace(/[^a-z]/g, '') : ''; }
359
358
  function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
360
359
 
@@ -531,14 +530,11 @@ function addLines(rawLines, isInitial) {
531
530
  const base = S.logs.length;
532
531
  const frag = document.createDocumentFragment();
533
532
 
534
- let lineNum = base;
535
533
  for (let i = 0; i < rawLines.length; i++) {
536
534
  if (!rawLines[i].trim()) continue;
537
- const entry = parseLine(rawLines[i], lineNum);
538
- lineNum++;
535
+ const entry = parseLine(rawLines[i], base + i);
539
536
  if (!isInitial) entry.isNew = true;
540
537
  S.logs.push(entry);
541
- S.totalReceived++;
542
538
  const div = renderLine(entry, searchRe);
543
539
  let show = shouldShow(entry);
544
540
  if (show && searchRe) { searchRe.lastIndex = 0; show = searchRe.test(entry.raw); }
@@ -549,37 +545,24 @@ function addLines(rawLines, isInitial) {
549
545
  logArea.appendChild(frag);
550
546
 
551
547
  while (logArea.children.length > MAX_LINES) logArea.removeChild(logArea.firstChild);
552
-
553
- let trimmedCount = 0;
554
- while (S.logs.length > MAX_LINES) {
555
- S.logs.shift();
556
- trimmedCount++;
548
+ const excess = S.logs.length - MAX_LINES;
549
+ if (excess > 0) {
550
+ S.logs.splice(0, excess);
551
+ const shiftSet = (s) => {
552
+ const updated = new Set();
553
+ s.forEach((idx) => { const ni = idx - excess; if (ni >= 0) updated.add(ni); });
554
+ return updated;
555
+ };
556
+ S.pins = shiftSet(S.pins);
557
+ S.selected = shiftSet(S.selected);
558
+ if (S.lastClickIdx >= 0) {
559
+ S.lastClickIdx = Math.max(-1, S.lastClickIdx - excess);
560
+ }
557
561
  }
558
562
 
559
- if (trimmedCount > 0) {
560
- const newPins = new Set();
561
- S.pins.forEach((idx) => {
562
- if (idx >= trimmedCount) newPins.add(idx - trimmedCount);
563
- });
564
- S.pins = newPins;
565
-
566
- const newSelected = new Set();
567
- S.selected.forEach((idx) => {
568
- if (idx >= trimmedCount) newSelected.add(idx - trimmedCount);
569
- });
570
- S.selected = newSelected;
571
-
572
- S.sourceCounts = {};
573
- S.channelCounts = {};
574
- S.logs.forEach((entry) => {
575
- if (entry.source) S.sourceCounts[entry.source] = (S.sourceCounts[entry.source] || 0) + 1;
576
- if (entry.channel) S.channelCounts[entry.channel] = (S.channelCounts[entry.channel] || 0) + 1;
577
- });
578
-
579
- for (let j = 0; j < S.logs.length; j++) S.logs[j].n = j;
580
- const rows = logArea.querySelectorAll('.ll');
581
- for (let k = 0; k < rows.length; k++) rows[k].setAttribute('data-idx', k);
582
- }
563
+ for (let j = 0; j < S.logs.length; j++) S.logs[j].n = j;
564
+ const rows = logArea.querySelectorAll('.ll');
565
+ for (let k = 0; k < rows.length; k++) rows[k].setAttribute('data-idx', k);
583
566
 
584
567
  $('stTotal').textContent = S.logs.length;
585
568
  const vis = logArea.querySelectorAll('.ll:not(.hidden)').length;
@@ -591,8 +574,27 @@ function addLines(rawLines, isInitial) {
591
574
  if (S.statsDashOpen) updateStatsDashboard();
592
575
  }
593
576
 
577
+ function diffTailLines(snapshotLines) {
578
+ if (!Array.isArray(snapshotLines) || snapshotLines.length === 0) return [];
579
+ const existingLen = S.logs.length;
580
+ const maxOverlap = Math.min(existingLen, snapshotLines.length);
581
+ for (let overlap = maxOverlap; overlap > 0; overlap--) {
582
+ // Fast pre-check: first candidate line
583
+ if (S.logs[existingLen - overlap].raw !== snapshotLines[0]) continue;
584
+ let same = true;
585
+ for (let i = 1; i < overlap; i++) {
586
+ if (S.logs[existingLen - overlap + i].raw !== snapshotLines[i]) {
587
+ same = false;
588
+ break;
589
+ }
590
+ }
591
+ if (same) return snapshotLines.slice(overlap);
592
+ }
593
+ return snapshotLines;
594
+ }
595
+
594
596
  function updateRate() {
595
- const now = S.totalReceived;
597
+ const now = S.logs.length;
596
598
  const diff = now - S.prevCount;
597
599
  S.prevCount = now;
598
600
  S.rateHistory.push(diff);
@@ -619,32 +621,42 @@ function fetchLogs() {
619
621
  if (!r.ok) throw new Error('HTTP ' + r.status);
620
622
  return r.json();
621
623
  }).then((data) => {
624
+ const hasTotal = Number.isFinite(data.total);
625
+ const displayTotal = hasTotal ? data.total : (data.truncated ? '~' + data.lines.length : data.lines.length);
622
626
  const modeLabel = S.wsMode ? 'WS+Poll' : 'Polling';
623
- setStatus('connected', modeLabel + ' (' + (parseInt($('intervalSel').value) / 1000) + 's) \u2022 ' + data.total + ' total');
624
- if (data.fileSize) $('fileInfo').textContent = (data.fileSize / 1024 / 1024).toFixed(1) + 'MB';
627
+ setStatus('connected', modeLabel + ' (' + (parseInt($('intervalSel').value) / 1000) + 's) \u2022 ' + displayTotal + ' total');
628
+ const bytes = data.totalBytes || data.fileSize;
629
+ if (bytes) $('fileInfo').textContent = (bytes / 1024 / 1024).toFixed(1) + 'MB';
625
630
 
626
631
  if (!S.initialized) {
627
632
  addLines(data.lines, true);
628
633
  S.lastMtime = data.mtime;
629
- S.lastTotal = data.total;
634
+ S.lastTotal = hasTotal ? data.total : null;
635
+ S.lastHadTotal = hasTotal;
630
636
  S.initialized = true;
631
637
  } else if (data.mtime > S.lastMtime) {
632
- const newCount = data.total - S.lastTotal;
633
- if (S.ws && S.ws.readyState === WebSocket.OPEN) {
634
- S.lastMtime = data.mtime;
635
- S.lastTotal = data.total;
636
- } else if (newCount > 0 && newCount <= MAX_INCREMENTAL_LINES) {
637
- addLines(data.lines.slice(-newCount), false);
638
- S.lastMtime = data.mtime;
639
- S.lastTotal = data.total;
640
- } else if (newCount > MAX_INCREMENTAL_LINES) {
641
- S.logs = []; S.sourceCounts = {}; S.channelCounts = {};
642
- S.pins = new Set(); S.selected = null;
643
- logArea.innerHTML = '';
644
- addLines(data.lines, true);
645
- S.lastMtime = data.mtime;
646
- S.lastTotal = data.total;
638
+ if (hasTotal && S.lastHadTotal && Number.isFinite(S.lastTotal)) {
639
+ const newCount = data.total - S.lastTotal;
640
+ if (newCount > 0 && newCount <= MAX_INCREMENTAL_LINES) {
641
+ addLines(data.lines.slice(-newCount), false);
642
+ } else if (newCount > MAX_INCREMENTAL_LINES) {
643
+ S.logs = []; S.sourceCounts = {}; S.channelCounts = {};
644
+ logArea.innerHTML = '';
645
+ addLines(data.lines, true);
646
+ }
647
+ } else {
648
+ const incremental = diffTailLines(data.lines);
649
+ if (incremental.length > 0 && incremental.length <= MAX_INCREMENTAL_LINES) {
650
+ addLines(incremental, false);
651
+ } else if (incremental.length > MAX_INCREMENTAL_LINES) {
652
+ S.logs = []; S.sourceCounts = {}; S.channelCounts = {};
653
+ logArea.innerHTML = '';
654
+ addLines(data.lines, true);
655
+ }
647
656
  }
657
+ S.lastMtime = data.mtime;
658
+ S.lastTotal = hasTotal ? data.total : null;
659
+ S.lastHadTotal = hasTotal;
648
660
  }
649
661
  updateRate();
650
662
  }).catch((e) => {
@@ -673,12 +685,6 @@ function stopPolling() {
673
685
  function connectWS() {
674
686
  if (S.ws && (S.ws.readyState === WebSocket.OPEN || S.ws.readyState === WebSocket.CONNECTING)) return;
675
687
 
676
- // Stop polling to prevent duplicate logs
677
- if (S.pollTimer) {
678
- clearInterval(S.pollTimer);
679
- S.pollTimer = null;
680
- }
681
-
682
688
  S.wsMode = true;
683
689
  $('wsBtn').classList.add('ws-mode');
684
690
  setStatus('connecting', 'WS connecting...');
@@ -702,22 +708,13 @@ function connectWS() {
702
708
  if (data.type === 'log' && data.line) {
703
709
  if (emptyState && emptyState.parentNode) emptyState.remove();
704
710
  addLines([data.line], false);
705
- // Update mtime/total to prevent polling duplicates
706
- if (data.mtime) S.lastMtime = data.mtime;
707
- if (data.total) S.lastTotal = data.total;
708
- updateRate();
709
711
  } else if (data.type === 'logs' && data.lines) {
710
712
  addLines(data.lines, !S.initialized);
711
713
  S.initialized = true;
712
- // Update mtime/total to prevent polling duplicates
713
- if (data.mtime) S.lastMtime = data.mtime;
714
- if (data.total) S.lastTotal = data.total;
715
- updateRate();
716
714
  }
717
715
  } catch (e) {
718
716
  if (typeof evt.data === 'string' && evt.data.trim()) {
719
717
  addLines([evt.data], false);
720
- updateRate();
721
718
  }
722
719
  }
723
720
  };
@@ -752,7 +749,7 @@ function disconnectWS() {
752
749
  function fallbackToPolling(reason) {
753
750
  disconnectWS();
754
751
  setStatus('disconnected', 'WS failed: ' + reason + ' \u2014 switching to polling');
755
- if (S.live) startPolling();
752
+ if (!S.live) startPolling();
756
753
  }
757
754
 
758
755
  /* ===== Export ===== */
@@ -1168,7 +1165,7 @@ $('selCopy').addEventListener('click', () => {
1168
1165
  $('selSend').addEventListener('click', () => {
1169
1166
  const text = getSelectedText();
1170
1167
  const msg = '[\uc120\ud0dd\ub41c \ub85c\uadf8 ' + S.selected.size + '\uc904]:\n```\n' + text + '\n```';
1171
- window.parent.postMessage({ type: 'playground:sendToChat', message: msg }, location.origin);
1168
+ window.parent.postMessage({ type: 'playground:sendToChat', message: msg }, POST_MSG_ORIGIN);
1172
1169
  S.selected.clear();
1173
1170
  logArea.querySelectorAll('.ll.selected').forEach((el) => { el.classList.remove('selected'); });
1174
1171
  updateSelectionBar();
@@ -1195,14 +1192,13 @@ $('autoBtn').addEventListener('click', function() {
1195
1192
  if (S.autoScroll) logArea.scrollTop = logArea.scrollHeight;
1196
1193
  });
1197
1194
  $('clearBtn').addEventListener('click', () => {
1198
- S.logs = []; S.selected.clear(); S.pins.clear(); S.lastMtime = 0; S.lastTotal = 0; S.initialized = false;
1199
- S.prevCount = 0; S.rateHistory = []; S.totalReceived = 0; S.sourceCounts = {}; S.channelCounts = {};
1195
+ S.logs = []; S.selected.clear(); S.pins.clear(); savePins(); S.lastClickIdx = -1;
1196
+ S.lastMtime = 0; S.lastTotal = 0; S.lastHadTotal = false; S.initialized = false;
1197
+ S.prevCount = 0; S.rateHistory = []; S.sourceCounts = {}; S.channelCounts = {};
1200
1198
  logArea.innerHTML = '<div class="empty" id="emptyState"><div class="ico">&#128203;</div><p>Cleared</p></div>';
1201
1199
  emptyState = $('emptyState');
1202
1200
  $('stTotal').textContent = '0'; $('stShown').textContent = '0';
1203
1201
  $('rateBadge').textContent = '0 l/s'; $('modStats').innerHTML = '';
1204
- savePins();
1205
- updatePinUI();
1206
1202
  updateSelectionBar();
1207
1203
  updateMinimap();
1208
1204
  if (S.statsDashOpen) updateStatsDashboard();
@@ -1313,7 +1309,7 @@ $('promptSend').addEventListener('click', () => {
1313
1309
  S.selected.forEach((idx) => { if (S.logs[idx]) selLogs.push(S.logs[idx].raw); });
1314
1310
  msg += '\n\n[\uc120\ud0dd\ub41c \ub85c\uadf8 ' + selLogs.length + '\uc904]:\n```\n' + selLogs.join('\n') + '\n```';
1315
1311
  }
1316
- window.parent.postMessage({ type: 'playground:sendToChat', message: msg }, location.origin);
1312
+ window.parent.postMessage({ type: 'playground:sendToChat', message: msg }, POST_MSG_ORIGIN);
1317
1313
  $('promptInput').value = '';
1318
1314
  });
1319
1315
  $('promptCopy').addEventListener('click', () => {
@@ -1329,7 +1325,6 @@ $('promptCopy').addEventListener('click', () => {
1329
1325
  });
1330
1326
 
1331
1327
  window.addEventListener('message', (e) => {
1332
- if (e.origin !== location.origin && e.source !== window.parent) return;
1333
1328
  if (e.data && e.data.type === 'mama:logs') {
1334
1329
  const lines = e.data.content.split('\n').filter((l) => l.trim());
1335
1330
  addLines(lines, true);