aicodeman 1.26.0 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/codex-transcript.d.ts +84 -0
- package/dist/codex-transcript.d.ts.map +1 -0
- package/dist/codex-transcript.js +341 -0
- package/dist/codex-transcript.js.map +1 -0
- package/dist/config/buffer-limits.d.ts +20 -0
- package/dist/config/buffer-limits.d.ts.map +1 -1
- package/dist/config/buffer-limits.js +42 -0
- package/dist/config/buffer-limits.js.map +1 -1
- package/dist/config/cli-registry/schema.d.ts +4 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +15 -1
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +12 -0
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +23 -0
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/mux-interface.d.ts +6 -1
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/services/unified-session-service.d.ts +28 -10
- package/dist/services/unified-session-service.d.ts.map +1 -1
- package/dist/services/unified-session-service.js +11 -6
- package/dist/services/unified-session-service.js.map +1 -1
- package/dist/session.d.ts +11 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +90 -41
- package/dist/session.js.map +1 -1
- package/dist/tmux-manager.d.ts +38 -5
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +91 -32
- package/dist/tmux-manager.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/{app.3a89ac57.js → app.c4dbfcfb.js} +2 -2
- package/dist/web/public/app.c4dbfcfb.js.br +0 -0
- package/dist/web/public/{app.3a89ac57.js.gz → app.c4dbfcfb.js.gz} +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.7a635e34.js → constants.e6d48776.js} +16 -0
- package/dist/web/public/constants.e6d48776.js.br +0 -0
- package/dist/web/public/constants.e6d48776.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js +9 -1
- package/dist/web/public/entrance-animations.js.br +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
- package/dist/web/public/{image-input.ee16ad88.js → image-input.cd4b97c4.js} +13 -2
- package/dist/web/public/image-input.cd4b97c4.js.br +0 -0
- package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
- package/dist/web/public/index.html +12 -11
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.daf18302.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.0f83a608.js → mobile-handlers.2e9c214a.js} +7 -0
- package/dist/web/public/mobile-handlers.2e9c214a.js.br +0 -0
- package/dist/web/public/mobile-handlers.2e9c214a.js.gz +0 -0
- package/dist/web/public/mobile-overview.js +12 -1
- package/dist/web/public/mobile-overview.js.br +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.65176832.css +1 -0
- package/dist/web/public/mobile.65176832.css.br +0 -0
- package/dist/web/public/mobile.65176832.css.gz +0 -0
- package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.db4785bf.js → panels-ui.9eb5b235.js} +1 -1
- package/dist/web/public/panels-ui.9eb5b235.js.br +0 -0
- package/dist/web/public/panels-ui.9eb5b235.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.a9c126c6.js → session-ui.cd222710.js} +1 -1
- package/dist/web/public/session-ui.cd222710.js.br +0 -0
- package/dist/web/public/session-ui.cd222710.js.gz +0 -0
- package/dist/web/public/settings-ui.554f9cdd.js.gz +0 -0
- package/dist/web/public/styles.89069bbc.css +1 -0
- package/dist/web/public/styles.89069bbc.css.br +0 -0
- package/dist/web/public/styles.89069bbc.css.gz +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
- package/dist/web/public/terminal-ui.1547ce5e.js +2 -0
- package/dist/web/public/terminal-ui.1547ce5e.js.br +0 -0
- package/dist/web/public/terminal-ui.1547ce5e.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +16 -26
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +78 -4
- package/dist/web/routes/session-routes.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/app.3a89ac57.js.br +0 -0
- package/dist/web/public/constants.7a635e34.js.br +0 -0
- package/dist/web/public/constants.7a635e34.js.gz +0 -0
- package/dist/web/public/image-input.ee16ad88.js.br +0 -0
- package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
- package/dist/web/public/mobile-handlers.0f83a608.js.br +0 -0
- package/dist/web/public/mobile-handlers.0f83a608.js.gz +0 -0
- package/dist/web/public/mobile.7112f27d.css +0 -1
- package/dist/web/public/mobile.7112f27d.css.br +0 -0
- package/dist/web/public/mobile.7112f27d.css.gz +0 -0
- package/dist/web/public/panels-ui.db4785bf.js.br +0 -0
- package/dist/web/public/panels-ui.db4785bf.js.gz +0 -0
- package/dist/web/public/session-ui.a9c126c6.js.br +0 -0
- package/dist/web/public/session-ui.a9c126c6.js.gz +0 -0
- package/dist/web/public/styles.298f81f2.css +0 -1
- package/dist/web/public/styles.298f81f2.css.br +0 -0
- package/dist/web/public/styles.298f81f2.css.gz +0 -0
- package/dist/web/public/terminal-ui.70445f81.js +0 -2
- package/dist/web/public/terminal-ui.70445f81.js.br +0 -0
- package/dist/web/public/terminal-ui.70445f81.js.gz +0 -0
|
@@ -228,6 +228,11 @@ Object.assign(CodemanApp.prototype, {
|
|
|
228
228
|
name: item.name || '',
|
|
229
229
|
title: title || item.name || dir.split('/').pop() || item.sessionId.slice(0, 8),
|
|
230
230
|
mode: item.mode || 'claude',
|
|
231
|
+
// Only the scanner sets this, and only for a codex rollout. Dropping it here
|
|
232
|
+
// is not cosmetic: resumeMobileOverviewSession() passes row.resumeId on to
|
|
233
|
+
// resumeHistorySession(), so without it a tapped Codex row starts a FRESH
|
|
234
|
+
// session on a thread that is already on disk.
|
|
235
|
+
resumeId: item.resumeId || undefined,
|
|
231
236
|
caseName: matched ? matched.name : '',
|
|
232
237
|
dir: this._shortenHomePath ? this._shortenHomePath(dir) : dir,
|
|
233
238
|
at: item.lastActivityAt || item.createdAt || 0,
|
|
@@ -389,7 +394,13 @@ Object.assign(CodemanApp.prototype, {
|
|
|
389
394
|
async resumeMobileOverviewSession(sessionId) {
|
|
390
395
|
const row = (this._mobileOverviewPastRows || []).find((r) => r.id === sessionId);
|
|
391
396
|
if (!row || !row.workingDir) return;
|
|
392
|
-
await this.resumeHistorySession(
|
|
397
|
+
await this.resumeHistorySession(
|
|
398
|
+
row.claudeSessionId || row.id,
|
|
399
|
+
row.workingDir,
|
|
400
|
+
row.name || undefined,
|
|
401
|
+
row.mode,
|
|
402
|
+
row.resumeId
|
|
403
|
+
);
|
|
393
404
|
},
|
|
394
405
|
|
|
395
406
|
// ═══════════════════════════════════════════════════════════════
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
html.mobile-init .header-font-controls,html.mobile-init .header-system-stats,html.mobile-init .header-tokens,html.mobile-init .monitor-panel,html.mobile-init .subagents-panel,html.mobile-init .project-insights-panel,html.mobile-init .file-browser-panel{display:none!important}@media(max-width:768px){input,textarea,select{font-size:16px!important}html{touch-action:manipulation}.session-tab .tab-detach{display:none!important}}@media(max-width:768px)and (min-width:430px){.header{position:fixed;top:0;left:0;right:0;min-height:48px;max-height:48px;padding:.35rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));background:#0a0a0a;border-bottom:1px solid rgba(255,255,255,.08);contain:none;overflow:visible;z-index:1200}.ios-device .header{padding-top:calc(.35rem + var(--safe-area-top));min-height:calc(48px + var(--safe-area-top));max-height:calc(48px + var(--safe-area-top))}.app{padding-top:54px}.ios-device .app{padding-top:calc(54px + var(--safe-area-top))}.header-font-controls{gap:.15rem;padding:.15rem .25rem}.header-font-controls .btn-icon-sm{width:18px;height:18px}.header-system-stats{font-size:.6rem;gap:.25rem}.header-right{gap:.35rem}.btn-icon-header:not(.btn-sm){width:44px;height:44px}.session-tabs,.session-tabs.tabs-two-rows{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:none;max-height:52px;gap:3px}.session-tabs::-webkit-scrollbar{display:none}.session-tab{padding:.4rem .6rem;font-size:.75rem;min-height:40px}.session-tab .tab-name{max-width:80px}.toolbar{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));gap:.4rem}.tab-count-group{display:none}.btn-toolbar{padding:.4rem .8rem;font-size:.8rem;min-height:40px}.case-select-group{max-width:none}.case-combobox{width:160px}.toolbar-select{font-size:.75rem}.monitor-panel,.subagents-panel{width:100%;max-width:100%;left:0;right:0;border-radius:8px 8px 0 0;max-height:40vh}.project-insights-panel{max-width:280px;font-size:.7rem}.modal{z-index:1300}.command-palette-modal{padding:10vh .75rem 0}.command-palette-shell{width:100%;max-height:74vh}.command-palette-input-row{grid-template-columns:20px minmax(0,1fr)}.command-palette-input-row kbd{display:none}.command-palette-item{min-height:56px}.settings-grid{gap:.4rem .75rem}.settings-item{font-size:.7rem}.event-type-grid{grid-template-columns:1fr 40px 40px 40px;gap:5px 6px}.event-label{font-size:.7rem}.subagent-window{width:320px;height:280px;min-width:240px;min-height:160px}.subagent-window-header{padding:.35rem .5rem}.subagent-window-title .id{font-size:.7rem;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.subagent-window-title .status{font-size:.55rem}.subagent-window-body{font-size:.7rem}.respawn-banner{padding:.25rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.65rem}.respawn-compact-layout{gap:.75rem}.respawn-status-row1{gap:.4rem}.respawn-action-log{max-height:2.6em;font-size:.6rem}.respawn-countdown-timer{font-size:.55rem}.respawn-timer-bar{width:24px}.toolbar-center .btn-toolbar.btn-voice{display:flex!important}.toolbar{padding:0 .5rem;gap:.5rem}.toolbar-left,.toolbar-right,.toolbar-group{gap:.5rem}.btn-toolbar{padding:.4rem .75rem;font-size:.75rem;min-height:unset}}@media(max-width:430px){:root{--header-height: 44px}.header-brand{padding-right:0;margin-right:.1rem;border-right:none}.header-brand .logo{display:inline-flex;align-items:center;justify-content:center;min-width:44px;height:var(--header-height);margin-left:-.3rem;font-size:1.15rem;line-height:1;border-radius:8px;-webkit-tap-highlight-color:transparent}.header-brand .logo:active{background:#60a5fa29}.header-brand .logo .logo-text{display:none}.header-brand .logo .logo-compact{display:inline}.header-font-controls{gap:.1rem;padding:.1rem .2rem}.header-font-controls .btn-icon-sm{width:16px;height:16px}.header-font-controls .font-size-display{font-size:.6rem;min-width:14px}.header-system-stats{font-size:.55rem;gap:.15rem}.header-tokens{font-size:.6rem;padding:.1rem .3rem}.header{position:fixed;top:0;left:0;right:0;min-height:var(--header-height);max-height:var(--header-height);align-items:center;padding:.15rem .3rem;padding-left:calc(.3rem + var(--safe-area-left));padding-right:calc(.3rem + var(--safe-area-right));gap:.15rem;overflow:hidden;background:#0a0a0a;border-bottom:1px solid rgba(255,255,255,.08);contain:none;z-index:1200}.ios-device .header{padding-top:calc(.15rem + var(--safe-area-top));min-height:calc(var(--header-height) + var(--safe-area-top));max-height:calc(var(--header-height) + var(--safe-area-top))}.app{padding-top:calc(var(--header-height) + 6px)}.ios-device .app{padding-top:calc(var(--header-height) + 6px + var(--safe-area-top))}.main{padding-bottom:calc(40px + var(--safe-area-bottom))}.ios-device.safari-browser .main{padding-bottom:calc(40px + var(--safe-area-bottom) + var(--chrome-overlap, 0px))}.header-right{padding-left:.2rem;gap:.1rem;flex-shrink:0;border-left:none}.btn-icon-header{width:26px;height:26px;padding:0}.btn-icon-header svg{width:12px;height:12px}html[data-session-list=sidebar] #sidebarToggleBtn{width:44px;height:44px}html[data-session-list=sidebar] #sidebarToggleBtn svg{width:18px;height:18px}.btn-icon-header.btn-settings,.btn-icon-header.btn-lifecycle-log,.btn-icon-header.btn-away-digest,.btn-icon-header.btn-session-manager,.btn-icon-header.btn-file-viewer,.btn-icon-header.btn-approvals,.btn-icon-header.btn-readmymind,.btn-admin-panel{display:none!important}.btn-voice-mobile{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;background:#1a2a3f;border:1px solid rgba(59,130,246,.3);border-radius:4px;color:#93c5fd;cursor:pointer;flex-shrink:0;order:5}.btn-voice-mobile svg{width:13px;height:13px}.btn-voice-mobile:active{background:#2a3a5f}.btn-voice-mobile.recording{background:#ef444440;border-color:#ef444499;color:#ef4444;animation:mobile-voice-pulse 1.2s ease-in-out infinite}@keyframes mobile-voice-pulse{0%,to{box-shadow:inset 0 0 0 1px #ef444459;background:#ef444433}50%{box-shadow:inset 0 0 0 2px #ef4444bf;background:#ef444459}}.btn-settings-mobile{display:inline-flex!important;align-items:center;justify-content:center;width:26px;height:26px;background:transparent;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#9ca3af;font-size:.85rem;cursor:pointer;flex-shrink:0;order:6;position:relative}.btn-settings-mobile svg{width:13px;height:13px}.btn-settings-mobile:active{background:#ffffff1a;color:#fff}.app{overflow:hidden;position:relative}.keyboard-visible .app{position:fixed;inset:0 0 auto;height:var(--app-height, 100dvh)}.session-tabs,.session-tabs.tabs-two-rows{flex:1;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:none;max-height:36px;gap:2px;padding:0}.session-tabs::-webkit-scrollbar{display:none}.session-tab{flex-shrink:0;min-height:32px;max-height:32px;padding:.35rem .5rem;font-size:.7rem;gap:.25rem;border-radius:4px}.session-tab .tab-status{width:4px;height:4px}.session-tab .tab-status.busy{width:9px;height:9px;box-shadow:0 0 8px 2px color-mix(in srgb,var(--green) 55%,transparent)!important}.session-tab .tab-status.busy:after{display:none}.session-tab .tab-name{max-width:50px;overflow:hidden;text-overflow:ellipsis}.session-tab.active .tab-name{min-width:44px}.session-tab .tab-close,.session-tab .tab-gear{display:none}.session-tab.active .tab-gear{display:inline-flex;align-items:center;justify-content:center;font-size:.65rem;line-height:1;width:32px;height:32px;margin-left:auto;opacity:.6}.session-tab.active .tab-close{display:inline-flex;align-items:center;justify-content:center;font-size:1.1rem;line-height:1;width:20px;height:18px;margin-left:-2px}.toolbar{position:fixed;bottom:var(--safe-area-bottom);left:0;right:0;height:40px;min-height:40px;max-height:40px;padding:.3rem .4rem;padding-left:calc(.4rem + var(--safe-area-left));padding-right:calc(.4rem + var(--safe-area-right));flex-wrap:nowrap;gap:.3rem;align-items:center;justify-content:space-between;background:#111;border-top:1px solid rgba(255,255,255,.1);z-index:50;transition:transform .15s ease-out;will-change:transform}.ios-device.safari-browser .toolbar{bottom:calc(var(--safe-area-bottom) + var(--chrome-overlap, 0px))}.keyboard-visible.ios-device.safari-browser .toolbar{bottom:var(--safe-area-bottom)}.keyboard-visible.ios-device.safari-browser .keyboard-accessory-bar{bottom:calc(var(--safe-area-bottom) + 40px)}.toolbar-center{display:flex!important;align-items:center}.toolbar-center .btn-toolbar.btn-voice,.toolbar-right,.version-display{display:none!important}.toolbar-left{flex:1 1 0;min-width:0;align-items:center;gap:.3rem}.toolbar-left .toolbar-group{display:flex;flex:1 1 0;min-width:0;align-items:center;gap:.3rem}.toolbar-left .toolbar-group:first-child{flex:1 1 0;min-width:0;justify-content:space-between;gap:.3rem;flex-wrap:nowrap;align-items:center}.tab-count-group{display:none!important}.btn-toolbar{min-height:26px!important;max-height:26px!important;height:26px!important;padding:0 .5rem!important;font-size:.65rem!important;border-radius:4px;line-height:26px;display:inline-flex;align-items:center;justify-content:center;font-weight:500;letter-spacing:.01em;color:#fff}.run-btn-group{display:flex;flex:0 0 auto}.btn-toolbar.btn-run{flex:0 0 auto;padding:0 .6rem!important;font-weight:500;border-radius:4px 0 0 4px!important;border-right:none!important}.btn-toolbar.btn-run svg{width:10px;height:10px;margin-right:3px}.btn-toolbar.btn-run-gear{flex:0 0 auto;padding:0 .35rem!important;min-width:unset!important;border-radius:0 4px 4px 0!important;border-left:1px solid rgba(255,255,255,.15)!important}.btn-toolbar.btn-run-gear svg{width:10px;height:10px}.btn-toolbar.btn-run.mode-claude,.btn-toolbar.btn-run-gear.mode-claude{background:#1e3a5f;border-color:#3b82f64d;color:#93c5fd}.btn-toolbar.btn-run.mode-claude:active,.btn-toolbar.btn-run-gear.mode-claude:active{background:#2563eb;border-color:#3b82f680}.btn-toolbar.btn-run.mode-opencode,.btn-toolbar.btn-run-gear.mode-opencode{background:#0a2e2a;border-color:#10b9814d;color:#6ee7b7}.btn-toolbar.btn-run.mode-opencode:active,.btn-toolbar.btn-run-gear.mode-opencode:active{background:#0d4a40;border-color:#10b98180}.btn-toolbar.btn-run.mode-gemini,.btn-toolbar.btn-run-gear.mode-gemini{background:#10243f;border-color:#60a5fa4d;color:#dbeafe}.btn-toolbar.btn-run.mode-gemini:active,.btn-toolbar.btn-run-gear.mode-gemini:active{background:#174ea6;border-color:#60a5fa80}.btn-toolbar.btn-run.mode-antigravity,.btn-toolbar.btn-run-gear.mode-antigravity{background:#0b2b33;border-color:#22d3ee4d;color:#cffafe}.btn-toolbar.btn-run.mode-antigravity:active,.btn-toolbar.btn-run-gear.mode-antigravity:active{background:#0e7490;border-color:#22d3ee80}.btn-toolbar.btn-run.mode-pi,.btn-toolbar.btn-run-gear.mode-pi{background:#33121f!important;border-color:#f472b64d!important;color:#fce7f3!important}.btn-toolbar.btn-run.mode-pi:active,.btn-toolbar.btn-run-gear.mode-pi:active{background:#9d174d!important;border-color:#f472b680!important}.btn-toolbar.btn-run.mode-grok,.btn-toolbar.btn-run-gear.mode-grok{background:#1c1c1f!important;border-color:#d4d4d84d!important;color:#f4f4f5!important}.btn-toolbar.btn-run.mode-grok:active,.btn-toolbar.btn-run-gear.mode-grok:active{background:#3f3f46!important;border-color:#d4d4d880!important}.btn-toolbar.btn-run.mode-deepseek,.btn-toolbar.btn-run-gear.mode-deepseek{background:#16225f!important;border-color:#7c93ff59!important;color:#eef2ff!important}.btn-toolbar.btn-run.mode-deepseek:active,.btn-toolbar.btn-run-gear.mode-deepseek:active{background:#3350e6!important;border-color:#96aaff8c!important}.btn-toolbar.btn-run.mode-omp,.btn-toolbar.btn-run-gear.mode-omp{background:#312e81!important;border-color:#818cf84d!important;color:#e0e7ff!important}.btn-toolbar.btn-run.mode-omp:active,.btn-toolbar.btn-run-gear.mode-omp:active{background:#4f46e5!important;border-color:#818cf880!important}.run-mode-menu{bottom:100%;left:0;margin-bottom:6px;min-width:160px;max-width:80vw}.run-mode-option{padding:10px 12px;font-size:.8rem;cursor:pointer;-webkit-tap-highlight-color:rgba(255,255,255,.1)}.run-mode-row-btn{width:34px;height:34px;font-size:1rem;-webkit-tap-highlight-color:rgba(255,255,255,.1)}.run-mode-webview-delete{font-size:1.2rem}.run-mode-history{-webkit-overflow-scrolling:touch;touch-action:manipulation}.btn-toolbar.btn-stop{display:flex!important;flex:0 0 auto;padding:0 8px!important;min-width:unset;order:3}.btn-toolbar.btn-stop svg{width:10px;height:10px;margin-right:0}.btn-toolbar.btn-shell{display:none!important}.btn-toolbar.btn-enter{display:flex!important;flex:0 0 auto;align-items:center;justify-content:center;min-width:54px;width:54px;white-space:nowrap;padding:0 8px!important;overflow:hidden;font-size:.65rem;font-weight:600;letter-spacing:.01em;background:#1e3a5fd9!important;border:1px solid rgba(59,130,246,.45)!important;color:#dbeafe!important;order:4}.btn-toolbar.btn-enter:hover,.btn-toolbar.btn-enter:active{background:#254a7af2!important;border-color:#3b82f6b3!important;color:#fff!important}.case-select-group{display:none!important}.toolbar-left .toolbar-group:first-child{width:100%;gap:8px}.btn-toolbar.btn-case-mobile{display:flex!important;flex:1 1 0!important;min-width:0;padding:0 8px!important;order:2;overflow:hidden;justify-content:center;gap:4px}.btn-toolbar.btn-case-mobile #mobileCaseName{max-width:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.btn-case-settings-mobile{display:inline-flex!important;align-items:center;justify-content:center;width:26px;height:26px;background:transparent;border:1px solid rgba(255,255,255,.2);border-radius:4px;color:#9ca3af;cursor:pointer;flex-shrink:0;order:1}.btn-case-settings-mobile:active{background:#ffffff1a;color:#fff}@media(max-width:374px){.toolbar{padding:0 2px}.toolbar-left,.toolbar-left .toolbar-group,.toolbar-left .toolbar-group:first-child{gap:2px}}.btn-case-settings-mobile{display:none!important}.case-settings-popover-mobile{position:fixed;bottom:calc(var(--safe-area-bottom) + 46px);left:8px;right:8px;background:#1e1e1e;border:1px solid rgba(255,255,255,.15);border-radius:8px;padding:.6rem .75rem;z-index:1000;box-shadow:0 4px 16px #00000080;display:block}.case-settings-popover-mobile.hidden{display:none!important}.case-settings-popover-mobile .checkbox-inline{display:flex;align-items:center;gap:6px;font-size:.75rem;color:#e5e7eb}.case-settings-popover-mobile .form-hint{display:block;margin-top:.2rem;font-size:.6rem;color:#6b7280}.keyboard-accessory-bar{display:none;position:fixed;bottom:calc(var(--safe-area-bottom) + 40px);left:0;right:0;height:44px;background:#1a1a1a;border-top:1px solid rgba(255,255,255,.1);padding:6px 8px;padding-left:calc(8px + var(--safe-area-left));padding-right:calc(8px + var(--safe-area-right));gap:8px;align-items:center;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;z-index:51;transition:transform .15s ease-out;will-change:transform}.keyboard-accessory-bar.visible{display:flex}.keyboard-accessory-bar::-webkit-scrollbar{display:none}.accessory-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;gap:4px;padding:6px 12px;background:#2a2a2a;border:1px solid rgba(255,255,255,.15);border-radius:6px;color:#e5e5e5;font-size:.65rem;font-weight:500;cursor:pointer;transition:background .15s,border-color .15s}.accessory-btn.confirming{background:#6b4f00;border-color:#b8860b;color:#ffd54f}.accessory-btn.accessory-btn-ctrl.armed{background:#2563eb;border-color:#3b82f6e6;color:#fff;font-weight:700;box-shadow:0 0 0 2px #3b82f673}.accessory-btn:active{background:#3a3a3a}.accessory-btn svg{width:14px;height:14px}.accessory-btn-arrow{padding:6px 10px;background:#2563eb;border-color:#3b82f680;color:#fff}.accessory-btn-arrow:active{background:#1d4ed8}.accessory-btn-dismiss{margin-left:auto;flex:1 1 0;max-width:100px;padding:10px 8px;background:#2563eb;border-color:#3b82f680;color:#fff;font-weight:600}.accessory-btn-dismiss svg{width:22px;height:22px}.accessory-btn-dismiss:active{background:#1d4ed8}.voice-preview{bottom:calc(var(--safe-area-bottom) + 94px);font-size:.8rem;max-width:90%;padding:6px 14px}.btn-case-add,.btn-case-settings,.toolbar-select{display:none!important}.toolbar .btn-case-add{min-width:26px!important;max-width:26px!important;width:26px!important;min-height:26px!important;max-height:26px!important;height:26px!important;padding:0!important;font-size:.9rem;font-weight:700;display:inline-flex!important;align-items:center;justify-content:center;line-height:1;border-radius:4px;background:transparent;border:1px solid rgba(255,255,255,.15);color:#9ca3af}.btn-case-add:hover,.btn-case-add:active{background:#ffffff1a;color:#fff}.monitor-panel,.subagents-panel{width:100%;max-width:100%;left:0;right:0;border-radius:8px 8px 0 0;bottom:calc(44px + 2rem + var(--safe-area-bottom));max-height:35vh}.modal{z-index:1300}.modal-content{width:100%;max-width:100%;height:100%;max-height:100%;border-radius:0;margin:0;display:flex;flex-direction:column}.modal-content.modal-sm,.modal-content.readmymind-modal{height:auto;max-height:85vh;border-radius:12px;margin:1rem;width:calc(100% - 2rem)}.readmymind-modal .modal-footer{flex-wrap:wrap}.readmymind-modal .modal-footer .btn-toolbar{flex:1 1 auto;justify-content:center;min-height:38px}.readmymind-alt,.readmymind-steer-input{min-height:38px}.ios-device .modal-content{padding-top:var(--safe-area-top);padding-bottom:var(--safe-area-bottom);padding-left:var(--safe-area-left);padding-right:var(--safe-area-right)}.modal-header{padding:.75rem 1rem}.modal-header h3{font-size:1rem}.modal-body{padding:.75rem 1rem;flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}.away-digest-modal{width:100%;max-width:100%;height:100%;max-height:100%}.away-digest-ranges{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.4rem}.away-digest-ranges .filter-btn{min-height:38px;padding:.4rem .5rem}.away-digest-custom-range,.away-digest-custom-range.active{grid-template-columns:1fr}.away-digest-summary{grid-template-columns:repeat(2,minmax(0,1fr));gap:.5rem}.away-digest-item{grid-template-columns:1fr;gap:.5rem}.away-digest-action{width:100%;min-height:38px}.modal-footer,.form-actions{padding:.75rem 1rem;padding-bottom:calc(.75rem + var(--safe-area-bottom))}.ios-device .terminal-container{padding-bottom:var(--safe-area-bottom)}.main{flex:1;min-height:0}.cli-info-bar{display:block}.terminal-container{height:100%;min-height:0;position:relative;overflow:visible;touch-action:none}.terminal-container .xterm,.terminal-container .xterm-viewport,.terminal-container .xterm-screen{touch-action:none}.response-viewer{padding-bottom:var(--safe-area-bottom, 0px);max-height:88vh;max-height:92dvh}.response-viewer-body{font-size:14.5px;line-height:1.65;padding:16px 16px 24px;--rv-content-max: 100%}.response-viewer-body .rv-text pre,.response-viewer-body pre{padding:12px 14px;margin-left:-4px;margin-right:-4px;border-radius:6px}.response-viewer-body .rv-text pre code,.response-viewer-body pre code{font-size:11.5px;line-height:1.5}.response-viewer-body .rv-text h1,.response-viewer-body>h1{font-size:1.35em}.response-viewer-body .rv-text h2,.response-viewer-body>h2{font-size:1.2em}.response-viewer-body .rv-text h3,.response-viewer-body>h3{font-size:1.08em}.welcome-content{max-width:calc(100vw - 1.5rem);padding:1rem .75rem}.welcome-title{font-size:1.2rem;margin-bottom:.5rem}.welcome-desc{font-size:.8rem;margin-bottom:.4rem}.welcome-actions{flex-direction:column;gap:.5rem;margin-top:1rem}.welcome-btn{width:100%;justify-content:center;min-height:44px;padding:.75rem 1rem;font-size:.85rem}.history-show-more{display:block;margin-bottom:.75rem}.welcome-ralph-link{display:block;margin:.75rem auto 0}.welcome-hint{font-size:.7rem;margin-top:.75rem}.modal-wizard{display:flex;flex-direction:column}.wizard-progress{padding:.5rem}.wizard-step{padding:.3rem}.wizard-step-number{width:24px;height:24px;font-size:.7rem}.wizard-step-label{display:none}.timer-banner{padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right))}.respawn-banner{padding:.3rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.65rem}.respawn-compact-layout{flex-direction:column;gap:.15rem}.respawn-status-col{flex-shrink:1;min-width:0;gap:.1rem}.respawn-status-row1{flex-wrap:wrap;gap:.25rem;row-gap:.1rem}.respawn-state{font-size:.6rem;padding:.05rem .3rem}.respawn-banner .detection-confidence{font-size:.5rem;padding:.02rem .2rem}.respawn-cycles{font-size:.55rem}.respawn-timer{font-size:.55rem;padding:0 .25rem}.respawn-tokens{font-size:.55rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:120px}.respawn-indicator{font-size:.65rem}.respawn-banner .btn-icon-only{min-width:36px;min-height:36px;font-size:1rem;display:flex;align-items:center;justify-content:center;margin-left:auto;border-radius:6px;flex-shrink:0}.respawn-status-row2{font-size:.55rem;gap:.3rem;min-height:0;flex-wrap:wrap}.respawn-banner .detection-hook,.respawn-banner .detection-ai-check,.respawn-banner .detection-status{font-size:.55rem;padding:.02rem .2rem}.respawn-countdown-timers{gap:.2rem}.respawn-countdown-timer{font-size:.5rem;padding:.02rem .2rem;gap:.15rem}.respawn-countdown-timer .respawn-timer-bar{display:none}.respawn-action-log{border-left:none;border-top:1px solid rgba(34,197,94,.15);padding-left:0;padding-top:.15rem;max-height:1.4em;font-size:.55rem;overflow:hidden}.respawn-header{flex-direction:row;gap:.4rem;align-items:center}.respawn-header .respawn-actions{display:flex;gap:.3rem;flex-shrink:0}.respawn-header .respawn-actions .btn-toolbar{min-height:28px!important;font-size:.7rem!important;padding:.2rem .5rem!important;border-radius:5px}.duration-presets{display:flex;flex-wrap:wrap;gap:.2rem}.duration-preset-btn{min-height:24px;padding:.1rem .4rem;font-size:.6rem;border-radius:4px;text-align:center}.duration-custom{display:flex;gap:.2rem;align-items:center}.duration-custom-input.visible{flex:0 1 auto}.duration-custom-input input{width:64px;min-height:24px;font-size:16px;padding:.1rem .3rem}.preset-selector{display:grid;grid-template-columns:1fr 1fr;gap:.25rem}.preset-selector select{grid-column:1 / -1;min-height:32px;font-size:16px;border-radius:5px;padding:.2rem .4rem}.preset-selector .btn{min-height:32px;font-size:.65rem;border-radius:5px;padding:.2rem .4rem}#sessionOptionsModal textarea{font-size:16px;min-height:32px!important;max-height:56px;height:auto!important;border-radius:6px;padding:.3rem .5rem}#modalRespawnPrompt{min-height:32px!important;max-height:56px}#modalRespawnKickstart{min-height:32px!important;max-height:48px}#sessionOptionsModal .checkbox-inline{min-height:30px;font-size:.75rem;padding:.15rem 0;gap:.4rem}#sessionOptionsModal .checkbox-inline input[type=checkbox]{width:18px;height:18px}#sessionOptionsModal .respawn-loop-title{font-size:.75rem}#sessionOptionsModal .respawn-loop-box .checkbox-inline{font-size:.65rem}#sessionOptionsModal .respawn-options-row{gap:.5rem}#sessionOptionsModal .form-section-header{margin-top:.75rem;padding-top:.5rem;font-size:.65rem}#sessionOptionsModal .form-row{margin-bottom:.5rem}#sessionOptionsModal .form-row label{font-size:.65rem;margin-bottom:.2rem}#sessionOptionsModal .form-hint{font-size:.6rem;margin-top:.2rem}.context-setting{padding:.625rem}.context-setting-header{flex-wrap:wrap;gap:.4rem}.context-setting-header .input-suffix-sm input{width:60px;font-size:16px;min-height:36px}.context-setting input[type=text]{font-size:16px;min-height:36px;padding:.4rem .6rem;border-radius:6px}.color-picker{gap:8px}.color-swatch{width:36px;height:36px;border-radius:6px}.form-row-switch{min-height:40px;gap:.4rem}.context-settings-grid input[type=number]{font-size:16px;min-height:36px}.ralph-limits-grid{grid-template-columns:1fr 1fr;gap:.5rem}.ralph-limits-grid .form-col input[type=number]{font-size:16px;min-height:36px;padding:.4rem .5rem;border-radius:6px}#modalRalphPhrase{font-size:16px;min-height:40px;border-radius:6px}.ralph-config-actions{margin-top:1rem}.ralph-config-actions .btn-toolbar{width:100%;min-height:44px;font-size:.85rem;border-radius:8px}.run-summary-filters{gap:.3rem;margin-bottom:.5rem}.filter-btn{padding:.35rem .75rem;font-size:.7rem;min-height:32px}.timeline-event{padding:.4rem .5rem;margin-bottom:.25rem;font-size:.7rem}.run-summary-footer{flex-direction:column;gap:.4rem;padding:.5rem 0}.run-summary-actions{flex-wrap:wrap;gap:.3rem}.run-summary-actions .btn-toolbar{flex:1;min-height:36px;font-size:.7rem;white-space:nowrap}.auto-refresh-label{font-size:.7rem}.ralph-panel{font-size:.75rem}.ralph-summary{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right))}.project-insights-panel{max-width:100%;font-size:.65rem;bottom:calc(44px + 2rem + var(--safe-area-bottom))}.file-browser-panel{max-width:100%;max-height:50vh;bottom:calc(44px + 2rem + var(--safe-area-bottom))}.file-preview-window{width:100vw;max-width:100vw;height:var(--app-height, 100vh);max-height:var(--app-height, 100vh);border-radius:0;border-left:none;border-right:none}.file-preview-editbar{padding-bottom:calc(.4rem + var(--safe-area-bottom))}.file-preview-overlay .file-preview-footer{padding-bottom:calc(.35rem + var(--safe-area-bottom))}.file-preview-body textarea.file-preview-editor{font-size:16px}.notification-drawer{width:100%;max-width:100%;right:0;border-radius:0;padding-left:var(--safe-area-left);padding-right:var(--safe-area-right);padding-bottom:var(--safe-area-bottom)}input,textarea,[contenteditable]{scroll-margin-bottom:200px;scroll-margin-top:80px}.keyboard-visible .modal-body{max-height:40vh;overflow-y:auto}.keyboard-visible #createCaseModal .modal-body{max-height:60vh}.mobile-case-picker .modal-backdrop{background:#00000080}.mobile-case-picker-sheet{max-height:60vh;padding-bottom:var(--safe-area-bottom);animation:slideUp .2s ease-out}@keyframes slideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.mobile-case-picker-header .modal-close{width:32px;height:32px;font-size:1.5rem}.mobile-case-picker-footer{padding-bottom:calc(12px + var(--safe-area-bottom))}#createCaseModal .form-row{margin-bottom:1rem}#createCaseModal .form-row label{font-size:.8rem;margin-bottom:.4rem;font-weight:500;color:#e5e7eb}#createCaseModal .form-row input[type=text]{min-height:44px;font-size:16px;padding:.5rem .75rem;border-radius:8px}#createCaseModal .form-row .form-hint{font-size:.65rem;margin-top:.35rem;line-height:1.4}#createCaseModal .form-actions{padding:.75rem 1rem;padding-bottom:calc(.75rem + var(--safe-area-bottom));gap:.75rem}#createCaseModal .form-actions .btn-toolbar{min-height:44px!important;max-height:44px!important;height:44px!important;font-size:.85rem!important;font-weight:500;border-radius:8px}#caseModalSubmit.loading{opacity:.6;pointer-events:none}#createCaseModal.from-mobile .modal-content{animation:caseModalSlideUp .25s ease-out}@keyframes caseModalSlideUp{0%{transform:translateY(30px);opacity:0}to{transform:translateY(0);opacity:1}}.btn-case-create-mobile{min-height:48px!important;max-height:48px!important;height:48px!important;font-size:.85rem!important;font-weight:500;border-radius:10px}.settings-grid{grid-template-columns:1fr;gap:.35rem}.settings-grid-3col{grid-template-columns:1fr 1fr 1fr}.settings-item{padding:.35rem .5rem;font-size:.7rem}.settings-item-label{font-size:.7rem}.settings-section-header{font-size:.6rem;padding:.35rem 0 .2rem;margin-top:.5rem}.form-row{margin-bottom:.5rem}.form-row label{font-size:.7rem;margin-bottom:.2rem}.form-row .form-hint{font-size:.6rem}.form-row input[type=text],.form-row input[type=number],.form-row textarea,.form-row .form-select,.form-row select{font-size:.75rem;padding:.35rem .5rem;min-height:32px}.form-row-switch{gap:.3rem}.form-row-switch>label:first-child{font-size:.7rem}.form-section-header{font-size:.6rem;margin-top:.75rem}.event-type-grid{grid-template-columns:1fr 36px 36px 36px;gap:4px 4px;padding:6px;margin-top:6px}.event-header{font-size:.55rem}.event-label{font-size:.65rem}.event-type-grid input[type=checkbox]{width:12px;height:12px}.form-actions{gap:.5rem}.form-actions .btn-toolbar{flex:1;min-height:36px!important;max-height:36px!important;height:36px!important;font-size:.75rem!important}.subagent-window{position:fixed;width:calc(100% - 8px);max-width:calc(100% - 8px);height:110px;min-height:80px;max-height:110px;min-width:200px;border-radius:6px;resize:none;box-shadow:0 2px 8px #0006}.subagent-window:after{display:none}.subagent-window-header{padding:.2rem .4rem;min-height:24px}.subagent-window-title{gap:.2rem;overflow:hidden}.subagent-window-title .icon{font-size:.7rem}.subagent-window-title .id{font-size:.6rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:45vw}.subagent-window-title .status{font-size:.45rem;padding:.05rem .15rem}.subagent-model-badge{font-size:.45rem!important;padding:.05rem .15rem!important}.subagent-window-actions button{font-size:.7rem;padding:.15rem .35rem;min-width:26px;min-height:26px;display:flex;align-items:center;justify-content:center}.subagent-window-body{font-size:.6rem;padding:.2rem .35rem}.subagent-window-body .activity-line{gap:.15rem;padding:.05rem 0}.subagent-window-body .activity-line .time{font-size:.5rem}.subagent-window-body .activity-line .tool-name,.subagent-window-body .activity-line .tool-detail{font-size:.55rem}.subagent-window-parent{display:none}.session-tab .tab-subagent-badge{height:14px;padding:0 3px;border-radius:7px;margin-left:2px}.session-tab .tab-subagent-badge .subagent-label{font-size:.45rem}.subagent-dropdown{position:fixed!important;left:8px!important;right:8px!important;bottom:auto!important;min-width:auto!important;max-width:none!important;border-radius:8px;transform:none!important}.mobile-overview.visible{position:absolute;inset:0;z-index:10;display:flex;flex-direction:column;gap:.75rem;padding:.75rem .6rem calc(1rem + var(--safe-area-bottom));background:var(--bg-dark);overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}.mobile-overview-top{display:flex;align-items:center;justify-content:space-between;gap:.5rem;padding:0}.mobile-overview-brand{display:inline-flex;align-items:center;min-height:48px;font-size:1.5rem;font-weight:800;line-height:1;color:var(--accent-hover);letter-spacing:-.02em}.mobile-overview-header{position:relative;display:flex;flex-direction:column}.mobile-overview-run-group{display:flex;align-items:stretch;flex-shrink:0}.mobile-overview-run-group .mobile-overview-run{display:inline-flex;align-items:center;gap:.4rem;min-height:48px!important;height:48px!important;max-height:48px!important;padding:0 1.15rem!important;font-size:.95rem!important;line-height:1;font-weight:700;font-family:inherit;border-radius:10px 0 0 10px!important}.mobile-overview-run-mode{font-weight:600;font-size:.85rem;opacity:.8}.mobile-overview-run-group .mobile-overview-run-caret{display:inline-flex;align-items:center;justify-content:center;min-height:48px!important;height:48px!important;max-height:48px!important;min-width:48px!important;width:48px!important;padding:0!important;line-height:1;font-family:inherit;border-radius:0 10px 10px 0!important}.mobile-overview-run-group .mobile-overview-run-caret svg{display:block;width:20px!important;height:20px!important;margin:0!important}.mobile-overview-run-menu{display:flex;flex-direction:column;gap:.15rem;margin:.5rem 0 0;padding:.35rem;border:1px solid var(--border);border-radius:12px;background:var(--floating-bg);box-shadow:var(--elevated-shadow)}.mobile-overview-run-option{display:flex;align-items:center;gap:.5rem;min-height:44px;padding:0 .6rem;border:none;border-radius:8px;background:transparent;color:var(--text);font-family:inherit;font-size:.82rem;text-align:left}.mobile-overview-run-option.selected{background:var(--control-bg-hover)}.mobile-overview-run-option:active{background:var(--bg-hover)}.mobile-overview-run-option--add{color:var(--accent)}.mobile-overview-run-header{padding:.4rem .6rem .2rem;font-size:.6rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--text-muted)}.mobile-overview-section{display:flex;flex-direction:column;gap:.4rem}.mobile-overview-heading{display:flex;align-items:center;gap:.35rem;margin:.35rem 0 0;padding:0;font-size:.65rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--text-muted)}.mobile-overview-heading-count{color:var(--text-dim);font-weight:600}.mobile-overview-empty{margin:0;padding:.5rem 0;font-size:.75rem;color:var(--text-muted)}.mobile-overview-row{display:flex;align-items:center;gap:.6rem;width:100%;min-height:56px;padding:.5rem .7rem;border:1px solid var(--border);border-radius:12px;background:var(--bg-card);color:var(--text);font-family:inherit;text-align:left}.mobile-overview-row:active{background:var(--bg-hover)}.mobile-overview-row-wrap{width:100%}.mobile-overview-approval-strip{display:flex;flex-wrap:wrap;gap:.4rem;padding:.4rem .2rem .1rem}.mobile-overview-approval-btn{border:1px solid var(--border);border-radius:8px;background:var(--bg-card);color:var(--text);font-family:inherit;font-size:.72rem;padding:.35rem .6rem;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mobile-overview-approval-btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}.mobile-overview-approval-btn.danger{border-color:var(--error);color:var(--error)}.mobile-overview-row--needs{border-color:var(--red);animation:mobile-overview-blink-red 2.5s ease-in-out infinite}.mobile-overview-row--waiting{border-color:var(--yellow);animation:mobile-overview-blink-yellow 3.5s ease-in-out infinite}.mobile-overview-row--error{border-color:var(--red)}.mobile-overview-row--working{border-color:var(--green);animation:mobile-overview-breathe-green 2.2s ease-in-out infinite}@keyframes mobile-overview-breathe-green{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#22c55e1a;border-color:var(--green)}}.mobile-overview-pill--working:after{content:"";display:inline-block;width:.75em;text-align:left;animation:mobile-overview-pill-dots 1.5s steps(1,end) infinite}@keyframes mobile-overview-pill-dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}@keyframes mobile-overview-blink-red{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#ef444424;border-color:var(--red)}}@keyframes mobile-overview-blink-yellow{0%,to{background:var(--bg-card);border-color:var(--border)}50%{background:#eab3081f;border-color:var(--yellow)}}.mobile-overview-row-body{display:flex;flex-direction:column;gap:.15rem;flex:1;min-width:0}.mobile-overview-row-title{display:block;font-size:.9rem;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-overview-row-case{color:var(--text-dim);font-weight:500}.mobile-overview-row-sub{display:block;font-size:.68rem;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-overview-row-meta{display:flex;align-items:center;gap:.3rem;min-width:0;font-family:var(--font-mono, monospace);font-size:.63rem;color:var(--text-muted);white-space:nowrap;overflow:hidden}.mobile-overview-meta-item{min-width:0;overflow:hidden;text-overflow:ellipsis}.mobile-overview-meta-key{margin-right:.3rem;opacity:.6;text-transform:uppercase;letter-spacing:.05em}.mobile-overview-meta-sep{opacity:.45}.mobile-overview-row--working .mobile-overview-meta-since{color:var(--green);opacity:.95}.mobile-overview-dot{flex-shrink:0;width:9px;height:9px;border-radius:50%;background:var(--text-muted)}.mobile-overview-dot--needs,.mobile-overview-dot--error{background:var(--red)}.mobile-overview-dot--waiting{background:var(--yellow)}.mobile-overview-dot--working{background:var(--green);animation:pulse 1.5s infinite;box-shadow:0 0 8px 2px color-mix(in srgb,var(--green) 55%,transparent);will-change:opacity}.mobile-overview-dot{position:relative}.mobile-overview-dot--working:after{content:"";position:absolute;inset:-4px;border:2px solid rgba(34,197,94,.25);border-top-color:var(--green);border-radius:50%;animation:tab-load-spin .7s linear infinite}.mobile-overview-dot--idle{background:var(--green)}.mobile-overview-dot--done{background:var(--text-muted);opacity:.5}.mobile-overview-pill{flex-shrink:0;display:inline-flex;align-items:center;gap:.25rem;padding:.2rem .45rem;border:1px solid var(--border-light);border-radius:999px;font-size:.62rem;font-weight:600;color:var(--text-dim);white-space:nowrap}.mobile-overview-pill--needs,.mobile-overview-pill--error{border-color:var(--red);color:var(--red)}.mobile-overview-pill--waiting{border-color:var(--yellow);color:var(--yellow)}.mobile-overview-pill--idle,.mobile-overview-pill--working{border-color:var(--green);color:var(--green)}.mobile-overview-chevron{flex-shrink:0;color:var(--text-muted);font-size:1rem;line-height:1}.mobile-overview-row--past{background:transparent;border-style:dashed}.mobile-overview-row--past .mobile-overview-row-title{font-weight:500;color:var(--text-dim)}.mobile-overview-dot--past{background:transparent;border:1px solid var(--border-light)}.mobile-overview-pill--past{border-color:var(--border-light);color:var(--text-muted)}.mobile-overview-more{display:flex;align-items:center;justify-content:center;gap:.35rem;min-height:40px;border:none;border-radius:10px;background:var(--control-bg);color:var(--text-dim);font-family:inherit;font-size:.72rem;font-weight:600}.mobile-overview-more-count{padding:.05rem .35rem;border-radius:999px;background:var(--control-bg-hover);color:var(--text-muted)}}@media(prefers-reduced-motion:reduce){.mobile-overview-row--needs,.mobile-overview-row--waiting{animation:none}.mobile-overview-row--needs{background:#ef444424}.mobile-overview-row--waiting{background:#eab3081f}.mobile-overview-dot--working{animation:none}.mobile-overview-dot--working:after{border-color:var(--green);animation:none}.mobile-overview-row--working{animation:none}.mobile-overview-pill--working:after{content:"...";animation:none}}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.header,.toolbar,.keyboard-accessory-bar){background:var(--glass-bg);border-color:var(--glass-border);color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-voice-mobile,.btn-settings-mobile,.btn-toolbar.btn-shell,.toolbar .btn-case-add,.accessory-btn:not(.armed)){background:var(--control-bg);border-color:var(--control-border);color:var(--text-dim)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-voice-mobile:active,.btn-settings-mobile:active,.btn-toolbar.btn-shell:hover,.btn-toolbar.btn-shell:active,.btn-case-add:hover,.btn-case-add:active,.accessory-btn:active){background:var(--control-bg-hover);border-color:var(--control-border-hover);color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-claude,.btn-toolbar.btn-run-gear.mode-claude){background:linear-gradient(135deg,var(--accent-grad-a),var(--accent-grad-b));border-color:var(--accent);color:var(--accent-ink)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-opencode,.btn-toolbar.btn-run-gear.mode-opencode){background:linear-gradient(135deg,var(--accent-d),var(--accent-grad-b));border-color:var(--accent);color:var(--accent-ink)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-gemini,.btn-toolbar.btn-run-gear.mode-gemini){background:linear-gradient(135deg,#174ea6,#4f46e5);border-color:#315fc3;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-antigravity,.btn-toolbar.btn-run-gear.mode-antigravity){background:linear-gradient(135deg,#0e7490,#0891b2);border-color:#155e75;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-pi,.btn-toolbar.btn-run-gear.mode-pi){background:linear-gradient(135deg,#be185d,#db2777);border-color:#9d174d;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-omp,.btn-toolbar.btn-run-gear.mode-omp){background:linear-gradient(135deg,#4f46e5,#6366f1);border-color:#4338ca;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-grok,.btn-toolbar.btn-run-gear.mode-grok){background:linear-gradient(135deg,#27272a,#52525b);border-color:#18181b;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.btn-toolbar.btn-run.mode-deepseek,.btn-toolbar.btn-run-gear.mode-deepseek){background:linear-gradient(135deg,#2740c4,#4d6bfe);border-color:#1b2a8f;color:#fff}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .btn-toolbar.btn-run-gear{border-left-color:var(--control-border-hover)!important}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.case-settings-popover-mobile,.mobile-case-picker-sheet){background:var(--floating-bg);border-color:var(--control-border);color:var(--text);box-shadow:var(--elevated-shadow)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) :is(.case-settings-popover-mobile .checkbox-inline,#createCaseModal .form-row label){color:var(--text)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .case-settings-popover-mobile .form-hint{color:var(--text-muted)}html:is([data-skin=paper-gray],[data-skin=solarized-light],[data-skin=catppuccin-latte],[data-skin=rose-pine-dawn]) .mobile-case-picker .modal-backdrop{background:var(--modal-backdrop)}.ios-device.safari-browser{overscroll-behavior:none}@media(hover:none)and (pointer:coarse){.session-tab .tab-close,.session-tab .tab-gear{opacity:1;width:auto;padding:.15rem .25rem;align-items:center;justify-content:center}.btn-toolbar:hover,.btn-icon-header:hover{transform:none}.subagent-dropdown-trigger:active+.subagent-dropdown-menu,.subagent-dropdown-trigger:focus+.subagent-dropdown-menu{display:block}}@media(max-width:430px){.attachment-history-drawer{top:0;bottom:0;width:100%;max-width:100%;height:100vh;height:100dvh;border-left:none;border-radius:0;padding-top:var(--safe-area-top);padding-left:var(--safe-area-left);padding-right:var(--safe-area-right);padding-bottom:var(--safe-area-bottom)}.attachment-history-header{padding:12px}.attachment-history-list{padding:6px}.attachment-history-item{grid-template-columns:104px minmax(0,1fr);gap:8px;padding:8px 6px}.attachment-history-thumb{width:104px}.attachment-history-actions{gap:4px}.attachment-history-actions button{padding:4px 7px}}@media(max-width:430px){.offline-banner{padding:.4rem .5rem;padding-left:calc(.5rem + var(--safe-area-left));padding-right:calc(.5rem + var(--safe-area-right));font-size:.7rem;gap:.4rem}.offline-banner-detail{display:none}.offline-banner-retry{padding:.25rem .5rem;margin-left:auto}.offline-overlay-card{padding:22px 18px 18px}.offline-overlay-title{font-size:1.05rem}.offline-overlay-actions{flex-direction:column}.offline-overlay-btn{width:100%;padding:.65rem 1rem}}@media(max-width:860px){:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .modal-content.modal-lg{width:100%;max-width:100%;height:100%;max-height:100%}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-body{display:flex;flex-direction:column;min-height:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail{flex-direction:row;align-items:center;border-right:0;border-bottom:1px solid var(--border);background:transparent;padding:10px 14px;overflow:visible;flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail-items,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-rail-foot{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-search{margin:0;flex:1}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-search input{padding:9px 10px 9px 30px;border-radius:10px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-actions:has(.set-head-save){padding:3px;border:1px solid var(--border);border-radius:12px;background:var(--bg-input)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-save{display:inline-flex;height:36px;padding:0 16px;font-size:.86rem}#createCaseModal .set-head-save.loading{opacity:.6;pointer-events:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-head-actions .modal-close{width:36px;height:36px;font-size:1.35rem}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-foot{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-doc{padding:0 14px 34px;flex:1}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump{display:flex;position:sticky;top:0;z-index:4;align-items:center;gap:8px;width:100%;margin:10px 0 2px;padding:10px 12px;border-radius:11px;font:inherit;font-size:.82rem;color:var(--text);background:rgba(var(--accent-rgb),.13);border:1px solid rgba(var(--accent-rgb),.3);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);cursor:pointer}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-ico{color:var(--accent);flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-label{font-weight:580;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-chev{margin-left:auto;color:var(--text-muted);flex-shrink:0;transition:transform .18s}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump[aria-expanded=true] .set-jump-chev{transform:rotate(180deg)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-veil{display:none;position:fixed;inset:0;z-index:8;background:#04080d9e}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-menu{display:none;position:absolute;left:14px;right:14px;z-index:9;padding:7px;border-radius:16px;background:var(--bg-card);border:1px solid var(--control-border);box-shadow:var(--elevated-shadow);max-height:70vh;overflow-y:auto}#appSettingsModal.jump-open .set-jump-veil,#appSettingsModal.jump-open .set-jump-menu{display:block}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row{display:flex;align-items:center;gap:11px;width:100%;padding:11px 12px;border:0;border-radius:11px;background:transparent;color:var(--text-dim);font:inherit;font-size:.82rem;text-align:left}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row svg{color:var(--text-muted);flex-shrink:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row .set-jump-count{margin-left:auto;font-size:.62rem;color:var(--text-muted)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row.active{background:rgba(var(--accent-rgb),.14);color:var(--text);font-weight:570}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-jump-row.active svg{color:var(--accent)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section{padding-top:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section+.set-section{border-top:0;margin-top:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head{gap:7px;margin:18px 0 2px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head svg{padding:0;border:0;background:none;color:var(--text-muted);width:12px;height:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head h2{font-size:.6rem;font-weight:640;letter-spacing:.1em;text-transform:uppercase;color:var(--text-muted)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-head:after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--border),transparent)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-section-blurb{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-preview{margin-bottom:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-preview-stage{min-height:62px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group{margin-top:14px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group+.set-group{margin-top:16px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-head{margin-bottom:7px;padding:0 3px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-hint{padding:0 3px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body{gap:0;background:#ffffff09;border:1px solid rgba(255,255,255,.06);border-radius:13px;overflow:hidden}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-row{background:transparent;border:0;border-radius:0;padding:12px 13px;gap:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-row+.set-row{border-top:1px solid rgba(255,255,255,.055)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-chips,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-modelgrid,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.set-minigrid,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>#appSettingsShortcutsList{padding:12px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-group-body>.event-type-grid{padding:12px;margin:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-label{font-size:.84rem}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-desc{font-size:.69rem;max-width:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field{flex-direction:column;align-items:stretch;gap:9px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field .set-select,:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row.has-field .set-input{width:100%;min-width:0;max-width:none;box-sizing:border-box}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-actions-wide{width:100%}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-row-actions-wide .set-input{flex:1;min-width:0}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-num{width:76px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm{width:40px;height:24px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm .slider:before{height:18px;width:18px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .switch-sm input:checked+.slider:before{transform:translate(16px)}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-chip{font-size:.78rem;padding:9px 14px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-modelgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-minigrid{grid-template-columns:1fr}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-mini .set-select{width:148px}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment{overflow-x:auto;scrollbar-width:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment::-webkit-scrollbar{display:none}:is(#appSettingsModal,#sessionOptionsModal,#createCaseModal) .set-segment button{flex:0 0 auto;padding:8px 12px}}@media(max-width:860px){:is(#sessionOptionsModal,#createCaseModal) .set-rail{padding:8px 10px}:is(#sessionOptionsModal,#createCaseModal) .set-rail-items{display:flex;flex-direction:row;flex:1;min-width:0;gap:4px;overflow-x:auto;scrollbar-width:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-items::-webkit-scrollbar{display:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item{white-space:nowrap;padding:8px 12px}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item.active:before{display:none}:is(#sessionOptionsModal,#createCaseModal) .set-rail-item.active{background:rgba(var(--accent-rgb),.13)}}html[data-session-list=sidebar] .session-sidebar{position:absolute;top:0;bottom:0;left:0;width:min(280px,80vw);flex:0 0 auto;transform:translate(-100%);visibility:hidden;transition:transform var(--sidebar-transition),visibility var(--sidebar-transition);box-shadow:10px 0 28px #0000005c;z-index:12;padding-left:var(--safe-area-left)}html[data-session-list=sidebar][data-sidebar-detail=rich] .session-sidebar{width:min(280px,80vw);flex:0 0 auto}html[data-session-list=sidebar] .session-sidebar.open{transform:translate(0);visibility:visible}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar{flex-basis:auto;width:min(280px,80vw)}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar-head,html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar-filter{display:flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .session-tab{justify-content:flex-start;flex-wrap:nowrap;padding:.4rem .5rem}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-info{display:flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-number{display:inline-flex}html[data-session-list=sidebar][data-sidebar=collapsed] .session-sidebar .tab-subagent-badge{margin-left:4px}html[data-session-list=sidebar] .session-sidebar .session-tab{min-height:44px;max-height:none;flex-shrink:0}html[data-session-list=sidebar] .session-sidebar .session-tab .tab-gear,html[data-session-list=sidebar] .session-sidebar .session-tab .tab-close{display:inline-flex;align-items:center;justify-content:center;opacity:1;width:auto;min-width:28px;height:auto;margin-left:0;padding:.15rem .25rem}@media(prefers-reduced-motion:reduce){html[data-session-list=sidebar] .session-sidebar{transition:none}}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<span class="command-palette-subtitle">${escapeHtml(i.subtitle||"")}</span>
|
|
7
7
|
</span>
|
|
8
8
|
</button>
|
|
9
|
-
`}).join("")},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(n=>n.value===t.caseName)){const n=document.createElement("option");n.value=t.caseName,n.textContent=t.caseName,s.appendChild(n)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}await this.run()}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),n=s.ok?await s.json():null;this.cases=n?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e&&e.classList.remove("active")},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),n=await fetch(s),i=await n.json().catch(()=>null);if(!n.ok||!i||i.success===!1||!i.data){this._setSessionManagerMessage(t,i?.error||`Failed to load sessions (HTTP ${n.status})`);return}const a=i.data.sessions||[];if(t.replaceChildren(),a.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const r of a){const o={sessionId:r.sessionId,workingDir:r.workingDir||"",sizeBytes:r.sizeBytes??0,lastModified:new Date(r.lastActivityAt??r.createdAt??Date.now()).toISOString(),firstPrompt:r.firstPrompt||r.name||"",gitBranch:r.gitBranch,worktreeName:r.worktreeName,worktreeRepo:r.worktreeRepo},l=!!this.sessions?.has?.(r.sessionId),c=this._buildHistoryItem(o,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),l?this.selectSession(r.sessionId):o.workingDir&&this.resumeHistorySession(r.claudeSessionId||r.sessionId,o.workingDir,void 0,r.mode)}});t.appendChild(c)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const n=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(n)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const n=this.awayDigestRange||"since-last-visit",i=new URLSearchParams({range:n});if(n==="since-last-visit"){const o=this.readAwayDigestLastViewed();Number.isFinite(o)&&i.set("lastViewed",String(o))}if(n==="custom"){this.ensureAwayDigestCustomDefaults();const o=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),l=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(o))throw new Error("Choose a custom start time");i.set("since",String(o)),Number.isFinite(l)&&i.set("until",String(l))}const a=await fetch(`/api/away-digest?${i.toString()}`),r=await a.json();if(!a.ok||!r.success)throw new Error(r.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=r.digest.generatedAt,n==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=r.digest.generatedAt),this.renderAwayDigest(r.digest)}catch(n){const i=n instanceof Error?n.message:"Failed to load away digest";console.error("Failed to fetch away digest:",n),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(i)}</div>`),this.showToast(i,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),n=document.getElementById("awayDigestSections");if(!t||!s||!n)return;const i=e.totals.inputTokens||0,a=e.totals.outputTokens||0,r=e.totals.estimatedCost||0;t.innerHTML=`
|
|
9
|
+
`}).join("")},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(n=>n.value===t.caseName)){const n=document.createElement("option");n.value=t.caseName,n.textContent=t.caseName,s.appendChild(n)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}await this.run()}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),n=s.ok?await s.json():null;this.cases=n?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e&&e.classList.remove("active")},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),n=await fetch(s),i=await n.json().catch(()=>null);if(!n.ok||!i||i.success===!1||!i.data){this._setSessionManagerMessage(t,i?.error||`Failed to load sessions (HTTP ${n.status})`);return}const a=i.data.sessions||[];if(t.replaceChildren(),a.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const r of a){const o={sessionId:r.sessionId,workingDir:r.workingDir||"",sizeBytes:r.sizeBytes??0,lastModified:new Date(r.lastActivityAt??r.createdAt??Date.now()).toISOString(),firstPrompt:r.firstPrompt||r.name||"",gitBranch:r.gitBranch,worktreeName:r.worktreeName,worktreeRepo:r.worktreeRepo},l=!!this.sessions?.has?.(r.sessionId),c=this._buildHistoryItem(o,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),l?this.selectSession(r.sessionId):o.workingDir&&this.resumeHistorySession(r.claudeSessionId||r.sessionId,o.workingDir,void 0,r.mode,r.resumeId)}});t.appendChild(c)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const n=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(n)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const n=this.awayDigestRange||"since-last-visit",i=new URLSearchParams({range:n});if(n==="since-last-visit"){const o=this.readAwayDigestLastViewed();Number.isFinite(o)&&i.set("lastViewed",String(o))}if(n==="custom"){this.ensureAwayDigestCustomDefaults();const o=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),l=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(o))throw new Error("Choose a custom start time");i.set("since",String(o)),Number.isFinite(l)&&i.set("until",String(l))}const a=await fetch(`/api/away-digest?${i.toString()}`),r=await a.json();if(!a.ok||!r.success)throw new Error(r.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=r.digest.generatedAt,n==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=r.digest.generatedAt),this.renderAwayDigest(r.digest)}catch(n){const i=n instanceof Error?n.message:"Failed to load away digest";console.error("Failed to fetch away digest:",n),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(i)}</div>`),this.showToast(i,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),n=document.getElementById("awayDigestSections");if(!t||!s||!n)return;const i=e.totals.inputTokens||0,a=e.totals.outputTokens||0,r=e.totals.estimatedCost||0;t.innerHTML=`
|
|
10
10
|
<div class="away-digest-card">
|
|
11
11
|
<span class="away-digest-card-label">Needs Attention</span>
|
|
12
12
|
<span class="away-digest-card-value">${e.totals.needsAttention}</span>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<span class="case-combobox-check">${d?"\u2713":""}</span>
|
|
11
11
|
<span class="case-combobox-option-label">${escapeHtml(o.label)}</span>
|
|
12
12
|
</button>
|
|
13
|
-
`}).join(""),t.classList.remove("hidden"),e.setAttribute("aria-activedescendant",`quickStartCaseOption-${this._casePickerActiveIndex}`)},selectQuickStartCase(e,{save:t=!0}={}){const s=document.getElementById("quickStartCase");if(!s)return;s.value=e||"testcase",this.updateCasePickerInput(s.value),this.closeCasePicker(),this.updateDirDisplayForCase(s.value),this.updateMobileCaseLabel(s.value);const n=(this.cases||[]).find(a=>a.name===s.value);n?.location==="docker"&&this._probeDockerCaseModes(n,null),t&&this.saveLastUsedCase(s.value)},setupQuickStartCasePicker(){const e=document.getElementById("quickStartCase"),t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList"),n=document.getElementById("quickStartCasePicker");!e||!t||!s||!n||t.dataset.listenerAdded||(t.addEventListener("focus",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("click",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("input",()=>{this.openCasePicker(t.value)}),t.addEventListener("keydown",a=>{const i=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||t.value);if(a.key==="ArrowDown")a.preventDefault(),this._casePickerActiveIndex=Math.min((this._casePickerActiveIndex||0)+1,Math.max(0,i.length-1)),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="ArrowUp")a.preventDefault(),this._casePickerActiveIndex=Math.max((this._casePickerActiveIndex||0)-1,0),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="Enter"){const o=i[this._casePickerActiveIndex||0];o&&(a.preventDefault(),this.selectQuickStartCase(o.name),this.run?.())}else a.key==="Escape"?(a.preventDefault(),this.updateCasePickerInput(e.value),this.closeCasePicker()):a.key==="Tab"&&(this.updateCasePickerInput(e.value),this.closeCasePicker())}),s.addEventListener("mousedown",a=>a.preventDefault()),s.addEventListener("click",a=>{const i=a.target.closest?.(".case-combobox-option");i?.dataset?.case&&this.selectQuickStartCase(i.dataset.case)}),document.addEventListener&&!this._casePickerDocumentListenerAdded&&(document.addEventListener("pointerdown",a=>{n.contains(a.target)||(this.updateCasePickerInput(e.value),this.closeCasePicker())}),this._casePickerDocumentListenerAdded=!0),t.dataset.listenerAdded="true")},async loadQuickStartCases(e=null,t=null){try{let s=null;try{const r=t?await t:await fetch("/api/settings").then(c=>c.ok?c.json():null).then(c=>c?.data??null);r&&(s=r.lastUsedCase||null)}catch{}const a=(await(await fetch("/api/cases")).json()).data;this.cases=a,console.log("[loadQuickStartCases] Loaded cases:",a.map(r=>r.name),"lastUsedCase:",s);const i=document.getElementById("quickStartCase"),o=this.getCasePickerOptions();if(this.renderQuickStartCaseSelectOptions(i,o),console.log("[loadQuickStartCases] Set options:",i.innerHTML.substring(0,200)),e)i.value=e,this.updateDirDisplayForCase(e),this.updateMobileCaseLabel(e);else if(s&&a.some(r=>r.name===s))i.value=s,this.updateDirDisplayForCase(s),this.updateMobileCaseLabel(s);else if(a.length>0){const r=a.find(c=>c.name==="testcase")||a[0];i.value=r.name,this.updateDirDisplayForCase(r.name),this.updateMobileCaseLabel(r.name)}else i.value="testcase",document.getElementById("dirDisplay").textContent="~/codeman-cases/testcase",this.updateMobileCaseLabel("testcase");this.updateCasePickerInput(i.value),this.renderCasePickerList(),this.closeCasePicker(),i.dataset.listenerAdded||(i.addEventListener("change",()=>{this.updateDirDisplayForCase(i.value),this.saveLastUsedCase(i.value),this.updateMobileCaseLabel(i.value),this.updateCasePickerInput(i.value)}),i.dataset.listenerAdded="true"),this.setupQuickStartCasePicker(),this._refreshMobileOverviewIfVisible?.()}catch(s){console.error("Failed to load cases:",s)}},async updateDirDisplayForCase(e){try{const s=(await(await fetch(`/api/cases/${e}`)).json()).data;s.path&&(document.getElementById("dirDisplay").textContent=s.path,document.getElementById("dirInput").value=s.path)}catch{document.getElementById("dirDisplay").textContent=e}},async saveLastUsedCase(e){try{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({lastUsedCase:e})})}catch(t){console.error("Failed to save last used case:",t)}},async quickStart(){return this.run()},async _ensureCreatedSessionVisible(e,t){if(!e)return;let s=t;if(!s&&!this.sessions?.has(e)){const a=await(await fetch(`/api/sessions/${encodeURIComponent(e)}`)).json();if(!a.success)throw new Error(a.error||"Failed to load the new session");s=a.data?.session||a.data}s?.id&&this._onSessionCreated(s),this._renderSessionTabsImmediate?.()},async run(){if(this._runInFlight)return;const e=Date.now(),t=Number.isFinite(this._runMinLockMs)?this._runMinLockMs:500,s=document.getElementById("runBtn");this._runInFlight=!0,s&&(s.disabled=!0,s.setAttribute("aria-busy","true"));try{const n=this._runMode||"claude";return n==="opencode"?await this.runOpenCode():n==="codex"?await this.runCodex():n==="gemini"?await this.runGemini():n==="antigravity"?await this.runAntigravity():n==="omp"?await this.runOmp():n==="pi"?await this.runPi():n==="grok"?await this.runGrok():n==="deepseek"?await this.runDeepSeek():n==="shell"?await this.runShell():await this.runClaude()}finally{const n=t-(Date.now()-e);n>0&&await new Promise(a=>setTimeout(a,n)),this._runInFlight=!1,s&&(s.disabled=!1,s.removeAttribute("aria-busy"))}},setRunMode(e){this._runMode=e;try{localStorage.setItem("codeman_runMode",e)}catch{}this._applyRunMode(),this._apiPut("/api/settings",{runMode:e}).catch(()=>{}),document.getElementById("runModeMenu")?.classList.remove("active")},toggleRunModeMenu(e){e?.stopPropagation();const t=document.getElementById("runModeMenu");if(t&&(t.classList.toggle("active"),t.querySelectorAll(".run-mode-option").forEach(s=>{s.classList.toggle("selected",s.dataset.mode===this.runMode)}),t.classList.contains("active"))){this._loadRunModeHistory(),this._refreshRunModeAvailability(t);const s=n=>{t.contains(n.target)||(t.classList.remove("active"),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}},_refreshRunModeAvailability(e){const t=document.getElementById("quickStartCase")?.value,s=t?(this.cases||[]).find(d=>d.name===t):null,n=s?.location==="docker",a=n&&(this._dockerCaseModes?.[t]||s.docker?.availableModes)||null;n&&!this._dockerCaseModes?.[t]&&this._probeDockerCaseModes(s,e);const i=n?this._dockerCaseProbeError?.[t]:null;for(const d of["claude","opencode","codex","gemini","antigravity","pi","grok","deepseek","omp"]){const l=e.querySelector(`.run-mode-option[data-mode="${d}"]`);if(!l)continue;let m;n?m=i?!1:a?a.includes(d):!0:m=this.isCliAvailable(d),l.style.display=m?"flex":"none"}this._renderRunModeNotice(e,i);const o=window.__codemanCliAvailable||{},r=e.querySelector("#runModeDeepSeekInstall");r&&(r.style.display=!o.deepseek&&o.deepseekBinary?"flex":"none");const c=e.querySelector("#runModeDeepSeekWeb");c&&(c.style.display=o.deepseekBinary?"flex":"none")},async runDeepSeekWeb(){document.getElementById("runModeMenu")?.classList.remove("active");const e=this._beginSessionLaunchStatus("Starting the DeepSeek web UI...");try{const s=await(await fetch("/api/deepseek/web",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({authority:location.host})})).json();if(!s.success)throw new Error(s.error||"Failed to start the DeepSeek web UI");const n=s.data.url;let a=[...this.webviews?.values()||[]].find(i=>i.managed==="deepseek-web");if(a){const o=await(await fetch(`/api/webviews/${a.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:n,trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to update the web tab");a=o.data.webview||o.data}else{const o=await(await fetch("/api/webviews",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"DeepSeek Harness",url:n,icon:"\u{1F433}",managed:"deepseek-web",trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to save the web tab");a=o.data.webview||o.data}await this.refreshWebviews?.(),this._appendSessionLaunchStatus(e,`Serving on ${n} - opening it as a tab.`),a?.id&&await this.openWebview(a.id)}catch(t){this._reportSessionLaunchError(e,t.message)}},async installDeepSeekProfile(){const t=this._beginSessionLaunchStatus("Installing a DeepSeek terminal profile (this can take a minute)...");try{const n=await(await fetch("/api/deepseek/install-profile",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})})).json();if(!n.success)throw new Error(n.error||"Failed to install the profile");window.__codemanCliAvailable={...window.__codemanCliAvailable||{},deepseek:!!n.data.runnable},this._appendSessionLaunchStatus(t,`Installed ${n.data.package} into profile "${n.data.profile}".`),this.showToast?.(`DeepSeek profile "${n.data.profile}" installed`,"success");const a=document.getElementById("runModeMenu");a&&this._refreshRunModeAvailability(a)}catch(s){this._reportSessionLaunchError(t,s.message)}},_renderRunModeNotice(e,t){if(!e)return;let s=e.querySelector(".run-mode-notice");if(!t){s?.remove();return}s||(s=document.createElement("div"),s.className="run-mode-notice",e.prepend(s)),s.textContent=t},async _probeDockerCaseModes(e,t){const s=e?.name,n=e?.docker?.container,a=e?.docker?.hostId;if(!(!s||!n||!a)&&(this._dockerCaseModes=this._dockerCaseModes||{},!this._dockerModeProbeInFlight?.[s])){this._dockerModeProbeInFlight=this._dockerModeProbeInFlight||{},this._dockerModeProbeInFlight[s]=!0;try{const i=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:a,container:n}});i?.ok&&Array.isArray(i.availableModes)?(this._dockerCaseModes[s]=i.availableModes,delete this._dockerCaseProbeError?.[s]):(e?.docker?.owned===!1&&(this._dockerCaseProbeError=this._dockerCaseProbeError||{},this._dockerCaseProbeError[s]=i?.error||`Could not read container "${n}".`),delete this._dockerCaseModes[s]),t?.classList.contains("active")&&this._refreshRunModeAvailability(t)}finally{delete this._dockerModeProbeInFlight[s]}}},async _loadRunModeHistory(){const e=document.getElementById("runModeHistory");if(e){e.innerHTML='<div class="run-mode-hist-empty">Loading...</div>';try{const t=await this._fetchHistorySessions(10);if(t.length===0){e.innerHTML='<div class="run-mode-hist-empty">No history</div>';return}e.replaceChildren();for(const s of t){const n=new Date(s.lastModified),a=n.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+n.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1}),i=this._shortenHomePath(s.workingDir),o=i.lastIndexOf("/"),r=o===-1?i:i.slice(o+1),c=(o===-1?"":i.slice(0,o)).replace(/\/\.claude\/worktrees$/,""),d=document.createElement("button");d.className="run-mode-option run-mode-hist-row",d.title=s.workingDir,d.dataset.sessionId=s.sessionId,d.dataset.workingDir=s.workingDir;const l=document.createElement("span");l.className="hist-name",l.textContent=r;const m=[l],h=this._worktreeLabel?this._worktreeLabel(s):"";if(h){const u=document.createElement("span");u.className="hist-wt",u.textContent=h,m.push(u)}if(c){const u=document.createElement("span");u.className="hist-dir",u.textContent=c,m.push(u)}const C=document.createElement("span");C.className="hist-meta",C.textContent=a,m.push(C),d.append(...m),d.addEventListener("click",u=>{u.stopPropagation(),this.resumeHistorySession(s.sessionId,s.workingDir,s.name,s.mode)}),e.appendChild(d)}}catch{e.innerHTML='<div class="run-mode-hist-empty">Failed to load</div>'}}},_applyRunMode(){const e=this.runMode,t=document.getElementById("runBtn"),s=t?.nextElementSibling,n=document.getElementById("runBtnLabel");t&&(t.className=`btn-toolbar btn-run mode-${e}`),s&&(s.className=`btn-toolbar btn-run-gear mode-${e}`),n&&(n.textContent=e==="opencode"?"Run OC":e==="codex"?"Run CX":e==="gemini"?"Run GM":e==="antigravity"?"Run AG":e==="pi"?"Run PI":e==="grok"?"Run GK":e==="deepseek"?"Run DS":e==="omp"?"Run OMP":e==="shell"?"Run SH":"Run")},sendEnterKey(){if(!this.activeSessionId)return;const e=this.terminal?._core?.coreService;if(e&&typeof e.triggerDataEvent=="function"){e.triggerDataEvent("\r",!0);return}this.sendInput("\r")},_initRunMode(){try{this._runMode=localStorage.getItem("codeman_runMode")||"claude"}catch{this._runMode="claude"}this._applyRunMode()},incrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},incrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},_nextCaseSessionStartNumber(e,t="w"){const s=new RegExp(`^${t}(\\d+)-([a-zA-Z0-9_-]+)`);let n=1;for(const[,a]of this.sessions||[]){const i=a.name&&a.name.match(s);if(i&&i[2]===e){const o=parseInt(i[1]);o>=n&&(n=o+1)}}return n},_beginSessionLaunchStatus(e,t="1;32"){const s=!this.activeSessionId;return s?(this.terminal.clear(),this.terminal.writeln(`\x1B[${t}m ${e}\x1B[0m`),this.terminal.writeln("")):this.showToast?.(e,"info"),s},_appendSessionLaunchStatus(e,t,s="90"){!e||this.activeSessionId||this.terminal.writeln(`\x1B[${s}m ${t}\x1B[0m`)},_reportSessionLaunchError(e,t){e&&!this.activeSessionId?this.terminal.writeln(`\x1B[1;31m Error: ${t}\x1B[0m`):this.showToast?.(t,"error")},async runClaude(){const e=document.getElementById("quickStartCase").value||"testcase",t=Math.min(20,Math.max(1,parseInt(document.getElementById("tabCount").value)||1)),s=this._beginSessionLaunchStatus(`Starting ${t} Claude session(s) in ${e}...`);this.terminal.focus();try{let a=(await(await fetch(`/api/cases/${e}`)).json())?.data??{};if(!a.path){const S=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!S.success)throw new Error(S.error||"Failed to create case");a=S.data.case}const i=a.path;if(!i)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const g=this._nextCaseSessionStartNumber(e);let S;if(a.location==="docker"){const E=this.loadAppSettingsFromStorage(),I=this.getCaseSettings(e).opusContext1m||E.opusContext1mEnabled;S=E.claudeModel||(I?"opus[1m]":"")}const b=[];let T=!1;for(let E=0;E<t;E++){const B=JSON.stringify({caseName:e,mode:"claude",sessionName:`w${g+E}-${e}`,...S!==void 0?{modelOverride:S}:{}}),I=async()=>(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:B})).json();let v=await I();if(!v.success&&v.errorCode==="CONFLICT"&&a.location==="docker"&&!T&&(T=!0,confirm(`Container config for "${e}" changed since its container was created.
|
|
13
|
+
`}).join(""),t.classList.remove("hidden"),e.setAttribute("aria-activedescendant",`quickStartCaseOption-${this._casePickerActiveIndex}`)},selectQuickStartCase(e,{save:t=!0}={}){const s=document.getElementById("quickStartCase");if(!s)return;s.value=e||"testcase",this.updateCasePickerInput(s.value),this.closeCasePicker(),this.updateDirDisplayForCase(s.value),this.updateMobileCaseLabel(s.value);const n=(this.cases||[]).find(a=>a.name===s.value);n?.location==="docker"&&this._probeDockerCaseModes(n,null),t&&this.saveLastUsedCase(s.value)},setupQuickStartCasePicker(){const e=document.getElementById("quickStartCase"),t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList"),n=document.getElementById("quickStartCasePicker");!e||!t||!s||!n||t.dataset.listenerAdded||(t.addEventListener("focus",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("click",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("input",()=>{this.openCasePicker(t.value)}),t.addEventListener("keydown",a=>{const i=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||t.value);if(a.key==="ArrowDown")a.preventDefault(),this._casePickerActiveIndex=Math.min((this._casePickerActiveIndex||0)+1,Math.max(0,i.length-1)),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="ArrowUp")a.preventDefault(),this._casePickerActiveIndex=Math.max((this._casePickerActiveIndex||0)-1,0),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="Enter"){const o=i[this._casePickerActiveIndex||0];o&&(a.preventDefault(),this.selectQuickStartCase(o.name),this.run?.())}else a.key==="Escape"?(a.preventDefault(),this.updateCasePickerInput(e.value),this.closeCasePicker()):a.key==="Tab"&&(this.updateCasePickerInput(e.value),this.closeCasePicker())}),s.addEventListener("mousedown",a=>a.preventDefault()),s.addEventListener("click",a=>{const i=a.target.closest?.(".case-combobox-option");i?.dataset?.case&&this.selectQuickStartCase(i.dataset.case)}),document.addEventListener&&!this._casePickerDocumentListenerAdded&&(document.addEventListener("pointerdown",a=>{n.contains(a.target)||(this.updateCasePickerInput(e.value),this.closeCasePicker())}),this._casePickerDocumentListenerAdded=!0),t.dataset.listenerAdded="true")},async loadQuickStartCases(e=null,t=null){try{let s=null;try{const r=t?await t:await fetch("/api/settings").then(c=>c.ok?c.json():null).then(c=>c?.data??null);r&&(s=r.lastUsedCase||null)}catch{}const a=(await(await fetch("/api/cases")).json()).data;this.cases=a,console.log("[loadQuickStartCases] Loaded cases:",a.map(r=>r.name),"lastUsedCase:",s);const i=document.getElementById("quickStartCase"),o=this.getCasePickerOptions();if(this.renderQuickStartCaseSelectOptions(i,o),console.log("[loadQuickStartCases] Set options:",i.innerHTML.substring(0,200)),e)i.value=e,this.updateDirDisplayForCase(e),this.updateMobileCaseLabel(e);else if(s&&a.some(r=>r.name===s))i.value=s,this.updateDirDisplayForCase(s),this.updateMobileCaseLabel(s);else if(a.length>0){const r=a.find(c=>c.name==="testcase")||a[0];i.value=r.name,this.updateDirDisplayForCase(r.name),this.updateMobileCaseLabel(r.name)}else i.value="testcase",document.getElementById("dirDisplay").textContent="~/codeman-cases/testcase",this.updateMobileCaseLabel("testcase");this.updateCasePickerInput(i.value),this.renderCasePickerList(),this.closeCasePicker(),i.dataset.listenerAdded||(i.addEventListener("change",()=>{this.updateDirDisplayForCase(i.value),this.saveLastUsedCase(i.value),this.updateMobileCaseLabel(i.value),this.updateCasePickerInput(i.value)}),i.dataset.listenerAdded="true"),this.setupQuickStartCasePicker(),this._refreshMobileOverviewIfVisible?.()}catch(s){console.error("Failed to load cases:",s)}},async updateDirDisplayForCase(e){try{const s=(await(await fetch(`/api/cases/${e}`)).json()).data;s.path&&(document.getElementById("dirDisplay").textContent=s.path,document.getElementById("dirInput").value=s.path)}catch{document.getElementById("dirDisplay").textContent=e}},async saveLastUsedCase(e){try{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({lastUsedCase:e})})}catch(t){console.error("Failed to save last used case:",t)}},async quickStart(){return this.run()},async _ensureCreatedSessionVisible(e,t){if(!e)return;let s=t;if(!s&&!this.sessions?.has(e)){const a=await(await fetch(`/api/sessions/${encodeURIComponent(e)}`)).json();if(!a.success)throw new Error(a.error||"Failed to load the new session");s=a.data?.session||a.data}s?.id&&this._onSessionCreated(s),this._renderSessionTabsImmediate?.()},async run(){if(this._runInFlight)return;const e=Date.now(),t=Number.isFinite(this._runMinLockMs)?this._runMinLockMs:500,s=document.getElementById("runBtn");this._runInFlight=!0,s&&(s.disabled=!0,s.setAttribute("aria-busy","true"));try{const n=this._runMode||"claude";return n==="opencode"?await this.runOpenCode():n==="codex"?await this.runCodex():n==="gemini"?await this.runGemini():n==="antigravity"?await this.runAntigravity():n==="omp"?await this.runOmp():n==="pi"?await this.runPi():n==="grok"?await this.runGrok():n==="deepseek"?await this.runDeepSeek():n==="shell"?await this.runShell():await this.runClaude()}finally{const n=t-(Date.now()-e);n>0&&await new Promise(a=>setTimeout(a,n)),this._runInFlight=!1,s&&(s.disabled=!1,s.removeAttribute("aria-busy"))}},setRunMode(e){this._runMode=e;try{localStorage.setItem("codeman_runMode",e)}catch{}this._applyRunMode(),this._apiPut("/api/settings",{runMode:e}).catch(()=>{}),document.getElementById("runModeMenu")?.classList.remove("active")},toggleRunModeMenu(e){e?.stopPropagation();const t=document.getElementById("runModeMenu");if(t&&(t.classList.toggle("active"),t.querySelectorAll(".run-mode-option").forEach(s=>{s.classList.toggle("selected",s.dataset.mode===this.runMode)}),t.classList.contains("active"))){this._loadRunModeHistory(),this._refreshRunModeAvailability(t);const s=n=>{t.contains(n.target)||(t.classList.remove("active"),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}},_refreshRunModeAvailability(e){const t=document.getElementById("quickStartCase")?.value,s=t?(this.cases||[]).find(d=>d.name===t):null,n=s?.location==="docker",a=n&&(this._dockerCaseModes?.[t]||s.docker?.availableModes)||null;n&&!this._dockerCaseModes?.[t]&&this._probeDockerCaseModes(s,e);const i=n?this._dockerCaseProbeError?.[t]:null;for(const d of["claude","opencode","codex","gemini","antigravity","pi","grok","deepseek","omp"]){const l=e.querySelector(`.run-mode-option[data-mode="${d}"]`);if(!l)continue;let m;n?m=i?!1:a?a.includes(d):!0:m=this.isCliAvailable(d),l.style.display=m?"flex":"none"}this._renderRunModeNotice(e,i);const o=window.__codemanCliAvailable||{},r=e.querySelector("#runModeDeepSeekInstall");r&&(r.style.display=!o.deepseek&&o.deepseekBinary?"flex":"none");const c=e.querySelector("#runModeDeepSeekWeb");c&&(c.style.display=o.deepseekBinary?"flex":"none")},async runDeepSeekWeb(){document.getElementById("runModeMenu")?.classList.remove("active");const e=this._beginSessionLaunchStatus("Starting the DeepSeek web UI...");try{const s=await(await fetch("/api/deepseek/web",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({authority:location.host})})).json();if(!s.success)throw new Error(s.error||"Failed to start the DeepSeek web UI");const n=s.data.url;let a=[...this.webviews?.values()||[]].find(i=>i.managed==="deepseek-web");if(a){const o=await(await fetch(`/api/webviews/${a.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:n,trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to update the web tab");a=o.data.webview||o.data}else{const o=await(await fetch("/api/webviews",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"DeepSeek Harness",url:n,icon:"\u{1F433}",managed:"deepseek-web",trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to save the web tab");a=o.data.webview||o.data}await this.refreshWebviews?.(),this._appendSessionLaunchStatus(e,`Serving on ${n} - opening it as a tab.`),a?.id&&await this.openWebview(a.id)}catch(t){this._reportSessionLaunchError(e,t.message)}},async installDeepSeekProfile(){const t=this._beginSessionLaunchStatus("Installing a DeepSeek terminal profile (this can take a minute)...");try{const n=await(await fetch("/api/deepseek/install-profile",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})})).json();if(!n.success)throw new Error(n.error||"Failed to install the profile");window.__codemanCliAvailable={...window.__codemanCliAvailable||{},deepseek:!!n.data.runnable},this._appendSessionLaunchStatus(t,`Installed ${n.data.package} into profile "${n.data.profile}".`),this.showToast?.(`DeepSeek profile "${n.data.profile}" installed`,"success");const a=document.getElementById("runModeMenu");a&&this._refreshRunModeAvailability(a)}catch(s){this._reportSessionLaunchError(t,s.message)}},_renderRunModeNotice(e,t){if(!e)return;let s=e.querySelector(".run-mode-notice");if(!t){s?.remove();return}s||(s=document.createElement("div"),s.className="run-mode-notice",e.prepend(s)),s.textContent=t},async _probeDockerCaseModes(e,t){const s=e?.name,n=e?.docker?.container,a=e?.docker?.hostId;if(!(!s||!n||!a)&&(this._dockerCaseModes=this._dockerCaseModes||{},!this._dockerModeProbeInFlight?.[s])){this._dockerModeProbeInFlight=this._dockerModeProbeInFlight||{},this._dockerModeProbeInFlight[s]=!0;try{const i=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:a,container:n}});i?.ok&&Array.isArray(i.availableModes)?(this._dockerCaseModes[s]=i.availableModes,delete this._dockerCaseProbeError?.[s]):(e?.docker?.owned===!1&&(this._dockerCaseProbeError=this._dockerCaseProbeError||{},this._dockerCaseProbeError[s]=i?.error||`Could not read container "${n}".`),delete this._dockerCaseModes[s]),t?.classList.contains("active")&&this._refreshRunModeAvailability(t)}finally{delete this._dockerModeProbeInFlight[s]}}},async _loadRunModeHistory(){const e=document.getElementById("runModeHistory");if(e){e.innerHTML='<div class="run-mode-hist-empty">Loading...</div>';try{const t=await this._fetchHistorySessions(10);if(t.length===0){e.innerHTML='<div class="run-mode-hist-empty">No history</div>';return}e.replaceChildren();for(const s of t){const n=new Date(s.lastModified),a=n.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+n.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1}),i=this._shortenHomePath(s.workingDir),o=i.lastIndexOf("/"),r=o===-1?i:i.slice(o+1),c=(o===-1?"":i.slice(0,o)).replace(/\/\.claude\/worktrees$/,""),d=document.createElement("button");d.className="run-mode-option run-mode-hist-row",d.title=s.workingDir,d.dataset.sessionId=s.sessionId,d.dataset.workingDir=s.workingDir;const l=document.createElement("span");l.className="hist-name",l.textContent=r;const m=[l],h=this._worktreeLabel?this._worktreeLabel(s):"";if(h){const u=document.createElement("span");u.className="hist-wt",u.textContent=h,m.push(u)}if(c){const u=document.createElement("span");u.className="hist-dir",u.textContent=c,m.push(u)}const C=document.createElement("span");C.className="hist-meta",C.textContent=a,m.push(C),d.append(...m),d.addEventListener("click",u=>{u.stopPropagation(),this.resumeHistorySession(s.sessionId,s.workingDir,s.name,s.mode,s.resumeId)}),e.appendChild(d)}}catch{e.innerHTML='<div class="run-mode-hist-empty">Failed to load</div>'}}},_applyRunMode(){const e=this.runMode,t=document.getElementById("runBtn"),s=t?.nextElementSibling,n=document.getElementById("runBtnLabel");t&&(t.className=`btn-toolbar btn-run mode-${e}`),s&&(s.className=`btn-toolbar btn-run-gear mode-${e}`),n&&(n.textContent=e==="opencode"?"Run OC":e==="codex"?"Run CX":e==="gemini"?"Run GM":e==="antigravity"?"Run AG":e==="pi"?"Run PI":e==="grok"?"Run GK":e==="deepseek"?"Run DS":e==="omp"?"Run OMP":e==="shell"?"Run SH":"Run")},sendEnterKey(){if(!this.activeSessionId)return;const e=this.terminal?._core?.coreService;if(e&&typeof e.triggerDataEvent=="function"){e.triggerDataEvent("\r",!0);return}this.sendInput("\r")},_initRunMode(){try{this._runMode=localStorage.getItem("codeman_runMode")||"claude"}catch{this._runMode="claude"}this._applyRunMode()},incrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},incrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},_nextCaseSessionStartNumber(e,t="w"){const s=new RegExp(`^${t}(\\d+)-([a-zA-Z0-9_-]+)`);let n=1;for(const[,a]of this.sessions||[]){const i=a.name&&a.name.match(s);if(i&&i[2]===e){const o=parseInt(i[1]);o>=n&&(n=o+1)}}return n},_beginSessionLaunchStatus(e,t="1;32"){const s=!this.activeSessionId;return s?(this.terminal.clear(),this.terminal.writeln(`\x1B[${t}m ${e}\x1B[0m`),this.terminal.writeln("")):this.showToast?.(e,"info"),s},_appendSessionLaunchStatus(e,t,s="90"){!e||this.activeSessionId||this.terminal.writeln(`\x1B[${s}m ${t}\x1B[0m`)},_reportSessionLaunchError(e,t){e&&!this.activeSessionId?this.terminal.writeln(`\x1B[1;31m Error: ${t}\x1B[0m`):this.showToast?.(t,"error")},async runClaude(){const e=document.getElementById("quickStartCase").value||"testcase",t=Math.min(20,Math.max(1,parseInt(document.getElementById("tabCount").value)||1)),s=this._beginSessionLaunchStatus(`Starting ${t} Claude session(s) in ${e}...`);this.terminal.focus();try{let a=(await(await fetch(`/api/cases/${e}`)).json())?.data??{};if(!a.path){const S=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!S.success)throw new Error(S.error||"Failed to create case");a=S.data.case}const i=a.path;if(!i)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const g=this._nextCaseSessionStartNumber(e);let S;if(a.location==="docker"){const E=this.loadAppSettingsFromStorage(),I=this.getCaseSettings(e).opusContext1m||E.opusContext1mEnabled;S=E.claudeModel||(I?"opus[1m]":"")}const b=[];let T=!1;for(let E=0;E<t;E++){const B=JSON.stringify({caseName:e,mode:"claude",sessionName:`w${g+E}-${e}`,...S!==void 0?{modelOverride:S}:{}}),I=async()=>(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:B})).json();let v=await I();if(!v.success&&v.errorCode==="CONFLICT"&&a.location==="docker"&&!T&&(T=!0,confirm(`Container config for "${e}" changed since its container was created.
|
|
14
14
|
|
|
15
15
|
Recreate the container to apply the new config? Workspace files and the conversation survive (the conversation resumes on launch).`))){const _=await(await fetch(`/api/docker-cases/${encodeURIComponent(e)}/recreate`,{method:"POST"})).json();if(!_.success)throw new Error(_.error||"Failed to recreate container");v=await I()}if(!v.success)throw new Error(v.error||"Failed to start remote Claude session");await this._ensureCreatedSessionVisible(v.data.sessionId,v.data.session),b.push(v.data.sessionId)}this._appendSessionLaunchStatus(s,`All ${t} remote session(s) ready`),b[0]&&(await this.selectSession(b[0]),this.loadQuickStartCases()),this.terminal.focus();return}let o=null;const r=this._nextCaseSessionStartNumber(e),c=this.isRalphTrackerEnabledByDefault(),d=[];for(let g=0;g<t;g++)d.push(`w${r+g}-${e}`);const l=this.getCaseSettings(e),m=this.loadAppSettingsFromStorage(),h=this.buildEnvOverrides(l,m),C=Object.keys(h).length>0,u=this.getEffortSetting(m),f=l.opusContext1m||m.opusContext1mEnabled,y=m.claudeModel||(f?"opus[1m]":"");this._appendSessionLaunchStatus(s,`Creating ${t} session(s)...`);const k=d.map(g=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workingDir:i,name:g,...C?{envOverrides:h}:{},...u?{effort:u}:{},...y!==void 0?{modelOverride:y}:{},statusLineTelemetry:this.planUsageChipEnabled(m)})}).then(S=>S.json())),p=await Promise.all(k),w=[];for(const g of p){if(!g.success)throw new Error(g.error);await this._ensureCreatedSessionVisible(g.data.session.id,g.data.session),w.push(g.data.session.id)}o=w[0],await Promise.all(w.map(g=>fetch(`/api/sessions/${g}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:c,disableAutoEnable:!c})}))),this._appendSessionLaunchStatus(s,`Starting ${t} session(s) in parallel...`),await Promise.all(w.map(g=>fetch(`/api/sessions/${g}/interactive`,{method:"POST"}))),this._appendSessionLaunchStatus(s,`All ${t} sessions ready`),o&&(await this.selectSession(o),this.loadQuickStartCases()),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},stopClaude(){if(!this.activeSessionId)return;const e=document.querySelector(".btn-toolbar.btn-stop");e&&(this._stopConfirmTimer?(clearTimeout(this._stopConfirmTimer),this._stopConfirmTimer=null,e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml,e.classList.remove("confirming"),fetch(`/api/sessions/${this.activeSessionId}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:""})})):(e.dataset.origHtml=e.innerHTML,e.textContent="Tap again",e.classList.add("confirming"),this._stopConfirmTimer=setTimeout(()=>{this._stopConfirmTimer=null,e.dataset.origHtml&&(e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml),e.classList.remove("confirming")},2e3)))},async runShell(){const e=document.getElementById("quickStartCase").value||"testcase",t=Math.min(20,Math.max(1,parseInt(document.getElementById("shellCount").value)||1)),s=this._beginSessionLaunchStatus(`Starting ${t} Shell session(s) in ${e}...`,"1;33");try{let a=(await(await fetch(`/api/cases/${e}`)).json())?.data??{};if(!a.path){const f=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!f.success)throw new Error(f.error||"Failed to create case");a=f.data.case}const i=(this.cases||[]).find(u=>u.name===e),o=a.location==="remote"||a.location==="docker"||i?.location==="remote"||i?.location==="docker",r=a.path;if(!r)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const u=this._nextCaseSessionStartNumber(e,"s"),f=[];for(let y=0;y<t;y++){const p=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"shell",sessionName:`s${u+y}-${e}`})})).json();if(!p.success)throw new Error(p.error||"Failed to start remote shell session");await this._ensureCreatedSessionVisible(p.data.sessionId,p.data.session),f.push(p.data.sessionId)}f[0]&&await this.selectSession(f[0]),this.terminal.focus();return}const c=this._nextCaseSessionStartNumber(e,"s"),d=[];for(let u=0;u<t;u++)d.push(`s${c+u}-${e}`);const l=d.map(u=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...o?{caseName:e}:{workingDir:r},mode:"shell",name:u})}).then(f=>f.json())),m=await Promise.all(l),h=[];for(const u of m){if(!u.success)throw new Error(u.error);await this._ensureCreatedSessionVisible(u.data.session.id,u.data.session),h.push(u.data.session.id)}await Promise.all(h.map(u=>fetch(`/api/sessions/${u}/shell`,{method:"POST"})));const C=this.getTerminalDimensions();C&&await Promise.all(h.map(u=>fetch(`/api/sessions/${u}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(C)}))),h.length>0&&await this.selectSession(h[0]),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},async runOpenCode(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting OpenCode session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/opencode/status")).json()).data.available){this._reportSessionLaunchError(n,"OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"opencode",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{openCodeConfig:{autoAllowTools:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start OpenCode");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runCodex(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Codex session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/codex/status")).json()).data.available){this._reportSessionLaunchError(n,"Codex CLI not found. Install with: npm install -g @openai/codex");return}const a=this.loadAppSettingsFromStorage(),i=this.buildEnvOverrides(this.getCaseSettings(e),a),r=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"codex",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{codexConfig:{dangerouslyBypassApprovals:a.codexDangerouslyBypassApprovals??!1,animations:a.codexAnimationsEnabled??!1,renderMode:"hybrid"},...Object.keys(i).length>0?{envOverrides:i}:{}}})})).json();if(!r.success)throw new Error(r.error||"Failed to start Codex");await this._ensureCreatedSessionVisible(r.data.sessionId,r.data.session),r.data.sessionId&&await this.selectSession(r.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runGemini(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Gemini session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/gemini/status")).json()).data.available){this._reportSessionLaunchError(n,"Gemini CLI not found. Install with: npm install -g @google/gemini-cli");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"gemini",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{geminiConfig:{approvalMode:"yolo"},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Gemini");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runAntigravity(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Antigravity session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/antigravity/status")).json()).data.available){this._reportSessionLaunchError(n,"Antigravity CLI not found. Install with: curl -fsSL https://antigravity.google/cli/install.sh | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"antigravity",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{antigravityConfig:{dangerouslySkipPermissions:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Antigravity");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runPi(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Pi session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/pi/status")).json()).data.available){this._reportSessionLaunchError(n,"Pi CLI not found. Install with: npm install -g --ignore-scripts @earendil-works/pi-coding-agent");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"pi",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s||Object.keys(a).length===0?{}:{envOverrides:a}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Pi");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runOmp(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting OMP session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/omp/status")).json()).data.available){this._reportSessionLaunchError(n,"OMP CLI not found. Install with: curl -fsSL https://omp.sh/install | sh");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"omp",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start OMP");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runGrok(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Grok session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/grok/status")).json()).data.available){this._reportSessionLaunchError(n,"Grok CLI not found. Install with: curl -fsSL https://x.ai/cli/install.sh | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"grok",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{grokConfig:{alwaysApprove:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Grok");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runDeepSeek(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting DeepSeek session in ${e}...`);this.terminal.focus();try{if(!s){const c=(await(await fetch("/api/deepseek/status")).json()).data;if(!c.available){this._reportSessionLaunchError(n,"DeepSeek Harness CLI (dsh) not found. Install with: npm install -g @deepseek-ai/dsh");return}if(!c.runnable){this._reportSessionLaunchError(n,"No interactive DeepSeek Harness profile is installed. DeepSeek ships only web and headless profiles, so the terminal agent comes from a plugin. Install one from the Run menu, or run: dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui");return}}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"deepseek",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{deepSeekConfig:{permissionMode:"danger-full-access"},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start DeepSeek");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},_tabDetachOverrides(){if(this._tabDetachOverrideMap===void 0)try{this._tabDetachOverrideMap=JSON.parse(localStorage.getItem("codeman:tab-detach-overrides")||"{}")||{}}catch{this._tabDetachOverrideMap={}}return this._tabDetachOverrideMap},hasTabDetachOverride(e){return!!this._tabDetachOverrides()[e]},onSessionTabDetachToggle(e){const t=this.editingSessionId;if(!t)return;const s=this._tabDetachOverrides();e?s[t]=1:delete s[t];for(const a of Object.keys(s))a!==t&&this.sessions&&!this.sessions.has(a)&&delete s[a];try{localStorage.setItem("codeman:tab-detach-overrides",JSON.stringify(s))}catch{}const n=document.querySelector(`.session-tab[data-id="${CSS.escape(t)}"]`);n&&n.classList.toggle("tab-show-detach",!!e)},openSessionOptions(e){const t=this.sessions.get(e);if(!t)return;this.editingSessionId=e;const s=document.getElementById("sessionOptShowTabDetach");s&&(s.checked=this.hasTabDetachOverride(e));const n=t.mode==="opencode"||t.mode==="codex"||t.mode==="gemini"||t.mode==="antigravity"||t.mode==="pi"||t.mode==="grok"||t.mode==="deepseek"||t.mode==="omp";this.switchOptionsTab(n?"summary":"respawn");const a=document.getElementById("sessionRespawnStatus"),i=document.getElementById("modalEnableRespawnBtn"),o=document.getElementById("modalStopRespawnBtn");this.respawnStatus[e]?(a.classList.add("active"),a.querySelector(".respawn-status-text").textContent=this.respawnStatus[e].state||"Active",i.style.display="none",o.style.display=""):(a.classList.remove("active"),a.querySelector(".respawn-status-text").textContent="Not active",i.style.display="",o.style.display="none");const r=document.getElementById("sessionRespawnSection");t.mode==="claude"&&t.pid?r.style.display="":r.style.display="none";const c=t.mode==="opencode"||t.mode==="codex"||t.mode==="gemini"||t.mode==="antigravity"||t.mode==="pi"||t.mode==="grok"||t.mode==="deepseek"||t.mode==="omp";document.querySelectorAll("[data-claude-only]").forEach(k=>{k.style.display=c?"none":""}),this.selectDurationPreset(""),this.loadSavedRespawnConfig(e),document.getElementById("modalAutoCompactEnabled").checked=t.autoCompactEnabled??!1,document.getElementById("modalAutoCompactThreshold").value=t.autoCompactThreshold??11e4,document.getElementById("modalAutoCompactPrompt").value=t.autoCompactPrompt??"",document.getElementById("modalAutoClearEnabled").checked=t.autoClearEnabled??!1,document.getElementById("modalAutoClearThreshold").value=t.autoClearThreshold??14e4,document.getElementById("modalAutoResumeEnabled").checked=t.autoResumeEnabled??!1,this.updateAutoResumeStatus(e),document.getElementById("modalImageWatcherEnabled").checked=t.imageWatcherEnabled??!0,document.getElementById("modalFlickerFilterEnabled").checked=t.flickerFilterEnabled??!1;const l=parseSessionPrefix(t.name),m=document.getElementById("modalSessionPrefix");l?(m.textContent=l.prefix+": ",m.style.display="",document.getElementById("modalSessionName").value=l.suffix,document.getElementById("modalSessionName").placeholder="Add description..."):(m.style.display="none",m.textContent="",document.getElementById("modalSessionName").value=t.name||"",document.getElementById("modalSessionName").placeholder="Auto (directory name)");const h=t.color||"default";document.getElementById("sessionColorPicker")?.querySelectorAll(".color-swatch").forEach(k=>{k.classList.toggle("selected",k.dataset.color===h)}),this.renderPresetDropdown(),document.getElementById("respawnPresetSelect").value="",document.getElementById("presetDescriptionHint").textContent="";const u=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="ralph"]'),f=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="respawn"]');if(c?(u&&(u.style.display="none"),f&&(f.style.display="none"),this.switchOptionsTab("context")):(u&&(u.style.display=""),f&&(f.style.display="")),!c){const k=this.ralphStates.get(e);this.populateRalphForm({enabled:k?.loop?.enabled??t.ralphLoop?.enabled??!1,completionPhrase:k?.loop?.completionPhrase||t.ralphLoop?.completionPhrase||"",maxIterations:k?.loop?.maxIterations||t.ralphLoop?.maxIterations||0,maxTodos:k?.loop?.maxTodos||t.ralphLoop?.maxTodos,todoExpirationMinutes:k?.loop?.todoExpirationMinutes||t.ralphLoop?.todoExpirationMinutes})}const y=document.getElementById("sessionOptionsModal");y.dataset.chipsReady!=="1"&&(y.dataset.chipsReady="1",y.addEventListener("change",k=>{k.target?.closest?.(".set-chip")&&this._syncSettingsChips()})),this._syncSettingsChips(),y.classList.add("active"),this.activeFocusTrap=new FocusTrap(y),this.activeFocusTrap.activate()},_applyLocalSessionName(e,t){if(typeof t!="string")return;const s=this.sessions.get(e);s&&(s.name=t,this.sessions.set(e,s),this.updateSubagentParentNames?.(e))},async _putSessionName(e,t){const s=await this._apiPut(`/api/sessions/${e}/name`,{name:t});if(!s||!s.ok)return null;let n=null;try{n=await s.json()}catch{return null}if(n&&n.success===!1)return null;const a=n?.data?.name;return typeof a=="string"?a:t},async saveSessionName(){if(!this.editingSessionId)return;const e=this.editingSessionId,t=this.sessions.get(e),s=t?parseSessionPrefix(t.name):null,n=document.getElementById("modalSessionName").value.trim();let a;s?a=s.prefix+(n?": "+n:""):a=n;const i=await this._putSessionName(e,a);if(i===null){this.showToast("Failed to save session name","error");return}this._applyLocalSessionName(e,i),this.renderSessionTabs()},async autoSaveAutoCompact(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-compact`,{enabled:document.getElementById("modalAutoCompactEnabled").checked,threshold:parseInt(document.getElementById("modalAutoCompactThreshold").value)||11e4,prompt:document.getElementById("modalAutoCompactPrompt").value.trim()||void 0})}catch{}},async autoSaveAutoClear(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-clear`,{enabled:document.getElementById("modalAutoClearEnabled").checked,threshold:parseInt(document.getElementById("modalAutoClearThreshold").value)||14e4})}catch{}},async autoSaveAutoResume(){if(!this.editingSessionId)return;const e=document.getElementById("modalAutoResumeEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-resume`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.autoResumeEnabled=e,e||(t.autoResumeAt=void 0)),this.updateAutoResumeStatus(this.editingSessionId),this.showToast(`Auto-resume on usage limit ${e?"enabled":"disabled"}`,"success")}catch(t){this.showToast("Failed to toggle auto-resume: "+t.message,"error")}},updateAutoResumeStatus(e){const t=document.getElementById("autoResumeStatus");if(!t||this.editingSessionId!==e)return;const s=this.sessions.get(e);if(s?.autoResumeAt&&s.autoResumeAt>Date.now()){const n=new Date(s.autoResumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.textContent=`Usage limit pause active \u2014 resumes at ${n}`,t.classList.add("active")}else t.textContent="",t.classList.remove("active")},async toggleSessionImageWatcher(){if(!this.editingSessionId)return;const e=document.getElementById("modalImageWatcherEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/image-watcher`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.imageWatcherEnabled=e),this.showToast(`Image watcher ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle image watcher","error")}},async toggleFlickerFilter(){if(!this.editingSessionId)return;const e=document.getElementById("modalFlickerFilterEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/flicker-filter`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.flickerFilterEnabled=e),this.showToast(`Flicker filter ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle flicker filter","error")}},async autoSaveRespawnConfig(){if(!this.editingSessionId)return;const e={updatePrompt:document.getElementById("modalRespawnPrompt").value,sendClear:document.getElementById("modalRespawnSendClear").checked,sendInit:document.getElementById("modalRespawnSendInit").checked,kickstartPrompt:document.getElementById("modalRespawnKickstart").value.trim()||void 0,autoAcceptPrompts:document.getElementById("modalRespawnAutoAccept").checked};try{await this._apiPut(`/api/sessions/${this.editingSessionId}/respawn/config`,e)}catch{}},async loadSavedRespawnConfig(e){try{const s=await(await fetch(`/api/sessions/${e}/respawn/config`)).json();if(s.success&&s.data&&s.data.config){const n=s.data.config;document.getElementById("modalRespawnPrompt").value=n.updatePrompt||"update all the docs and CLAUDE.md",document.getElementById("modalRespawnSendClear").checked=n.sendClear??!0,document.getElementById("modalRespawnSendInit").checked=n.sendInit??!0,document.getElementById("modalRespawnKickstart").value=n.kickstartPrompt||"",document.getElementById("modalRespawnAutoAccept").checked=n.autoAcceptPrompts??!0,n.durationMinutes&&(document.querySelector(`.duration-preset-btn[data-minutes="${n.durationMinutes}"]`)?this.selectDurationPreset(String(n.durationMinutes)):(this.selectDurationPreset("custom"),document.getElementById("modalRespawnDuration").value=n.durationMinutes))}}catch{}},selectDurationPreset(e){document.querySelectorAll(".duration-preset-btn").forEach(a=>a.classList.remove("active"));const t=document.querySelector(`.duration-preset-btn[data-minutes="${e}"]`);t&&t.classList.add("active");const s=document.querySelector(".duration-custom-input"),n=document.getElementById("modalRespawnDuration");e==="custom"?(s.classList.add("visible"),n.focus()):(s.classList.remove("visible"),n.value="")},getSelectedDuration(){const e=document.querySelector(".duration-custom-input"),t=document.getElementById("modalRespawnDuration");if(e.classList.contains("visible"))return t.value?parseInt(t.value):null;{const n=document.querySelector(".duration-preset-btn.active")?.dataset.minutes;return n?parseInt(n):null}},switchOptionsTab(e){document.querySelectorAll("#sessionOptionsModal .set-rail-item").forEach(s=>{s.classList.toggle("active",s.dataset.tab===e)}),document.getElementById("respawn-tab").classList.toggle("hidden",e!=="respawn"),document.getElementById("context-tab").classList.toggle("hidden",e!=="context"),document.getElementById("ralph-tab").classList.toggle("hidden",e!=="ralph"),document.getElementById("summary-tab").classList.toggle("hidden",e!=="summary");const t=document.getElementById("sessionOptionsDoc");t&&(t.scrollTop=0),e==="summary"&&this.editingSessionId&&this.loadRunSummary(this.editingSessionId)},getRalphConfig(){return{enabled:document.getElementById("modalRalphEnabled").checked,completionPhrase:document.getElementById("modalRalphPhrase").value.trim(),maxIterations:parseInt(document.getElementById("modalRalphMaxIterations").value)||0,maxTodos:parseInt(document.getElementById("modalRalphMaxTodos").value)||50,todoExpirationMinutes:parseInt(document.getElementById("modalRalphTodoExpiration").value)||60}},populateRalphForm(e){document.getElementById("modalRalphEnabled").checked=e?.enabled??!1,document.getElementById("modalRalphPhrase").value=e?.completionPhrase||"",document.getElementById("modalRalphMaxIterations").value=e?.maxIterations||0,document.getElementById("modalRalphMaxTodos").value=e?.maxTodos||50,document.getElementById("modalRalphTodoExpiration").value=e?.todoExpirationMinutes||60},async saveRalphConfig(){if(!this.editingSessionId){this.showToast("No session selected","warning");return}const e=this.getRalphConfig();e.enabled&&this.ralphClosedSessions.delete(this.editingSessionId);try{const s=await(await fetch(`/api/sessions/${this.editingSessionId}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).json();if(s.error)throw new Error(s.error);this.showToast("Ralph config saved","success")}catch(t){this.showToast("Failed to save Ralph config: "+t.message,"error")}},startInlineRename(e){const t=this.sessions.get(e);if(!t)return;this._activeRename?.cancel();const s=document.querySelector(`.tab-name[data-session-id="${e}"]`);if(!s)return;this._inlineRenameActive=!0,s.classList.add("tab-name-renaming");const n=this.getSessionName(t),a=parseSessionPrefix(t.name),i=s.textContent,o=[...s.childNodes].map(p=>p.cloneNode(!0)),r=()=>{s.replaceChildren(...o.map(p=>p.cloneNode(!0)))};for(s.textContent="";s.firstChild;)s.removeChild(s.firstChild);if(a){const p=document.createElement("span");p.className="tab-rename-prefix",p.textContent=a.prefix+": ",p.style.cssText="color: var(--text-muted); font-size: 0.75rem; white-space: nowrap;",s.appendChild(p)}const c=document.createElement("input");c.type="text",c.value=a?a.suffix:t.name||"",c.placeholder=a?"Add description...":n,c.className="tab-rename-input";const d=s.closest(".tab-rail")?"auto":this.isSessionSidebarActive?.()?"100%":"80px";c.style.cssText=`width: ${d}; min-width: 0; font-size: 0.75rem; padding: 2px 4px; background: var(--bg-input); border: 1px solid var(--accent); border-radius: 3px; color: var(--text); outline: none;`,s.appendChild(c),c.focus(),c.select();let l=!1,m=!1,h=!1;const C=()=>{this._activeRename===k&&(this._inlineRenameActive=!1)},u=()=>{this._activeRename===k&&(h=!0,C(),this._activeRename=null,this.renderSessionTabs())},f=()=>{m||h||(m=!0,l=!0,s.classList.remove("tab-name-renaming"),r(),u())},y=async({commit:p})=>{if(l||m)return;if(l=!0,s.classList.remove("tab-name-renaming"),!p){f();return}if(this._activeRename!==k)return;C();const w=c.value.trim(),g=a?a.prefix+(w?": "+w:""):w;if(g===t.name?r():s.textContent=g||i,this.sessions.has(e)&&g!==t.name){const b=await this._putSessionName(e,g);if(m||this._activeRename!==k||!this.sessions.has(e))return;b===null?(r(),this.showToast("Failed to rename","error")):this._applyLocalSessionName(e,b)}u()},k={sessionId:e,cancel:f};this._activeRename=k,c.addEventListener("blur",()=>y({commit:!0})),c.addEventListener("keydown",p=>{p.isComposing||p.keyCode===229||(p.key==="Enter"?(p.preventDefault(),c.blur()):p.key==="Escape"&&(p.preventDefault(),f()))})},toggleCaseSettings(){const e=document.getElementById("caseSettingsPopover");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeams").checked=s.agentTeams,document.getElementById("caseOpusContext1m").checked=s.opusContext1m,e.classList.remove("hidden");const n=a=>{!e.contains(a.target)&&!a.target.classList.contains("btn-case-settings")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},getCaseSettings(e){try{const t=localStorage.getItem("caseSettings_"+e);if(t)return JSON.parse(t)}catch{}return{agentTeams:!1,opusContext1m:!0}},saveCaseSettings(e,t){localStorage.setItem("caseSettings_"+e,JSON.stringify(t))},onCaseSettingChanged(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeams").checked,t.opusContext1m=document.getElementById("caseOpusContext1m").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeamsMobile");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1mMobile");n&&(n.checked=t.opusContext1m)},toggleCaseSettingsMobile(){const e=document.getElementById("caseSettingsPopoverMobile");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeamsMobile").checked=s.agentTeams,document.getElementById("caseOpusContext1mMobile").checked=s.opusContext1m,e.classList.remove("hidden");const n=a=>{!e.contains(a.target)&&!a.target.classList.contains("btn-case-settings-mobile")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},onCaseSettingChangedMobile(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeamsMobile").checked,t.opusContext1m=document.getElementById("caseOpusContext1mMobile").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeams");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1m");n&&(n.checked=t.opusContext1m)},showCreateCaseModal(){document.getElementById("newCaseName").value="",document.getElementById("newCaseDescription").value="",document.getElementById("linkCaseName").value="",document.getElementById("linkCasePath").value="",["remoteCaseName","remoteCasePath","remoteHostId","remoteHostAddress","remoteHostUsername","remoteHostPort","remoteHostCodexCommand","remoteHostIdentityFile","remoteHostSocksProxy","remoteHostJumpHost","remoteHostExtraSshOptions"].forEach(r=>{const c=document.getElementById(r);c&&(c.value="")}),this._resetCloneForm();const t=document.getElementById("caseCloneTabBtn");t&&(t.style.display=this.isCliAvailable("git")?"":"none"),this.caseModalTab="case-create",this.switchCaseModalTab("case-create");const s=document.getElementById("createCaseModal");s.querySelectorAll(".set-rail-item").forEach(r=>{r.onclick=()=>this.switchCaseModalTab(r.dataset.tab)});const n=document.getElementById("dockerAdoptExisting");n&&(n.onchange=()=>this._syncDockerAdoptMode());const a=document.getElementById("dockerAdoptCheckBtn");a&&(a.onclick=()=>this._dockerAdoptPreflight());const i=document.getElementById("dockerAdoptJumpBtn");i&&(i.onclick=()=>this.jumpToDockerAdopt());const o=document.getElementById("dockerHostId");o&&(o.onchange=()=>{delete document.getElementById("dockerContainerList")?.dataset.loadedFor,document.getElementById("dockerAdoptExisting")?.checked&&this._loadDockerContainerOptions()}),delete document.getElementById("dockerContainerList")?.dataset.loadedFor,this._syncDockerAdoptMode(),s.querySelectorAll('input[type="text"]').forEach(r=>{r._mobileScrollWired||(r._mobileScrollWired=!0,r.addEventListener("focus",()=>{window.innerWidth<=430&&setTimeout(()=>r.scrollIntoView({behavior:"smooth",block:"center"}),300)}))}),s.classList.add("active"),document.getElementById("newCaseName").focus()},switchCaseModalTab(e){this.caseModalTab=e;const t=document.getElementById("createCaseModal");t.querySelectorAll(".set-rail-item").forEach(a=>{a.classList.toggle("active",a.dataset.tab===e)}),t.querySelectorAll(".set-section").forEach(a=>{a.classList.toggle("hidden",a.id!==e)});const s=document.getElementById("createCaseDoc");s&&(s.scrollTop=0);const n=["caseModalSubmit","caseModalSubmitMobile"].map(a=>document.getElementById(a)).filter(Boolean);if(e==="case-manage")n.forEach(a=>{a.style.display="none"}),this.renderCaseManageList(),this.refreshDockerExports();else{const a=e==="case-create"?"Create":e==="case-clone"?"Clone":e==="case-remote"?"Link Remote":e==="case-docker"?"Link Docker":"Link";n.forEach(i=>{i.style.display="",i.textContent=a})}e==="case-create"?document.getElementById("newCaseName").focus():e==="case-clone"?document.getElementById("cloneRepoUrl").focus():e==="case-link"?document.getElementById("linkCaseName").focus():e==="case-remote"?document.getElementById("remoteCaseName").focus():e==="case-docker"&&document.getElementById("dockerCaseName").focus()},closeCreateCaseModal(){document.getElementById("createCaseModal").classList.remove("active")},async submitCaseModal(){const e=["caseModalSubmit","caseModalSubmitMobile"].map(n=>document.getElementById(n)).filter(Boolean),t=e.map(n=>n.textContent),s=this.caseModalTab==="case-create"?"Creating...":this.caseModalTab==="case-clone"?"Cloning...":"Linking...";e.forEach(n=>{n.classList.add("loading"),n.textContent=s,n.disabled=!0});try{this.caseModalTab==="case-create"?await this.createCase():this.caseModalTab==="case-clone"?await this.cloneCase():this.caseModalTab==="case-remote"?await this.linkRemoteCase():this.caseModalTab==="case-docker"?await this.linkDockerCase():await this.linkCase()}finally{e.forEach((n,a)=>{n.classList.remove("loading"),n.disabled=!1,n.textContent=t[a]})}},async createCase(){const e=document.getElementById("newCaseName").value.trim(),t=document.getElementById("newCaseDescription").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}const s=document.getElementById("newCaseDocker")?.checked,n=s?"/api/cases/docker-quickcreate":"/api/cases",a=s?{name:e,description:t,...this._collectDockerQuickSettings()}:{name:e,description:t};try{const o=await(await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json();if(o.success)if(this.closeCreateCaseModal(),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e),s){const r=o.data?.capsEnforced===!1?" (resource caps advisory on this engine)":"";this.showToast(`Docker case "${e}" created${r} \u2014 starting session\u2026`,"success"),await this.runClaude()}else this.showToast(`Case "${e}" created`,"success");else this.showToast(o.error||"Failed to create case","error")}catch(i){console.error("Failed to create case:",i),this.showToast("Failed to create case: "+i.message,"error")}},applyDockerTemplate(){const e=document.getElementById("quickDockerTemplate")?.value,s={small:{m:"2g",c:"1",g:""},medium:{m:"",c:"",g:""},large:{m:"8g",c:"4",g:""},gpu:{m:"8g",c:"4",g:"all"}}[e];if(!s)return;const n=(a,i)=>{const o=document.getElementById(a);o&&(o.value=i)};n("quickDockerMemory",s.m),n("quickDockerCpus",s.c),n("quickDockerGpus",s.g)},_collectDockerQuickSettings(){const e=c=>(document.getElementById(c)?.value||"").trim(),t={},s=e("quickDockerMemory");s&&(t.memory=s);const n=e("quickDockerCpus");n&&(t.cpus=n);const a=e("quickDockerGpus");a&&a.toLowerCase()!=="none"&&(t.gpus=a);const i=document.getElementById("quickDockerNetwork")?.value;i&&i!=="bridge"&&(t.network=i);const o=e("quickDockerImage");o&&(t.image=o);const r=document.getElementById("quickDockerMountCreds");return r&&!r.checked&&(t.mountCredentials=!1),t},async linkCase(){const e=document.getElementById("linkCaseName").value.trim(),t=document.getElementById("linkCasePath").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t){this.showToast("Please enter a folder path","error");return}try{const n=await(await fetch("/api/cases/link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,path:t})})).json();n.success?(this.closeCreateCaseModal(),this.showToast(`Case "${e}" linked to ${t}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(n.error||"Failed to link case","error")}catch(s){console.error("Failed to link case:",s),this.showToast("Failed to link case: "+s.message,"error")}},_resetCloneForm(){const e=(o,r)=>{const c=document.getElementById(o);c&&(c.value=r)};e("cloneRepoUrl",""),e("cloneCaseName",""),e("cloneRepoRef","");const t=document.getElementById("cloneShallow");t&&(t.checked=!1);const s=document.getElementById("cloneStartSession");s&&(s.checked=!1);const n=document.getElementById("cloneRepoRefOptions");n&&n.replaceChildren();const a=document.getElementById("cloneRefHint");a&&(a.textContent="Leave blank for the repository's default branch."),this._cloneNameEdited=!1,this._clonePreflight=null,clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");const i=document.getElementById("cloneCaseBrain");if(i){for(const r of i.options){const c=r.dataset.cli;r.hidden=!!c&&!this.isCliAvailable(c)}const o=this.runMode||"claude";i.value=[...i.options].some(r=>r.value===o&&!r.hidden)?o:""}},_setCloneStatus(e,t){const s=document.getElementById("cloneRepoStatus");s&&(s.textContent=e,s.className=`form-hint clone-status${t?" clone-status-"+t:""}`)},_repoNameFromUrl(e){const t=(e||"").trim().replace(/\/+$/,"");return t?(t.replace(/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//,"").replace(/^[^@/]*@/,"").split(/[/:]/).filter(Boolean).pop()||"").replace(/\.git$/i,"").replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/-{2,}/g,"-").replace(/^[-_]+|[-_]+$/g,"").slice(0,64):""},onCloneNameEdited(){this._cloneNameEdited=!!document.getElementById("cloneCaseName")?.value.trim()},onCloneUrlInput(){const e=document.getElementById("cloneRepoUrl")?.value.trim()||"",t=document.getElementById("cloneCaseName");if(t&&!this._cloneNameEdited&&(t.value=this._repoNameFromUrl(e)),clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,!e){this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");return}if(this.isCliAvailable("git")===!1){this._setCloneStatus("git is not installed on the Codeman host, so cloning is unavailable.","err");return}this._setCloneStatus("Checking the repository\u2026",""),this._clonePreflightTimer=setTimeout(()=>this._runClonePreflight(e),450)},async _runClonePreflight(e){const t=new AbortController;this._clonePreflightAbort=t;try{const n=await(await fetch("/api/cases/clone-preflight",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({repository:e}),signal:t.signal})).json();if(document.getElementById("cloneRepoUrl")?.value.trim()!==e)return;if(!n.success){this._setCloneStatus(n.error||"Could not check that URL.","err");return}this._applyClonePreflight(n.data,e)}catch(s){if(s.name==="AbortError")return;this._setCloneStatus("Could not reach Codeman to check that URL.","err")}},_applyClonePreflight(e,t){this._clonePreflight=e;const s=e?.parse;if(!s?.cloneable){this._setCloneStatus(s?.message||"That URL cannot be cloned.","err");return}const n=document.getElementById("cloneCaseName");n&&!this._cloneNameEdited&&s.suggestedName&&(n.value=s.suggestedName);const a=s.owner?`${s.provider} ${s.owner}/${s.repo}`:`${s.provider} ${s.repo}`;if(e.gitAvailable===!1){this._setCloneStatus(`${a}: git is not installed on the Codeman host.`,"err");return}const i=e.remote;if(i&&!i.reachable){this._setCloneStatus(`${a}: ${i.failure?.message||"the remote could not be read."}`,"err");return}const o=document.getElementById("cloneRefHint"),r=document.getElementById("cloneRepoRefOptions");if(i&&r){r.replaceChildren();for(const d of[...i.branches||[],...i.tags||[]]){const l=document.createElement("option");l.value=d,r.appendChild(l)}if(o){const d=`${i.branches?.length||0} branches, ${i.tags?.length||0} tags`;o.textContent=i.defaultBranch?`Blank clones the default branch (${i.defaultBranch}). ${d} available.`:`Blank clones the default branch. ${d} available.`}}const c=s.warnings?.[0];this._setCloneStatus(c?`${a}: ${c}`:`${a}: ready to clone.`,c?"warn":"ok")},async cloneCase(){const e=document.getElementById("cloneRepoUrl").value.trim(),t=document.getElementById("cloneCaseName").value.trim(),s=document.getElementById("cloneRepoRef").value.trim(),n=!!document.getElementById("cloneShallow")?.checked,a=document.getElementById("cloneCaseBrain")?.value||"",i=!!document.getElementById("cloneStartSession")?.checked;if(!e){this.showToast("Please enter a repository URL","error");return}if(!t){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(t)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}this._setCloneStatus(`Cloning ${e}\u2026 this can take a while for a large repository.`,"");try{const r=await(await fetch("/api/cases/clone",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,repository:e,...s?{ref:s}:{},...n?{shallow:!0}:{}})})).json();if(!r.success){this._setCloneStatus(r.error||"Clone failed.","err"),this.showToast(r.error||"Failed to clone repository","error");return}a&&this.setRunMode(a),this.closeCreateCaseModal(),await this.loadQuickStartCases(t),await this.saveLastUsedCase(t),this.showToast(`Cloned into case "${t}"`,"success");for(const c of r.data?.warnings||[])this.showToast(c,"warning");i&&await this.run()}catch(o){console.error("Failed to clone repository:",o),this._setCloneStatus(`Lost the connection while cloning: ${o.message}. If git finishes, the case still appears in the list.`,"warn"),this.showToast("Clone request interrupted \u2014 watch the case list","error")}},openLinkCasePathPicker(){const e=document.getElementById("linkCasePath");PathPicker.open({title:"Select Existing Project Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("linkCaseName");if(!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[\p{L}\p{N}_-]+$/u.test(n)&&(s.value=n)}e.focus(),e.setSelectionRange(t.length,t.length)}})},openDockerWorkspacePathPicker(){const e=document.getElementById("dockerWorkspacePath");PathPicker.open({title:"Select Host Workspace Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("dockerCaseName");if(s&&!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[a-zA-Z0-9_-]+$/.test(n)&&(s.value=n)}}})},openDockerWorkdirPicker(){const e=document.getElementById("dockerAdoptWorkdir"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerHostId")?.value.trim()||"local";if(!t){this.showToast("Enter the container name first","error");return}PathPicker.open({title:`Select Folder Inside ${t}`,initialPath:e.value.trim()||"/",directoriesOnly:!0,fetchListing:async n=>{const a=await this._apiJson("/api/docker-cases/browse",{method:"POST",body:{hostId:s,container:t,path:n||"/"}});return a?a.error?{success:!1,error:a.error}:{success:!0,data:{...a,root:"/",roots:[{label:t,path:"/"}],truncated:!1}}:{success:!1,error:`Could not read ${t}. Is it running?`}},onSelect:n=>{e.value=n}})},async linkRemoteCase(){const e=document.getElementById("remoteCaseName").value.trim(),t=document.getElementById("remoteCasePath").value.trim(),s=document.getElementById("remoteHostId").value.trim(),n=document.getElementById("remoteHostAddress").value.trim(),a=document.getElementById("remoteHostUsername").value.trim(),i=document.getElementById("remoteHostCodexCommand").value.trim(),o=document.getElementById("remoteHostPort").value.trim(),r=document.getElementById("remoteHostIdentityFile").value.trim(),c=document.getElementById("remoteHostSocksProxy").value.trim(),d=document.getElementById("remoteHostJumpHost").value.trim(),l=document.getElementById("remoteHostExtraSshOptions").value.split(`
|
|
16
16
|
`).map(h=>h.trim()).filter(h=>h.length>0);if(!e||!t||!s||!n||!a){this.showToast("Please complete all required remote fields","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Remote path must be absolute","error");return}let m;if(o&&(m=Number(o),!Number.isInteger(m)||m<1||m>65535)){this.showToast("SSH port must be a number between 1 and 65535","error");return}try{const h={id:s,label:s,host:n,username:a,...m?{port:m}:{},...r?{identityFile:r}:{},...c?{socksProxy:c}:{},...d?{jumpHost:d}:{},...l.length?{extraSshOptions:l}:{},...i?{commands:{codex:i}}:{}},u=await(await fetch("/api/remote-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)})).json();if(!u.success&&u.errorCode!=="ALREADY_EXISTS")throw new Error(u.error||"Failed to save remote host");const y=await(await fetch("/api/cases/remote-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,hostId:s,remotePath:t})})).json();y.success?(this.closeCreateCaseModal(),this.showToast(`Remote case "${e}" linked`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(y.error||"Failed to link remote case","error")}catch(h){console.error("Failed to link remote case:",h),this.showToast("Failed to link remote case: "+h.message,"error")}},_syncDockerAdoptMode(){const e=document.getElementById("createCaseModal");if(!e)return;const t=document.getElementById("dockerAdoptExisting")?.checked;t?e.setAttribute("data-docker-adopt","1"):e.removeAttribute("data-docker-adopt"),t&&this._loadDockerContainerOptions()},async _loadDockerContainerOptions(){const e=document.getElementById("dockerContainerList");if(!e)return;const t=document.getElementById("dockerHostId")?.value.trim()||"local";if(e.dataset.loadedFor===t)return;const n=(await this._apiJson(`/api/docker-hosts/${encodeURIComponent(t)}/containers`))?.containers||[];e.textContent="";for(const a of n){const i=document.createElement("option");i.value=a.name,i.textContent=a.running?`${a.image} \xB7 ${a.status}`:`${a.image} \xB7 ${a.status} (not running)`,e.appendChild(i)}e.dataset.loadedFor=t},jumpToDockerAdopt(){this.switchCaseModalTab("case-docker");const e=document.getElementById("dockerAdoptExisting");e&&(e.checked=!0),this._syncDockerAdoptMode(),document.getElementById("dockerContainerName")?.focus()},async _dockerAdoptPreflight(){const e=document.getElementById("dockerLinkStatus"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerAdoptWorkdir")?.value.trim(),n=document.getElementById("dockerHostId").value.trim()||"local";if(!t){e&&(e.textContent="Enter a container name first.");return}e&&(e.textContent="Inspecting container...");const a=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:n,container:t,...s?{containerWorkdir:s}:{}}});if(!e)return;if(!a){e.textContent="Could not reach the docker host profile. Save a Host ID first.";return}if(!a.ok){e.textContent=a.error||"Container is not adoptable.";return}const i=(a.availableModes||[]).filter(o=>o!=="shell");e.textContent=i.length?`Running (${a.image||"unknown image"}). Available: ${i.join(", ")}.`:`Running (${a.image||"unknown image"}), but no agent CLI found inside \u2014 only Shell will work.`},async linkDockerCase(){const e=document.getElementById("dockerCaseName").value.trim(),t=document.getElementById("dockerWorkspacePath").value.trim(),s=document.getElementById("dockerHostId").value.trim()||"local",n=!!document.getElementById("dockerAdoptExisting")?.checked,a=document.getElementById("dockerContainerName")?.value.trim()||"",i=document.getElementById("dockerAdoptWorkdir")?.value.trim()||"",o=document.getElementById("dockerImage").value.trim()||"codeman/agent:base",r=document.getElementById("dockerNetwork").value,c=document.getElementById("dockerMemory").value.trim(),d=document.getElementById("dockerCpus").value.trim(),l=document.getElementById("dockerMountCredentials").checked,m=document.getElementById("dockerResumeOnStart").checked,h=document.getElementById("dockerLinkStatus");if(!e||!t){this.showToast("Please enter a case name and workspace path","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Workspace path must be absolute","error");return}if(n&&!a){this.showToast("Enter the name of the running container to attach to","error");return}try{h&&(h.textContent=n?"Inspecting the existing container...":"Checking docker daemon + base image...");const C={};c&&(C.memory=c),d&&(C.cpus=d);const u={id:s,label:s,image:o,network:r,mountCredentials:l,resumeOnStart:m,...Object.keys(C).length?{resources:C}:{}};let f=await fetch("/api/docker-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await f.json();if(!y.success&&y.errorCode==="ALREADY_EXISTS"&&(f=await fetch(`/api/docker-hosts/${encodeURIComponent(s)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await f.json()),!y.success)throw new Error(y.error||"Failed to save docker host");const p=await(await fetch(n?"/api/cases/docker-adopt":"/api/cases/docker-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n?{name:e,hostId:s,hostWorkspacePath:t,container:a,...i?{containerWorkdir:i}:{}}:{name:e,hostId:s,hostWorkspacePath:t})})).json();if(p.success){this.closeCreateCaseModal();const w=p.data?.capsEnforced===!1?" (resource caps are advisory on this engine)":"",g=(p.data?.availableModes||[]).filter(b=>b!=="shell"),S=n&&g.length?` \u2014 found ${g.join(", ")}`:"";this.showToast(`Docker case "${e}" ${n?"attached":"linked"}${w}${S}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)}else h&&(h.textContent=p.error||"Failed to link docker case"),this.showToast(p.error||"Failed to link docker case","error")}catch(C){console.error("Failed to link docker case:",C),h&&(h.textContent=C.message),this.showToast("Failed to link docker case: "+C.message,"error")}},async refreshDockerExports(){const e=document.getElementById("dockerExportsList");if(e)try{const n=(await(await fetch("/api/docker-exports")).json())?.data?.exports||[];if(n.length===0){e.innerHTML='<span class="form-hint">No exports yet. Export a docker case from its tab.</span>';return}e.innerHTML=n.map(a=>{const i=(a.sizeBytes/1e6).toFixed(1),o=escapeHtml(a.name);return`<div class="case-manage-item" style="display:flex; align-items:center; gap:8px; justify-content:space-between;">
|
|
Binary file
|
|
Binary file
|
|
Binary file
|