repoburg 1.3.270 → 1.3.272

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 (28) hide show
  1. package/agent-pane/backend/dist/index.js +54904 -277
  2. package/agent-pane/backend/dist/server.js +54904 -277
  3. package/agent-pane/examples/pr-review/manifest.json +1 -1
  4. package/agent-pane/frontend/dist/assets/index-BuZ-_HXG.js +606 -0
  5. package/agent-pane/frontend/dist/assets/index-DlwZnsU3.css +1 -0
  6. package/agent-pane/frontend/dist/index.html +2 -2
  7. package/daemon/dist/tabtape/config.js +1 -1
  8. package/daemon/dist/tabtape/mcp/definitions.js +2 -2
  9. package/daemon/dist/tabtape/mcp/server.js +2 -2
  10. package/daemon/dist/tabtape/mcp/server.spec.js +18 -0
  11. package/daemon/dist/tabtape/mcp/tools.js +10 -0
  12. package/daemon/dist/tabtape/query/perf.js +53 -1
  13. package/daemon/dist/tabtape/query/query.spec.js +13 -1
  14. package/daemon/dist/tabtape/query/types.js +4 -0
  15. package/daemon/dist/tabtape/testing/querytest.js +8 -1
  16. package/package.json +5 -1
  17. package/tabtape/extension/dist/build-info.json +4 -4
  18. package/tabtape/extension/dist/manifest.json +2 -2
  19. package/tabtape/extension/dist/recorder.js +21 -21
  20. package/tabtape/extension/dist/recorder.js.map +1 -1
  21. package/tabtape/ui/dist/app/assets/{index-iWNSSrAE.js → index-B7yWGVQ_.js} +10 -9
  22. package/tabtape/ui/dist/app/assets/{index-Canv3Ljk.css → index-BE22UToa.css} +1 -1
  23. package/tabtape/ui/dist/app/index.html +2 -2
  24. package/tabtape/ui/dist/build-info.json +4 -4
  25. package/tabtape/ui/dist/export/viewer.css +1 -1
  26. package/tabtape/ui/dist/export/viewer.js +6 -5
  27. package/agent-pane/frontend/dist/assets/index-CcL4MDxZ.js +0 -572
  28. package/agent-pane/frontend/dist/assets/index-Cr-XES2b.css +0 -1
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Inter:wght@400;450;510;590;600&family=JetBrains+Mono:wght@400;500&display=swap";:root{--canvas: #fdfdfc;--surface-0: #f8f7f5;--surface-1: #f0efed;--surface-2: #e6e4e0;--surface-3: #d6d3cd;--border: #e2e0db;--border-muted: #edebe7;--border-hover: #ccc8c0;--text: #1c1b18;--text-2: #54504a;--text-3: #78736c;--text-muted: #a8a399;--accent: #d97706;--accent-hover: #b45309;--accent-soft: rgba(217, 119, 6, .08);--accent-glow: rgba(217, 119, 6, .2);--green: #16a34a;--amber: #ca8a04;--red: #dc2626;--purple: #9333ea;--green-soft: rgba(22, 163, 74, .08);--amber-soft: rgba(202, 138, 4, .08);--red-soft: rgba(220, 38, 38, .08);--purple-soft: rgba(147, 51, 234, .08);--ic-claude: #c2410c;--ic-codex: #6366f1;--ic-repoburg: #059669;--ic-cursor: #db2777;--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SF Mono", "Fira Code", monospace;--r-sm: 4px;--r-md: 6px;--r-lg: 8px;--r-xl: 12px;--r-pill: 9999px;--ease: cubic-bezier(.25, .46, .45, .94);--ease-out: cubic-bezier(.22, 1, .36, 1);--dur-fast: .1s;--dur-normal: .15s;--dur-slow: .25s;--inset-highlight: inset 0 1px 0 rgba(0, 0, 0, .03);--inset-strong: inset 0 1px 0 rgba(0, 0, 0, .05);--focus-ring: 0 0 0 3px var(--accent-glow)}*{margin:0;padding:0;box-sizing:border-box}html,body{height:100%;overflow:hidden}body{font-family:var(--font-sans);font-size:13px;font-weight:400;background:var(--canvas);color:var(--text-2);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;font-feature-settings:"ss03","cv11";font-variant-numeric:tabular-nums;letter-spacing:-.01em}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--surface-3);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-md)}.ide-root{display:flex;flex-direction:column;height:100vh}.ide-layout{display:grid;grid-template-columns:240px 6px 1fr 6px 300px;flex:1;overflow:hidden}.resize-handle{width:6px;cursor:col-resize;background:transparent;flex-shrink:0;touch-action:none;transition:background var(--dur-fast) var(--ease)}.resize-handle:hover,.resize-handle.dragging{background:var(--border-hover)}body.is-resizing{-webkit-user-select:none;user-select:none}body.is-resizing *{cursor:col-resize!important}.ide-sidebar{background:var(--surface-0);border-right:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column}.sidebar-header{padding:10px 12px 8px;display:flex;align-items:center;justify-content:space-between}.sidebar-header-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.sidebar-add{width:20px;height:20px;border-radius:var(--r-sm);border:none;background:transparent;color:var(--text-muted);cursor:pointer;font-size:15px;display:flex;align-items:center;justify-content:center;transition:all var(--dur-normal) var(--ease)}.sidebar-add:hover{background:#0000000f;color:var(--text)}.sidebar-header-actions{display:flex;align-items:center;gap:2px}.sidebar-filter.active{background:var(--accent-soft);color:var(--accent)}.sidebar-filter.active:hover{color:var(--accent-hover)}.tree-section{margin-bottom:2px}.tree-section-header{padding:5px 8px;display:flex;align-items:center;gap:6px;font-size:11px;font-weight:590;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-section-header:hover{background:#0000000a}.tree-chevron{font-size:9px;color:var(--text-muted);width:10px;transition:transform var(--dur-normal) var(--ease)}.tree-section.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-section.collapsed .tree-children{display:none}.tree-count{margin-left:auto;font-size:10px;background:var(--surface-2);padding:1px 6px;border-radius:var(--r-pill);color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-children{padding-left:4px}.tree-item{padding:4px 8px 4px 26px;border-radius:var(--r-sm);font-size:12px;cursor:pointer;display:flex;align-items:center;gap:6px;color:var(--text-2);-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.tree-item:hover{background:#0000000a;color:var(--text)}.tree-item.active{background:var(--accent-soft);color:var(--text)}.tree-item.selected{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.tree-item.active.selected{box-shadow:none}.tree-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.tree-item .ri{width:16px;height:16px;border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;color:#fff;flex-shrink:0}.tree-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.star-btn{display:flex;align-items:center;justify-content:center;width:14px;height:14px;border:none;border-radius:3px;background:none;padding:0;color:var(--text-muted);opacity:0;cursor:pointer;flex-shrink:0;transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.tree-item:hover .star-btn,.star-btn:focus-visible{opacity:1}.star-btn:hover{color:var(--amber);opacity:.75}.star-btn.starred{opacity:1;color:#ca8a04a6}.tree-item-starred{background:#d9770609}.tree-item-starred:hover{background:#d9770612}.tree-item.active.tree-item-starred{background:var(--accent-soft)}.sidebar-footer{margin-top:auto;padding:8px 12px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted);display:flex;align-items:center;gap:6px;cursor:pointer}.sidebar-footer:hover{color:var(--text-2)}.ide-center{display:flex;flex-direction:column;background:var(--canvas);overflow:hidden;min-height:0}.ide-tabs{display:flex;background:var(--surface-0);border-bottom:1px solid var(--border);overflow-x:auto;flex-shrink:0;scrollbar-width:none}.ide-tabs::-webkit-scrollbar{display:none}.ide-tab{padding:8px 12px;font-size:12px;color:var(--text-3);border-right:1px solid var(--border-muted);cursor:pointer;display:flex;align-items:center;gap:6px;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.ide-tab:hover{background:#00000008;color:var(--text-2)}.ide-tab.active{color:var(--text);background:var(--canvas)}.ide-tab.active:after{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--accent)}.ide-tab .ri{width:14px;height:14px;font-size:7px;border-radius:3px}.ide-tab-close{margin-left:4px;color:var(--text-muted);font-size:14px;opacity:0;transition:opacity var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab:hover .ide-tab-close{opacity:1}.ide-tab-close:hover{color:var(--red)}.ide-tab-add{padding:8px 10px;color:var(--text-muted);cursor:pointer;font-size:14px;transition:color var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab-add:hover{color:var(--text)}.ide-render{flex:1;overflow:hidden;display:flex;flex-direction:column;position:relative;min-height:0}.render-scroll{flex:1;padding:20px 28px;overflow-y:auto;font-size:14px;line-height:1.7;color:var(--text);min-height:0}.render-content{max-width:720px}.render-content h1,.render-content h2,.render-content h3{margin:20px 0 8px;font-weight:600;color:var(--text);line-height:1.3}.render-content h1{font-size:20px}.render-content h2{font-size:17px}.render-content h3{font-size:15px}.render-content p{margin-bottom:12px;color:var(--text-2)}.render-content ul,.render-content ol{margin-bottom:12px;padding-left:24px}.render-content li{margin-bottom:4px;color:var(--text-2)}.render-content code{font-family:var(--font-mono);font-size:12px;background:var(--surface-1);padding:2px 6px;border-radius:var(--r-sm);color:var(--accent)}.render-content pre{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:12px 16px;overflow-x:auto;margin-bottom:12px}.render-content pre code{background:none;padding:0;color:var(--text);font-size:12.5px;line-height:1.6}.render-content a{color:var(--accent);text-decoration:none}.render-content a:hover{text-decoration:underline}.render-content blockquote{border-left:3px solid var(--border);padding-left:14px;color:var(--text-3);margin-bottom:12px}.render-content table{width:100%;border-collapse:collapse;margin-bottom:12px}.render-content th,.render-content td{border:1px solid var(--border);padding:6px 10px;font-size:13px}.render-content th{background:var(--surface-1);font-weight:510}.turn-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}.turn-header-icon{width:24px;height:24px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:9px;font-weight:700;color:#fff}.turn-header-title{font-size:14px;font-weight:600;color:var(--text)}.turn-header-meta{font-size:11px;color:var(--text-muted)}.tool-calls{margin-bottom:16px}.tool-calls-header{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--surface-1);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:background .15s ease-out;-webkit-user-select:none;user-select:none}.tool-calls-header:hover{background:var(--surface-2)}.tool-calls-icon{display:flex;align-items:center;color:var(--text-3);flex-shrink:0}.tool-calls-summary{font-size:13px;font-weight:500;color:var(--text-2);flex:1}.tool-calls-chevron{color:var(--text-muted);transition:transform .15s ease-out;flex-shrink:0}.tool-calls-body{margin-top:8px;padding-left:16px;border-left:2px solid var(--border)}.intermediate-segment{margin-bottom:16px}.intermediate-segment:last-child{margin-bottom:0}.user-message{font-size:14px;color:var(--text);background:var(--accent-soft);padding:12px 16px;border-radius:var(--r-md);border:1px solid rgba(217,119,6,.15)}.cmd-bar{position:relative;display:flex;flex-direction:column;padding:0;background:var(--surface-0);border-top:1px solid var(--border);flex-shrink:0}.cmd-input-row{display:flex;align-items:flex-end;gap:8px;padding:8px 12px}.cmd-bar:focus-within{box-shadow:inset 0 0 0 1px #d9770666}.cmd-textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:13px;font-family:var(--font-sans);outline:none;resize:none;overflow-y:auto;line-height:1.5;padding:6px 0}.cmd-textarea::placeholder{color:var(--text-muted)}.cmd-textarea:disabled{opacity:.5}.cmd-textarea:focus-visible{box-shadow:none}.cmd-send-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--surface-2);color:var(--text-muted);cursor:default;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-send-btn:not(:disabled){background:var(--accent);color:#fff;cursor:pointer}.cmd-send-btn:not(:disabled):hover{background:var(--accent-hover)}.cmd-send-btn:disabled{opacity:.4}.cmd-stop-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--red);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-stop-btn:hover{background:#b91c1c}.ide-right{background:var(--surface-0);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}.right-header{display:flex;align-items:center;border-bottom:1px solid var(--border);flex-shrink:0}.right-tabs{display:flex;flex:1;min-width:0;align-self:stretch;padding-left:8px;margin-bottom:-1px;overflow-x:auto;scrollbar-width:none}.right-tabs::-webkit-scrollbar{display:none}.right-tab{padding:7px 8px;font-size:11px;font-weight:510;color:var(--text-3);cursor:pointer;border-bottom:2px solid transparent;-webkit-user-select:none;user-select:none;white-space:nowrap;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.right-tab:hover{color:var(--text-2)}.right-tab.active{color:var(--text);border-bottom-color:var(--accent)}.right-content{flex:1;overflow-y:auto;padding:14px}.right-icon-btn{position:relative;display:flex;align-items:center;justify-content:center;width:26px;height:26px;flex-shrink:0;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.right-icon-btn:hover{background:#0000000f;color:var(--text)}.right-collapse-btn{width:22px;height:22px;margin-right:4px}.ide-right.collapsed{align-items:center;gap:2px;padding:6px 0}.right-rail-divider{width:16px;height:1px;margin:4px 0;background:var(--border);flex-shrink:0}.right-rail-tab.active{background:var(--accent-soft);color:var(--accent)}.right-rail-tab .right-tab-badge{position:absolute;top:-2px;right:-4px;min-width:14px;height:14px;margin:0;padding:0 3px;font-size:9px}.right-section{margin-bottom:20px}.right-section-title{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:8px}.turn-item{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:var(--r-sm);cursor:pointer;font-size:12px;color:var(--text-3);transition:all var(--dur-fast) var(--ease);position:relative}.turn-item:hover{background:#0000000a;color:var(--text-2)}.turn-item.active{background:var(--accent-soft);color:var(--text)}.turn-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.turn-item-icon{width:18px;height:18px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:8px;font-weight:700;color:#fff}.turn-item-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.turn-item-status{font-size:10px;color:var(--amber);flex-shrink:0}.turn-item-meta{font-size:10px;color:var(--text-muted);flex-shrink:0}.file-change{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:12px;border-bottom:1px solid var(--border-muted)}.file-change:last-child{border:none}.fc-status{width:14px;text-align:center;font-weight:700;font-size:11px;flex-shrink:0}.fc-add{color:var(--green)}.fc-mod{color:var(--amber)}.fc-del{color:var(--red)}.fc-name{flex:1;color:var(--text-2);font-family:var(--font-mono);font-size:11px}.ide-statusbar{display:flex;align-items:center;gap:12px;padding:0 12px;height:24px;background:var(--surface-0);border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);flex-shrink:0;font-variant-numeric:tabular-nums}.ide-hidden{display:none}.vscode-view{flex:1;display:flex;position:relative;overflow:hidden}.vscode-view-frame{flex:1;width:100%;border:none;background:#fff}.vscode-view--loading{align-items:center;justify-content:center;gap:10px;font-size:12px;color:var(--text-muted)}.vscode-view-hint{display:flex;align-items:center;gap:8px}.vscode-view-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;gap:8px;background:var(--surface-0);color:var(--text-muted);font-size:12px;z-index:10}.vscode-view-close{position:absolute;top:8px;right:8px}.sb-item{display:flex;align-items:center;gap:3px;cursor:pointer;transition:color var(--dur-fast) var(--ease)}.sb-item:hover{color:var(--text-2)}.sb-btn{background:none;border:none;font:inherit;padding:0;height:100%}.sb-item-active{color:var(--amber)}.sb-spacer{flex:1}.sb-divider{color:var(--border)}.sb-context{display:flex;align-items:center;gap:5px}.sb-context-text{font-size:10px;color:var(--text-muted);font-variant-numeric:tabular-nums}.model-selector{position:relative}.model-selector-btn{display:flex;align-items:center;gap:4px;background:none;border:none;cursor:pointer;color:var(--text-muted);font-size:11px;padding:2px 6px;border-radius:3px;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.model-selector-btn:hover{background:var(--surface-1);color:var(--text-2)}.model-selector-provider{font-weight:500;color:var(--accent)}.model-selector-sep{color:var(--border);margin:0 1px}.model-selector-model{color:var(--text-2)}.model-selector-reasoning{color:var(--text-muted);font-style:italic}.model-selector-chevron{opacity:.5;flex-shrink:0}.model-selector-popover{position:absolute;bottom:calc(100% + 4px);left:0;display:flex;gap:1px;background:var(--surface-0);border:1px solid var(--border);border-radius:6px;box-shadow:0 4px 16px #0003;z-index:100;min-width:0;overflow:hidden}.model-selector-column{min-width:140px;max-width:220px;max-height:280px;overflow-y:auto;padding:4px 0;background:var(--surface-0)}.model-selector-col-header{position:sticky;top:0;background:var(--surface-0);padding:4px 10px;font-size:9px;font-weight:600;text-transform:uppercase;color:var(--text-muted);letter-spacing:.5px}.model-selector-item{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;font-size:11px;color:var(--text-2);transition:background var(--dur-fast) var(--ease)}.model-selector-item:hover{background:var(--surface-1)}.model-selector-item.selected{color:var(--accent)}.model-selector-item.disabled{cursor:default;opacity:.5}.model-selector-item.disabled:hover{background:none}.model-selector-item-main{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}.model-selector-item-name{font-weight:500;white-space:nowrap}.model-selector-item-desc{font-size:9px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.model-selector-coming-soon{display:flex;align-items:center;gap:2px;font-size:9px;color:var(--text-muted);font-style:italic}.model-selector-empty{padding:8px 10px;font-size:10px;color:var(--text-muted);font-style:italic}.dialog-select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;padding-right:26px}.badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:var(--r-pill);font-size:11px;font-weight:510;white-space:nowrap}.badge-running{background:var(--green-soft);color:var(--green)}.badge-queued{background:var(--amber-soft);color:var(--amber)}.badge-done{background:var(--accent-soft);color:var(--accent)}.badge-failed{background:var(--red-soft);color:var(--red)}.badge-paused{background:#a8a3991f;color:var(--text-muted)}.runtime-icon{width:20px;height:20px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:#fff;flex-shrink:0;letter-spacing:0}.ic-claude{background:var(--ic-claude)}.ic-codex{background:var(--ic-codex)}.ic-repoburg{background:var(--ic-repoburg)}.ic-cursor{background:var(--ic-cursor)}.status-dot{width:6px;height:6px;border-radius:50%;display:inline-block;flex-shrink:0}.status-dot.running{background:var(--green);animation:dot-pulse 1.5s ease-in-out infinite}.status-dot.background{background:var(--purple);box-shadow:0 0 0 2px var(--purple-soft);animation:dot-blink 1s ease-in-out infinite}.status-dot.queued{background:var(--amber)}.status-dot.interrupted{background:transparent;box-shadow:inset 0 0 0 1.5px var(--amber)}.status-dot.error{background:var(--red)}.status-dot.done{background:var(--accent)}.status-dot.paused{background:var(--text-muted)}[data-lucide],svg.lucide{width:16px;height:16px;stroke-width:1.5;flex-shrink:0}.icon-xs{width:12px!important;height:12px!important}.icon-sm{width:14px!important;height:14px!important}.icon-lg{width:20px!important;height:20px!important}.dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000004d;display:flex;align-items:center;justify-content:center;z-index:100}.dialog{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:400px;max-width:90vw;box-shadow:0 8px 32px #00000029}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--border-muted)}.dialog-title{font-size:14px;font-weight:600;color:var(--text)}.dialog-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:var(--r-sm);display:flex;align-items:center;transition:all var(--dur-fast) var(--ease)}.dialog-close:hover{background:#0000000f;color:var(--text)}.dialog-body{padding:16px;display:flex;flex-direction:column;gap:14px}.dialog-label{display:flex;flex-direction:column;gap:4px;font-size:11px;font-weight:510;color:var(--text-muted)}.dialog-label a{color:var(--accent)}.dialog-input{border:1px solid var(--border);border-radius:var(--r-sm);padding:8px 10px;font-size:13px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;transition:border-color var(--dur-fast) var(--ease)}.dialog-input:focus{border-color:var(--accent);box-shadow:var(--focus-ring)}.dialog-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border-muted)}.dialog-btn-cancel{padding:6px 14px;border-radius:var(--r-sm);border:1px solid var(--border);background:transparent;color:var(--text-2);font-size:12px;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease);display:inline-flex;align-items:center;justify-content:center;gap:6px}.dialog-btn-cancel:hover{background:var(--surface-2);color:var(--text)}.dialog-btn-create{padding:6px 14px;border-radius:var(--r-sm);border:none;background:var(--accent);color:#fff;font-size:12px;font-weight:510;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease);display:inline-flex;align-items:center;justify-content:center;gap:6px}.dialog-btn-create:hover{background:var(--accent-hover)}.dialog-hint{font-size:12px;color:var(--text-2);line-height:1.5}.share-directives-input{resize:vertical;min-height:56px;font-family:var(--font-sans)}.spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.turn-group{margin-bottom:24px}.turn-block{margin-bottom:32px;padding-bottom:8px;border-bottom:1px solid var(--border)}.render-load-earlier{display:flex;justify-content:center;padding:0 0 16px}.render-load-earlier-btn{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-1);color:var(--text-muted);font-size:11px;font-family:var(--font-sans);padding:5px 12px;cursor:pointer;transition:all var(--dur-fast) var(--ease)}.thread-card-followup-stop{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-1);color:var(--red);cursor:pointer;padding:5px 8px;transition:all var(--dur-fast) var(--ease)}.thread-card-followup-stop:hover{background:var(--surface-2)}.turn-block:last-child{border-bottom:none}.cmd-block{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px}.cmd-block code{font-family:var(--font-mono);font-size:12px;color:var(--text)}.cmd-output{background:var(--surface-0);border:1px solid var(--border-muted);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px;max-height:200px;overflow-y:auto}.cmd-output code{font-family:var(--font-mono);font-size:12px;color:var(--text-3)}.cmd-output-toggle{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-1);color:var(--text-muted);font-size:11px;font-family:var(--font-sans);padding:4px 10px;cursor:pointer;margin-bottom:12px;transition:all var(--dur-fast) var(--ease)}.cmd-output-toggle:hover{background:var(--surface-2);color:var(--text-2)}.mcp-args{margin-bottom:12px}.mcp-arg{margin-bottom:6px}.mcp-arg-key{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:3px}.mcp-arg-value{font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word}.file-change-list{display:flex;flex-direction:column;gap:2px}.todo-list{list-style:none;padding-left:0}.todo-done{color:var(--text-3);text-decoration:line-through}.todo-pending{color:var(--text-2)}.empty-state{padding:40px 20px;text-align:center;color:var(--text-muted);font-size:13px}.daemon-download{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;padding:24px;background:var(--canvas);font-family:var(--font-sans);text-align:center}.daemon-download-title{margin:0;font-size:22px;font-weight:600;color:var(--text);letter-spacing:-.01em}.daemon-download-text{margin:0;font-size:13px;color:var(--text-2)}.daemon-download-btn{display:inline-flex;align-items:center;gap:8px;padding:10px 20px;border-radius:var(--r-md);background:var(--accent);color:#fff;font-size:14px;font-weight:510;text-decoration:none;transition:background var(--dur-fast) var(--ease)}.daemon-download-btn:hover{background:var(--accent-hover)}.daemon-download-btn:focus-visible,.daemon-download-link:focus-visible{outline:none;box-shadow:var(--focus-ring)}.daemon-download-link{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-3);text-decoration:none;border-radius:var(--r-sm)}.daemon-download-link:hover{color:var(--accent)}.daemon-download-waiting{margin:0;display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted)}.daemon-download-hint{margin:0;font-size:12px;color:var(--text-3)}.palette-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000040;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:flex-start;justify-content:center;padding-top:120px;z-index:200}.palette{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:520px;max-width:90vw;box-shadow:0 12px 40px #0003;overflow:hidden}.palette-search{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--border-muted)}.palette-search input{flex:1;border:none;background:transparent;color:var(--text);font-size:15px;font-family:var(--font-sans);outline:none}.palette-search input::placeholder{color:var(--text-muted)}.palette-esc{font-size:10px;font-weight:600;color:var(--text-muted);background:var(--surface-2);padding:2px 6px;border-radius:var(--r-sm)}.palette-list{max-height:360px;overflow-y:auto;padding:4px}.palette-empty{padding:24px;text-align:center;color:var(--text-muted);font-size:13px}.palette-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--r-sm);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.palette-item.selected{background:var(--accent-soft)}.palette-item-icon{color:var(--text-muted);flex-shrink:0;display:flex;align-items:center}.palette-item.selected .palette-item-icon{color:var(--accent)}.palette-item-label{font-size:13px;color:var(--text);font-weight:510}.palette-item-hint{font-size:11px;color:var(--text-muted);margin-left:auto}.palette-item-enter{color:var(--text-muted);flex-shrink:0}.toast-container{position:fixed;bottom:36px;right:16px;display:flex;flex-direction:column-reverse;gap:8px;z-index:300;pointer-events:none}.toast{display:flex;align-items:center;gap:8px;padding:10px 14px;border-radius:var(--r-md);font-size:12px;font-weight:500;min-width:280px;max-width:400px;pointer-events:auto;animation:toast-in .2s ease-out;border:1px solid var(--border);background:var(--surface-0);box-shadow:0 4px 16px #0000001f}@keyframes toast-in{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.toast-success{border-left:3px solid var(--green)}.toast-success svg{color:var(--green)}.toast-error{border-left:3px solid var(--red)}.toast-error svg{color:var(--red)}.toast-info{border-left:3px solid var(--accent)}.toast-info svg{color:var(--accent)}.toast-warn{border-left:3px solid var(--amber)}.toast-warn svg{color:var(--amber)}.toast-message{flex:1;color:var(--text-2)}.toast-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:var(--r-sm);display:flex;align-items:center;transition:color var(--dur-fast) var(--ease)}.toast-close:hover{color:var(--text)}.error-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#dc262614;border:1px solid rgba(220,38,38,.2);border-radius:var(--r-md);margin-bottom:16px}.banner-icon{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0}.error-banner .banner-icon{background:var(--red);color:#fff}.error-banner .banner-text{color:var(--red);font-size:13px;font-weight:500}.aborted-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#d9770614;border:1px solid rgba(217,119,6,.2);border-radius:var(--r-md);margin-top:16px}.aborted-banner .banner-icon{background:var(--amber);color:#fff}.aborted-banner .banner-text{color:var(--amber);font-size:13px;font-weight:500}.interruption-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:var(--amber-soft);border:1px solid rgba(202,138,4,.25);border-radius:var(--r-md);margin-top:16px}.interruption-banner .banner-icon{background:var(--amber);color:#fff}.interruption-banner .banner-text{flex:1;min-width:0;color:var(--amber);font-size:13px;font-weight:500}.interruption-banner .banner-detail{display:block;margin-top:2px;color:var(--text-3);font-family:var(--font-mono);font-size:12px;font-weight:400;white-space:pre-wrap;word-break:break-word}.interruption-banner[data-state=gave_up],.interruption-banner[data-state=skipped],.interruption-banner[data-state=unsupported]{background:var(--red-soft);border-color:#dc262633}.interruption-banner[data-state=gave_up] .banner-icon,.interruption-banner[data-state=skipped] .banner-icon,.interruption-banner[data-state=unsupported] .banner-icon{background:var(--red)}.interruption-banner[data-state=gave_up] .banner-text,.interruption-banner[data-state=skipped] .banner-text,.interruption-banner[data-state=unsupported] .banner-text{color:var(--red)}.interruption-banner.resumed{background:transparent;border-color:var(--border-muted);padding:6px 16px}.interruption-banner.resumed .banner-icon{background:var(--surface-2);color:var(--text-3)}.interruption-banner.resumed .banner-text{color:var(--text-3);font-size:12px;font-weight:400}.banner-action{display:inline-flex;align-items:center;gap:5px;flex-shrink:0;padding:4px 10px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--canvas);color:var(--text-2);font:500 12px var(--font-sans);cursor:pointer;transition:border-color var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.banner-action:hover:not(:disabled){border-color:var(--border-hover);color:var(--text)}.banner-action:disabled{opacity:.6;cursor:default}.banner-action svg.lucide{width:12px;height:12px}.retry-banner{display:flex;align-items:center;gap:10px;padding:8px 16px;background:var(--amber-soft);border:1px dashed rgba(202,138,4,.35);border-radius:var(--r-md);margin-top:12px}.retry-banner .banner-icon{background:var(--amber);color:#fff}.retry-banner .banner-text{color:var(--amber);font-size:13px}.interruption-marker{display:flex;align-items:center;gap:10px;margin:12px 0;color:var(--amber);font-size:12px}.interruption-marker:before,.interruption-marker:after{content:"";flex:1;border-top:1px dashed rgba(202,138,4,.45)}.interruption-marker span{max-width:80%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.skeleton-bars{width:80%;max-width:500px;margin:20px 0}.skeleton-bar{height:10px;border-radius:var(--r-sm);background:var(--surface-1);margin-bottom:8px;animation:shimmer 1.2s infinite}.skeleton-bar:nth-child(1){width:60%}.skeleton-bar:nth-child(2){width:85%}.skeleton-bar:nth-child(3){width:70%}.skeleton-bar:nth-child(4){width:90%}.skeleton-bar:nth-child(5){width:50%}@keyframes shimmer{0%{opacity:.3}50%{opacity:.6}to{opacity:.3}}@keyframes dot-pulse{0%{opacity:1}to{opacity:.4}}@keyframes dot-blink{0%,to{opacity:1}50%{opacity:.15}}.palette-footer{display:flex;gap:16px;padding:8px 16px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted)}.palette-footer-hint{display:flex;align-items:center;gap:4px}.kbd{font-family:var(--font-mono);font-size:10px;padding:1px 5px;border-radius:var(--r-sm);background:var(--surface-2);border:1px solid var(--border)}.toast-undo{font-size:12px;font-weight:500;color:var(--accent);background:transparent;border:none;cursor:pointer;padding:2px 8px;border-radius:var(--r-sm);display:flex;align-items:center;gap:4px;transition:background var(--dur-fast) var(--ease)}.toast-undo:hover{background:var(--accent-soft)}.tree-section-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.tree-section-add{width:18px;height:18px;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--dur-fast) var(--ease);flex-shrink:0}.tree-section-add:hover{background:var(--accent-soft);color:var(--accent)}.tree-empty{padding:4px 8px 4px 26px;font-size:11px;color:var(--text-muted);font-style:italic}.tree-subgroup{margin-bottom:1px}.tree-subgroup-header{padding:3px 8px 3px 18px;display:flex;align-items:center;gap:5px;font-size:10px;font-weight:590;color:var(--text-muted);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-subgroup-header:hover{background:#0000000a;color:var(--text-2)}.tree-subgroup.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-subgroup.collapsed .tree-subgroup-items{display:none}.tree-subgroup-label{text-transform:uppercase;letter-spacing:.05em}.tree-subgroup-count{margin-left:auto;font-size:9px;color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-subgroup-items{padding-left:0}.tree-item-finished .tree-label{color:var(--text-muted);opacity:.6}.tree-item-finished:hover .tree-label{opacity:.85}.ctx-menu{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;padding:4px;min-width:160px}.ctx-menu-header{padding:4px 10px 2px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.4px}.ctx-menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:var(--r-sm);font-size:12px;color:var(--text-2);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.ctx-menu-item:hover{background:var(--accent-soft);color:var(--text)}.ctx-menu-item.ctx-danger:hover{background:#dc262614;color:var(--red)}.ctx-menu-item.ctx-disabled{opacity:.4;cursor:default}.ctx-menu-item.ctx-disabled:hover{background:transparent;color:var(--text-2)}.tree-folder{margin-bottom:1px}.tree-folder-header{padding:3px 8px 3px 18px;display:flex;align-items:center;gap:5px;font-size:11px;font-weight:590;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-folder-header:hover{background:#0000000a}.tree-folder.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-folder.collapsed .tree-folder-children{display:none}.tree-folder-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-folder-children{padding-left:8px}.tree-folder-header.drop-over{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.drop-over{background:var(--accent-soft);border-radius:var(--r-sm)}.tree-item.dragging,.tree-folder.dragging{opacity:.35}.drag-overlay{display:flex;align-items:center;gap:6px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-sm);padding:4px 10px;font-size:12px;color:var(--text);box-shadow:0 4px 12px #00000026;max-width:200px}.drag-overlay span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-rename-input{flex:1;border:1px solid var(--accent);border-radius:var(--r-sm);padding:1px 6px;font-size:12px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;box-shadow:var(--focus-ring);min-width:0}.slash-popup{position:absolute;bottom:100%;left:12px;right:12px;margin-bottom:4px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;max-height:280px;overflow-y:auto;z-index:100}.slash-popup-header{padding:6px 10px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:4px}.slash-popup-back{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 4px;border-radius:var(--r-sm)}.slash-popup-back:hover{background:var(--surface-1);color:var(--text-2)}.slash-popup-empty{padding:12px 10px;font-size:12px;color:var(--text-muted);text-align:center}.slash-popup-item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 10px;cursor:pointer;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.slash-popup-item:hover,.slash-popup-item.selected{background:var(--accent-soft)}.slash-popup-label{font-size:12px;font-weight:500;color:var(--text-2);font-family:var(--font-mono)}.slash-popup-hint{font-size:11px;color:var(--text-muted)}.slash-popup-item-main{display:flex;flex-direction:column;gap:1px}.slash-popup-check{color:var(--accent);font-size:13px}.skill-badges{display:flex;flex-wrap:wrap;gap:4px;padding:6px 12px 0}.skill-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;font-size:11px;font-family:var(--font-mono);color:var(--accent);background:var(--accent-soft);border-radius:var(--r-sm)}.skill-badge-remove{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:13px;line-height:1;padding:0}.skill-badge-remove:hover{color:var(--red)}.attachment-preview-area{display:flex;flex-wrap:wrap;gap:4px;padding:6px 12px 0}.attachment-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 6px 2px 2px;border:1px solid var(--border);border-radius:var(--r-pill);background:var(--surface-1);max-width:180px;position:relative;transition:border-color var(--dur-fast) var(--ease)}.attachment-chip:hover{border-color:var(--accent)}.attachment-thumb{width:18px;height:18px;object-fit:cover;border-radius:50%;flex-shrink:0}.attachment-file-icon{width:14px;height:14px;color:var(--text-muted);flex-shrink:0}.attachment-info{display:flex;flex-direction:column;gap:0;overflow:hidden;min-width:0}.attachment-name{font-size:10px;font-family:var(--font-mono);color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.attachment-size{font-size:9px;color:var(--text-muted);font-variant-numeric:tabular-nums}.attachment-remove{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:1px;display:flex;align-items:center;justify-content:center;border-radius:var(--r-xs);transition:all var(--dur-fast) var(--ease);flex-shrink:0}.attachment-remove:hover{color:var(--red);background:#ef44441a}.attachment-clip-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.attachment-clip-btn:hover{color:var(--accent);background:var(--surface-2)}.attachment-clip-btn:disabled{opacity:.3;cursor:default}.cmd-bar.drag-over{box-shadow:inset 0 0 0 2px var(--accent);background:var(--accent-soft)}.image-preview-modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:10000;background:#000c;display:flex;align-items:center;justify-content:center;padding:32px;animation:modal-fade-in .15s ease-out}@keyframes modal-fade-in{0%{opacity:0}to{opacity:1}}.image-preview-content{position:relative;max-width:90vw;max-height:90vh;display:flex;flex-direction:column;align-items:center;gap:8px}.image-preview-content img{max-width:100%;max-height:80vh;object-fit:contain;border-radius:var(--r-sm);border:1px solid var(--border)}.image-preview-info{display:flex;gap:12px;font-size:12px;color:var(--text-muted);font-family:var(--font-mono)}.image-preview-close{position:absolute;top:-12px;right:-12px;width:28px;height:28px;border:none;border-radius:50%;background:var(--surface-2);color:var(--text);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--dur-fast) var(--ease)}.image-preview-close:hover{background:var(--red);color:#fff}.attachment-pills{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.attachment-pill{display:inline-flex;align-items:center;gap:4px;padding:2px 8px 2px 2px;border:1px solid var(--border);border-radius:var(--r-pill);background:var(--surface-1);font-size:10px;font-family:var(--font-mono);color:var(--text-muted);transition:border-color var(--dur-fast) var(--ease)}.attachment-pill:hover{border-color:var(--accent)}.attachment-pill-thumb{width:16px;height:16px;object-fit:cover;border-radius:50%;flex-shrink:0}.attachment-pill-icon{color:var(--text-muted);flex-shrink:0}.attachment-pill-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.right-tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;padding:0 4px;margin-left:4px;font-size:10px;font-weight:600;color:#fff;background:var(--accent);border-radius:8px}.task-count-badge{font-size:10px;font-weight:500}.task-card{border:1px solid var(--border);border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;transition:border-color var(--dur-fast) var(--ease)}.task-card.task-running{border-color:var(--accent)}.task-card.task-failed{border-color:var(--red)}.task-card-header{display:flex;align-items:center;gap:8px}.task-card-icon{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--r-sm);background:var(--surface-2);color:var(--text-3);flex-shrink:0}.task-card-type{font-size:13px;font-weight:600;color:var(--text)}.task-card-status{display:flex;align-items:center;gap:3px;font-size:11px;padding:2px 6px;border-radius:var(--r-sm);flex-shrink:0}.task-status-running{color:var(--accent);background:var(--accent-soft)}.task-status-done{color:var(--green);background:var(--green-soft)}.task-status-failed{color:var(--red);background:var(--red-soft)}.task-card-chevron{color:var(--text-muted);flex-shrink:0;transition:transform var(--dur-fast) var(--ease)}.task-card-desc{font-size:12px;color:var(--text-2);margin-top:6px;font-family:var(--font-mono)}.task-card-meta{font-size:11px;color:var(--text-muted);margin-top:4px}.task-card-body{margin-top:8px}.task-output{max-height:300px}.task-card-placeholder{font-size:12px;color:var(--text-muted);font-style:italic;padding:8px 0}.task-card-context{font-size:10px;color:var(--text-muted);margin-top:6px;padding-top:6px;border-top:1px solid var(--border-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}mark[data-thread-id]{background:#d977062e;border-radius:2px;cursor:pointer;padding:0 1px;transition:background var(--dur-fast) var(--ease)}mark[data-thread-id]:hover{background:#d977064d}mark[data-thread-id].thread-mark-resolved{background:transparent;border-bottom:2px dashed var(--text-muted)}.selection-actions{position:fixed;z-index:9999;display:flex;gap:4px}.discuss-button{display:flex;align-items:center;gap:4px;padding:4px 10px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-0);color:var(--accent);font-size:11px;font-weight:500;cursor:pointer;box-shadow:0 2px 8px #0000001f;transition:all var(--dur-fast) var(--ease)}.discuss-button:hover{background:var(--accent-soft);border-color:var(--accent)}.copy-text-btn{position:absolute;top:-4px;right:-4px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-0);color:var(--text-3);cursor:pointer;opacity:0;z-index:5;box-shadow:0 1px 4px #00000014;transition:all var(--dur-fast) var(--ease)}.copy-text-wrapper:hover .copy-text-btn,.copy-text-btn:focus-visible,.copy-text-btn.copied{opacity:1}.copy-text-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}.copy-text-btn.copied{border-color:var(--green);color:var(--green);background:var(--surface-0)}.thread-create-popover{position:fixed;z-index:9999;min-width:280px;max-width:360px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #00000026;padding:10px;display:flex;flex-direction:column;gap:8px;transform:translate(-100%)}.thread-create-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.thread-create-quote{font-size:11px;color:var(--text-muted);font-style:italic;flex:1;line-height:1.4}.thread-create-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:var(--r-sm);flex-shrink:0}.thread-create-close:hover{background:var(--surface-1);color:var(--text)}.thread-create-input{border:1px solid var(--border);border-radius:var(--r-sm);padding:8px 10px;font-size:13px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;resize:none;line-height:1.5;transition:border-color var(--dur-fast) var(--ease)}.thread-create-input:focus{border-color:var(--accent);box-shadow:var(--focus-ring)}.thread-create-footer{display:flex;align-items:center;justify-content:space-between}.thread-create-hint{font-size:10px;color:var(--text-muted)}.thread-create-send{display:flex;align-items:center;gap:4px;padding:4px 10px;border:none;border-radius:var(--r-sm);background:var(--accent);color:#fff;font-size:11px;font-weight:500;cursor:pointer;transition:background var(--dur-fast) var(--ease)}.thread-create-send:disabled{opacity:.4;cursor:default}.thread-create-send:not(:disabled):hover{background:var(--accent-hover)}.thread-filter-tabs{display:flex;gap:2px;margin-bottom:12px;padding:2px;background:var(--surface-1);border-radius:var(--r-md)}.thread-filter-tab{flex:1;padding:4px 8px;border:none;background:transparent;color:var(--text-3);font-size:10px;font-weight:500;cursor:pointer;border-radius:var(--r-sm);font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.thread-filter-tab:hover{color:var(--text-2)}.thread-filter-tab.active{background:var(--surface-0);color:var(--text);box-shadow:var(--inset-highlight)}.thread-card{border:1px solid var(--border);border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;transition:border-color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}.thread-card.thread-resolved{opacity:.7}.thread-card-highlighted{border-color:var(--accent);background:var(--accent-soft)}.thread-card-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;cursor:pointer}.thread-card-quote{font-size:11px;color:var(--text-muted);font-style:italic;line-height:1.4;flex:1}.thread-card-header-right{display:flex;align-items:center;gap:4px;flex-shrink:0}.thread-status-badge{font-size:10px;font-weight:600;padding:2px 8px;border-radius:var(--r-pill)}.thread-status-open{background:var(--accent-soft);color:var(--accent)}.thread-status-resolved{background:var(--green-soft);color:var(--green)}.thread-card-conversation{margin-top:8px;max-height:300px;overflow-y:auto}.thread-card-turn{margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--border-muted)}.thread-card-turn:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.thread-card-user-message{font-size:12px;color:var(--text);background:var(--accent-soft);padding:6px 10px;border-radius:var(--r-sm);border:1px solid rgba(217,119,6,.15);margin-bottom:4px}.thread-card-ai-response{font-size:12px;color:var(--text-2);padding:4px 0;line-height:1.5}.thread-card-ai-response p{margin-bottom:6px}.thread-card-ai-response code{font-family:var(--font-mono);font-size:11px;background:var(--surface-1);padding:1px 4px;border-radius:var(--r-sm);color:var(--accent)}.thread-card-ai-response pre{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-sm);padding:8px;overflow-x:auto;margin-bottom:6px}.thread-card-ai-response pre code{background:none;padding:0}.thread-card-pending{font-size:11px;color:var(--text-muted);font-style:italic;padding:4px 0}.thread-card-placeholder{font-size:11px;color:var(--text-muted);font-style:italic;padding:8px 0}.thread-card-followup{display:flex;gap:4px;margin-top:8px}.thread-card-followup-input{flex:1;border:1px solid var(--border);border-radius:var(--r-sm);padding:6px 8px;font-size:12px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;resize:none;line-height:1.5;transition:border-color var(--dur-fast) var(--ease)}.thread-card-followup-input:focus{border-color:var(--accent)}.thread-card-followup-input:disabled{opacity:.5}.thread-card-followup-send{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background var(--dur-fast) var(--ease)}.thread-card-followup-send:disabled{opacity:.4;cursor:default}.thread-card-followup-send:not(:disabled):hover{background:var(--accent-hover)}.thread-locate-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:3px;display:flex;align-items:center;transition:all var(--dur-fast) var(--ease);flex-shrink:0}.thread-locate-btn:hover{color:var(--accent);background:var(--accent-soft)}.thread-mark-flash{animation:mark-flash 1.5s ease-out}@keyframes mark-flash{0%{background:#d9770680}to{background:#d977062e}}.thread-card-actions{display:flex;gap:6px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-muted)}.thread-action-btn{display:flex;align-items:center;gap:4px;padding:4px 8px;border:1px solid var(--border);border-radius:var(--r-sm);background:transparent;color:var(--text-3);font-size:11px;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.thread-action-btn:hover{background:var(--surface-1);color:var(--text)}.thread-action-btn.thread-action-danger:hover{background:#dc262614;color:var(--red);border-color:#dc262633}.thread-action-btn:disabled{opacity:.5;cursor:default;pointer-events:none}.sidecar-panel{display:flex;flex-direction:column;min-height:100%}.sidecar-conversation{flex:1}.sidecar-hint{font-size:11px;margin-top:4px;line-height:1.5}.sidecar-footer{position:sticky;bottom:-14px;margin:0 -14px -14px;padding:8px 14px 14px;background:var(--surface-0);border-top:1px solid var(--border-muted)}.sidecar-footer .thread-card-followup{margin-top:0}.agent-call-card{display:flex;align-items:center;gap:8px;padding:8px 14px;border-left:3px solid var(--accent);background:var(--surface);border-radius:0 var(--r-sm) var(--r-sm) 0}.agent-call-icon{color:var(--text-2);display:flex;align-items:center}.agent-call-desc{font-size:13px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.agent-call-status{font-size:10px;font-family:var(--font-mono);padding:1px 6px;border-radius:var(--r-sm)}.agent-call-status.running{color:var(--accent);background:var(--accent-soft)}.agent-call-status.done{color:var(--green);background:#22c55e14}.agent-call-status.failed{color:var(--red);background:#ef444414}.ask-user-card{border-left:3px solid var(--accent)}.ask-user-groups{display:flex;flex-direction:column;gap:10px;margin-top:6px}.ask-user-group{display:flex;flex-direction:column;gap:6px}.ask-user-question{font-size:12px;font-weight:600;color:var(--text-2)}.ask-user-options{display:flex;flex-wrap:wrap;gap:6px}.ask-user-option{padding:4px 10px;font-size:12px;font-family:var(--font-sans);color:var(--text-2);background:var(--canvas);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.ask-user-option:not(:disabled):hover{border-color:var(--accent);color:var(--accent)}.ask-user-option.selected{background:var(--accent);border-color:var(--accent);color:#fff}.ask-user-option:disabled{opacity:.55;cursor:default}.ask-user-option.selected:disabled{opacity:.8}.ask-user-send{display:inline-flex;align-items:center;gap:5px;padding:4px 12px;font-size:12px;font-family:var(--font-sans);color:#fff;background:var(--accent);border:none;border-radius:var(--r-sm);cursor:pointer;align-self:flex-start;transition:background var(--dur-fast) var(--ease)}.ask-user-send:disabled{opacity:.4;cursor:default}.ask-user-send:not(:disabled):hover{background:var(--accent-hover)}.ask-user-submitted{font-size:11px;color:var(--text-muted);font-style:italic}.miniapp-view{display:flex;flex-direction:column;height:100%;background:var(--canvas)}.miniapp-view-hidden{display:none}.miniapp-header{display:flex;align-items:center;gap:8px;padding:8px 12px;border-bottom:1px solid var(--border-muted)}.miniapp-header-icon{flex-shrink:0;color:var(--text-2)}.miniapp-header-title{font-size:12px;font-weight:600;color:var(--text)}.miniapp-header-close{margin-left:auto;display:flex;padding:3px;color:var(--text-muted);background:none;border:none;border-radius:var(--r-sm);cursor:pointer}.miniapp-header-close:hover{color:var(--text);background:#0000000d}.miniapp-workspace-select{margin-left:8px;padding:3px 6px;font-size:11px;color:var(--text-2);background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;font-family:var(--font-sans);max-width:220px}.miniapp-workspace-select:hover{border-color:var(--border-hover)}.miniapp-workspace-select+.miniapp-header-btn{margin-left:0}.miniapp-body{flex:1;min-height:0}.miniapp-runtime{display:flex;flex-direction:column;height:100%}.miniapp-frame{display:block;width:100%;flex:1;min-height:0;border:none;background:#fff}.miniapp-diagnostics{padding:8px 12px;max-height:160px;overflow-y:auto;background:var(--red-bg, rgba(220, 38, 38, .08));border-bottom:1px solid rgba(220,38,38,.3);font-size:11px;color:var(--red)}.miniapp-diagnostics-title{font-weight:600;margin-bottom:4px}.miniapp-diagnostics-warn{background:var(--amber-soft);border-bottom-color:var(--amber);color:var(--amber)}.miniapp-diag{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap;margin:2px 0}.miniapp-rt-errors{border-top:1px solid rgba(220,38,38,.3);background:#dc26260f;max-height:130px;overflow-y:auto;padding:6px 12px;font-size:11px;color:var(--red)}.miniapp-rt-error-message{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap}.miniapp-rt-error-stack{margin:2px 0 6px;padding:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--text-muted);white-space:pre-wrap}.miniapp-tab-icon{flex-shrink:0}.sidebar-apps{flex-shrink:0;padding-top:8px;border-top:1px solid var(--border-muted)}.sidebar-apps-header{padding-bottom:4px}.app-catalog{width:480px;max-width:92vw}.catalog-tabs{display:flex;gap:4px;padding:0 16px;border-bottom:1px solid var(--border)}.catalog-tab{padding:8px 12px;font-size:12px;font-weight:510;color:var(--text-2);background:none;border:none;border-bottom:2px solid transparent;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.catalog-tab:hover{color:var(--text)}.catalog-tab.active{color:var(--accent);border-bottom-color:var(--accent)}.catalog-body{display:flex;flex-direction:column;gap:12px}.catalog-examples{display:flex;flex-direction:column;gap:8px;max-height:300px;overflow-y:auto}.example-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--border);border-radius:var(--r-sm)}.example-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.example-title{font-size:12px;font-weight:510;color:var(--text)}.example-desc{font-size:11px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.example-install{padding:4px 12px;border-radius:var(--r-sm);border:none;background:var(--accent);color:#fff;font-size:11px;font-weight:510;cursor:pointer;font-family:var(--font-sans)}.example-install:hover:not(:disabled){background:var(--accent-hover)}.example-install:disabled{background:var(--surface-2);color:var(--text-3);cursor:default}.catalog-action-btn{align-self:flex-start}.catalog-upload-hint{font-size:11px;color:var(--text-3);line-height:1.5}.catalog-upload-summary{font-size:11px;color:var(--text-2)}.apps-panel{display:flex;flex-direction:column;gap:6px;padding:10px}.apps-panel-row{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.apps-panel-row:hover{border-color:var(--border-hover);background:var(--surface-0)}.apps-panel-row.active{border-color:var(--accent);background:var(--accent-soft)}.apps-panel-info{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}.apps-panel-title{font-size:12px;font-weight:510;color:var(--text)}.apps-panel-desc{font-size:11px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.apps-panel-action{display:flex;padding:4px;color:var(--text-muted);background:none;border:none;border-radius:var(--r-sm);cursor:pointer}.apps-panel-action:hover{color:var(--text);background:#0000000d}.apps-panel-action.pinned{color:var(--accent)}.apps-panel-danger:hover{color:var(--red);background:var(--red-soft)}.sidebar-app-row{display:flex;align-items:center;gap:8px;padding:5px 12px;font-size:12px;color:var(--text-2);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.sidebar-app-row:hover{background:#00000008;color:var(--text)}.sidebar-app-row.active{background:var(--accent-soft);color:var(--accent)}.sidebar-app-icon{flex-shrink:0}.sidebar-app-pin{margin-left:auto;color:var(--accent);flex-shrink:0}.sidebar-app-count{margin-left:auto;font-size:10px;background:var(--surface-2);padding:1px 6px;border-radius:var(--r-pill);color:var(--text-muted);font-variant-numeric:tabular-nums;flex-shrink:0}.sidebar-app-count+.sidebar-app-pin{margin-left:0}.sidebar-app-chevron{display:flex;padding:2px;color:var(--text-muted);background:none;border:none;border-radius:var(--r-sm);cursor:pointer;flex-shrink:0}.sidebar-app-chevron:hover{color:var(--text);background:#0000000d}.sidebar-app-chevron.closed .tree-chevron{transform:rotate(-90deg)}.sidebar-app-edit-row{display:flex;align-items:center;gap:6px;padding:3px 12px 3px 28px;font-size:11.5px;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:all var(--dur-fast) var(--ease)}.sidebar-app-edit-row:hover{background:#0000000a;color:var(--text)}.sidebar-app-edit-row.active{background:var(--accent-soft);color:var(--text)}.sidebar-app-edit-row.selected{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.sidebar-app-edit-row.active.selected{box-shadow:none}.sidebar-app-edits .tree-subgroup-header{padding:3px 12px 3px 20px}.miniapp-header-btn{display:inline-flex;align-items:center;gap:4px;margin-left:auto;padding:3px 10px;font-size:11px;color:var(--text-2);background:none;border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.miniapp-header-btn:hover{border-color:var(--accent);color:var(--accent)}.miniapp-header-btn+.miniapp-header-close{margin-left:0}.tree-app-badge{display:inline-flex;flex-shrink:0;color:var(--text-muted)}
@@ -10,8 +10,8 @@
10
10
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;450;510;590;600&family=JetBrains+Mono:wght@400;500&display=swap"
11
11
  rel="stylesheet"
12
12
  />
13
- <script type="module" crossorigin src="/assets/index-CcL4MDxZ.js"></script>
14
- <link rel="stylesheet" crossorigin href="/assets/index-Cr-XES2b.css">
13
+ <script type="module" crossorigin src="/assets/index-BuZ-_HXG.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/assets/index-DlwZnsU3.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -12,7 +12,7 @@ const os_1 = __importDefault(require("os"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const redact_1 = require("./redact");
14
14
  /** Version of the tabtape component (extension, replay UI, server API). */
15
- exports.TABTAPE_VERSION = '0.5.0';
15
+ exports.TABTAPE_VERSION = '0.6.0';
16
16
  /** URL prefix of everything tabtape serves on the daemon's port. */
17
17
  exports.TABTAPE_MOUNT = '/tabtape';
18
18
  const UNITS = [
@@ -135,7 +135,7 @@ const TOOLS = [
135
135
  { name: 'has_errors', type: 'boolean', description: 'only sessions with console errors or failed requests' },
136
136
  { name: 'limit', type: 'integer', description: 'maximum number of sessions (default 20)' },
137
137
  ], OUTPUT.list, (t, input) => t.listSessions(input)),
138
- def('get_session_summary', "What happened in a recording, in order: page views, clicks, form changes, submits, the app's own events (tabtape.track), console errors, failed requests, poor Web Vitals and long freezes, each with its time and replay link. Also the identified user (tabtape.identify).", [
138
+ def('get_session_summary', "What happened in a recording, in order: page views, clicks, form changes, submits, the app's own events (tabtape.track), console errors, failed requests, poor Web Vitals and long freezes, each with its time and replay link. Also the identified user (tabtape.identify) and the page's memory: JS heap at the start, at the end and its peak.", [
139
139
  { name: 'session_id', type: 'string', description: 'session id, or latest for the most recent recording', required: true },
140
140
  { name: 'cursor', type: 'string', description: CURSOR },
141
141
  ], OUTPUT.summary, (t, input) => t.getSessionSummary(input)),
@@ -174,7 +174,7 @@ const TOOLS = [
174
174
  { name: 'limit', type: 'integer', description: 'maximum number of messages (default 100)' },
175
175
  { name: 'cursor', type: 'string', description: CURSOR },
176
176
  ], OUTPUT.console, (t, input) => t.getConsole(input)),
177
- def('get_context_at', 'Everything around one moment, in order: user actions, requests and console messages from 10 seconds before to 2 seconds after (adjustable), then the last 10 Redux / Zustand store actions before the moment with the state paths they changed. Use it to see what led to an error.', [
177
+ def('get_context_at', "Everything around one moment, in order: user actions, requests and console messages from 10 seconds before to 2 seconds after (adjustable), the page's JS heap at the moment and how it changed in the window, then the last 10 Redux / Zustand store actions before the moment with the state paths they changed. Use it to see what led to an error.", [
178
178
  { name: 'session_id', type: 'string', description: SESSION_LATEST, required: true },
179
179
  {
180
180
  name: 'at',
@@ -24,13 +24,13 @@ const log_1 = require("../log");
24
24
  const definitions_1 = require("./definitions");
25
25
  const gofmt_1 = require("./gofmt");
26
26
  const tools_1 = require("./tools");
27
- exports.INSTRUCTIONS = `tabtape records browser sessions locally: DOM replay, clicks, page views, form changes, network requests, console output, the app's own events (tabtape.track) and user id (tabtape.identify), Web Vitals and long freezes, and Redux / Zustand store actions.
27
+ exports.INSTRUCTIONS = `tabtape records browser sessions locally: DOM replay, clicks, page views, form changes, network requests, console output, the app's own events (tabtape.track) and user id (tabtape.identify), Web Vitals, long freezes and the page's memory (JS heap), and Redux / Zustand store actions.
28
28
  Use these tools to answer questions about what happened in a recording. Times are offsets from the start of the replay (mm:ss.mmm).
29
29
  Every session and line carries a replay link; include the relevant links in answers so the user can watch the moment.
30
30
  Start with list_sessions or get_session_summary (session_id "latest" is the most recent recording), then drill down with get_network, get_request, get_console and get_context_at.
31
31
  Request and response bodies are only returned by get_request or with include_bodies=true. Sensitive headers are shown as [redacted].
32
32
  Recordings made in deep mode also have the real request headers and cookies, the timing split, why a request failed (CORS, blocked cookies, mixed content) and WebSocket connections: get_network with kind=websocket lists them, get_request on a connection pages its messages.
33
- get_context_at ends with the last store actions before the moment and the state paths they changed.
33
+ get_session_summary says how the JS heap grew over the recording; get_context_at gives the heap at the moment and ends with the last store actions before it and the state paths they changed.
34
34
  To record a browser you drive yourself (Playwright MCP, a Playwright script), get_record_link returns links that start and stop a recording in it; open the start link before the check and the stop link after it.`;
35
35
  const RESOURCE_PREFIX = 'tabtape://session/';
36
36
  const SESSION_TEMPLATE = {
@@ -501,6 +501,24 @@ describe('TabtapeMcp', () => {
501
501
  ({ text } = await call(e, 'get_context_at', { session_id: 's1', at: '00:03.000' }));
502
502
  expect(text).toContain('CLS 0.02 (good)');
503
503
  });
504
+ it('reports the page memory', async () => {
505
+ const e = await setup();
506
+ qt.append(e.st, 's1', qt.memory(t0 + 100, 12, 120), qt.memory(t0 + 3100, 64, 900), qt.memory(t0 + 6100, 48, 1500));
507
+ let { text } = await call(e, 'get_session_summary', { session_id: 's1' });
508
+ expect(text).toContain('Memory: JS heap 12.0 MB at the start, 48.0 MB at the end, peak 64.0 MB at 00:03.090 (limit 4.00 GB); DOM elements 120 → 1,500. get_context_at shows the heap at a moment.');
509
+ expect(text).not.toContain('perf');
510
+ ({ text } = await call(e, 'get_context_at', { session_id: 's1', at: '00:05', before: '5', after: '2' }));
511
+ expect(text).toContain('Memory at 00:05.000: JS heap 64.0 MB used of 128.0 MB (limit 4.00 GB) · 900 DOM elements; 12.0 MB → 48.0 MB in this window (+36.0 MB).');
512
+ ({ text } = await call(e, 'get_context_at', { session_id: 's1', at: '00:05', before: '0.5', after: '0.5' }));
513
+ expect(text).toContain('Memory at 00:05.000: JS heap 64.0 MB used of 128.0 MB (limit 4.00 GB) · 900 DOM elements.\n');
514
+ });
515
+ it('leaves memory out of recordings without samples', async () => {
516
+ const e = await setup();
517
+ let { text } = await call(e, 'get_session_summary', { session_id: 's1' });
518
+ expect(text).not.toContain('Memory');
519
+ ({ text } = await call(e, 'get_context_at', { session_id: 's1', at: '00:00' }));
520
+ expect(text).not.toContain('Memory');
521
+ });
504
522
  it('reports deep mode network data and store state', async () => {
505
523
  const e = await setup();
506
524
  const recs = [
@@ -168,6 +168,7 @@ class Tools {
168
168
  const notes = dataNotes(v);
169
169
  if (notes !== '')
170
170
  b.write(notes);
171
+ b.write((0, perf_1.memorySummary)(memorySamples(v)));
171
172
  if (so.live)
172
173
  b.write('Live: the recording is still being written.\n');
173
174
  if (so.trimmed)
@@ -568,6 +569,7 @@ class Tools {
568
569
  out.items = items;
569
570
  else
570
571
  b.write('Nothing was recorded in this window apart from screen changes.\n');
572
+ b.write((0, perf_1.memoryAt)(memorySamples(v), at, at - before, at + after));
571
573
  const actions = await this.stateActions(v, at);
572
574
  if (actions.length > 0) {
573
575
  out.stateActions = actions;
@@ -677,6 +679,14 @@ function dataNotes(v) {
677
679
  }
678
680
  return b;
679
681
  }
682
+ /** The page's memory samples, in time order. */
683
+ function memorySamples(v) {
684
+ const out = [];
685
+ for (const l of v.lines)
686
+ if (l.perf && l.perf.kind === 'memory')
687
+ out.push({ offset: v.offset(l.ts), p: l.perf });
688
+ return out;
689
+ }
680
690
  function itemLine(it) {
681
691
  return `${it.at} ${(0, gofmt_1.padRight)(it.kind, 9)} ${it.text} [${it.id}] ${it.replay}\n`;
682
692
  }
@@ -6,7 +6,9 @@ exports.baseName = baseName;
6
6
  exports.longestScript = longestScript;
7
7
  exports.sortedJSON = sortedJSON;
8
8
  exports.propsText = propsText;
9
- /** Web Vitals and long animation frame texts. */
9
+ exports.memorySummary = memorySummary;
10
+ exports.memoryAt = memoryAt;
11
+ /** Web Vitals, long animation frame and memory texts. */
10
12
  const format_1 = require("./format");
11
13
  /** A metric's value; CLS has no unit. */
12
14
  function vitalValue(name, value) {
@@ -91,3 +93,53 @@ function propsText(props, n) {
91
93
  const keys = Object.keys(props).sort();
92
94
  return (0, format_1.clip)(keys.map((k) => `${k}: ${propValue(props[k])}`).join(', '), n);
93
95
  }
96
+ const count = (n) => n.toLocaleString('en-US');
97
+ /**
98
+ * One line about the page's memory over the whole recording, e.g.
99
+ * "Memory: JS heap 12.0 MB at the start, 48.0 MB at the end, peak 64.0 MB at
100
+ * 00:30.000 (limit 4.00 GB); DOM elements 120 → 900." Empty without samples.
101
+ */
102
+ function memorySummary(samples) {
103
+ if (samples.length === 0)
104
+ return '';
105
+ const first = samples[0];
106
+ const last = samples[samples.length - 1];
107
+ let peak = first;
108
+ for (const s of samples)
109
+ if (s.p.used > peak.p.used)
110
+ peak = s;
111
+ let b = `Memory: JS heap ${(0, format_1.fmtBytes)(first.p.used)} at the start, ${(0, format_1.fmtBytes)(last.p.used)} at the end, peak ${(0, format_1.fmtBytes)(peak.p.used)} at ${(0, format_1.clock)(peak.offset)}`;
112
+ if (peak.p.limit > 0)
113
+ b += ` (limit ${(0, format_1.fmtBytes)(peak.p.limit)})`;
114
+ if (first.p.nodes !== undefined && last.p.nodes !== undefined)
115
+ b += `; DOM elements ${count(first.p.nodes)} → ${count(last.p.nodes)}`;
116
+ return b + '. get_context_at shows the heap at a moment.\n';
117
+ }
118
+ /**
119
+ * The memory at offset `at` (the last sample at or before it, else the
120
+ * first) and its change over the samples between from and to. Empty without
121
+ * samples.
122
+ */
123
+ function memoryAt(samples, at, from, to) {
124
+ if (samples.length === 0)
125
+ return '';
126
+ let now = samples[0];
127
+ for (const s of samples) {
128
+ if (s.offset > at)
129
+ break;
130
+ now = s;
131
+ }
132
+ let b = `Memory at ${(0, format_1.clock)(at)}: JS heap ${(0, format_1.fmtBytes)(now.p.used)} used of ${(0, format_1.fmtBytes)(now.p.total)}`;
133
+ if (now.p.limit > 0)
134
+ b += ` (limit ${(0, format_1.fmtBytes)(now.p.limit)})`;
135
+ if (now.p.nodes !== undefined)
136
+ b += ` · ${count(now.p.nodes)} DOM elements`;
137
+ const window = samples.filter((s) => s.offset >= from && s.offset <= to);
138
+ if (window.length >= 2) {
139
+ const a = window[0].p.used;
140
+ const z = window[window.length - 1].p.used;
141
+ const d = z - a;
142
+ b += `; ${(0, format_1.fmtBytes)(a)} → ${(0, format_1.fmtBytes)(z)} in this window (${d < 0 ? '-' : '+'}${(0, format_1.fmtBytes)(Math.abs(d))})`;
143
+ }
144
+ return b + '.\n';
145
+ }
@@ -225,9 +225,21 @@ describe('network texts', () => {
225
225
  });
226
226
  describe('perf texts', () => {
227
227
  it('names the longest script and renders props', () => {
228
- const p = { kind: 'loaf', name: '', value: 0, rating: '', id: '', url: '', duration: 600, blockingDuration: 550 };
228
+ const p = { kind: 'loaf', name: '', value: 0, rating: '', id: '', url: '', duration: 600, blockingDuration: 550, used: 0, total: 0, limit: 0 };
229
229
  expect((0, perf_1.longestScript)({ ...p, scripts: [{ url: 'http://a.test/js/slow.js?v=1', fn: 'handleClick', invoker: '', invokerType: '', duration: 1 }] })).toBe('slow.js handleClick');
230
230
  expect((0, perf_1.longestScript)({ ...p, scripts: [{ url: '', fn: '', invoker: 'BUTTON#go.onclick', invokerType: '', duration: 1 }] })).toBe('BUTTON#go.onclick');
231
231
  expect((0, perf_1.propsText)({ plan: 'pro', items: 3, nested: { b: 1, a: 2 }, none: null }, 120)).toBe('items: 3, nested: {"a":2,"b":1}, none: null, plan: pro');
232
232
  });
233
+ it('describes memory samples', () => {
234
+ const MB = 1024 * 1024;
235
+ const p = { kind: 'memory', name: '', value: 0, rating: '', id: '', url: '', duration: 0, blockingDuration: 0, limit: 0 };
236
+ const samples = [
237
+ { offset: 0, p: { ...p, used: 50 * MB, total: 60 * MB } },
238
+ { offset: 5000, p: { ...p, used: 20 * MB, total: 60 * MB } },
239
+ ];
240
+ expect((0, perf_1.memorySummary)([])).toBe('');
241
+ expect((0, perf_1.memoryAt)([], 0, 0, 0)).toBe('');
242
+ expect((0, perf_1.memorySummary)(samples)).toBe('Memory: JS heap 50.0 MB at the start, 20.0 MB at the end, peak 50.0 MB at 00:00.000. get_context_at shows the heap at a moment.\n');
243
+ expect((0, perf_1.memoryAt)(samples, 9000, 0, 9000)).toBe('Memory at 00:09.000: JS heap 20.0 MB used of 60.0 MB; 50.0 MB → 20.0 MB in this window (-30.0 MB).\n');
244
+ });
233
245
  });
@@ -247,6 +247,10 @@ function decodePerf(v) {
247
247
  duration: num(s.duration),
248
248
  }))
249
249
  : undefined,
250
+ used: num(d.used),
251
+ total: num(d.total),
252
+ limit: num(d.limit),
253
+ nodes: optNum(d.nodes),
250
254
  };
251
255
  }
252
256
  // ---------- predicates ----------
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stateRec = exports.ws = exports.loaf = exports.vital = exports.identify = exports.track = exports.consoleRec = exports.net = exports.submit = exports.change = exports.click = exports.pageView = exports.rrInc = exports.rrFull = exports.rrMeta = exports.UA = exports.T0 = void 0;
3
+ exports.stateRec = exports.ws = exports.memory = exports.loaf = exports.vital = exports.identify = exports.track = exports.consoleRec = exports.net = exports.submit = exports.change = exports.click = exports.pageView = exports.rrInc = exports.rrFull = exports.rrMeta = exports.UA = exports.T0 = void 0;
4
4
  exports.testStore = testStore;
5
5
  exports.closeTestStores = closeTestStores;
6
6
  exports.append = append;
@@ -108,6 +108,13 @@ const loaf = (ts, duration, ...scripts) => ({
108
108
  data: { kind: 'loaf', duration, blockingDuration: Math.max(duration - 50, 0), ...(scripts.length ? { scripts } : {}) },
109
109
  });
110
110
  exports.loaf = loaf;
111
+ /** A memory sample: used and allocated heap in MB, a 4 GB limit. */
112
+ const memory = (ts, usedMb, nodes) => ({
113
+ ts,
114
+ type: 'perf',
115
+ data: { kind: 'memory', used: usedMb * 1024 * 1024, total: 2 * usedMb * 1024 * 1024, limit: 4096 * 1024 * 1024, url: 'http://localhost:7788/', ...(nodes === undefined ? {} : { nodes }) },
116
+ });
117
+ exports.memory = memory;
111
118
  /** A WebSocket message of connection conn. */
112
119
  const ws = (ts, conn, dir, data) => ({
113
120
  ts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repoburg",
3
- "version": "1.3.270",
3
+ "version": "1.3.272",
4
4
  "description": "A local AI-powered software developer assistant that runs on your own machine.",
5
5
  "author": "Celal Ertug",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -73,6 +73,10 @@
73
73
  "tabtape:build": "cd tabtape && npm ci --no-audit --no-fund && npm run build",
74
74
  "test:publish": "node --test prepublish-check.test.js publish-scope.test.js",
75
75
  "dev:tabtape": "cd tabtape && npm run dev -w ui",
76
+ "mac:test": "swift test --package-path daemon-macos",
77
+ "mac:build": "daemon-macos/scripts/build-app.sh",
78
+ "mac:install": "daemon-macos/scripts/install.sh",
79
+ "mac:release": "daemon-macos/scripts/release.sh",
76
80
  "jaeger:start": "docker run -d --rm --name jaeger -e COLLECTOR_OTLP_ENABLED=true -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest",
77
81
  "jaeger:stop": "docker stop jaeger",
78
82
  "lo:build": "npm run build -w backend && npm run build -w website2 && (cd agent-pane/backend && npm run build) && (cd agent-pane/frontend && npm run build) && npm run build -w recorder && npm run build -w visual-editor-proxy && npm run tabtape:build && npm run build -w daemon && cd frontend && npm run build",
@@ -1,7 +1,7 @@
1
1
  {
2
- "tree": "f1e4a7bc0d8f8c6677cf229567552e042a4aa3a3",
3
- "commit": "9d2cc76f4215bcf0b70ad8b7789178ebaa44c713",
2
+ "tree": "be7a0bb65dfb8b69e1abe13098765c382867de6a",
3
+ "commit": "17acf248ca860a514d2081ab86e779df017fa194",
4
4
  "dirty": false,
5
- "repoburgVersion": "1.3.270",
6
- "builtAt": "2026-10-23T22:28:25.521Z"
5
+ "repoburgVersion": "1.3.272",
6
+ "builtAt": "2026-10-24T00:05:54.786Z"
7
7
  }
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "name": "tabtape recorder",
4
4
  "short_name": "tabtape",
5
- "version": "0.5.0",
5
+ "version": "0.6.0",
6
6
  "description": "Records the current tab (DOM, clicks, network, console, app state) to tabtape in your local Repoburg daemon for replay.",
7
7
  "minimum_chrome_version": "125",
8
8
  "icons": {
@@ -58,5 +58,5 @@
58
58
  ]
59
59
  }
60
60
  ],
61
- "version_name": "0.5.0 (repoburg 1.3.270, 9d2cc76)"
61
+ "version_name": "0.6.0 (repoburg 1.3.272, 17acf24)"
62
62
  }