@bitkyc08/opencodex 2.7.29 → 2.7.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +479 -0
- package/README.zh-CN.md +1 -1
- package/gui/dist/assets/index-BPa0R6EN.js +46 -0
- package/gui/dist/assets/index-BY7KvJRB.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/cursor/cursor-errors.ts +7 -2
- package/src/adapters/cursor/discovery.ts +2 -2
- package/src/adapters/cursor/request-builder.ts +90 -6
- package/src/adapters/cursor/tool-definitions.ts +23 -6
- package/src/adapters/google.ts +7 -0
- package/src/codex/auth-api.ts +18 -0
- package/src/codex/catalog.ts +39 -11
- package/src/codex/routing.ts +85 -4
- package/src/combos/index.ts +1 -1
- package/src/combos/request.ts +26 -4
- package/src/combos/types.ts +4 -4
- package/src/lib/errors.ts +4 -0
- package/src/lib/upstream-retry.ts +21 -0
- package/src/lib/winsw.ts +7 -1
- package/src/oauth/anthropic.ts +23 -1
- package/src/oauth/index.ts +83 -4
- package/src/oauth/local-token-detect.ts +3 -0
- package/src/oauth/store.ts +32 -0
- package/src/providers/antigravity-models.ts +23 -12
- package/src/providers/base-url-choices.ts +18 -0
- package/src/providers/registry.ts +122 -7
- package/src/responses/parser.ts +11 -6
- package/src/router.ts +6 -1
- package/src/server/index.ts +3 -3
- package/src/server/relay.ts +31 -5
- package/src/server/request-log.ts +12 -0
- package/src/server/responses.ts +111 -27
- package/src/service.ts +12 -3
- package/src/storage/scanner.ts +18 -6
- package/src/types.ts +4 -2
- package/src/usage/expected-prices.ts +12 -9
- package/gui/dist/assets/index-CMKZnkG9.js +0 -40
- package/gui/dist/assets/index-DyBPh28A.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.provider-catalog{flex-direction:column;gap:10px;display:flex}.provider-catalog-tabs{border-bottom:1px solid var(--border);gap:4px;display:flex}.provider-catalog-tab{appearance:none;color:var(--muted);font:inherit;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:8px 12px}.provider-catalog-tab.active{color:var(--fg);border-bottom-color:var(--accent)}.provider-catalog-accounts-hint{padding:2px 2px 0}.provider-catalog-search{width:100%}.provider-catalog-rows{flex-direction:column;gap:6px;max-height:360px;display:flex;overflow-y:auto}.provider-catalog-badges{flex-shrink:0;align-items:center;gap:4px;display:flex}.provider-catalog-empty{padding:8px}.provider-catalog-account-row .sub{text-overflow:ellipsis;overflow:hidden}.provider-catalog-footer{align-items:center;gap:8px;display:flex}.bar-warn{background:linear-gradient(90deg, var(--green), var(--amber))}.quota-row--warn .quota-label{color:var(--amber)}.quota-val--warn{color:var(--amber);align-items:center;gap:3px;display:inline-flex}.quota-stacked{flex-direction:column;gap:10px;display:flex}.quota-stacked-row{flex-direction:column;gap:4px;display:flex}.quota-stacked-head{justify-content:space-between;align-items:baseline;gap:8px;display:flex}.quota-stacked-limit{font-weight:600}.quota-stacked-reset{font-size:12px}.quota-stacked-bar-row{align-items:center;gap:8px;display:flex}.quota-stacked-bar{flex:1}.quota-stacked-used{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px}.quota-stacked-used--warn{color:var(--amber)}.quota-stacked-limit-reached{color:var(--amber);align-items:center;gap:4px;font-size:12px;display:inline-flex}.main-inner:has(.pws-shell-container){max-width:1440px}.pws-shell-container{width:100%;min-width:0;container:provider-workspace/inline-size}.pws-root{gap:var(--space-4);grid-template-columns:minmax(240px,280px) minmax(0,1fr);width:100%;max-width:100%;min-height:480px;display:grid}.pws-rail{gap:var(--space-3);border-right:1px solid var(--border);padding-right:var(--space-3);flex-direction:column;min-width:0;display:flex}.pws-search-row{align-items:center;gap:6px;display:flex}.pws-search-wrap{flex:1;min-width:0;position:relative}.pws-search-icon{color:var(--muted);pointer-events:none;position:absolute;top:50%;left:8px;transform:translateY(-50%)}.pws-search-wrap .pws-search-input{width:100%;padding-left:32px}.pws-filter-wrap{position:relative}.pws-filter-btn{appearance:none;border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;color:var(--muted);min-width:var(--control-md);min-height:var(--control-md);background:0 0;padding:6px;position:relative}.pws-filter-btn--active{color:var(--text);border-color:var(--text)}.pws-filter-dot{background:var(--accent);border-radius:50%;width:6px;height:6px;position:absolute;top:3px;right:3px}.pws-filter-menu{z-index:30;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);flex-direction:column;gap:4px;min-width:230px;padding:10px;display:flex;position:absolute;top:calc(100% + 6px);right:0;box-shadow:0 8px 24px #0000001f}.pws-filter-title{margin-bottom:2px;font-weight:600}.pws-filter-head{text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin-top:8px;font-size:11px}.pws-filter-option{cursor:pointer;align-items:center;gap:8px;padding:3px 2px;display:flex}.pws-filter-label{flex:1}.pws-filter-count{color:var(--muted);font-variant-numeric:tabular-nums;font-size:12px}.pws-sort-grid{grid-template-columns:1fr 1fr;gap:4px;display:grid}.pws-sort-btn{appearance:none;border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;color:var(--muted);background:0 0;padding:4px 8px;font-size:12px}.pws-sort-btn--active{color:var(--text);border-color:var(--text)}.pws-filter-footer{justify-content:flex-end;margin-top:8px;display:flex}.pws-rail-list{flex-direction:column;gap:4px;min-height:0;display:flex;overflow-y:auto}.pws-rail-empty{padding:8px 4px;font-size:12px}.pws-rail-group{flex-direction:column;gap:2px;display:flex}.pws-rail-group-head{justify-content:space-between;align-items:center;gap:var(--space-2);font-size:var(--text-caption);font-weight:var(--weight-medium);color:var(--muted);padding:var(--space-2) var(--space-2) var(--space-1);display:flex}.pws-rail-group-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.pws-rail-group-count{font-variant-numeric:tabular-nums;flex-shrink:0}.providers-workspace-rail-row{grid-template-columns:var(--icon-lg) minmax(0, 1fr) max-content;align-items:center;gap:var(--space-2);width:100%;min-height:var(--pws-rail-row-height,46px);appearance:none;border-radius:var(--radius-sm);padding:var(--space-1-5) var(--space-2);cursor:pointer;text-align:left;color:inherit;font:inherit;transition:background var(--motion-fast), box-shadow var(--motion-fast);background:0 0;border:none;display:grid;overflow:hidden}.providers-workspace-rail-row:hover{background:var(--surface)}.providers-workspace-rail-row--selected{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--border)}.providers-workspace-rail-icon{width:var(--icon-lg);height:var(--icon-lg);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.providers-workspace-rail-icon img,.providers-workspace-rail-icon .provider-icon-mask{width:var(--icon-lg);height:var(--icon-lg);display:block}.provider-icon-mask{-webkit-mask-position:50%;mask-position:50%;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.providers-workspace-rail-copy{gap:var(--space-0-5);flex-direction:column;min-width:0;display:flex;overflow:hidden}.providers-workspace-rail-primary{align-items:center;gap:var(--space-1-5);min-width:0;display:flex}.providers-workspace-rail-name-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-size:var(--text-body);font-weight:var(--weight-medium);line-height:var(--leading-ui);overflow:hidden}.providers-workspace-rail-secondary{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-size:var(--text-caption);line-height:var(--leading-ui);color:var(--muted);overflow:hidden}.pwi-rail-badge{border:1px solid var(--border);color:var(--muted);border-radius:999px;padding:1px 6px;font-size:10px}.pwi-rail-badge--free{color:var(--green);border-color:var(--green)}.pwi-rail-badge--local{color:var(--amber);border-color:var(--amber)}.providers-workspace-rail-trail{flex-shrink:0;align-items:center;gap:4px;display:inline-flex}.pwi-default-star{color:var(--amber);display:inline-flex}.providers-workspace-rail-status{border-radius:50%;width:8px;height:8px;display:inline-block}.providers-workspace-rail-status--active{background:var(--green)}.providers-workspace-rail-status--warning{background:var(--amber)}.providers-workspace-rail-status--inactive{background:var(--muted)}.pws-main{min-width:0;max-width:100%;padding:0 var(--space-2);overflow:hidden}.pws-detail-placeholder{flex-direction:column;align-items:flex-start;gap:8px;padding:24px 8px;display:flex}.pws-empty-root{justify-content:center;padding:48px 16px;display:flex}.pws-empty-hero{text-align:center;flex-direction:column;align-items:center;gap:16px;max-width:640px;display:flex}.pws-empty-tiles{grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;width:100%;display:grid}.pws-empty-tile{appearance:none;border:1px solid var(--border);border-radius:var(--radius-sm);cursor:pointer;color:inherit;font:inherit;background:0 0;flex-direction:column;align-items:center;gap:6px;padding:14px 12px;display:flex}.pws-empty-tile:hover{background:var(--surface)}.pws-empty-tile-label{font-weight:600}.pws-empty-tile-desc{font-size:12px}@container provider-workspace (width<=920px){.pws-root{gap:var(--space-3);grid-template-columns:240px minmax(0,1fr)}}@container provider-workspace (width<=680px){.pws-root{grid-template-columns:minmax(0,1fr);min-height:auto}.pws-rail{--pws-rail-row-height:var(--control-touch);border-right:none;border-bottom:1px solid var(--border);padding-right:0;padding-bottom:var(--space-3);max-height:320px;overflow-y:auto}.pws-main{padding:var(--space-2) 0 0}}@media (width<=768px){.pws-root{grid-template-columns:1fr;min-height:auto}.pws-rail{border-right:none;border-bottom:1px solid var(--border);max-height:320px;padding-bottom:12px;padding-right:0;overflow-y:auto}.pws-main{padding-top:8px}.pws-empty-tiles{grid-template-columns:1fr}}@media (width<=360px){.main-inner:has(.pws-shell-container)>.page-head{flex-wrap:wrap;align-items:flex-start}.main-inner:has(.pws-shell-container)>.page-head .row{flex-wrap:wrap;justify-content:flex-start;width:100%}}.pws-detail-back-link{color:var(--accent,#3b82f6);font:inherit;cursor:pointer;background:0 0;border:none;align-items:center;gap:4px;margin-bottom:8px;padding:0;font-size:.82rem;display:inline-flex}.pws-detail-back-link:hover{text-decoration:underline}.pws-detail-back-chevron{width:12px;height:12px;transform:rotate(180deg)}.pws-detail-head-main{align-items:center;gap:10px;margin-bottom:12px;display:flex}.pws-detail-head-main .pws-detail-title{align-items:center;gap:8px;display:flex}.pws-detail-actions{align-items:center;gap:8px;margin-left:auto;display:flex}.pws-detail-toggle{align-items:center;gap:6px;display:flex}.pws-detail-toggle-label{color:var(--muted);font-size:.82rem}.btn-icon-only{padding:4px 6px}.pws-overview-layout{grid-template-columns:1fr 280px;align-items:start;gap:24px;display:grid}.pws-overview-main{flex-direction:column;gap:20px;min-width:0;display:flex}.pws-overview-sidebar{flex-direction:column;align-self:start;gap:20px;display:flex}@container provider-workspace (width<=920px){.pws-overview-layout{grid-template-columns:minmax(0,1fr)}}.pws-auth-summary{align-items:center;gap:8px;font-size:.88rem;display:flex}.pws-auth-summary--warn{border:1px solid color-mix(in srgb, var(--yellow,#eab308) 45%, transparent);background:color-mix(in srgb, var(--yellow,#eab308) 12%, transparent);color:inherit;border-radius:8px;align-items:flex-start;padding:10px 12px}.pws-auth-summary-body{flex-wrap:wrap;flex:1;align-items:center;gap:8px 10px;min-width:0;display:flex}.pws-auth-summary--warn svg{color:var(--yellow,#eab308);flex-shrink:0;margin-top:2px}.pws-auth-dot{background:var(--green,#22c55e);border-radius:50%;flex-shrink:0;width:8px;height:8px}.pws-notes-section{min-width:0}.pws-notes-display{text-align:left;width:100%;font:inherit;color:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;min-height:48px;padding:8px 10px;font-size:.85rem;transition:border-color .15s;display:block}.pws-notes-display:hover{border-color:var(--border)}.pws-notes-textarea{border:1px solid var(--accent,#3b82f6);width:100%;font:inherit;color:inherit;background:var(--bg);resize:vertical;border-radius:6px;min-height:48px;padding:8px 10px;font-size:.85rem}.pws-notes-textarea:focus{outline:none;box-shadow:0 0 0 2px #3b82f640}@media (width<=768px){.pws-overview-layout{grid-template-columns:1fr}.pws-overview-sidebar{position:static}}.pws-detail{flex-direction:column;gap:0;width:100%;min-width:0;max-width:960px;display:flex}.pws-detail-icon{flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;display:flex}.pws-detail-icon img,.pws-detail-icon .provider-icon-mask{width:28px;height:28px}.pws-detail-title-wrap{flex:1;min-width:0}.pws-detail-title{margin:0;font-size:1.15rem;font-weight:600;line-height:1.3}.pws-detail-tabs{scrollbar-width:thin;border-bottom:1px solid var(--border);gap:0;margin-top:8px;margin-bottom:16px;display:flex;overflow-x:auto}.pws-detail-tab{appearance:none;font:inherit;color:var(--muted);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:8px 14px;font-size:.82rem;font-weight:500;transition:color .15s,border-color .15s}.pws-detail-tab:hover{color:var(--text)}.pws-detail-tab--active{color:var(--text);border-bottom-color:var(--text)}.pws-detail-tab:focus-visible{outline:2px solid var(--accent-ring);outline-offset:-2px}.pws-detail-panel:focus{outline:none}.pws-section{margin-bottom:16px}.pws-section-title{text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:0 0 8px;font-size:.7rem;font-weight:600}.pws-section--side{margin-bottom:12px}.pws-kv{flex-direction:column;gap:0;margin:0;display:flex}.pws-kv-row{gap:12px;padding:5px 0;font-size:.84rem;line-height:1.4;display:flex}.pws-kv-row dt{width:130px;color:var(--muted);flex-shrink:0;font-weight:400}.pws-kv-row dd{word-break:break-word;flex:1;min-width:0;margin:0}.pws-kv-row dd code{font-size:.8rem}.pws-kv-mono{font-variant-numeric:tabular-nums}.pws-status-ok{color:var(--green,#22c55e);align-items:center;gap:4px;display:flex}.pws-status-warn{color:var(--amber,#f59e0b);align-items:center;gap:4px;display:flex}.pws-stats-note{margin-top:6px;font-size:.75rem}.pws-edit-settings-link,.pws-view-usage-link{margin-top:8px;font-size:.8rem}.pws-section-head{justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:12px;display:flex}.pws-section-head .pws-section-title{margin-bottom:0}.pws-model-search{width:100%;margin-bottom:18px}.pws-model-list{flex-wrap:wrap;align-items:center;gap:12px;margin-top:4px;display:flex}.pws-model-chip{border:1px solid color-mix(in oklab, var(--border) 85%, transparent);background:color-mix(in oklab, var(--surface,var(--panel)) 92%, var(--text) 4%);border-radius:8px;align-items:center;gap:10px;max-width:100%;padding:8px 10px 8px 12px;display:inline-flex}.pws-model-chip-main{min-width:0;color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;margin:0;padding:0;display:inline-flex}.pws-model-chip-main:hover .pws-model-id{color:var(--accent,var(--text))}.pws-model-chip-main:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px;border-radius:4px}.pws-model-id{font-family:var(--mono,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);color:var(--text);white-space:nowrap;font-size:.8rem;font-weight:600;line-height:1.35}.pws-model-flag{flex-shrink:0}.pws-inline-error{align-items:center;gap:10px;margin-top:8px;display:flex}.pws-usage-block+.pws-usage-block{border-top:1px solid color-mix(in oklab, var(--border) 45%, transparent);margin-top:32px;padding-top:24px}.pws-usage-metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:20px 28px;margin-top:14px;display:grid}.pws-usage-metric{flex-direction:column;gap:8px;min-width:0;display:flex}.pws-usage-metric-value{font-variant-numeric:tabular-nums;letter-spacing:-.02em;color:var(--text);font-size:1.35rem;font-weight:650;line-height:1.15}.pws-usage-metric-label{font-size:.8rem;line-height:1.3}.pws-usage-meta{margin-top:16px}@media (width<=640px){.pws-usage-metrics{grid-template-columns:1fr;gap:16px}}.pwi-auth-section{flex-direction:column;gap:12px;display:flex}.pwi-auth-body{flex-direction:column;gap:10px;display:flex}.pwi-auth-status-row{align-items:center;gap:8px;display:flex}.pwi-auth-dot{border-radius:var(--radius-round);background:var(--muted);flex-shrink:0;width:8px;height:8px}.pwi-auth-dot--ok{background:var(--green)}.pwi-auth-dot--off{background:var(--muted)}.pwi-auth-dot--warn{background:var(--amber)}.pwi-auth-status-text{font-size:var(--text-control);color:var(--text)}.pwi-auth-state{min-height:36px;font-size:var(--text-label);color:var(--muted);background:var(--raised);border-radius:var(--radius-xs);align-items:center;gap:8px;padding:8px 10px;display:flex}.pwi-auth-state--error{color:var(--red);background:var(--red-soft);justify-content:space-between}.pwi-auth-state--empty{justify-content:center}.pwi-auth-actions{flex-wrap:wrap;gap:8px;display:flex}.pwi-auth-wait{flex-direction:column;gap:6px;display:flex}.pwi-auth-wait-title{font-size:var(--text-control);color:var(--text);font-weight:600}.pwi-auth-wait-copy{font-size:var(--text-label);color:var(--muted);line-height:1.45}.pwi-auth-open-link{font-size:var(--text-label);color:var(--accent);cursor:pointer;text-decoration:underline}.pwi-auth-list{flex-direction:column;gap:4px;display:flex}.pwi-auth-row{border-radius:var(--radius-xs);transition:background var(--motion-fast);align-items:center;gap:8px;padding:6px 8px;display:flex}.pwi-auth-row:hover{background:var(--hover)}.pwi-auth-row--active{background:var(--accent-soft)}.pwi-auth-row-main{appearance:none;min-width:0;color:inherit;text-align:left;cursor:pointer;border-radius:var(--radius-2xs);background:0 0;border:0;flex:1;align-items:center;gap:8px;padding:2px;display:flex}.pwi-auth-row-main:disabled{cursor:default;opacity:.72}.pwi-auth-row-main:focus-visible,.pwi-auth-row-remove:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px}.pwi-auth-row-label{font-size:var(--text-control);color:var(--text);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.pwi-auth-row-remove{cursor:pointer;color:var(--muted);border-radius:var(--radius-2xs);transition:color var(--motion-fast), background var(--motion-fast);background:0 0;border:none;padding:2px}.pwi-auth-row-remove:hover{color:var(--red);background:var(--red-soft)}.pwi-auth-add-key{font-size:var(--text-label);color:var(--accent);cursor:pointer;text-align:left;background:0 0;border:none;padding:4px 0}.pwi-auth-add-key:hover{text-decoration:underline}@keyframes pwi-spin{to{transform:rotate(360deg)}}.pwi-spin-inline{border:2px solid var(--border);border-top-color:var(--accent);border-radius:var(--radius-round);width:14px;height:14px;animation:.7s linear infinite pwi-spin;display:inline-block}.pwi-settings-form{flex-direction:column;gap:14px;display:flex;position:relative}.pwi-settings-field{flex-direction:column;gap:4px;display:flex}.pwi-settings-label{font-size:var(--text-label);color:var(--muted);letter-spacing:.01em;font-weight:500}.pwi-settings-textarea{width:100%;min-height:60px;font:inherit;font-size:var(--text-control);color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-xs);resize:vertical;transition:border-color var(--motion-fast);padding:8px 10px}.pwi-settings-textarea:focus{border-color:var(--accent-ring);outline:none}.pwi-settings-hint{font-size:var(--text-caption);color:var(--muted);line-height:1.4}.pwi-settings-sticky-bar{z-index:2;background:var(--bg);border-top:1px solid var(--border-soft);align-items:center;gap:8px;padding:10px 0;display:flex;position:sticky;bottom:0}.pwi-settings-sticky-bar-actions{gap:8px;margin-left:auto;display:flex}.pwi-settings-msg{font-size:var(--text-label);border-radius:var(--radius-xs);padding:6px 10px;line-height:1.4}.pwi-settings-msg--ok{background:var(--green-soft);color:var(--green)}.pwi-settings-msg--err{background:var(--red-soft);color:var(--red)}.pwi-settings-dirty{font-size:var(--text-caption);color:var(--amber)}.pwi-json-panel{flex-direction:column;gap:8px;display:flex}.pwi-json-panel-header{justify-content:space-between;align-items:center;gap:8px;display:flex}.pwi-json-panel-title{font-size:var(--text-control);color:var(--text);font-weight:600}.pwi-json-panel-actions{gap:6px;display:flex}.pwi-json-panel-desc{font-size:var(--text-caption);color:var(--muted);line-height:1.4}.pwi-json-textarea{width:100%;min-height:180px;font-family:ui-monospace,SF Mono,Cascadia Code,Segoe UI Mono,Menlo,monospace;font-size:var(--text-label);tab-size:2;color:var(--text);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-xs);resize:vertical;transition:border-color var(--motion-fast);padding:10px 12px;line-height:1.5}.pwi-json-textarea:focus{border-color:var(--accent-ring);outline:none}.dialog-backdrop{z-index:900;background:#00000073;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.dialog{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);width:90%;max-width:420px;box-shadow:var(--shadow);flex-direction:column;gap:16px;padding:24px;display:flex}.dialog-actions{justify-content:flex-end;gap:8px;display:flex}.pws-dashboard{flex-direction:column;gap:14px;max-width:100%;padding:4px 0;display:flex}.pws-dashboard-header{flex-direction:row;justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.pws-dashboard-header-text{flex-direction:column;gap:2px;min-width:0;display:flex}.pws-dashboard-title{margin:0;font-size:1.1rem;font-weight:600}.pws-dashboard-subtitle{margin:0;font-size:.82rem}.pws-dashboard-summary{gap:10px;display:flex}.pws-dashboard-card{border:1px solid var(--border);background:var(--bg-secondary,var(--bg));border-radius:8px;flex-direction:column;align-items:center;gap:2px;min-width:80px;padding:10px 20px;display:flex}.pws-dashboard-card-count{font-size:1.25rem;font-weight:700;line-height:1}.pws-dashboard-card--ok .pws-dashboard-card-count{color:var(--green,#22c55e)}.pws-dashboard-card--warn .pws-dashboard-card-count{color:var(--yellow,#eab308)}.pws-dashboard-card--muted .pws-dashboard-card-count{color:var(--fg-muted,#888)}.pws-dashboard-card-label{color:var(--fg-muted,#888);letter-spacing:.02em;font-size:.7rem}.pws-dashboard-columns{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);align-items:start;gap:20px;display:grid}.pws-dashboard-section{flex-direction:column;gap:4px;min-width:0;display:flex}.pws-dashboard-section-title{text-transform:uppercase;letter-spacing:.04em;color:var(--fg-muted,#888);margin:0;padding-bottom:2px;font-size:.68rem;font-weight:600}.pws-dashboard-attention .pws-dashboard-section-title{color:var(--yellow,#eab308);text-transform:none;letter-spacing:0;align-items:center;gap:6px;font-size:.82rem;display:inline-flex}.pws-dashboard-row--attention{border-color:color-mix(in srgb, var(--yellow,#eab308) 40%, var(--border));background:color-mix(in srgb, var(--yellow,#eab308) 8%, var(--bg-secondary,var(--bg)))}.pws-dashboard-rows{flex-direction:column;gap:0;display:flex}.pws-dashboard-row{cursor:pointer;text-align:left;color:inherit;font:inherit;background:0 0;border:none;border-radius:6px;grid-template-columns:22px 1fr auto auto;align-items:center;gap:8px;width:100%;padding:6px;transition:background .12s;display:grid}.pws-dashboard-row:hover{background:var(--bg-hover,#80808014)}.pws-dashboard-row-icon{justify-content:center;align-items:center;width:20px;height:20px;display:flex}.pws-dashboard-row-icon img,.pws-dashboard-row-icon .provider-icon-mask{width:18px;height:18px}.pws-dashboard-row-info{flex-direction:column;gap:1px;min-width:0;display:flex}.pws-dashboard-row-name{white-space:nowrap;text-overflow:ellipsis;font-size:.85rem;font-weight:500;overflow:hidden}.pws-dashboard-row-meta{font-size:.72rem}.pws-dashboard-row-count{white-space:nowrap;font-size:.8rem}.pws-dashboard-row-chevron{width:12px;height:12px;color:var(--fg-muted,#888);flex-shrink:0}.pws-dashboard-row-bars{grid-column:1/-1;padding-top:1px;padding-left:30px}@container provider-workspace (width<=920px){.pws-dashboard-columns{grid-template-columns:1fr;gap:14px}}@media (width<=900px){.pws-dashboard-columns{grid-template-columns:1fr;gap:14px}}@media (width<=600px){.pws-dashboard-summary{flex-direction:column}.pws-dashboard-card{flex-direction:row;justify-content:space-between;min-width:0}}.combos-workspace-root{grid-template-columns:minmax(340px,28vw) 1fr;align-items:stretch;width:100%;height:100%;min-height:100%;display:grid;overflow:hidden}.combos-workspace-shell{flex-direction:column;width:100%;height:100%;min-height:0;display:flex;overflow:hidden}.combos-workspace-shell-banner{flex-shrink:0;padding:10px 16px 0}.combos-workspace-shell-body{flex-direction:column;flex:auto;min-height:0;display:flex;overflow:hidden}.combos-workspace-rail{border-right:1px solid var(--border);background:var(--rail);flex-direction:column;height:100%;min-height:0;display:flex;position:sticky;top:0;overflow-y:auto}.combos-workspace-rail-header{border-bottom:1px solid var(--border-soft);flex-shrink:0;justify-content:space-between;align-items:center;gap:8px;padding:14px 16px 12px;display:flex}.combos-workspace-rail-title{color:var(--text);font-size:18px;font-weight:600}.combos-workspace-rail-count{font-family:var(--mono);color:var(--faint);font-size:11px}.combos-workspace-rail-list{flex-direction:column;flex:auto;display:flex;overflow-y:auto}.combos-workspace-rail-group+.combos-workspace-rail-group{margin-top:10px}.combos-workspace-rail-group-head{color:var(--muted);align-items:center;gap:7px;padding:8px 16px 6px;font-size:11.5px;font-weight:600;display:flex}.combos-workspace-rail-row{border:none;border-bottom:1px solid var(--border-soft);cursor:pointer;min-height:40px;font:inherit;color:var(--text);text-align:left;background:0 0;grid-template-columns:26px minmax(0,1fr) 3.5rem 14px;align-items:center;column-gap:8px;width:100%;padding:11px 12px 11px 14px;font-size:13px;transition:background .12s;display:grid}.combos-workspace-rail-row:hover{background:var(--hover)}.combos-workspace-rail-row.combos-workspace-rail-row--selected{background:var(--accent-soft);box-shadow:inset 3px 0 0 var(--accent)}.combos-workspace-rail-row:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}.combos-workspace-rail-icon{width:26px;height:26px;color:var(--text);flex-shrink:0;justify-content:center;align-items:center;display:flex}.combos-workspace-rail-name{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:var(--mono);font-size:12.5px;overflow:hidden}.combos-workspace-rail-meta{font-family:var(--mono);color:var(--faint);text-align:right;font-size:11px}.combos-workspace-rail-chevron{width:14px;height:14px;color:var(--faint)}.combos-workspace-main{background:var(--bg);flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;overflow:hidden}.combos-workspace-overview,.combos-workspace-detail{flex:auto;min-height:0;padding:20px 24px 32px;overflow-y:auto}.combos-workspace-empty-root{justify-content:center;align-items:center;height:100%;min-height:100%;display:flex}.cwi-empty-cta{appearance:none;border:1px solid color-mix(in srgb, var(--border,var(--text)) 55%, transparent);background:color-mix(in srgb, var(--surface,transparent) 40%, transparent);width:100%;max-width:44ch;font:inherit;text-align:center;color:inherit;cursor:pointer;border-radius:10px;flex-direction:column;justify-content:center;align-items:center;gap:10px;margin:0;padding:40px 28px;transition:border-color .15s,background-color .15s,box-shadow .15s;display:flex}.cwi-empty-cta-title{color:var(--text);font-size:20px;font-weight:650;transition:color .15s}.cwi-empty-cta .pwi-empty-right-icon{transition:color .15s}.cwi-empty-cta:hover{border-color:color-mix(in srgb, var(--accent,var(--text)) 35%, var(--border,var(--text)));background:color-mix(in srgb, var(--accent,var(--text)) 6%, transparent);box-shadow:0 0 0 1px color-mix(in srgb, var(--accent,var(--text)) 12%, transparent)}.cwi-empty-cta:hover .pwi-empty-right-icon{color:var(--muted)}.cwi-empty-cta:hover .cwi-empty-cta-title{color:var(--accent,var(--text))}.cwi-empty-cta:focus-visible{outline:2px solid color-mix(in srgb, var(--accent,var(--text)) 45%, transparent);outline-offset:3px}.combos-workspace-overview-head{justify-content:space-between;align-items:baseline;gap:12px;margin-bottom:16px;display:flex}.combos-workspace-overview-title{margin:0;font-size:20px;font-weight:600}.combos-workspace-detail-head{border-bottom:1px solid var(--border-soft);flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;display:flex}.combos-workspace-detail-title{font-size:18px;font-weight:600;font-family:var(--mono);min-width:0;margin:0}.combos-workspace-detail-actions{flex-wrap:wrap;align-items:center;gap:8px;margin-left:auto;display:flex}.combos-workspace-tabs{border-bottom:1px solid var(--border-soft);gap:4px;margin-bottom:16px;display:flex}.combos-workspace-tab{appearance:none;font:inherit;color:var(--muted);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-1px;padding:8px 12px;font-size:13px;font-weight:500}.combos-workspace-tab:hover{color:var(--text)}.combos-workspace-tab.combos-workspace-tab--active{color:var(--text);border-bottom-color:var(--accent)}.combos-workspace-tab-content{flex-direction:column;gap:16px;max-width:720px;display:flex}.cwi-search-row{border-bottom:1px solid var(--border-soft);flex-shrink:0;align-items:center;gap:8px;padding:10px 14px 12px;display:flex}.cwi-search-wrap{flex:1;min-width:0;position:relative}.cwi-search-wrap .cwi-search-icon{width:14px;height:14px;color:var(--faint);pointer-events:none;position:absolute;top:50%;left:10px;transform:translateY(-50%)}.cwi-search-input{width:100%;padding-left:32px!important}.cwi-count-strip{flex-wrap:wrap;gap:10px;margin-bottom:18px;display:flex}.cwi-count-pill{border:1px solid var(--border-soft);border-radius:var(--radius);background:var(--raised);align-items:baseline;gap:6px;padding:8px 12px;display:inline-flex}.cwi-count-pill strong{font-family:var(--mono);font-size:16px}.cwi-count-pill span{color:var(--muted);font-size:12px}.cwi-target-list{flex-direction:column;gap:8px;display:flex}.cwi-target-row{grid-template-columns:28px minmax(0,1fr) minmax(0,1.2fr) 4.5rem auto;align-items:center;gap:8px;display:grid}.cwi-target-row--failover{grid-template-columns:28px minmax(0,1fr) minmax(0,1.2fr) auto}.cwi-target-row--dragging{opacity:.55}.cwi-target-row--drop{box-shadow:inset 0 0 0 1px var(--accent);border-radius:var(--radius)}.cwi-target-grip{border-radius:var(--radius);width:28px;height:32px;color:var(--faint);cursor:grab;touch-action:none;background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.cwi-target-grip:hover{color:var(--muted);background:var(--hover)}.cwi-target-grip:active{cursor:grabbing}.cwi-target-actions{flex-shrink:0;gap:2px;display:flex}.cwi-strategy-seg{border-radius:var(--radius-pill);background:var(--surface-soft,var(--raised));gap:2px;padding:3px;display:inline-flex}.cwi-strategy-seg .btn{border-radius:var(--radius-pill);border:none;min-width:88px;padding:5px 12px}.cwi-strategy-seg .btn-ghost{color:var(--muted);background:0 0}.cwi-copy-chip{font-family:var(--mono);cursor:pointer;font-size:12px}.cwi-form-grid{flex-direction:column;gap:12px;display:flex}.cwi-field label{color:var(--muted);margin-bottom:4px;font-size:12px;font-weight:600;display:block}.cwi-field .input,.cwi-field select.input{width:100%}.cwi-attention-list{flex-direction:column;gap:0;display:flex}.cwi-attention-row{border:none;border-bottom:1px solid var(--border-soft);width:100%;font:inherit;color:var(--text);text-align:left;cursor:pointer;background:0 0;align-items:center;gap:10px;padding:10px 0;display:flex}.cwi-attention-row:hover{color:var(--accent)}.cwi-modal-form{flex-direction:column;gap:14px;max-height:min(70vh,560px);padding-right:2px;display:flex;overflow-y:auto}.cwi-modal-actions{justify-content:flex-end;gap:8px;margin-top:16px;display:flex}@media (width<=939px){.combos-workspace-root{grid-template-rows:minmax(220px,38vh) 1fr;grid-template-columns:1fr}.combos-workspace-rail{border-right:none;border-bottom:1px solid var(--border);position:relative}.cwi-target-row,.cwi-target-row--failover{grid-template-columns:28px 1fr auto}.cwi-target-row>.input:nth-child(2),.cwi-target-row>.input:nth-child(3){grid-column:2/-1}}.pwi-dot{background:var(--muted);border-radius:50%;flex-shrink:0;width:7px;height:7px;display:inline-block}.pwi-back-overview{white-space:nowrap;flex:none;gap:4px;margin-right:2px}.pwi-section{background:0 0;border:none;border-radius:0;min-width:0;padding:0}.pwi-section-title{color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin:0 0 4px;font-size:12px;font-weight:650}.pwi-empty-right-icon{color:var(--faint)}.pwi-empty-right-sub{color:var(--muted);max-width:44ch;margin:0;font-size:13.5px;line-height:1.5}.pwi-json-unsaved-card,.pwi-remove-confirm-card{width:min(420px,92vw);max-width:420px;padding:20px 22px 16px}.pwi-json-unsaved-title,.pwi-remove-confirm-title{color:var(--text);margin:0 0 8px;font-size:16px;font-weight:650}.pwi-json-unsaved-desc,.pwi-remove-confirm-desc{margin:0 0 18px;font-size:13.5px;line-height:1.45}.pwi-json-unsaved-actions,.pwi-remove-confirm-actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.pwi-remove-confirm-danger{background:var(--red)!important;color:#fff!important;border-color:#0000!important}.pwi-remove-confirm-danger:hover:not(:disabled){filter:brightness(1.08)}:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--bg:var(--lightningcss-light,#fff)var(--lightningcss-dark,#212121);--rail:var(--lightningcss-light,#f9f9f9)var(--lightningcss-dark,#171717);--surface:var(--lightningcss-light,#fff)var(--lightningcss-dark,#262626);--raised:var(--lightningcss-light,#f4f4f4)var(--lightningcss-dark,#303030);--raised-hover:var(--lightningcss-light,#ececec)var(--lightningcss-dark,#3a3a3a);--border:var(--lightningcss-light,#e6e6e6)var(--lightningcss-dark,#3d3d3d);--border-soft:var(--lightningcss-light,#f0f0f0)var(--lightningcss-dark,#333);--hover:var(--lightningcss-light,#0d0d0d08)var(--lightningcss-dark,#ffffff08);--text:var(--lightningcss-light,#0d0d0d)var(--lightningcss-dark,#ececec);--muted:var(--lightningcss-light,#6e6e6e)var(--lightningcss-dark,#a6a6a6);--faint:var(--lightningcss-light,#707070)var(--lightningcss-dark,#9a9a9a);--accent:var(--lightningcss-light,#0d0d0d)var(--lightningcss-dark,#ececec);--accent-hover:var(--lightningcss-light,#3d3d3d)var(--lightningcss-dark,#fff);--accent-ink:var(--lightningcss-light,#fff)var(--lightningcss-dark,#0d0d0d);--accent-soft:var(--lightningcss-light,#0d0d0d0f)var(--lightningcss-dark,#ffffff17);--accent-ring:var(--lightningcss-light,#0d0d0d4d)var(--lightningcss-dark,#ffffff61);--green:var(--lightningcss-light,#0a7d5c)var(--lightningcss-dark,#4ecb9d);--green-soft:var(--lightningcss-light,#10a37f1a)var(--lightningcss-dark,#4ecb9d21);--red:var(--lightningcss-light,#b91c1c)var(--lightningcss-dark,#f87171);--red-soft:var(--lightningcss-light,#b91c1c17)var(--lightningcss-dark,#f8717121);--amber:var(--lightningcss-light,#9a4a08)var(--lightningcss-dark,#fbbf24);--amber-soft:var(--lightningcss-light,#b453091a)var(--lightningcss-dark,#fbbf2421);--space-0-5:2px;--space-1:4px;--space-1-5:6px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:20px;--space-6:24px;--space-8:32px;--space-10:40px;--space-12:48px;--space-16:64px;--radius-2xs:4px;--radius:12px;--radius-sm:8px;--radius-xs:6px;--radius-lg:16px;--radius-round:50%;--radius-pill:999px;--font-ui:"OpenAI Sans", "Pretendard Variable", Pretendard, "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;--font-code:ui-monospace, "SFMono-Regular", "Cascadia Code", "JetBrains Mono", "Noto Sans Mono CJK KR", Menlo, Consolas, monospace;--font:var(--font-ui);--mono:var(--font-code);--text-micro:10px;--text-caption:11px;--text-label:12px;--text-control:13px;--text-body:14px;--text-subtitle:16px;--text-title:20px;--text-display:24px;--weight-regular:400;--weight-medium:500;--weight-semibold:600;--weight-bold:700;--leading-tight:1.2;--leading-ui:1.35;--leading-body:1.5;--leading-relaxed:1.6;--tracking-normal:0;--tracking-wide:.04em;--control-sm:28px;--control-md:34px;--control-lg:40px;--control-touch:44px;--icon-sm:14px;--icon-md:16px;--icon-lg:20px;--motion-fast:.12s;--motion-normal:.18s;--shadow:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#00000080), 0 10px 28px var(--lightningcss-light,#10182812)var(--lightningcss-dark,#0000004d);--shadow-sm:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#0006);--toggle-w:36px;--toggle-h:20px;--toggle-dot:14px;--toggle-off-bg:var(--lightningcss-light,#d4d4d4)var(--lightningcss-dark,#4a4a4a);--toggle-on-bg:var(--lightningcss-light,#0d0d0d)var(--lightningcss-dark,#4ecb9d);--toggle-dot-color:var(--lightningcss-light,#fff)var(--lightningcss-dark,#0d0d0d)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}:root[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}:root{--glass-rail:var(--lightningcss-light,#f9f9f9a8)var(--lightningcss-dark,#1717179e);--glass-panel:var(--lightningcss-light,#ffffffc7)var(--lightningcss-dark,#262626d1);--glass-blur:saturate(1.6) blur(22px)}*{box-sizing:border-box}html,body,#root{height:100%}html{background:var(--bg);overflow-x:hidden}body{color:var(--text);font-family:var(--font-ui);font-size:var(--text-body);line-height:var(--leading-body);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;background:0 0;margin:0;overflow-x:hidden}body:before{content:"";z-index:-1;pointer-events:none;filter:blur(70px);background:radial-gradient(42% 38% at 12% 6%,var(--lightningcss-light,#a4c4ff6b)var(--lightningcss-dark,#6082c829),#0000 70%),radial-gradient(46% 42% at 88% 18%,var(--lightningcss-light,#a8e2c561)var(--lightningcss-dark,#58a08221),#0000 70%),radial-gradient(40% 36% at 70% 92%,var(--lightningcss-light,#ffe0c24d)var(--lightningcss-dark,#b48c6414),#0000 72%);position:fixed;inset:-20%}a{color:var(--text);text-decoration:underline;-webkit-text-decoration-color:var(--faint);text-decoration-color:var(--faint);text-underline-offset:2px}a:hover{-webkit-text-decoration-color:var(--text);text-decoration-color:var(--text)}code{font-family:var(--font-code);font-size:var(--text-label)}.mono{font-family:var(--font-code);font-variant-numeric:tabular-nums}h1,h2,h3,h4{font-weight:var(--weight-semibold);letter-spacing:0;line-height:var(--leading-tight);margin:0}.text-micro{line-height:var(--leading-ui);font-size:var(--text-micro)!important}.text-caption{line-height:var(--leading-ui);font-size:var(--text-caption)!important}.text-label{line-height:var(--leading-ui);font-size:var(--text-label)!important}.text-control{line-height:var(--leading-ui);font-size:var(--text-control)!important}.text-body{line-height:var(--leading-body);font-size:var(--text-body)!important}.text-subtitle{line-height:var(--leading-tight);font-size:var(--text-subtitle)!important}.text-title{line-height:var(--leading-tight);font-size:var(--text-title)!important}.text-display{line-height:var(--leading-tight);font-size:var(--text-display)!important}.font-regular{font-weight:var(--weight-regular)!important}.font-medium{font-weight:var(--weight-medium)!important}.font-semibold{font-weight:var(--weight-semibold)!important}.font-bold{font-weight:var(--weight-bold)!important}.leading-tight{line-height:var(--leading-tight)!important}.leading-ui{line-height:var(--leading-ui)!important}.leading-body{line-height:var(--leading-body)!important}.leading-relaxed{line-height:var(--leading-relaxed)!important}::selection{background:var(--accent-soft)}input[type=checkbox],input[type=radio]{accent-color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--border);border-radius:var(--radius-pill);border:2px solid var(--bg)}::-webkit-scrollbar-thumb:hover{background:var(--faint)}:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px;border-radius:var(--radius-2xs)}.app{grid-template-columns:232px 1fr;min-height:100dvh;display:grid}.sidebar{border-right:1px solid var(--border);background:var(--glass-rail);height:100dvh;-webkit-backdrop-filter:var(--glass-blur);flex-direction:column;align-self:start;gap:4px;padding:18px 14px;display:flex;position:sticky;top:0}.brand{align-items:center;gap:10px;padding:6px 8px 14px;display:flex}.brand-logo{background:var(--text);flex-shrink:0;width:26px;height:26px;-webkit-mask:url(/logo.png) 50%/contain no-repeat;mask:url(/logo.png) 50%/contain no-repeat}.brand .name{font-weight:var(--weight-semibold);font-size:var(--text-subtitle);letter-spacing:0;line-height:26px}.brand .ver{font-family:var(--font-code);font-size:var(--text-micro);color:var(--muted);line-height:var(--leading-tight);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-pill);align-self:center;padding:2px 6px}.sidebar nav{flex-direction:column;gap:4px;display:flex}.nav-item{border-radius:var(--radius-sm);text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;font-size:var(--text-control);font-weight:var(--weight-medium);transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;align-items:center;gap:10px;padding:8px 10px;display:flex}.nav-item:hover,.nav-item.active{background:var(--accent-soft);color:var(--text)}.nav-item.active{font-weight:var(--weight-semibold)}.nav-item svg{width:17px;height:17px;color:var(--faint);flex-shrink:0}.nav-item.active svg{color:var(--text)}.sidebar-foot{flex-direction:column;gap:2px;margin-top:auto;padding-top:12px;display:flex}.drawer-head{align-items:flex-start;display:flex}.drawer-head .brand{flex:auto;min-width:0}.mobile-topbar{display:none}.menu-toggle{border-radius:var(--radius-sm);min-width:44px;min-height:44px;color:var(--muted);cursor:pointer;transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;justify-content:center;align-items:center;padding:8px;display:none}.menu-toggle:hover{background:var(--accent-soft);color:var(--text)}.menu-toggle svg{width:20px;height:20px}.drawer-scrim{z-index:30;background:var(--lightningcss-light,#14141452)var(--lightningcss-dark,#00000085);display:none;position:fixed;inset:0}.sidebar-link{color:var(--muted);font-size:var(--text-control);border-radius:var(--radius-sm);align-items:center;gap:9px;padding:8px 10px;text-decoration:none;display:flex}.sidebar-link:hover{background:var(--accent-soft);color:var(--text);text-decoration:none}.sidebar-link svg{width:16px;height:16px}.lang-toggle{width:100%;color:var(--muted);font-size:var(--text-control);border-radius:var(--radius-sm);transition:background var(--motion-fast), color var(--motion-fast);align-items:center;gap:9px;padding:8px 10px;display:flex;position:relative}.lang-toggle:hover{background:var(--accent-soft);color:var(--text)}.lang-toggle svg{flex-shrink:0;width:16px;height:16px}.lang-toggle .custom-select{width:100%;position:static!important}.lang-toggle .select-trigger{width:100%;color:inherit;font-size:var(--text-control);min-height:auto;box-shadow:none;-webkit-backdrop-filter:none;background:0 0;border:none;justify-content:space-between;padding:0}.lang-toggle .select-trigger:hover:not(:disabled){color:inherit;box-shadow:none;background:0 0;border:none}.lang-toggle .select-dropdown{background:var(--glass-rail);-webkit-backdrop-filter:var(--glass-blur);border:1px solid var(--border);box-shadow:var(--shadow-sm)}.lang-toggle .select-dropdown-beside{min-width:10rem;top:0;left:calc(100% + 6px);right:auto}.theme-toggle{text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;font-size:var(--text-control);border-radius:var(--radius-sm);transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;align-items:center;gap:9px;padding:8px 10px;display:flex}.theme-toggle:hover{background:var(--accent-soft);color:var(--text)}.theme-toggle svg{flex-shrink:0;width:16px;height:16px}.theme-toggle .mode{text-transform:capitalize}.stop-toggle{color:var(--red)}.stop-toggle:hover{background:var(--red-soft);color:var(--red)}.stop-toggle:disabled{opacity:.5;cursor:default}.main{min-width:0}.main-inner{max-width:980px;margin:0 auto;padding:32px 36px 64px}.main-inner.main-inner--combos{flex-direction:column;max-width:none;height:100dvh;min-height:100dvh;margin:0;padding:0;display:flex;overflow:hidden}.main-inner.main-inner--combos>.combos-workspace-shell{flex-direction:column;flex:auto;height:100%;min-height:0;display:flex}.page-head{justify-content:space-between;align-items:center;gap:16px;margin-bottom:6px;display:flex}.page-head h2{font-size:var(--text-title)}.page-sub{color:var(--muted);font-size:var(--text-body);max-width:70ch;margin:4px 0 22px}.page-tabs{border-bottom:1px solid var(--border);gap:2px;margin:2px 0 14px;display:flex}.page-tab{appearance:none;color:var(--muted);cursor:pointer;font:inherit;font-size:var(--text-control);background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-1px;padding:8px 12px}.page-tab:hover{color:var(--text)}.page-tab--active{color:var(--text);border-bottom-color:var(--accent);font-weight:var(--weight-semibold)}.page-tab:focus-visible{outline:2px solid var(--accent-ring);outline-offset:-2px}.page-sub b{color:var(--text);font-weight:var(--weight-semibold)}.api-page h2 svg{vertical-align:-.16em;width:1em;height:1em}.api-page .page-sub code{font-size:var(--text-label);color:var(--text);background:var(--raised);border:1px solid var(--border-soft);border-radius:var(--radius-xs);padding:1px 4px}.btn{border-radius:var(--radius-pill);font:inherit;font-size:var(--text-control);font-weight:var(--weight-medium);line-height:var(--leading-ui);cursor:pointer;transition:background var(--motion-fast), border-color var(--motion-fast), opacity var(--motion-fast);white-space:nowrap;border:1px solid #0000;justify-content:center;align-items:center;gap:7px;padding:8px 16px;display:inline-flex}.btn svg{width:15px;height:15px}.btn:disabled{opacity:.55;cursor:default}.btn-primary{background:var(--accent);color:var(--accent-ink)}.btn-primary:hover:not(:disabled){background:var(--accent-hover)}.btn-ghost{background:var(--bg);color:var(--text);border-color:var(--border)}.btn-ghost:hover:not(:disabled){background:var(--raised)}.btn-danger{color:var(--red);background:0 0;border-color:#f871714d}.btn-danger:hover:not(:disabled){background:var(--red-soft)}.btn-sm{font-size:var(--text-label);border-radius:var(--radius-pill);padding:4px 12px}.btn-icon{appearance:none;font:inherit;cursor:pointer;width:28px;height:28px;color:var(--muted);border-radius:var(--radius-sm);transition:background var(--motion-fast), color var(--motion-fast);background:0 0;border:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.btn-icon:hover{background:var(--raised-hover);color:var(--text)}.btn-icon:focus-visible{outline:2px solid var(--accent-ring);outline-offset:1px}.btn-icon svg{width:16px;height:16px;display:block}.btn.btn-ghost.btn-icon{width:28px;height:28px;padding:0}.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);min-width:0}.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:18px}.panel-accent{border-color:color-mix(in srgb, var(--accent) 28%, var(--border));background:color-mix(in srgb, var(--accent) 5%, var(--surface))}.api-panel{flex-direction:column;gap:10px;display:flex;overflow:hidden}.api-panel .panel-title,.api-panel .muted{margin:0}.api-form-row{align-items:center;gap:8px;min-width:0;display:flex}.api-form-row .input{flex:1;min-width:0}.api-code{min-width:0;color:var(--text);background:var(--raised);border:1px solid var(--border-soft);border-radius:var(--radius-sm);font-family:var(--font-code);font-size:var(--text-label);line-height:var(--leading-relaxed);white-space:pre;margin:0;padding:9px 11px;display:block;overflow-x:auto}.api-code-inline{white-space:nowrap}.api-actions{justify-content:flex-end;align-items:center;gap:4px;display:flex}.maintenance-head{flex-wrap:wrap;align-items:flex-start}.maintenance-actions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}.maintenance-notice{align-items:flex-start;margin:14px 0 0}.update-row{justify-content:space-between;align-items:center;gap:12px;margin-bottom:14px;display:flex}.update-row .field-label{margin:0}.update-empty{margin-bottom:14px;padding:18px}.update-box{flex-direction:column;gap:12px;display:flex}.update-command{font-size:var(--text-label);flex-wrap:wrap;align-items:flex-start;gap:6px;display:flex}.update-command .chip{white-space:pre-wrap;word-break:break-all;overflow-wrap:anywhere;flex:auto;min-width:0;max-width:100%;line-height:1.5}.update-recheck{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.update-recheck .btn{flex:none}.update-recheck-reason{min-width:0;font-size:var(--text-label);color:var(--muted);flex:200px}.update-restart{border-top:1px solid var(--border-soft);padding-top:12px}.injection-head{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.injection-label{font-weight:var(--weight-semibold)}@media (width<=800px){.injection-head{gap:8px}.injection-label{flex:1 0 calc(100% - 70px);order:1}.injection-head>.badge{order:1;margin-left:auto}.injection-head>.custom-select{order:2}}.stat-row{grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:28px;display:grid}.stat-row>.stat{flex-direction:column;justify-content:center;min-height:80px;display:flex}@media (width<=1100px){.stat-row{grid-template-columns:repeat(3,1fr)}}@media (width<=640px){.stat-row{grid-template-columns:repeat(2,1fr)}}.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);transition:border-color var(--motion-fast);padding:14px 16px}.stat:hover{border-color:var(--faint)}.stat .label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);align-items:center;gap:6px;margin-bottom:6px;display:flex}.stat .label svg{width:14px;height:14px}.stat .value{font-size:var(--text-title);font-weight:var(--weight-semibold);letter-spacing:0;line-height:var(--leading-tight)}.stat .value.mono{font-family:var(--font-code);font-size:var(--text-subtitle)}.model-group-head{font-size:var(--text-control);font-weight:var(--weight-semibold);color:var(--text);align-items:baseline;gap:8px;margin:0 0 8px;display:flex}.model-group-head .count{font-family:var(--font-code);font-weight:var(--weight-medium);color:var(--faint);font-size:var(--text-label)}.group-head{cursor:pointer;background:var(--surface);transition:background var(--motion-fast);padding:10px 12px}.group-head:hover{background:var(--hover)}.group-head.open{border-bottom:1px solid var(--border-soft)}.model-grid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;display:grid}.model-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);transition:border-color var(--motion-fast), background var(--motion-fast);padding:10px 12px}.model-card:hover{border-color:var(--faint);background:var(--hover)}.model-card .id{font-family:var(--font-code);font-weight:var(--weight-semibold);font-size:var(--text-control);letter-spacing:0;color:var(--text)}.badge{font-size:var(--text-caption);font-weight:var(--weight-semibold);line-height:var(--leading-ui);border-radius:var(--radius-pill);font-family:var(--font-code);letter-spacing:0;border:1px solid #0000;align-items:center;gap:5px;padding:2px 8px;display:inline-flex}.badge-accent{background:var(--accent-soft);color:var(--text)}.badge-green{background:var(--green-soft);color:var(--green)}.badge-amber{background:var(--amber-soft);color:var(--amber)}.badge-muted{background:var(--raised);color:var(--muted);border:1px solid var(--border)}.badge-clickable{cursor:pointer;transition:filter var(--motion-fast);appearance:none}.badge-clickable:hover{filter:brightness(1.1)}.badge-disabled{opacity:.5;cursor:default}.card-badges{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:inline-flex}.card-badges .badge{flex-shrink:0}.confirm-icon{border-radius:var(--radius-round);background:var(--amber-soft);width:44px;height:44px;color:var(--amber);justify-content:center;align-items:center;margin:0 auto 12px;display:flex}.credit-list{flex-direction:column;gap:6px;display:flex}.credit-item{border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--raised);transition:border-color var(--motion-fast);padding:8px 10px}.credit-next{border-color:var(--amber);background:var(--amber-soft)}.credit-item-head{color:var(--text);font-size:var(--text-label);font-weight:var(--weight-semibold);align-items:center;gap:6px;margin-bottom:3px;display:flex}.credit-item-head svg{color:var(--amber);flex-shrink:0}.credit-item-dates{font-size:var(--text-caption);font-family:var(--font-code);color:var(--muted);justify-content:space-between;display:flex}.credit-urgent{color:var(--red);font-weight:var(--weight-semibold)}.dot{border-radius:var(--radius-round);flex-shrink:0;width:7px;height:7px}.dot-green{background:var(--green);box-shadow:0 0 0 3px var(--green-soft)}.dot-red{background:var(--red);box-shadow:0 0 0 3px var(--red-soft)}.tbl{border-collapse:collapse;width:100%;font-size:var(--text-control)}.tbl thead th{text-align:left;color:var(--muted);font-weight:var(--weight-medium);font-size:var(--text-label);border-bottom:1px solid var(--border);padding:9px 12px}.tbl tbody td{border-bottom:1px solid var(--border-soft);padding:10px 12px}.tbl tbody tr:last-child td{border-bottom:none}.tbl tbody tr:hover td{background:var(--hover)}.tbl .num{text-align:right;font-family:var(--font-code);font-variant-numeric:tabular-nums}.tbl-wrap{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);overflow-x:auto}.input,textarea.input{border-radius:var(--radius-sm);background:var(--raised);border:1px solid var(--border);width:100%;color:var(--text);font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);transition:border-color var(--motion-fast);padding:8px 11px}.input::placeholder{color:var(--faint)}.input:focus{border-color:var(--faint);box-shadow:0 0 0 3px var(--accent-soft);outline:none}textarea.input{resize:vertical;font-family:var(--font-code);line-height:var(--leading-relaxed)}.field-label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);margin-bottom:5px;display:block}select.input{appearance:none}.select-sm{border-radius:var(--radius-pill);background:color-mix(in oklab, canvas 75%, transparent);-webkit-backdrop-filter:blur(12px)saturate(1.3);border:1px solid var(--border);color:var(--text);font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);cursor:pointer;transition:border-color var(--motion-fast), box-shadow var(--motion-fast);padding:6px 12px;box-shadow:0 2px 8px #0000000f}.select-sm:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft);outline:none}.select-sm:hover:not(:disabled){border-color:var(--faint);box-shadow:0 2px 12px #0000001a}.select-sm:disabled{opacity:.5;cursor:default;-webkit-backdrop-filter:none}.select-trigger{border-radius:var(--radius-pill);background:color-mix(in oklab, canvas 75%, transparent);-webkit-backdrop-filter:blur(12px)saturate(1.3);border:1px solid var(--border);color:var(--text);font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);cursor:pointer;transition:border-color var(--motion-fast), box-shadow var(--motion-fast);white-space:nowrap;align-items:center;gap:6px;padding:6px 12px;display:inline-flex;box-shadow:0 2px 8px #0000000f}.select-trigger:hover:not(:disabled){border-color:var(--faint);box-shadow:0 2px 12px #0000001a}.select-trigger:disabled{opacity:.5;cursor:default}.select-dropdown{z-index:40;background:color-mix(in oklab, canvas 84%, transparent);-webkit-backdrop-filter:blur(20px)saturate(1.4);border:1px solid var(--border);border-radius:var(--radius);min-width:100%;max-height:280px;padding:4px;position:absolute;top:calc(100% + 4px);left:0;overflow-y:auto;box-shadow:0 8px 32px #00000029}.select-dropdown-right{right:0;left:auto!important}.select-dropdown-beside{min-width:10rem;top:0;left:calc(100% + 6px);right:auto}.select-option{text-align:left;border-radius:var(--radius-sm);width:100%;color:var(--text);font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);cursor:pointer;transition:background var(--motion-fast);white-space:nowrap;background:0 0;border:none;padding:7px 12px;display:block}.select-option:hover{background:var(--hover)}.select-option.active{background:var(--accent-soft);color:var(--accent);font-weight:var(--weight-semibold)}.switch{border-radius:var(--radius-pill);border:1px solid var(--border);cursor:pointer;background:var(--raised);vertical-align:middle;width:34px;height:20px;transition:background var(--motion-normal), border-color var(--motion-normal);appearance:none;flex-shrink:0;align-items:center;padding:2px;line-height:0;display:inline-flex}.switch.on{background:var(--toggle-on-bg);border-color:var(--toggle-on-bg)}.switch:disabled{opacity:.6;cursor:default}.switch .knob{border-radius:var(--radius-round);width:14px;height:14px;transition:transform var(--motion-normal), background var(--motion-normal);background:var(--lightningcss-light,#fff)var(--lightningcss-dark,#ececec);transform:translate(0);box-shadow:0 0 0 1px #10182814,0 1px 1px #1018282e}.switch.on .knob{background:var(--toggle-dot-color);transform:translate(14px);box-shadow:0 0 0 1px #0000001f}.muted{color:var(--muted)}.faint{color:var(--faint)}.row{align-items:center;gap:10px;display:flex}.spread{justify-content:space-between;align-items:center;gap:12px;display:flex}.setting-hint{font-size:var(--text-control);line-height:var(--leading-body);margin-top:3px}.stack{flex-direction:column;display:flex}.chip{font-family:var(--font-code);font-size:var(--text-label);line-height:var(--leading-ui);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-xs);color:var(--text);padding:1px 7px}.empty{text-align:center;border:1px dashed var(--border);border-radius:var(--radius);color:var(--muted);padding:56px 20px}.empty svg{width:30px;height:30px;color:var(--faint);margin-bottom:12px}.empty .title{color:var(--text);font-weight:var(--weight-semibold);margin-bottom:6px}.notice{font-size:var(--text-control);line-height:var(--leading-body);border-radius:var(--radius-sm);align-items:center;gap:8px;margin-bottom:14px;padding:9px 12px;display:flex}.notice svg{flex-shrink:0;width:15px;height:15px}.notice-ok{background:var(--green-soft);color:var(--green)}.notice-err{background:var(--red-soft);color:var(--red)}.h-section{font-size:var(--text-control);font-weight:var(--weight-semibold);line-height:var(--leading-ui);color:var(--text);align-items:center;gap:8px;margin:30px 0 12px;display:flex}.h-section .count{color:var(--muted);font-weight:var(--weight-medium);font-family:var(--font-code);font-size:var(--text-label)}.spin{border:2px solid var(--border);border-top-color:var(--accent);border-radius:var(--radius-round);width:14px;height:14px;animation:.7s linear infinite spin;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.sidebar,.lang-toggle .select-dropdown{background:var(--rail)}.modal-card{background:var(--surface)}}@media (prefers-reduced-transparency:reduce){body:before{display:none}.sidebar,.lang-toggle .select-dropdown{background:var(--rail);-webkit-backdrop-filter:none}.modal-card{background:var(--surface);-webkit-backdrop-filter:none}.modal-overlay{-webkit-backdrop-filter:none}}.modal-overlay{-webkit-backdrop-filter:blur(40px)saturate(1.2);z-index:50;background:var(--lightningcss-light,#11131cc7)var(--lightningcss-dark,#000000d1);justify-content:center;align-items:flex-start;padding:8vh 16px;display:flex;position:fixed;inset:0}dialog.modal-overlay{width:100%;max-width:none;height:100%;max-height:none;color:inherit;border:none;margin:0}dialog.modal-overlay::backdrop{background:0 0}.modal-card{background:color-mix(in oklab, canvas 92%, transparent);-webkit-backdrop-filter:blur(20px)saturate(1.4);border:1px solid var(--border);border-radius:var(--radius-lg);width:100%;max-width:520px;max-height:84vh;padding:20px;overflow-y:auto;box-shadow:0 8px 32px #0000002e}.modal-head{justify-content:space-between;align-items:center;margin-bottom:16px;display:flex}.modal-head h3{font-size:var(--text-subtitle)}.card-head{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;padding:14px 16px 6px;display:flex}.card-head strong{overflow-wrap:anywhere;min-width:0}.card-sub{font-size:var(--text-label);line-height:var(--leading-body);color:var(--muted);overflow-wrap:anywhere;min-width:0;padding:0 16px 10px}.card-active{border-color:var(--accent-ring)}.card-right{font-size:var(--text-caption);color:var(--faint);align-items:center;gap:4px;margin-left:auto;display:flex}.btn-icon-danger.card-right{appearance:none;color:var(--red);cursor:pointer;background:0 0;border:1px solid #0000;justify-content:center}.btn-icon-danger.card-right:hover{background:var(--red-soft);border-color:var(--red-soft);color:var(--red)}.card-row{justify-content:space-between;align-items:center;padding:14px 16px;display:flex}.badge-primary{background:var(--accent-soft);color:var(--accent-hover)}.dot-blue{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.dot-muted{background:var(--muted)}.dot-amber{background:var(--amber);box-shadow:0 0 0 3px var(--amber-soft)}.section-sep{align-items:center;gap:10px;margin:20px 0 12px;display:flex}.section-label{font-size:var(--text-label);color:var(--muted);font-weight:var(--weight-medium);white-space:nowrap}.sep-line{background:var(--border);flex:1;height:1px}.quota-compact{gap:4px;padding:2px 16px 12px;display:grid}.quota-row{grid-template-columns:minmax(34px,max-content) 34px minmax(34px,44px) minmax(38px,42px) minmax(58px,1fr) minmax(30px,max-content);align-items:center;gap:8px;min-width:0;display:grid}.quota-label{font-size:var(--text-caption);color:var(--muted);font-weight:var(--weight-semibold)}.quota-val{font-size:var(--text-caption);font-family:var(--font-code);color:var(--text);text-align:right}.quota-reset-label{text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-caption);color:var(--faint);overflow:hidden}.quota-reset-day,.quota-reset-time{font-size:var(--text-caption);color:var(--muted);white-space:nowrap}.quota-reset-time{font-family:var(--font-code)}.bar{background:var(--raised);border-radius:var(--radius-2xs);min-width:0;height:5px;overflow:hidden}.bar-fill{border-radius:var(--radius-2xs);height:100%;transition:width var(--motion-normal)}.bar-green{background:var(--green)}.bar-amber{background:linear-gradient(90deg, var(--green), var(--amber))}.toggle{width:var(--toggle-w);height:var(--toggle-h);border-radius:var(--radius-pill);background:var(--toggle-off-bg);border:1px solid var(--border);cursor:pointer;transition:background var(--motion-normal), border-color var(--motion-normal);flex-shrink:0;position:relative}.toggle.on{background:var(--toggle-on-bg);border-color:var(--toggle-on-bg)}.toggle-knob{border-radius:var(--radius-round);width:16px;height:16px;transition:left var(--motion-normal), background var(--motion-normal);background:var(--lightningcss-light,#fff)var(--lightningcss-dark,#ececec);position:absolute;top:1px;left:1px}.toggle.on .toggle-knob{background:var(--toggle-dot-color);left:17px}.notice-warn{font-size:var(--text-label);line-height:var(--leading-body);border-radius:var(--radius-sm);background:var(--amber-soft);color:var(--amber);align-items:center;gap:6px;margin-bottom:12px;padding:8px 10px;display:flex}.notice-warn svg{flex-shrink:0;width:14px;height:14px}.modal-desc{font-size:var(--text-control);line-height:var(--leading-body);color:var(--muted);margin-bottom:14px}.modal-actions{gap:8px;margin-top:16px;display:flex}.modal-actions .btn{flex:1}.log-reqid{-webkit-line-clamp:2;word-break:break-all;-webkit-box-orient:vertical;max-width:14ch;display:-webkit-box;overflow:hidden}.log-col-model{overflow-wrap:break-word;word-break:normal;max-width:18ch}.log-col-tokens{min-width:10ch}table.logs-table{min-width:960px}.log-col-rate{white-space:nowrap;min-width:7ch}.log-col-cost{white-space:nowrap;min-width:10ch}.log-status-cell{min-width:7ch;line-height:var(--leading-tight);flex-direction:column;align-items:flex-start;gap:2px;display:inline-flex}.log-detail-btn{cursor:pointer;color:var(--accent-hover);font:inherit;font-size:var(--text-caption);white-space:nowrap;background:0 0;border:none;padding:0;text-decoration:underline}.log-detail-grid{font-size:var(--text-control);grid-template-columns:max-content minmax(0,1fr);gap:6px 14px;display:grid}.log-detail-break{word-break:break-all}.log-detail-card{max-width:760px}.log-detail-section{border-top:1px solid var(--border-soft);padding:14px 0}.log-detail-section:first-of-type{border-top:0;padding-top:0}.log-detail-section-title{font-size:var(--text-label);font-weight:var(--weight-semibold);color:var(--text);margin:0 0 10px}.log-detail-request-row{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.log-detail-request-row>span{min-width:0}.log-detail-notes{color:var(--muted);font-size:var(--text-label);margin:10px 0 0;padding-left:18px}.log-detail-notes-line{font-size:var(--text-label);margin:8px 0 0}.log-detail-attempts-wrap{border:1px solid var(--border-soft);border-radius:var(--radius-sm);overflow-x:auto}.log-detail-attempts{min-width:680px}.log-detail-attempts th,.log-detail-attempts td{vertical-align:top}.log-detail-raw{margin-top:14px}.log-detail-raw>summary{cursor:pointer;color:var(--muted);font-size:var(--text-label)}.log-detail-raw[open]>summary{margin-bottom:6px}.usage-cost-row{border:1px solid var(--border-soft);border-radius:var(--radius-sm);background:var(--raised);align-items:baseline;gap:10px;margin:10px 0 4px;padding:10px 14px;display:flex}.usage-cost-value{font-size:var(--text-lg,1.15em)}@media (width<=760px){.modal-overlay{padding:16px 10px}.log-detail-card{max-height:calc(100dvh - 32px);padding:16px}.log-detail-grid{grid-template-columns:minmax(7rem,max-content) minmax(0,1fr);gap:8px 10px}.log-detail-request-row{flex-direction:column;align-items:flex-start}}.log-detail-json{background:var(--raised);border:1px solid var(--border-soft);border-radius:var(--radius-sm);font-family:var(--font-code);font-size:var(--text-caption);line-height:var(--leading-body);white-space:pre-wrap;word-break:break-all;max-height:40vh;margin:0;padding:10px 12px;overflow:auto}.setup-guide{font-size:var(--text-control);line-height:var(--leading-body);border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:4px;padding:8px 12px}.setup-guide summary{cursor:pointer;color:var(--accent-hover);font-weight:var(--weight-medium)}.setup-guide summary:hover{text-decoration:underline}.setup-guide a{color:var(--accent-hover)}.list-row{text-align:left;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--raised);cursor:pointer;width:100%;color:var(--text);font:inherit;transition:background var(--motion-fast), border-color var(--motion-fast);justify-content:space-between;align-items:center;gap:10px;padding:11px 13px;display:flex}.list-row:hover{background:var(--raised-hover);border-color:var(--accent-ring)}.list-row .title{font-weight:var(--weight-semibold);font-size:var(--text-body)}.list-row .sub{font-size:var(--text-label);color:var(--muted);margin-top:2px}.prov-card{overflow:hidden}.prov-card-main{flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:12px;padding:15px 16px;display:flex}.prov-card-disabled{opacity:.62}.prov-card-info{flex:360px;align-items:flex-start;gap:11px;min-width:0;display:flex}.prov-card-copy{flex:1;min-width:0}.prov-title{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;margin-bottom:5px;display:flex}.provider-icon{border-radius:var(--radius-xs);background:var(--raised);border:1px solid var(--border-soft);width:31px;height:31px;color:var(--text);flex:none;justify-content:center;align-items:center;display:inline-flex}.provider-icon img{object-fit:contain;width:19px;height:19px;display:block}.prov-meta{flex-wrap:wrap;align-items:center;gap:5px;min-width:0;display:flex}.prov-meta>span{text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%;overflow:hidden}.provider-quota{padding-left:58px}.provider-actions{flex-shrink:0;align-items:center;gap:8px;margin-left:auto;display:flex}.openai-mode-row{flex-wrap:wrap;align-items:center;gap:10px;margin-top:10px;display:flex}.openai-mode-control .usage-segmented-btn{min-width:76px}.link-btn{color:var(--accent-hover);font:inherit;font-size:var(--text-control);cursor:pointer;background:0 0;border:none;padding:6px 2px;text-decoration:underline}.link-btn svg{flex-shrink:0;width:14px;height:14px}.prov-accounts-toggle{border:none;border-top:1px solid var(--border-soft);width:100%;color:var(--muted);font:inherit;font-size:var(--text-label);cursor:pointer;background:0 0;justify-content:center;align-items:center;gap:6px;min-height:24px;padding:4px 0;display:flex}.prov-accounts-toggle:hover{color:var(--text);background:var(--raised)}.prov-accounts-toggle .chev{transition:transform var(--motion-normal) ease;display:inline-flex}.prov-accounts-toggle .chev svg{width:12px;height:12px;transform:rotate(90deg)}.prov-accounts-toggle.open .chev svg{transform:rotate(-90deg)}.prov-accounts-list{border-top:1px solid var(--border-soft);flex-direction:column;gap:2px;padding:6px 16px 10px;display:flex}.prov-account-row{border-radius:var(--radius-xs);align-items:center;gap:8px;width:100%;min-height:32px;padding:6px 8px;display:flex}button.prov-account-row{text-align:left;color:var(--text);font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);cursor:pointer;background:0 0;border:none}button.prov-account-row:hover,.prov-account-row:hover{background:var(--raised)}button.prov-account-row.active{cursor:default}.prov-account-row-main{appearance:none;min-width:0;color:inherit;text-align:left;cursor:pointer;font:inherit;font-size:var(--text-control);line-height:var(--leading-ui);background:0 0;border:0;flex:auto;align-items:center;gap:8px;padding:0;display:flex}.prov-account-row-main:disabled{cursor:default;opacity:.72}.prov-account-row .prov-account-email{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}.prov-account-row .badge{flex:none}.prov-account-reauth{color:var(--accent);cursor:pointer;font:inherit;font-size:var(--text-label);border-radius:var(--radius-xs);background:0 0;border:none;flex:none;padding:4px 6px}.prov-account-reauth:hover:not(:disabled){color:var(--accent-hover);background:var(--raised)}.prov-account-reauth:disabled{opacity:.6;cursor:default}.prov-account-remove{color:var(--muted);cursor:pointer;border-radius:var(--radius-xs);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:4px;display:inline-flex}.prov-account-remove:hover{color:var(--red);background:var(--red-soft)}.prov-account-add{color:var(--muted);font-size:var(--text-label)}.prov-account-add:hover{color:var(--accent-hover)}.prov-account-keyform{cursor:default;gap:6px}.prov-account-keyform:hover{background:0 0}.prov-account-keyform .input-sm{min-width:0;font-size:var(--text-label);height:var(--control-sm);flex:auto;padding:4px 8px}.oauth-grid{grid-template-columns:minmax(140px,max-content) minmax(0,1fr) max-content;align-items:center;gap:10px 16px;display:grid}.oauth-row{grid-column:1/-1;grid-template-columns:subgrid;align-items:center;min-height:30px;display:grid}.oauth-name{font-size:var(--text-control);font-weight:var(--weight-semibold);align-items:center;gap:8px;min-width:0;display:inline-flex}.oauth-name-text{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.provider-icon-sm{border-radius:var(--radius-xs);width:24px;height:24px}.provider-icon-sm img{width:15px;height:15px}.oauth-status{font-size:var(--text-control);align-items:center;gap:7px;min-width:0;display:inline-flex}.oauth-email{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.oauth-actions{justify-content:flex-end;align-items:center;gap:8px;min-width:0;display:inline-flex}.oauth-login-hint{font-size:var(--text-label);line-height:var(--leading-body);flex-direction:column;grid-column:1/-1;align-items:stretch;gap:8px;display:flex}.oauth-login-hint-links{flex-wrap:wrap;align-items:center;gap:8px;display:inline-flex}.oauth-login-paste{align-items:center;gap:8px;width:100%;display:flex}.oauth-login-paste .input{min-width:0;font-size:var(--text-label);flex:1;padding:6px 10px}@media (width<=760px){.app{grid-template-rows:auto 1fr;grid-template-columns:1fr}.mobile-topbar{z-index:20;border-bottom:1px solid var(--border);background:var(--glass-rail);min-width:0;-webkit-backdrop-filter:var(--glass-blur);align-items:center;gap:2px;padding:4px 10px;display:flex;position:sticky;top:0}.mobile-topbar .brand{flex:auto;min-width:0;padding:4px}.mobile-topbar .stop-toggle{justify-content:center;width:auto;min-width:44px;min-height:44px;padding:8px}.menu-toggle{display:inline-flex}.sidebar{z-index:40;width:min(280px,84vw);height:100dvh;padding-bottom:calc(18px + env(safe-area-inset-bottom));visibility:hidden;transition:transform var(--motion-normal) ease, visibility var(--motion-normal);background:var(--lightningcss-light,#f9f9f9f7)var(--lightningcss-dark,#171717f5);outline:none;position:fixed;top:0;bottom:0;left:0;overflow-y:auto;transform:translate(-100%)}.sidebar.open{visibility:visible;transform:translate(0);box-shadow:0 12px 40px var(--lightningcss-light,#14141438)var(--lightningcss-dark,#00000080)}.drawer-scrim{display:block}.main-inner{padding:22px 18px 48px}.main-inner.main-inner--combos{height:100%;min-height:0;padding:0;overflow:hidden}.setting-row{flex-wrap:wrap}.setting-row .setting-copy{flex:100%!important}.setting-row .setting-controls{width:100%}.setting-row .setting-controls .select-sm{flex:1 1 0;min-width:0}.setting-row>.select-sm{width:100%}.api-form-row{flex-direction:column;align-items:stretch}.api-form-row .btn{width:100%;min-height:40px}.stat-row>.stat{min-width:100px}.tbl{min-width:460px}.usage-cards{grid-template-columns:repeat(2,minmax(0,1fr))!important}.provider-quota{padding-left:16px}.prov-meta{grid-template-columns:max-content minmax(0,1fr);width:100%;display:grid}.prov-meta .chip~span:not(:last-child){display:none}.oauth-grid{grid-template-columns:minmax(0,auto) minmax(0,1fr) max-content;column-gap:8px}.sidebar .lang-toggle .select-dropdown-beside{inset:auto auto calc(100% + 6px) 0}}.usage-cards{grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:8px;display:grid}.usage-cards .stat-value{font-size:var(--text-title);font-weight:var(--weight-semibold);margin-top:4px}.usage-head{flex-wrap:wrap}.usage-filters{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}.usage-segmented{border:1px solid var(--border);border-radius:var(--radius-pill);background:var(--surface);gap:2px;padding:2px;display:inline-flex}.usage-segmented-btn{color:var(--muted);border-radius:var(--radius-pill);cursor:pointer;font:inherit;white-space:nowrap;background:0 0;border:none;justify-content:center;align-items:center;gap:6px;padding:4px 12px;display:inline-flex}.usage-segmented-btn.active{background:var(--raised);color:var(--text);font-weight:var(--weight-semibold)}.usage-source-mark{width:var(--icon-sm);height:var(--icon-sm);object-fit:contain;flex:none}:root[data-theme=dark] .usage-source-mark{filter:invert()}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .usage-source-mark{filter:invert()}}@media (width<=760px){.usage-segmented-btn{min-height:var(--control-touch)}.openai-mode-row{flex-direction:column;align-items:stretch;gap:6px}.openai-mode-control{width:100%}.openai-mode-control .usage-segmented-btn{flex:1 1 0;min-width:0}}@media (width<=640px){.usage-source-btn .usage-source-label-collapsible{display:none}}@media (width<=360px){.usage-filters{flex-direction:column;align-items:stretch;width:100%}.usage-segmented{width:100%}.usage-segmented-btn{flex:1 1 0}}.panel-title{font-size:var(--text-body);font-weight:var(--weight-semibold);color:var(--text);margin:0 0 12px}.panel-head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:12px;display:flex}.panel-head .panel-title{margin:0}.panel-head .input{max-width:220px}.heatmap{--hm-cell:11px;--hm-gap:3px;flex-direction:column;gap:6px;padding-bottom:4px;display:flex;overflow-x:auto}.heatmap-months{font-size:var(--text-caption);color:var(--muted);width:max-content;margin-bottom:-2px;display:grid}.heatmap-day-spacer{grid-column:1}.heatmap-month{white-space:nowrap}.heatmap-body{gap:var(--hm-gap);width:max-content;display:flex}.heatmap-days{grid-template-rows:repeat(7, var(--hm-cell));row-gap:var(--hm-gap);font-size:var(--text-micro);color:var(--muted);background:var(--surface);z-index:1;flex-shrink:0;align-items:center;width:25px;display:grid;position:sticky;left:0}.heatmap-grid{gap:var(--hm-gap);display:grid}.heatmap-week{grid-template-rows:repeat(7, var(--hm-cell));gap:var(--hm-gap);display:grid}.heatmap-cell{width:var(--hm-cell);height:var(--hm-cell);border-radius:var(--radius-2xs);background:var(--border)}.heatmap-cell-0{background:var(--border)}.heatmap-cell-1{background:color-mix(in oklch, var(--green) 25%, var(--surface))}.heatmap-cell-2{background:color-mix(in oklch, var(--green) 50%, var(--surface))}.heatmap-cell-3{background:color-mix(in oklch, var(--green) 75%, var(--surface))}.heatmap-cell-4{background:var(--green)}.heatmap-legend{font-size:var(--text-label);align-self:flex-end;align-items:center;gap:4px;display:inline-flex;position:sticky;right:0}.heatmap-legend .heatmap-cell{width:10px;height:10px}.heatmap-tip{z-index:10;pointer-events:none;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);white-space:nowrap;font-size:var(--text-label);padding:6px 10px;position:fixed;transform:translate(-50%,-100%)translateY(-8px);box-shadow:0 6px 20px #00000059}.heatmap-tip-date{font-weight:var(--weight-semibold);color:var(--text);margin-bottom:2px}.heatmap-tip-val{color:var(--text);font-variant-numeric:tabular-nums}.heatmap-tip-req{font-size:var(--text-caption)}.usage-bar{background:var(--border);border-radius:var(--radius-pill);width:100%;min-width:60px;height:6px;overflow:hidden}.usage-bar-fill{background:var(--green);border-radius:var(--radius-pill);height:100%}.daybars{grid-template-columns:repeat(7,1fr);align-items:end;gap:10px;height:180px;padding-top:8px;display:grid}.daybar{flex-direction:column;justify-content:flex-end;align-items:center;gap:6px;height:100%;display:flex;position:relative}.daybar-track{background:var(--border);border-radius:var(--radius-xs);flex:1;align-items:flex-end;width:100%;max-width:48px;display:flex;overflow:hidden}.daybar-stack{border-radius:var(--radius-xs) var(--radius-xs) 0 0;width:100%;min-height:2px;transition:height var(--motion-normal) ease;flex-direction:column-reverse;display:flex;overflow:hidden}.daybar-seg{width:100%;min-height:1px}.daybar-count{font-size:var(--text-label);font-weight:var(--weight-semibold);color:var(--text)}.daybar-label{font-size:var(--text-caption);white-space:nowrap}.daybar:hover .daybar-track{outline:1px solid var(--border)}.daybar-tip{z-index:5;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);pointer-events:none;min-width:160px;padding:8px 10px;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);box-shadow:0 6px 20px #00000059}.daybar-tip-date{font-size:var(--text-label);font-weight:var(--weight-semibold);color:var(--text);white-space:nowrap;margin-bottom:6px}.daybar-tip-row{font-size:var(--text-label);line-height:var(--leading-relaxed);align-items:center;gap:8px;display:flex}.daybar-tip-swatch{border-radius:var(--radius-2xs);flex-shrink:0;width:10px;height:10px}.daybar-tip-name{color:var(--text);white-space:nowrap;text-overflow:ellipsis;flex:1;max-width:160px;overflow:hidden}.daybar-tip-val{color:var(--muted);font-variant-numeric:tabular-nums}.usage-scroll{max-height:360px;overflow-y:auto}.usage-scroll thead th{z-index:1;background:var(--surface);position:sticky;top:0}.toggle{width:var(--toggle-w);height:var(--toggle-h);flex-shrink:0;display:inline-block;position:relative}.toggle input{opacity:0;width:0;height:0;position:absolute}.toggle .slider{background:var(--toggle-off-bg);border-radius:var(--radius-pill);cursor:pointer;transition:background var(--motion-normal) ease;position:absolute;inset:0}.toggle .slider:after{content:"";width:var(--toggle-dot);height:var(--toggle-dot);background:var(--toggle-dot-color);border-radius:var(--radius-round);transition:transform var(--motion-normal) ease;position:absolute;top:3px;left:3px}.toggle input:checked+.slider{background:var(--toggle-on-bg)}.toggle input:checked+.slider:after{transform:translateX(calc(var(--toggle-w) - var(--toggle-dot) - 6px))}.toggle input:focus-visible+.slider{outline:2px solid var(--accent-ring);outline-offset:2px}.setting-row{justify-content:space-between;align-items:center;gap:16px;padding:12px 16px;display:flex}.setting-row+.setting-row{border-top:1px solid var(--border-soft)}.setting-label{flex-direction:column;gap:2px;min-width:0;display:flex}.setting-label .title{font-size:var(--text-body);font-weight:var(--weight-semibold);color:var(--text)}.setting-label .desc{font-size:var(--text-label);color:var(--muted);line-height:var(--leading-body)}
|
package/gui/dist/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-BPa0R6EN.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BY7KvJRB.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -48,7 +48,10 @@ export function classifyCursorError(message: string): string {
|
|
|
48
48
|
|
|
49
49
|
if (
|
|
50
50
|
lower.includes("resource_exhausted") ||
|
|
51
|
-
lower.includes("resource exhausted")
|
|
51
|
+
lower.includes("resource exhausted")
|
|
52
|
+
) return "Cursor resource limit exceeded";
|
|
53
|
+
|
|
54
|
+
if (
|
|
52
55
|
lower.includes("rate limit") ||
|
|
53
56
|
lower.includes("rate-limit") ||
|
|
54
57
|
lower.includes("too many requests") ||
|
|
@@ -106,7 +109,9 @@ export function classifyCursorError(message: string): string {
|
|
|
106
109
|
* Mirrors `safeKiroErrorMessage` / `safeKiroHttpErrorMessage` in kiro-errors.ts.
|
|
107
110
|
*/
|
|
108
111
|
export function safeCursorErrorMessage(rawMessage: string): string {
|
|
109
|
-
const detail = sanitize(rawMessage).slice(0, 500);
|
|
110
112
|
const prefix = classifyCursorError(rawMessage);
|
|
113
|
+
const detail = sanitize(rawMessage)
|
|
114
|
+
.replace(/resource[_ ]exhausted/gi, "resource limit exceeded")
|
|
115
|
+
.slice(0, 500);
|
|
111
116
|
return detail ? `${prefix}: ${detail}` : prefix;
|
|
112
117
|
}
|
|
@@ -165,7 +165,7 @@ export const CURSOR_STATIC_MODELS: readonly CursorModelInfo[] = normalizeCursorM
|
|
|
165
165
|
{ id: "kimi-k2.7-code", contextWindow: CONTEXT_262K },
|
|
166
166
|
|
|
167
167
|
{ id: "grok-4.5", contextWindow: 500_000, supportsReasoningEffort: true },
|
|
168
|
-
{ id: "grok-4.5-fast", contextWindow: 500_000 },
|
|
168
|
+
{ id: "grok-4.5-fast", contextWindow: 500_000, supportsReasoningEffort: true },
|
|
169
169
|
]);
|
|
170
170
|
|
|
171
171
|
export function cursorModelIds(models: readonly CursorModelInfo[] = CURSOR_STATIC_MODELS): string[] {
|
|
@@ -195,7 +195,7 @@ export function cursorModelReasoningEfforts(
|
|
|
195
195
|
normalizeCursorModels(models).map(model => [
|
|
196
196
|
model.id,
|
|
197
197
|
model.supportsReasoningEffort === true
|
|
198
|
-
? cursorModelEffortLadder(model.id) ?? [
|
|
198
|
+
? cursorModelEffortLadder(model.id) ?? []
|
|
199
199
|
: [],
|
|
200
200
|
]),
|
|
201
201
|
);
|
|
@@ -6,10 +6,89 @@ import type {
|
|
|
6
6
|
OcxToolCall,
|
|
7
7
|
OcxToolResultMessage,
|
|
8
8
|
} from "../../types";
|
|
9
|
-
import { namespacedToolName } from "../../types";
|
|
9
|
+
import { isAllowedToolChoice, namespacedToolName, toolChoiceAliases, type OcxTool, type OcxToolChoice } from "../../types";
|
|
10
10
|
import type { CursorRequestMessage, CursorRunRequest } from "./types";
|
|
11
11
|
import { cursorCodexToWireModelId } from "./discovery";
|
|
12
12
|
import { cursorEffortSuffix } from "./effort-map";
|
|
13
|
+
import {
|
|
14
|
+
cursorMcpToolEncodedSize,
|
|
15
|
+
cursorMcpToolsEncodedSize,
|
|
16
|
+
cursorToolAllowedByChoice,
|
|
17
|
+
cursorToolWireName,
|
|
18
|
+
cursorToolsForActivePrompt,
|
|
19
|
+
} from "./tool-definitions";
|
|
20
|
+
|
|
21
|
+
/** Probe-verified Cursor Connect boundaries, with byte headroom for the enclosing field. */
|
|
22
|
+
export const CURSOR_TOOL_COUNT_LIMIT = 330;
|
|
23
|
+
export const CURSOR_TOOL_BYTES_LIMIT = 120_000;
|
|
24
|
+
|
|
25
|
+
interface CursorToolBudgetResult {
|
|
26
|
+
tools: OcxTool[];
|
|
27
|
+
omitted: OcxTool[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function explicitlySelectedNames(choice: OcxToolChoice | undefined): Set<string> {
|
|
31
|
+
if (!choice || choice === "auto" || choice === "none" || choice === "required") return new Set();
|
|
32
|
+
return new Set("name" in choice ? [choice.name] : isAllowedToolChoice(choice) ? choice.allowedTools : []);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function toolPriority(tool: OcxTool, selectedNames: ReadonlySet<string>): number {
|
|
36
|
+
if (toolChoiceAliases(tool).some(name => selectedNames.has(name))) return 0;
|
|
37
|
+
if (tool.loadedFromToolSearch) return 1;
|
|
38
|
+
if (!tool.namespace) return 2;
|
|
39
|
+
return 3;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Select one catalog used by both Cursor protobuf registration and call recognition.
|
|
44
|
+
* Actual McpTools serialization is measured after every candidate so descriptions,
|
|
45
|
+
* names, provider identifiers, and schemas all count toward the byte ceiling.
|
|
46
|
+
*/
|
|
47
|
+
export function applyCursorToolBudget(
|
|
48
|
+
tools: readonly OcxTool[] | undefined,
|
|
49
|
+
toolChoice: OcxToolChoice | undefined,
|
|
50
|
+
): CursorToolBudgetResult {
|
|
51
|
+
const eligible = (tools ?? []).filter(tool => cursorToolAllowedByChoice(tool, toolChoice));
|
|
52
|
+
if (
|
|
53
|
+
eligible.length <= CURSOR_TOOL_COUNT_LIMIT
|
|
54
|
+
&& cursorMcpToolsEncodedSize(eligible, toolChoice) <= CURSOR_TOOL_BYTES_LIMIT
|
|
55
|
+
) return { tools: [...eligible], omitted: [] };
|
|
56
|
+
|
|
57
|
+
const selectedNames = explicitlySelectedNames(toolChoice);
|
|
58
|
+
const candidates = eligible
|
|
59
|
+
.map((tool, index) => ({ tool, index, priority: toolPriority(tool, selectedNames) }))
|
|
60
|
+
.sort((a, b) => a.priority - b.priority || a.index - b.index);
|
|
61
|
+
const kept: OcxTool[] = [];
|
|
62
|
+
const keptSet = new Set<OcxTool>();
|
|
63
|
+
let keptBytes = 0;
|
|
64
|
+
|
|
65
|
+
for (const candidate of candidates) {
|
|
66
|
+
if (kept.length >= CURSOR_TOOL_COUNT_LIMIT) continue;
|
|
67
|
+
// Repeated protobuf message fields serialize as concatenated tag/length/value entries,
|
|
68
|
+
// so each one-entry wrapper size is the exact additive contribution to McpTools.
|
|
69
|
+
const candidateBytes = cursorMcpToolEncodedSize(candidate.tool, toolChoice);
|
|
70
|
+
if (keptBytes + candidateBytes > CURSOR_TOOL_BYTES_LIMIT) continue;
|
|
71
|
+
kept.push(candidate.tool);
|
|
72
|
+
keptSet.add(candidate.tool);
|
|
73
|
+
keptBytes += candidateBytes;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
tools: eligible.filter(tool => keptSet.has(tool)),
|
|
78
|
+
omitted: eligible.filter(tool => !keptSet.has(tool)),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function catalogLimitNote(kept: readonly OcxTool[], omitted: readonly OcxTool[]): string | undefined {
|
|
83
|
+
if (omitted.length === 0) return undefined;
|
|
84
|
+
const recoverable = kept.some(tool => tool.toolSearch || cursorToolWireName(tool) === "tool_search");
|
|
85
|
+
const names = omitted.slice(0, 12).map(cursorToolWireName);
|
|
86
|
+
const remainder = omitted.length - names.length;
|
|
87
|
+
const omittedSummary = `${names.join(", ")}${remainder > 0 ? `, and ${remainder} more` : ""}`;
|
|
88
|
+
return recoverable
|
|
89
|
+
? `[opencodex] Cursor's transport limit allows ${kept.length} of ${kept.length + omitted.length} client tools this turn. Omitted: ${omittedSummary}. Use tool_search for a needed omitted tool; tools returned by tool_search are prioritized on the next turn.`
|
|
90
|
+
: `[opencodex] Cursor's transport limit allows ${kept.length} of ${kept.length + omitted.length} client tools this turn. Omitted and unavailable this turn: ${omittedSummary}.`;
|
|
91
|
+
}
|
|
13
92
|
|
|
14
93
|
/**
|
|
15
94
|
* Resolve a `cursor/<model>` selection + Codex reasoning effort to the actual Cursor model id. Cursor
|
|
@@ -80,6 +159,13 @@ export function generatedCursorConversationId(): string {
|
|
|
80
159
|
}
|
|
81
160
|
|
|
82
161
|
export function createCursorRequest(parsed: OcxParsedRequest): CursorRunRequest {
|
|
162
|
+
const messages = parsed.context.messages
|
|
163
|
+
.map(requestMessage)
|
|
164
|
+
.filter((message): message is CursorRequestMessage => !!message && message.content.length > 0);
|
|
165
|
+
const activeText = [...messages].reverse().find(message => message.role === "user" || message.role === "developer")?.content ?? "";
|
|
166
|
+
const visibleTools = cursorToolsForActivePrompt(parsed.context.tools, activeText, parsed.options.toolChoice);
|
|
167
|
+
const budget = applyCursorToolBudget(visibleTools, parsed.options.toolChoice);
|
|
168
|
+
const limitNote = catalogLimitNote(budget.tools, budget.omitted);
|
|
83
169
|
return {
|
|
84
170
|
modelId: normalizeCursorModelId(parsed.modelId, parsed.options.reasoning),
|
|
85
171
|
// The Cursor conversation id comes ONLY from remembered state (_cursorConversationId). Do NOT fall
|
|
@@ -87,12 +173,10 @@ export function createCursorRequest(parsed: OcxParsedRequest): CursorRunRequest
|
|
|
87
173
|
// different namespace and would start an unrelated Cursor conversation, breaking tool-result
|
|
88
174
|
// continuation. If we have no remembered Cursor conversation, start a fresh one.
|
|
89
175
|
conversationId: parsed._cursorConversationId ?? generatedCursorConversationId(),
|
|
90
|
-
system: [...(parsed.context.systemPrompt ?? [])],
|
|
91
|
-
messages
|
|
92
|
-
.map(requestMessage)
|
|
93
|
-
.filter((message): message is CursorRequestMessage => !!message && message.content.length > 0),
|
|
176
|
+
system: [...(parsed.context.systemPrompt ?? []), ...(limitNote ? [limitNote] : [])],
|
|
177
|
+
messages,
|
|
94
178
|
rawMessages: parsed.context.messages,
|
|
95
|
-
...(
|
|
179
|
+
...(budget.tools.length ? { tools: budget.tools } : {}),
|
|
96
180
|
...(parsed.options.toolChoice ? { toolChoice: parsed.options.toolChoice } : {}),
|
|
97
181
|
...(parsed.options.parallelToolCalls !== undefined ? { parallelToolCalls: parsed.options.parallelToolCalls } : {}),
|
|
98
182
|
};
|
|
@@ -2,7 +2,7 @@ import { create, fromJson, toBinary, type JsonValue } from "@bufbuild/protobuf";
|
|
|
2
2
|
import { ValueSchema } from "@bufbuild/protobuf/wkt";
|
|
3
3
|
import type { OcxRequestOptions, OcxTool } from "../../types";
|
|
4
4
|
import { namespacedToolName } from "../../types";
|
|
5
|
-
import { McpToolDefinitionSchema, type McpToolDefinition } from "./gen/agent_pb";
|
|
5
|
+
import { McpToolDefinitionSchema, McpToolsSchema, type McpToolDefinition } from "./gen/agent_pb";
|
|
6
6
|
|
|
7
7
|
export const OCX_RESPONSES_TOOL_PROVIDER = "opencodex-responses";
|
|
8
8
|
export const CODEX_EXEC_COMMAND_TOOL = "exec_command";
|
|
@@ -50,7 +50,7 @@ export function cursorRequestAdvertisesApplyPatch(
|
|
|
50
50
|
tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
|
|
51
51
|
toolChoice?: OcxRequestOptions["toolChoice"],
|
|
52
52
|
): boolean {
|
|
53
|
-
return tools?.some(tool => !tool.namespace && tool.name === CODEX_APPLY_PATCH_TOOL && tool.freeform === true &&
|
|
53
|
+
return tools?.some(tool => !tool.namespace && tool.name === CODEX_APPLY_PATCH_TOOL && tool.freeform === true && cursorToolAllowedByChoice(tool, toolChoice)) ?? false;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function cursorToolWireName(tool: Pick<OcxTool, "namespace" | "name">): string {
|
|
@@ -176,7 +176,7 @@ export function cursorToolsForActivePrompt<T extends Pick<OcxTool, "namespace" |
|
|
|
176
176
|
): readonly T[] | undefined {
|
|
177
177
|
if (!shouldUseNativeExecOnlyForGenericToolUse(tools, activeText)) return tools;
|
|
178
178
|
const execTools = tools?.filter(isBareCodexExecCommandTool);
|
|
179
|
-
if (execTools?.length && !execTools.some(tool =>
|
|
179
|
+
if (execTools?.length && !execTools.some(tool => cursorToolAllowedByChoice(tool, toolChoice))) return tools;
|
|
180
180
|
return execTools && execTools.length > 0 ? execTools : tools;
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -199,7 +199,7 @@ export function appendCursorShellAliasHint(
|
|
|
199
199
|
return `${text}${text.endsWith("\n") ? "\n" : "\n\n"}${CURSOR_SHELL_ALIAS_USER_HINT}`;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
function
|
|
202
|
+
export function cursorToolAllowedByChoice(tool: Pick<OcxTool, "namespace" | "name">, toolChoice: OcxRequestOptions["toolChoice"] | undefined): boolean {
|
|
203
203
|
if (!toolChoice || toolChoice === "auto" || toolChoice === "required") return true;
|
|
204
204
|
if (toolChoice === "none") return false;
|
|
205
205
|
if ("allowedTools" in toolChoice) {
|
|
@@ -232,7 +232,7 @@ export function buildCursorToolGuidanceSystemNote(
|
|
|
232
232
|
if (!tools?.length) return undefined;
|
|
233
233
|
const wireNames = [...new Set(
|
|
234
234
|
tools
|
|
235
|
-
.filter(tool =>
|
|
235
|
+
.filter(tool => cursorToolAllowedByChoice(tool, toolChoice))
|
|
236
236
|
.map(tool => cursorToolWireName(tool)),
|
|
237
237
|
)];
|
|
238
238
|
if (wireNames.length === 0) return undefined;
|
|
@@ -291,7 +291,7 @@ export function buildCursorToolDefinitions(
|
|
|
291
291
|
toolChoice?: OcxRequestOptions["toolChoice"],
|
|
292
292
|
): McpToolDefinition[] {
|
|
293
293
|
if (!tools?.length) return [];
|
|
294
|
-
return tools.filter(tool =>
|
|
294
|
+
return tools.filter(tool => cursorToolAllowedByChoice(tool, toolChoice)).map(tool => {
|
|
295
295
|
const wireName = cursorToolWireName(tool);
|
|
296
296
|
return create(McpToolDefinitionSchema, {
|
|
297
297
|
name: wireName,
|
|
@@ -302,3 +302,20 @@ export function buildCursorToolDefinitions(
|
|
|
302
302
|
});
|
|
303
303
|
});
|
|
304
304
|
}
|
|
305
|
+
|
|
306
|
+
/** Exact byte size of the protobuf field value Cursor receives for client tool registration. */
|
|
307
|
+
export function cursorMcpToolsEncodedSize(
|
|
308
|
+
tools: readonly OcxTool[] | undefined,
|
|
309
|
+
toolChoice?: OcxRequestOptions["toolChoice"],
|
|
310
|
+
): number {
|
|
311
|
+
const definitions = buildCursorToolDefinitions(tools, toolChoice);
|
|
312
|
+
return toBinary(McpToolsSchema, create(McpToolsSchema, { mcpTools: definitions })).byteLength;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Exact additive contribution of one repeated McpToolDefinition entry. */
|
|
316
|
+
export function cursorMcpToolEncodedSize(
|
|
317
|
+
tool: OcxTool,
|
|
318
|
+
toolChoice?: OcxRequestOptions["toolChoice"],
|
|
319
|
+
): number {
|
|
320
|
+
return cursorMcpToolsEncodedSize([tool], toolChoice);
|
|
321
|
+
}
|
package/src/adapters/google.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { neutralizeIdentity } from "./identity";
|
|
|
23
23
|
import { antigravityUsesReplayCache, applyAntigravityReplay, clearAntigravityReplay, observeAntigravityReplay } from "./google-antigravity-replay";
|
|
24
24
|
import { resolveAntigravityWireModelId } from "../providers/antigravity-models";
|
|
25
25
|
import { buildNonOpenAIToolCatalogNudgeForTools } from "./tool-catalog-nudge";
|
|
26
|
+
import { mapReasoningEffort } from "../reasoning-effort";
|
|
26
27
|
|
|
27
28
|
// Google-family models (Gemini/Vertex/Antigravity) tend to emit long running commentary between
|
|
28
29
|
// tool calls. This steers them to keep the BETWEEN-STEP text to one line and reason internally
|
|
@@ -225,6 +226,12 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
225
226
|
if (parsed.options.temperature !== undefined) generationConfig.temperature = parsed.options.temperature;
|
|
226
227
|
if (parsed.options.topP !== undefined) generationConfig.topP = parsed.options.topP;
|
|
227
228
|
if (parsed.options.stopSequences) generationConfig.stopSequences = parsed.options.stopSequences;
|
|
229
|
+
const directFlashThinking = provider.googleMode !== "vertex"
|
|
230
|
+
&& provider.googleMode !== "cloud-code-assist"
|
|
231
|
+
&& (parsed.modelId === "gemini-3.5-flash" || parsed.modelId === "gemini-3.6-flash")
|
|
232
|
+
? mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning)
|
|
233
|
+
: undefined;
|
|
234
|
+
if (directFlashThinking) generationConfig.thinkingConfig = { thinkingLevel: directFlashThinking };
|
|
228
235
|
if (Object.keys(generationConfig).length > 0) body.generationConfig = generationConfig;
|
|
229
236
|
|
|
230
237
|
const method = parsed.stream ? "streamGenerateContent" : "generateContent";
|
package/src/codex/auth-api.ts
CHANGED
|
@@ -763,6 +763,24 @@ export async function handleCodexAuthAPI(
|
|
|
763
763
|
}
|
|
764
764
|
}
|
|
765
765
|
|
|
766
|
+
if (url.pathname === "/api/codex-auth/login/code" && req.method === "POST") {
|
|
767
|
+
const body = (await req.json().catch(() => ({}))) as { flowId?: unknown; input?: unknown };
|
|
768
|
+
const flowId = typeof body.flowId === "string" ? body.flowId.trim() : "";
|
|
769
|
+
const input = typeof body.input === "string" ? body.input : "";
|
|
770
|
+
if (!flowId) return jsonResponse({ error: "flowId required" }, 400);
|
|
771
|
+
if (input.length > 4096) return jsonResponse({ error: "input too long" }, 400);
|
|
772
|
+
|
|
773
|
+
// Import may yield; validate afterwards so cancel/replace cannot race a stale flow through.
|
|
774
|
+
const { submitManualLoginCode } = await import("../oauth");
|
|
775
|
+
const flow = codexAuthLoginState.get(flowId);
|
|
776
|
+
if (!flow) return jsonResponse({ error: "login flow expired or unknown" }, 400);
|
|
777
|
+
if (flow.status !== "pending") return jsonResponse({ error: "login flow is not pending" }, 400);
|
|
778
|
+
|
|
779
|
+
const result = submitManualLoginCode("chatgpt", input);
|
|
780
|
+
if (!result.ok) return jsonResponse({ error: result.error }, 400);
|
|
781
|
+
return jsonResponse({ ok: true }, 202);
|
|
782
|
+
}
|
|
783
|
+
|
|
766
784
|
if (url.pathname === "/api/codex-auth/login/cancel" && req.method === "POST") {
|
|
767
785
|
const body = (await req.json().catch(() => ({}))) as { flowId?: string };
|
|
768
786
|
const { cancelLoginFlow } = await import("../oauth");
|
package/src/codex/catalog.ts
CHANGED
|
@@ -1240,11 +1240,22 @@ function catalogHintsFromModelsApiItem(providerName: string, item: ProviderModel
|
|
|
1240
1240
|
async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs: number, contextCap?: number): Promise<CatalogModel[]> {
|
|
1241
1241
|
if (prov.authMode === "forward") return []; // ChatGPT backend has no /models
|
|
1242
1242
|
const apiKey = await resolveModelsAuthToken(name, prov);
|
|
1243
|
-
const
|
|
1243
|
+
const seedVertexDefault = prov.adapter === "google"
|
|
1244
|
+
&& prov.googleMode === "vertex"
|
|
1245
|
+
&& (prov.models?.length ?? 0) === 0
|
|
1246
|
+
&& Boolean(prov.defaultModel);
|
|
1247
|
+
const configuredIds = seedVertexDefault && prov.defaultModel ? [prov.defaultModel] : (prov.models ?? []);
|
|
1248
|
+
const configured: CatalogModel[] = configuredIds.map(id => ({
|
|
1244
1249
|
id,
|
|
1245
1250
|
provider: name,
|
|
1246
1251
|
...catalogHintsFromProviderConfig(name, prov, id, contextCap),
|
|
1247
1252
|
}));
|
|
1253
|
+
const vertexDefaultSeed = seedVertexDefault ? configured[0] : undefined;
|
|
1254
|
+
const withVertexDefaultSeed = (models: CatalogModel[]): CatalogModel[] => (
|
|
1255
|
+
vertexDefaultSeed && !models.some(model => model.id === vertexDefaultSeed.id)
|
|
1256
|
+
? [...models, vertexDefaultSeed]
|
|
1257
|
+
: models
|
|
1258
|
+
);
|
|
1248
1259
|
if (prov.adapter === "cursor") {
|
|
1249
1260
|
if (prov.liveModels === false || !apiKey) return configured;
|
|
1250
1261
|
// Cursor uses a bespoke GetUsableModels RPC (not /models), returning the full effort-suffixed
|
|
@@ -1266,25 +1277,37 @@ async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs:
|
|
|
1266
1277
|
const staleCursor = getStaleCached(name);
|
|
1267
1278
|
return staleCursor ? applyConfigHintsToCachedModels(name, prov, staleCursor) : configured;
|
|
1268
1279
|
}
|
|
1269
|
-
if (prov.authMode === "oauth" && !apiKey)
|
|
1280
|
+
if (prov.authMode === "oauth" && !apiKey) {
|
|
1281
|
+
// No usable token (logged out, or account marked needsReauth). Still surface the
|
|
1282
|
+
// configured static catalog so the GUI Models tab / rail counts are not empty —
|
|
1283
|
+
// matching Cursor's !apiKey → configured degradation and fetch-failure fallback.
|
|
1284
|
+
return configured;
|
|
1285
|
+
}
|
|
1270
1286
|
if (prov.liveModels === false) {
|
|
1271
1287
|
return configured;
|
|
1272
1288
|
}
|
|
1273
1289
|
const fresh = getFreshCached(name, ttlMs);
|
|
1274
|
-
if (fresh) return applyConfigHintsToCachedModels(name, prov, fresh, contextCap); // dedups Codex's frequent /v1/models polling within the TTL
|
|
1290
|
+
if (fresh) return withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, fresh, contextCap)); // dedups Codex's frequent /v1/models polling within the TTL
|
|
1275
1291
|
if (isModelsFetchCoolingDown(name)) {
|
|
1276
1292
|
// A recently-failed provider (unreachable API, missing proxy, bad key) must not re-pay the
|
|
1277
1293
|
// fetch timeout on every catalog poll — the dashboard polls this path per page load.
|
|
1278
1294
|
const stale = getStaleCached(name);
|
|
1279
|
-
return stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap) : configured;
|
|
1295
|
+
return stale ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap)) : configured;
|
|
1280
1296
|
}
|
|
1281
1297
|
const { url, headers } = buildModelsRequest(prov, apiKey, name);
|
|
1298
|
+
const urlClass = new URL(url).hostname.endsWith("aiplatform.googleapis.com")
|
|
1299
|
+
? "vertex-aiplatform"
|
|
1300
|
+
: "provider-models";
|
|
1282
1301
|
try {
|
|
1283
1302
|
const res = await fetch(url, { headers, signal: AbortSignal.timeout(8000) });
|
|
1284
1303
|
if (!res.ok) {
|
|
1285
1304
|
markModelsFetchFailure(name);
|
|
1286
1305
|
const stale = getStaleCached(name);
|
|
1287
|
-
|
|
1306
|
+
const fallback = stale ? "stale" : "configured";
|
|
1307
|
+
console.warn(
|
|
1308
|
+
`[opencodex] Provider model discovery for "${name}" failed with HTTP ${res.status} [urlClass=${urlClass}, fallback=${fallback}].`,
|
|
1309
|
+
);
|
|
1310
|
+
return stale ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap)) : configured;
|
|
1288
1311
|
}
|
|
1289
1312
|
const json = await res.json() as unknown;
|
|
1290
1313
|
const data = json !== null && typeof json === "object" && !Array.isArray(json)
|
|
@@ -1296,7 +1319,7 @@ async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs:
|
|
|
1296
1319
|
`[opencodex] Provider model discovery for "${name}" returned malformed 2xx data; using stale/static catalog degradation.`,
|
|
1297
1320
|
);
|
|
1298
1321
|
const stale = getStaleCached(name);
|
|
1299
|
-
return stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap) : configured;
|
|
1322
|
+
return stale ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap)) : configured;
|
|
1300
1323
|
}
|
|
1301
1324
|
const items = data;
|
|
1302
1325
|
const live = items.map(m => applyProviderConfigHints(name, prov, {
|
|
@@ -1319,7 +1342,7 @@ async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs:
|
|
|
1319
1342
|
if (dated) {
|
|
1320
1343
|
// Reapply config hints so alias-keyed overrides (modelContextWindows etc.) win.
|
|
1321
1344
|
live.push(applyProviderConfigHints(name, prov, { ...dated, id: m.id }, contextCap));
|
|
1322
|
-
} else if (shouldRetainConfiguredProviderModel(name, m.id)) {
|
|
1345
|
+
} else if (seedVertexDefault || shouldRetainConfiguredProviderModel(name, m.id)) {
|
|
1323
1346
|
live.push(m);
|
|
1324
1347
|
} else {
|
|
1325
1348
|
droppedConfiguredIds.push(m.id);
|
|
@@ -1336,10 +1359,14 @@ async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs:
|
|
|
1336
1359
|
}
|
|
1337
1360
|
setCached(name, live);
|
|
1338
1361
|
return live;
|
|
1339
|
-
} catch {
|
|
1362
|
+
} catch (error) {
|
|
1340
1363
|
markModelsFetchFailure(name);
|
|
1341
1364
|
const stale = getStaleCached(name);
|
|
1342
|
-
|
|
1365
|
+
const fallback = stale ? "stale" : "configured";
|
|
1366
|
+
console.warn(
|
|
1367
|
+
`[opencodex] Provider model discovery for "${name}" threw ${error instanceof Error ? error.name : "unknown"} [urlClass=${urlClass}, fallback=${fallback}].`,
|
|
1368
|
+
);
|
|
1369
|
+
return stale ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap)) : configured;
|
|
1343
1370
|
}
|
|
1344
1371
|
}
|
|
1345
1372
|
|
|
@@ -1436,11 +1463,12 @@ function intersectStrings(values: readonly string[][]): string[] {
|
|
|
1436
1463
|
}
|
|
1437
1464
|
|
|
1438
1465
|
function effectiveComboDefault(
|
|
1439
|
-
configured: string | undefined,
|
|
1466
|
+
configured: string | null | undefined,
|
|
1440
1467
|
common: readonly string[],
|
|
1441
1468
|
): string | undefined {
|
|
1469
|
+
if (!configured) return undefined;
|
|
1442
1470
|
if (configured && common.includes(configured)) return configured;
|
|
1443
|
-
const requestedRank = codexEffortRank(configured
|
|
1471
|
+
const requestedRank = codexEffortRank(configured);
|
|
1444
1472
|
const ranked = common
|
|
1445
1473
|
.map(effort => ({ effort, rank: codexEffortRank(effort) }))
|
|
1446
1474
|
.filter(item => item.rank >= 0)
|