@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.
Files changed (41) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +1 -1
  3. package/README.ru.md +479 -0
  4. package/README.zh-CN.md +1 -1
  5. package/gui/dist/assets/index-BPa0R6EN.js +46 -0
  6. package/gui/dist/assets/index-BY7KvJRB.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/package.json +1 -1
  9. package/src/adapters/cursor/cursor-errors.ts +7 -2
  10. package/src/adapters/cursor/discovery.ts +2 -2
  11. package/src/adapters/cursor/request-builder.ts +90 -6
  12. package/src/adapters/cursor/tool-definitions.ts +23 -6
  13. package/src/adapters/google.ts +7 -0
  14. package/src/codex/auth-api.ts +18 -0
  15. package/src/codex/catalog.ts +39 -11
  16. package/src/codex/routing.ts +85 -4
  17. package/src/combos/index.ts +1 -1
  18. package/src/combos/request.ts +26 -4
  19. package/src/combos/types.ts +4 -4
  20. package/src/lib/errors.ts +4 -0
  21. package/src/lib/upstream-retry.ts +21 -0
  22. package/src/lib/winsw.ts +7 -1
  23. package/src/oauth/anthropic.ts +23 -1
  24. package/src/oauth/index.ts +83 -4
  25. package/src/oauth/local-token-detect.ts +3 -0
  26. package/src/oauth/store.ts +32 -0
  27. package/src/providers/antigravity-models.ts +23 -12
  28. package/src/providers/base-url-choices.ts +18 -0
  29. package/src/providers/registry.ts +122 -7
  30. package/src/responses/parser.ts +11 -6
  31. package/src/router.ts +6 -1
  32. package/src/server/index.ts +3 -3
  33. package/src/server/relay.ts +31 -5
  34. package/src/server/request-log.ts +12 -0
  35. package/src/server/responses.ts +111 -27
  36. package/src/service.ts +12 -3
  37. package/src/storage/scanner.ts +18 -6
  38. package/src/types.ts +4 -2
  39. package/src/usage/expected-prices.ts +12 -9
  40. package/gui/dist/assets/index-CMKZnkG9.js +0 -40
  41. 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)}
@@ -16,8 +16,8 @@
16
16
  } catch (e) {}
17
17
  })();
18
18
  </script>
19
- <script type="module" crossorigin src="/assets/index-CMKZnkG9.js"></script>
20
- <link rel="stylesheet" crossorigin href="/assets/index-DyBPh28A.css">
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitkyc08/opencodex",
3
- "version": "2.7.29",
3
+ "version": "2.7.31",
4
4
  "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code",
5
5
  "type": "module",
6
6
  "main": "./bin/package-main.mjs",
@@ -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) ?? [...CURSOR_REASONING_EFFORTS]
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: parsed.context.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
- ...(parsed.context.tools?.length ? { tools: parsed.context.tools } : {}),
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 && toolChoiceAllows(tool, toolChoice)) ?? false;
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 => toolChoiceAllows(tool, toolChoice))) return tools;
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 toolChoiceAllows(tool: Pick<OcxTool, "namespace" | "name">, toolChoice: OcxRequestOptions["toolChoice"] | undefined): boolean {
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 => toolChoiceAllows(tool, toolChoice))
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 => toolChoiceAllows(tool, toolChoice)).map(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
+ }
@@ -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";
@@ -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");
@@ -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 configured: CatalogModel[] = (prov.models ?? []).map(id => ({
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) return []; // not logged in → skip
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
- return stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap) : configured;
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
- return stale ? applyConfigHintsToCachedModels(name, prov, stale, contextCap) : configured;
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 ?? "medium");
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)