dsh-codex-subscription 3.0.0-beta.7 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -1075,6 +1075,7 @@ window.__ModuleLoader__.load({
1075
1075
  "account/select",
1076
1076
  "account/remove",
1077
1077
  "usage",
1078
+ "usage/accounts",
1078
1079
  "usage/history",
1079
1080
  "usage/profile",
1080
1081
  "diagnostics",
@@ -1325,10 +1326,6 @@ window.__ModuleLoader__.load({
1325
1326
  className: "codexImageToolTitle",
1326
1327
  children: t("imageGenerate")
1327
1328
  }),
1328
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1329
- className: "codexImageBeta",
1330
- children: t("imageBeta")
1331
- }),
1332
1329
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1333
1330
  className: "codexImageToolState",
1334
1331
  children: status
@@ -5477,6 +5474,8 @@ window.__ModuleLoader__.load({
5477
5474
  const IconChevronDownOutline14 = _deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular;
5478
5475
  const IconChevronRightOutline14 = _deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular;
5479
5476
  const Menu = _deepseek_ai_dsh_client_ui_primitives.Menu;
5477
+ const MenuSurface = _deepseek_ai_dsh_client_ui_primitives.MenuSurface;
5478
+ const MenuGroup = _deepseek_ai_dsh_client_ui_primitives.MenuGroup;
5480
5479
  const Tooltip = _deepseek_ai_dsh_client_ui_primitives.Tooltip;
5481
5480
  const IconChevronLeftOutline14 = _deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutlineRegular;
5482
5481
  const IconCloseOutline16 = _deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular;
@@ -5681,10 +5680,17 @@ window.__ModuleLoader__.load({
5681
5680
  inputImageDetail_high: "高",
5682
5681
  inputImageDetail_original: "原图",
5683
5682
  connectors: "ChatGPT 连接器",
5684
- connectorsHint: "让 DSH 里的任何模型使用你在 ChatGPT 网页里已连接的应用(GitHub、Gmail、Google 云端硬盘、日历等)。只读:模型只能读取;允许写入:发邮件、改文件等写操作每次都要你批准。应用返回的内容来自第三方,模型不会照其中的指令行事。需先在 ChatGPT 里连接应用。",
5683
+ connectorsHint: "让 DSH 里的任何模型使用你在 ChatGPT 里已连接的应用(GitHub、Gmail、云端硬盘、日历等)。需先在 ChatGPT 里连接应用;应用返回的内容来自第三方,模型不会照其中的指令行事。",
5684
+ connectorsMode_off: "连接器关闭,模型看不到这些应用。",
5685
+ connectorsMode_read: "模型只能读取(搜邮件、读文件、查 PR),不会修改任何数据。",
5686
+ connectorsMode_ask: "发邮件、改文件等写操作每次都会弹出确认,你批准后才执行。",
5687
+ connectorsMode_write: "写操作直接执行,不再弹出确认,误操作无法撤回,请谨慎使用。",
5688
+ hintMore: "展开",
5689
+ hintLess: "收起",
5685
5690
  connectors_off: "关闭",
5686
5691
  connectors_read: "只读",
5687
- connectors_ask: "允许写入(每次审批)",
5692
+ connectors_ask: "询问后写入",
5693
+ connectors_write: "直接写入",
5688
5694
  reasoningSummary: "推理摘要",
5689
5695
  reasoningSummaryHint: "让模型在会话的“思考”部分给出推理摘要。自动由模型决定;简洁更短;详细更完整;关闭则不要摘要。",
5690
5696
  retryPolicy: "请求重试",
@@ -5708,6 +5714,7 @@ window.__ModuleLoader__.load({
5708
5714
  remoteHint: "实验功能,默认关闭。开启后,这台电脑上的 DSH 会出现在 ChatGPT 手机 App 的 Codex 主机列表里,可用手机查看对话、发消息、切换模型和审批。需要订阅账号登录;电脑要保持开机和联网。",
5709
5715
  remoteConnected: "已连接",
5710
5716
  remoteConnecting: "正在连接",
5717
+ remoteWaiting: "正在等待上一次连接释放,通常几分钟内自动连上",
5711
5718
  remoteError: "连接失败,会自动重试",
5712
5719
  remoteStopped: "已停止",
5713
5720
  remotePaired: "已配对的手机",
@@ -6108,7 +6115,13 @@ window.__ModuleLoader__.load({
6108
6115
  resetNoCredit: "没有可用的额度重置。",
6109
6116
  resetAlready: "这次重置请求已处理。",
6110
6117
  resetFailed: "无法使用额度重置。",
6118
+ accountQuotaLeft: "{label}剩余 {value}%",
6119
+ accountQuotaResets: "{value} 重置",
6120
+ accountQuotaLoading: "正在读取额度…",
6121
+ accountQuotaError: "暂时读不到这个账号的额度",
6122
+ accountQuotaNone: "没有额度窗口信息",
6111
6123
  resetRenewLogin: "登录状态已失效,请重新登录。",
6124
+ resetBlocked: "ChatGPT 的网络防护拦截了这次请求(HTTP 403),登录状态没有问题。请稍后再试,或检查网络、代理或 VPN。",
6112
6125
  resetExpired: "本次确认已失效,请重新开始。",
6113
6126
  resetInProgress: "额度重置正在处理中。",
6114
6127
  resetTooEarly: "请等待冷静期结束后再确认。",
@@ -6207,7 +6220,6 @@ window.__ModuleLoader__.load({
6207
6220
  modelFailed: "模型目录加载失败:{value}",
6208
6221
  groupFailed: "{name}:{value}",
6209
6222
  imageGenerate: "生成图片",
6210
- imageBeta: "Beta",
6211
6223
  imageGenerating: "正在生成…",
6212
6224
  imageGenerated: "已生成",
6213
6225
  imageFailed: "生成失败",
@@ -6354,10 +6366,17 @@ window.__ModuleLoader__.load({
6354
6366
  inputImageDetail_high: "High",
6355
6367
  inputImageDetail_original: "Original",
6356
6368
  connectors: "ChatGPT connectors",
6357
- connectorsHint: "Lets any model in DSH use the apps you have connected in ChatGPT (GitHub, Gmail, Google Drive, Calendar and more). Read-only: models can only read. Allow writes: anything that changes data, such as sending mail or editing files, asks for your approval every time. What apps return is third-party content and models do not follow instructions inside it. Connect the apps in ChatGPT first.",
6369
+ connectorsHint: "Lets any model in DSH use the apps you have connected in ChatGPT (GitHub, Gmail, Drive, Calendar and more). Connect the apps in ChatGPT first; what apps return is third-party content and models do not follow instructions inside it.",
6370
+ connectorsMode_off: "Connectors are off; models cannot see these apps.",
6371
+ connectorsMode_read: "Models can only read (search mail, read files, look up pull requests) and never change data.",
6372
+ connectorsMode_ask: "Anything that changes data, such as sending mail or editing files, asks for your approval every time.",
6373
+ connectorsMode_write: "Changing actions run immediately without a prompt and cannot be undone, so use this carefully.",
6374
+ hintMore: "More",
6375
+ hintLess: "Less",
6358
6376
  connectors_off: "Off",
6359
6377
  connectors_read: "Read-only",
6360
- connectors_ask: "Allow writes (ask each time)",
6378
+ connectors_ask: "Write after asking",
6379
+ connectors_write: "Write directly",
6361
6380
  reasoningSummary: "Reasoning summary",
6362
6381
  reasoningSummaryHint: "Shows a summary of the reasoning in the Thinking section of the conversation. Auto lets the model decide; concise is shorter; detailed is fuller; off asks for none.",
6363
6382
  retryPolicy: "Request retries",
@@ -6381,6 +6400,7 @@ window.__ModuleLoader__.load({
6381
6400
  remoteHint: "Experimental, off by default. When on, this computer's DSH appears as a host in the ChatGPT mobile app's Codex list, so you can follow conversations, send messages, switch models and approve actions from your phone. Needs a signed-in subscription account; the computer must stay on and online.",
6382
6401
  remoteConnected: "Connected",
6383
6402
  remoteConnecting: "Connecting",
6403
+ remoteWaiting: "Waiting for the previous connection to be released; usually reconnects within a few minutes",
6384
6404
  remoteError: "Connection failed, retrying",
6385
6405
  remoteStopped: "Stopped",
6386
6406
  remotePaired: "Paired phones",
@@ -6395,7 +6415,7 @@ window.__ModuleLoader__.load({
6395
6415
  remotePairSteps: "Scan this in the ChatGPT app's Codex section, or type the manual code.",
6396
6416
  remoteManualCode: "Manual pairing code",
6397
6417
  remoteQrLabel: "Pairing QR code",
6398
- remoteExpires: "Valid for about {minutes} minute(s)",
6418
+ remoteExpires: "Expires in about {minutes} min",
6399
6419
  remoteExpired: "The pairing code expired. Create a new one.",
6400
6420
  remoteLimits: "From the phone you can follow and continue DSH conversations, start new ones, send photos, switch models, choose permissions, approve actions and view changes. The phone cannot run other commands on the computer.",
6401
6421
  reviewModelTitle: "Auto review model",
@@ -6781,7 +6801,13 @@ window.__ModuleLoader__.load({
6781
6801
  resetNoCredit: "No quota reset is available.",
6782
6802
  resetAlready: "This reset request was already processed.",
6783
6803
  resetFailed: "Could not use the quota reset.",
6804
+ accountQuotaLeft: "{label} {value}% left",
6805
+ accountQuotaResets: "resets {value}",
6806
+ accountQuotaLoading: "Reading quota…",
6807
+ accountQuotaError: "The quota of this account could not be read right now",
6808
+ accountQuotaNone: "No quota window reported",
6784
6809
  resetRenewLogin: "Your sign-in expired. Sign in again.",
6810
+ resetBlocked: "ChatGPT network protection blocked this request (HTTP 403). Your sign-in is fine; try again later or check your network, proxy or VPN.",
6785
6811
  resetExpired: "This confirmation expired. Start again.",
6786
6812
  resetInProgress: "A quota reset is already in progress.",
6787
6813
  resetTooEarly: "Wait for the cooldown before confirming.",
@@ -6880,7 +6906,6 @@ window.__ModuleLoader__.load({
6880
6906
  modelFailed: "Could not load models: {value}",
6881
6907
  groupFailed: "{name}: {value}",
6882
6908
  imageGenerate: "Generate image",
6883
- imageBeta: "Beta",
6884
6909
  imageGenerating: "Generating…",
6885
6910
  imageGenerated: "Generated",
6886
6911
  imageFailed: "Generation failed",
@@ -6949,11 +6974,26 @@ window.__ModuleLoader__.load({
6949
6974
  .codexSubscriptionCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);padding:14px 16px;display:flex;flex-direction:column;gap:12px}
6950
6975
  .codexSubscriptionUsageCard{padding:12px 14px;gap:9px}
6951
6976
  .codexSubscriptionPreferencesCard{padding:12px 14px;gap:10px}
6952
- .codexSubscriptionPreference{min-height:32px;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}
6977
+ .codexSubscriptionPreference{min-height:32px;box-sizing:border-box;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}
6953
6978
  .codexSubscriptionPreferenceCopy{display:flex;min-width:0;flex-direction:column;gap:2px}
6954
6979
  .codexSubscriptionPreferenceLabel{display:flex;align-items:center;gap:6px}
6955
- .codexSubscriptionPreferenceHint{max-width:300px;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
6956
- .codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}
6980
+ .codexSubscriptionPreference>.codexSubscriptionPreferenceCopy{flex:1 1 240px}
6981
+ .codexSubscriptionPreferenceHint{max-width:none;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
6982
+ .codexSubscriptionHintText{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
6983
+ .codexSubscriptionHintFold[data-open=true] .codexSubscriptionHintText{display:block;-webkit-line-clamp:unset}
6984
+ .codexSubscriptionHintToggle{display:inline-flex;align-items:center;gap:3px;margin-top:2px;padding:0;border:0;background:none;font:inherit;font-size:11px;line-height:17px;color:var(--dsw-alias-label-secondary);cursor:pointer}
6985
+ .codexSubscriptionHintToggle::after{content:"";width:5px;height:5px;margin-top:-2px;border:solid currentColor;border-width:0 1.5px 1.5px 0;transform:rotate(45deg);transition:transform .15s}
6986
+ .codexSubscriptionHintFold[data-open=true] .codexSubscriptionHintToggle::after{margin-top:2px;transform:rotate(-135deg)}
6987
+ .codexSubscriptionHintToggle:hover{color:var(--dsw-alias-label-primary)}
6988
+ .codexSubscriptionHintToggle:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px;border-radius:3px}
6989
+ .codexSubscriptionPreferenceStack{margin-top:6px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l2)}
6990
+ .codexSubscriptionPreferenceStack>.codexSubscriptionQuotaModes{flex:1 1 100%;margin-left:0;display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}
6991
+ .codexSubscriptionPreferenceStack .codexSubscriptionQuotaMode{min-height:30px;padding:4px 8px;text-align:center;white-space:normal;line-height:16px}
6992
+ .codexSubscriptionPreferenceLabel small{padding:0 6px;border-radius:999px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);font-size:10px;font-weight:500;line-height:16px}
6993
+ @container (max-width:560px){.codexSubscriptionPreferenceStack>.codexSubscriptionQuotaModes{grid-auto-flow:row;grid-template-columns:repeat(2,minmax(0,1fr))}}
6994
+ .codexSubscriptionModeNote{flex:1 1 100%;padding:7px 10px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}
6995
+ .codexSubscriptionModeNote[data-danger=true]{background:color-mix(in srgb,var(--dsw-alias-label-danger,#d92d20) 12%,transparent);color:var(--dsw-alias-label-danger,#d92d20)}
6996
+ .codexSubscriptionQuotaModes{display:flex;flex-wrap:wrap;max-width:100%;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}
6957
6997
  .codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer;white-space:nowrap}
6958
6998
  .codexSubscriptionQuotaMode small{margin-left:3px;font-size:9px;line-height:1;color:var(--dsw-alias-label-tertiary)}
6959
6999
  .codexSubscriptionQuotaMode:has(input:checked){background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 0 0 1px var(--dsw-alias-border-l3)}
@@ -6987,6 +7027,9 @@ window.__ModuleLoader__.load({
6987
7027
  .codexSubscriptionAccounts{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}
6988
7028
  .codexSubscriptionAccount{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}
6989
7029
  .codexSubscriptionAccount:last-child{border-bottom:0}
7030
+ .codexSubscriptionAccountMain{display:flex;flex-direction:column;gap:2px;padding:6px 0;min-width:0}
7031
+ .codexSubscriptionAccountQuota{display:flex;flex-wrap:wrap;gap:2px 12px;font-size:12px;color:var(--dsw-alias-text-l2)}
7032
+ .codexSubscriptionAccountQuota[data-state=error]{color:var(--dsw-alias-text-danger,#c0392b)}
6990
7033
  .codexSubscriptionAccount[data-active=true] .codexSubscriptionEmail,.codexSubscriptionAccount[data-active=true]>span{font-weight:600}
6991
7034
  .codexSubscriptionEmail{max-width:100%;overflow:hidden;padding:2px 4px;border:0;border-radius:5px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}
6992
7035
  .codexSubscriptionEmail:hover{background:var(--dsw-alias-interactive-bg-hover)}
@@ -7129,7 +7172,7 @@ window.__ModuleLoader__.load({
7129
7172
  .codexComposerQuotaBar::-webkit-progress-value{background:var(--dsw-alias-label-secondary);border-radius:999px}
7130
7173
  .codexComposerQuotaBar::-moz-progress-bar{background:var(--dsw-alias-label-secondary);border-radius:999px}
7131
7174
  .codexModelSelect{position:relative;min-width:0}
7132
- .codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}
7175
+ .codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:var(--dsw-radius-sm);outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}
7133
7176
  .codexModelSelectTrigger:hover:not(:disabled),.codexModelSelectTrigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}
7134
7177
  .codexModelSelectTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
7135
7178
  .codexModelSelectTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}
@@ -7138,34 +7181,32 @@ window.__ModuleLoader__.load({
7138
7181
  .codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}
7139
7182
  .codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}
7140
7183
  .codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
7141
- .codexModelSelectMenu,.codexModelSelectSubmenu{position:absolute;z-index:30;box-sizing:border-box;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:min(420px,calc(100vw - 32px));max-height:min(360px,calc(100vh - 96px));padding:4px;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#2c2c2e);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);overflow:hidden}
7142
- .codexModelSelectMenu{right:0;bottom:calc(100% + 8px)}
7143
- .codexModelSelectSubmenu{right:calc(100% + 8px);bottom:0;min-width:min(230px,calc(100vw - 32px))}
7144
- /* Keep search outside the scroll viewport; let the model list fit the bounded menu. */
7145
- .codexModelSelectModelMenu{display:flex;flex-direction:column}
7146
- .codexModelSelectCell{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;height:40px;box-sizing:border-box;padding:0 10px;border:0;border-radius:10px;background:transparent;color:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}
7147
- .codexModelSelectCell:hover,.codexModelSelectCell:focus-visible,.codexModelSelectCell[data-open=true]{background:var(--dsw-alias-interactive-bg-hover);outline:0}
7148
- .codexModelSelectCell:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}
7184
+ /* The menu follows DSH's own model picker: one floating surface above the trigger, rows drill into the same surface. */
7185
+ .codexModelSelectMenu{z-index:1100;--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-sizing:border-box;position:fixed;display:flex;flex-direction:column;width:max-content;min-width:min(240px,100vw - 32px);max-width:min(420px,100vw - 32px);max-height:min(360px,100vh - 96px);padding:4px;border:0;box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);overflow:hidden}
7186
+ .codexModelSelectCell{box-sizing:border-box;display:flex;align-items:center;gap:6px;width:auto;min-width:100%;height:34px;padding:0 8px;border:none;border-radius:var(--dsw-radius-md);outline:none;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-align:left;cursor:pointer}
7187
+ .codexModelSelectCell:hover,.codexModelSelectCell:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}
7149
7188
  .codexModelSelectCellLabel{flex:none;white-space:nowrap}
7150
7189
  .codexModelSelectCellValue{flex:auto;min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary);text-align:right;text-overflow:ellipsis;white-space:nowrap}
7151
- .codexModelSelectCellChevron{flex:none;color:var(--dsw-alias-label-tertiary)}
7152
- .codexModelSelectSearch{display:block;flex-shrink:0;width:100%;box-sizing:border-box;height:32px;margin:0 0 4px;padding:0 10px;border:1px solid var(--dsw-alias-border-l3);border-radius:8px;outline:0;background:transparent;color:inherit;font:inherit;font-size:13px}
7153
- .codexModelSelectSearch:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
7190
+ .codexModelSelectCellChevron{flex:none;width:12px;height:12px;color:var(--dsw-alias-menu-icon)}
7191
+ .codexModelSelectSearchRow{flex-shrink:0;position:relative;margin:2px 0 3px}
7192
+ .codexModelSelectSearchRow .codexModelSelectSearch{display:flex;height:auto;padding:5px 7px;border:0 solid transparent;border-radius:var(--dsw-radius-md);background:transparent}
7193
+ .codexModelSelectSearchRow .codexModelSelectSearch:focus-within{border-color:transparent}
7194
+ .codexModelSelectSearchRow .codexModelSelectSearch input{padding:0;font-size:12px;line-height:normal}
7195
+ .codexModelSelectSearchRow .codexModelSelectSearch input::placeholder{color:var(--dsw-alias-label-caption)}
7154
7196
  .codexModelSelectGroups{flex:1 1 auto;min-height:0;overflow-y:auto}
7155
- .codexModelSelectGroup+.codexModelSelectGroup{margin-top:4px}
7156
- .codexModelSelectGroupTitle{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-alias-bg-layer-2,#2c2c2e);color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}
7157
- .codexModelSelectOption{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;min-height:38px;box-sizing:border-box;padding:6px 8px;border:0;border-radius:10px;outline:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
7197
+ .codexModelSelectGroupTitle{padding:5px 8px 3px;color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}
7198
+ .codexModelSelectOption{box-sizing:border-box;display:flex;align-items:center;gap:6px;width:auto;min-width:100%;min-height:34px;padding:5px 7px;border:none;border-radius:var(--dsw-radius-md);outline:none;background:transparent;color:inherit;text-align:left;cursor:pointer}
7158
7199
  .codexModelSelectOption:hover:not(:disabled),.codexModelSelectOption:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}
7159
7200
  .codexModelSelectOption:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}
7160
- .codexModelSelectOptionCopy{display:flex;flex:1;min-width:0;flex-direction:column}
7161
- .codexModelSelectOptionName{overflow:hidden;color:inherit;font-size:14px;font-weight:500;line-height:20px;text-overflow:ellipsis;white-space:nowrap}
7162
- .codexModelSelectOptionDescription{overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}
7163
- .codexModelSelectCheck{display:grid;place-items:center;flex:0 0 18px;color:var(--dsw-alias-label-primary)}
7164
- .codexModelSelectStatus,.codexModelSelectEmpty{padding:10px;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}
7165
- .codexModelSelectError,.codexModelSelectWarning{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:4px;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
7201
+ .codexModelSelectOptionCopy{display:flex;flex:1;flex-direction:column;min-width:0}
7202
+ .codexModelSelectOptionName{overflow:hidden;color:inherit;font-size:13px;font-weight:400;line-height:18px;text-overflow:ellipsis;white-space:nowrap}
7203
+ .codexModelSelectOptionDescription{overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px;text-overflow:ellipsis;white-space:nowrap}
7204
+ .codexModelSelectCheck{display:grid;place-items:center;flex:0 0 14px;color:var(--dsw-alias-label-primary)}
7205
+ .codexModelSelectCheck svg{width:14px;height:14px}
7206
+ .codexModelSelectStatus,.codexModelSelectEmpty{padding:8px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
7207
+ .codexModelSelectError,.codexModelSelectWarning{display:flex;align-items:flex-start;justify-content:space-between;gap:6px;margin-bottom:3px;padding:6px 7px;border-radius:var(--dsw-radius-md);background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px}
7166
7208
  .codexModelSelectWarning{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label)}
7167
- .codexModelSelectRetry{flex:none;padding:0;border:0;background:transparent;color:inherit;font:inherit;font-weight:600;cursor:pointer}
7168
- .codexModelSelectMenu{overflow:visible}
7209
+ .codexModelSelectRetry{flex:none;padding:0;border:none;background:transparent;color:inherit;font:inherit;font-weight:600;cursor:pointer}
7169
7210
  .codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}
7170
7211
  .codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}
7171
7212
  .codexImageToolIcon{display:block;flex-shrink:0;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}
@@ -7180,7 +7221,6 @@ window.__ModuleLoader__.load({
7180
7221
  .codexGeneratedImageFrame img{display:block;width:100%;height:100%;object-fit:cover}
7181
7222
  .codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}
7182
7223
  @keyframes codexImageSpin{to{transform:rotate(360deg)}}
7183
- .codexImageBeta{padding:0 5px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px}
7184
7224
  .codexImageToolGallery{display:flex;align-items:flex-start;flex-direction:column;gap:8px}
7185
7225
  @container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
7186
7226
  @container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}
@@ -8594,7 +8634,8 @@ window.__ModuleLoader__.load({
8594
8634
  const CONNECTOR_MODES = Object.freeze([
8595
8635
  "off",
8596
8636
  "read",
8597
- "ask"
8637
+ "ask",
8638
+ "write"
8598
8639
  ]);
8599
8640
  const INPUT_IMAGE_DETAIL_FIELD = "inputImageDetail";
8600
8641
  const INPUT_IMAGE_DETAILS = Object.freeze([
@@ -9205,7 +9246,9 @@ window.__ModuleLoader__.load({
9205
9246
  return `${local[0]}•••${local.at(-1)}@${domain}`;
9206
9247
  };
9207
9248
  const hours$1 = (seconds) => Math.round(seconds / 3600 * 10) / 10;
9208
- const percent = (value) => Number(value).toLocaleString(void 0, { maximumFractionDigits: 1 });
9249
+ /** The language DSH shows its interface in, so dates and numbers match the text around them rather than the OS. */
9250
+ const uiLocale = () => typeof document === "undefined" ? void 0 : document.documentElement.lang || void 0;
9251
+ const percent = (value) => Number(value).toLocaleString(uiLocale(), { maximumFractionDigits: 1 });
9209
9252
  const isApproximateWindow = (seconds, expected) => seconds >= expected * .95 && seconds <= expected * 1.05;
9210
9253
  const windowLabel = (seconds, t) => {
9211
9254
  if (isApproximateWindow(seconds, 18e3)) return t("windowFiveHours");
@@ -9282,7 +9325,7 @@ window.__ModuleLoader__.load({
9282
9325
  }
9283
9326
  //#endregion
9284
9327
  //#region src/version.js
9285
- const PACKAGE_VERSION = "3.0.0-beta.7";
9328
+ const PACKAGE_VERSION = "3.0.0";
9286
9329
  //#endregion
9287
9330
  //#region src/client-recovery.js
9288
9331
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -9510,7 +9553,7 @@ window.__ModuleLoader__.load({
9510
9553
  }
9511
9554
  function shortReset(quota, t) {
9512
9555
  if (!Number.isSafeInteger(quota.resetsAt)) return t("resetUnknown");
9513
- const value = (/* @__PURE__ */ new Date(quota.resetsAt * 1e3)).toLocaleString(void 0, {
9556
+ const value = (/* @__PURE__ */ new Date(quota.resetsAt * 1e3)).toLocaleString(uiLocale(), {
9514
9557
  month: "numeric",
9515
9558
  day: "numeric",
9516
9559
  hour: "2-digit",
@@ -9553,6 +9596,11 @@ window.__ModuleLoader__.load({
9553
9596
  const ForwardRef = /*#__PURE__*/ react.forwardRef(BoltIcon);
9554
9597
  //#endregion
9555
9598
  //#region src/client-model-select.jsx
9599
+ const MEASURE_STYLE = {
9600
+ visibility: "hidden",
9601
+ left: 0,
9602
+ top: 0
9603
+ };
9556
9604
  function CodexModelSelect({ locked, available, directory, load, select, preference, t }) {
9557
9605
  const state = (0, react.useSyncExternalStore)(directory.subscribe, directory.getSnapshot);
9558
9606
  const preferenceSnapshot = usePreferenceSnapshot(preference);
@@ -9560,6 +9608,8 @@ window.__ModuleLoader__.load({
9560
9608
  const [pane, setPane] = (0, react.useState)("root");
9561
9609
  const [query, setQuery] = (0, react.useState)("");
9562
9610
  const rootRef = (0, react.useRef)(null);
9611
+ const menuRef = (0, react.useRef)(null);
9612
+ const [menuPos, setMenuPos] = (0, react.useState)(null);
9563
9613
  const triggerRef = (0, react.useRef)(null);
9564
9614
  const id = (0, react.useId)();
9565
9615
  const choices = (0, react.useMemo)(() => state.groups.flatMap((group) => group.models.map((model) => ({
@@ -9643,7 +9693,7 @@ window.__ModuleLoader__.load({
9643
9693
  (0, react.useEffect)(() => {
9644
9694
  if (!open) return void 0;
9645
9695
  const closeOutside = (event) => {
9646
- if (!rootRef.current?.contains(event.target)) {
9696
+ if (!rootRef.current?.contains(event.target) && !menuRef.current?.contains(event.target)) {
9647
9697
  setOpen(false);
9648
9698
  setPane("root");
9649
9699
  setQuery("");
@@ -9652,6 +9702,39 @@ window.__ModuleLoader__.load({
9652
9702
  document.addEventListener("mousedown", closeOutside);
9653
9703
  return () => document.removeEventListener("mousedown", closeOutside);
9654
9704
  }, [open]);
9705
+ (0, react.useLayoutEffect)(() => {
9706
+ if (!open) {
9707
+ setMenuPos(null);
9708
+ return;
9709
+ }
9710
+ const place = () => {
9711
+ const rect = triggerRef.current?.getBoundingClientRect();
9712
+ if (rect === void 0) return;
9713
+ const margin = 12;
9714
+ const width = menuRef.current?.offsetWidth ?? 0;
9715
+ const height = menuRef.current?.offsetHeight ?? 0;
9716
+ let left = rect.right - width;
9717
+ let top = rect.top - 8 - height;
9718
+ if (width > 0) left = Math.min(Math.max(left, margin), window.innerWidth - width - margin);
9719
+ if (height > 0) top = Math.min(Math.max(top, margin), window.innerHeight - height - margin);
9720
+ setMenuPos({
9721
+ left,
9722
+ top
9723
+ });
9724
+ };
9725
+ place();
9726
+ window.addEventListener("scroll", place, true);
9727
+ window.addEventListener("resize", place);
9728
+ return () => {
9729
+ window.removeEventListener("scroll", place, true);
9730
+ window.removeEventListener("resize", place);
9731
+ };
9732
+ }, [
9733
+ open,
9734
+ pane,
9735
+ state,
9736
+ query
9737
+ ]);
9655
9738
  (0, react.useEffect)(() => {
9656
9739
  if (pane !== "model") setQuery("");
9657
9740
  }, [pane]);
@@ -9725,10 +9808,10 @@ window.__ModuleLoader__.load({
9725
9808
  type: "button",
9726
9809
  role: "menuitem",
9727
9810
  className: "codexModelSelectCell",
9728
- "data-open": pane === target,
9729
- "aria-haspopup": "menu",
9730
- "aria-expanded": pane === target,
9731
- onClick: () => setPane((current) => current === target ? "root" : target),
9811
+ onClick: () => {
9812
+ setQuery("");
9813
+ setPane(target);
9814
+ },
9732
9815
  children: [
9733
9816
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9734
9817
  className: "codexModelSelectCellLabel",
@@ -9741,141 +9824,147 @@ window.__ModuleLoader__.load({
9741
9824
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronRightOutline14, { className: "codexModelSelectCellChevron" })
9742
9825
  ]
9743
9826
  });
9744
- let submenu = null;
9745
- if (pane === "model") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9746
- className: "codexModelSelectSubmenu codexModelSelectModelMenu",
9747
- role: "menu",
9748
- "aria-label": t("modelLabel"),
9749
- children: [
9750
- state.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9751
- className: "codexModelSelectStatus",
9752
- children: t("modelsLoading")
9753
- }) : null,
9754
- state.error === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9755
- className: "codexModelSelectError",
9756
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("modelFailed"), { value: state.error }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9757
- className: "codexModelSelectRetry",
9758
- type: "button",
9759
- onClick: load,
9760
- children: t("modelRetry")
9761
- })]
9762
- }),
9763
- state.failures.map((failure) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9764
- className: "codexModelSelectWarning",
9765
- children: fill(t("groupFailed"), {
9766
- name: failure.name,
9767
- value: failure.message
9768
- })
9769
- }, failure.id)),
9770
- searchable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
9827
+ const group = (key, label, children) => MenuGroup === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9828
+ role: "group",
9829
+ "aria-label": label,
9830
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9831
+ className: "codexModelSelectGroupTitle",
9832
+ children: label
9833
+ }), children]
9834
+ }, key) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuGroup, {
9835
+ label,
9836
+ children
9837
+ }, key);
9838
+ let content = null;
9839
+ if (pane === "root") content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9840
+ cell("model", t("modelLabel"), modelLabel),
9841
+ reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
9842
+ (speedSupported || ultrafastSupported) && cell("speed", t("speedTitle"), t(speedKey)),
9843
+ verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel)
9844
+ ] });
9845
+ else if (pane === "model") content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9846
+ searchable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9847
+ className: "codexModelSelectSearchRow",
9848
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
9771
9849
  className: "codexModelSelectSearch",
9772
- type: "search",
9850
+ type: "text",
9851
+ role: "searchbox",
9773
9852
  value: query,
9774
9853
  autoFocus: true,
9775
9854
  placeholder: t("modelSearch"),
9776
9855
  "aria-label": t("modelSearch"),
9777
9856
  onChange: (event) => setQuery(event.target.value)
9778
- }) : null,
9779
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9780
- className: "codexModelSelectGroups scrollable",
9781
- children: shownGroups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9782
- className: "codexModelSelectGroup",
9783
- role: "group",
9784
- "aria-labelledby": `${id}-${group.id}`,
9785
- children: [
9786
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9787
- className: "codexModelSelectGroupTitle",
9788
- id: `${id}-${group.id}`,
9789
- children: group.name
9790
- }),
9791
- group.allHidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9792
- className: "codexModelSelectEmpty",
9793
- children: t("modelsHidden")
9794
- }) : null,
9795
- group.models.map((model) => option({
9796
- key: model.id,
9797
- label: model.name,
9798
- description: model.description,
9799
- selected: state.current?.provider === group.id && state.current.model === model.id,
9800
- disabled: busy,
9801
- onClick: () => chooseModel({
9802
- provider: group.id,
9803
- model: model.id
9804
- })
9805
- }))
9806
- ]
9807
- }, group.id))
9808
- }),
9809
- state.status === "ready" && visibleGroups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9810
- className: "codexModelSelectEmpty",
9811
- children: t(choices.length === 0 ? "modelsEmpty" : "modelsHidden")
9812
- }) : null,
9813
- state.status === "ready" && visibleGroups.length > 0 && shownGroups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9857
+ })
9858
+ }) : null,
9859
+ state.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9860
+ className: "codexModelSelectStatus",
9861
+ children: t("modelsLoading")
9862
+ }) : null,
9863
+ state.error === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9864
+ className: "codexModelSelectError",
9865
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("modelFailed"), { value: state.error }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9866
+ className: "codexModelSelectRetry",
9867
+ type: "button",
9868
+ onClick: load,
9869
+ children: t("modelRetry")
9870
+ })]
9871
+ }),
9872
+ state.failures.map((failure) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9873
+ className: "codexModelSelectWarning",
9874
+ children: fill(t("groupFailed"), {
9875
+ name: failure.name,
9876
+ value: failure.message
9877
+ })
9878
+ }, failure.id)),
9879
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9880
+ className: "codexModelSelectGroups scrollable",
9881
+ role: "menu",
9882
+ "aria-label": t("modelLabel"),
9883
+ children: shownGroups.map((entry) => group(entry.id, entry.name, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [entry.allHidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9814
9884
  className: "codexModelSelectEmpty",
9815
- children: t("modelNoMatch")
9816
- }) : null
9817
- ]
9818
- });
9819
- else if (pane === "effort") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9820
- className: "codexModelSelectSubmenu",
9821
- role: "menu",
9822
- "aria-label": t("effortLabel"),
9823
- children: effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9885
+ children: t("modelsHidden")
9886
+ }) : null, entry.models.map((model) => option({
9887
+ key: model.id,
9888
+ label: model.name,
9889
+ selected: state.current?.provider === entry.id && state.current.model === model.id,
9890
+ disabled: busy,
9891
+ onClick: () => chooseModel({
9892
+ provider: entry.id,
9893
+ model: model.id
9894
+ })
9895
+ }))] })))
9896
+ }),
9897
+ state.status === "ready" && visibleGroups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9824
9898
  className: "codexModelSelectEmpty",
9825
- children: t("effortsEmpty")
9826
- }) : effortChoices.map((level) => option({
9827
- key: level.key,
9828
- label: level.label,
9829
- description: level.description,
9830
- selected: effectiveEffort === level.effort,
9831
- disabled: busy,
9832
- onClick: () => chooseEffort(level.effort)
9833
- }))
9834
- });
9835
- else if (pane === "speed") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9836
- className: "codexModelSelectSubmenu",
9837
- role: "menu",
9838
- "aria-label": t("speedTitle"),
9839
- children: [
9840
- option({
9841
- key: SPEED_MODE_STANDARD,
9842
- label: t("speedStandard"),
9843
- description: t("speedStandardHint"),
9844
- selected: !fast,
9845
- disabled: !speedWritable,
9846
- onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
9847
- }),
9848
- speedSupported && option({
9849
- key: "fast",
9850
- label: t("speedFast"),
9851
- description: t(state.current?.model === "gpt-6-astra" ? "speedFastAstraHint" : "speedFastHint"),
9852
- selected: fast && !ultrafast,
9853
- disabled: !speedWritable,
9854
- onClick: () => chooseSpeed("fast")
9855
- }),
9856
- ultrafastSupported && option({
9857
- key: "ultrafast",
9858
- label: t("speedUltrafast"),
9859
- description: t("speedUltrafastHint"),
9860
- selected: ultrafast,
9861
- disabled: !speedWritable,
9862
- onClick: () => chooseSpeed("ultrafast")
9863
- })
9864
- ]
9865
- });
9866
- else if (pane === "verbosity") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9867
- className: "codexModelSelectSubmenu",
9868
- role: "menu",
9869
- "aria-label": t("verbosityTitle"),
9870
- children: verbosityItems.map((item) => option({
9871
- key: item.id,
9872
- label: item.label,
9873
- description: item.description,
9874
- selected: preferenceSnapshot.outputVerbosity === item.id,
9875
- disabled: !verbosityWritable,
9876
- onClick: () => chooseVerbosity(item.id)
9877
- }))
9878
- });
9899
+ children: t(choices.length === 0 ? "modelsEmpty" : "modelsHidden")
9900
+ }) : null,
9901
+ state.status === "ready" && visibleGroups.length > 0 && shownGroups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9902
+ className: "codexModelSelectEmpty",
9903
+ children: t("modelNoMatch")
9904
+ }) : null
9905
+ ] });
9906
+ else if (pane === "effort") content = effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9907
+ className: "codexModelSelectEmpty",
9908
+ children: t("effortsEmpty")
9909
+ }) : effortChoices.map((level) => option({
9910
+ key: level.key,
9911
+ label: level.label,
9912
+ description: level.description,
9913
+ selected: effectiveEffort === level.effort,
9914
+ disabled: busy,
9915
+ onClick: () => chooseEffort(level.effort)
9916
+ }));
9917
+ else if (pane === "speed") content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9918
+ option({
9919
+ key: SPEED_MODE_STANDARD,
9920
+ label: t("speedStandard"),
9921
+ description: t("speedStandardHint"),
9922
+ selected: !fast,
9923
+ disabled: !speedWritable,
9924
+ onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
9925
+ }),
9926
+ speedSupported && option({
9927
+ key: "fast",
9928
+ label: t("speedFast"),
9929
+ description: t(state.current?.model === "gpt-6-astra" ? "speedFastAstraHint" : "speedFastHint"),
9930
+ selected: fast && !ultrafast,
9931
+ disabled: !speedWritable,
9932
+ onClick: () => chooseSpeed("fast")
9933
+ }),
9934
+ ultrafastSupported && option({
9935
+ key: "ultrafast",
9936
+ label: t("speedUltrafast"),
9937
+ description: t("speedUltrafastHint"),
9938
+ selected: ultrafast,
9939
+ disabled: !speedWritable,
9940
+ onClick: () => chooseSpeed("ultrafast")
9941
+ })
9942
+ ] });
9943
+ else if (pane === "verbosity") content = verbosityItems.map((item) => option({
9944
+ key: item.id,
9945
+ label: item.label,
9946
+ description: item.description,
9947
+ selected: preferenceSnapshot.outputVerbosity === item.id,
9948
+ disabled: !verbosityWritable,
9949
+ onClick: () => chooseVerbosity(item.id)
9950
+ }));
9951
+ const menu = open ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuSurface ?? "div", {
9952
+ ref: menuRef,
9953
+ id: `${id}-menu`,
9954
+ className: "codexModelSelectMenu",
9955
+ style: menuPos ?? MEASURE_STYLE,
9956
+ role: pane === "model" ? "group" : "menu",
9957
+ "aria-label": t("modelMenuAria"),
9958
+ "aria-busy": state.status === "loading" || busy,
9959
+ onKeyDown: (event) => {
9960
+ if (event.key !== "Escape") return;
9961
+ event.preventDefault();
9962
+ event.stopPropagation();
9963
+ if (pane === "root") close(true);
9964
+ else setPane("root");
9965
+ },
9966
+ children: content
9967
+ }), document.body) : null;
9879
9968
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9880
9969
  className: "codexModelSelect",
9881
9970
  ref: rootRef,
@@ -9911,19 +10000,51 @@ window.__ModuleLoader__.load({
9911
10000
  }),
9912
10001
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, { className: "codexModelSelectChevron" })
9913
10002
  ]
9914
- }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9915
- className: "codexModelSelectMenu",
9916
- id: `${id}-menu`,
9917
- role: "menu",
9918
- "aria-label": t("modelMenuAria"),
9919
- "aria-busy": state.status === "loading" || busy,
9920
- children: [
9921
- cell("model", t("modelLabel"), modelLabel),
9922
- reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
9923
- (speedSupported || ultrafastSupported) && cell("speed", t("speedTitle"), t(speedKey)),
9924
- verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel),
9925
- submenu
9926
- ]
10003
+ }), menu]
10004
+ });
10005
+ }
10006
+ //#endregion
10007
+ //#region src/client-hint.jsx
10008
+ /** A setting's explanation: shows up to two lines; a "More" link appears only when the text is actually cut off. */
10009
+ function Hint({ children, t, as: Tag = "span" }) {
10010
+ const [open, setOpen] = (0, react.useState)(false);
10011
+ const [clipped, setClipped] = (0, react.useState)(false);
10012
+ const text = (0, react.useRef)(null);
10013
+ const id = (0, react.useId)();
10014
+ const foldable = typeof children === "string";
10015
+ (0, react.useLayoutEffect)(() => {
10016
+ const node = text.current;
10017
+ if (!foldable || node === null || open) return;
10018
+ const measure = () => setClipped(node.scrollHeight > node.clientHeight + 1);
10019
+ measure();
10020
+ if (typeof ResizeObserver !== "function") return;
10021
+ const observer = new ResizeObserver(measure);
10022
+ observer.observe(node);
10023
+ return () => observer.disconnect();
10024
+ }, [
10025
+ children,
10026
+ foldable,
10027
+ open
10028
+ ]);
10029
+ if (!foldable) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
10030
+ className: "codexSubscriptionPreferenceHint",
10031
+ children
10032
+ });
10033
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Tag, {
10034
+ className: "codexSubscriptionPreferenceHint codexSubscriptionHintFold",
10035
+ "data-open": open || void 0,
10036
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10037
+ id,
10038
+ ref: text,
10039
+ className: "codexSubscriptionHintText",
10040
+ children
10041
+ }), clipped || open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10042
+ type: "button",
10043
+ className: "codexSubscriptionHintToggle",
10044
+ "aria-expanded": open,
10045
+ "aria-controls": id,
10046
+ onClick: () => setOpen((value) => !value),
10047
+ children: t(open ? "hintLess" : "hintMore")
9927
10048
  }) : null]
9928
10049
  });
9929
10050
  }
@@ -9947,7 +10068,7 @@ window.__ModuleLoader__.load({
9947
10068
  }
9948
10069
  //#endregion
9949
10070
  //#region src/image-preferences.jsx
9950
- function ImageChoice({ label, hint, value, text, items, disabled, onSelect }) {
10071
+ function ImageChoice({ t, label, hint, value, text, items, disabled, onSelect }) {
9951
10072
  const [open, setOpen] = (0, react.useState)(false);
9952
10073
  const anchor = (0, react.useRef)(null);
9953
10074
  (0, react.useEffect)(() => {
@@ -9966,8 +10087,8 @@ window.__ModuleLoader__.load({
9966
10087
  className: "codexSubscriptionPreference codexImagePreference",
9967
10088
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9968
10089
  className: "codexSubscriptionPreferenceCopy",
9969
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), hint ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9970
- className: "codexSubscriptionPreferenceHint",
10090
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), hint ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10091
+ t,
9971
10092
  children: hint
9972
10093
  }) : null]
9973
10094
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
@@ -10021,6 +10142,7 @@ window.__ModuleLoader__.load({
10021
10142
  Object.keys(IMAGE_SETTING_GROUPS).filter((group) => group.startsWith("sketch") === sketch).map((group) => {
10022
10143
  const value = imageGroupValue(snapshot, group);
10023
10144
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageChoice, {
10145
+ t,
10024
10146
  label: t(sketch ? `${group}Setting` : group),
10025
10147
  hint: t(`${group}Hint`),
10026
10148
  value,
@@ -10038,6 +10160,7 @@ window.__ModuleLoader__.load({
10038
10160
  !sketch ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10039
10161
  className: "codexImageDefaultsGroup",
10040
10162
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageChoice, {
10163
+ t,
10041
10164
  label: t("imageModel"),
10042
10165
  value: snapshot.imageModel,
10043
10166
  text: modelLabel(snapshot.imageModel),
@@ -10053,6 +10176,7 @@ window.__ModuleLoader__.load({
10053
10176
  });
10054
10177
  }
10055
10178
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageChoice, {
10179
+ t,
10056
10180
  label: t("imageQuality"),
10057
10181
  value: snapshot.imageQuality,
10058
10182
  text: t(`imageQuality_${snapshot.imageQuality}`),
@@ -10066,8 +10190,9 @@ window.__ModuleLoader__.load({
10066
10190
  }
10067
10191
  })]
10068
10192
  }) : null,
10069
- !sketch && snapshot.imageModel.includes("2.5") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10070
- className: "codexSubscriptionPreferenceHint",
10193
+ !sketch && snapshot.imageModel.includes("2.5") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10194
+ t,
10195
+ as: "p",
10071
10196
  children: t("imageModelHint")
10072
10197
  }) : null
10073
10198
  ]
@@ -10125,8 +10250,8 @@ window.__ModuleLoader__.load({
10125
10250
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10126
10251
  className: "codexSubscriptionPreferenceLabel",
10127
10252
  children: t("quotaAlerts")
10128
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10129
- className: "codexSubscriptionPreferenceHint",
10253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10254
+ t,
10130
10255
  children: t("quotaAlertsHint")
10131
10256
  })]
10132
10257
  }), choices("quotaAlerts", QUOTA_ALERT_MODES)]
@@ -10160,8 +10285,9 @@ window.__ModuleLoader__.load({
10160
10285
  children: t("searchMode")
10161
10286
  }), choices("searchMode", SEARCH_MODES)]
10162
10287
  }),
10163
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10164
- className: "codexSubscriptionPreferenceHint",
10288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10289
+ t,
10290
+ as: "p",
10165
10291
  children: t("searchModeHint")
10166
10292
  }),
10167
10293
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
@@ -10180,8 +10306,8 @@ window.__ModuleLoader__.load({
10180
10306
  if (event.key === "Enter") event.currentTarget.blur();
10181
10307
  }
10182
10308
  }),
10183
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10184
- className: "codexSubscriptionPreferenceHint",
10309
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10310
+ t,
10185
10311
  children: t("searchDomainsHint")
10186
10312
  })
10187
10313
  ]
@@ -10267,8 +10393,8 @@ window.__ModuleLoader__.load({
10267
10393
  className: "codexSubscriptionPreferenceLabel",
10268
10394
  children: t("defaultModelTitle")
10269
10395
  }),
10270
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10271
- className: "codexSubscriptionPreferenceHint",
10396
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
10397
+ t,
10272
10398
  children: hint
10273
10399
  }),
10274
10400
  snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -12634,6 +12760,7 @@ window.__ModuleLoader__.load({
12634
12760
  const STATUS_KEYS = {
12635
12761
  connected: "remoteConnected",
12636
12762
  connecting: "remoteConnecting",
12763
+ waiting: "remoteWaiting",
12637
12764
  error: "remoteError",
12638
12765
  stopped: "remoteStopped"
12639
12766
  };
@@ -12787,8 +12914,8 @@ window.__ModuleLoader__.load({
12787
12914
  " ",
12788
12915
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
12789
12916
  ]
12790
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12791
- className: "codexSubscriptionPreferenceHint",
12917
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
12918
+ t,
12792
12919
  children: t("remoteHint")
12793
12920
  })]
12794
12921
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -12875,7 +13002,7 @@ window.__ModuleLoader__.load({
12875
13002
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: [
12876
13003
  client.name ?? t("remotePhoneUnknown"),
12877
13004
  client.platform,
12878
- client.lastSeenAt ? t("remoteLastSeen").replace("{date}", new Date(client.lastSeenAt).toLocaleString()) : null
13005
+ client.lastSeenAt ? t("remoteLastSeen").replace("{date}", new Date(client.lastSeenAt).toLocaleString(uiLocale())) : null
12879
13006
  ].filter(Boolean).join(" · ") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
12880
13007
  type: "button",
12881
13008
  variant: "outline",
@@ -12950,8 +13077,8 @@ window.__ModuleLoader__.load({
12950
13077
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12951
13078
  className: "codexSubscriptionPreferenceLabel",
12952
13079
  children: t("quickQuotaSetting")
12953
- }), snapshot.quickQuotaMode === "forecast" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12954
- className: "codexSubscriptionPreferenceHint",
13080
+ }), snapshot.quickQuotaMode === "forecast" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13081
+ t,
12955
13082
  children: t("quickQuotaForecastHint")
12956
13083
  }) : null]
12957
13084
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -12983,8 +13110,8 @@ window.__ModuleLoader__.load({
12983
13110
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12984
13111
  className: "codexSubscriptionPreferenceLabel",
12985
13112
  children: t("autoQuotaRetry")
12986
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12987
- className: "codexSubscriptionPreferenceHint",
13113
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13114
+ t,
12988
13115
  children: t("autoQuotaRetryHint")
12989
13116
  })]
12990
13117
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Switch, {
@@ -13022,8 +13149,8 @@ window.__ModuleLoader__.load({
13022
13149
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13023
13150
  className: "codexSubscriptionPreferenceLabel",
13024
13151
  children: t("searchTitle")
13025
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13026
- className: "codexSubscriptionPreferenceHint",
13152
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13153
+ t,
13027
13154
  children: t(hint)
13028
13155
  })]
13029
13156
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -13055,8 +13182,8 @@ window.__ModuleLoader__.load({
13055
13182
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13056
13183
  className: "codexSubscriptionPreferenceLabel",
13057
13184
  children: t("inputImageDetail")
13058
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13059
- className: "codexSubscriptionPreferenceHint",
13185
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13186
+ t,
13060
13187
  children: t("inputImageDetailHint")
13061
13188
  })]
13062
13189
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13090,8 +13217,8 @@ window.__ModuleLoader__.load({
13090
13217
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13091
13218
  className: "codexSubscriptionPreferenceLabel",
13092
13219
  children: t("reasoningSummary")
13093
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13094
- className: "codexSubscriptionPreferenceHint",
13220
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13221
+ t,
13095
13222
  children: t("reasoningSummaryHint")
13096
13223
  })]
13097
13224
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13125,8 +13252,8 @@ window.__ModuleLoader__.load({
13125
13252
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13126
13253
  className: "codexSubscriptionPreferenceLabel",
13127
13254
  children: t("retryPolicy")
13128
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13129
- className: "codexSubscriptionPreferenceHint",
13255
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13256
+ t,
13130
13257
  children: t("retryPolicyHint")
13131
13258
  })]
13132
13259
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13154,39 +13281,44 @@ window.__ModuleLoader__.load({
13154
13281
  const snapshot = usePreferenceSnapshot(preference);
13155
13282
  const writable = snapshot.status === "ready" && snapshot.writable === true;
13156
13283
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13157
- className: "codexSubscriptionPreference",
13158
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13159
- className: "codexSubscriptionPreferenceCopy",
13160
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
13161
- className: "codexSubscriptionPreferenceLabel",
13162
- children: [
13163
- t("connectors"),
13164
- " ",
13165
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
13166
- ]
13167
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13168
- className: "codexSubscriptionPreferenceHint",
13169
- children: t("connectorsHint")
13170
- })]
13171
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13172
- className: "codexSubscriptionQuotaModes",
13173
- "data-saving": snapshot.saving || void 0,
13174
- "aria-busy": snapshot.saving || void 0,
13175
- role: "radiogroup",
13176
- "aria-label": t("connectors"),
13177
- children: CONNECTOR_MODES.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
13178
- className: "codexSubscriptionQuotaMode",
13179
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
13180
- type: "radio",
13181
- name: "codex-connectors",
13182
- checked: snapshot.connectors === value,
13183
- disabled: !writable,
13184
- onChange: () => {
13185
- preference.set({ [CONNECTORS_FIELD]: value });
13186
- }
13187
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(`connectors_${value}`) })]
13188
- }, value))
13189
- })]
13284
+ className: "codexSubscriptionPreference codexSubscriptionPreferenceStack",
13285
+ children: [
13286
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13287
+ className: "codexSubscriptionPreferenceCopy",
13288
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13289
+ className: "codexSubscriptionPreferenceLabel",
13290
+ children: t("connectors")
13291
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13292
+ t,
13293
+ children: t("connectorsHint")
13294
+ })]
13295
+ }),
13296
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13297
+ className: "codexSubscriptionQuotaModes",
13298
+ "data-saving": snapshot.saving || void 0,
13299
+ "aria-busy": snapshot.saving || void 0,
13300
+ role: "radiogroup",
13301
+ "aria-label": t("connectors"),
13302
+ children: CONNECTOR_MODES.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
13303
+ className: "codexSubscriptionQuotaMode",
13304
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
13305
+ type: "radio",
13306
+ name: "codex-connectors",
13307
+ checked: snapshot.connectors === value,
13308
+ disabled: !writable,
13309
+ onChange: () => {
13310
+ preference.set({ [CONNECTORS_FIELD]: value });
13311
+ }
13312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(`connectors_${value}`) })]
13313
+ }, value))
13314
+ }),
13315
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13316
+ className: "codexSubscriptionModeNote",
13317
+ "data-danger": snapshot.connectors === "write" || void 0,
13318
+ role: "status",
13319
+ children: t(`connectorsMode_${snapshot.connectors}`)
13320
+ })
13321
+ ]
13190
13322
  });
13191
13323
  }
13192
13324
  function StreamIdleTimeoutPreference({ preference, t }) {
@@ -13199,8 +13331,8 @@ window.__ModuleLoader__.load({
13199
13331
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13200
13332
  className: "codexSubscriptionPreferenceLabel",
13201
13333
  children: t("streamIdleTimeoutTitle")
13202
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13203
- className: "codexSubscriptionPreferenceHint",
13334
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13335
+ t,
13204
13336
  children: t("streamIdleTimeoutHint")
13205
13337
  })]
13206
13338
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13266,8 +13398,8 @@ window.__ModuleLoader__.load({
13266
13398
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13267
13399
  className: "codexSubscriptionPreferenceLabel",
13268
13400
  children: t("pickerModelsTitle")
13269
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13270
- className: "codexSubscriptionPreferenceHint",
13401
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13402
+ t,
13271
13403
  children: t("pickerModelsHint")
13272
13404
  })]
13273
13405
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -13538,8 +13670,8 @@ window.__ModuleLoader__.load({
13538
13670
  " ",
13539
13671
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
13540
13672
  ]
13541
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13542
- className: "codexSubscriptionPreferenceHint",
13673
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13674
+ t,
13543
13675
  children: t("connectionHint")
13544
13676
  })]
13545
13677
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13582,8 +13714,8 @@ window.__ModuleLoader__.load({
13582
13714
  " ",
13583
13715
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
13584
13716
  ]
13585
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13586
- className: "codexSubscriptionPreferenceHint",
13717
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13718
+ t,
13587
13719
  children: t("reviewModelHint")
13588
13720
  })]
13589
13721
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13626,8 +13758,8 @@ window.__ModuleLoader__.load({
13626
13758
  " ",
13627
13759
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
13628
13760
  ]
13629
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13630
- className: "codexSubscriptionPreferenceHint",
13761
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13762
+ t,
13631
13763
  children: t("compactionHint")
13632
13764
  })]
13633
13765
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13664,8 +13796,8 @@ window.__ModuleLoader__.load({
13664
13796
  " ",
13665
13797
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
13666
13798
  ]
13667
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
13668
- className: "codexSubscriptionPreferenceHint",
13799
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
13800
+ t,
13669
13801
  children: t(snapshot.subagentBackendAvailable ? "subagentBackendHint" : "subagentBackendUnavailable")
13670
13802
  })]
13671
13803
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13768,6 +13900,73 @@ window.__ModuleLoader__.load({
13768
13900
  }
13769
13901
  }
13770
13902
  //#endregion
13903
+ //#region src/client-account-quota.jsx
13904
+ const when = (seconds) => (/* @__PURE__ */ new Date(seconds * 1e3)).toLocaleString(uiLocale(), {
13905
+ month: "numeric",
13906
+ day: "numeric",
13907
+ hour: "2-digit",
13908
+ minute: "2-digit"
13909
+ });
13910
+ /** Quota of every signed-in account (read-only; the active account does not change). */
13911
+ function useAccountQuotas(rpc, ids) {
13912
+ const [entries, setEntries] = (0, react.useState)({});
13913
+ const [busy, setBusy] = (0, react.useState)(false);
13914
+ const request = (0, react.useRef)(0);
13915
+ const key = ids.join(",");
13916
+ const load = (force) => {
13917
+ if (ids.length < 2) {
13918
+ setEntries({});
13919
+ return;
13920
+ }
13921
+ const id = ++request.current;
13922
+ setBusy(true);
13923
+ recoveryCall(rpc, "usage/accounts", { force }).then((value) => {
13924
+ if (request.current === id) setEntries(Object.fromEntries((value?.accounts ?? []).map((entry) => [entry.id, entry])));
13925
+ }).catch(() => {
13926
+ if (request.current === id) setEntries(Object.fromEntries(ids.map((account) => [account, {
13927
+ id: account,
13928
+ error: "Could not read ChatGPT usage"
13929
+ }])));
13930
+ }).finally(() => {
13931
+ if (request.current === id) setBusy(false);
13932
+ });
13933
+ };
13934
+ (0, react.useEffect)(() => {
13935
+ load(false);
13936
+ return () => {
13937
+ request.current += 1;
13938
+ };
13939
+ }, [key]);
13940
+ return {
13941
+ entries,
13942
+ busy,
13943
+ refresh: () => load(true)
13944
+ };
13945
+ }
13946
+ function AccountQuota({ entry, loading, t }) {
13947
+ if (entry === void 0) return loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
13948
+ className: "codexSubscriptionAccountQuota",
13949
+ children: t("accountQuotaLoading")
13950
+ }) : null;
13951
+ if (entry.error !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
13952
+ className: "codexSubscriptionAccountQuota",
13953
+ "data-state": "error",
13954
+ children: entry.error === "ChatGPT sign-in needs to be renewed" ? t("resetRenewLogin") : t("accountQuotaError")
13955
+ });
13956
+ const windows = entry.usage?.rateLimits?.find((limit) => limit.id === "codex")?.windows ?? [];
13957
+ if (windows.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
13958
+ className: "codexSubscriptionAccountQuota",
13959
+ children: t("accountQuotaNone")
13960
+ });
13961
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
13962
+ className: "codexSubscriptionAccountQuota",
13963
+ children: windows.map((window) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [fill(t("accountQuotaLeft"), {
13964
+ label: windowLabel(window.windowSeconds, t),
13965
+ value: percent(window.remainingPercent)
13966
+ }), window.resetsAt === void 0 ? "" : ` · ${fill(t("accountQuotaResets"), { value: when(window.resetsAt) })}`] }, window.windowSeconds))
13967
+ });
13968
+ }
13969
+ //#endregion
13771
13970
  //#region src/client-account.jsx
13772
13971
  const LOGIN_FAILURES = [
13773
13972
  "account-claim",
@@ -13789,6 +13988,7 @@ window.__ModuleLoader__.load({
13789
13988
  children: emailVisible ? candidate.email : maskEmail(candidate.email)
13790
13989
  });
13791
13990
  }
13991
+ const signedInIds = (account) => account?.authenticated === true ? (account.accounts ?? []).map((candidate) => candidate.id).filter((id) => typeof id === "string") : [];
13792
13992
  function AccountCard({ rpc, t, account, setAccount, onSignedOut }) {
13793
13993
  const [flow, setFlow] = (0, react.useState)();
13794
13994
  const flowGeneration = (0, react.useRef)(0);
@@ -13801,6 +14001,7 @@ window.__ModuleLoader__.load({
13801
14001
  const [emailVisibilityKey, setEmailVisibilityKey] = (0, react.useState)(accountVisibilityKey);
13802
14002
  const [busy, setBusy] = (0, react.useState)(false);
13803
14003
  const [error, setError] = (0, react.useState)();
14004
+ const quotas = useAccountQuotas(rpc, signedInIds(account));
13804
14005
  const call = (endpoint, payload = {}) => recoveryCall(rpc, endpoint, payload);
13805
14006
  (0, react.useEffect)(() => {
13806
14007
  if (emailVisibilityKey === accountVisibilityKey) return;
@@ -13996,12 +14197,19 @@ window.__ModuleLoader__.load({
13996
14197
  children: accounts.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
13997
14198
  className: "codexSubscriptionAccount",
13998
14199
  "data-active": candidate.active,
13999
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountEmail, {
14000
- candidate,
14001
- fallback: candidate.label,
14002
- t,
14003
- emailVisible: emailVisibleForAccount,
14004
- onClick: toggleEmail
14200
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14201
+ className: "codexSubscriptionAccountMain",
14202
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountEmail, {
14203
+ candidate,
14204
+ fallback: candidate.label,
14205
+ t,
14206
+ emailVisible: emailVisibleForAccount,
14207
+ onClick: toggleEmail
14208
+ }), accounts.length > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountQuota, {
14209
+ entry: quotas.entries[candidate.id],
14210
+ loading: quotas.busy,
14211
+ t
14212
+ }) : null]
14005
14213
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
14006
14214
  className: "codexSubscriptionActions",
14007
14215
  children: [
@@ -14200,8 +14408,9 @@ window.__ModuleLoader__.load({
14200
14408
  }) : null
14201
14409
  ]
14202
14410
  }),
14203
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
14204
- className: "codexSubscriptionPreferenceHint",
14411
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hint, {
14412
+ t,
14413
+ as: "p",
14205
14414
  children: t(confirm ? "recoveryClearHint" : "recoveryHint")
14206
14415
  }),
14207
14416
  failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -14405,7 +14614,7 @@ window.__ModuleLoader__.load({
14405
14614
  children: [
14406
14615
  t("diagnosticsSnapshotTime"),
14407
14616
  " ",
14408
- new Date(report.generatedAt).toLocaleString()
14617
+ new Date(report.generatedAt).toLocaleString(uiLocale())
14409
14618
  ]
14410
14619
  }) : null,
14411
14620
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -14423,7 +14632,7 @@ window.__ModuleLoader__.load({
14423
14632
  " · ",
14424
14633
  t(`diagnosticSource_${event.source}`),
14425
14634
  " · ",
14426
- new Date(event.observedAt).toLocaleTimeString()
14635
+ new Date(event.observedAt).toLocaleTimeString(uiLocale())
14427
14636
  ] }, `${event.source}:${event.action}`)) }) : null
14428
14637
  ] }, item.code)) }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("diagnosticsNoRecordedFailure") })
14429
14638
  }),
@@ -14441,7 +14650,7 @@ window.__ModuleLoader__.load({
14441
14650
  ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: (report.inspection?.capabilities ?? []).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
14442
14651
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: t(`diagnosticCapability_${item.id}`) }),
14443
14652
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [t(`diagnosticReason_${item.reason}`), item.blockedBy ? ` · ${t(`diagnosticCapability_${item.blockedBy}`)}` : ""] }),
14444
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [item.latest ? `${item.latest.action} · ${t(`diagnosticSource_${item.latest.source}`)} · ${t(`diagnosticOutcome_${item.latest.status}`)} · ${new Date(item.latest.observedAt).toLocaleTimeString()}` : t("diagnosticsUnverified"), item.unresolved?.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("diagnosticsUnresolved") }) : null] })
14653
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [item.latest ? `${item.latest.action} · ${t(`diagnosticSource_${item.latest.source}`)} · ${t(`diagnosticOutcome_${item.latest.status}`)} · ${new Date(item.latest.observedAt).toLocaleTimeString(uiLocale())}` : t("diagnosticsUnverified"), item.unresolved?.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("diagnosticsUnresolved") }) : null] })
14445
14654
  ] }, item.id)) })]
14446
14655
  }),
14447
14656
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -14588,7 +14797,6 @@ window.__ModuleLoader__.load({
14588
14797
  }
14589
14798
  //#endregion
14590
14799
  //#region src/client-usage-overview.jsx
14591
- const uiLocale = () => typeof document === "undefined" ? void 0 : document.documentElement.lang || void 0;
14592
14800
  const WEEKS = 26;
14593
14801
  const compact = (value) => new Intl.NumberFormat(uiLocale(), {
14594
14802
  notation: "compact",
@@ -14858,8 +15066,8 @@ window.__ModuleLoader__.load({
14858
15066
  }
14859
15067
  //#endregion
14860
15068
  //#region src/client-usage.jsx
14861
- const count = (value) => Number(value).toLocaleString();
14862
- const creditAmount = (value) => Number.isFinite(Number(value)) && String(value).trim() !== "" ? Number(value).toLocaleString(void 0, { maximumFractionDigits: 2 }) : value;
15069
+ const count = (value) => Number(value).toLocaleString(uiLocale());
15070
+ const creditAmount = (value) => Number.isFinite(Number(value)) && String(value).trim() !== "" ? Number(value).toLocaleString(uiLocale(), { maximumFractionDigits: 2 }) : value;
14863
15071
  function CreditExpiry({ credits, t }) {
14864
15072
  const date = validDate(credits.expiresAt);
14865
15073
  if (date === void 0 || credits.unlimited) return null;
@@ -14870,7 +15078,7 @@ window.__ModuleLoader__.load({
14870
15078
  "data-soon": status.soon,
14871
15079
  role: "status",
14872
15080
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [fill(t(status.daysLeft === 0 ? "creditsExpiredToday" : "creditsExpires"), {
14873
- date: date.toLocaleDateString(),
15081
+ date: date.toLocaleDateString(uiLocale()),
14874
15082
  days: status.daysLeft
14875
15083
  }), estimate ? ` ${t("creditsExpiryEstimate")}` : ""] })
14876
15084
  });
@@ -14878,7 +15086,7 @@ window.__ModuleLoader__.load({
14878
15086
  function ResetTime({ resetsAt, t }) {
14879
15087
  const date = Number.isSafeInteger(resetsAt) ? validDate(resetsAt * 1e3) : void 0;
14880
15088
  if (date === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetUnknown") });
14881
- const value = date.toLocaleString(void 0, {
15089
+ const value = date.toLocaleString(uiLocale(), {
14882
15090
  month: "numeric",
14883
15091
  day: "numeric",
14884
15092
  hour: "2-digit",
@@ -14886,7 +15094,7 @@ window.__ModuleLoader__.load({
14886
15094
  });
14887
15095
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
14888
15096
  dateTime: date.toISOString(),
14889
- title: date.toLocaleString(),
15097
+ title: date.toLocaleString(uiLocale()),
14890
15098
  children: fill(t("resets"), { value })
14891
15099
  });
14892
15100
  }
@@ -14896,8 +15104,8 @@ window.__ModuleLoader__.load({
14896
15104
  className: "codexSubscriptionResetExpiry",
14897
15105
  children: date === void 0 ? t("resetCreditExpiryUnknown") : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
14898
15106
  dateTime: date.toISOString(),
14899
- title: date.toLocaleString(),
14900
- children: fill(t("resetCreditExpires"), { value: date.toLocaleDateString(void 0, {
15107
+ title: date.toLocaleString(uiLocale()),
15108
+ children: fill(t("resetCreditExpires"), { value: date.toLocaleDateString(uiLocale(), {
14901
15109
  month: "long",
14902
15110
  day: "numeric"
14903
15111
  }) })
@@ -15089,6 +15297,7 @@ window.__ModuleLoader__.load({
15089
15297
  return t((/* @__PURE__ */ new Map([
15090
15298
  ["ChatGPT subscription is not signed in", "resetRenewLogin"],
15091
15299
  ["ChatGPT sign-in needs to be renewed", "resetRenewLogin"],
15300
+ ["ChatGPT blocked this request before it reached your account (HTTP 403); your sign-in is fine, try again later or check your network, proxy or VPN", "resetBlocked"],
15092
15301
  ["No quota reset is available", "resetNoCredit"],
15093
15302
  ["No usable quota reset is available", "resetNoCredit"],
15094
15303
  ["The available quota reset expires too soon", "resetExpired"],
@@ -15151,7 +15360,7 @@ window.__ModuleLoader__.load({
15151
15360
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("usage") }), fetchedAt === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
15152
15361
  className: "codexSubscriptionFreshness",
15153
15362
  dateTime: fetchedAt.toISOString(),
15154
- children: fill(t("usageUpdated"), { value: fetchedAt.toLocaleString() })
15363
+ children: fill(t("usageUpdated"), { value: fetchedAt.toLocaleString(uiLocale()) })
15155
15364
  })]
15156
15365
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
15157
15366
  className: "codexSubscriptionRefresh",