@pablopunk/webr 0.3.13 → 0.3.15
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/dist/client/_astro/App.FpiLskEl.js +4 -0
- package/dist/client/_astro/App.L92siqEU.css +1 -0
- package/dist/server/chunks/{App_CKe0Z9nu.mjs → App_HJ7bmNpR.mjs} +88 -16
- package/dist/server/chunks/{_id__Bk-s-r2G.mjs → _id__Dl1xEdu9.mjs} +1 -1
- package/dist/server/chunks/{_tab__BmEFH_DR.mjs → _tab__BXxhjK-Q.mjs} +1 -1
- package/dist/server/chunks/{new_Cpp90K8n.mjs → new_D_b9CCPu.mjs} +1 -1
- package/dist/server/chunks/{settings_CwcEfyk0.mjs → settings_DC2X19WH.mjs} +1 -1
- package/dist/server/entry.mjs +5 -5
- package/package.json +1 -1
- package/server/run.ts +5 -2
- package/server/update/service.ts +108 -0
- package/src/server/host.ts +6 -1
- package/src/server/transport/herdr-target.ts +1 -1
- package/src/shared/update.ts +5 -0
- package/dist/client/_astro/App.8h0zS6BR.css +0 -1
- package/dist/client/_astro/App.VJmP4d0F.js +0 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:JetBrains Mono;src:url(/_astro/jetbrains-mono.CFJaiWaY.woff2)format("woff2");font-weight:100 800;font-style:normal;font-display:swap}@font-face{font-family:Webr Symbols;src:url(/_astro/symbols-nerd.CEdkKAK8.woff2)format("woff2");font-display:swap;unicode-range:U+E0A0-E0D7,U+E5FA-E6B7,U+E700-E7C5,U+F400-F4A8}:root{color-scheme:light;--page:#f8f8f7;--surface:#fff;--surface-raised:#fff;--surface-muted:#f4f4f3;--surface-hover:#f0f0ef;--surface-active:#eaeae9;--sidebar:#f3f3f2;--card-hover:#fff;--card-edge:#1a1d2017;--card-shadow:inset 0 1px 2px #fffffff2, 0 1px 2px #00000029, 0 3px 7px #00000012;--card-shadow-hover:inset 0 1px 2px #fffffff2, 0 2px 4px #0000002b, 0 5px 10px #00000014;--ink:#1b1c1d;--ink-soft:#5b5d61;--ink-muted:#8b8d90;--line:#e9e9e7;--line-strong:#dedfdd;--accent:#357dba;--action-blue:#345fba;--accent-soft:#e9f3fa;--focus-ring:#579bcf;--working:#58a47a;--blocked:#dca362;--danger:#c9534d;--done:#7196ca;--idle:#9a9fa3;--terminal-bg:#fefefd;--terminal-ink:#333639;--terminal-cursor:#555b60;--terminal-selection:#bbd8e8;--shadow:0 1px 2px #1c202308, 0 10px 36px #1c202308;--ease:cubic-bezier(.22, 1, .36, 1);--font-ui:"DM Sans", Inter, system-ui, sans-serif;--font-mono:"JetBrains Mono", "Webr Symbols", ui-monospace, Menlo, monospace}html[data-theme=dark]{color-scheme:dark;--page:#121313;--surface:#1b1c1c;--surface-raised:#202121;--surface-muted:#242626;--surface-hover:#2a2c2c;--surface-active:#333535;--sidebar:#111212;--card-hover:#2b2d2d;--card-edge:#ffffff14;--card-shadow:inset 0 1px 2px #ffffff2b, 0 1px 2px #0000005c, 0 3px 7px #0000002e;--card-shadow-hover:inset 0 1px 2px #ffffff40, 0 2px 4px #00000061, 0 5px 10px #0000002e;--ink:#f1f2f0;--ink-soft:#b1b3b0;--ink-muted:#777b7b;--line:#292b2b;--line-strong:#393b3b;--accent:#91cae8;--action-blue:#365eb9;--accent-soft:#203239;--focus-ring:#9dd5e9;--working:#85cba2;--blocked:#ecc188;--danger:#e07a74;--done:#a0bdec;--idle:#858d8b;--terminal-bg:#181a1a;--terminal-ink:#d8dcda;--terminal-cursor:#d8dcda;--terminal-selection:#37505a;--shadow:0 1px 2px #00000024, 0 10px 36px #0000001f}*,:before,:after{box-sizing:border-box}html{background:var(--page)}body{color:var(--ink);background:var(--page);font:15px/1.45 var(--font-ui);-webkit-font-smoothing:antialiased;margin:0}button,input,textarea,select{font:inherit}button{cursor:pointer}a{color:inherit;text-decoration:none}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:0}.app-shell{min-height:100dvh;display:flex}.main-panel{flex-direction:column;flex:1;min-width:0;height:100dvh;min-height:100dvh;display:flex;overflow-y:auto}.icon-button{width:30px;height:30px;color:var(--ink-muted);background:0 0;border:0;border-radius:6px;flex:none;justify-content:center;align-items:center;display:inline-flex}.icon-button:hover{background:var(--surface-hover);color:var(--ink)}.not-found{max-width:680px;margin:14vh auto 0;padding:25px}.not-found h1{font-size:26px;font-weight:600}.not-found p{color:var(--ink-muted)}.mobile-controls{display:none}@media (width<=760px){.mobile-controls{z-index:8;top:max(10px, env(safe-area-inset-top));left:max(12px, env(safe-area-inset-left));right:max(12px, env(safe-area-inset-right));pointer-events:none;justify-content:space-between;display:flex;position:fixed}.mobile-controls button{border:1px solid var(--line);background:var(--sidebar);width:48px;height:48px;box-shadow:var(--card-shadow);color:var(--ink-soft);pointer-events:auto;touch-action:manipulation;border-radius:50%;place-items:center;display:grid}.mobile-controls button:active{background:var(--surface-hover)}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important}}@media (pointer:coarse){.app-shell.is-thread{top:var(--app-top,0px);height:var(--app-height,100dvh);min-height:0;position:fixed;left:0;right:0;overflow:hidden}.app-shell.is-thread .main-panel{height:100%;min-height:0;padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}html:has(.app-shell.is-thread),html:has(.app-shell.is-thread) body{overscroll-behavior:none}}.sidebar{border-right:1px solid var(--line);background:var(--sidebar);flex-direction:column;flex:0 0 280px;min-width:0;height:100dvh;display:flex;position:sticky;top:0}.sidebar.is-collapsed{flex-basis:44px}.sidebar-header{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;height:48px;padding:0 10px 0 16px;display:flex}.sidebar.is-collapsed .sidebar-header{justify-content:center;padding:0}.brand{letter-spacing:-.02em;align-items:center;gap:7px;font-size:14px;font-weight:700;display:inline-flex}.sidebar-collapse{width:26px;height:26px}.sidebar-actions{flex:none;align-items:center;gap:5px;margin:12px 8px 4px;display:flex}.sidebar-new-thread{border:1px solid var(--card-edge);background:var(--surface-raised);height:34px;box-shadow:var(--card-shadow);color:var(--ink);border-radius:7px;flex:none;justify-content:center;align-items:center;gap:6px;padding:0 10px;font-size:13px;font-weight:600;transition:background-color .2s,box-shadow .2s;display:inline-flex}.sidebar-new-thread span{transform:translateY(1px)}.sidebar-new-thread:hover{background:var(--card-hover);box-shadow:var(--card-shadow-hover)}.sidebar.is-collapsed .sidebar-actions{justify-content:center;margin:10px 0 0}.sidebar.is-collapsed .sidebar-new-thread{width:28px;height:28px;padding:0}.sidebar-open-worktree{border:1px solid var(--card-edge);background:var(--surface-raised);width:34px;height:34px;box-shadow:var(--card-shadow);color:var(--ink-soft);border-radius:7px;flex:none;place-items:center;padding:0;display:grid}.sidebar-open-worktree:hover:not(:disabled){background:var(--card-hover);box-shadow:var(--card-shadow-hover);color:var(--ink)}.sidebar.is-collapsed .sidebar-actions{flex-direction:column}.sidebar.is-collapsed .sidebar-open-worktree{width:28px;height:28px}.sidebar-view-switch{border:1px solid var(--line);background:var(--surface-muted);border-radius:7px;flex:none;gap:2px;width:70px;height:34px;margin-left:auto;padding:2px;display:flex}.sidebar-view-switch button{min-width:0;color:var(--ink-soft);background:0 0;border:1px solid #0000;border-radius:5px;flex:1;place-items:center;padding:0;display:grid}.sidebar-view-switch button:hover{color:var(--ink);background:var(--surface-hover)}.sidebar-view-switch button[aria-pressed=true]{border-color:var(--card-edge);background:var(--surface-raised);box-shadow:var(--card-shadow);color:var(--ink)}.thread-navigation{scrollbar-width:thin;flex:1;padding:8px;overflow-y:auto}.thread-row{min-height:60px;color:var(--ink-soft);border:1px solid #0000;border-radius:7px;grid-template-rows:17px 1fr;grid-template-columns:25px minmax(0,1fr) auto;column-gap:9px;padding:7px 10px;font-size:13.5px;transition:background-color .2s,border-color .2s,box-shadow .2s;display:grid}.thread-item{display:block;position:relative}.thread-item+.thread-item{margin-top:4px}.thread-archive{width:26px;height:26px;color:var(--ink-soft);opacity:0;pointer-events:none;background:0 0;border:0;border-radius:5px;place-items:center;padding:0;transition:opacity .15s,background-color .15s;display:grid;position:absolute;top:50%;right:9px;transform:translateY(-50%)}.thread-item:hover .thread-archive,.thread-archive:focus-visible{opacity:1;pointer-events:auto}.thread-archive:hover{background:var(--surface-hover);color:var(--ink)}.thread-item:hover .thread-time,.thread-item:focus-within .thread-time{visibility:hidden}@media (hover:none){.thread-archive{opacity:1;pointer-events:auto}.thread-item .thread-time{visibility:hidden}}.thread-menu-positioner{z-index:30}.thread-menu{border:1px solid var(--card-edge);background:var(--surface-raised);min-width:180px;color:var(--ink);box-shadow:var(--card-shadow-hover), 0 12px 32px #0000002e;border-radius:8px;outline:0;padding:4px}.thread-menu-item{cursor:pointer;border-radius:5px;outline:0;align-items:center;gap:8px;min-height:32px;padding:6px 8px;font-size:14px;display:flex}.thread-menu-item[data-highlighted]{background:var(--surface-hover)}.worktree-menu{width:260px;padding:0;overflow:hidden}.worktree-menu-list{max-height:min(320px, var(--available-height));padding:4px;overflow-y:auto}.worktree-menu-note{color:var(--ink-soft);margin:0;padding:8px;font-size:14px}.thread-menu-item>svg,.thread-menu-item>.thread-project{flex:none}.worktree-menu-name{overflow-wrap:anywhere;min-width:0;display:grid}.worktree-menu-name small{color:var(--ink-soft);font-size:12.5px}.worktree-menu-chevron{color:var(--ink-soft);margin-left:auto}.thread-menu-path{border-top:1px solid var(--line);max-width:240px;color:var(--ink-muted);text-overflow:ellipsis;white-space:nowrap;user-select:text;margin-top:4px;padding:6px 8px 4px;font-size:13px;overflow:hidden}.thread-menu-item.is-danger{color:var(--danger)}.archived-threads{border-top:1px solid var(--line);scrollbar-width:thin;flex:none;max-height:45%;padding:6px 8px;overflow-y:auto}.archived-threads .group-header{z-index:1;background:var(--sidebar);position:sticky;top:-6px}.group-count{font:10px var(--font-mono);color:var(--ink-muted);margin-left:2px}.archived-delete-all{height:26px;color:var(--ink-soft);background:0 0;border:1px solid #0000;border-radius:5px;flex:none;margin-right:4px;padding:0 8px;font-size:13px}.archived-delete-all:hover:not(:disabled){border-color:var(--line);background:var(--surface-hover);color:var(--danger)}.archived-delete-all:disabled{opacity:.6}.thread-avatar{grid-area:1/1/3;justify-content:center;align-self:center;align-items:center;width:25px;height:25px;display:inline-flex;position:relative}.thread-row:hover,.thread-row.is-current:hover{border-color:var(--card-edge);background:var(--card-hover);box-shadow:var(--card-shadow-hover);color:var(--ink)}.thread-row.needs-attention.status-blocked{--attention-bg:color-mix(in srgb, var(--blocked) 10%, var(--sidebar));border-color:var(--card-edge);background:var(--attention-bg);box-shadow:var(--card-shadow)}.thread-row.needs-attention.status-done{--attention-bg:color-mix(in srgb, var(--done) 10%, var(--sidebar));border-color:var(--card-edge);background:var(--attention-bg);box-shadow:var(--card-shadow)}.thread-row.needs-attention .thread-status,.thread-row.needs-attention .thread-avatar-harness{background:var(--attention-bg)}.thread-row.is-current{border-color:var(--card-edge);background:var(--surface-raised);box-shadow:var(--card-shadow);color:var(--ink)}.thread-row.is-current:hover{background:var(--card-hover);box-shadow:var(--card-shadow-hover)}.thread-copy{flex-direction:column;grid-area:1/2/3;justify-content:center;gap:4px;min-width:0;display:flex}.thread-context{color:var(--ink-soft);align-items:center;gap:5px;font-size:12px;display:flex}.thread-name{white-space:nowrap;text-overflow:ellipsis;color:var(--ink);overflow:hidden}.thread-name-input{border:1px solid var(--focus-ring);background:var(--surface);width:100%;min-width:0;color:var(--ink);font:inherit;border-radius:4px;outline:0;margin:-2px -4px;padding:1px 4px}.thread-time{font:10px var(--font-mono);color:var(--ink-soft);grid-area:1/3;justify-self:end}.thread-status{background:var(--sidebar);color:var(--ink-soft);border-radius:50%;padding:1px;position:absolute;top:-5px;left:-5px}.thread-avatar-harness{background:var(--sidebar);border-radius:5px;padding:1.5px;display:grid;position:absolute;bottom:-6px;right:-6px}.thread-row.is-current .thread-avatar-harness{background:var(--surface-raised)}.thread-row:hover .thread-avatar-harness{background:var(--card-hover)}.thread-row.is-current .thread-status{background:var(--surface-raised)}.thread-row:hover .thread-status{background:var(--card-hover)}.thread-status.status-blocked{color:var(--blocked)}.thread-status.status-done{color:var(--done)}.thread-project{background:color-mix(in srgb, var(--project-color) 17%, transparent);width:17px;height:17px;color:var(--project-color);font:700 10px var(--font-mono);border-radius:3px;flex:none;place-items:center;display:grid;position:relative;overflow:hidden}.thread-project img{object-fit:contain;background:var(--surface-raised);opacity:0;width:100%;height:100%;position:absolute;inset:0}.thread-project.has-icon img{opacity:1}.group-header{align-items:center;min-width:0;display:flex}.group-title{min-width:0;color:var(--ink-soft);text-align:left;background:0 0;border:0;border-radius:5px;flex:1;align-items:center;gap:6px;padding:8px;font-size:13px;display:flex}.group-title:hover{color:var(--ink)}.thread-group{border-radius:7px}.thread-group:has(>.group-header:hover){background:var(--surface-hover)}.group-name{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.group-chevron{flex:none;justify-content:center;align-items:center;width:12px;height:17px;display:inline-flex}.thread-group+.thread-group{margin-top:8px}.sidebar-footer{border-top:1px solid var(--line);flex:none;align-items:center;gap:8px;padding:4px 12px 4px 4px;display:flex}.sidebar-settings{height:35px;color:var(--ink-soft);border-radius:6px;flex:1;align-items:center;gap:10px;padding:0 12px;font-size:13.5px;display:flex}.sidebar-palette{border:1px solid var(--line-strong);color:var(--ink-soft);background:0 0;border-radius:4px;justify-content:center;align-items:center;padding:3px 6px;display:inline-flex}.sidebar-palette:hover{color:var(--ink);background:var(--surface-hover)}.sidebar-palette kbd{font:10px/1 var(--font-mono)}.sidebar-update{background:var(--accent-soft);color:var(--accent);border:0;border-radius:4px;flex:none;align-items:center;gap:5px;padding:3px 8px;font-size:12px;display:inline-flex}.sidebar-update:hover:not(:disabled){filter:brightness(1.08)}.sidebar-update:disabled{opacity:.7}.sidebar-settings:hover{color:var(--ink);background:var(--surface-hover)}.sidebar-empty{color:var(--ink-muted);padding:8px;font-size:13px}.sidebar-scrim,.mobile-close{display:none}@media (width<=760px){.sidebar,.sidebar.is-collapsed{z-index:11;flex-basis:auto;width:min(280px,86vw);transition:transform .2s;position:fixed;transform:translate(-100%)}.sidebar.is-mobile-open{transform:translate(0)}.sidebar.is-collapsed .sidebar-header{justify-content:space-between;padding:0 10px 0 16px}.sidebar.is-collapsed .thread-navigation,.sidebar.is-collapsed .sidebar-footer{display:flex}.mobile-close{display:inline-flex}.sidebar-collapse{display:none}.sidebar-footer{padding:6px 12px calc(14px + env(safe-area-inset-bottom)) 8px}.sidebar-settings{min-height:44px;font-size:17px}.sidebar-scrim{z-index:10;background:#00000073;border:0;display:block;position:fixed;inset:0}}.thread-worktree{opacity:.7;flex:none}.form-page{width:min(760px,100%);margin:8vh auto 0;padding:0 20px 60px}.form-page h1{letter-spacing:-.03em;margin:0 0 26px;font-size:28px;font-weight:600}.form-error{color:#d16a64;font-size:14px}.settings-page section{margin-top:28px}.settings-page h2{margin:18px 0 8px;font-size:16px;font-weight:600}.settings-row{justify-content:space-between;align-items:center;gap:12px;min-height:48px;font-size:16px;display:flex}.settings-section-title{justify-content:space-between;align-items:center;display:flex}.settings-section-title button{color:var(--ink-soft);background:0 0;border:0;border-radius:5px;padding:6px 9px;font-size:15px}.settings-section-title button:hover{background:var(--surface-hover)}.settings-section-title button:hover,.shortcut-key:hover{color:var(--ink)}.shortcut-key{min-height:32px;color:var(--ink-soft);background:0 0;border:0;align-items:center;gap:4px;padding:3px 0;font-size:15px;display:inline-flex}.shortcut-key kbd{background:var(--surface-raised);min-width:30px;height:30px;box-shadow:var(--card-shadow);color:var(--ink-soft);font:13px var(--font-mono);border:0;border-radius:5px;place-items:center;padding:0 5px;display:inline-grid}.shortcut-key:hover kbd,.shortcut-key:focus-visible kbd{color:var(--ink);background:var(--card-hover);box-shadow:var(--card-shadow-hover)}.shortcut-key[data-recording=true]{box-shadow:inset 0 0 0 1px var(--focus-ring);color:var(--ink);border-radius:5px;padding:3px 8px}.settings-note{color:var(--ink-soft);margin:0 0 10px;font-size:15px}.theme-control{background:var(--surface-muted);border-radius:7px;gap:2px;padding:2px;display:flex}.theme-option{color:var(--ink-soft);text-transform:capitalize;background:0 0;border:0;border-radius:5px;align-items:center;gap:5px;padding:8px 10px;font-size:15px;display:flex}.theme-option:hover{color:var(--ink)}.theme-option.is-selected{background:var(--surface-raised);box-shadow:var(--card-shadow);color:var(--ink)}.theme-control--labels .theme-option{text-transform:none}.mobile-menu{display:none}@media (width<=760px){.form-page{margin-top:35px}.mobile-menu{color:var(--ink-soft);background:0 0;border:0;margin-bottom:30px;padding:4px 0;display:block}}.new-thread-page{flex-direction:column;justify-content:center;width:min(800px,100%);min-height:100dvh;margin:0 auto;padding:60px 20px;display:flex;position:relative}.new-thread-page h1{color:var(--ink);letter-spacing:-.035em;text-align:center;margin:0 0 26px;font-size:clamp(24px,2.8vw,32px);font-weight:500;line-height:1.25}.thread-composer{border:1px solid var(--line-strong);background:var(--surface);box-shadow:var(--card-shadow);border-radius:18px;transition:border-color .2s,box-shadow .2s}.thread-composer:focus-within{border-color:color-mix(in srgb, var(--focus-ring) 50%, var(--line-strong));box-shadow:var(--card-shadow-hover)}.workspace-composer{gap:12px;padding:18px;display:grid}.workspace-composer label{color:var(--ink-soft);gap:6px;font-size:14px;display:grid}.workspace-composer input{border:1px solid var(--line-strong);width:100%;color:var(--ink);background:0 0;border-radius:8px;padding:10px}.workspace-composer button{justify-self:end;padding:8px 12px}.workspace-composer .path-field{position:relative}.path-suggestions{z-index:5;border:1px solid var(--card-edge);background:var(--surface-raised);box-shadow:var(--card-shadow-hover);border-radius:8px;max-height:240px;margin:4px 0 0;padding:4px;list-style:none;position:absolute;top:100%;left:0;right:0;overflow-y:auto}.path-suggestions li{color:var(--ink);cursor:pointer;border-radius:5px;padding:6px 8px;font-size:15px}.path-suggestions li[data-highlighted]{background:var(--surface-hover)}.workspace-cancel{color:var(--ink-soft);background:0 0;border:0;border-radius:6px;align-self:center;padding:8px 12px}.workspace-cancel:hover{background:var(--surface-hover);color:var(--ink)}.thread-composer textarea{resize:vertical;width:100%;min-height:94px;max-height:45vh;color:var(--ink);background:0 0;border:0;outline:0;padding:17px 18px 0;font-size:16px;line-height:1.5;display:block}.thread-composer textarea::placeholder{color:var(--ink-muted)}.composer-toolbar{align-items:center;gap:10px;padding:9px 12px 12px;display:flex}.composer-selectors{flex-wrap:wrap;align-items:center;gap:3px;min-width:0;display:flex}.composer-actions{flex:none;align-items:center;gap:5px;margin-left:auto;display:inline-flex}.composer-preview-note{color:var(--ink-soft);text-align:center;margin:12px 0 0;font-size:13px}.worktree-option{width:30px;height:32px;color:var(--ink-soft);cursor:pointer;border-radius:6px;place-items:center;display:inline-grid;position:relative}.worktree-option:hover{color:var(--ink);background:var(--surface-hover)}.worktree-option:focus-within{outline:0}.worktree-option input{opacity:0;width:1px;height:1px;position:absolute}.worktree-option:has(input:not(:checked)){color:var(--ink-muted)}.worktree-option:has(input:checked){background:var(--surface-muted);color:var(--ink)}.composer-send{background:var(--action-blue);color:#fff;border:0;border-radius:50%;flex:none;place-items:center;width:36px;height:36px;display:inline-grid}.composer-send:hover:not(:disabled){filter:brightness(1.12)}.composer-send:disabled{background:var(--surface-active);color:var(--ink-muted);cursor:not-allowed}.new-thread-page .form-error{margin:12px 4px}@media (width<=760px){.new-thread-page{padding:60px 16px}.new-thread-page .mobile-menu{margin:0;position:absolute;top:16px;left:16px}}@media (width<=480px){.composer-toolbar{gap:6px;padding:8px}}.thread-composer.is-dropping{border-style:dashed;border-color:var(--focus-ring);box-shadow:var(--card-shadow-hover)}.composer-images{flex-wrap:wrap;gap:8px;margin:0;padding:14px 18px 0;list-style:none;display:flex}.composer-images li{border:1px solid var(--line-strong);background:var(--surface-raised);border-radius:9px;width:56px;height:56px;position:relative;overflow:hidden}.composer-images img{object-fit:cover;width:100%;height:100%;display:block}.composer-images li.is-file{color:var(--ink-muted);place-content:center;justify-items:center;gap:3px;padding:4px;display:grid}.composer-images li.is-file span{text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:10px;overflow:hidden}.composer-images button{background:color-mix(in srgb, var(--surface) 85%, transparent);width:18px;height:18px;color:var(--ink);cursor:pointer;opacity:0;border:0;border-radius:50%;place-items:center;padding:0;transition:opacity .15s;display:grid;position:absolute;top:3px;right:3px}.composer-images li:hover button,.composer-images button:focus-visible{opacity:1}.composer-images li.is-uploading{background:linear-gradient(100deg, var(--surface-raised) 30%, var(--surface-hover) 50%, var(--surface-raised) 70%) 0 0 / 200% 100%;animation:1.1s linear infinite composer-image-loading}@keyframes composer-image-loading{to{background-position:-200% 0}}@media (hover:none){.composer-images button{opacity:1}}.composer-select{min-width:0;max-width:min(220px,100%);height:32px;color:var(--ink-soft);background:0 0;border:1px solid #0000;border-radius:6px;justify-content:flex-start;align-items:center;gap:5px;padding:0 6px;font-size:13px;display:inline-flex}.composer-select:hover,.composer-select[data-popup-open]{border-color:var(--line);background:var(--surface-hover);color:var(--ink)}.composer-select-icon{flex:none;justify-content:center;align-items:center;display:inline-flex}.composer-select-icon .thread-project{width:14px;height:14px}.harness-icon{color:var(--ink);flex:none;place-items:center;display:inline-grid}.harness-icon svg{width:100%;height:100%}.harness-icon-letter{font:700 10px var(--font-mono)}.composer-select-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}.composer-select-caret{flex:none;margin-left:8px}.composer-select-positioner{z-index:20}.composer-select-popup{width:min(280px, var(--available-width));max-height:var(--available-height);border:1px solid var(--card-edge);background:var(--surface-raised);color:var(--ink);box-shadow:var(--card-shadow-hover), 0 12px 32px #0000002e;border-radius:9px;overflow:hidden}.composer-select-search{border-bottom:1px solid var(--line);color:var(--ink-soft);align-items:center;gap:8px;padding:10px 12px;display:flex}.composer-select-search input{width:100%;min-width:0;color:var(--ink);background:0 0;border:0;outline:0;padding:0;font-size:16px;line-height:1.4}.composer-select-search input::placeholder{color:var(--ink-soft)}.composer-select-list{max-height:min(240px, calc(var(--available-height) - 50px));overscroll-behavior:contain;padding:5px;overflow-y:auto}.composer-select-option{cursor:pointer;border-radius:5px;align-items:center;gap:8px;min-height:36px;padding:8px;font-size:14px;display:flex}.composer-select-option[data-highlighted]{background:var(--surface-hover);outline:0}.composer-select-option[data-disabled]{opacity:.5;cursor:not-allowed}.composer-select-option-icon{flex:none;align-items:center;display:inline-flex}.composer-select-option-label{overflow-wrap:anywhere;flex:1;min-width:0}.composer-select-check{color:var(--ink-soft);flex:none;display:inline-flex}.composer-select-action{border:0;border-top:1px solid var(--line);width:calc(100% - 10px);min-height:36px;color:var(--ink);text-align:left;background:0 0;border-radius:5px;align-items:center;gap:8px;margin:2px 5px 5px;padding:8px;font-size:14px;display:flex}.composer-select-action:hover{background:var(--surface-hover)}.composer-select-empty{color:var(--ink-soft);font-size:14px}.composer-select-empty:not(:empty){padding:12px}@media (width>=761px){.composer-select-search input{font-size:14px}}@media (width<=480px){.composer-select-icon{display:none}}.pane-layout{background:var(--line-strong);grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;height:100dvh;min-height:0;display:grid}.pane-layout.single-pane{grid-template-columns:minmax(0,1fr)}.terminal-pane{background:var(--terminal-bg);min-width:0;min-height:0;overflow:hidden}.terminal-host{width:100%;height:100%}.terminal-host .xterm{height:100%;padding:12px 8px 8px 13px}.terminal-host .xterm-viewport{scrollbar-width:thin}@media (width<=760px){.pane-layout:not(.single-pane){grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:minmax(0,1fr)}}.native-thread-layout{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.pane-strip,.pane-tabbed{flex:1;min-width:0;min-height:160px;display:flex;position:relative}.pane-tabbed{flex-direction:column}.pane-slot{flex:1 1 0;min-width:0;min-height:0;padding:2px;position:relative}.pane-slot .terminal-pane{flex-direction:column;height:100%;display:flex}.pane-strip.is-split .terminal-pane{outline:1px solid var(--line);outline-offset:-1px;border-radius:5px;transition:outline-color .15s}.pane-strip.is-split .terminal-pane.is-active{outline-color:color-mix(in srgb, var(--focus-ring) 15%, var(--line-strong))}.pane-collapsed{background:var(--surface-muted);color:var(--ink-soft);border:0;border-radius:6px;flex-direction:column;flex:0 0 24px;justify-content:center;align-items:center;gap:6px;margin:2px;padding:8px 0;font-size:13px;transition:background-color .15s,color .15s;display:flex;overflow:hidden}.pane-collapsed:hover,.pane-collapsed:focus-visible{background:var(--surface-hover);color:var(--ink)}.pane-collapsed span{writing-mode:vertical-rl;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pane-tabs{scrollbar-width:none;align-items:center;gap:4px;min-height:48px;margin:0 64px;display:flex;overflow-x:auto}.pane-tab{max-width:160px;color:var(--ink-soft);background:0 0;border:0;border-radius:6px;flex:none;align-items:center;gap:6px;padding:6px 10px;font-size:14px;display:flex}.pane-tab span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pane-tab[aria-selected=true]{background:var(--surface-muted);color:var(--ink)}.terminal-host{flex:1;height:auto;min-height:0;overflow:hidden}.terminal-pane{position:relative}.terminal-input-capture{opacity:.01;resize:none;border:0;width:2px;height:2px;padding:0;position:absolute;bottom:8px;left:12px}.terminal-status{clip-path:inset(50%);width:1px;height:1px;position:absolute;overflow:hidden}.terminal-control-conflict{z-index:10;border:1px solid var(--line-strong);background:var(--surface-raised);max-width:calc(100% - 16px);color:var(--ink-soft);box-shadow:var(--card-shadow);white-space:nowrap;border-radius:8px;align-items:center;gap:10px;padding:6px 10px;display:flex;position:absolute;top:8px;left:50%;transform:translate(-50%)}.terminal-control-conflict button{background:var(--surface-hover);color:var(--ink);border:0;border-radius:5px;padding:3px 7px}.runtime-notice{color:var(--ink-muted);padding:10px 16px;font-size:15px}.launch-progress{align-content:center;justify-items:start;gap:18px;width:min(520px,100%);height:100%;margin:0 auto;padding:0 20px;display:grid}.launch-progress h1{letter-spacing:-.03em;margin:0;font-size:22px;font-weight:600}.launch-prompt{border-left:2px solid var(--line-strong);color:var(--ink-soft);white-space:pre-wrap;overflow-wrap:anywhere;max-height:9em;margin:0;padding:10px 14px;font-size:15px;overflow:auto}.launch-steps{gap:10px;margin:0;padding:0;font-size:15px;list-style:none;display:grid}.launch-step{color:var(--ink-muted);align-items:center;gap:10px;display:flex}.launch-step.is-done{color:var(--ink-soft)}.launch-step.is-active{color:var(--ink)}.launch-step.is-active svg{animation:1s linear infinite launch-spin}.launch-step.is-failed{color:#d16a64}.launch-failure{color:var(--ink-soft);gap:10px;font-size:15px;display:grid}.launch-failure p{margin:0}.launch-retry{border:1px solid var(--line-strong);background:var(--surface-raised);color:var(--ink);border-radius:7px;justify-self:start;padding:7px 11px;font-size:14px;text-decoration:none}@keyframes launch-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.launch-step.is-active svg{animation:none}}.terminal-host .xterm{font-variant-ligatures:none;font-feature-settings:"liga" 0, "calt" 0}.terminal-drop-overlay{z-index:15;border:1.5px dashed var(--line-strong);background:color-mix(in srgb, var(--terminal-bg) 82%, transparent);color:var(--ink);pointer-events:none;border-radius:10px;place-content:center;justify-items:center;gap:8px;font-size:15px;display:grid;position:absolute;inset:8px}.terminal-attach-notice{z-index:16;border:1px solid var(--line-strong);background:var(--surface-raised);max-width:calc(100% - 28px);box-shadow:var(--card-shadow);color:var(--ink-soft);border-radius:8px;padding:6px 10px;font-size:14px;position:absolute;bottom:12px;right:14px}.terminal-attach-notice.is-error{color:#d16a64}.terminal-key-bar{padding:6px 8px calc(6px + env(safe-area-inset-bottom));border-top:1px solid var(--line);background:var(--surface-muted);flex:none;gap:6px;display:flex}:root[data-keyboard-open] .terminal-key-bar{padding-bottom:6px}.terminal-key-bar button{background:var(--surface-raised);min-height:38px;box-shadow:var(--card-shadow);color:var(--ink);touch-action:manipulation;-webkit-user-select:none;user-select:none;border:0;border-radius:8px;flex:1;place-items:center;font-size:15px;display:inline-grid}.terminal-key-bar button.is-armed{background:var(--action-blue);color:#fff}.terminal-key-bar .terminal-voice.is-recording{background:var(--danger);color:#fff}.terminal-key-bar .terminal-voice .is-spinning{animation:1s linear infinite launch-spin}::view-transition-group(.pane-move),::view-transition-group(.pane-enter),::view-transition-group(.pane-exit){animation-duration:.22s;animation-timing-function:cubic-bezier(.2,.8,.2,1);overflow:clip}::view-transition-old(.pane-move),::view-transition-new(.pane-move){object-fit:none;object-position:left top;height:100%;animation-duration:.22s}::view-transition-new(.pane-enter){animation:.22s cubic-bezier(.2,.8,.2,1) pane-enter}::view-transition-old(.pane-exit){animation:.16s ease-in forwards pane-exit}@keyframes pane-enter{0%{opacity:0;transform:translate(24px)}}@keyframes pane-exit{to{opacity:0;transform:scale(.98)}}@media (prefers-reduced-motion:reduce){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}}.palette-overlay{z-index:30;background:#0000006e;justify-content:center;align-items:flex-start;padding:min(16vh,140px) 16px 16px;display:flex;position:fixed;inset:0}.palette{border:1px solid var(--card-edge);background:var(--surface);border-radius:9px;width:min(520px,100%);overflow:hidden;box-shadow:inset 0 1px 2px #ffffff1f,0 16px 60px #00000038}.palette>input{border:0;border-bottom:1px solid var(--line);width:100%;height:48px;color:var(--ink);background:0 0;outline:0;padding:0 16px;font-size:15px;display:block}.palette>input::placeholder{color:var(--ink-muted)}.palette-results{max-height:min(400px,55vh);padding:6px;overflow-y:auto}.palette-results button{width:100%;min-height:36px;color:var(--ink);text-align:left;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:10px;padding:0 10px;font-size:14px;transition:background-color .2s,border-color .2s,box-shadow .2s;display:flex}.palette-icon{width:22px;height:22px;color:var(--ink-soft);flex:none;justify-content:center;align-items:center;display:inline-flex}.palette-label{white-space:nowrap;text-overflow:ellipsis;flex:1;overflow:hidden}.palette-results button:hover,.palette-results button.is-selected{border-color:var(--card-edge);background:var(--surface-raised);box-shadow:var(--card-shadow)}.palette-results button:hover{background:var(--card-hover);box-shadow:var(--card-shadow-hover)}.palette-results button small{color:var(--ink-soft);white-space:nowrap;font-size:12px}.palette-results button kbd{border:1px solid var(--line-strong);min-width:34px;color:var(--ink-soft);font:10px var(--font-mono);text-align:center;white-space:nowrap;border-radius:4px;margin-left:6px;padding:3px 5px}.palette-results p{color:var(--ink-muted);padding:4px 10px}.palette-help{border-top:1px solid var(--line);color:var(--ink-soft);font:10px var(--font-mono);gap:14px;padding:9px 14px;display:flex}.dialog-backdrop{z-index:40;background:#0000006e;position:fixed;inset:0}.dialog{z-index:41;border:1px solid var(--card-edge);background:var(--surface);width:min(400px,100vw - 32px);color:var(--ink);border-radius:10px;outline:0;padding:18px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:inset 0 1px 2px #ffffff1f,0 16px 60px #00000038}.dialog-message{margin:0 0 16px;font-size:15px;line-height:1.5}.dialog-actions{justify-content:flex-end;gap:8px;display:flex}.dialog-button{border:1px solid var(--line-strong);background:var(--surface-raised);min-height:32px;color:var(--ink);cursor:pointer;border-radius:6px;padding:0 12px;font-size:14px}.dialog-button:hover{background:var(--surface-hover)}.dialog-button.is-primary{background:var(--action-blue);color:#fff;border-color:#0000}.dialog-button.is-danger{background:var(--danger)}.icon-dropzone{border:1.5px dashed var(--line-strong);width:100%;min-height:120px;color:var(--ink);cursor:pointer;background:0 0;border-radius:8px;align-content:center;place-items:center;gap:8px;margin:0 0 16px;font-size:14px;display:grid}.icon-current{color:var(--ink-muted);align-items:center;gap:8px;margin:0 0 12px;font-size:13px;display:flex}.icon-candidates{grid-template-columns:repeat(auto-fill,48px);gap:8px;margin:0 0 16px;display:grid}.icon-candidate{border:1px solid var(--line-strong);cursor:pointer;background:0 0;border-radius:8px;place-items:center;width:48px;height:48px;padding:6px;display:grid}.icon-candidate:hover:not(:disabled){background:var(--surface-hover);border-color:var(--action-blue)}.icon-candidate img{object-fit:contain;max-width:100%;max-height:100%}.icon-dropzone:hover,.icon-dropzone.is-dragging{background:var(--surface-hover);border-color:var(--action-blue)}.pairing-title{margin:0 0 6px;font-size:16px;font-weight:600}.pairing-code{font:700 40px/1 var(--font-mono);letter-spacing:.18em;text-align:center;text-indent:.18em;margin:0 0 16px}.pairing-invite .dialog-message code{font-family:var(--font-mono)}.qr-code{aspect-ratio:1;border-radius:8px;width:min(240px,100%);margin:0 auto 14px;display:block}.pairing-token{justify-content:center;align-items:center;gap:8px;margin:0 0 6px;display:flex}.pairing-token code{font:600 14px var(--font-mono);letter-spacing:.08em;user-select:all}.pairing-token .dialog-button{place-items:center;min-width:32px;padding:0;display:inline-grid}.device-tag{background:var(--accent-soft);color:var(--accent);border-radius:4px;margin-left:8px;padding:1px 6px;font-size:12px;font-style:normal}.device-meta{color:var(--ink-muted);font-size:15px;display:block}.crash-report{z-index:100;color:#7a1f1a;max-height:60dvh;font:11px/1.4 var(--font-mono);white-space:pre-wrap;word-break:break-word;background:#fff0ef;margin:0;padding:12px 16px;position:fixed;inset:0 0 auto;overflow:auto}.pairing-invite .theme-control{flex-wrap:wrap;justify-content:center;margin:0 0 12px}.pairing-invite .theme-option{white-space:nowrap}.settings-subtitle{color:var(--ink-soft);margin:16px 0 4px;font-size:15px;font-weight:500}.activity-row{color:var(--ink-muted);justify-content:space-between;gap:12px;margin:0;padding:4px 0;font-size:15px;display:flex}.activity-row time{flex:none}.tailscale-callout{border:1px solid var(--line,currentColor);color:var(--ink-soft);border-radius:6px;margin:0 0 10px;padding:8px 10px;font-size:13px;line-height:1.45}.perf-overlay{z-index:40;color:#d7ffd7;font-variant-numeric:tabular-nums;pointer-events:none;background:#000000c7;border-radius:6px;padding:4px 8px;font:11px/1.5 ui-monospace,monospace;position:fixed;bottom:8px;right:8px}.tooltip-positioner{z-index:40}.tooltip-popup{border:1px solid var(--line);background:var(--surface-raised);box-shadow:var(--card-shadow);color:var(--ink);white-space:nowrap;border-radius:6px;padding:5px 8px;font-size:13px;font-weight:500;transition:opacity .16s,transform .16s}.tooltip-popup[data-starting-style],.tooltip-popup[data-ending-style]{opacity:0;transform:translateY(3px)}::view-transition-group(root),::view-transition-old(root),::view-transition-new(root){mix-blend-mode:normal;animation:none}.astro-route-announcer{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;top:0;left:0;overflow:hidden}.xterm{cursor:text;-webkit-user-select:none;-ms-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:underline double}.xterm-underline-3{text-decoration:underline wavy}.xterm-underline-4{text-decoration:underline dotted}.xterm-underline-5{text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S as createAstro, f as renderHead, i as renderComponent, m as createRenderInstruction, p as addAttribute, s as renderSlot, u as renderTemplate } from "./server_dfdLOyV2.mjs";
|
|
2
2
|
import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
|
|
3
3
|
import { ViewTransition, createContext, memo, useCallback, useContext, useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { Archive, ArchiveRestore, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bot, Check, ChevronDown, ChevronRight, Circle, CircleAlert, CircleCheck, CircleHelp, Command, Copy, Cpu, FileText, Folder, FolderTree, GitBranch, ImagePlus, ImageUp, LayoutList, LoaderCircle, MessageCircleQuestion, Mic, Monitor, Moon, PanelLeft, PanelLeftClose, PanelLeftOpen, Pencil, Plus, Search, Server, Settings2, Square, SquarePen, SquareTerminal, Sun, TerminalSquare, Trash2, TriangleAlert, X } from "lucide-react";
|
|
4
|
+
import { Archive, ArchiveRestore, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bot, Check, ChevronDown, ChevronRight, Circle, CircleAlert, CircleArrowUp, CircleCheck, CircleHelp, Command, Copy, Cpu, FileText, Folder, FolderTree, GitBranch, ImagePlus, ImageUp, LayoutList, LoaderCircle, MessageCircleQuestion, Mic, Monitor, Moon, PanelLeft, PanelLeftClose, PanelLeftOpen, Pencil, Plus, Search, Server, Settings2, Square, SquarePen, SquareTerminal, Sun, TerminalSquare, Trash2, TriangleAlert, X } from "lucide-react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -2888,7 +2888,7 @@ function ArchivedThreads({ threads, renderThread }) {
|
|
|
2888
2888
|
}), open && threads.map(renderThread)]
|
|
2889
2889
|
});
|
|
2890
2890
|
}
|
|
2891
|
-
function Sidebar({ projects, threads, archived = [], machines, currentId, mode, onModeChange, collapsed, mobileOpen, onCollapse, onCloseMobile, onOpenPalette }) {
|
|
2891
|
+
function Sidebar({ projects, threads, archived = [], machines, currentId, mode, onModeChange, collapsed, mobileOpen, onCollapse, onCloseMobile, onOpenPalette, updateAction }) {
|
|
2892
2892
|
const [closedProjects, setClosedProjects] = useState([]);
|
|
2893
2893
|
const currentProjectId = threads.find((thread) => thread.id === currentId)?.projectId;
|
|
2894
2894
|
const projectGroups = groupProjectLocations(projects, currentProjectId);
|
|
@@ -3012,26 +3012,97 @@ function Sidebar({ projects, threads, archived = [], machines, currentId, mode,
|
|
|
3012
3012
|
}),
|
|
3013
3013
|
/* @__PURE__ */ jsxs("div", {
|
|
3014
3014
|
className: "sidebar-footer",
|
|
3015
|
-
children: [
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3015
|
+
children: [
|
|
3016
|
+
/* @__PURE__ */ jsxs("a", {
|
|
3017
|
+
className: "sidebar-settings",
|
|
3018
|
+
href: "/settings",
|
|
3019
|
+
children: [/* @__PURE__ */ jsx(Settings2, { size: 15 }), " Settings"]
|
|
3020
|
+
}),
|
|
3021
|
+
updateAction,
|
|
3022
|
+
/* @__PURE__ */ jsx(Tooltip$1, {
|
|
3023
|
+
label: "Open command palette",
|
|
3024
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
3025
|
+
type: "button",
|
|
3026
|
+
className: "sidebar-palette",
|
|
3027
|
+
"aria-label": "Open command palette",
|
|
3028
|
+
onClick: onOpenPalette,
|
|
3029
|
+
children: /* @__PURE__ */ jsx("kbd", { children: "⌘K" })
|
|
3030
|
+
})
|
|
3027
3031
|
})
|
|
3028
|
-
|
|
3032
|
+
]
|
|
3029
3033
|
})
|
|
3030
3034
|
] })
|
|
3031
3035
|
]
|
|
3032
3036
|
})] });
|
|
3033
3037
|
}
|
|
3034
3038
|
//#endregion
|
|
3039
|
+
//#region src/client/update.ts
|
|
3040
|
+
var CHECK_MS = 18e5;
|
|
3041
|
+
var POLL_MS = 2e3;
|
|
3042
|
+
var GIVE_UP_MS = 18e4;
|
|
3043
|
+
var fetchStatus = async (signal) => {
|
|
3044
|
+
const response = await fetch("/api/update", { signal });
|
|
3045
|
+
if (!response.ok) throw new Error("Updates are not available.");
|
|
3046
|
+
return await response.json();
|
|
3047
|
+
};
|
|
3048
|
+
var confirmationMessage = ({ current, latest }) => `Update Webr from ${current} to ${latest}? Webr restarts and this page reloads. Running agents keep working.`;
|
|
3049
|
+
function useUpdate() {
|
|
3050
|
+
const [updatingFrom, setUpdatingFrom] = useState();
|
|
3051
|
+
const data = useQuery({
|
|
3052
|
+
queryKey: ["update"],
|
|
3053
|
+
queryFn: ({ signal }) => fetchStatus(signal),
|
|
3054
|
+
refetchInterval: updatingFrom ? POLL_MS : CHECK_MS,
|
|
3055
|
+
refetchOnWindowFocus: !updatingFrom
|
|
3056
|
+
}).data;
|
|
3057
|
+
const stopWaiting = useCallback((message) => {
|
|
3058
|
+
setUpdatingFrom(void 0);
|
|
3059
|
+
alertDialog(message);
|
|
3060
|
+
}, []);
|
|
3061
|
+
useEffect(() => {
|
|
3062
|
+
if (!updatingFrom || !data) return;
|
|
3063
|
+
if (data.current !== updatingFrom) window.location.reload();
|
|
3064
|
+
else if (data.state === "failed") stopWaiting(data.error ?? "The update failed.");
|
|
3065
|
+
}, [
|
|
3066
|
+
updatingFrom,
|
|
3067
|
+
data,
|
|
3068
|
+
stopWaiting
|
|
3069
|
+
]);
|
|
3070
|
+
useEffect(() => {
|
|
3071
|
+
if (!updatingFrom) return;
|
|
3072
|
+
const timer = setTimeout(() => stopWaiting("Webr did not come back after the update. Reload this page, or restart Herdr."), GIVE_UP_MS);
|
|
3073
|
+
return () => clearTimeout(timer);
|
|
3074
|
+
}, [updatingFrom, stopWaiting]);
|
|
3075
|
+
const requestUpdate = useCallback(async () => {
|
|
3076
|
+
if (!data || !await confirmDialog(confirmationMessage(data), { confirmLabel: "Update" })) return;
|
|
3077
|
+
if ((await fetch("/api/update", { method: "POST" }).catch(() => void 0))?.status === 202) setUpdatingFrom(data.current);
|
|
3078
|
+
else await alertDialog("Webr could not start the update.");
|
|
3079
|
+
}, [data]);
|
|
3080
|
+
return {
|
|
3081
|
+
status: data,
|
|
3082
|
+
updating: !!updatingFrom,
|
|
3083
|
+
requestUpdate
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
//#endregion
|
|
3087
|
+
//#region src/components/UpdateButton.tsx
|
|
3088
|
+
function UpdateButton() {
|
|
3089
|
+
const { status, updating, requestUpdate } = useUpdate();
|
|
3090
|
+
if (!status || !(status.available || updating)) return null;
|
|
3091
|
+
return /* @__PURE__ */ jsx(Tooltip$1, {
|
|
3092
|
+
label: `Webr ${status.latest} is available`,
|
|
3093
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
3094
|
+
type: "button",
|
|
3095
|
+
className: "sidebar-update",
|
|
3096
|
+
disabled: updating,
|
|
3097
|
+
onClick: () => void requestUpdate(),
|
|
3098
|
+
children: [/* @__PURE__ */ jsx(CircleArrowUp, {
|
|
3099
|
+
size: 14,
|
|
3100
|
+
"aria-hidden": "true"
|
|
3101
|
+
}), updating ? "Updating…" : "Update"]
|
|
3102
|
+
})
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
//#endregion
|
|
3035
3106
|
//#region src/client/store.ts
|
|
3036
3107
|
var equal = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
3037
3108
|
var share = (previous, next) => previous && equal(previous, next) ? previous : next;
|
|
@@ -4897,7 +4968,8 @@ function RuntimeApp({ page, bootstrap, threadId, projectId }) {
|
|
|
4897
4968
|
mobileOpen,
|
|
4898
4969
|
onCollapse: toggleSidebar,
|
|
4899
4970
|
onCloseMobile: () => setMobileOpen(false),
|
|
4900
|
-
onOpenPalette: () => setPaletteOpen(true)
|
|
4971
|
+
onOpenPalette: () => setPaletteOpen(true),
|
|
4972
|
+
updateAction: /* @__PURE__ */ jsx(UpdateButton, {})
|
|
4901
4973
|
}),
|
|
4902
4974
|
/* @__PURE__ */ jsxs("div", {
|
|
4903
4975
|
className: "main-panel",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
|
|
2
2
|
import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
|
|
3
|
-
import { n as $$Base, t as App } from "./
|
|
3
|
+
import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
|
|
4
4
|
//#region src/pages/threads/[id].astro
|
|
5
5
|
var _id__exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
default: () => $$Id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
|
|
2
2
|
import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
|
|
3
|
-
import { n as $$Base, t as App } from "./
|
|
3
|
+
import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
|
|
4
4
|
//#region src/pages/sessions/[session]/tabs/[tab].astro
|
|
5
5
|
var _tab__exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
default: () => $$Tab,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
|
|
2
2
|
import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
|
|
3
|
-
import { n as $$Base, t as App } from "./
|
|
3
|
+
import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
|
|
4
4
|
//#region src/pages/new.astro
|
|
5
5
|
var new_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
default: () => $$New,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as createAstro, V as __exportAll, i as renderComponent, u as renderTemplate } from "./server_dfdLOyV2.mjs";
|
|
2
2
|
import { t as createComponent } from "./compiler_BnrQvXXD.mjs";
|
|
3
|
-
import { n as $$Base, t as App } from "./
|
|
3
|
+
import { n as $$Base, t as App } from "./App_HJ7bmNpR.mjs";
|
|
4
4
|
//#region src/pages/settings.astro
|
|
5
5
|
var settings_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
default: () => $$Settings,
|
package/dist/server/entry.mjs
CHANGED
|
@@ -2426,10 +2426,10 @@ var renderers = [Object.assign({
|
|
|
2426
2426
|
//#endregion
|
|
2427
2427
|
//#region \0virtual:astro:pages
|
|
2428
2428
|
var _page0 = () => import("./chunks/node_C8FqXy_n.mjs").then((n) => n.t);
|
|
2429
|
-
var _page1 = () => import("./chunks/
|
|
2430
|
-
var _page2 = () => import("./chunks/
|
|
2431
|
-
var _page3 = () => import("./chunks/
|
|
2432
|
-
var _page4 = () => import("./chunks/
|
|
2429
|
+
var _page1 = () => import("./chunks/new_D_b9CCPu.mjs");
|
|
2430
|
+
var _page2 = () => import("./chunks/_tab__BXxhjK-Q.mjs");
|
|
2431
|
+
var _page3 = () => import("./chunks/settings_DC2X19WH.mjs");
|
|
2432
|
+
var _page4 = () => import("./chunks/_id__Dl1xEdu9.mjs");
|
|
2433
2433
|
var _page5 = () => import("./chunks/index_Bvv1gpI0.mjs");
|
|
2434
2434
|
var pageMap = /* @__PURE__ */ new Map([
|
|
2435
2435
|
["node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js", _page0],
|
|
@@ -2441,7 +2441,7 @@ var pageMap = /* @__PURE__ */ new Map([
|
|
|
2441
2441
|
]);
|
|
2442
2442
|
//#endregion
|
|
2443
2443
|
//#region \0virtual:astro:manifest
|
|
2444
|
-
var _manifest = deserializeManifest({"rootDir":"file:///home/runner/work/webr/webr/","cacheDir":"file:///home/runner/work/webr/webr/node_modules/.astro/","outDir":"file:///home/runner/work/webr/webr/dist/","srcDir":"file:///home/runner/work/webr/webr/src/","publicDir":"file:///home/runner/work/webr/webr/public/","buildClientDir":"file:///home/runner/work/webr/webr/dist/client/","buildServerDir":"file:///home/runner/work/webr/webr/dist/server/","adapterName":"@astrojs/node","assetsDir":"_astro","routes":[{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"type":"page","component":"_server-islands.astro","params":["name"],"segments":[[{"content":"_server-islands","dynamic":false,"spread":false}],[{"content":"name","dynamic":true,"spread":false}]],"pattern":"^\\/_server-islands\\/([^/]+?)\\/?$","prerender":false,"isIndex":false,"fallbackRoutes":[],"route":"/_server-islands/[name]","origin":"internal","distURL":[],"_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/_image","component":"node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js","params":[],"pathname":"/_image","pattern":"^\\/_image\\/?$","segments":[[{"content":"_image","dynamic":false,"spread":false}]],"type":"endpoint","prerender":false,"fallbackRoutes":[],"distURL":[],"isIndex":false,"origin":"internal","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.
|
|
2444
|
+
var _manifest = deserializeManifest({"rootDir":"file:///home/runner/work/webr/webr/","cacheDir":"file:///home/runner/work/webr/webr/node_modules/.astro/","outDir":"file:///home/runner/work/webr/webr/dist/","srcDir":"file:///home/runner/work/webr/webr/src/","publicDir":"file:///home/runner/work/webr/webr/public/","buildClientDir":"file:///home/runner/work/webr/webr/dist/client/","buildServerDir":"file:///home/runner/work/webr/webr/dist/server/","adapterName":"@astrojs/node","assetsDir":"_astro","routes":[{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"type":"page","component":"_server-islands.astro","params":["name"],"segments":[[{"content":"_server-islands","dynamic":false,"spread":false}],[{"content":"name","dynamic":true,"spread":false}]],"pattern":"^\\/_server-islands\\/([^/]+?)\\/?$","prerender":false,"isIndex":false,"fallbackRoutes":[],"route":"/_server-islands/[name]","origin":"internal","distURL":[],"_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/_image","component":"node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node.js","params":[],"pathname":"/_image","pattern":"^\\/_image\\/?$","segments":[[{"content":"_image","dynamic":false,"spread":false}]],"type":"endpoint","prerender":false,"fallbackRoutes":[],"distURL":[],"isIndex":false,"origin":"internal","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/new","isIndex":false,"type":"page","pattern":"^\\/new\\/?$","segments":[[{"content":"new","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/new.astro","pathname":"/new","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/sessions/[session]/tabs/[tab]","isIndex":false,"type":"page","pattern":"^\\/sessions\\/([^/]+?)\\/tabs\\/([^/]+?)\\/?$","segments":[[{"content":"sessions","dynamic":false,"spread":false}],[{"content":"session","dynamic":true,"spread":false}],[{"content":"tabs","dynamic":false,"spread":false}],[{"content":"tab","dynamic":true,"spread":false}]],"params":["session","tab"],"component":"src/pages/sessions/[session]/tabs/[tab].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/settings","isIndex":false,"type":"page","pattern":"^\\/settings\\/?$","segments":[[{"content":"settings","dynamic":false,"spread":false}]],"params":[],"component":"src/pages/settings.astro","pathname":"/settings","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[{"type":"external","src":"_astro/App.L92siqEU.css"}],"routeData":{"route":"/threads/[id]","isIndex":false,"type":"page","pattern":"^\\/threads\\/([^/]+?)\\/?$","segments":[[{"content":"threads","dynamic":false,"spread":false}],[{"content":"id","dynamic":true,"spread":false}]],"params":["id"],"component":"src/pages/threads/[id].astro","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}},{"file":"","links":[],"scripts":[],"styles":[],"routeData":{"route":"/","isIndex":true,"type":"page","pattern":"^\\/$","segments":[],"params":[],"component":"src/pages/index.astro","pathname":"/","prerender":false,"fallbackRoutes":[],"distURL":[],"origin":"project","_meta":{"trailingSlash":"ignore"}}}],"serverLike":true,"middlewareMode":"classic","base":"/","trailingSlash":"ignore","compressHTML":"jsx","componentMetadata":[["/home/runner/work/webr/webr/src/pages/new.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/sessions/[session]/tabs/[tab].astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/settings.astro",{"propagation":"none","containsHead":true}],["/home/runner/work/webr/webr/src/pages/threads/[id].astro",{"propagation":"none","containsHead":true}]],"renderers":[],"clientDirectives":[["idle","(()=>{var l=(n,t)=>{let i=async()=>{await(await n())()},e=typeof t.value==\"object\"?t.value:void 0,s={timeout:e==null?void 0:e.timeout};\"requestIdleCallback\"in window?window.requestIdleCallback(i,s):setTimeout(i,s.timeout||200)};(self.Astro||(self.Astro={})).idle=l;window.dispatchEvent(new Event(\"astro:idle\"));})();"],["load","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).load=e;window.dispatchEvent(new Event(\"astro:load\"));})();"],["media","(()=>{var n=(a,t)=>{let i=async()=>{await(await a())()};if(t.value){let e=matchMedia(t.value);e.matches?i():e.addEventListener(\"change\",i,{once:!0})}};(self.Astro||(self.Astro={})).media=n;window.dispatchEvent(new Event(\"astro:media\"));})();"],["only","(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).only=e;window.dispatchEvent(new Event(\"astro:only\"));})();"],["visible","(()=>{var a=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value==\"object\"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let l of e)if(l.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=a;window.dispatchEvent(new Event(\"astro:visible\"));})();"]],"entryModules":{"\u0000noop-middleware":"virtual_astro_middleware.mjs","\u0000virtual:astro:server-island-manifest":"chunks/_virtual_astro_server-island-manifest_C1Q2srgE.mjs","\u0000virtual:astro:session-driver":"chunks/_virtual_astro_session-driver_Dp7RXjOf.mjs","\u0000virtual:astro:actions/noop-entrypoint":"chunks/noop-entrypoint_Z3zFhrGC.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/@astrojs+react@7.0.0_@types+node@22.20.4_@types+react-dom@19.3.0_@types+react@19.3.0__@_02aa85dceaccf3d763325676dd8540a8/node_modules/@astrojs/react/dist/vnode-children.js":"chunks/vnode-children_BSi0H4PL.mjs","@astrojs/node/server.js":"entry.mjs","\u0000virtual:astro:page:src/pages/threads/[id]@_@astro":"chunks/_id__Dl1xEdu9.mjs","\u0000virtual:astro:page:src/pages/sessions/[session]/tabs/[tab]@_@astro":"chunks/_tab__BXxhjK-Q.mjs","\u0000virtual:astro:page:src/pages/index@_@astro":"chunks/index_Bvv1gpI0.mjs","\u0000virtual:astro:page:src/pages/new@_@astro":"chunks/new_D_b9CCPu.mjs","\u0000virtual:astro:page:node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/endpoint/node@_@js":"chunks/node_C8FqXy_n.mjs","\u0000virtual:astro:page:src/pages/settings@_@astro":"chunks/settings_DC2X19WH.mjs","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/dist/assets/services/sharp.js":"chunks/sharp_8J8zk4Wd.mjs","/home/runner/work/webr/webr/src/components/App.tsx":"_astro/App.FpiLskEl.js","/home/runner/work/webr/webr/node_modules/.pnpm/astro@7.3.5_@types+node@22.20.4_tsx@4.23.15_yaml@2.9.1/node_modules/astro/components/ClientRouter.astro?astro&type=script&index=0&lang.ts":"_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","@astrojs/react/client.js":"_astro/client.BDkzSRUN.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-fit@0.10.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-fit/lib/addon-fit.js":"_astro/addon-fit.jgKqzwky.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-web-links@0.11.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-web-links/lib/addon-web-links.js":"_astro/addon-web-links.C9lyQRxI.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+addon-webgl@0.18.0_@xterm+xterm@5.5.0/node_modules/@xterm/addon-webgl/lib/addon-webgl.js":"_astro/addon-webgl.Bd5ox92E.js","/home/runner/work/webr/webr/node_modules/.pnpm/@xterm+xterm@5.5.0/node_modules/@xterm/xterm/lib/xterm.js":"_astro/xterm.B-l5AIf6.js","astro:scripts/before-hydration.js":""},"inlinedScripts":[],"assets":["/apple-touch-icon.png","/brand-mark.png","/favicon-16.png","/favicon-32.png","/favicon.ico","/icon-192.png","/icon-512.png","/icon-maskable-512.png","/manifest.webmanifest","/_astro/App.FpiLskEl.js","/_astro/ClientRouter.astro_astro_type_script_index_0_lang.CTgtIFyY.js","/_astro/addon-fit.jgKqzwky.js","/_astro/addon-web-links.C9lyQRxI.js","/_astro/addon-webgl.Bd5ox92E.js","/_astro/client.BDkzSRUN.js","/_astro/client.Bbg9OBwT.js","/_astro/client.CLSsMr2g.js","/_astro/xterm.B-l5AIf6.js","/_astro/App.L92siqEU.css","/_astro/jetbrains-mono.CFJaiWaY.woff2","/_astro/symbols-nerd.CEdkKAK8.woff2"],"buildFormat":"directory","checkOrigin":true,"actionBodySizeLimit":1048576,"serverIslandBodySizeLimit":1048576,"allowedDomains":[],"key":"HZxm4Mi2IX3Ty0isRVymtm3WJdpCYu8n3SdTrJfXV9Y=","sessionConfig":{"driver":"unstorage/drivers/fs-lite","options":{"base":"/home/runner/work/webr/webr/node_modules/.astro/sessions"}},"image":{},"devToolbar":{"enabled":false,"debugInfoOutput":""},"logLevel":"info","shouldInjectCspMetaTags":false});
|
|
2445
2445
|
var manifestRoutes = _manifest.routes;
|
|
2446
2446
|
var manifest = Object.assign(_manifest, {
|
|
2447
2447
|
renderers,
|
package/package.json
CHANGED
package/server/run.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { join } from 'node:path';
|
|
|
18
18
|
import { builtSsr, devSsr } from './ssr';
|
|
19
19
|
import { recordPid, restartWhenRebuilt } from './rebuilt-restart';
|
|
20
20
|
import { PID_FILE } from './plugin/files';
|
|
21
|
+
import { UpdateService } from './update/service';
|
|
21
22
|
|
|
22
23
|
const WILDCARD_HOSTS = ['0.0.0.0', '::'];
|
|
23
24
|
|
|
@@ -37,13 +38,15 @@ export async function runServer() {
|
|
|
37
38
|
const managesTailscale = !process.env.WEBR_ORIGIN && [...WILDCARD_HOSTS, '127.0.0.1'].includes(host);
|
|
38
39
|
const tailscale = managesTailscale ? await ensureTailscaleHttps(port) : undefined;
|
|
39
40
|
const urls = [...(tailscale?.status === 'ready' ? [tailscale.url] : []), ...publicUrls(origin, host, port, undefined, await detectTailscaleHost())];
|
|
40
|
-
const
|
|
41
|
+
const updates = process.env.WEBR_DEV === '1' ? undefined : new UpdateService();
|
|
42
|
+
const app = await createHost(manager, origin, ssr.handler, tls, undefined, { publicUrls: urls, tailscale: tailscale?.status }, { devHmrPort: ssr.hmrPort, transcriber: new Transcriber(modelDirectory(webrHome())), updates });
|
|
41
43
|
await app.listen({ host, port });
|
|
42
44
|
manager.start();
|
|
45
|
+
const stopWatchingUpdates = updates?.watch();
|
|
43
46
|
if (!process.env.WEBR_TARGETS) void discoverSavedMachines(process.env, boundedProcess, (profile) => manager.addTarget(new HerdrTarget(profile)));
|
|
44
47
|
recordPid(process.env.HERDR_PLUGIN_STATE_DIR, PID_FILE);
|
|
45
48
|
if (process.env.WEBR_DEV !== '1') restartWhenRebuilt(async () => { await Promise.all([app.close(), ssr.stop()]); database.close(); });
|
|
46
49
|
console.log(`Webr listening at ${origin}`);
|
|
47
50
|
if (!isLoopbackHost(host) || urls.length) console.log(`Other devices connect at:\n${(urls.length ? urls : [origin]).map((url) => ` ${url}`).join('\n')}\nThey ask for access and you approve them in Webr on this computer.`);
|
|
48
|
-
for (const signal of ['SIGINT', 'SIGTERM'] as const) process.once(signal, () => { void Promise.all([app.close(), ssr.stop()]).finally(() => { database.close(); process.exit(0); }); });
|
|
51
|
+
for (const signal of ['SIGINT', 'SIGTERM'] as const) process.once(signal, () => { void Promise.all([app.close(), ssr.stop()]).finally(() => { stopWatchingUpdates?.(); database.close(); process.exit(0); }); });
|
|
49
52
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { closeSync, mkdirSync, openSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import type { UpdateState, UpdateStatus, Updates } from '../../src/shared/update';
|
|
5
|
+
import { installedEntry } from '../entry';
|
|
6
|
+
import { webrHome } from '../home';
|
|
7
|
+
import { packageInfo } from '../package-info';
|
|
8
|
+
import { fetchLatestVersion, readCachedLatest, writeCachedLatest } from './latest';
|
|
9
|
+
import { updateCheckDisabled } from './hint';
|
|
10
|
+
import { detectPackageManager, installedPackagePath, isNpxRun } from './package-manager';
|
|
11
|
+
import { isNewerVersion } from './versions';
|
|
12
|
+
|
|
13
|
+
const REFRESH_MS = 6 * 60 * 60 * 1000;
|
|
14
|
+
const RESTART_GRACE_MS = 60 * 1000;
|
|
15
|
+
const LOG_LINES_SHOWN = 4;
|
|
16
|
+
|
|
17
|
+
export type UpdateCommand = { command: string; args: string[] };
|
|
18
|
+
type Exit = (code: number | null) => void;
|
|
19
|
+
|
|
20
|
+
export function updateCommand(installPath: string, name: string): UpdateCommand | undefined {
|
|
21
|
+
if (detectPackageManager(installPath)) return { command: process.execPath, args: [installedEntry(), 'update'] };
|
|
22
|
+
return isNpxRun(installPath) ? { command: 'npx', args: ['--yes', `${name}@latest`, 'update'] } : undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const logPath = () => join(webrHome(), 'update.log');
|
|
26
|
+
|
|
27
|
+
function spawnDetached({ command, args }: UpdateCommand, onExit: Exit) {
|
|
28
|
+
mkdirSync(webrHome(), { recursive: true });
|
|
29
|
+
const log = openSync(logPath(), 'w');
|
|
30
|
+
const child = spawn(command, args, { detached: true, stdio: ['ignore', log, log], windowsHide: true, env: { ...process.env, WEBR_NO_UPDATE_CHECK: '1' } });
|
|
31
|
+
closeSync(log);
|
|
32
|
+
child.once('error', () => onExit(null));
|
|
33
|
+
child.once('exit', onExit);
|
|
34
|
+
child.unref();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const logTail = () => {
|
|
38
|
+
try { return readFileSync(logPath(), 'utf8').split('\n').filter((line) => line.trim() && !/ExperimentalWarning|trace-warnings/.test(line)).slice(-LOG_LINES_SHOWN).join('\n'); } catch { return ''; }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type UpdateServiceDeps = {
|
|
42
|
+
env?: NodeJS.ProcessEnv;
|
|
43
|
+
command?: UpdateCommand | undefined;
|
|
44
|
+
run?: (command: UpdateCommand, onExit: Exit) => void;
|
|
45
|
+
fetchLatest?: (name: string) => Promise<string>;
|
|
46
|
+
tail?: () => string;
|
|
47
|
+
restartGraceMs?: number;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export class UpdateService implements Updates {
|
|
51
|
+
private state: UpdateState = 'idle';
|
|
52
|
+
private error: string | undefined;
|
|
53
|
+
private readonly env: NodeJS.ProcessEnv;
|
|
54
|
+
private readonly command: UpdateCommand | undefined;
|
|
55
|
+
private readonly name = packageInfo().name;
|
|
56
|
+
|
|
57
|
+
constructor(private readonly deps: UpdateServiceDeps = {}) {
|
|
58
|
+
this.env = deps.env ?? process.env;
|
|
59
|
+
this.command = 'command' in deps ? deps.command : safely(() => updateCommand(installedPackagePath(), this.name));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
watch() {
|
|
63
|
+
if (updateCheckDisabled(this.env) || !this.command) return () => {};
|
|
64
|
+
void this.refresh();
|
|
65
|
+
const timer = setInterval(() => void this.refresh(), REFRESH_MS);
|
|
66
|
+
timer.unref();
|
|
67
|
+
return () => clearInterval(timer);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async refresh() {
|
|
71
|
+
const latest = await (this.deps.fetchLatest ?? fetchLatestVersion)(this.name).catch(() => undefined);
|
|
72
|
+
if (latest) writeCachedLatest(latest, this.env);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
status(): UpdateStatus {
|
|
76
|
+
const { version: current } = packageInfo();
|
|
77
|
+
const latest = readCachedLatest(this.env)?.latest ?? current;
|
|
78
|
+
const available = !!this.command && !updateCheckDisabled(this.env) && isNewerVersion(latest, current);
|
|
79
|
+
return { current, latest, available, state: this.state, ...(this.error ? { error: this.error } : {}) };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
start(): UpdateStatus {
|
|
83
|
+
if (this.state === 'updating' || !this.command || !this.status().available) return this.status();
|
|
84
|
+
this.state = 'updating';
|
|
85
|
+
this.error = undefined;
|
|
86
|
+
(this.deps.run ?? spawnDetached)(this.command, (code) => this.finished(code));
|
|
87
|
+
return this.status();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private finished(code: number | null) {
|
|
91
|
+
if (code === 0) return void this.failAfterGrace('Webr installed the update but did not restart. Restart Herdr to use it.');
|
|
92
|
+
const output = (this.deps.tail ?? logTail)();
|
|
93
|
+
this.fail(output ? `The update failed.\n${output}` : 'The update failed.');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private failAfterGrace(message: string) {
|
|
97
|
+
setTimeout(() => this.fail(message), this.deps.restartGraceMs ?? RESTART_GRACE_MS).unref();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private fail(message: string) {
|
|
101
|
+
this.state = 'failed';
|
|
102
|
+
this.error = message;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function safely<T>(read: () => T): T | undefined {
|
|
107
|
+
try { return read(); } catch { return undefined; }
|
|
108
|
+
}
|
package/src/server/host.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { isTrustedHost } from './auth/access';
|
|
|
14
14
|
import { registerDevHmrProxy } from './dev-hmr-proxy';
|
|
15
15
|
import { registerVoiceRoutes } from './voice/routes';
|
|
16
16
|
import type { Transcriber } from './voice/transcriber';
|
|
17
|
+
import type { Updates } from '../shared/update';
|
|
17
18
|
import { MAX_IMAGE_BYTES, UploadStore, uploadContentTypes, uploadFileName } from './uploads';
|
|
18
19
|
|
|
19
20
|
const localOwner = 'local';
|
|
@@ -21,7 +22,7 @@ type SsrHandler = (request: FastifyRequest['raw'], response: import('node:http')
|
|
|
21
22
|
|
|
22
23
|
const MAX_PROJECT_ICON_BYTES = 512 * 1024;
|
|
23
24
|
|
|
24
|
-
export async function createHost(manager: RuntimeManager, origin: string, ssr?: SsrHandler, tls?: { key: Buffer; cert: Buffer }, uploads = new UploadStore(), authOptions: AuthOptions = {}, { devHmrPort, transcriber }: { devHmrPort?: number; transcriber?: Transcriber } = {}) {
|
|
25
|
+
export async function createHost(manager: RuntimeManager, origin: string, ssr?: SsrHandler, tls?: { key: Buffer; cert: Buffer }, uploads = new UploadStore(), authOptions: AuthOptions = {}, { devHmrPort, transcriber, updates }: { devHmrPort?: number; transcriber?: Transcriber; updates?: Updates } = {}) {
|
|
25
26
|
const app = Fastify({ logger: false, bodyLimit: 16 * 1024, ...(tls ? { https: tls } : {}), requestTimeout: 10_000 });
|
|
26
27
|
const configuredOrigin = new URL(origin);
|
|
27
28
|
const auth = new Auth(manager.database, configuredOrigin, authOptions);
|
|
@@ -53,6 +54,10 @@ export async function createHost(manager: RuntimeManager, origin: string, ssr?:
|
|
|
53
54
|
auth.routes(app);
|
|
54
55
|
if (devHmrPort) registerDevHmrProxy(app, devHmrPort);
|
|
55
56
|
if (transcriber) registerVoiceRoutes(app, transcriber);
|
|
57
|
+
if (updates) {
|
|
58
|
+
app.get('/api/update', async () => updates.status());
|
|
59
|
+
app.post('/api/update', async (_request, reply) => { const status = updates.start(); return reply.code(status.state === 'updating' ? 202 : 409).send(status); });
|
|
60
|
+
}
|
|
56
61
|
app.get('/api/catalog/machines', async () => manager.bootstrap().machines);
|
|
57
62
|
app.get('/api/catalog/:machineId', async (request) => {
|
|
58
63
|
const { machineId } = z.object({ machineId: opaqueId }).parse(request.params);
|
|
@@ -102,7 +102,7 @@ export class HerdrTarget implements TargetAdapter {
|
|
|
102
102
|
const api = await this.connect();
|
|
103
103
|
await api.request('ping');
|
|
104
104
|
const run = (command: string, args: string[]) => this.runOnTarget(command, args);
|
|
105
|
-
const isPresent = (kind: string) => run('/bin/sh', ['-c', 'command -v "$1"
|
|
105
|
+
const isPresent = (kind: string) => run('/bin/sh', ['-c', 'command -v "$1"', 'sh', kind]).then((path) => path.trim().length > 0, () => false);
|
|
106
106
|
const present = (await Promise.all(herdrAgentKinds.map(async (kind) => (await isPresent(kind)) ? kind : undefined))).filter((kind): kind is string => !!kind);
|
|
107
107
|
present.forEach((kind) => this.discoverModels(kind));
|
|
108
108
|
const modelsPending = present.some((kind) => this.pendingModels.has(kind));
|