sh3-server 0.6.0 → 0.7.5

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.
@@ -1 +1 @@
1
- .modal-frame.svelte-2tcvcm{position:absolute;inset:0;display:grid;place-items:center;pointer-events:auto}.modal-box.svelte-2tcvcm{background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-radius:var(--shell-radius);min-width:320px;max-width:min(640px,90vw);max-height:90vh;overflow:auto;box-shadow:0 20px 48px #00000080;outline:none}.popup-frame.svelte-mp81cl{position:absolute;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-radius:var(--shell-radius-sm);box-shadow:0 8px 24px #0006;min-width:120px;outline:none;pointer-events:auto}.toast.svelte-12gwnj0{pointer-events:auto;display:flex;align-items:center;gap:var(--shell-pad-md);padding:var(--shell-pad-sm) var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-left-width:3px;border-radius:var(--shell-radius-sm);box-shadow:0 8px 20px #0006;font-size:12px;min-width:220px;max-width:360px;cursor:pointer;animation:svelte-12gwnj0-toast-in .16s ease-out both}.toast-level.svelte-12gwnj0{text-transform:uppercase;font-family:var(--shell-font-mono);font-size:10px;letter-spacing:.5px;color:var(--shell-fg-muted)}.toast-message.svelte-12gwnj0{flex:1}.toast-info.svelte-12gwnj0{border-left-color:var(--shell-accent)}.toast-success.svelte-12gwnj0{border-left-color:#5cb176}.toast-warn.svelte-12gwnj0{border-left-color:#d6a84a}.toast-error.svelte-12gwnj0{border-left-color:#d06060}@keyframes svelte-12gwnj0-toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.shell-title.svelte-1ifjvh5{display:inline-block;line-height:0;overflow:hidden}.shell-title.svelte-1ifjvh5 canvas{transform:scale(var(--shell-title-scale));transform-origin:top left;display:block}.shell-title-fallback.svelte-1ifjvh5{margin:0;font-size:42px;color:var(--shell-accent);letter-spacing:2px}.shell-home.svelte-cpn2x2{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:48px 24px;overflow:auto;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg);font-family:system-ui,sans-serif}.shell-home-header.svelte-cpn2x2{text-align:center;margin-bottom:32px;display:flex;flex-direction:column;align-items:center;gap:12px}.shell-home-title-row.svelte-cpn2x2{display:flex;align-items:baseline;gap:6px}.shell-home-credit.svelte-cpn2x2{font-size:11px;color:var(--shell-fg-muted);letter-spacing:.04em;margin-top:-4px}.shell-home-credit.svelte-cpn2x2 a:where(.svelte-cpn2x2){color:var(--shell-fg-subtle);text-decoration:none;border-bottom:1px dotted var(--shell-fg-muted)}.shell-home-credit.svelte-cpn2x2 a:where(.svelte-cpn2x2):hover{color:var(--shell-accent);border-bottom-color:var(--shell-accent)}.shell-home-version.svelte-cpn2x2{font-size:14px;color:var(--shell-fg-subtle);letter-spacing:.04em}.shell-home-alpha.svelte-cpn2x2{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#fff;background:var(--shell-accent);padding:2px 8px;border-radius:8px;position:relative;top:-1px}.shell-home-empty.svelte-cpn2x2{color:var(--shell-fg-muted);font-style:italic}.shell-home-section.svelte-cpn2x2{width:100%;max-width:440px;margin-bottom:24px}.shell-home-section-title.svelte-cpn2x2{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--shell-fg-subtle);margin:0 0 12px}.shell-home-list.svelte-cpn2x2{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.shell-home-entry.svelte-cpn2x2{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto auto;gap:4px 16px;align-items:center;padding:14px 18px;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border:1px solid var(--shell-border);border-radius:var(--shell-radius-md)}.shell-home-entry-label.svelte-cpn2x2{grid-column:1;grid-row:1;font-weight:600}.shell-home-entry-meta.svelte-cpn2x2{grid-column:1;grid-row:2;font-size:11px;color:var(--shell-fg-subtle)}.shell-home-launch.svelte-cpn2x2{grid-column:2;grid-row:1 / span 2;padding:8px 16px;font-weight:600}.shell-text.svelte-ypr8s{margin:0;padding:0 8px;font-family:var(--shell-font-mono, monospace);white-space:pre-wrap;word-break:break-word;color:var(--shell-fg, #ddd)}.shell-text.stderr.svelte-ypr8s{color:var(--shell-fg-error, #f88)}.shell-prompt.svelte-u0gb59{padding:4px 8px 0;font-family:var(--shell-font-mono, monospace);display:flex;gap:8px}.shell-prompt-cwd.svelte-u0gb59{color:var(--shell-fg-muted, #888)}.shell-prompt-arrow.svelte-u0gb59{color:var(--shell-accent, #6cf)}.shell-prompt-line.svelte-u0gb59{color:var(--shell-fg, #ddd)}.shell-status.svelte-nfxdpt{padding:2px 8px;font-family:var(--shell-font-mono, monospace);font-style:italic}.shell-status.info.svelte-nfxdpt{color:var(--shell-fg-muted, #888)}.shell-status.warn.svelte-nfxdpt{color:var(--shell-fg-warn, #fc6)}.shell-status.error.svelte-nfxdpt{color:var(--shell-fg-error, #f88)}.shell-rich.svelte-1rnhl05{padding:4px 8px}.shell-scrollback.svelte-isy3jt{flex:1 1 auto;overflow-y:auto;background:var(--shell-bg, #111);color:var(--shell-fg, #ddd)}.shell-input.svelte-1dfv2gk{display:flex;gap:8px;padding:4px 8px;border-top:1px solid var(--shell-border, #333);font-family:var(--shell-font-mono, monospace)}.shell-input-cwd.svelte-1dfv2gk{color:var(--shell-fg-muted, #888)}.shell-input-arrow.svelte-1dfv2gk{color:var(--shell-accent, #6cf)}.shell-input-field.svelte-1dfv2gk{flex:1 1 auto;background:transparent;border:0;outline:0;color:var(--shell-fg, #ddd);font:inherit}.shell-input.locked.svelte-1dfv2gk .shell-input-field:where(.svelte-1dfv2gk){opacity:.5;cursor:default}.shell-rich-help.svelte-m248jy table:where(.svelte-m248jy){border-collapse:collapse;width:100%}.shell-rich-help.svelte-m248jy th:where(.svelte-m248jy),.shell-rich-help.svelte-m248jy td:where(.svelte-m248jy){padding:2px 8px;text-align:left}.shell-rich-help.svelte-m248jy button:where(.svelte-m248jy){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-help.svelte-m248jy button:where(.svelte-m248jy):hover{text-decoration:underline}.shell-rich-history.svelte-o8m437 ol:where(.svelte-o8m437){list-style-position:inside;margin:0;padding:0}.shell-rich-history.svelte-o8m437 li:where(.svelte-o8m437){padding:2px 0}.shell-rich-history.svelte-o8m437 button:where(.svelte-o8m437){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit;text-align:left}.shell-rich-history.svelte-o8m437 button:where(.svelte-o8m437):hover{text-decoration:underline}.shell-rich-apps.svelte-1u5krjz table:where(.svelte-1u5krjz){border-collapse:collapse;width:100%}.shell-rich-apps.svelte-1u5krjz th:where(.svelte-1u5krjz),.shell-rich-apps.svelte-1u5krjz td:where(.svelte-1u5krjz){padding:2px 8px;text-align:left}.shell-rich-apps.svelte-1u5krjz button:where(.svelte-1u5krjz){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-apps.svelte-1u5krjz button:where(.svelte-1u5krjz):hover{text-decoration:underline}.shell-rich-appcard.svelte-npcp8i{padding:8px;border:1px solid var(--shell-border, #444)}.shell-rich-appcard.svelte-npcp8i h3:where(.svelte-npcp8i){margin:0 0 8px}.shell-rich-appcard.svelte-npcp8i p:where(.svelte-npcp8i){margin:4px 0}.shell-rich-shards.svelte-sc3ux4 table:where(.svelte-sc3ux4){border-collapse:collapse;width:100%}.shell-rich-shards.svelte-sc3ux4 th:where(.svelte-sc3ux4),.shell-rich-shards.svelte-sc3ux4 td:where(.svelte-sc3ux4){padding:2px 8px;text-align:left}.shell-rich-views.svelte-15elbr1 table:where(.svelte-15elbr1){border-collapse:collapse;width:100%}.shell-rich-views.svelte-15elbr1 th:where(.svelte-15elbr1),.shell-rich-views.svelte-15elbr1 td:where(.svelte-15elbr1){padding:2px 8px;text-align:left}.shell-rich-views.svelte-15elbr1 button:where(.svelte-15elbr1){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-views.svelte-15elbr1 button:where(.svelte-15elbr1):hover{text-decoration:underline}.shell-rich-zones.svelte-1w7onag table:where(.svelte-1w7onag){border-collapse:collapse;width:100%}.shell-rich-zones.svelte-1w7onag th:where(.svelte-1w7onag),.shell-rich-zones.svelte-1w7onag td:where(.svelte-1w7onag){padding:2px 8px;text-align:left}.shell-rich-zonetree.svelte-13iiyr1 pre:where(.svelte-13iiyr1){overflow:auto;padding:8px;background:var(--shell-bg, #000);color:var(--shell-fg, #fff)}.shell-rich-env.svelte-1ox8vog table:where(.svelte-1ox8vog){border-collapse:collapse;width:100%}.shell-rich-env.svelte-1ox8vog th:where(.svelte-1ox8vog),.shell-rich-env.svelte-1ox8vog td:where(.svelte-1ox8vog){padding:2px 8px;text-align:left}.shell-terminal.svelte-13komre{display:flex;flex-direction:column;height:100%;background:var(--shell-bg, #111);color:var(--shell-fg, #ddd)}.store-view.svelte-1aafzt0{font-family:var(--shell-font-ui);color:var(--shell-fg, #e0e0e0);background:var(--shell-bg, #1e1e1e);padding:16px;height:100%;overflow-y:auto;box-sizing:border-box}.store-header.svelte-1aafzt0{margin-bottom:16px}.store-header.svelte-1aafzt0 h2:where(.svelte-1aafzt0){margin:0 0 8px;font-size:1.25rem;font-weight:600}.store-controls.svelte-1aafzt0{display:flex;gap:8px;flex-wrap:wrap}.store-search.svelte-1aafzt0{flex:1;min-width:160px;padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.875rem}.store-search.svelte-1aafzt0::placeholder{color:var(--shell-fg-muted, #888)}.store-filter.svelte-1aafzt0{padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.875rem}.store-refresh.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-error.svelte-1aafzt0{padding:8px 12px;margin-bottom:12px;background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent);color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius);font-size:.8125rem}.store-grid.svelte-1aafzt0{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.store-card.svelte-1aafzt0{background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius-md);padding:14px;display:flex;flex-direction:column;gap:8px}.store-card.svelte-1aafzt0:hover{border-color:var(--shell-accent, #007acc)}.store-card-header.svelte-1aafzt0{display:flex;align-items:center;gap:10px}.store-card-icon.svelte-1aafzt0{width:36px;height:36px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.store-icon-img.svelte-1aafzt0{width:36px;height:36px;border-radius:var(--shell-radius);object-fit:cover}.store-icon-placeholder.svelte-1aafzt0{width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:var(--shell-accent, #007acc);color:#fff;border-radius:var(--shell-radius);font-weight:700;font-size:1rem}.store-card-title.svelte-1aafzt0{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.store-card-label.svelte-1aafzt0{font-weight:600;font-size:.9375rem}.store-card-badge.svelte-1aafzt0{font-size:.6875rem;padding:1px 6px;border-radius:var(--shell-radius-sm);text-transform:uppercase;font-weight:600;letter-spacing:.04em}.badge-shard.svelte-1aafzt0{background:color-mix(in srgb,var(--shell-accent, #007acc) 25%,transparent);color:var(--shell-accent, #007acc)}.badge-app.svelte-1aafzt0{background:color-mix(in srgb,var(--shell-success, #4caf50) 25%,transparent);color:var(--shell-success, #4caf50)}.store-card-version.svelte-1aafzt0{font-size:.75rem;color:var(--shell-fg-muted, #888)}.store-card-desc.svelte-1aafzt0{margin:0;font-size:.8125rem;color:var(--shell-fg-muted, #888);line-height:1.4}.store-card-author.svelte-1aafzt0{font-size:.75rem;color:var(--shell-fg-muted, #888)}.store-card-warning.svelte-1aafzt0{font-size:.75rem;color:var(--shell-warning, #ff9800);padding:4px 8px;background:color-mix(in srgb,var(--shell-warning, #ff9800) 10%,transparent);border-radius:var(--shell-radius-sm)}.store-card-actions.svelte-1aafzt0{margin-top:auto;display:flex;justify-content:flex-end}.store-install-btn.svelte-1aafzt0{padding:5px 14px;font-size:.8125rem}.store-install-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-installed-label.svelte-1aafzt0{font-size:.8125rem;color:var(--shell-success, #4caf50);font-weight:600}.store-update-btn.svelte-1aafzt0{padding:5px 14px;background:var(--shell-warning, #ff9800);font-size:.8125rem}.store-update-btn.svelte-1aafzt0:hover:not(:disabled){filter:brightness(1.1)}.store-update-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-empty.svelte-1aafzt0{text-align:center;padding:32px 16px;color:var(--shell-fg-muted, #888);font-size:.875rem}.store-registries.svelte-1aafzt0{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}.store-registry-entry.svelte-1aafzt0{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-size:.8125rem}.store-registry-url.svelte-1aafzt0{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--shell-fg-muted, #888)}.store-registry-remove.svelte-1aafzt0{padding:2px 8px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius-sm);font-size:.75rem;flex-shrink:0;margin-left:8px}.store-add-registry.svelte-1aafzt0{display:flex;gap:8px;margin-bottom:12px}.store-registry-input.svelte-1aafzt0{flex:1;padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.8125rem}.store-registry-input.svelte-1aafzt0::placeholder{color:var(--shell-fg-muted, #888)}.store-add-btn.svelte-1aafzt0{font-size:.8125rem;white-space:nowrap}.store-add-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.installed-view.svelte-1hqclkp{font-family:var(--shell-font-ui);color:var(--shell-fg, #e0e0e0);background:var(--shell-bg, #1e1e1e);padding:16px;height:100%;overflow-y:auto;box-sizing:border-box}.installed-header.svelte-1hqclkp{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.installed-header.svelte-1hqclkp h2:where(.svelte-1hqclkp){margin:0;font-size:1.25rem;font-weight:600}.installed-empty.svelte-1hqclkp{text-align:center;padding:32px 16px;color:var(--shell-fg-muted, #888);font-size:.875rem}.installed-list.svelte-1hqclkp{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.installed-item.svelte-1hqclkp{background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius-md);padding:12px 14px;display:flex;flex-direction:column;gap:6px}.installed-item-main.svelte-1hqclkp{display:flex;align-items:center;gap:8px}.installed-item-id.svelte-1hqclkp{font-weight:600;font-size:.9375rem}.installed-item-badge.svelte-1hqclkp{font-size:.6875rem;padding:1px 6px;border-radius:var(--shell-radius-sm);text-transform:uppercase;font-weight:600;letter-spacing:.04em}.badge-shard.svelte-1hqclkp{background:color-mix(in srgb,var(--shell-accent, #007acc) 25%,transparent);color:var(--shell-accent, #007acc)}.badge-app.svelte-1hqclkp{background:color-mix(in srgb,var(--shell-success, #4caf50) 25%,transparent);color:var(--shell-success, #4caf50)}.installed-item-version.svelte-1hqclkp{font-size:.75rem;color:var(--shell-fg-muted, #888)}.installed-item-meta.svelte-1hqclkp{display:flex;gap:16px;flex-wrap:wrap;font-size:.75rem;color:var(--shell-fg-muted, #888)}.installed-item-actions.svelte-1hqclkp{display:flex;justify-content:flex-end;gap:8px}.installed-uninstall-btn.svelte-1hqclkp{padding:4px 12px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:.8125rem}.installed-uninstall-btn.svelte-1hqclkp:hover:not(:disabled){background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent)}.installed-uninstall-btn.svelte-1hqclkp:disabled{opacity:.6;cursor:not-allowed}.installed-update-btn.svelte-1hqclkp{padding:4px 12px;background:var(--shell-warning, #ff9800);font-size:.8125rem}.installed-update-btn.svelte-1hqclkp:hover:not(:disabled){filter:brightness(1.1)}.installed-update-btn.svelte-1hqclkp:disabled{opacity:.6;cursor:not-allowed}.installed-error.svelte-1hqclkp{padding:8px 12px;margin-bottom:12px;background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent);color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius);font-size:.8125rem}.admin-users.svelte-4q792t{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-users-header.svelte-4q792t{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.admin-users-header.svelte-4q792t h2:where(.svelte-4q792t){margin:0;font-size:18px}.admin-create-form.svelte-4q792t,.admin-edit-form.svelte-4q792t{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;max-width:400px}.admin-input.svelte-4q792t{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-btn.svelte-4q792t{font-weight:600;font-size:13px}.admin-btn.svelte-4q792t:disabled{opacity:.6;cursor:not-allowed}.admin-btn-secondary.svelte-4q792t{background:transparent;color:var(--shell-fg-subtle);border:1px solid var(--shell-border);font-size:12px}.admin-btn-danger.svelte-4q792t{background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:12px}.admin-user-list.svelte-4q792t{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.admin-user-item.svelte-4q792t{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px)}.admin-user-info.svelte-4q792t{display:flex;flex-direction:column;gap:2px}.admin-user-name.svelte-4q792t{font-weight:600}.admin-user-meta.svelte-4q792t{font-size:11px;color:var(--shell-fg-subtle)}.admin-user-actions.svelte-4q792t,.admin-edit-actions.svelte-4q792t{display:flex;gap:6px}.admin-error.svelte-4q792t{color:var(--shell-error, #d32f2f);font-size:13px}.admin-muted.svelte-4q792t{color:var(--shell-fg-muted);font-style:italic}.admin-auth.svelte-1hsgdb4{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-auth.svelte-1hsgdb4 h2:where(.svelte-1hsgdb4){margin:0 0 16px;font-size:18px}.admin-auth-fields.svelte-1hsgdb4{display:flex;flex-direction:column;gap:16px;max-width:480px}.admin-toggle.svelte-1hsgdb4{display:flex;flex-wrap:wrap;align-items:center;gap:8px;cursor:pointer}.admin-toggle.svelte-1hsgdb4 input:where(.svelte-1hsgdb4){accent-color:var(--shell-accent, #7c7cf0)}.admin-hint.svelte-1hsgdb4{flex-basis:100%;font-size:11px;color:var(--shell-fg-muted);margin-left:24px}.admin-field.svelte-1hsgdb4{display:flex;flex-direction:column;gap:4px}.admin-field.svelte-1hsgdb4 span:where(.svelte-1hsgdb4){font-size:13px}.admin-input.svelte-1hsgdb4{padding:8px 12px;background:var(--shell-bg);color:var(--shell-fg);border:1px solid var(--shell-border);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-input-sm.svelte-1hsgdb4{max-width:120px}.admin-btn.svelte-1hsgdb4{padding:8px 16px;font-weight:600;align-self:flex-start}.admin-btn.svelte-1hsgdb4:disabled{opacity:.6;cursor:not-allowed}.admin-error.svelte-1hsgdb4{margin-top:8px;color:var(--shell-error, #d32f2f);font-size:13px}.admin-muted.svelte-1hsgdb4{color:var(--shell-fg-muted);font-style:italic}.admin-system.svelte-1gkiloq{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-system.svelte-1gkiloq h2:where(.svelte-1gkiloq){margin:0 0 16px;font-size:18px}.admin-system-info.svelte-1gkiloq{margin-bottom:24px}.admin-system-row.svelte-1gkiloq{display:flex;gap:12px;padding:8px 0;border-bottom:1px solid var(--shell-border, #3a3a5c);font-size:13px}.admin-system-label.svelte-1gkiloq{color:var(--shell-fg-subtle);min-width:140px}.admin-system-actions.svelte-1gkiloq{display:flex;flex-direction:column;gap:8px;align-items:flex-start}.admin-btn-danger.svelte-1gkiloq{padding:8px 16px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-weight:600}.admin-btn-danger.svelte-1gkiloq:disabled{opacity:.6;cursor:not-allowed}.admin-error.svelte-1gkiloq{color:var(--shell-error, #d32f2f);font-size:13px}.admin-keys.svelte-1afg5z5{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-keys-header.svelte-1afg5z5{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.admin-keys-header.svelte-1afg5z5 h2:where(.svelte-1afg5z5){margin:0;font-size:18px}.admin-create-form.svelte-1afg5z5{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;max-width:400px}.admin-input.svelte-1afg5z5{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-btn.svelte-1afg5z5{font-weight:600;font-size:13px}.admin-btn.svelte-1afg5z5:disabled{opacity:.6;cursor:not-allowed}.admin-btn-secondary.svelte-1afg5z5{background:transparent;color:var(--shell-fg-subtle);border:1px solid var(--shell-border);font-size:12px}.admin-btn-danger.svelte-1afg5z5{background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:12px}.admin-key-list.svelte-1afg5z5{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.admin-key-item.svelte-1afg5z5{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px)}.admin-key-info.svelte-1afg5z5{display:flex;flex-direction:column;gap:2px}.admin-key-label.svelte-1afg5z5{font-weight:600}.admin-key-meta.svelte-1afg5z5{font-size:11px;color:var(--shell-fg-subtle)}.admin-key-value.svelte-1afg5z5{font-size:12px;color:var(--shell-fg-muted);background:var(--shell-bg, #1a1a2e);padding:2px 6px;border-radius:3px;margin-top:2px;word-break:break-all}.admin-key-actions.svelte-1afg5z5{display:flex;gap:6px;flex-shrink:0}.admin-muted.svelte-1afg5z5{color:var(--shell-fg-muted);font-style:italic}.admin-error.svelte-1afg5z5{color:var(--shell-error, #d32f2f);font-size:13px}button,input[type=button],input[type=submit],input[type=reset],.shell-base-button{padding:6px 14px;background:var(--shell-accent, #6ea8fe);color:#fff;border:none;border-radius:var(--shell-radius);cursor:pointer;font-family:inherit;font-size:.875rem;line-height:var(--shell-line)}button:hover,input[type=button]:hover,input[type=submit]:hover,input[type=reset]:hover,.shell-base-button:hover{filter:brightness(1.12)}button:active,input[type=button]:active,input[type=submit]:active,input[type=reset]:active,.shell-base-button:active{filter:brightness(.92)}.splitter.svelte-1adl4o1{display:flex;width:100%;height:100%;min-width:0;min-height:0}.splitter.horizontal.svelte-1adl4o1{flex-direction:row}.splitter.vertical.svelte-1adl4o1{flex-direction:column}.splitter-pane.svelte-1adl4o1{position:relative;min-width:0;min-height:0;overflow:hidden;display:flex}.horizontal.svelte-1adl4o1>.splitter-pane:where(.svelte-1adl4o1){flex-direction:row}.vertical.svelte-1adl4o1>.splitter-pane:where(.svelte-1adl4o1){flex-direction:column}.splitter-pane.collapsed.svelte-1adl4o1{overflow:visible}.pane-content.svelte-1adl4o1{flex:1 1 0;position:relative;min-width:0;min-height:0;overflow:hidden}.collapse-header.svelte-1adl4o1{appearance:none;flex:0 0 auto;display:flex;align-items:center;justify-content:center;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border:none;color:var(--shell-fg-muted);cursor:pointer;padding:0;font-size:10px}.collapse-header.svelte-1adl4o1:hover{color:var(--shell-fg);background:var(--shell-accent-muted)}body[data-dragging] .collapse-header.svelte-1adl4o1{pointer-events:none}.collapse-header.horizontal.svelte-1adl4o1{width:100%;height:100%;writing-mode:vertical-rl}.collapse-header.vertical.svelte-1adl4o1{width:100%;height:100%}.collapse-header.expanded.horizontal.svelte-1adl4o1{width:16px;height:100%;border-right:1px solid var(--shell-border)}.collapse-header.expanded.vertical.svelte-1adl4o1{width:100%;height:16px;border-bottom:1px solid var(--shell-border)}.splitter-handle.svelte-1adl4o1{flex:0 0 auto;background:var(--shell-border);transition:background-color .12s ease;touch-action:none}.splitter-handle.svelte-1adl4o1:hover,.splitter-handle.dragging.svelte-1adl4o1{background:var(--shell-accent)}body[data-dragging] .splitter-handle.svelte-1adl4o1{pointer-events:none}.splitter-handle.disabled.svelte-1adl4o1{cursor:default;pointer-events:none}.horizontal.svelte-1adl4o1>.splitter-handle:where(.svelte-1adl4o1){width:4px;cursor:col-resize}.vertical.svelte-1adl4o1>.splitter-handle:where(.svelte-1adl4o1){height:4px;cursor:row-resize}.tabbed-panel.svelte-1kxcyhf{display:flex;flex-direction:column;width:100%;height:100%;min-width:0;min-height:0;background:var(--shell-grad-bg, var(--shell-bg))}.tab-strip.svelte-1kxcyhf{position:relative;flex:0 0 auto;display:flex;gap:1px;background:var(--shell-grad-bg-sunken, var(--shell-bg-sunken));border-bottom:1px solid var(--shell-border);padding:0 var(--shell-pad-sm);user-select:none}.tab.svelte-1kxcyhf{appearance:none;background:transparent;border:none;color:var(--shell-fg-muted);font:inherit;font-size:12px;padding:var(--shell-pad-sm) var(--shell-pad-md);margin-top:2px;display:inline-flex;align-items:center;gap:var(--shell-pad-sm);cursor:pointer;border-top:2px solid transparent;border-radius:2px 2px 0 0;touch-action:none}.tab.svelte-1kxcyhf:hover{color:var(--shell-fg);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated))}.tab.active.svelte-1kxcyhf{color:var(--shell-fg);background:var(--shell-grad-bg, var(--shell-bg));border-top-color:var(--shell-accent)}.tab-icon.svelte-1kxcyhf{font-size:11px}.tab-label.svelte-1kxcyhf{white-space:nowrap}.tab-dirty.svelte-1kxcyhf{width:8px;height:8px;border-radius:50%;background:var(--shell-accent);flex-shrink:0}.tab-close.svelte-1kxcyhf{display:inline-flex;font-size:10px;line-height:1;padding:2px;border-radius:var(--shell-radius-sm);color:var(--shell-fg-muted);cursor:pointer;flex-shrink:0;margin-left:auto}.tab-close.svelte-1kxcyhf:hover{color:var(--shell-fg);background:var(--shell-bg-sunken)}.drop-indicator.svelte-1kxcyhf{position:absolute;width:2px;background:var(--shell-accent);box-shadow:0 0 6px var(--shell-accent);pointer-events:none;border-radius:1px}.tab-body.svelte-1kxcyhf{flex:1 1 auto;position:relative;min-width:0;min-height:0;overflow:hidden}.tab-body-pane.svelte-1kxcyhf{position:absolute;inset:0;min-width:0;min-height:0;display:none}.tab-body-pane.active.svelte-1kxcyhf{display:block}.slot.svelte-1czj0s8{position:relative;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden}.slot-placeholder.svelte-1czj0s8{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--shell-pad-sm);color:var(--shell-fg-muted);font-size:12px;text-align:center;padding:var(--shell-pad-md);background:repeating-linear-gradient(45deg,var(--shell-bg) 0 10px,var(--shell-bg-elevated) 10px 20px);border:1px dashed var(--shell-border-strong);pointer-events:none}.slot-id.svelte-1czj0s8{color:var(--shell-fg);font-family:var(--shell-font-mono);font-size:13px}.slot-meta.svelte-1czj0s8 code:where(.svelte-1czj0s8){font-family:var(--shell-font-mono);color:var(--shell-accent)}.slot-dims.svelte-1czj0s8{font-family:var(--shell-font-mono);color:var(--shell-fg-subtle);font-size:11px}.slot-drop-zone.svelte-re71zu{position:absolute;inset:0;pointer-events:none}.slot-drop-zone.active.svelte-re71zu{pointer-events:auto}.quad-highlight.svelte-re71zu{position:absolute;background:var(--shell-accent);opacity:.18;border:1px dashed var(--shell-accent);pointer-events:none;transition:inset 80ms ease}.quad-highlight.quad-left.svelte-re71zu{inset:0 50% 0 0}.quad-highlight.quad-right.svelte-re71zu{inset:0 0 0 50%}.quad-highlight.quad-top.svelte-re71zu{inset:0 0 50%}.quad-highlight.quad-bottom.svelte-re71zu{inset:50% 0 0}.tab-slot-wrapper.svelte-1gw9g38,.leaf-slot-wrapper.svelte-1gw9g38{position:absolute;inset:0;min-width:0;min-height:0}.empty-tabs-placeholder.svelte-1gw9g38{width:100%;height:100%;min-width:0;min-height:0;position:relative}.empty-tabs-default.svelte-1gw9g38{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--shell-fg-muted);font-size:12px;background:repeating-linear-gradient(45deg,var(--shell-bg) 0 10px,var(--shell-bg-elevated) 10px 20px);border:1px dashed var(--shell-border-strong)}.empty-tabs-custom.svelte-1gw9g38{position:absolute;inset:0}.empty-tabs-drop.svelte-1gw9g38{position:absolute;inset:0;pointer-events:auto}.drag-preview.svelte-133fiip{position:absolute;display:inline-flex;align-items:center;gap:var(--shell-pad-sm);padding:var(--shell-pad-sm) var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-accent);border-radius:var(--shell-radius-sm);box-shadow:0 8px 24px #00000080;font-size:12px;font-family:var(--shell-font-ui);pointer-events:none;opacity:.9}.drag-preview-icon.svelte-133fiip{font-size:11px}.drag-preview-label.svelte-133fiip{white-space:nowrap}.guest-banner.svelte-pymkh{display:flex;align-items:center;justify-content:center;gap:12px;padding:6px var(--shell-pad-md, 12px);background:color-mix(in srgb,var(--shell-accent, #7c7cf0) 15%,transparent);border-bottom:1px solid var(--shell-border, #3a3a5c);font-size:12px;color:var(--shell-fg, #e0e0e0)}.guest-banner-action.svelte-pymkh{padding:3px 10px;color:var(--shell-bg, #1a1a2e);font-size:11px;font-weight:600}.guest-signin-overlay.svelte-pymkh{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#00000080;z-index:9999}.guest-signin-card.svelte-pymkh{display:flex;flex-direction:column;gap:12px;padding:32px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius-lg, 12px);min-width:300px}.guest-signin-form.svelte-pymkh{display:flex;flex-direction:column;gap:10px}.guest-signin-input.svelte-pymkh{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.guest-signin-input.svelte-pymkh::placeholder{color:var(--shell-fg-muted, #888)}.guest-signin-actions.svelte-pymkh{display:flex;gap:8px}.guest-signin-btn.svelte-pymkh{flex:1;padding:8px;color:var(--shell-bg, #1a1a2e);font-weight:600}.guest-signin-btn.svelte-pymkh:disabled{opacity:.6;cursor:not-allowed}.guest-signin-cancel.svelte-pymkh{padding:8px 12px;background:transparent;color:var(--shell-fg-subtle, #aaa);border:1px solid var(--shell-border, #3a3a5c)}.guest-signin-error.svelte-pymkh{padding:6px 10px;font-size:12px;color:var(--shell-error, #d32f2f);background:color-mix(in srgb,var(--shell-error, #d32f2f) 10%,transparent);border-radius:var(--shell-radius, 6px)}.shell.svelte-187fra4{display:grid;grid-template-rows:var(--shell-tabbar-height) auto 1fr var(--shell-statusbar-height);height:100%;width:100%;position:relative;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg)}.shell-tabbar.svelte-187fra4{display:flex;align-items:center;gap:var(--shell-pad-md);padding:0 var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border-bottom:1px solid var(--shell-border);user-select:none}.shell-tabbar-brand.svelte-187fra4{font-weight:600;color:var(--shell-accent);letter-spacing:.5px}.shell-content.svelte-187fra4{position:relative;overflow:hidden;background:var(--shell-grad-bg, var(--shell-bg));min-width:0;min-height:0}.shell-statusbar.svelte-187fra4{display:flex;align-items:center;justify-content:space-between;padding:0 var(--shell-pad-md);background:var(--shell-grad-bg-sunken, var(--shell-bg-sunken));border-top:1px solid var(--shell-border);color:var(--shell-fg-muted);font-size:11px;user-select:none}.shell-overlays.svelte-187fra4,.shell-overlay-root.svelte-187fra4{position:absolute;inset:0;pointer-events:none}.shell-tabbar-home-button.svelte-187fra4{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:var(--shell-fg-muted);border:1px solid var(--shell-border)}.shell-tabbar-home-button.svelte-187fra4:hover:not(:disabled){color:var(--shell-fg);border-color:var(--shell-fg-muted)}.shell-tabbar-home-button.svelte-187fra4:disabled{color:var(--shell-fg-subtle);border-color:var(--shell-border);cursor:default}.shell-tabbar-home-icon.svelte-187fra4{width:14px;height:14px}.shell-tabbar-user.svelte-187fra4{display:flex;align-items:center;gap:6px;margin-left:auto}.shell-tabbar-user-name.svelte-187fra4{font-size:12px;color:var(--shell-fg-subtle)}.shell-tabbar-tag.svelte-187fra4{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#fff;background:var(--shell-accent);padding:1px 6px;border-radius:6px}.shell-tabbar-signout.svelte-187fra4{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:var(--shell-fg-muted);border:1px solid var(--shell-border)}.shell-tabbar-signout.svelte-187fra4:hover{color:var(--shell-fg);border-color:var(--shell-fg-muted)}.shell-tabbar-signout-icon.svelte-187fra4{width:14px;height:14px}.signin-wall.svelte-lh4k15{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:var(--shell-grad-bg, var(--shell-bg, #1a1a2e));color:var(--shell-fg, #e0e0e0);font-family:system-ui,sans-serif}.signin-card.svelte-lh4k15{display:flex;flex-direction:column;align-items:center;gap:16px;padding:48px 40px;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated, #252540));border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius-lg, 12px);min-width:320px}.signin-brand.svelte-lh4k15{margin:0 0 8px;font-size:42px;color:var(--shell-accent, #7c7cf0);letter-spacing:2px}.signin-form.svelte-lh4k15{display:flex;flex-direction:column;gap:12px;width:100%}.signin-input.svelte-lh4k15{padding:10px 14px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:14px}.signin-input.svelte-lh4k15::placeholder{color:var(--shell-fg-muted, #888)}.signin-btn.svelte-lh4k15{padding:10px 16px;color:var(--shell-bg, #1a1a2e);font-weight:600;font-size:14px}.signin-btn.svelte-lh4k15:disabled{opacity:.6;cursor:not-allowed}.signin-link.svelte-lh4k15{background:none;color:var(--shell-accent, #7c7cf0);font-size:13px;padding:0}.signin-link.svelte-lh4k15:hover{text-decoration:underline}.signin-error.svelte-lh4k15{padding:8px 12px;font-size:13px;color:var(--shell-error, #d32f2f);background:color-mix(in srgb,var(--shell-error, #d32f2f) 10%,transparent);border-radius:var(--shell-radius, 6px);width:100%;text-align:center}:root{--shell-bg: #1a1b1e;--shell-bg-elevated: #22232a;--shell-bg-sunken: #141518;--shell-border: #2e3038;--shell-border-strong: #3c3f4a;--shell-fg: #e4e6eb;--shell-fg-muted: #9aa0aa;--shell-fg-subtle: #6b7280;--shell-accent: #6ea8fe;--shell-accent-muted: #3a5580;--shell-input-bg: #2a2a2a;--shell-error: #f87171;--shell-warning: #fbbf24;--shell-success: #34d399;--shell-font-ui: system-ui, -apple-system, "Segoe UI", sans-serif;--shell-font-mono: ui-monospace, "Cascadia Code", "Consolas", monospace;--shell-font-size: 13px;--shell-line: 1.45;--shell-radius-sm: 3px;--shell-radius: 4px;--shell-radius-md: 6px;--shell-radius-lg: 8px;--shell-pad-xs: 2px;--shell-pad-sm: 4px;--shell-pad-md: 8px;--shell-pad-lg: 12px;--shell-tabbar-height: 32px;--shell-statusbar-height: 22px;--shell-z-layer-0: 0;--shell-z-layer-1: 100;--shell-z-layer-2: 200;--shell-z-layer-3: 300;--shell-z-layer-4: 400;--shell-z-layer-5: 500;--shell-z-layer-6: 600}*,*:before,*:after{box-sizing:border-box}html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg);font-family:var(--shell-font-ui);font-size:var(--shell-font-size);line-height:var(--shell-line);-webkit-font-smoothing:antialiased}#app{height:100%}
1
+ .modal-frame.svelte-2tcvcm{position:absolute;inset:0;display:grid;place-items:center;pointer-events:auto}.modal-box.svelte-2tcvcm{background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-radius:var(--shell-radius);min-width:320px;max-width:min(640px,90vw);max-height:90vh;overflow:auto;box-shadow:0 20px 48px #00000080;outline:none}.popup-frame.svelte-mp81cl{position:absolute;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-radius:var(--shell-radius-sm);box-shadow:0 8px 24px #0006;min-width:120px;outline:none;pointer-events:auto}.toast.svelte-12gwnj0{pointer-events:auto;display:flex;align-items:center;gap:var(--shell-pad-md);padding:var(--shell-pad-sm) var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-left-width:3px;border-radius:var(--shell-radius-sm);box-shadow:0 8px 20px #0006;font-size:12px;min-width:220px;max-width:360px;cursor:pointer;animation:svelte-12gwnj0-toast-in .16s ease-out both}.toast-level.svelte-12gwnj0{text-transform:uppercase;font-family:var(--shell-font-mono);font-size:10px;letter-spacing:.5px;color:var(--shell-fg-muted)}.toast-message.svelte-12gwnj0{flex:1}.toast-info.svelte-12gwnj0{border-left-color:var(--shell-accent)}.toast-success.svelte-12gwnj0{border-left-color:#5cb176}.toast-warn.svelte-12gwnj0{border-left-color:#d6a84a}.toast-error.svelte-12gwnj0{border-left-color:#d06060}@keyframes svelte-12gwnj0-toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.shell-title.svelte-1ifjvh5{display:inline-block;line-height:0;overflow:hidden}.shell-title.svelte-1ifjvh5 canvas{transform:scale(var(--shell-title-scale));transform-origin:top left;display:block}.shell-title-fallback.svelte-1ifjvh5{margin:0;font-size:42px;color:var(--shell-accent);letter-spacing:2px}.shell-home.svelte-cpn2x2{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:48px 24px;overflow:auto;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg);font-family:system-ui,sans-serif}.shell-home-header.svelte-cpn2x2{text-align:center;margin-bottom:32px;display:flex;flex-direction:column;align-items:center;gap:12px}.shell-home-title-row.svelte-cpn2x2{display:flex;align-items:baseline;gap:6px}.shell-home-credit.svelte-cpn2x2{font-size:11px;color:var(--shell-fg-muted);letter-spacing:.04em;margin-top:-4px}.shell-home-credit.svelte-cpn2x2 a:where(.svelte-cpn2x2){color:var(--shell-fg-subtle);text-decoration:none;border-bottom:1px dotted var(--shell-fg-muted)}.shell-home-credit.svelte-cpn2x2 a:where(.svelte-cpn2x2):hover{color:var(--shell-accent);border-bottom-color:var(--shell-accent)}.shell-home-version.svelte-cpn2x2{font-size:14px;color:var(--shell-fg-subtle);letter-spacing:.04em}.shell-home-alpha.svelte-cpn2x2{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#fff;background:var(--shell-accent);padding:2px 8px;border-radius:8px;position:relative;top:-1px}.shell-home-empty.svelte-cpn2x2{color:var(--shell-fg-muted);font-style:italic}.shell-home-section.svelte-cpn2x2{width:100%;max-width:440px;margin-bottom:24px}.shell-home-section-title.svelte-cpn2x2{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--shell-fg-subtle);margin:0 0 12px}.shell-home-list.svelte-cpn2x2{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:12px}.shell-home-entry.svelte-cpn2x2{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto auto;gap:4px 16px;align-items:center;padding:14px 18px;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border:1px solid var(--shell-border);border-radius:var(--shell-radius-md)}.shell-home-entry-label.svelte-cpn2x2{grid-column:1;grid-row:1;font-weight:600}.shell-home-entry-meta.svelte-cpn2x2{grid-column:1;grid-row:2;font-size:11px;color:var(--shell-fg-subtle)}.shell-home-launch.svelte-cpn2x2{grid-column:2;grid-row:1 / span 2;padding:8px 16px;font-weight:600}.shell-text.svelte-ypr8s{margin:0;padding:0 8px;font-family:var(--shell-font-mono, monospace);white-space:pre-wrap;word-break:break-word;color:var(--shell-fg, #ddd)}.shell-text.stderr.svelte-ypr8s{color:var(--shell-fg-error, #f88)}.shell-prompt.svelte-u0gb59{padding:4px 8px 0;font-family:var(--shell-font-mono, monospace);display:flex;gap:8px}.shell-prompt-cwd.svelte-u0gb59{color:var(--shell-fg-muted, #888)}.shell-prompt-arrow.svelte-u0gb59{color:var(--shell-accent, #6cf)}.shell-prompt-line.svelte-u0gb59{color:var(--shell-fg, #ddd)}.shell-status.svelte-nfxdpt{padding:2px 8px;font-family:var(--shell-font-mono, monospace);font-style:italic}.shell-status.info.svelte-nfxdpt{color:var(--shell-fg-muted, #888)}.shell-status.warn.svelte-nfxdpt{color:var(--shell-fg-warn, #fc6)}.shell-status.error.svelte-nfxdpt{color:var(--shell-fg-error, #f88)}.shell-rich.svelte-1rnhl05{padding:4px 8px}.shell-scrollback.svelte-isy3jt{flex:1 1 auto;overflow-y:auto;background:var(--shell-bg, #111);color:var(--shell-fg, #ddd)}.shell-input.svelte-1dfv2gk{display:flex;gap:8px;padding:4px 8px;border-top:1px solid var(--shell-border, #333);font-family:var(--shell-font-mono, monospace)}.shell-input-cwd.svelte-1dfv2gk{color:var(--shell-fg-muted, #888)}.shell-input-arrow.svelte-1dfv2gk{color:var(--shell-accent, #6cf)}.shell-input-field.svelte-1dfv2gk{flex:1 1 auto;background:transparent;border:0;outline:0;color:var(--shell-fg, #ddd);font:inherit}.shell-input.locked.svelte-1dfv2gk .shell-input-field:where(.svelte-1dfv2gk){opacity:.5;cursor:default}.shell-terminal.svelte-13komre{display:flex;flex-direction:column;height:100%;background:var(--shell-bg, #111);color:var(--shell-fg, #ddd)}.shell-rich-help.svelte-m248jy table:where(.svelte-m248jy){border-collapse:collapse;width:100%}.shell-rich-help.svelte-m248jy th:where(.svelte-m248jy),.shell-rich-help.svelte-m248jy td:where(.svelte-m248jy){padding:2px 8px;text-align:left}.shell-rich-help.svelte-m248jy button:where(.svelte-m248jy){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-help.svelte-m248jy button:where(.svelte-m248jy):hover{text-decoration:underline}.shell-rich-history.svelte-o8m437 ol:where(.svelte-o8m437){list-style-position:inside;margin:0;padding:0}.shell-rich-history.svelte-o8m437 li:where(.svelte-o8m437){padding:2px 0}.shell-rich-history.svelte-o8m437 button:where(.svelte-o8m437){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit;text-align:left}.shell-rich-history.svelte-o8m437 button:where(.svelte-o8m437):hover{text-decoration:underline}.shell-rich-apps.svelte-1u5krjz table:where(.svelte-1u5krjz){border-collapse:collapse;width:100%}.shell-rich-apps.svelte-1u5krjz th:where(.svelte-1u5krjz),.shell-rich-apps.svelte-1u5krjz td:where(.svelte-1u5krjz){padding:2px 8px;text-align:left}.shell-rich-apps.svelte-1u5krjz button:where(.svelte-1u5krjz){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-apps.svelte-1u5krjz button:where(.svelte-1u5krjz):hover{text-decoration:underline}.shell-rich-appcard.svelte-npcp8i{padding:8px;border:1px solid var(--shell-border, #444)}.shell-rich-appcard.svelte-npcp8i h3:where(.svelte-npcp8i){margin:0 0 8px}.shell-rich-appcard.svelte-npcp8i p:where(.svelte-npcp8i){margin:4px 0}.shell-rich-shards.svelte-sc3ux4 table:where(.svelte-sc3ux4){border-collapse:collapse;width:100%}.shell-rich-shards.svelte-sc3ux4 th:where(.svelte-sc3ux4),.shell-rich-shards.svelte-sc3ux4 td:where(.svelte-sc3ux4){padding:2px 8px;text-align:left}.shell-rich-views.svelte-15elbr1 table:where(.svelte-15elbr1){border-collapse:collapse;width:100%}.shell-rich-views.svelte-15elbr1 th:where(.svelte-15elbr1),.shell-rich-views.svelte-15elbr1 td:where(.svelte-15elbr1){padding:2px 8px;text-align:left}.shell-rich-views.svelte-15elbr1 button:where(.svelte-15elbr1){background:none;border:0;color:var(--shell-link, #6cf);cursor:pointer;padding:0;font:inherit}.shell-rich-views.svelte-15elbr1 button:where(.svelte-15elbr1):hover{text-decoration:underline}.shell-rich-zones.svelte-1w7onag table:where(.svelte-1w7onag){border-collapse:collapse;width:100%}.shell-rich-zones.svelte-1w7onag th:where(.svelte-1w7onag),.shell-rich-zones.svelte-1w7onag td:where(.svelte-1w7onag){padding:2px 8px;text-align:left}.shell-rich-zonetree.svelte-13iiyr1 pre:where(.svelte-13iiyr1){overflow:auto;padding:8px;background:var(--shell-bg, #000);color:var(--shell-fg, #fff)}.shell-rich-env.svelte-1ox8vog table:where(.svelte-1ox8vog){border-collapse:collapse;width:100%}.shell-rich-env.svelte-1ox8vog th:where(.svelte-1ox8vog),.shell-rich-env.svelte-1ox8vog td:where(.svelte-1ox8vog){padding:2px 8px;text-align:left}.store-view.svelte-1aafzt0{font-family:var(--shell-font-ui);color:var(--shell-fg, #e0e0e0);background:var(--shell-bg, #1e1e1e);padding:16px;height:100%;overflow-y:auto;box-sizing:border-box}.store-header.svelte-1aafzt0{margin-bottom:16px}.store-header.svelte-1aafzt0 h2:where(.svelte-1aafzt0){margin:0 0 8px;font-size:1.25rem;font-weight:600}.store-controls.svelte-1aafzt0{display:flex;gap:8px;flex-wrap:wrap}.store-search.svelte-1aafzt0{flex:1;min-width:160px;padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.875rem}.store-search.svelte-1aafzt0::placeholder{color:var(--shell-fg-muted, #888)}.store-filter.svelte-1aafzt0{padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.875rem}.store-refresh.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-error.svelte-1aafzt0{padding:8px 12px;margin-bottom:12px;background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent);color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius);font-size:.8125rem}.store-grid.svelte-1aafzt0{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.store-card.svelte-1aafzt0{background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius-md);padding:14px;display:flex;flex-direction:column;gap:8px}.store-card.svelte-1aafzt0:hover{border-color:var(--shell-accent, #007acc)}.store-card-header.svelte-1aafzt0{display:flex;align-items:center;gap:10px}.store-card-icon.svelte-1aafzt0{width:36px;height:36px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.store-icon-img.svelte-1aafzt0{width:36px;height:36px;border-radius:var(--shell-radius);object-fit:cover}.store-icon-placeholder.svelte-1aafzt0{width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:var(--shell-accent, #007acc);color:#fff;border-radius:var(--shell-radius);font-weight:700;font-size:1rem}.store-card-title.svelte-1aafzt0{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.store-card-label.svelte-1aafzt0{font-weight:600;font-size:.9375rem}.store-card-badge.svelte-1aafzt0{font-size:.6875rem;padding:1px 6px;border-radius:var(--shell-radius-sm);text-transform:uppercase;font-weight:600;letter-spacing:.04em}.badge-shard.svelte-1aafzt0{background:color-mix(in srgb,var(--shell-accent, #007acc) 25%,transparent);color:var(--shell-accent, #007acc)}.badge-app.svelte-1aafzt0{background:color-mix(in srgb,var(--shell-success, #4caf50) 25%,transparent);color:var(--shell-success, #4caf50)}.store-card-version.svelte-1aafzt0{font-size:.75rem;color:var(--shell-fg-muted, #888)}.store-card-desc.svelte-1aafzt0{margin:0;font-size:.8125rem;color:var(--shell-fg-muted, #888);line-height:1.4}.store-card-author.svelte-1aafzt0{font-size:.75rem;color:var(--shell-fg-muted, #888)}.store-card-warning.svelte-1aafzt0{font-size:.75rem;color:var(--shell-warning, #ff9800);padding:4px 8px;background:color-mix(in srgb,var(--shell-warning, #ff9800) 10%,transparent);border-radius:var(--shell-radius-sm)}.store-card-actions.svelte-1aafzt0{margin-top:auto;display:flex;justify-content:flex-end}.store-install-btn.svelte-1aafzt0{padding:5px 14px;font-size:.8125rem}.store-install-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-installed-label.svelte-1aafzt0{font-size:.8125rem;color:var(--shell-success, #4caf50);font-weight:600}.store-update-btn.svelte-1aafzt0{padding:5px 14px;background:var(--shell-warning, #ff9800);font-size:.8125rem}.store-update-btn.svelte-1aafzt0:hover:not(:disabled){filter:brightness(1.1)}.store-update-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.store-empty.svelte-1aafzt0{text-align:center;padding:32px 16px;color:var(--shell-fg-muted, #888);font-size:.875rem}.store-registries.svelte-1aafzt0{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}.store-registry-entry.svelte-1aafzt0{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-size:.8125rem}.store-registry-url.svelte-1aafzt0{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--shell-fg-muted, #888)}.store-registry-remove.svelte-1aafzt0{padding:2px 8px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius-sm);font-size:.75rem;flex-shrink:0;margin-left:8px}.store-add-registry.svelte-1aafzt0{display:flex;gap:8px;margin-bottom:12px}.store-registry-input.svelte-1aafzt0{flex:1;padding:6px 10px;background:var(--shell-input-bg, #2a2a2a);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius);font-family:inherit;font-size:.8125rem}.store-registry-input.svelte-1aafzt0::placeholder{color:var(--shell-fg-muted, #888)}.store-add-btn.svelte-1aafzt0{font-size:.8125rem;white-space:nowrap}.store-add-btn.svelte-1aafzt0:disabled{opacity:.6;cursor:not-allowed}.installed-view.svelte-1hqclkp{font-family:var(--shell-font-ui);color:var(--shell-fg, #e0e0e0);background:var(--shell-bg, #1e1e1e);padding:16px;height:100%;overflow-y:auto;box-sizing:border-box}.installed-header.svelte-1hqclkp{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.installed-header.svelte-1hqclkp h2:where(.svelte-1hqclkp){margin:0;font-size:1.25rem;font-weight:600}.installed-empty.svelte-1hqclkp{text-align:center;padding:32px 16px;color:var(--shell-fg-muted, #888);font-size:.875rem}.installed-list.svelte-1hqclkp{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.installed-item.svelte-1hqclkp{background:var(--shell-input-bg, #2a2a2a);border:1px solid var(--shell-border, #444);border-radius:var(--shell-radius-md);padding:12px 14px;display:flex;flex-direction:column;gap:6px}.installed-item-main.svelte-1hqclkp{display:flex;align-items:center;gap:8px}.installed-item-id.svelte-1hqclkp{font-weight:600;font-size:.9375rem}.installed-item-badge.svelte-1hqclkp{font-size:.6875rem;padding:1px 6px;border-radius:var(--shell-radius-sm);text-transform:uppercase;font-weight:600;letter-spacing:.04em}.badge-shard.svelte-1hqclkp{background:color-mix(in srgb,var(--shell-accent, #007acc) 25%,transparent);color:var(--shell-accent, #007acc)}.badge-app.svelte-1hqclkp{background:color-mix(in srgb,var(--shell-success, #4caf50) 25%,transparent);color:var(--shell-success, #4caf50)}.installed-item-version.svelte-1hqclkp{font-size:.75rem;color:var(--shell-fg-muted, #888)}.installed-item-meta.svelte-1hqclkp{display:flex;gap:16px;flex-wrap:wrap;font-size:.75rem;color:var(--shell-fg-muted, #888)}.installed-item-actions.svelte-1hqclkp{display:flex;justify-content:flex-end;gap:8px}.installed-uninstall-btn.svelte-1hqclkp{padding:4px 12px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:.8125rem}.installed-uninstall-btn.svelte-1hqclkp:hover:not(:disabled){background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent)}.installed-uninstall-btn.svelte-1hqclkp:disabled{opacity:.6;cursor:not-allowed}.installed-update-btn.svelte-1hqclkp{padding:4px 12px;background:var(--shell-warning, #ff9800);font-size:.8125rem}.installed-update-btn.svelte-1hqclkp:hover:not(:disabled){filter:brightness(1.1)}.installed-update-btn.svelte-1hqclkp:disabled{opacity:.6;cursor:not-allowed}.installed-error.svelte-1hqclkp{padding:8px 12px;margin-bottom:12px;background:color-mix(in srgb,var(--shell-error, #d32f2f) 15%,transparent);color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);border-radius:var(--shell-radius);font-size:.8125rem}.admin-users.svelte-4q792t{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-users-header.svelte-4q792t{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.admin-users-header.svelte-4q792t h2:where(.svelte-4q792t){margin:0;font-size:18px}.admin-create-form.svelte-4q792t,.admin-edit-form.svelte-4q792t{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;max-width:400px}.admin-input.svelte-4q792t{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-btn.svelte-4q792t{font-weight:600;font-size:13px}.admin-btn.svelte-4q792t:disabled{opacity:.6;cursor:not-allowed}.admin-btn-secondary.svelte-4q792t{background:transparent;color:var(--shell-fg-subtle);border:1px solid var(--shell-border);font-size:12px}.admin-btn-danger.svelte-4q792t{background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:12px}.admin-user-list.svelte-4q792t{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.admin-user-item.svelte-4q792t{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px)}.admin-user-info.svelte-4q792t{display:flex;flex-direction:column;gap:2px}.admin-user-name.svelte-4q792t{font-weight:600}.admin-user-meta.svelte-4q792t{font-size:11px;color:var(--shell-fg-subtle)}.admin-user-actions.svelte-4q792t,.admin-edit-actions.svelte-4q792t{display:flex;gap:6px}.admin-error.svelte-4q792t{color:var(--shell-error, #d32f2f);font-size:13px}.admin-muted.svelte-4q792t{color:var(--shell-fg-muted);font-style:italic}.admin-auth.svelte-1hsgdb4{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-auth.svelte-1hsgdb4 h2:where(.svelte-1hsgdb4){margin:0 0 16px;font-size:18px}.admin-auth-fields.svelte-1hsgdb4{display:flex;flex-direction:column;gap:16px;max-width:480px}.admin-toggle.svelte-1hsgdb4{display:flex;flex-wrap:wrap;align-items:center;gap:8px;cursor:pointer}.admin-toggle.svelte-1hsgdb4 input:where(.svelte-1hsgdb4){accent-color:var(--shell-accent, #7c7cf0)}.admin-hint.svelte-1hsgdb4{flex-basis:100%;font-size:11px;color:var(--shell-fg-muted);margin-left:24px}.admin-field.svelte-1hsgdb4{display:flex;flex-direction:column;gap:4px}.admin-field.svelte-1hsgdb4 span:where(.svelte-1hsgdb4){font-size:13px}.admin-input.svelte-1hsgdb4{padding:8px 12px;background:var(--shell-bg);color:var(--shell-fg);border:1px solid var(--shell-border);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-input-sm.svelte-1hsgdb4{max-width:120px}.admin-btn.svelte-1hsgdb4{padding:8px 16px;font-weight:600;align-self:flex-start}.admin-btn.svelte-1hsgdb4:disabled{opacity:.6;cursor:not-allowed}.admin-error.svelte-1hsgdb4{margin-top:8px;color:var(--shell-error, #d32f2f);font-size:13px}.admin-muted.svelte-1hsgdb4{color:var(--shell-fg-muted);font-style:italic}.admin-system.svelte-1gkiloq{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-system.svelte-1gkiloq h2:where(.svelte-1gkiloq){margin:0 0 16px;font-size:18px}.admin-system-info.svelte-1gkiloq{margin-bottom:24px}.admin-system-row.svelte-1gkiloq{display:flex;gap:12px;padding:8px 0;border-bottom:1px solid var(--shell-border, #3a3a5c);font-size:13px}.admin-system-label.svelte-1gkiloq{color:var(--shell-fg-subtle);min-width:140px}.admin-system-actions.svelte-1gkiloq{display:flex;flex-direction:column;gap:8px;align-items:flex-start}.admin-btn-danger.svelte-1gkiloq{padding:8px 16px;background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-weight:600}.admin-btn-danger.svelte-1gkiloq:disabled{opacity:.6;cursor:not-allowed}.admin-error.svelte-1gkiloq{color:var(--shell-error, #d32f2f);font-size:13px}.admin-keys.svelte-1afg5z5{padding:24px;font-family:system-ui,sans-serif;color:var(--shell-fg)}.admin-keys-header.svelte-1afg5z5{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.admin-keys-header.svelte-1afg5z5 h2:where(.svelte-1afg5z5){margin:0;font-size:18px}.admin-create-form.svelte-1afg5z5{display:flex;flex-direction:column;gap:8px;margin-bottom:16px;max-width:400px}.admin-input.svelte-1afg5z5{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.admin-btn.svelte-1afg5z5{font-weight:600;font-size:13px}.admin-btn.svelte-1afg5z5:disabled{opacity:.6;cursor:not-allowed}.admin-btn-secondary.svelte-1afg5z5{background:transparent;color:var(--shell-fg-subtle);border:1px solid var(--shell-border);font-size:12px}.admin-btn-danger.svelte-1afg5z5{background:transparent;color:var(--shell-error, #d32f2f);border:1px solid var(--shell-error, #d32f2f);font-size:12px}.admin-key-list.svelte-1afg5z5{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.admin-key-item.svelte-1afg5z5{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px)}.admin-key-info.svelte-1afg5z5{display:flex;flex-direction:column;gap:2px}.admin-key-label.svelte-1afg5z5{font-weight:600}.admin-key-meta.svelte-1afg5z5{font-size:11px;color:var(--shell-fg-subtle)}.admin-key-value.svelte-1afg5z5{font-size:12px;color:var(--shell-fg-muted);background:var(--shell-bg, #1a1a2e);padding:2px 6px;border-radius:3px;margin-top:2px;word-break:break-all}.admin-key-actions.svelte-1afg5z5{display:flex;gap:6px;flex-shrink:0}.admin-muted.svelte-1afg5z5{color:var(--shell-fg-muted);font-style:italic}.admin-error.svelte-1afg5z5{color:var(--shell-error, #d32f2f);font-size:13px}button,input[type=button],input[type=submit],input[type=reset],.shell-base-button{padding:6px 14px;background:var(--shell-accent, #6ea8fe);color:#fff;border:none;border-radius:var(--shell-radius);cursor:pointer;font-family:inherit;font-size:.875rem;line-height:var(--shell-line)}button:hover,input[type=button]:hover,input[type=submit]:hover,input[type=reset]:hover,.shell-base-button:hover{filter:brightness(1.12)}button:active,input[type=button]:active,input[type=submit]:active,input[type=reset]:active,.shell-base-button:active{filter:brightness(.92)}.splitter.svelte-1adl4o1{display:flex;width:100%;height:100%;min-width:0;min-height:0}.splitter.horizontal.svelte-1adl4o1{flex-direction:row}.splitter.vertical.svelte-1adl4o1{flex-direction:column}.splitter-pane.svelte-1adl4o1{position:relative;min-width:0;min-height:0;overflow:hidden;display:flex}.horizontal.svelte-1adl4o1>.splitter-pane:where(.svelte-1adl4o1){flex-direction:row}.vertical.svelte-1adl4o1>.splitter-pane:where(.svelte-1adl4o1){flex-direction:column}.splitter-pane.collapsed.svelte-1adl4o1{overflow:visible}.pane-content.svelte-1adl4o1{flex:1 1 0;position:relative;min-width:0;min-height:0;overflow:hidden}.collapse-header.svelte-1adl4o1{appearance:none;flex:0 0 auto;display:flex;align-items:center;justify-content:center;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border:none;color:var(--shell-fg-muted);cursor:pointer;padding:0;font-size:10px}.collapse-header.svelte-1adl4o1:hover{color:var(--shell-fg);background:var(--shell-accent-muted)}body[data-dragging] .collapse-header.svelte-1adl4o1{pointer-events:none}.collapse-header.horizontal.svelte-1adl4o1{width:100%;height:100%;writing-mode:vertical-rl}.collapse-header.vertical.svelte-1adl4o1{width:100%;height:100%}.collapse-header.expanded.horizontal.svelte-1adl4o1{width:16px;height:100%;border-right:1px solid var(--shell-border)}.collapse-header.expanded.vertical.svelte-1adl4o1{width:100%;height:16px;border-bottom:1px solid var(--shell-border)}.splitter-handle.svelte-1adl4o1{flex:0 0 auto;background:var(--shell-border);transition:background-color .12s ease;touch-action:none}.splitter-handle.svelte-1adl4o1:hover,.splitter-handle.dragging.svelte-1adl4o1{background:var(--shell-accent)}body[data-dragging] .splitter-handle.svelte-1adl4o1{pointer-events:none}.splitter-handle.disabled.svelte-1adl4o1{cursor:default;pointer-events:none}.horizontal.svelte-1adl4o1>.splitter-handle:where(.svelte-1adl4o1){width:4px;cursor:col-resize}.vertical.svelte-1adl4o1>.splitter-handle:where(.svelte-1adl4o1){height:4px;cursor:row-resize}.tabbed-panel.svelte-1kxcyhf{display:flex;flex-direction:column;width:100%;height:100%;min-width:0;min-height:0;background:var(--shell-grad-bg, var(--shell-bg))}.tab-strip.svelte-1kxcyhf{position:relative;flex:0 0 auto;display:flex;gap:1px;background:var(--shell-grad-bg-sunken, var(--shell-bg-sunken));border-bottom:1px solid var(--shell-border);padding:0 var(--shell-pad-sm);user-select:none}.tab.svelte-1kxcyhf{appearance:none;background:transparent;border:none;color:var(--shell-fg-muted);font:inherit;font-size:12px;padding:var(--shell-pad-sm) var(--shell-pad-md);margin-top:2px;display:inline-flex;align-items:center;gap:var(--shell-pad-sm);cursor:pointer;border-top:2px solid transparent;border-radius:2px 2px 0 0;touch-action:none}.tab.svelte-1kxcyhf:hover{color:var(--shell-fg);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated))}.tab.active.svelte-1kxcyhf{color:var(--shell-fg);background:var(--shell-grad-bg, var(--shell-bg));border-top-color:var(--shell-accent)}.tab-icon.svelte-1kxcyhf{font-size:11px}.tab-label.svelte-1kxcyhf{white-space:nowrap}.tab-dirty.svelte-1kxcyhf{width:8px;height:8px;border-radius:50%;background:var(--shell-accent);flex-shrink:0}.tab-close.svelte-1kxcyhf{display:inline-flex;font-size:10px;line-height:1;padding:2px;border-radius:var(--shell-radius-sm);color:var(--shell-fg-muted);cursor:pointer;flex-shrink:0;margin-left:auto}.tab-close.svelte-1kxcyhf:hover{color:var(--shell-fg);background:var(--shell-bg-sunken)}.drop-indicator.svelte-1kxcyhf{position:absolute;width:2px;background:var(--shell-accent);box-shadow:0 0 6px var(--shell-accent);pointer-events:none;border-radius:1px}.tab-body.svelte-1kxcyhf{flex:1 1 auto;position:relative;min-width:0;min-height:0;overflow:hidden}.tab-body-pane.svelte-1kxcyhf{position:absolute;inset:0;min-width:0;min-height:0;display:none}.tab-body-pane.active.svelte-1kxcyhf{display:block}.slot.svelte-1czj0s8{position:relative;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden}.slot-placeholder.svelte-1czj0s8{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--shell-pad-sm);color:var(--shell-fg-muted);font-size:12px;text-align:center;padding:var(--shell-pad-md);background:repeating-linear-gradient(45deg,var(--shell-bg) 0 10px,var(--shell-bg-elevated) 10px 20px);border:1px dashed var(--shell-border-strong);pointer-events:none}.slot-id.svelte-1czj0s8{color:var(--shell-fg);font-family:var(--shell-font-mono);font-size:13px}.slot-meta.svelte-1czj0s8 code:where(.svelte-1czj0s8){font-family:var(--shell-font-mono);color:var(--shell-accent)}.slot-dims.svelte-1czj0s8{font-family:var(--shell-font-mono);color:var(--shell-fg-subtle);font-size:11px}.slot-drop-zone.svelte-re71zu{position:absolute;inset:0;pointer-events:none}.slot-drop-zone.active.svelte-re71zu{pointer-events:auto}.quad-highlight.svelte-re71zu{position:absolute;background:var(--shell-accent);opacity:.18;border:1px dashed var(--shell-accent);pointer-events:none;transition:inset 80ms ease}.quad-highlight.quad-left.svelte-re71zu{inset:0 50% 0 0}.quad-highlight.quad-right.svelte-re71zu{inset:0 0 0 50%}.quad-highlight.quad-top.svelte-re71zu{inset:0 0 50%}.quad-highlight.quad-bottom.svelte-re71zu{inset:50% 0 0}.quad-target.svelte-re71zu{position:absolute;pointer-events:none}.quad-target.quad-left.svelte-re71zu{inset:0 50% 0 0}.quad-target.quad-right.svelte-re71zu{inset:0 0 0 50%}.quad-target.quad-top.svelte-re71zu{inset:0 0 50%}.quad-target.quad-bottom.svelte-re71zu{inset:50% 0 0}.tab-slot-wrapper.svelte-1gw9g38,.leaf-slot-wrapper.svelte-1gw9g38{position:absolute;inset:0;min-width:0;min-height:0}.empty-tabs-placeholder.svelte-1gw9g38{width:100%;height:100%;min-width:0;min-height:0;position:relative}.empty-tabs-default.svelte-1gw9g38{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--shell-fg-muted);font-size:12px;background:repeating-linear-gradient(45deg,var(--shell-bg) 0 10px,var(--shell-bg-elevated) 10px 20px);border:1px dashed var(--shell-border-strong)}.empty-tabs-custom.svelte-1gw9g38{position:absolute;inset:0}.empty-tabs-drop.svelte-1gw9g38{position:absolute;inset:0;pointer-events:auto}.drag-preview.svelte-133fiip{position:absolute;display:inline-flex;align-items:center;gap:var(--shell-pad-sm);padding:var(--shell-pad-sm) var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));color:var(--shell-fg);border:1px solid var(--shell-accent);border-radius:var(--shell-radius-sm);box-shadow:0 8px 24px #00000080;font-size:12px;font-family:var(--shell-font-ui);pointer-events:none;opacity:.9}.drag-preview-icon.svelte-133fiip{font-size:11px}.drag-preview-label.svelte-133fiip{white-space:nowrap}.sh3-float-frame.svelte-1p734al{position:absolute;display:flex;flex-direction:column;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated, #1e1e1e));color:var(--shell-fg);border:1px solid var(--shell-border-strong);border-radius:var(--shell-radius);box-shadow:0 8px 24px #0006;pointer-events:auto}.sh3-float-header.svelte-1p734al{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;background:var(--shell-bg, #111);cursor:move;user-select:none;border-bottom:1px solid var(--shell-border-strong);border-top-left-radius:var(--shell-radius);border-top-right-radius:var(--shell-radius);flex-shrink:0}.sh3-float-title.svelte-1p734al{font-size:12px;color:var(--shell-fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sh3-float-close.svelte-1p734al{background:transparent;border:none;color:var(--shell-fg);font-size:16px;line-height:1;cursor:pointer;padding:0 4px;flex-shrink:0}.sh3-float-body.svelte-1p734al{flex:1;position:relative;overflow:hidden;min-height:0}.sh3-float-layer.svelte-1rzcset{position:absolute;inset:0;pointer-events:none}.guest-banner.svelte-pymkh{display:flex;align-items:center;justify-content:center;gap:12px;padding:6px var(--shell-pad-md, 12px);background:color-mix(in srgb,var(--shell-accent, #7c7cf0) 15%,transparent);border-bottom:1px solid var(--shell-border, #3a3a5c);font-size:12px;color:var(--shell-fg, #e0e0e0)}.guest-banner-action.svelte-pymkh{padding:3px 10px;color:var(--shell-bg, #1a1a2e);font-size:11px;font-weight:600}.guest-signin-overlay.svelte-pymkh{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#00000080;z-index:9999}.guest-signin-card.svelte-pymkh{display:flex;flex-direction:column;gap:12px;padding:32px;background:var(--shell-bg-elevated, #252540);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius-lg, 12px);min-width:300px}.guest-signin-form.svelte-pymkh{display:flex;flex-direction:column;gap:10px}.guest-signin-input.svelte-pymkh{padding:8px 12px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:13px}.guest-signin-input.svelte-pymkh::placeholder{color:var(--shell-fg-muted, #888)}.guest-signin-actions.svelte-pymkh{display:flex;gap:8px}.guest-signin-btn.svelte-pymkh{flex:1;padding:8px;color:var(--shell-bg, #1a1a2e);font-weight:600}.guest-signin-btn.svelte-pymkh:disabled{opacity:.6;cursor:not-allowed}.guest-signin-cancel.svelte-pymkh{padding:8px 12px;background:transparent;color:var(--shell-fg-subtle, #aaa);border:1px solid var(--shell-border, #3a3a5c)}.guest-signin-error.svelte-pymkh{padding:6px 10px;font-size:12px;color:var(--shell-error, #d32f2f);background:color-mix(in srgb,var(--shell-error, #d32f2f) 10%,transparent);border-radius:var(--shell-radius, 6px)}.shell.svelte-187fra4{display:grid;grid-template-rows:var(--shell-tabbar-height) auto 1fr var(--shell-statusbar-height);height:100%;width:100%;position:relative;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg)}.shell-tabbar.svelte-187fra4{display:flex;align-items:center;gap:var(--shell-pad-md);padding:0 var(--shell-pad-md);background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated));border-bottom:1px solid var(--shell-border);user-select:none}.shell-tabbar-brand.svelte-187fra4{font-weight:600;color:var(--shell-accent);letter-spacing:.5px}.shell-content.svelte-187fra4{position:relative;overflow:hidden;background:var(--shell-grad-bg, var(--shell-bg));min-width:0;min-height:0}.shell-statusbar.svelte-187fra4{display:flex;align-items:center;justify-content:space-between;padding:0 var(--shell-pad-md);background:var(--shell-grad-bg-sunken, var(--shell-bg-sunken));border-top:1px solid var(--shell-border);color:var(--shell-fg-muted);font-size:11px;user-select:none}.shell-overlays.svelte-187fra4,.shell-overlay-root.svelte-187fra4{position:absolute;inset:0;pointer-events:none}.shell-tabbar-home-button.svelte-187fra4{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:var(--shell-fg-muted);border:1px solid var(--shell-border)}.shell-tabbar-home-button.svelte-187fra4:hover:not(:disabled){color:var(--shell-fg);border-color:var(--shell-fg-muted)}.shell-tabbar-home-button.svelte-187fra4:disabled{color:var(--shell-fg-subtle);border-color:var(--shell-border);cursor:default}.shell-tabbar-home-icon.svelte-187fra4{width:14px;height:14px}.shell-tabbar-user.svelte-187fra4{display:flex;align-items:center;gap:6px;margin-left:auto}.shell-tabbar-user-name.svelte-187fra4{font-size:12px;color:var(--shell-fg-subtle)}.shell-tabbar-tag.svelte-187fra4{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#fff;background:var(--shell-accent);padding:1px 6px;border-radius:6px}.shell-tabbar-signout.svelte-187fra4{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;background:transparent;color:var(--shell-fg-muted);border:1px solid var(--shell-border)}.shell-tabbar-signout.svelte-187fra4:hover{color:var(--shell-fg);border-color:var(--shell-fg-muted)}.shell-tabbar-signout-icon.svelte-187fra4{width:14px;height:14px}.signin-wall.svelte-lh4k15{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:var(--shell-grad-bg, var(--shell-bg, #1a1a2e));color:var(--shell-fg, #e0e0e0);font-family:system-ui,sans-serif}.signin-card.svelte-lh4k15{display:flex;flex-direction:column;align-items:center;gap:16px;padding:48px 40px;background:var(--shell-grad-bg-elevated, var(--shell-bg-elevated, #252540));border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius-lg, 12px);min-width:320px}.signin-brand.svelte-lh4k15{margin:0 0 8px;font-size:42px;color:var(--shell-accent, #7c7cf0);letter-spacing:2px}.signin-form.svelte-lh4k15{display:flex;flex-direction:column;gap:12px;width:100%}.signin-input.svelte-lh4k15{padding:10px 14px;background:var(--shell-bg, #1a1a2e);color:var(--shell-fg, #e0e0e0);border:1px solid var(--shell-border, #3a3a5c);border-radius:var(--shell-radius, 6px);font-size:14px}.signin-input.svelte-lh4k15::placeholder{color:var(--shell-fg-muted, #888)}.signin-btn.svelte-lh4k15{padding:10px 16px;color:var(--shell-bg, #1a1a2e);font-weight:600;font-size:14px}.signin-btn.svelte-lh4k15:disabled{opacity:.6;cursor:not-allowed}.signin-link.svelte-lh4k15{background:none;color:var(--shell-accent, #7c7cf0);font-size:13px;padding:0}.signin-link.svelte-lh4k15:hover{text-decoration:underline}.signin-error.svelte-lh4k15{padding:8px 12px;font-size:13px;color:var(--shell-error, #d32f2f);background:color-mix(in srgb,var(--shell-error, #d32f2f) 10%,transparent);border-radius:var(--shell-radius, 6px);width:100%;text-align:center}:root{--shell-bg: #1a1b1e;--shell-bg-elevated: #22232a;--shell-bg-sunken: #141518;--shell-border: #2e3038;--shell-border-strong: #3c3f4a;--shell-fg: #e4e6eb;--shell-fg-muted: #9aa0aa;--shell-fg-subtle: #6b7280;--shell-accent: #6ea8fe;--shell-accent-muted: #3a5580;--shell-input-bg: #2a2a2a;--shell-error: #f87171;--shell-warning: #fbbf24;--shell-success: #34d399;--shell-font-ui: system-ui, -apple-system, "Segoe UI", sans-serif;--shell-font-mono: ui-monospace, "Cascadia Code", "Consolas", monospace;--shell-font-size: 13px;--shell-line: 1.45;--shell-radius-sm: 3px;--shell-radius: 4px;--shell-radius-md: 6px;--shell-radius-lg: 8px;--shell-pad-xs: 2px;--shell-pad-sm: 4px;--shell-pad-md: 8px;--shell-pad-lg: 12px;--shell-tabbar-height: 32px;--shell-statusbar-height: 22px;--shell-z-layer-0: 0;--shell-z-layer-1: 100;--shell-z-layer-2: 200;--shell-z-layer-3: 300;--shell-z-layer-4: 400;--shell-z-layer-5: 500;--shell-z-layer-6: 600}*,*:before,*:after{box-sizing:border-box}html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--shell-grad-bg, var(--shell-bg));color:var(--shell-fg);font-family:var(--shell-font-ui);font-size:var(--shell-font-size);line-height:var(--shell-line);-webkit-font-smoothing:antialiased}#app{height:100%}
@@ -1 +1,2 @@
1
1
  function d(e,t,s,r){if(typeof t=="function"?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return s==="m"?r:s==="a"?r.call(e):r?r.value:t.get(e)}function h(e,t,s,r,o){if(typeof t=="function"?e!==t||!0:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var i;function w(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}async function a(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class y{get rid(){return d(this,i,"f")}constructor(t){i.set(this,void 0),h(this,i,t)}async close(){return a("plugin:resources|close",{rid:this.rid})}}i=new WeakMap;var c;(function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"})(c||(c={}));async function p(e,t){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(e,t),await a("plugin:event|unlisten",{event:e,eventId:t})}async function u(e,t,s){var r;const o=(r=void 0)!==null&&r!==void 0?r:{kind:"Any"};return a("plugin:event|listen",{event:e,target:o,handler:w(t)}).then(l=>async()=>p(e,l))}async function g(e,t){return await n.load(e,t)}class _{get store(){return this._store||(this._store=g(this.path,this.options)),this._store}constructor(t,s){this.path=t,this.options=s}async init(){await this.store}async set(t,s){return(await this.store).set(t,s)}async get(t){return(await this.store).get(t)}async has(t){return(await this.store).has(t)}async delete(t){return(await this.store).delete(t)}async clear(){await(await this.store).clear()}async reset(){await(await this.store).reset()}async keys(){return(await this.store).keys()}async values(){return(await this.store).values()}async entries(){return(await this.store).entries()}async length(){return(await this.store).length()}async reload(t){await(await this.store).reload(t)}async save(){await(await this.store).save()}async onKeyChange(t,s){return(await this.store).onKeyChange(t,s)}async onChange(t){return(await this.store).onChange(t)}async close(){this._store&&await(await this._store).close()}}class n extends y{constructor(t){super(t)}static async load(t,s){const r=await a("plugin:store|load",{path:t,options:s});return new n(r)}static async get(t){return await a("plugin:store|get_store",{path:t}).then(s=>s?new n(s):null)}async set(t,s){await a("plugin:store|set",{rid:this.rid,key:t,value:s})}async get(t){const[s,r]=await a("plugin:store|get",{rid:this.rid,key:t});return r?s:void 0}async has(t){return await a("plugin:store|has",{rid:this.rid,key:t})}async delete(t){return await a("plugin:store|delete",{rid:this.rid,key:t})}async clear(){await a("plugin:store|clear",{rid:this.rid})}async reset(){await a("plugin:store|reset",{rid:this.rid})}async keys(){return await a("plugin:store|keys",{rid:this.rid})}async values(){return await a("plugin:store|values",{rid:this.rid})}async entries(){return await a("plugin:store|entries",{rid:this.rid})}async length(){return await a("plugin:store|length",{rid:this.rid})}async reload(t){await a("plugin:store|reload",{rid:this.rid,...t})}async save(){await a("plugin:store|save",{rid:this.rid})}async onKeyChange(t,s){return await u("store://change",r=>{r.payload.resourceId===this.rid&&r.payload.key===t&&s(r.payload.exists?r.payload.value:void 0)})}async onChange(t){return await u("store://change",s=>{s.payload.resourceId===this.rid&&t(s.payload.key,s.payload.exists?s.payload.value:void 0)})}}class f{#e;#t=new Map;constructor(t){this.#e=new _(`${t}.json`,{defaults:{},autoSave:!0})}read(t){return this.#t.get(t)}write(t,s){this.#t.set(t,s),this.#e.set(t,s).catch(r=>console.warn("SH3: store write failed",r))}delete(t){this.#t.delete(t),this.#e.delete(t).catch(s=>console.warn("SH3: store delete failed",s))}list(){return[...this.#t.keys()]}async init(){const t=await this.#e.entries();for(const[s,r]of t)this.#t.set(s,r)}}export{f as TauriStoreBackend};
2
+ //# sourceMappingURL=tauri-backend-B3LR3-lo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tauri-backend-B3LR3-lo.js","sources":["../../../../node_modules/@tauri-apps/api/external/tslib/tslib.es6.js","../../../../node_modules/@tauri-apps/api/core.js","../../../../node_modules/@tauri-apps/api/event.js","../../../../node_modules/@tauri-apps/plugin-store/dist-js/index.js","../../../sh3-core/src/platform/tauri-backend.ts"],"sourcesContent":["/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\n\r\nfunction __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nfunction __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\n\nexport { __classPrivateFieldGet, __classPrivateFieldSet };\n","import { __classPrivateFieldSet, __classPrivateFieldGet } from './external/tslib/tslib.es6.js';\n\n// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\nvar _Channel_onmessage, _Channel_nextMessageIndex, _Channel_pendingMessages, _Channel_messageEndIndex, _Resource_rid;\n/**\n * Invoke your custom commands.\n *\n * This package is also accessible with `window.__TAURI__.core` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.\n * @module\n */\n/**\n * A key to be used to implement a special function\n * on your types that define how your type should be serialized\n * when passing across the IPC.\n * @example\n * Given a type in Rust that looks like this\n * ```rs\n * #[derive(serde::Serialize, serde::Deserialize)\n * enum UserId {\n * String(String),\n * Number(u32),\n * }\n * ```\n * `UserId::String(\"id\")` would be serialized into `{ String: \"id\" }`\n * and so we need to pass the same structure back to Rust\n * ```ts\n * import { SERIALIZE_TO_IPC_FN } from \"@tauri-apps/api/core\"\n *\n * class UserIdString {\n * id\n * constructor(id) {\n * this.id = id\n * }\n *\n * [SERIALIZE_TO_IPC_FN]() {\n * return { String: this.id }\n * }\n * }\n *\n * class UserIdNumber {\n * id\n * constructor(id) {\n * this.id = id\n * }\n *\n * [SERIALIZE_TO_IPC_FN]() {\n * return { Number: this.id }\n * }\n * }\n *\n * type UserId = UserIdString | UserIdNumber\n * ```\n *\n */\n// if this value changes, make sure to update it in:\n// 1. ipc.js\n// 2. process-ipc-message-fn.js\nconst SERIALIZE_TO_IPC_FN = '__TAURI_TO_IPC_KEY__';\n/**\n * Stores the callback in a known location, and returns an identifier that can be passed to the backend.\n * The backend uses the identifier to `eval()` the callback.\n *\n * @return An unique identifier associated with the callback function.\n *\n * @since 1.0.0\n */\nfunction transformCallback(\n// TODO: Make this not optional in v3\ncallback, once = false) {\n return window.__TAURI_INTERNALS__.transformCallback(callback, once);\n}\nclass Channel {\n constructor(onmessage) {\n _Channel_onmessage.set(this, void 0);\n // the index is used as a mechanism to preserve message order\n _Channel_nextMessageIndex.set(this, 0);\n _Channel_pendingMessages.set(this, []);\n _Channel_messageEndIndex.set(this, void 0);\n __classPrivateFieldSet(this, _Channel_onmessage, onmessage || (() => { }), \"f\");\n this.id = transformCallback((rawMessage) => {\n const index = rawMessage.index;\n if ('end' in rawMessage) {\n if (index == __classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\")) {\n this.cleanupCallback();\n }\n else {\n __classPrivateFieldSet(this, _Channel_messageEndIndex, index, \"f\");\n }\n return;\n }\n const message = rawMessage.message;\n // Process the message if we're at the right order\n if (index == __classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\")) {\n __classPrivateFieldGet(this, _Channel_onmessage, \"f\").call(this, message);\n __classPrivateFieldSet(this, _Channel_nextMessageIndex, __classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\") + 1, \"f\");\n // process pending messages\n while (__classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\") in __classPrivateFieldGet(this, _Channel_pendingMessages, \"f\")) {\n const message = __classPrivateFieldGet(this, _Channel_pendingMessages, \"f\")[__classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\")];\n __classPrivateFieldGet(this, _Channel_onmessage, \"f\").call(this, message);\n // eslint-disable-next-line @typescript-eslint/no-array-delete\n delete __classPrivateFieldGet(this, _Channel_pendingMessages, \"f\")[__classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\")];\n __classPrivateFieldSet(this, _Channel_nextMessageIndex, __classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\") + 1, \"f\");\n }\n if (__classPrivateFieldGet(this, _Channel_nextMessageIndex, \"f\") === __classPrivateFieldGet(this, _Channel_messageEndIndex, \"f\")) {\n this.cleanupCallback();\n }\n }\n // Queue the message if we're not\n else {\n // eslint-disable-next-line security/detect-object-injection\n __classPrivateFieldGet(this, _Channel_pendingMessages, \"f\")[index] = message;\n }\n });\n }\n cleanupCallback() {\n window.__TAURI_INTERNALS__.unregisterCallback(this.id);\n }\n set onmessage(handler) {\n __classPrivateFieldSet(this, _Channel_onmessage, handler, \"f\");\n }\n get onmessage() {\n return __classPrivateFieldGet(this, _Channel_onmessage, \"f\");\n }\n [(_Channel_onmessage = new WeakMap(), _Channel_nextMessageIndex = new WeakMap(), _Channel_pendingMessages = new WeakMap(), _Channel_messageEndIndex = new WeakMap(), SERIALIZE_TO_IPC_FN)]() {\n return `__CHANNEL__:${this.id}`;\n }\n toJSON() {\n // eslint-disable-next-line security/detect-object-injection\n return this[SERIALIZE_TO_IPC_FN]();\n }\n}\nclass PluginListener {\n constructor(plugin, event, channelId) {\n this.plugin = plugin;\n this.event = event;\n this.channelId = channelId;\n }\n async unregister() {\n return invoke(`plugin:${this.plugin}|remove_listener`, {\n event: this.event,\n channelId: this.channelId\n });\n }\n}\n/**\n * Adds a listener to a plugin event.\n *\n * @returns The listener object to stop listening to the events.\n *\n * @since 2.0.0\n */\nasync function addPluginListener(plugin, event, cb) {\n const handler = new Channel(cb);\n try {\n await invoke(`plugin:${plugin}|register_listener`, {\n event,\n handler\n });\n return new PluginListener(plugin, event, handler.id);\n }\n catch {\n // TODO(v3): remove this fallback\n // note: we must try with camelCase here for backwards compatibility\n await invoke(`plugin:${plugin}|registerListener`, { event, handler });\n return new PluginListener(plugin, event, handler.id);\n }\n}\n/**\n * Get permission state for a plugin.\n *\n * This should be used by plugin authors to wrap their actual implementation.\n */\nasync function checkPermissions(plugin) {\n return invoke(`plugin:${plugin}|check_permissions`);\n}\n/**\n * Request permissions.\n *\n * This should be used by plugin authors to wrap their actual implementation.\n */\nasync function requestPermissions(plugin) {\n return invoke(`plugin:${plugin}|request_permissions`);\n}\n/**\n * Sends a message to the backend.\n * @example\n * ```typescript\n * import { invoke } from '@tauri-apps/api/core';\n * await invoke('login', { user: 'tauri', password: 'poiwe3h4r5ip3yrhtew9ty' });\n * ```\n *\n * @param cmd The command name.\n * @param args The optional arguments to pass to the command.\n * @param options The request options.\n * @return A promise resolving or rejecting to the backend response.\n *\n * @since 1.0.0\n */\nasync function invoke(cmd, args = {}, options) {\n return window.__TAURI_INTERNALS__.invoke(cmd, args, options);\n}\n/**\n * Convert a device file path to an URL that can be loaded by the webview.\n * Note that `asset:` and `http://asset.localhost` must be added to [`app.security.csp`](https://v2.tauri.app/reference/config/#csp-1) in `tauri.conf.json`.\n * Example CSP value: `\"csp\": \"default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost\"` to use the asset protocol on image sources.\n *\n * Additionally, `\"enable\" : \"true\"` must be added to [`app.security.assetProtocol`](https://v2.tauri.app/reference/config/#assetprotocolconfig)\n * in `tauri.conf.json` and its access scope must be defined on the `scope` array on the same `assetProtocol` object.\n *\n * @param filePath The file path.\n * @param protocol The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol.\n * @example\n * ```typescript\n * import { appDataDir, join } from '@tauri-apps/api/path';\n * import { convertFileSrc } from '@tauri-apps/api/core';\n * const appDataDirPath = await appDataDir();\n * const filePath = await join(appDataDirPath, 'assets/video.mp4');\n * const assetUrl = convertFileSrc(filePath);\n *\n * const video = document.getElementById('my-video');\n * const source = document.createElement('source');\n * source.type = 'video/mp4';\n * source.src = assetUrl;\n * video.appendChild(source);\n * video.load();\n * ```\n *\n * @return the URL that can be used as source on the webview.\n *\n * @since 1.0.0\n */\nfunction convertFileSrc(filePath, protocol = 'asset') {\n return window.__TAURI_INTERNALS__.convertFileSrc(filePath, protocol);\n}\n/**\n * A rust-backed resource stored through `tauri::Manager::resources_table` API.\n *\n * The resource lives in the main process and does not exist\n * in the Javascript world, and thus will not be cleaned up automatically\n * except on application exit. If you want to clean it up early, call {@linkcode Resource.close}\n *\n * @example\n * ```typescript\n * import { Resource, invoke } from '@tauri-apps/api/core';\n * export class DatabaseHandle extends Resource {\n * static async open(path: string): Promise<DatabaseHandle> {\n * const rid: number = await invoke('open_db', { path });\n * return new DatabaseHandle(rid);\n * }\n *\n * async execute(sql: string): Promise<void> {\n * await invoke('execute_sql', { rid: this.rid, sql });\n * }\n * }\n * ```\n */\nclass Resource {\n get rid() {\n return __classPrivateFieldGet(this, _Resource_rid, \"f\");\n }\n constructor(rid) {\n _Resource_rid.set(this, void 0);\n __classPrivateFieldSet(this, _Resource_rid, rid, \"f\");\n }\n /**\n * Destroys and cleans up this resource from memory.\n * **You should not call any method on this object anymore and should drop any reference to it.**\n */\n async close() {\n return invoke('plugin:resources|close', {\n rid: this.rid\n });\n }\n}\n_Resource_rid = new WeakMap();\nfunction isTauri() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n return !!(globalThis || window).isTauri;\n}\n\nexport { Channel, PluginListener, Resource, SERIALIZE_TO_IPC_FN, addPluginListener, checkPermissions, convertFileSrc, invoke, isTauri, requestPermissions, transformCallback };\n","import { invoke, transformCallback } from './core.js';\n\n// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\n/**\n * The event system allows you to emit events to the backend and listen to events from it.\n *\n * This package is also accessible with `window.__TAURI__.event` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.\n * @module\n */\n/**\n * @since 1.1.0\n */\nvar TauriEvent;\n(function (TauriEvent) {\n TauriEvent[\"WINDOW_RESIZED\"] = \"tauri://resize\";\n TauriEvent[\"WINDOW_MOVED\"] = \"tauri://move\";\n TauriEvent[\"WINDOW_CLOSE_REQUESTED\"] = \"tauri://close-requested\";\n TauriEvent[\"WINDOW_DESTROYED\"] = \"tauri://destroyed\";\n TauriEvent[\"WINDOW_FOCUS\"] = \"tauri://focus\";\n TauriEvent[\"WINDOW_BLUR\"] = \"tauri://blur\";\n TauriEvent[\"WINDOW_SCALE_FACTOR_CHANGED\"] = \"tauri://scale-change\";\n TauriEvent[\"WINDOW_THEME_CHANGED\"] = \"tauri://theme-changed\";\n TauriEvent[\"WINDOW_CREATED\"] = \"tauri://window-created\";\n TauriEvent[\"WEBVIEW_CREATED\"] = \"tauri://webview-created\";\n TauriEvent[\"DRAG_ENTER\"] = \"tauri://drag-enter\";\n TauriEvent[\"DRAG_OVER\"] = \"tauri://drag-over\";\n TauriEvent[\"DRAG_DROP\"] = \"tauri://drag-drop\";\n TauriEvent[\"DRAG_LEAVE\"] = \"tauri://drag-leave\";\n})(TauriEvent || (TauriEvent = {}));\n/**\n * Unregister the event listener associated with the given name and id.\n *\n * @ignore\n * @param event The event name\n * @param eventId Event identifier\n * @returns\n */\nasync function _unlisten(event, eventId) {\n window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(event, eventId);\n await invoke('plugin:event|unlisten', {\n event,\n eventId\n });\n}\n/**\n * Listen to an emitted event to any {@link EventTarget|target}.\n *\n * @example\n * ```typescript\n * import { listen } from '@tauri-apps/api/event';\n * const unlisten = await listen<string>('error', (event) => {\n * console.log(`Got error, payload: ${event.payload}`);\n * });\n *\n * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted\n * unlisten();\n * ```\n *\n * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.\n * @param handler Event handler callback.\n * @param options Event listening options.\n * @returns A promise resolving to a function to unlisten to the event.\n * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.\n *\n * @since 1.0.0\n */\nasync function listen(event, handler, options) {\n var _a;\n const target = typeof (options === null || options === void 0 ? void 0 : options.target) === 'string'\n ? { kind: 'AnyLabel', label: options.target }\n : ((_a = options === null || options === void 0 ? void 0 : options.target) !== null && _a !== void 0 ? _a : { kind: 'Any' });\n return invoke('plugin:event|listen', {\n event,\n target,\n handler: transformCallback(handler)\n }).then((eventId) => {\n return async () => _unlisten(event, eventId);\n });\n}\n/**\n * Listens once to an emitted event to any {@link EventTarget|target}.\n *\n * @example\n * ```typescript\n * import { once } from '@tauri-apps/api/event';\n * interface LoadedPayload {\n * loggedIn: boolean,\n * token: string\n * }\n * const unlisten = await once<LoadedPayload>('loaded', (event) => {\n * console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);\n * });\n *\n * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted\n * unlisten();\n * ```\n *\n * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.\n * @param handler Event handler callback.\n * @param options Event listening options.\n * @returns A promise resolving to a function to unlisten to the event.\n * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.\n *\n * @since 1.0.0\n */\nasync function once(event, handler, options) {\n return listen(event, (eventData) => {\n void _unlisten(event, eventData.id);\n handler(eventData);\n }, options);\n}\n/**\n * Emits an event to all {@link EventTarget|targets}.\n *\n * @example\n * ```typescript\n * import { emit } from '@tauri-apps/api/event';\n * await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });\n * ```\n *\n * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.\n * @param payload Event payload.\n *\n * @since 1.0.0\n */\nasync function emit(event, payload) {\n await invoke('plugin:event|emit', {\n event,\n payload\n });\n}\n/**\n * Emits an event to all {@link EventTarget|targets} matching the given target.\n *\n * @example\n * ```typescript\n * import { emitTo } from '@tauri-apps/api/event';\n * await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });\n * ```\n *\n * @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.\n * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.\n * @param payload Event payload.\n *\n * @since 2.0.0\n */\nasync function emitTo(target, event, payload) {\n const eventTarget = typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target;\n await invoke('plugin:event|emit_to', {\n target: eventTarget,\n event,\n payload\n });\n}\n\nexport { TauriEvent, emit, emitTo, listen, once };\n","import { listen } from '@tauri-apps/api/event';\nimport { Resource, invoke } from '@tauri-apps/api/core';\n\n// Copyright 2019-2023 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\n/**\n * Create a new Store or load the existing store with the path.\n *\n * @example\n * ```typescript\n * import { Store } from '@tauri-apps/api/store';\n * const store = await Store.load('store.json');\n * ```\n *\n * @param path Path to save the store in `app_data_dir`\n * @param options Store configuration options\n */\nasync function load(path, options) {\n return await Store.load(path, options);\n}\n/**\n * Gets an already loaded store.\n *\n * If the store is not loaded, returns `null`. In this case you must {@link Store.load load} it.\n *\n * This function is more useful when you already know the store is loaded\n * and just need to access its instance. Prefer {@link Store.load} otherwise.\n *\n * @example\n * ```typescript\n * import { getStore } from '@tauri-apps/api/store';\n * const store = await getStore('store.json');\n * ```\n *\n * @param path Path of the store.\n */\nasync function getStore(path) {\n return await Store.get(path);\n}\n/**\n * A lazy loaded key-value store persisted by the backend layer.\n */\nclass LazyStore {\n get store() {\n if (!this._store) {\n this._store = load(this.path, this.options);\n }\n return this._store;\n }\n /**\n * Note that the options are not applied if someone else already created the store\n * @param path Path to save the store in `app_data_dir`\n * @param options Store configuration options\n */\n constructor(path, options) {\n this.path = path;\n this.options = options;\n }\n /**\n * Init/load the store if it's not loaded already\n */\n async init() {\n await this.store;\n }\n async set(key, value) {\n return (await this.store).set(key, value);\n }\n async get(key) {\n return (await this.store).get(key);\n }\n async has(key) {\n return (await this.store).has(key);\n }\n async delete(key) {\n return (await this.store).delete(key);\n }\n async clear() {\n await (await this.store).clear();\n }\n async reset() {\n await (await this.store).reset();\n }\n async keys() {\n return (await this.store).keys();\n }\n async values() {\n return (await this.store).values();\n }\n async entries() {\n return (await this.store).entries();\n }\n async length() {\n return (await this.store).length();\n }\n async reload(options) {\n await (await this.store).reload(options);\n }\n async save() {\n await (await this.store).save();\n }\n async onKeyChange(key, cb) {\n return (await this.store).onKeyChange(key, cb);\n }\n async onChange(cb) {\n return (await this.store).onChange(cb);\n }\n async close() {\n if (this._store) {\n await (await this._store).close();\n }\n }\n}\n/**\n * A key-value store persisted by the backend layer.\n */\nclass Store extends Resource {\n constructor(rid) {\n super(rid);\n }\n /**\n * Create a new Store or load the existing store with the path.\n *\n * @example\n * ```typescript\n * import { Store } from '@tauri-apps/api/store';\n * const store = await Store.load('store.json');\n * ```\n *\n * @param path Path to save the store in `app_data_dir`\n * @param options Store configuration options\n */\n static async load(path, options) {\n const rid = await invoke('plugin:store|load', {\n path,\n options\n });\n return new Store(rid);\n }\n /**\n * Gets an already loaded store.\n *\n * If the store is not loaded, returns `null`. In this case you must {@link Store.load load} it.\n *\n * This function is more useful when you already know the store is loaded\n * and just need to access its instance. Prefer {@link Store.load} otherwise.\n *\n * @example\n * ```typescript\n * import { Store } from '@tauri-apps/api/store';\n * let store = await Store.get('store.json');\n * if (!store) {\n * store = await Store.load('store.json');\n * }\n * ```\n *\n * @param path Path of the store.\n */\n static async get(path) {\n return await invoke('plugin:store|get_store', { path }).then((rid) => (rid ? new Store(rid) : null));\n }\n async set(key, value) {\n await invoke('plugin:store|set', {\n rid: this.rid,\n key,\n value\n });\n }\n async get(key) {\n const [value, exists] = await invoke('plugin:store|get', {\n rid: this.rid,\n key\n });\n return exists ? value : undefined;\n }\n async has(key) {\n return await invoke('plugin:store|has', {\n rid: this.rid,\n key\n });\n }\n async delete(key) {\n return await invoke('plugin:store|delete', {\n rid: this.rid,\n key\n });\n }\n async clear() {\n await invoke('plugin:store|clear', { rid: this.rid });\n }\n async reset() {\n await invoke('plugin:store|reset', { rid: this.rid });\n }\n async keys() {\n return await invoke('plugin:store|keys', { rid: this.rid });\n }\n async values() {\n return await invoke('plugin:store|values', { rid: this.rid });\n }\n async entries() {\n return await invoke('plugin:store|entries', { rid: this.rid });\n }\n async length() {\n return await invoke('plugin:store|length', { rid: this.rid });\n }\n async reload(options) {\n await invoke('plugin:store|reload', { rid: this.rid, ...options });\n }\n async save() {\n await invoke('plugin:store|save', { rid: this.rid });\n }\n async onKeyChange(key, cb) {\n return await listen('store://change', (event) => {\n if (event.payload.resourceId === this.rid && event.payload.key === key) {\n cb(event.payload.exists ? event.payload.value : undefined);\n }\n });\n }\n async onChange(cb) {\n return await listen('store://change', (event) => {\n if (event.payload.resourceId === this.rid) {\n cb(event.payload.key, event.payload.exists ? event.payload.value : undefined);\n }\n });\n }\n}\n\nexport { LazyStore, Store, getStore, load };\n","/*\n * TauriStoreBackend — implements the sh3 Backend interface using\n * @tauri-apps/plugin-store. Each zone gets its own .json store file\n * (e.g. \"workspace.json\", \"user.json\") in Tauri's app data directory.\n *\n * tauri-plugin-store v2 keeps an in-memory cache and flushes to disk\n * automatically. We pre-load the full store into a local Map during\n * init(), then serve reads/lists synchronously from that cache —\n * matching the Backend interface contract. Writes go to both the\n * local cache and the Tauri store (fire-and-forget async).\n */\n\nimport { LazyStore } from '@tauri-apps/plugin-store';\nimport type { Backend } from '../state/types';\n\nexport class TauriStoreBackend implements Backend {\n #store: LazyStore;\n #cache = new Map<string, unknown>();\n\n constructor(zoneName: string) {\n this.#store = new LazyStore(`${zoneName}.json`, { defaults: {}, autoSave: true });\n }\n\n read(shardId: string): unknown | undefined {\n return this.#cache.get(shardId);\n }\n\n write(shardId: string, value: unknown): void {\n this.#cache.set(shardId, value);\n // Fire-and-forget — autoSave flushes to disk.\n this.#store.set(shardId, value).catch((e: unknown) => console.warn('SH3: store write failed', e));\n }\n\n delete(shardId: string): void {\n this.#cache.delete(shardId);\n this.#store.delete(shardId).catch((e: unknown) => console.warn('SH3: store delete failed', e));\n }\n\n list(): string[] {\n return [...this.#cache.keys()];\n }\n\n /**\n * Load the store from disk into the local cache. Must be called once\n * before read/list return meaningful data. Called by the platform\n * resolver at boot.\n */\n async init(): Promise<void> {\n const entries = await this.#store.entries<unknown>();\n for (const [key, value] of entries) {\n this.#cache.set(key, value);\n }\n }\n}\n"],"names":["__classPrivateFieldGet","receiver","state","kind","f","__classPrivateFieldSet","value","_Resource_rid","transformCallback","callback","once","invoke","cmd","args","options","Resource","rid","TauriEvent","_unlisten","event","eventId","listen","handler","_a","target","load","path","Store","LazyStore","key","cb","exists","TauriStoreBackend","#store","#cache","zoneName","shardId","e","entries"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
package/app/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>SH3</title>
7
- <script type="module" crossorigin src="/assets/index-C7fUtJvb.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-B1mKDfA-.css">
7
+ <script type="module" crossorigin src="/assets/index-25fXNyG3.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-BcQ1cruS.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="app"></div>
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { cors } from 'hono/cors';
10
10
  import { serve } from '@hono/node-server';
11
11
  import { serveStatic } from '@hono/node-server/serve-static';
12
12
  import { createNodeWebSocket } from '@hono/node-ws';
13
- import { readFileSync, existsSync, renameSync } from 'node:fs';
13
+ import { readFileSync, writeFileSync, existsSync, renameSync } from 'node:fs';
14
14
  import { mkdirSync } from 'node:fs';
15
15
  import { fileURLToPath } from 'node:url';
16
16
  import { dirname, join } from 'node:path';
@@ -54,14 +54,41 @@ export async function createServer(options = {}) {
54
54
  const shardRouter = new ShardRouter();
55
55
  // Factory shards call to register a WebSocket upgrade handler. The
56
56
  // returned value is the Hono handler for `app.get(path, ..., handler)`.
57
- // The onConnect callback receives both the raw WS and the Hono Context
58
- // from the upgrade request, so shards can read `c.get('session')` to
59
- // route the connection to the correct per-user state.
60
- const wsRegister = (onConnect) => upgradeWebSocket((c) => ({
61
- onOpen(_evt, ws) {
62
- onConnect(ws, c);
63
- },
64
- }));
57
+ // The onConnect callback receives both an enriched WS and the Hono
58
+ // Context from the upgrade request, so shards can read `c.get('session')`
59
+ // to route the connection to the correct per-user state.
60
+ //
61
+ // `@hono/node-ws` exposes WebSocket lifecycle hooks via the WSEvents
62
+ // interface (onOpen/onMessage/onClose) returned from upgradeWebSocket,
63
+ // not via `addEventListener` on the WSContext. To give shards a simple
64
+ // per-connection closure, we enrich the ws object passed to onConnect
65
+ // with `onMessage` / `onClose` setter methods and route the outer
66
+ // WSEvents handlers through them. Each upgrade gets its own closure
67
+ // over `msgHandler` / `closeHandler`, so multiple connections don't
68
+ // share state.
69
+ const wsRegister = (onConnect) => upgradeWebSocket((c) => {
70
+ let msgHandler = null;
71
+ let closeHandler = null;
72
+ return {
73
+ onOpen(_evt, ws) {
74
+ const enriched = Object.assign(ws, {
75
+ onMessage: (h) => {
76
+ msgHandler = h;
77
+ },
78
+ onClose: (h) => {
79
+ closeHandler = h;
80
+ },
81
+ });
82
+ onConnect(enriched, c);
83
+ },
84
+ onMessage(evt, _ws) {
85
+ msgHandler?.(String(evt.data));
86
+ },
87
+ onClose(_evt, _ws) {
88
+ closeHandler?.();
89
+ },
90
+ };
91
+ });
65
92
  // CORS
66
93
  app.use('*', cors({ origin: '*', credentials: true }));
67
94
  // --- Public routes (no auth) ---
@@ -199,6 +226,16 @@ export async function createServer(options = {}) {
199
226
  console.log('╚══════════════════════════════════════════════════════════╝');
200
227
  console.log('');
201
228
  }
229
+ // Auto-seed official registry on first run (no store file yet)
230
+ const storePath = join(dataDir, 'env-state', 'sh3-store.json');
231
+ if (!existsSync(storePath)) {
232
+ const registryUrl = process.env.SH3_OFFICIAL_REGISTRY ?? 'https://unfinished-lair.github.io/sh3-apps/registry.json';
233
+ if (registryUrl !== '') {
234
+ mkdirSync(join(dataDir, 'env-state'), { recursive: true });
235
+ writeFileSync(storePath, JSON.stringify({ registries: [registryUrl] }));
236
+ console.log(`[sh3] Seeded official registry: ${registryUrl}`);
237
+ }
238
+ }
202
239
  await loadPackages(shardRouter, dataDir, keys, settings, wsRegister);
203
240
  // Periodic session cleanup (every 15 minutes)
204
241
  setInterval(() => sessions.cleanup(), 15 * 60 * 1000);
@@ -11,21 +11,37 @@ export interface MountContext {
11
11
  * route prefix. The returned value is a Hono middleware handler that
12
12
  * can be passed directly as the handler argument to `router.get(path, ...)`.
13
13
  *
14
- * The `ws` argument passed to `onConnect` is the server-side WebSocket
15
- * from `@hono/node-ws` (which wraps the `ws` package). `@hono/node-ws`
16
- * does not re-export a type name for it and `@types/ws` is not a
17
- * dependency, so we use `any` per the plan's explicit fallback rule.
18
- * The returned handler is likewise typed as `any` — its concrete type
19
- * is Hono's internal `MiddlewareHandler<..., { outputFormat: "ws" }>`,
20
- * which would leak Hono ws internals into every shard that touches it.
14
+ * The `ws` argument passed to `onConnect` is the `WSContext` from
15
+ * `@hono/node-ws` enriched with two per-connection setter methods:
16
+ *
17
+ * - `ws.send(data)` inherited from WSContext, send a frame.
18
+ * - `ws.close()` inherited from WSContext, close the connection.
19
+ * - `ws.onMessage(handler)` register a callback that receives each
20
+ * incoming frame as a string. Only one handler; last call wins.
21
+ * - `ws.onClose(handler)` — register a callback fired when the
22
+ * connection closes. Only one handler; last call wins.
23
+ *
24
+ * These setters exist because `@hono/node-ws` exposes the lifecycle
25
+ * via the `WSEvents` interface returned from `upgradeWebSocket`, not
26
+ * via `addEventListener` on WSContext. `wsRegister` in sh3-server
27
+ * bridges the two so shards can keep all per-connection state in a
28
+ * single closure. Do NOT try `ws.addEventListener('message', ...)` —
29
+ * WSContext has no such method and the call silently no-ops.
30
+ *
31
+ * `@hono/node-ws` does not re-export a type name for WSContext and
32
+ * `@types/ws` is not a dependency, so we use `any` per the plan's
33
+ * explicit fallback rule. The returned handler is likewise typed as
34
+ * `any` — its concrete type is Hono's internal
35
+ * `MiddlewareHandler<..., { outputFormat: "ws" }>`, which would leak
36
+ * Hono ws internals into every shard that touches it.
21
37
  *
22
38
  * The `c` argument is the Hono `Context` for the upgrade request.
23
39
  * Shards can read `c.get('session')` to route the connection to the
24
40
  * correct per-user state (e.g. `manager.getOrCreate(session.userId)`).
25
41
  *
26
- * @param onConnect Called with the raw WebSocket and request Context
27
- * when a client connects. Attach listeners in the body;
28
- * return nothing.
42
+ * @param onConnect Called with the enriched WebSocket and request
43
+ * Context when a client connects. Attach listeners
44
+ * via `ws.onMessage` / `ws.onClose`; return nothing.
29
45
  */
30
46
  wsRegister(onConnect: (ws: any, c: any) => void): any;
31
47
  }
@@ -39,11 +39,14 @@ export default {
39
39
  const userId = sessionUser(c);
40
40
  const session = manager.getOrCreate(userId);
41
41
  session.attach(ws);
42
- // Wire incoming frames through the dispatch layer.
43
- ws.addEventListener?.('message', (evt) => {
44
- handleClientMessage(session, ws, String(evt.data));
42
+ // Wire incoming frames through the dispatch layer. `wsRegister`
43
+ // enriches the ws object with per-connection `onMessage` /
44
+ // `onClose` setters that forward the hono/node-ws WSEvents
45
+ // callbacks for this upgrade.
46
+ ws.onMessage((data) => {
47
+ handleClientMessage(session, ws, data);
45
48
  });
46
- ws.addEventListener?.('close', () => {
49
+ ws.onClose(() => {
47
50
  session.detach(ws);
48
51
  });
49
52
  }));
@@ -3,6 +3,28 @@ export interface RunnerStartOpts {
3
3
  cmd: string;
4
4
  cwd: string;
5
5
  env: Record<string, string>;
6
+ /**
7
+ * Optional event callbacks wired up synchronously at the top of start()
8
+ * BEFORE the emitter can fire. Pass these when the caller cannot attach
9
+ * listeners on `handle.events` atomically with receiving the handle —
10
+ * e.g., ShellSession.submit, which uses `await runner.start(...)` and
11
+ * therefore only gets a chance to attach listeners in the next microtask.
12
+ *
13
+ * Why this matters: sync-failure paths (tokenize throw, empty command,
14
+ * Node 24's CVE-2024-27980 EINVAL for .cmd/.bat on Windows) emit their
15
+ * 'stderr'/'exit' events immediately via setImmediate. Without pre-
16
+ * registration, there's a subtle race between the emitter firing and
17
+ * the caller's post-await listener attachment — when `this.running = handle`
18
+ * is assigned only after await, an exit callback that fires on the wrong
19
+ * side of the boundary leaves `running` pointing at a dead handle and
20
+ * every subsequent submit gets silently dropped by the running-guard.
21
+ */
22
+ onStdout?: (data: string) => void;
23
+ onStderr?: (data: string) => void;
24
+ onExit?: (info: {
25
+ code: number | null;
26
+ signal: string | null;
27
+ }) => void;
6
28
  }
7
29
  export interface RunnerHandle {
8
30
  /** Send bytes to the process's stdin. No-op for LocalRunner in v1. */
@@ -14,12 +14,35 @@ import { tokenize } from './tokenize.js';
14
14
  export class LocalRunner {
15
15
  async start(opts) {
16
16
  const events = new EventEmitter();
17
+ // Pre-attach caller-supplied listeners BEFORE any code path that
18
+ // could emit. See note on RunnerStartOpts — this closes the race
19
+ // for every sync-failure path (tokenize throw, empty cmd, EINVAL).
20
+ if (opts.onStdout)
21
+ events.on('stdout', opts.onStdout);
22
+ if (opts.onStderr)
23
+ events.on('stderr', opts.onStderr);
24
+ if (opts.onExit)
25
+ events.on('exit', opts.onExit);
17
26
  let child;
18
27
  try {
19
- const [bin, ...args] = tokenize(opts.cmd);
28
+ // tokenize is used for VALIDATION only — detect unterminated quotes
29
+ // and empty commands before handing off to the shell. We don't pass
30
+ // the tokenized args to spawn: with `shell: true` (below) the shell
31
+ // re-parses the raw command line, and tokenizing would strip quotes
32
+ // the shell needs for its own escaping.
33
+ const [bin] = tokenize(opts.cmd);
20
34
  if (!bin) {
21
- // Empty command — emit an error exit without spawning
22
- queueMicrotask(() => {
35
+ // Empty command — emit an error exit without spawning.
36
+ // Must use setImmediate, not queueMicrotask: the caller
37
+ // (ShellSession.submit) attaches its 'stdout'/'stderr'/'exit'
38
+ // listeners in the continuation after `await runner.start()`,
39
+ // which is itself a microtask. queueMicrotask would drain FIFO
40
+ // before that continuation, emitting to an emitter with zero
41
+ // listeners — the exit event silently vanishes and the session
42
+ // gets stuck with `running` pointing at a dead handle. setImmediate
43
+ // defers to the event loop's check phase, strictly after microtask
44
+ // drain, so listeners are always in place when we fire.
45
+ setImmediate(() => {
23
46
  events.emit('stderr', 'shell: empty command\n');
24
47
  events.emit('exit', { code: null, signal: 'spawn-error' });
25
48
  });
@@ -30,15 +53,24 @@ export class LocalRunner {
30
53
  events,
31
54
  };
32
55
  }
33
- child = spawn(bin, args, {
56
+ // Use shell: true so the platform shell resolves PATH, handles
57
+ // Windows .cmd/.bat files (npm, yarn, tsc, …), and gives the user
58
+ // the metacharacter semantics they expect from a terminal. Node
59
+ // 24's CVE-2024-27980 patch throws EINVAL synchronously for
60
+ // .cmd/.bat with shell: false — which is what the terminal IS
61
+ // supposed to run, so shell: true is the only correct mode here.
62
+ // We pass opts.cmd as the sole command string and [] as args so
63
+ // spawn hands the whole line to the shell untouched.
64
+ child = spawn(opts.cmd, [], {
34
65
  cwd: opts.cwd,
35
66
  env: opts.env,
36
- shell: false,
67
+ shell: true,
37
68
  });
38
69
  }
39
70
  catch (err) {
40
71
  const message = err.message ?? String(err);
41
- queueMicrotask(() => {
72
+ // See note above on setImmediate vs queueMicrotask same race.
73
+ setImmediate(() => {
42
74
  events.emit('stderr', `shell: ${message}\n`);
43
75
  events.emit('exit', { code: null, signal: 'spawn-error' });
44
76
  });
@@ -7,13 +7,20 @@ export interface SessionConfig {
7
7
  defaultCwd: string;
8
8
  }
9
9
  /**
10
- * Minimal WebSocket interface — any object with .send(string) satisfies it.
11
- * The server's real WS implementation (from @hono/node-ws) provides a richer
12
- * surface; we intentionally narrow it here so tests can use plain mocks.
10
+ * Minimal WebSocket interface — what ShellSession needs to talk to a
11
+ * connected client. Real connections come from sh3-server's wsRegister
12
+ * (see MountContext.wsRegister in shard-router.ts), which enriches the
13
+ * `@hono/node-ws` WSContext with per-connection `onMessage` / `onClose`
14
+ * setter methods. ShellSession itself only ever calls `send` / `close`;
15
+ * the setter methods are only used by the connection-wiring code in
16
+ * shell-shard/index.ts, but they stay on this interface so the same
17
+ * type flows through `wsRegister(onConnect: (ws: WsLike, ...))`.
13
18
  */
14
19
  export interface WsLike {
15
20
  send(data: string): void;
16
21
  close(): void;
22
+ onMessage(handler: (data: string) => void): void;
23
+ onClose(handler: () => void): void;
17
24
  }
18
25
  export declare class ShellSession {
19
26
  readonly userId: string;