@electric-agent/studio 1.5.0 → 1.7.0

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.
@@ -0,0 +1 @@
1
+ @font-face{font-family:OpenSauceOne;font-style:normal;font-weight:300;src:url(/assets/OpenSauceOne-Light-NEdTeQp-.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:400;src:url(/assets/OpenSauceOne-Regular-BivIUdzJ.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:500;src:url(/assets/OpenSauceOne-Medium-Cu5cjAHY.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:600;src:url(/assets/OpenSauceOne-Bold-BeiFYFR5.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:700;src:url(/assets/OpenSauceOne-ExtraBold-DO6BqiNe.woff2) format("woff2")}@font-face{font-family:SourceCodePro;font-style:normal;font-weight:400;src:url(/assets/SourceCodePro-Regular-CoIbWt_c.woff2) format("woff2")}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg: #1b1b1f;--bg-surface: #202127;--bg-hover: #2a2a32;--border: #3a3a44;--text: rgba(255, 255, 245, .92);--text-muted: rgba(235, 235, 245, .68);--text-subtle: rgba(235, 235, 245, .46);--brand-1: #d0bcff;--brand-2: #998fe7;--brand-3: #7e78db;--electric-color: #00d2a0;--tanstack-db-color: #ff8c3b;--durable-streams-color: #75fbfd;--green: #3fb950;--yellow: #d29922;--red: #f85149;--purple: #d0bcff;--blue: #9ecbff;--orange: #ff8c3b;--cyan: #75fbfd;--font-sans: OpenSauceOne, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: SourceCodePro, ui-monospace, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--sh-keyword: #d0bcff;--sh-string: #3fb950;--sh-number: #ff8c3b;--sh-comment: rgba(235, 235, 245, .38);--sh-class: #d29922;--sh-identifier: #9ecbff;--sh-property: #75fbfd;--sh-sign: rgba(235, 235, 245, .5);--sh-entity: #f85149;--sh-jsxliterals: rgba(255, 255, 245, .92);--sidebar-width: 240px;--topbar-height: 48px;--footer-height: 60px}html,body,#root{height:100%;width:100%;background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:15px;line-height:1.6}*{scrollbar-width:thin;scrollbar-color:var(--border) transparent}*::-webkit-scrollbar{width:6px;height:6px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}*::-webkit-scrollbar-thumb:hover{background:var(--text-subtle)}.app-shell{display:grid;grid-template-columns:var(--sidebar-width) 1fr;height:100vh;overflow:hidden;transition:grid-template-columns .2s ease;position:relative}.app-shell.sidebar-collapsed{--sidebar-width: 64px}.sidebar{display:flex;flex-direction:column;height:100%;background:var(--bg-surface);border-right:1px solid var(--border);overflow:hidden;transition:width .2s ease}.sidebar-header{display:flex;align-items:center;gap:8px;padding:0 16px;border-bottom:1px solid var(--border);height:var(--topbar-height);flex-shrink:0}.sidebar-icon{width:24px;height:24px;flex-shrink:0}.sidebar-brand{font-size:15px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden}.global-settings-btn{position:absolute;top:8px;right:12px;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px;z-index:50;transition:color .15s,background .15s}.global-settings-btn:hover{color:var(--text);background:var(--bg-hover)}.sidebar-collapse{padding:0 8px;flex-shrink:0;border-top:1px solid var(--border);height:var(--footer-height);display:flex;align-items:center;box-sizing:border-box}.sidebar-collapse-btn{display:flex;align-items:center;gap:8px;width:100%;height:32px;padding:0 16px;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px;font-size:13px;transition:color .15s,background .15s}.sidebar-collapse-btn:hover{color:var(--text);background:var(--bg-hover)}.sidebar-collapse-btn svg{width:16px;height:16px;flex-shrink:0}.sidebar-collapse-label{white-space:nowrap;overflow:hidden;opacity:1;max-width:120px;transition:opacity .15s ease,max-width .2s ease}.sidebar-collapsed .sidebar-collapse-btn{gap:0}.sidebar-collapsed .sidebar-collapse-label{opacity:0;max-width:0;display:none}.sidebar-collapsed .sidebar-brand{display:none}.sidebar-collapsed .sidebar-section-label{font-size:0;padding:0 8px;margin:4px 0;height:1px;background:var(--border);border-radius:1px}.sidebar-collapsed .sidebar-section-label:first-child{display:none}.sidebar-collapsed .session-item{gap:0}.sidebar-collapsed .session-item-details,.sidebar-collapsed .session-item-delete,.sidebar-collapsed .session-item:hover .session-item-delete{opacity:0;width:0;overflow:hidden;pointer-events:none}.sidebar-section-label{font-size:11px;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;padding:8px 12px 4px}.sidebar-sessions{flex:1;overflow-y:auto;padding:0 4px}.session-content{display:flex;flex-direction:column;flex:1;overflow:hidden}.session-header{display:flex;align-items:center;gap:8px;padding:0 52px 0 16px;height:var(--topbar-height);font-size:13px;position:absolute;top:0;left:0;right:0;z-index:10;background:#1b1b1fcc;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-bottom:1px solid rgba(58,58,68,.5)}.session-header-name{font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.session-header-status{font-size:11px;margin-left:auto;flex-shrink:0}.session-header-cost{font-size:11px;font-family:var(--font-mono);color:var(--text-muted);flex-shrink:0;padding:2px 6px;border-radius:4px;background:var(--bg-hover)}.session-header-action{font-size:12px;font-family:var(--font-mono);cursor:pointer;color:var(--text-muted);background:transparent;border:1px solid var(--border);border-radius:6px;padding:4px 10px;transition:color .15s,background .15s,border-color .15s;flex-shrink:0;text-decoration:none;line-height:1.4}.session-header-action:hover{color:var(--text);background:var(--bg-hover);border-color:var(--text-subtle)}.session-header-action:disabled{opacity:.5;cursor:not-allowed}.session-header-action.primary{border-color:var(--brand-3);color:var(--brand-1)}.session-header-action.primary:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.session-initializing{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;color:var(--text-muted);font-size:15px;padding-top:var(--topbar-height)}.session-loading{padding:calc(var(--topbar-height) + 16px) 16px 16px;flex:1}.session-initializing-spinner{width:28px;height:28px;border:3px solid var(--border);border-top-color:var(--brand-1);border-radius:50%;animation:spin .8s linear infinite}.main-content{display:flex;flex-direction:column;height:100%;overflow:hidden;position:relative}.console{flex:1;overflow-y:auto;padding:calc(var(--topbar-height) + 16px) 16px 16px;position:relative}.mobile-preview-bar~.console{padding-top:16px}.shared-session-panel-body .console{padding-top:16px}.jump-to-bottom{position:sticky;bottom:8px;left:50%;transform:translate(-50%);display:block;margin:0 auto;padding:6px 16px;font-size:11px;font-family:var(--font-mono);color:var(--text);background:var(--bg-surface);border:1px solid var(--border);border-radius:16px;cursor:pointer;z-index:10;opacity:.9;transition:opacity .15s}.jump-to-bottom:hover{opacity:1;background:var(--bg-hover)}.prompt-bar{display:flex;align-items:center;gap:8px;padding:8px 16px;border-top:1px solid var(--border);height:var(--footer-height);box-sizing:border-box;flex-shrink:0}.prompt-bar textarea{flex:1;padding:10px 14px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-sans);font-size:15px;line-height:1.5;resize:none;min-height:44px;max-height:200px;transition:border-color .15s,box-shadow .15s}.prompt-bar textarea:hover{border-color:var(--border)}.prompt-bar textarea:focus{outline:none;border-color:var(--border);box-shadow:none}.prompt-bar textarea::placeholder{color:var(--text-subtle)}.hero{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;padding:0 24px;text-align:center}.hero-logo{height:64px;margin-bottom:16px}.hero-subtitle{font-size:17px;font-weight:500;color:var(--text-muted);margin-bottom:36px}.hero-prompt{width:100%;max-width:640px}.hero-prompt .prompt-bar{border-top:none;padding:0;gap:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:14px;overflow:hidden;align-items:center}.hero-prompt .prompt-bar textarea{border:none;border-radius:0;background:transparent;min-height:52px;font-size:15px;padding:14px}.hero-prompt .prompt-bar textarea:hover,.hero-prompt .prompt-bar textarea:focus{border:none;box-shadow:none}.hero-prompt .prompt-bar button{border:none;border-radius:0 13px 13px 0;min-height:52px;padding:8px 24px;flex-shrink:0;align-self:stretch}.shared-session-header{display:flex;align-items:center;gap:8px;padding:0 52px 0 16px;border-bottom:1px solid var(--border);height:var(--topbar-height);flex-shrink:0;font-size:13px}.shared-session-header-name{font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shared-session-header-participants{display:flex;align-items:center;gap:4px}.shared-session-participant{width:24px;height:24px;border-radius:50%;background:var(--brand-3);color:#fff;font-size:10px;font-weight:600;font-family:var(--font-mono);display:flex;align-items:center;justify-content:center;flex-shrink:0}.invite-code-label{font-size:12px;color:var(--text-subtle);flex-shrink:0;margin-left:auto}.invite-code-btn{font-family:var(--font-mono);font-size:12px;padding:4px 10px;border:1px dashed var(--border);border-radius:6px;background:transparent;color:var(--text-muted);cursor:pointer;transition:color .15s,background .15s,border-color .15s;flex-shrink:0}.invite-code-btn:hover{color:var(--text);background:var(--bg-hover);border-color:var(--text-subtle)}.shared-session-panels{display:flex;flex-direction:column;gap:2px;flex:1;overflow-y:auto;padding:0}.shared-session-panel{border:1px solid var(--border);border-radius:8px;overflow:hidden;display:flex;flex-direction:column}.shared-session-panel-header{display:flex;align-items:center;gap:8px;height:40px;padding:0 12px;cursor:pointer;font-size:13px;font-family:var(--font-mono);background:var(--bg-surface);transition:background .1s;flex-shrink:0;-webkit-user-select:none;user-select:none}.shared-session-panel-header:hover{background:var(--bg-hover)}.shared-session-panel-chevron{width:14px;height:14px;flex-shrink:0;color:var(--text-subtle);transition:transform .2s ease}.shared-session-panel.collapsed .shared-session-panel-chevron{transform:rotate(-90deg)}.shared-session-panel-id{color:var(--text-muted);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.shared-session-panel-body{display:none;flex-direction:column;overflow:hidden}.shared-session-panel.expanded .shared-session-panel-body{display:flex;flex:1}.shared-session-panel.expanded{flex:1}.shared-session-unlink-btn{font-size:11px;font-family:var(--font-mono);padding:2px 8px;border:1px solid var(--border);border-radius:4px;background:transparent;color:var(--text-subtle);cursor:pointer;transition:color .1s,border-color .1s;flex-shrink:0}.shared-session-unlink-btn:hover{color:var(--red);border-color:var(--red)}.shared-session-content{display:flex;flex-direction:column;flex:1;overflow:hidden;padding:8px;gap:8px}.shared-session-toolbar{display:flex;align-items:center;gap:8px;padding:4px 8px;flex-shrink:0}.shared-session-toolbar-label{font-size:12px;font-family:var(--font-mono);color:var(--text-subtle)}.shared-session-link-btn{font-size:12px;font-family:var(--font-mono);padding:4px 10px;border:1px solid var(--brand-3);border-radius:6px;background:transparent;color:var(--brand-1);cursor:pointer;transition:background .15s,color .15s}.shared-session-link-btn:hover{background:var(--brand-2);color:#fff}.shared-session-empty{display:flex;align-items:center;justify-content:center;flex:1;color:var(--text-subtle);font-size:14px}.session-avatar-shared{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--purple)}.sidebar-join-input{display:flex;align-items:center;gap:4px;padding:4px 8px;margin-bottom:2px}.sidebar-join-input input{flex:1;min-width:0;padding:4px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);font-family:var(--font-mono);font-size:12px}.sidebar-join-input input:focus{outline:none;border-color:var(--brand-2)}.sidebar-join-input input::placeholder{color:var(--text-subtle)}.sidebar-join-go{padding:4px 8px;border:1px solid var(--border);border-radius:4px;background:var(--bg-surface);color:var(--text-muted);font-family:var(--font-mono);font-size:12px;cursor:pointer;flex-shrink:0}.sidebar-join-go:hover{background:var(--bg-hover);color:var(--text)}.sidebar-join-go:disabled{opacity:.5;cursor:not-allowed}.shared-session-error{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;gap:12px;color:var(--text-muted);font-size:14px;padding:24px;text-align:center}.shared-session-error h2{font-size:18px;color:var(--text);margin:0}.shared-session-error p{margin:0}.console-entry{display:flex;align-items:baseline;gap:0;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6}.console a{color:var(--brand-1);text-decoration:none}.console a:hover{text-decoration:underline}.console-entry .prefix{font-weight:600;margin-right:6px}.console-entry .prefix.plan{color:var(--brand-1)}.console-entry .prefix.approve{color:var(--brand-2)}.console-entry .prefix.task{color:var(--blue)}.console-entry .prefix.build{color:var(--brand-2)}.console-entry .prefix.fix{color:var(--yellow)}.console-entry .prefix.done{color:var(--green)}.console-entry .prefix.error{color:var(--red)}.console-entry .prefix.debug{color:var(--text-subtle)}.duration{margin-left:auto;font-family:var(--font-mono);font-size:11px;color:var(--text-subtle);white-space:nowrap;flex-shrink:0}.user-message{padding:3px 0;margin:0}.tool-inline{margin:0;padding:0}.tool-inline summary{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-family:var(--font-mono);font-size:13px;color:var(--text-subtle);list-style:none;line-height:1.6}.tool-inline summary::-webkit-details-marker{display:none}.tool-inline summary:hover .tool-inline-name{text-decoration:underline}.tool-inline summary:hover .tool-inline-summary{text-decoration:underline;color:var(--text-muted)}.tool-inline-agent{font-weight:600;color:var(--blue);font-size:13px}.tool-inline-name{font-weight:600;color:var(--brand-1);font-size:13px}.tool-inline-summary{color:var(--text-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:600px}.tool-inline-command{color:var(--text-muted);font-family:var(--font-mono);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.spinner-inline{width:10px;height:10px;border:1.5px solid var(--border);border-top-color:var(--brand-1);border-radius:50%;animation:spin .8s linear infinite;flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.tool-inline-body{padding:8px 0 8px 16px;border-left:2px solid var(--border);margin:2px 0 4px 6px}.tool-inline-body pre{font-family:var(--font-mono);font-size:12px;line-height:1.5;color:var(--text-muted);white-space:pre-wrap;word-break:break-all;max-height:400px;overflow-y:auto}.tool-inline-body .section-label{font-size:11px;font-weight:600;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;margin:8px 0 4px}.tool-inline-body .section-label:first-child{margin-top:0}.thinking-inline{margin:0;padding:0}.thinking-inline summary{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-family:var(--font-mono);font-size:13px;color:var(--text-subtle);list-style:none;line-height:1.6}.thinking-inline summary::-webkit-details-marker{display:none}.thinking-inline summary:hover .thinking-label,.thinking-inline summary:hover .thinking-preview{text-decoration:underline;color:var(--text-muted)}.thinking-label{color:var(--brand-2);font-size:13px;font-weight:600;flex-shrink:0}.thinking-inline summary:hover .thinking-label{color:var(--brand-2)}.thinking-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-subtle);max-width:600px}.thinking-body{padding:8px 0 8px 16px;border-left:2px solid var(--border);margin:2px 0 4px 6px}.thinking-body pre{font-family:var(--font-mono);font-size:12px;line-height:1.5;color:var(--text-muted);white-space:pre-wrap;word-break:break-word;max-height:400px;overflow-y:auto}.waiting-indicator{gap:6px;color:var(--text-subtle);animation:fade-pulse 2s ease-in-out infinite}.waiting-label{font-style:italic}@keyframes fade-pulse{0%,to{opacity:1}50%{opacity:.5}}.tool-group{margin:2px 0;padding:0}.tool-group-header{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-family:var(--font-mono);font-size:13px;color:var(--text-muted);line-height:1.6}.tool-group-header:hover .tool-group-label{text-decoration:underline}.tool-group-label{font-weight:600;color:var(--brand-1)}.tool-group-tail,.tool-group-items{padding-left:16px}.tool-group-tail{overflow:hidden}.tool-group-slide-in{animation:group-slide-in .25s ease-out}@keyframes group-slide-in{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.todo-list{list-style:none;padding:0;margin:0}.todo-item{display:flex;align-items:center;gap:8px;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6;color:var(--text-muted)}.todo-status-icon{width:16px;text-align:center;flex-shrink:0;font-size:14px}.todo-status-done{color:var(--green)}.todo-status-progress{color:var(--brand-1)}.todo-status-pending{color:var(--text-subtle)}.todo-content{flex:1}.todo-priority{font-size:11px;padding:1px 6px;border-radius:4px;background:#ffffff0f;color:var(--text-subtle);flex-shrink:0}.gate-prompt{margin:8px 0;padding:16px;border:1px solid var(--border);border-radius:8px;background:var(--bg-surface)}.gate-prompt h3{font-family:var(--font-sans);font-size:15px;font-weight:600;margin-bottom:8px;color:var(--brand-1)}.gate-prompt .gate-summary{color:var(--text-muted);font-size:13px;font-family:var(--font-sans);margin-bottom:12px}.gate-plan{margin:8px 0}.gate-plan-body{padding:4px 0}.gate-plan-actions{display:flex;gap:8px;margin-top:12px;padding:12px 0;border-top:1px solid var(--border)}.gate-prompt .question{margin-bottom:8px}.gate-prompt .question label{display:block;font-family:var(--font-sans);font-size:13px;color:var(--text-muted);margin-bottom:4px}.gate-prompt .question input,.gate-prompt .question select,.gate-prompt .question textarea{width:100%;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-mono);font-size:13px;transition:border-color .15s,box-shadow .15s,background .15s}.gate-prompt .question textarea{resize:vertical}.gate-prompt .question input::placeholder,.gate-prompt .question textarea::placeholder{color:var(--text-subtle)}.gate-prompt .question select{appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:30px;cursor:pointer}.gate-prompt .question input:hover,.gate-prompt .question textarea:hover,.gate-prompt .question select:hover{border-color:var(--text-subtle)}.gate-prompt .question input:focus,.gate-prompt .question textarea:focus,.gate-prompt .question select:focus{outline:none;border-color:var(--brand-2);box-shadow:0 0 0 3px #998fe726}.gate-prompt .question input:disabled,.gate-prompt .question textarea:disabled,.gate-prompt .question select:disabled{opacity:.5;cursor:not-allowed}.gate-actions{display:flex;gap:8px;margin-top:12px}.gate-btn{padding:8px 18px;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);font-family:var(--font-mono);font-size:13px;cursor:pointer;transition:background .15s,border-color .15s,color .15s,box-shadow .15s}.gate-btn:hover{background:var(--bg-hover);border-color:var(--text-subtle)}.gate-btn:disabled{opacity:.5;cursor:not-allowed}.gate-btn-primary{background:transparent;border-color:var(--brand-3);color:var(--brand-1);font-weight:600}.gate-btn-primary:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.gate-btn-danger{border-color:var(--red);color:var(--red)}.gate-btn-danger:hover{background:#f851491a}.gate-continue{display:flex;align-items:center;gap:12px;margin:4px 0;padding:8px 12px;border:1px solid var(--border);border-radius:8px;background:var(--bg-surface);font-family:var(--font-mono);font-size:13px}.gate-continue-text{color:var(--text-muted);flex:1}.gate-continue .gate-btn{padding:4px 12px;font-size:12px}.gate-radio-group{display:flex;gap:12px;margin-top:4px;padding:4px 0}.gate-radio{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:13px;color:var(--text);cursor:pointer;line-height:1.4;padding:8px 12px;border-radius:8px;border:1px solid var(--border);transition:background .15s,border-color .15s}.gate-radio:hover{background:var(--bg-hover);border-color:var(--text-subtle)}.gate-radio:has(input:checked){border-color:var(--brand-2);background:var(--bg-hover)}.gate-radio input[type=radio],.gate-radio input[type=checkbox]{width:auto;margin:0;vertical-align:middle;accent-color:var(--brand-2)}.gate-option-group{display:flex;gap:8px;margin:8px 0}.gate-option{flex:1;display:flex;flex-direction:column;gap:4px;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:transparent;cursor:pointer;text-align:left;transition:background .15s,border-color .15s,box-shadow .15s}.gate-option:hover{background:var(--bg-hover);border-color:var(--text-subtle)}.gate-option.active{border-color:var(--brand-2);background:var(--bg-hover)}.gate-option:disabled{opacity:.5;cursor:not-allowed}.gate-option.selected{border-color:var(--green);opacity:1}.gate-option-title{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--text)}.gate-option-desc{font-size:11px;color:var(--text-subtle);line-height:1.3}.gate-answered{margin:0}.gate-answered-header{display:flex;align-items:center;gap:0;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6}.gate-answered-header .prefix{font-weight:600;margin-right:6px}.gate-resolved-label{color:var(--text-subtle)}.gate-answered .gate-prompt,.gate-answered .gate-plan,.gate-answered .gate-continue{opacity:.65}.gate-continue-decision{color:var(--text-muted);font-style:italic}.gate-config-summary{background:#ffffff0a;border:1px solid rgba(255,255,255,.1);border-radius:6px;padding:8px 10px;margin:6px 0;font-family:var(--font-mono);font-size:12px;line-height:1.6;word-break:break-all;color:var(--text-muted)}.gate-config-summary a{color:var(--brand-1);word-break:break-all}.gate-answer-summary{font-family:var(--font-mono);font-size:13px;color:var(--text-muted);padding:6px 10px;margin:8px 0;background:#ffffff0a;border:1px solid rgba(255,255,255,.1);border-radius:6px}.gate-option-group-vert{display:flex;flex-direction:column;gap:6px;margin:8px 0}.gate-option-group-vert .gate-option{flex:none}.gate-option.gate-option-other{border-style:dashed;opacity:.7}.gate-option.gate-option-other:hover{opacity:1}.gate-question-section{margin-bottom:12px;padding-bottom:12px}.gate-question-section:last-child{margin-bottom:0;padding-bottom:0}.gate-question-section+.gate-question-section{border-top:1px solid var(--border);padding-top:12px}.gate-question-header{display:inline-block;font-family:var(--font-sans);font-size:11px;font-weight:600;color:var(--brand-1);background:#998fe71a;border:1px solid rgba(153,143,231,.2);border-radius:4px;padding:2px 8px;margin-bottom:6px}.gate-option.gate-option-checkbox{flex-direction:row;align-items:center;gap:8px}.gate-option.gate-option-checkbox.checked{border-color:var(--brand-2);background:var(--bg-hover)}.gate-checkbox-indicator{font-size:16px;line-height:1;color:var(--text-muted);flex-shrink:0}.gate-option.gate-option-checkbox.checked .gate-checkbox-indicator{color:var(--brand-1)}.markdown{font-family:var(--font-sans);font-size:14px;line-height:1.7;color:var(--text);word-wrap:break-word}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{color:var(--text);font-weight:600;margin-top:1.2em;margin-bottom:.4em;line-height:1.3}.markdown h1{font-size:1.4em}.markdown h2{font-size:1.2em}.markdown h3{font-size:1.1em}.markdown h4{font-size:1em}.markdown h1:first-child,.markdown h2:first-child,.markdown h3:first-child{margin-top:0}.markdown p{margin-bottom:.6em}.markdown p:last-child{margin-bottom:0}.markdown ul,.markdown ol{padding-left:1.5em;margin-bottom:.6em}.markdown li{margin-bottom:.2em}.markdown li>p{margin-bottom:.2em}.markdown code{font-family:var(--font-mono);font-size:.9em;padding:.15em .4em;background:var(--bg-hover);border-radius:4px;color:var(--brand-1)}.markdown pre{margin:.6em 0;padding:12px 16px;background:var(--bg);border:1px solid var(--border);border-radius:6px;overflow-x:auto;font-family:var(--font-mono);font-size:13px;line-height:1.5}.markdown pre code{padding:0;background:none;border-radius:0;color:var(--text-muted);font-size:inherit}.markdown blockquote{margin:.6em 0;padding:4px 12px;border-left:3px solid var(--brand-2);color:var(--text-muted)}.markdown blockquote p{margin-bottom:.2em}.markdown table{width:100%;border-collapse:collapse;margin:.6em 0;font-size:13px}.markdown th,.markdown td{padding:6px 12px;border:1px solid var(--border);text-align:left}.markdown th{background:var(--bg-surface);font-weight:600;color:var(--text)}.markdown td{color:var(--text-muted)}.markdown hr{border:none;border-top:1px solid var(--border);margin:1em 0}.markdown a{color:var(--brand-1);text-decoration:none}.markdown a:hover{text-decoration:underline}.markdown strong{color:var(--text);font-weight:600}.markdown img{max-width:100%;border-radius:4px}.markdown-inline{font-family:var(--font-mono);font-size:13px;line-height:1.6;color:var(--text-muted)}.markdown-inline h1,.markdown-inline h2,.markdown-inline h3,.markdown-inline h4,.markdown-inline h5,.markdown-inline h6{font-size:inherit;font-weight:600;margin:0;line-height:inherit;color:inherit}.markdown-inline p{margin-bottom:.3em}.markdown-inline p:last-child{margin-bottom:0}.markdown-inline pre{font-size:12px;margin:.4em 0}.markdown-inline a{color:var(--brand-1);text-decoration:none}.markdown-inline a:hover{text-decoration:underline}.btn{padding:6px 16px;border-radius:6px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text);font-size:13px;cursor:pointer;transition:background .15s}.btn:hover{background:var(--bg-hover)}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background:var(--brand-3);border-color:var(--brand-3);color:#fff;font-weight:600}.btn-primary:hover{background:var(--brand-2);border-color:var(--brand-2)}.btn-danger{border-color:var(--red);color:var(--red)}.btn-danger:hover{background:#f851491a}.prompt-bar button{padding:6px 14px;min-height:36px;border-radius:8px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text);font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.prompt-bar button:hover{background:var(--bg-hover)}.prompt-bar button.primary{background:var(--brand-2);border-color:var(--brand-2);color:#fff;font-weight:600}.prompt-bar button.primary:hover{background:var(--brand-1);border-color:var(--brand-1)}.prompt-bar button.danger{border-color:var(--red);color:var(--red)}.prompt-bar button:disabled{opacity:.5;cursor:not-allowed}.tab-bar{display:flex;align-items:stretch;gap:0;border-bottom:1px solid var(--border);padding:0 16px;height:var(--topbar-height);flex-shrink:0}.tab-btn{display:flex;align-items:center;padding:0 16px;border:none;background:none;color:var(--text-subtle);font-size:13px;font-family:var(--font-mono);cursor:pointer;border-bottom:2px solid transparent;transition:color .15s,border-color .15s;margin-bottom:-1px}.tab-btn:hover{color:var(--text-muted)}.tab-bar-toggle{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:6px 8px;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px}.tab-bar-toggle:hover{color:var(--text);background:var(--bg-hover)}.tab-btn.active{color:var(--brand-1);border-bottom-color:var(--brand-1)}.status-badge{display:inline-block;font-size:11px;padding:1px 8px;border-radius:10px;font-family:var(--font-mono);line-height:1.6}.status-badge-running{background:var(--cyan);color:var(--bg)}.status-badge-complete{background:var(--green);color:var(--bg)}.status-badge-error{background:var(--red);color:var(--bg)}.status-badge-cancelled{background:var(--text-subtle);color:var(--bg)}.settings-panel{margin:4px 0;padding:8px 0 8px 16px;border-left:2px solid var(--brand-2)}.settings-header{display:flex;align-items:center;gap:8px;margin-bottom:6px}.settings-title{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--brand-1)}.settings-status{font-family:var(--font-mono);font-size:11px;padding:1px 6px;border-radius:8px}.settings-status.active{color:var(--green);border:1px solid var(--green)}.settings-status.missing{color:var(--yellow);border:1px solid var(--yellow)}.settings-field label{display:block;font-family:var(--font-mono);font-size:12px;color:var(--text-muted);margin-bottom:4px}.settings-input-row{display:flex;gap:6px}.settings-key-type-select{padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-mono);font-size:12px;cursor:pointer;transition:border-color .15s,box-shadow .15s}.settings-key-type-select:hover{border-color:var(--text-subtle)}.settings-key-type-select:focus{outline:none;border-color:var(--brand-2);box-shadow:0 0 0 3px #998fe726}.settings-input-row input{flex:1;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-mono);font-size:13px;transition:border-color .15s,box-shadow .15s,background .15s}.settings-input-row input::placeholder{color:var(--text-subtle)}.settings-input-row input:hover{border-color:var(--text-subtle)}.settings-input-row input:focus{outline:none;border-color:var(--brand-2);box-shadow:0 0 0 3px #998fe726}.settings-input-row input:disabled{opacity:.5;cursor:not-allowed}.settings-input-row button{padding:8px 14px;border-radius:8px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text-muted);font-family:var(--font-mono);font-size:13px;cursor:pointer;transition:background .15s,border-color .15s,color .15s}.settings-input-row button:hover{background:var(--bg-hover);border-color:var(--text-subtle)}.settings-input-row button.primary{background:transparent;border-color:var(--brand-3);color:var(--brand-1);font-weight:600}.settings-input-row button.primary:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.settings-input-row button:disabled{opacity:.5;cursor:not-allowed}.settings-divider{border-top:1px solid var(--border);margin:16px 0 12px}.settings-section-label{font-family:var(--font-mono);font-size:11px;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px}.settings-error{font-family:var(--font-mono);font-size:12px;color:var(--red);margin-top:4px}.skeleton{background:linear-gradient(90deg,var(--bg-surface) 25%,var(--bg-hover) 50%,var(--bg-surface) 75%);background-size:200% 100%;animation:skeleton-shimmer 1.5s ease-in-out infinite;border-radius:4px}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-line{height:14px;margin-bottom:8px}.skeleton-block{height:60px;margin-bottom:8px}.session-avatar{width:32px;height:32px;margin:4px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;font-family:var(--font-mono);letter-spacing:.5px;border-radius:50%;background:var(--bg-hover);color:var(--text);box-shadow:0 0 0 2px transparent,0 0 0 4px transparent}.session-avatar-running{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--cyan)}.session-avatar-complete{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--green)}.session-avatar-error{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--red)}.session-avatar-cancelled{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--text-subtle)}.session-item-pending{opacity:.5;pointer-events:none}.session-avatar-pending{background:var(--border);color:transparent;animation:pulse-fade 1.5s ease-in-out infinite}@keyframes pulse-fade{0%,to{opacity:.4}50%{opacity:.8}}.new-project-avatar{background:transparent;outline:1.5px dashed var(--text-subtle);outline-offset:-1.5px;color:var(--text-subtle);font-size:16px;font-weight:400}.session-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer;transition:background .1s,gap .2s ease;margin-bottom:1px;height:48px;box-sizing:border-box;overflow:hidden}.session-item:hover,.session-item.active{background:var(--bg-hover)}.session-item-details{flex:1;min-width:0;overflow:hidden;opacity:1;transition:opacity .15s ease,width .2s ease}.session-item-name{font-size:13px;font-weight:500;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-item-meta{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text-subtle)}.session-item-delete{opacity:1;padding:4px 6px;border:none;background:none;color:var(--text-subtle);font-size:18px;cursor:pointer;border-radius:4px;line-height:1;flex-shrink:0;overflow:hidden;transition:color .1s,background .1s}.session-item-delete:hover{color:var(--text-muted);background:var(--bg-hover)}.modal-overlay{position:fixed;inset:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.modal-card{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:24px;max-width:480px;width:90%}.modal-title{font-size:16px;font-weight:600;color:var(--text);margin-bottom:8px}.modal-body{font-size:14px;color:var(--text-muted);line-height:1.6;margin-bottom:20px}.modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.modal-btn{padding:8px 18px;border-radius:8px;border:1px solid var(--border);background:var(--bg-hover);color:var(--text);font-size:13px;font-family:var(--font-sans);cursor:pointer;transition:background .15s,border-color .15s}.modal-btn:hover{background:var(--border);border-color:var(--text-subtle)}.modal-btn-danger{background:var(--red);border-color:var(--red);color:#fff;font-weight:600}.modal-btn-danger:hover{background:#d63a33;border-color:#d63a33}.toast-container{font-family:var(--font-mono);font-size:13px}.git-status-badge{display:inline-flex;align-items:center;gap:4px;font-family:var(--font-mono);font-size:11px;padding:2px 8px;border-radius:10px;border:1px solid var(--border);color:var(--text-subtle);cursor:default}.git-status-badge:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}.repo-picker-filter{margin-top:12px}.repo-picker-filter input{width:100%;box-sizing:border-box;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-mono);font-size:13px;transition:border-color .15s,box-shadow .15s}.repo-picker-filter input:hover{border-color:var(--text-subtle)}.repo-picker-filter input:focus{outline:none;border-color:var(--brand-2);box-shadow:0 0 0 3px #998fe726}.repo-picker-filter input::placeholder{color:var(--text-subtle)}.repo-picker-list{max-height:300px;overflow-y:auto;margin-top:12px;border:1px solid var(--border);border-radius:6px}.repo-picker-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;font-size:13px;font-family:var(--font-mono);cursor:pointer;border-bottom:1px solid var(--border);transition:background .1s}.repo-picker-item:last-child{border-bottom:none}.repo-picker-item:hover{background:var(--bg-hover);color:var(--text)}.repo-picker-item-name{color:var(--text-muted)}.repo-picker-item-date{font-size:11px;color:var(--text-subtle)}.repo-picker-new-branch{display:flex;gap:8px;padding:8px 12px;align-items:center}.repo-picker-new-branch input{flex:1;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-mono);font-size:13px;transition:border-color .15s,box-shadow .15s}.repo-picker-new-branch input:hover{border-color:var(--text-subtle)}.repo-picker-new-branch input:focus{outline:none;border-color:var(--brand-2);box-shadow:0 0 0 3px #998fe726}.repo-picker-new-branch input::placeholder{color:var(--text-subtle)}.hero-resume-btn{margin-top:12px;padding:8px 20px;border-radius:6px;border:1px solid var(--border);background:transparent;color:var(--text-muted);font-size:13px;cursor:pointer;transition:background .15s,color .15s}.hero-resume-btn:hover{background:var(--bg-hover);color:var(--text)}.hero-resume-btn:disabled{opacity:.5;cursor:not-allowed}.modal-btn-primary{background:var(--brand-3);border-color:var(--brand-3);color:#fff}.modal-btn-primary:hover{background:var(--brand-2)}.modal-btn-primary:disabled{opacity:.5;cursor:not-allowed}.font-size-options{display:flex;gap:6px}.font-size-option{flex:1;padding:10px 12px;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);font-family:var(--font-sans);font-size:13px;cursor:pointer;transition:background .15s,border-color .15s,color .15s}.font-size-option:hover{background:var(--bg-hover);border-color:var(--text-subtle);color:var(--text)}.font-size-option.active{border-color:var(--brand-3);color:var(--brand-1);background:#7e78db1a}.link-session-list{max-height:300px;overflow-y:auto;border:1px solid var(--border);border-radius:6px;margin-top:12px}.link-session-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;font-size:13px;font-family:var(--font-mono);cursor:pointer;border-bottom:1px solid var(--border);transition:background .1s;border:none;background:transparent;width:100%;text-align:left;color:var(--text-muted)}.link-session-item:last-child{border-bottom:none}.link-session-item:hover{background:var(--bg-hover);color:var(--text)}@media(max-width:768px){.app-shell{grid-template-columns:1fr}.sidebar{position:fixed;top:0;left:0;bottom:0;width:280px;z-index:200;transform:translate(-100%);transition:transform .25s ease}.sidebar.mobile-open{transform:translate(0)}.sidebar-backdrop{display:block;position:fixed;inset:0;background:#00000080;z-index:199}.sidebar-collapse{display:none}.app-shell.sidebar-collapsed .sidebar-brand,.app-shell.sidebar-collapsed .sidebar-section-label{display:block}.app-shell.sidebar-collapsed .session-item{gap:8px}.app-shell.sidebar-collapsed .session-item-details,.app-shell.sidebar-collapsed .session-item-delete,.app-shell.sidebar-collapsed .session-item:hover .session-item-delete{opacity:1;width:auto;overflow:visible;pointer-events:auto}.app-shell.sidebar-collapsed .sidebar-collapse-label{opacity:1;max-width:120px;display:inline}.mobile-hamburger{display:flex;align-items:center;justify-content:center;width:42px;height:42px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:6px;flex-shrink:0;-webkit-tap-highlight-color:transparent}.mobile-hamburger:hover{color:var(--text);background:var(--bg-hover)}.session-header{padding:0 8px;gap:6px}.session-header-name{font-size:14px;min-width:0;flex:1}.session-header .session-header-cost,.session-header .session-header-actions-group{display:none}.session-header-overflow{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:6px;flex-shrink:0;-webkit-tap-highlight-color:transparent}.session-header-overflow:hover{color:var(--text);background:var(--bg-hover)}.session-header-overflow-menu{position:absolute;top:calc(var(--topbar-height) - 4px);right:8px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:6px;z-index:100;min-width:180px;box-shadow:0 8px 24px #0006}.session-header-overflow-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:none;color:var(--text-muted);font-size:14px;font-family:var(--font-mono);cursor:pointer;border-radius:6px;text-decoration:none;-webkit-tap-highlight-color:transparent}.session-header-overflow-menu-item:hover{background:var(--bg-hover);color:var(--text)}.mobile-preview-bar{display:flex;align-items:center;justify-content:center;padding:8px 12px;padding-top:calc(var(--topbar-height) + 8px);background:var(--bg-surface);border-bottom:1px solid var(--border);flex-shrink:0}.mobile-preview-link{display:inline-flex;align-items:center;gap:6px;padding:10px 20px;font-size:14px;font-family:var(--font-mono);color:var(--brand-1);background:transparent;border:1px solid var(--brand-3);border-radius:8px;text-decoration:none;-webkit-tap-highlight-color:transparent;transition:color .15s,background .15s,border-color .15s}.mobile-preview-link:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.console{padding:calc(var(--topbar-height) + 8px) 8px 8px;overflow-x:hidden}.mobile-preview-bar~.console{padding-top:8px}.session-content{overflow-x:hidden;touch-action:pan-y pinch-zoom}.session-loading{padding:calc(var(--topbar-height) + 8px) 8px 8px}.tool-inline-summary,.thinking-preview{max-width:200px}.tool-inline-command{max-width:200px;overflow:hidden;text-overflow:ellipsis}.tool-inline-body{padding:6px 0 6px 10px;margin-left:4px}.tool-inline-body pre{max-height:250px}.prompt-bar{padding:6px 8px;gap:6px;height:auto;min-height:var(--footer-height)}.prompt-bar textarea{padding:10px 12px;min-height:42px;font-size:16px}.prompt-bar button{padding:8px 14px;min-height:40px;font-size:14px}.mobile-home-topbar{display:flex;align-items:center;padding:6px 10px;height:52px;flex-shrink:0;border-bottom:1px solid rgba(58,58,68,.5);gap:8px;background:#1b1b1fcc;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);position:relative;z-index:10}.mobile-topbar-logo{height:26px}.hero{padding:0 16px;justify-content:flex-start;padding-top:8vh}.hero-logo{height:48px;margin-bottom:12px}.hero-subtitle{font-size:15px;margin-bottom:24px;white-space:nowrap}.hero-prompt{max-width:100%}.hero-prompt .prompt-bar{border-radius:12px}.hero-prompt .prompt-bar textarea{min-height:48px;font-size:16px;padding:12px}.hero-prompt .prompt-bar button{min-height:48px;padding:8px 18px;font-size:15px;border-radius:0 11px 11px 0}.hero-resume-btn{width:100%;padding:12px 20px;font-size:15px}.gate-prompt{padding:12px}.gate-prompt .question input,.gate-prompt .question textarea,.gate-prompt .question select{font-size:15px;padding:10px 12px}.gate-actions{flex-direction:column}.gate-actions .gate-btn{width:100%;padding:10px 16px;text-align:center}.gate-plan-actions{flex-wrap:wrap}.gate-plan-actions .gate-btn{flex:1;min-width:0;padding:10px 12px;text-align:center}.gate-btn kbd{display:none}.gate-continue{flex-wrap:wrap;gap:8px;padding:10px 12px}.gate-continue-text{width:100%;flex:none}.gate-continue .gate-btn{flex:1;text-align:center;padding:8px 12px}.gate-option-group{flex-direction:column}.gate-option{padding:12px}.modal-overlay{z-index:300}.modal-card{width:95%;max-width:none;max-height:90vh;overflow-y:auto;border-radius:14px}.modal-actions{flex-direction:column-reverse}.modal-actions .modal-btn{width:100%;text-align:center;padding:10px 16px}.settings-input-row{flex-direction:column;gap:8px}.settings-input-row input{font-size:15px;padding:10px 12px}.settings-input-row button{width:100%;padding:8px 12px;text-align:center}.repo-picker-item{padding:14px;min-height:48px}.repo-picker-new-branch{flex-direction:column}.repo-picker-new-branch input{font-size:14px;padding:10px 12px}.global-settings-btn{top:8px;right:8px;width:40px;height:40px}.global-settings-btn svg{width:20px;height:20px}.jump-to-bottom{padding:10px 20px;font-size:13px}.action-item-summary{max-width:150px}.action-item-detail{padding:8px 12px 8px 24px}.markdown pre{padding:10px 12px;font-size:12px}.markdown table{display:block;overflow-x:auto}}@media(min-width:769px){.mobile-hamburger,.mobile-home-topbar,.sidebar-backdrop,.session-header-overflow,.session-header-overflow-menu,.mobile-preview-bar,.mobile-topbar-logo{display:none}}
@@ -7,8 +7,8 @@
7
7
  <link rel="icon" type="image/svg+xml" href="/img/brand/favicon.svg" />
8
8
  <link rel="icon" type="image/png" href="/img/brand/favicon.png" />
9
9
  <link rel="shortcut icon" href="/favicon.ico" />
10
- <script type="module" crossorigin src="/assets/index-DDzmxYub.js"></script>
11
- <link rel="stylesheet" crossorigin href="/assets/index-DcP7prsZ.css">
10
+ <script type="module" crossorigin src="/assets/index-D5-jqAV-.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-YyyiO26y.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAarD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKtE,OAAO,EAGN,KAAK,YAAY,EAEjB,MAAM,cAAc,CAAA;AAErB,KAAK,UAAU,GAAG,aAAa,CAAA;AAE/B,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,QAAQ,EAAE,cAAc,CAAA;IACxB,yDAAyD;IACzD,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,eAAe,CAAA;IACxB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAA;IAC1B,yCAAyC;IACzC,UAAU,EAAE,UAAU,CAAA;CACtB;AAmQD,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,8EA2/D7C;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,eAAe,CAAA;IACxB,YAAY,EAAE,YAAY,CAAA;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAA;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAarD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKtE,OAAO,EAGN,KAAK,YAAY,EAEjB,MAAM,cAAc,CAAA;AAErB,KAAK,UAAU,GAAG,aAAa,CAAA;AAE/B,UAAU,YAAY;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,QAAQ,EAAE,cAAc,CAAA;IACxB,yDAAyD;IACzD,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,eAAe,CAAA;IACxB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAA;IAC1B,yCAAyC;IACzC,UAAU,EAAE,UAAU,CAAA;CACtB;AA2SD,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,8EA6jE7C;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,YAAY,CAAA;IACnB,OAAO,EAAE,eAAe,CAAA;IACxB,YAAY,EAAE,YAAY,CAAA;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAA;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhB"}
package/dist/server.js CHANGED
@@ -22,6 +22,8 @@ import { generateInviteCode } from "./shared-sessions.js";
22
22
  import { getSharedStreamConnectionInfo, getStreamConnectionInfo, } from "./streams.js";
23
23
  /** Active session bridges — one per running session */
24
24
  const bridges = new Map();
25
+ /** In-memory room presence: roomId → participantId → { displayName, lastPing } */
26
+ const roomPresence = new Map();
25
27
  /** Inflight hook session creations — prevents duplicate sessions from concurrent hooks */
26
28
  const inflightHookCreations = new Map();
27
29
  function parseRepoNameFromUrl(url) {
@@ -64,6 +66,30 @@ function resolveStudioUrl(port) {
64
66
  // Fallback — won't work from sprites VMs, but at least logs a useful URL
65
67
  return `http://localhost:${port}`;
66
68
  }
69
+ /**
70
+ * Accumulate cost and turn metrics from a session_end event into the session's totals.
71
+ * Called each time a Claude Code run finishes (initial + iterate runs).
72
+ */
73
+ function accumulateSessionCost(config, sessionId, event) {
74
+ if (event.type !== "session_end")
75
+ return;
76
+ const { cost_usd, num_turns, duration_ms } = event;
77
+ if (cost_usd == null && num_turns == null && duration_ms == null)
78
+ return;
79
+ const existing = config.sessions.get(sessionId);
80
+ const updates = {};
81
+ if (cost_usd != null) {
82
+ updates.totalCostUsd = (existing?.totalCostUsd ?? 0) + cost_usd;
83
+ }
84
+ if (num_turns != null) {
85
+ updates.totalTurns = (existing?.totalTurns ?? 0) + num_turns;
86
+ }
87
+ if (duration_ms != null) {
88
+ updates.totalDurationMs = (existing?.totalDurationMs ?? 0) + duration_ms;
89
+ }
90
+ config.sessions.update(sessionId, updates);
91
+ console.log(`[session:${sessionId}] Cost: $${updates.totalCostUsd?.toFixed(4) ?? "?"} (${updates.totalTurns ?? "?"} turns)`);
92
+ }
67
93
  /**
68
94
  * Create a Claude Code bridge for a session.
69
95
  * Spawns `claude` CLI with stream-json I/O inside the sandbox.
@@ -198,12 +224,26 @@ function mapHookToEngineEvent(body) {
198
224
  text: body.last_assistant_message || "",
199
225
  ts: now,
200
226
  };
201
- case "SessionEnd":
202
- return {
227
+ case "SessionEnd": {
228
+ const endEvent = {
203
229
  type: "session_end",
204
230
  success: true,
205
231
  ts: now,
206
232
  };
233
+ // Claude Code SessionEnd hook may include session stats
234
+ const session = body.session;
235
+ if (session) {
236
+ if (typeof session.cost_usd === "number")
237
+ endEvent.cost_usd = session.cost_usd;
238
+ if (typeof session.num_turns === "number")
239
+ endEvent.num_turns = session.num_turns;
240
+ if (typeof session.duration_ms === "number")
241
+ endEvent.duration_ms = session.duration_ms;
242
+ if (typeof session.duration_api_ms === "number")
243
+ endEvent.duration_api_ms = session.duration_api_ms;
244
+ }
245
+ return endEvent;
246
+ }
207
247
  case "UserPromptSubmit":
208
248
  return {
209
249
  type: "user_prompt",
@@ -421,6 +461,7 @@ export function createApp(config) {
421
461
  config.sessions.update(sessionId, {});
422
462
  // SessionEnd: mark session complete and close the bridge
423
463
  if (hookEvent.type === "session_end") {
464
+ accumulateSessionCost(config, sessionId, hookEvent);
424
465
  if (!isClaudeCodeBridge) {
425
466
  config.sessions.update(sessionId, { status: "complete" });
426
467
  closeBridge(sessionId);
@@ -553,6 +594,7 @@ export function createApp(config) {
553
594
  config.sessions.update(sessionId, {});
554
595
  // SessionEnd: mark complete and close bridge (keep mapping for potential re-open)
555
596
  if (hookEvent.type === "session_end") {
597
+ accumulateSessionCost(config, sessionId, hookEvent);
556
598
  config.sessions.update(sessionId, { status: "complete" });
557
599
  closeBridge(sessionId);
558
600
  return c.json({ ok: true, sessionId });
@@ -857,6 +899,15 @@ echo "Start claude in this project — the session will appear in the studio UI.
857
899
  projectName,
858
900
  projectDir: handle.projectDir,
859
901
  runtime: config.sandbox.runtime,
902
+ ...(repoConfig
903
+ ? {
904
+ git: {
905
+ mode: "create",
906
+ repoName: `${repoConfig.account}/${repoConfig.repoName}`,
907
+ visibility: repoConfig.visibility,
908
+ },
909
+ }
910
+ : {}),
860
911
  });
861
912
  try {
862
913
  await config.sandbox.exec(handle, `cat > '${handle.projectDir}/CLAUDE.md' << 'CLAUDEMD_EOF'\n${claudeMd}\nCLAUDEMD_EOF`);
@@ -900,7 +951,7 @@ echo "Start claude in this project — the session will appear in the studio UI.
900
951
  });
901
952
  }
902
953
  // 5. Start listening for agent events via the bridge
903
- // Track Claude Code session ID for --resume on iterate
954
+ // Track Claude Code session ID and cost from agent events
904
955
  bridge.onAgentEvent((event) => {
905
956
  if (event.type === "session_start") {
906
957
  const ccSessionId = event.session_id;
@@ -909,6 +960,9 @@ echo "Start claude in this project — the session will appear in the studio UI.
909
960
  config.sessions.update(sessionId, { lastCoderSessionId: ccSessionId });
910
961
  }
911
962
  }
963
+ if (event.type === "session_end") {
964
+ accumulateSessionCost(config, sessionId, event);
965
+ }
912
966
  });
913
967
  bridge.onComplete(async (success) => {
914
968
  const updates = {
@@ -964,17 +1018,12 @@ echo "Start claude in this project — the session will appear in the studio UI.
964
1018
  await bridge.start();
965
1019
  console.log(`[session:${sessionId}] Bridge started, sending 'new' command...`);
966
1020
  // 5. Send the new command via the bridge
967
- const newCmd = {
1021
+ await bridge.sendCommand({
968
1022
  command: "new",
969
1023
  description: body.description,
970
1024
  projectName,
971
1025
  baseDir: "/home/agent/workspace",
972
- };
973
- if (repoConfig) {
974
- newCmd.gitRepoName = `${repoConfig.account}/${repoConfig.repoName}`;
975
- newCmd.gitRepoVisibility = repoConfig.visibility;
976
- }
977
- await bridge.sendCommand(newCmd);
1026
+ });
978
1027
  console.log(`[session:${sessionId}] Command sent, waiting for agent...`);
979
1028
  };
980
1029
  asyncFlow().catch(async (err) => {
@@ -1501,6 +1550,43 @@ echo "Start claude in this project — the session will appear in the studio UI.
1501
1550
  await stream.append(JSON.stringify(event));
1502
1551
  return c.json({ ok: true });
1503
1552
  });
1553
+ // Heartbeat ping for room presence (in-memory, not persisted to stream)
1554
+ app.post("/api/shared-sessions/:id/ping", async (c) => {
1555
+ const id = c.req.param("id");
1556
+ const body = (await c.req.json());
1557
+ if (!body.participantId) {
1558
+ return c.json({ error: "participantId is required" }, 400);
1559
+ }
1560
+ let room = roomPresence.get(id);
1561
+ if (!room) {
1562
+ room = new Map();
1563
+ roomPresence.set(id, room);
1564
+ }
1565
+ room.set(body.participantId, {
1566
+ displayName: body.displayName || body.participantId.slice(0, 8),
1567
+ lastPing: Date.now(),
1568
+ });
1569
+ return c.json({ ok: true });
1570
+ });
1571
+ // Get active participants (pinged within last 90 seconds)
1572
+ app.get("/api/shared-sessions/:id/presence", (c) => {
1573
+ const id = c.req.param("id");
1574
+ const room = roomPresence.get(id);
1575
+ const STALE_MS = 90_000;
1576
+ const now = Date.now();
1577
+ const active = [];
1578
+ if (room) {
1579
+ for (const [pid, info] of room) {
1580
+ if (now - info.lastPing < STALE_MS) {
1581
+ active.push({ id: pid, displayName: info.displayName });
1582
+ }
1583
+ else {
1584
+ room.delete(pid);
1585
+ }
1586
+ }
1587
+ }
1588
+ return c.json({ participants: active });
1589
+ });
1504
1590
  // Link a session to a shared session (room)
1505
1591
  // The client sends session metadata since sessions are private (localStorage).
1506
1592
  app.post("/api/shared-sessions/:id/sessions", async (c) => {
@@ -1526,6 +1612,12 @@ echo "Start claude in this project — the session will appear in the studio UI.
1526
1612
  await stream.append(JSON.stringify(event));
1527
1613
  return c.json({ ok: true });
1528
1614
  });
1615
+ // Get a session token for a linked session (allows room participants to read session streams)
1616
+ app.get("/api/shared-sessions/:id/sessions/:sessionId/token", (c) => {
1617
+ const sessionId = c.req.param("sessionId");
1618
+ const sessionToken = deriveSessionToken(config.streamConfig.secret, sessionId);
1619
+ return c.json({ sessionToken });
1620
+ });
1529
1621
  // Unlink a session from a shared session
1530
1622
  app.delete("/api/shared-sessions/:id/sessions/:sessionId", async (c) => {
1531
1623
  const id = c.req.param("id");
@@ -1877,6 +1969,11 @@ echo "Start claude in this project — the session will appear in the studio UI.
1877
1969
  projectName: repoName,
1878
1970
  projectDir: handle.projectDir,
1879
1971
  runtime: config.sandbox.runtime,
1972
+ git: {
1973
+ mode: "existing",
1974
+ repoName: parseRepoNameFromUrl(body.repoUrl) ?? repoName,
1975
+ branch: gs.branch ?? body.branch ?? "main",
1976
+ },
1880
1977
  });
1881
1978
  try {
1882
1979
  await config.sandbox.exec(handle, `cat > '${handle.projectDir}/CLAUDE.md' << 'CLAUDEMD_EOF'\n${claudeMd}\nCLAUDEMD_EOF`);
@@ -1918,6 +2015,9 @@ echo "Start claude in this project — the session will appear in the studio UI.
1918
2015
  config.sessions.update(sessionId, { lastCoderSessionId: ccSessionId });
1919
2016
  }
1920
2017
  }
2018
+ if (event.type === "session_end") {
2019
+ accumulateSessionCost(config, sessionId, event);
2020
+ }
1921
2021
  });
1922
2022
  ccBridge.onComplete(async (success) => {
1923
2023
  const updates = {