dsh-codearts 1.2.10 → 1.2.11

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.
@@ -62,7 +62,7 @@ function subscribeSidebarPanelWanted(listener) {
62
62
  }
63
63
  //#endregion
64
64
  //#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPluginCard.module.css.mjs
65
- const css$1 = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex-wrap:wrap;flex:none;justify-content:flex-end;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTip[data-float=true]{z-index:40;position:fixed;bottom:auto;right:auto}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;margin:8px 0 2px;display:grid}.xoziZG_heatWeekday{color:var(--dsw-alias-label-tertiary);text-align:center;font-size:10px;line-height:14px}.xoziZG_heatCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);height:36px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;border:0;border-radius:8px;outline:0;justify-content:center;align-items:center;font-size:12px;transition:background .12s ease-out;display:flex}.xoziZG_heatCell[data-tone=empty]{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatCell[data-tone=pad]{background:0 0}.xoziZG_heatCell[data-tone=out]{color:var(--dsw-alias-label-tertiary);opacity:.45;background:0 0}.xoziZG_heatCell[data-tone=lv1]{color:#0f1115;background:#ddf4e7}.xoziZG_heatCell[data-tone=lv2]{color:#0f1115;background:#b3e8cc}.xoziZG_heatCell[data-tone=lv3]{color:#0f1115;background:#7dd8ac}.xoziZG_heatCell[data-tone=lv4]{color:#fff;background:#40c584}.xoziZG_heatCell[data-tone=lv5]{color:#fff;background:#16a34a}.xoziZG_heatCell[data-today=true]{font-weight:700;box-shadow:inset 0 -2px}.xoziZG_heatHours{grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;margin:8px 0 0;display:grid}.xoziZG_heatHourCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);border-radius:4px;height:26px;transition:background .12s ease-out}.xoziZG_heatHourCell[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatHourCell[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatHourCell[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatHourCell[data-tone=lv4]{background:#40c584}.xoziZG_heatHourCell[data-tone=lv5]{background:#16a34a}.xoziZG_heatAxis{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;font-size:10px;line-height:14px;display:grid}.xoziZG_heatAxisSlot{text-align:center;white-space:nowrap;overflow:hidden}.xoziZG_heatLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-start;align-items:center;gap:3px;margin:0 0 6px;font-size:10px;display:flex}.xoziZG_heatLegendChip{border-radius:3px;width:10px;height:10px}.xoziZG_heatLegendChip[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatLegendChip[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatLegendChip[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatLegendChip[data-tone=lv4]{background:#40c584}.xoziZG_heatLegendChip[data-tone=lv5]{background:#16a34a}.xoziZG_trendTip{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin:2px 0 0;font-size:11px;line-height:16px}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.xoziZG_skeleton{flex-direction:column;gap:10px;padding:4px 0;display:flex}.xoziZG_skeletonRow{border-radius:var(--dsw-radius-sm,4px);background:var(--dsw-alias-border-l2);height:12px;animation:1.4s ease-in-out infinite xoziZG_skeletonBreath}.xoziZG_skeletonRow:nth-child(2){width:72%}.xoziZG_skeletonRow:nth-child(3){width:46%}@keyframes xoziZG_skeletonBreath{0%,to{opacity:.45}50%{opacity:.9}}@media (prefers-reduced-motion:reduce){.xoziZG_skeletonRow{animation:none}}";
65
+ const css$1 = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex-wrap:wrap;flex:none;justify-content:flex-end;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTip[data-float=true]{z-index:40;position:fixed;bottom:auto;right:auto}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;margin:8px 0 2px;display:grid}.xoziZG_heatWeekday{color:var(--dsw-alias-label-tertiary);text-align:center;font-size:10px;line-height:14px}.xoziZG_heatCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);height:36px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;border:0;border-radius:8px;outline:0;justify-content:center;align-items:center;font-size:12px;transition:background .12s ease-out;display:flex}.xoziZG_heatCell[data-tone=empty]{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatCell[data-tone=pad]{background:0 0}.xoziZG_heatCell[data-tone=out]{color:var(--dsw-alias-label-tertiary);opacity:.45;background:0 0}.xoziZG_heatCell[data-tone=lv1]{color:#0f1115;background:#ddf4e7}.xoziZG_heatCell[data-tone=lv2]{color:#0f1115;background:#b3e8cc}.xoziZG_heatCell[data-tone=lv3]{color:#0f1115;background:#7dd8ac}.xoziZG_heatCell[data-tone=lv4]{color:#fff;background:#40c584}.xoziZG_heatCell[data-tone=lv5]{color:#fff;background:#16a34a}.xoziZG_heatCell[data-today=true]{font-weight:700;box-shadow:inset 0 -2px}.xoziZG_heatHours{grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;margin:8px 0 0;display:grid}.xoziZG_heatHourCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);border-radius:4px;height:26px;transition:background .12s ease-out}.xoziZG_heatHourCell[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatHourCell[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatHourCell[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatHourCell[data-tone=lv4]{background:#40c584}.xoziZG_heatHourCell[data-tone=lv5]{background:#16a34a}.xoziZG_heatAxis{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;font-size:10px;line-height:14px;display:grid}.xoziZG_heatAxisSlot{text-align:center;white-space:nowrap;overflow:hidden}.xoziZG_heatLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-start;align-items:center;gap:3px;margin:0 0 6px;font-size:10px;display:flex}.xoziZG_heatLegendChip{border-radius:3px;width:10px;height:10px}.xoziZG_heatLegendChip[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatLegendChip[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatLegendChip[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatLegendChip[data-tone=lv4]{background:#40c584}.xoziZG_heatLegendChip[data-tone=lv5]{background:#16a34a}.xoziZG_trendTip{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin:2px 0 0;font-size:11px;line-height:16px}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.xoziZG_skeleton{flex-direction:column;gap:10px;padding:4px 0;display:flex}.xoziZG_skeletonRow{border-radius:var(--dsw-radius-sm,4px);background:var(--dsw-alias-border-l2);height:12px;animation:1.4s ease-in-out infinite xoziZG_skeletonBreath}.xoziZG_skeletonRow:nth-child(2){width:72%}.xoziZG_skeletonRow:nth-child(3){width:46%}@keyframes xoziZG_skeletonBreath{0%,to{opacity:.45}50%{opacity:.9}}@media (prefers-reduced-motion:reduce){.xoziZG_skeletonRow{animation:none}}.xoziZG_modelSpec{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_doctorList{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_doctorRow{align-items:center;gap:8px;padding:4px 0;display:flex}.xoziZG_doctorName{color:var(--dsw-alias-label-secondary);flex:none;font-size:12px;line-height:18px}.xoziZG_doctorRow .xoziZG_meta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}";
66
66
  const tagId$1 = "dsh-codearts/CodeArtsPluginCard.module.css";
67
67
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
68
68
  const tag = document.createElement("style");
@@ -72,92 +72,96 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
72
72
  document.head.appendChild(tag);
73
73
  }
74
74
  var CodeArtsPluginCard_module_css_default = {
75
- "accountHint": "xoziZG_accountHint",
76
- "heatLegendChip": "xoziZG_heatLegendChip",
77
- "balance": "xoziZG_balance",
78
- "claimAllRow": "xoziZG_claimAllRow",
79
- "balanceUnit": "xoziZG_balanceUnit",
80
- "heatAxisSlot": "xoziZG_heatAxisSlot",
81
- "creditBlock": "xoziZG_creditBlock",
82
- "statusLine": "xoziZG_statusLine",
83
- "modelChart": "xoziZG_modelChart",
75
+ "usageFill": "xoziZG_usageFill",
76
+ "modelName": "xoziZG_modelName",
77
+ "tabPanel": "xoziZG_tabPanel",
84
78
  "sectionHead": "xoziZG_sectionHead",
85
- "usageBar": "xoziZG_usageBar",
86
- "accountCard": "xoziZG_accountCard",
87
- "usageTipName": "xoziZG_usageTipName",
88
- "choiceRow": "xoziZG_choiceRow",
89
- "fieldLabel": "xoziZG_fieldLabel",
90
- "modelRow": "xoziZG_modelRow",
79
+ "card": "xoziZG_card",
80
+ "usageTip": "xoziZG_usageTip",
91
81
  "expiryRow": "xoziZG_expiryRow",
92
- "headText": "xoziZG_headText",
93
- "modelTrack": "xoziZG_modelTrack",
94
- "heatHourCell": "xoziZG_heatHourCell",
95
- "header": "xoziZG_header",
96
- "accountToolbar": "xoziZG_accountToolbar",
97
- "statGrid": "xoziZG_statGrid",
98
- "skeletonBreath": "xoziZG_skeletonBreath",
99
- "balanceRow": "xoziZG_balanceRow",
100
- "modelFill": "xoziZG_modelFill",
101
- "heatAxis": "xoziZG_heatAxis",
102
- "accountRow": "xoziZG_accountRow",
103
- "heatGrid": "xoziZG_heatGrid",
104
- "field": "xoziZG_field",
82
+ "statusLine": "xoziZG_statusLine",
83
+ "tabs": "xoziZG_tabs",
84
+ "creditBlock": "xoziZG_creditBlock",
105
85
  "link": "xoziZG_link",
86
+ "statGrid": "xoziZG_statGrid",
87
+ "creditRows": "xoziZG_creditRows",
106
88
  "heatHours": "xoziZG_heatHours",
107
- "tabPanel": "xoziZG_tabPanel",
108
- "choices": "xoziZG_choices",
109
- "desc": "xoziZG_desc",
89
+ "manual": "xoziZG_manual",
90
+ "fieldLabel": "xoziZG_fieldLabel",
91
+ "area": "xoziZG_area",
92
+ "doctorRow": "xoziZG_doctorRow",
93
+ "heatCell": "xoziZG_heatCell",
110
94
  "creditHint": "xoziZG_creditHint",
111
- "creditFooter": "xoziZG_creditFooter",
112
- "accountInfo": "xoziZG_accountInfo",
113
- "manualForm": "xoziZG_manualForm",
114
- "card": "xoziZG_card",
115
- "actions": "xoziZG_actions",
116
- "usageFill": "xoziZG_usageFill",
117
- "usageTipRow": "xoziZG_usageTipRow",
118
- "modelTokens": "xoziZG_modelTokens",
119
- "trendTip": "xoziZG_trendTip",
120
- "section": "xoziZG_section",
121
- "tabs": "xoziZG_tabs",
122
- "meta": "xoziZG_meta",
123
- "bar": "xoziZG_bar",
124
- "barFill": "xoziZG_barFill",
125
- "modelRequests": "xoziZG_modelRequests",
126
- "skeleton": "xoziZG_skeleton",
127
- "modelName": "xoziZG_modelName",
95
+ "heatWeekday": "xoziZG_heatWeekday",
96
+ "heatLegend": "xoziZG_heatLegend",
97
+ "balanceUnit": "xoziZG_balanceUnit",
128
98
  "updated": "xoziZG_updated",
99
+ "heatAxisSlot": "xoziZG_heatAxisSlot",
100
+ "field": "xoziZG_field",
101
+ "skeleton": "xoziZG_skeleton",
102
+ "trendTip": "xoziZG_trendTip",
129
103
  "manualSummary": "xoziZG_manualSummary",
130
- "area": "xoziZG_area",
131
- "statCard": "xoziZG_statCard",
132
- "heatWeekday": "xoziZG_heatWeekday",
133
- "creditRow": "xoziZG_creditRow",
134
- "check": "xoziZG_check",
135
- "accountNameRow": "xoziZG_accountNameRow",
136
- "skeletonRow": "xoziZG_skeletonRow",
137
- "balanceMeta": "xoziZG_balanceMeta",
138
- "statSub": "xoziZG_statSub",
139
- "count": "xoziZG_count",
104
+ "hint": "xoziZG_hint",
105
+ "modelRequests": "xoziZG_modelRequests",
140
106
  "name": "xoziZG_name",
141
- "accountRowActions": "xoziZG_accountRowActions",
107
+ "accountInfo": "xoziZG_accountInfo",
108
+ "heatAxis": "xoziZG_heatAxis",
109
+ "usageBar": "xoziZG_usageBar",
110
+ "barFill": "xoziZG_barFill",
142
111
  "danger": "xoziZG_danger",
143
- "statLabel": "xoziZG_statLabel",
144
- "usageTipSep": "xoziZG_usageTipSep",
112
+ "accountHint": "xoziZG_accountHint",
145
113
  "modelShare": "xoziZG_modelShare",
146
- "heatCell": "xoziZG_heatCell",
147
- "heatLegend": "xoziZG_heatLegend",
148
- "manual": "xoziZG_manual",
149
- "avatar": "xoziZG_avatar",
150
- "error": "xoziZG_error",
114
+ "accountToolbar": "xoziZG_accountToolbar",
115
+ "section": "xoziZG_section",
116
+ "modelTokens": "xoziZG_modelTokens",
117
+ "skeletonRow": "xoziZG_skeletonRow",
118
+ "sectionLabel": "xoziZG_sectionLabel",
119
+ "creditRow": "xoziZG_creditRow",
120
+ "usageTipSep": "xoziZG_usageTipSep",
121
+ "skeletonBreath": "xoziZG_skeletonBreath",
151
122
  "body": "xoziZG_body",
152
- "creditLink": "xoziZG_creditLink",
153
- "accountName": "xoziZG_accountName",
154
- "statValue": "xoziZG_statValue",
123
+ "modelSpec": "xoziZG_modelSpec",
124
+ "heatLegendChip": "xoziZG_heatLegendChip",
125
+ "heatHourCell": "xoziZG_heatHourCell",
126
+ "modelRow": "xoziZG_modelRow",
127
+ "balance": "xoziZG_balance",
128
+ "meta": "xoziZG_meta",
129
+ "avatar": "xoziZG_avatar",
130
+ "heatGrid": "xoziZG_heatGrid",
131
+ "check": "xoziZG_check",
132
+ "statLabel": "xoziZG_statLabel",
133
+ "statSub": "xoziZG_statSub",
134
+ "statCard": "xoziZG_statCard",
135
+ "modelChart": "xoziZG_modelChart",
136
+ "actions": "xoziZG_actions",
137
+ "choices": "xoziZG_choices",
138
+ "usageTipName": "xoziZG_usageTipName",
139
+ "balanceMeta": "xoziZG_balanceMeta",
155
140
  "expiryLabel": "xoziZG_expiryLabel",
156
- "hint": "xoziZG_hint",
157
- "usageTip": "xoziZG_usageTip",
141
+ "accountName": "xoziZG_accountName",
142
+ "creditLink": "xoziZG_creditLink",
143
+ "doctorList": "xoziZG_doctorList",
144
+ "accountNameRow": "xoziZG_accountNameRow",
145
+ "accountCard": "xoziZG_accountCard",
146
+ "balanceRow": "xoziZG_balanceRow",
147
+ "error": "xoziZG_error",
148
+ "modelFill": "xoziZG_modelFill",
149
+ "bar": "xoziZG_bar",
150
+ "creditFooter": "xoziZG_creditFooter",
151
+ "modelTrack": "xoziZG_modelTrack",
152
+ "choiceRow": "xoziZG_choiceRow",
158
153
  "accountEntry": "xoziZG_accountEntry",
159
- "sectionLabel": "xoziZG_sectionLabel",
160
- "creditRows": "xoziZG_creditRows"
154
+ "headText": "xoziZG_headText",
155
+ "header": "xoziZG_header",
156
+ "count": "xoziZG_count",
157
+ "usageTipRow": "xoziZG_usageTipRow",
158
+ "accountRow": "xoziZG_accountRow",
159
+ "manualForm": "xoziZG_manualForm",
160
+ "doctorName": "xoziZG_doctorName",
161
+ "statValue": "xoziZG_statValue",
162
+ "claimAllRow": "xoziZG_claimAllRow",
163
+ "accountRowActions": "xoziZG_accountRowActions",
164
+ "desc": "xoziZG_desc"
161
165
  };
162
166
  //#endregion
163
167
  //#region src/client/CodeArtsPluginCard.tsx
@@ -222,6 +226,49 @@ const DOCK_DEFAULT = {
222
226
  * 后台再刷新 —— 比每次都先闪骨架舒服,也不会把「还没读到」误判成未登录。
223
227
  */
224
228
  let lastStatusSnapshot = null;
229
+ const lastTestResults = {};
230
+ /**
231
+ * 上下文窗口这类数字不适合印全值(1048576 比 1M 难读),按 K/M 取整。
232
+ *
233
+ * undefined 表示上游没给 —— 此时后端下发的 32768 是兜底值,不能当成真的印出来。
234
+ */
235
+ function formatWindow(tokens) {
236
+ if (tokens === void 0 || !Number.isFinite(tokens) || tokens <= 0) return "—";
237
+ if (tokens >= 1048576) return `${Math.round(tokens / 1048576)}M`;
238
+ if (tokens >= 1024) return `${Math.round(tokens / 1024)}K`;
239
+ return String(tokens);
240
+ }
241
+ /** 体检里一条检查的标题。账号级检查按 id 找回备注名,别让用户对着哈希猜。 */
242
+ function doctorCheckLabel(id, accounts, t) {
243
+ if (id.startsWith("account:")) {
244
+ const accountId = id.slice(8);
245
+ const account = accounts.find((entry) => entry.id === accountId);
246
+ const name = account?.label?.trim() || account?.userName?.trim() || accountId;
247
+ return `${t("doctorCheckAccount")} ${name}`;
248
+ }
249
+ switch (id) {
250
+ case "runtime": return t("doctorCheckRuntime");
251
+ case "accounts": return t("doctorCheckAccounts");
252
+ case "models": return t("doctorCheckModels");
253
+ case "usage": return t("doctorCheckUsage");
254
+ case "pi-ai": return t("doctorCheckPiAi");
255
+ default: return id;
256
+ }
257
+ }
258
+ /** 体检的 hints 是稳定 id(见 web-status.ts 的 doctorReport),这里翻成人话。 */
259
+ function doctorHintText(id, t) {
260
+ switch (id) {
261
+ case "no-account": return t("doctorHintNoAccount");
262
+ case "account-stale": return t("doctorHintAccountStale");
263
+ case "account-no-key": return t("doctorHintAccountNoKey");
264
+ case "account-expired": return t("doctorHintAccountExpired");
265
+ case "empty-catalog": return t("doctorHintEmptyCatalog");
266
+ case "usage-missing": return t("doctorHintUsageMissing");
267
+ case "dsh-home-missing": return t("doctorHintDshHome");
268
+ case "pi-ai": return t("doctorHintPiAi");
269
+ default: return t("doctorHintOther", { id });
270
+ }
271
+ }
225
272
  /** 一个 Tab 面板;未选中的用 hidden 留在 DOM 里,草稿和滚动位置都别丢。 */
226
273
  function TabPanel({ id, labelledBy, active, children }) {
227
274
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -753,8 +800,18 @@ function UsageSection({ usage, accounts, t }) {
753
800
  totals: entry.totals
754
801
  }));
755
802
  const today = usage.today;
756
- const hasUsage = usage.allTime.requests > 0 || today.requests > 0;
803
+ const failures = usage.failuresToday ?? {
804
+ total: 0,
805
+ byKind: {}
806
+ };
807
+ const hasUsage = usage.allTime.requests > 0 || today.requests > 0 || failures.total > 0;
757
808
  const hit = hitPercentOf(today);
809
+ const attempts = today.requests + failures.total;
810
+ const failRate = attempts > 0 ? Math.round(failures.total / attempts * 100) : void 0;
811
+ const latency = usage.latencyToday ?? {
812
+ samples: 0,
813
+ overflow: false
814
+ };
758
815
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
759
816
  className: CodeArtsPluginCard_module_css_default.section,
760
817
  children: [
@@ -814,6 +871,43 @@ function UsageSection({ usage, accounts, t }) {
814
871
  className: CodeArtsPluginCard_module_css_default.statValue,
815
872
  children: formatCount(today.requests)
816
873
  })]
874
+ }),
875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
876
+ className: CodeArtsPluginCard_module_css_default.statCard,
877
+ children: [
878
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
879
+ className: CodeArtsPluginCard_module_css_default.statLabel,
880
+ children: t("usageStatFailures")
881
+ }),
882
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
883
+ className: CodeArtsPluginCard_module_css_default.statValue,
884
+ children: failRate === void 0 ? "—" : `${failRate}%`
885
+ }),
886
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
887
+ className: CodeArtsPluginCard_module_css_default.statSub,
888
+ children: t("usageStatFailureCount", { n: formatCount(failures.total) })
889
+ })
890
+ ]
891
+ }),
892
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
893
+ className: CodeArtsPluginCard_module_css_default.statCard,
894
+ children: [
895
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
896
+ className: CodeArtsPluginCard_module_css_default.statLabel,
897
+ children: t("usageStatLatency")
898
+ }),
899
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
900
+ className: CodeArtsPluginCard_module_css_default.statValue,
901
+ children: latency.p95 === void 0 ? "—" : latency.overflow ? ">30 s" : `${formatCount(latency.p95)} ms`
902
+ }),
903
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
904
+ className: CodeArtsPluginCard_module_css_default.statSub,
905
+ children: latency.p50 === void 0 ? t("usageStatLatencyEmpty") : t("usageStatLatencyDetail", {
906
+ p50: formatCount(latency.p50),
907
+ n: formatCount(latency.samples)
908
+ })
909
+ })
910
+ ]
817
911
  })
818
912
  ]
819
913
  }),
@@ -899,7 +993,12 @@ function CodeArtsPluginCard({ t }) {
899
993
  /** 正在实测的模型 id;同一时间只测一个,避免把上游并发槽位占满。 */
900
994
  const [testingId, setTestingId] = (0, react.useState)(null);
901
995
  /** 逐模型的测试结果(通过/失败 + 原因)。 */
902
- const [testResults, setTestResults] = (0, react.useState)({});
996
+ const [testResults, setTestResults] = (0, react.useState)(() => ({ ...lastTestResults }));
997
+ /** 正在提交 paused/pinned 的账号 id。 */
998
+ const [flagBusy, setFlagBusy] = (0, react.useState)(null);
999
+ const [doctor, setDoctor] = (0, react.useState)(null);
1000
+ const [doctorBusy, setDoctorBusy] = (0, react.useState)(false);
1001
+ const [doctorError, setDoctorError] = (0, react.useState)(null);
903
1002
  /** 正在领取的账号 id;批量领取时是 CLAIM_ALL。null 表示没有在飞。 */
904
1003
  const [claimingId, setClaimingId] = (0, react.useState)(null);
905
1004
  /** 逐账号的领取结果文案。 */
@@ -1103,6 +1202,52 @@ function CodeArtsPluginCard({ t }) {
1103
1202
  setBusy(false);
1104
1203
  }
1105
1204
  }
1205
+ /**
1206
+ * 改一个账号的 paused/pinned 标记。
1207
+ *
1208
+ * 暂停 ≠ 删除:凭证还在,只是不参与轮转(比如这个号今天额度用完了,但明天还要用)。
1209
+ * 置顶改变的是 pick() 的优先级,不是顺序本身 —— 取消置顶就回到「最久未用优先」。
1210
+ */
1211
+ async function setAccountFlag(id, patch) {
1212
+ setFlagBusy(id);
1213
+ setMsg(null);
1214
+ try {
1215
+ const res = await fetch("/api/codearts/accounts", {
1216
+ method: "POST",
1217
+ headers: {
1218
+ "Content-Type": "application/json",
1219
+ Accept: "application/json"
1220
+ },
1221
+ body: JSON.stringify({
1222
+ id,
1223
+ ...patch
1224
+ })
1225
+ });
1226
+ if (!res.ok) {
1227
+ const data = await res.json().catch(() => ({}));
1228
+ throw new Error(typeof data.error === "string" ? data.error : `HTTP ${res.status}`);
1229
+ }
1230
+ await refresh();
1231
+ } catch (err) {
1232
+ setMsg(err instanceof Error ? err.message : String(err));
1233
+ } finally {
1234
+ setFlagBusy(null);
1235
+ }
1236
+ }
1237
+ /** 点「体检」拉一次本机报告;只读,不改任何状态。 */
1238
+ async function runDoctor() {
1239
+ setDoctorBusy(true);
1240
+ setDoctorError(null);
1241
+ try {
1242
+ const res = await fetch("/api/codearts/doctor", { headers: { Accept: "application/json" } });
1243
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1244
+ setDoctor(await res.json());
1245
+ } catch (err) {
1246
+ setDoctorError(err instanceof Error ? err.message : String(err));
1247
+ } finally {
1248
+ setDoctorBusy(false);
1249
+ }
1250
+ }
1106
1251
  const all = selection?.choices.length ?? 0;
1107
1252
  const blockedCount = selection?.choices.filter((c) => c.blocked === true).length ?? 0;
1108
1253
  const wire = draft.length === all ? [] : draft;
@@ -1145,8 +1290,16 @@ function CodeArtsPluginCard({ t }) {
1145
1290
  * 上游的清单会列出调不动的模型(81003.401),刷新救不了;只有真发一次最小请求
1146
1291
  * 才知道。测试成功会清掉后端记的「异常」标记,所以结束后重拉一次 selection。
1147
1292
  */
1293
+ function recordTest(id, result) {
1294
+ lastTestResults[id] = result;
1295
+ setTestResults((current) => ({
1296
+ ...current,
1297
+ [id]: result
1298
+ }));
1299
+ }
1148
1300
  async function testModel(id) {
1149
1301
  setTestingId(id);
1302
+ delete lastTestResults[id];
1150
1303
  setTestResults((current) => {
1151
1304
  const next = { ...current };
1152
1305
  delete next[id];
@@ -1163,23 +1316,17 @@ function CodeArtsPluginCard({ t }) {
1163
1316
  });
1164
1317
  const data = await res.json().catch(() => null);
1165
1318
  if (!res.ok) throw new Error(data?.message ?? `HTTP ${res.status}`);
1166
- setTestResults((current) => ({
1167
- ...current,
1168
- [id]: {
1169
- ok: data?.ok === true,
1170
- message: data?.message ?? "",
1171
- ms: data?.ms
1172
- }
1173
- }));
1319
+ recordTest(id, {
1320
+ ok: data?.ok === true,
1321
+ message: data?.message ?? "",
1322
+ ms: data?.ms
1323
+ });
1174
1324
  await refreshSelection();
1175
1325
  } catch (err) {
1176
- setTestResults((current) => ({
1177
- ...current,
1178
- [id]: {
1179
- ok: false,
1180
- message: err instanceof Error ? err.message : String(err)
1181
- }
1182
- }));
1326
+ recordTest(id, {
1327
+ ok: false,
1328
+ message: err instanceof Error ? err.message : String(err)
1329
+ });
1183
1330
  } finally {
1184
1331
  setTestingId(null);
1185
1332
  }
@@ -1498,37 +1645,69 @@ function CodeArtsPluginCard({ t }) {
1498
1645
  }),
1499
1646
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1500
1647
  className: CodeArtsPluginCard_module_css_default.accountInfo,
1501
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1502
- className: CodeArtsPluginCard_module_css_default.accountNameRow,
1503
- children: [
1504
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1505
- className: CodeArtsPluginCard_module_css_default.accountName,
1506
- children: accountName(account)
1507
- }),
1508
- account.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNeedsSignIn") }),
1509
- !account.signable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNoKey") })
1510
- ]
1511
- }), accountLine !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1512
- className: CodeArtsPluginCard_module_css_default.meta,
1513
- children: accountLine
1514
- })]
1648
+ children: [
1649
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1650
+ className: CodeArtsPluginCard_module_css_default.accountNameRow,
1651
+ children: [
1652
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1653
+ className: CodeArtsPluginCard_module_css_default.accountName,
1654
+ children: accountName(account)
1655
+ }),
1656
+ account.paused && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountPaused") }),
1657
+ account.pinned && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
1658
+ tone: "success",
1659
+ children: t("accountPinned")
1660
+ }),
1661
+ account.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNeedsSignIn") }),
1662
+ !account.signable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNoKey") })
1663
+ ]
1664
+ }),
1665
+ accountLine !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1666
+ className: CodeArtsPluginCard_module_css_default.meta,
1667
+ children: accountLine
1668
+ }),
1669
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1670
+ className: CodeArtsPluginCard_module_css_default.meta,
1671
+ children: t("accountToday", {
1672
+ n: formatCount(status?.usage?.byAccountToday[account.id]?.requests ?? 0),
1673
+ failed: formatCount(status?.usage?.failuresByAccountToday?.[account.id] ?? 0)
1674
+ })
1675
+ })
1676
+ ]
1515
1677
  }),
1516
1678
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1517
1679
  className: CodeArtsPluginCard_module_css_default.accountRowActions,
1518
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1519
- variant: account.stale ? "primary" : "outline",
1520
- size: "sm",
1521
- disabled: busy || loginPending,
1522
- onClick: () => void startOAuthLogin(account.id),
1523
- children: reloginId === account.id && loginPending ? t("reloginPending") : t("accountRelogin")
1524
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1525
- variant: "outline",
1526
- size: "sm",
1527
- className: CodeArtsPluginCard_module_css_default.danger,
1528
- disabled: busy || loginPending,
1529
- onClick: () => void removeAccount(account.id),
1530
- children: t("accountRemove")
1531
- })]
1680
+ children: [
1681
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1682
+ variant: "outline",
1683
+ size: "sm",
1684
+ disabled: busy || loginPending || flagBusy === account.id,
1685
+ onClick: () => void setAccountFlag(account.id, { paused: !account.paused }),
1686
+ children: account.paused ? t("accountResume") : t("accountPause")
1687
+ }),
1688
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1689
+ variant: "outline",
1690
+ size: "sm",
1691
+ disabled: busy || loginPending || flagBusy === account.id,
1692
+ onClick: () => void setAccountFlag(account.id, { pinned: !account.pinned }),
1693
+ children: account.pinned ? t("accountUnpin") : t("accountPin")
1694
+ }),
1695
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1696
+ variant: account.stale ? "primary" : "outline",
1697
+ size: "sm",
1698
+ disabled: busy || loginPending,
1699
+ onClick: () => void startOAuthLogin(account.id),
1700
+ children: reloginId === account.id && loginPending ? t("reloginPending") : t("accountRelogin")
1701
+ }),
1702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1703
+ variant: "outline",
1704
+ size: "sm",
1705
+ className: CodeArtsPluginCard_module_css_default.danger,
1706
+ disabled: busy || loginPending,
1707
+ onClick: () => void removeAccount(account.id),
1708
+ children: t("accountRemove")
1709
+ })
1710
+ ]
1532
1711
  })
1533
1712
  ]
1534
1713
  }), credit !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditBlock, {
@@ -1612,7 +1791,7 @@ function CodeArtsPluginCard({ t }) {
1612
1791
  }),
1613
1792
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1614
1793
  className: CodeArtsPluginCard_module_css_default.choices,
1615
- children: selection.choices.map((choice) => {
1794
+ children: (selection.choices ?? []).map((choice) => {
1616
1795
  const result = testResults[choice.id];
1617
1796
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1618
1797
  className: CodeArtsPluginCard_module_css_default.choiceRow,
@@ -1624,6 +1803,17 @@ function CodeArtsPluginCard({ t }) {
1624
1803
  onChange: (on) => setModel(choice.id, on),
1625
1804
  label: modelName(choice)
1626
1805
  }),
1806
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1807
+ className: CodeArtsPluginCard_module_css_default.modelSpec,
1808
+ title: t("modelSpecTitle", {
1809
+ context: choice.contextWindow === void 0 ? "?" : formatCount(choice.contextWindow),
1810
+ output: choice.maxTokens === void 0 ? "?" : formatCount(choice.maxTokens)
1811
+ }),
1812
+ children: t("modelSpec", {
1813
+ context: formatWindow(choice.contextWindow),
1814
+ output: formatWindow(choice.maxTokens)
1815
+ })
1816
+ }),
1627
1817
  choice.benefit === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
1628
1818
  tone: choice.blocked === true ? "warning" : "success",
1629
1819
  children: choice.blocked === true ? t("benefitBlocked") : t("benefit")
@@ -1706,80 +1896,129 @@ function CodeArtsPluginCard({ t }) {
1706
1896
  id: panelId("display"),
1707
1897
  labelledBy: tabId("display"),
1708
1898
  active: activeTab === "display",
1709
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1710
- className: CodeArtsPluginCard_module_css_default.section,
1711
- children: [
1712
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1713
- className: CodeArtsPluginCard_module_css_default.sectionHead,
1714
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1715
- className: CodeArtsPluginCard_module_css_default.sectionLabel,
1716
- children: t("displayTitle")
1717
- })
1718
- }),
1719
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1720
- className: CodeArtsPluginCard_module_css_default.hint,
1721
- children: t("displayHint")
1722
- }),
1723
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1724
- className: CodeArtsPluginCard_module_css_default.choices,
1725
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1726
- className: CodeArtsPluginCard_module_css_default.choiceRow,
1727
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1728
- className: CodeArtsPluginCard_module_css_default.check,
1729
- checked: dock.credits,
1730
- disabled: !dockWritable || dockSaving,
1731
- onChange: (on) => void toggleDock("credits", on),
1732
- label: t("displayCreditsToggle")
1733
- })
1734
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1735
- className: CodeArtsPluginCard_module_css_default.choiceRow,
1736
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1737
- className: CodeArtsPluginCard_module_css_default.check,
1738
- checked: dock.queue,
1739
- disabled: !dockWritable || dockSaving,
1740
- onChange: (on) => void toggleDock("queue", on),
1741
- label: t("displayQueueToggle")
1899
+ children: [
1900
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1901
+ className: CodeArtsPluginCard_module_css_default.section,
1902
+ children: [
1903
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1904
+ className: CodeArtsPluginCard_module_css_default.sectionHead,
1905
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1906
+ className: CodeArtsPluginCard_module_css_default.sectionLabel,
1907
+ children: t("displayTitle")
1742
1908
  })
1743
- })]
1744
- }),
1745
- !dockWritable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1746
- className: CodeArtsPluginCard_module_css_default.hint,
1747
- children: t("displayNotWritable")
1748
- }),
1749
- dockError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1750
- className: CodeArtsPluginCard_module_css_default.error,
1751
- children: t("displayFailed", { message: dockError })
1752
- })
1753
- ]
1754
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1755
- className: CodeArtsPluginCard_module_css_default.section,
1756
- children: [
1757
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1758
- className: CodeArtsPluginCard_module_css_default.sectionHead,
1759
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1760
- className: CodeArtsPluginCard_module_css_default.sectionLabel,
1761
- children: t("displaySidebarTitle")
1909
+ }),
1910
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1911
+ className: CodeArtsPluginCard_module_css_default.hint,
1912
+ children: t("displayHint")
1913
+ }),
1914
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1915
+ className: CodeArtsPluginCard_module_css_default.choices,
1916
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1917
+ className: CodeArtsPluginCard_module_css_default.choiceRow,
1918
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1919
+ className: CodeArtsPluginCard_module_css_default.check,
1920
+ checked: dock.credits,
1921
+ disabled: !dockWritable || dockSaving,
1922
+ onChange: (on) => void toggleDock("credits", on),
1923
+ label: t("displayCreditsToggle")
1924
+ })
1925
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1926
+ className: CodeArtsPluginCard_module_css_default.choiceRow,
1927
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1928
+ className: CodeArtsPluginCard_module_css_default.check,
1929
+ checked: dock.queue,
1930
+ disabled: !dockWritable || dockSaving,
1931
+ onChange: (on) => void toggleDock("queue", on),
1932
+ label: t("displayQueueToggle")
1933
+ })
1934
+ })]
1935
+ }),
1936
+ !dockWritable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1937
+ className: CodeArtsPluginCard_module_css_default.hint,
1938
+ children: t("displayNotWritable")
1939
+ }),
1940
+ dockError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1941
+ className: CodeArtsPluginCard_module_css_default.error,
1942
+ children: t("displayFailed", { message: dockError })
1762
1943
  })
1763
- }),
1764
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1765
- className: CodeArtsPluginCard_module_css_default.hint,
1766
- children: t("displaySidebarHint")
1767
- }),
1768
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1769
- className: CodeArtsPluginCard_module_css_default.choices,
1770
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1771
- className: CodeArtsPluginCard_module_css_default.choiceRow,
1772
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1773
- className: CodeArtsPluginCard_module_css_default.check,
1774
- checked: dock.sidebar,
1775
- disabled: !dockWritable || dockSaving,
1776
- onChange: (on) => void toggleDock("sidebar", on),
1777
- label: t("displaySidebarToggle")
1944
+ ]
1945
+ }),
1946
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1947
+ className: CodeArtsPluginCard_module_css_default.section,
1948
+ children: [
1949
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1950
+ className: CodeArtsPluginCard_module_css_default.sectionHead,
1951
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1952
+ className: CodeArtsPluginCard_module_css_default.sectionLabel,
1953
+ children: t("displaySidebarTitle")
1954
+ })
1955
+ }),
1956
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1957
+ className: CodeArtsPluginCard_module_css_default.hint,
1958
+ children: t("displaySidebarHint")
1959
+ }),
1960
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1961
+ className: CodeArtsPluginCard_module_css_default.choices,
1962
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1963
+ className: CodeArtsPluginCard_module_css_default.choiceRow,
1964
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1965
+ className: CodeArtsPluginCard_module_css_default.check,
1966
+ checked: dock.sidebar,
1967
+ disabled: !dockWritable || dockSaving,
1968
+ onChange: (on) => void toggleDock("sidebar", on),
1969
+ label: t("displaySidebarToggle")
1970
+ })
1778
1971
  })
1779
1972
  })
1780
- })
1781
- ]
1782
- })]
1973
+ ]
1974
+ }),
1975
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1976
+ className: CodeArtsPluginCard_module_css_default.section,
1977
+ children: [
1978
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1979
+ className: CodeArtsPluginCard_module_css_default.sectionHead,
1980
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1981
+ className: CodeArtsPluginCard_module_css_default.sectionLabel,
1982
+ children: t("doctorTitle")
1983
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1984
+ variant: "outline",
1985
+ size: "sm",
1986
+ disabled: doctorBusy,
1987
+ onClick: () => void runDoctor(),
1988
+ children: doctorBusy ? t("doctorRunning") : t("doctorRun")
1989
+ })]
1990
+ }),
1991
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1992
+ className: CodeArtsPluginCard_module_css_default.hint,
1993
+ children: t("doctorHint")
1994
+ }),
1995
+ doctorError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1996
+ className: CodeArtsPluginCard_module_css_default.error,
1997
+ children: t("doctorFailed", { message: doctorError })
1998
+ }),
1999
+ doctor !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2000
+ className: CodeArtsPluginCard_module_css_default.doctorList,
2001
+ children: doctor.checks.map((check) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2002
+ className: CodeArtsPluginCard_module_css_default.doctorRow,
2003
+ children: [
2004
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: check.ok ? "done" : "warning" }),
2005
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2006
+ className: CodeArtsPluginCard_module_css_default.doctorName,
2007
+ children: doctorCheckLabel(check.id, accounts, t)
2008
+ }),
2009
+ check.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2010
+ className: CodeArtsPluginCard_module_css_default.meta,
2011
+ children: check.detail
2012
+ })
2013
+ ]
2014
+ }, check.id))
2015
+ }), doctor.hints.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2016
+ className: CodeArtsPluginCard_module_css_default.hint,
2017
+ children: doctor.hints.map((id) => doctorHintText(id, t)).join(";")
2018
+ })] })
2019
+ ]
2020
+ })
2021
+ ]
1783
2022
  })
1784
2023
  ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1785
2024
  className: CodeArtsPluginCard_module_css_default.section,
@@ -2430,14 +2669,14 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
2430
2669
  document.head.appendChild(tag);
2431
2670
  }
2432
2671
  var CodeArtsPanel_module_css_default = {
2433
- "head": "Z66cgG_head",
2434
2672
  "body": "Z66cgG_body",
2435
2673
  "title": "Z66cgG_title",
2436
- "desc": "Z66cgG_desc",
2437
- "back": "Z66cgG_back",
2438
- "icon": "Z66cgG_icon",
2439
2674
  "page": "Z66cgG_page",
2440
- "backCaret": "Z66cgG_backCaret"
2675
+ "back": "Z66cgG_back",
2676
+ "head": "Z66cgG_head",
2677
+ "desc": "Z66cgG_desc",
2678
+ "backCaret": "Z66cgG_backCaret",
2679
+ "icon": "Z66cgG_icon"
2441
2680
  };
2442
2681
  //#endregion
2443
2682
  //#region src/client/CodeArtsPanel.tsx
@@ -2592,6 +2831,40 @@ const zh = {
2592
2831
  usageTipHit: "命中率",
2593
2832
  usageStatHit: "缓存命中",
2594
2833
  usageStatRequests: "今日请求",
2834
+ usageStatFailures: "今日失败率",
2835
+ usageStatFailureCount: "失败 {n} 次",
2836
+ usageStatLatency: "首字 P95",
2837
+ usageStatLatencyDetail: "P50 {p50} ms · {n} 次",
2838
+ usageStatLatencyEmpty: "还没有成功请求",
2839
+ modelSpec: "{context} 上下文 · {output} 输出",
2840
+ modelSpecTitle: "上游返回的上下文窗口 {context} token,最大输出 {output} token",
2841
+ accountPaused: "已暂停",
2842
+ accountPinned: "已置顶",
2843
+ accountPause: "暂停",
2844
+ accountResume: "恢复",
2845
+ accountPin: "置顶",
2846
+ accountUnpin: "取消置顶",
2847
+ accountToday: "今日 {n} 次 · 失败 {failed}",
2848
+ doctorTitle: "体检",
2849
+ doctorHint: "只查本机状态(版本、凭证、目录、账本、pi-ai 兼容),不联网、不改任何东西。",
2850
+ doctorRun: "开始体检",
2851
+ doctorRunning: "检查中…",
2852
+ doctorFailed: "体检失败:{message}",
2853
+ doctorCheckAccount: "账号",
2854
+ doctorCheckRuntime: "运行环境",
2855
+ doctorCheckAccounts: "账号数量",
2856
+ doctorCheckModels: "模型目录",
2857
+ doctorCheckUsage: "用量账本",
2858
+ doctorCheckPiAi: "pi-ai 兼容",
2859
+ doctorHintNoAccount: "还没有账号:先添加一个,或用 token 手动接入。",
2860
+ doctorHintAccountStale: "有账号需要重新登录。",
2861
+ doctorHintAccountNoKey: "有账号缺少签名私钥,无法自动续期。",
2862
+ doctorHintAccountExpired: "有账号凭证已过期:重新登录即可续上。",
2863
+ doctorHintEmptyCatalog: "模型目录为空:点「重拉目录」或检查上游连通性。",
2864
+ doctorHintUsageMissing: "用量账本没有接上:重启宿主后再看。",
2865
+ doctorHintDshHome: "没有设置 DSH_HOME:凭证和账本会写到默认位置。",
2866
+ doctorHintPiAi: "宿主口的 pi-ai 版本与插件预期不一致,可能影响流式解析。",
2867
+ doctorHintOther: "未知提示:{id}",
2595
2868
  usageRequests: "{n} 次请求",
2596
2869
  usageTrendWeek: "本月 · 每日 token",
2597
2870
  usageTrendHour: "今天 · 逐小时 token",
@@ -2745,6 +3018,40 @@ const en = {
2745
3018
  usageTipHit: "Hit rate",
2746
3019
  usageStatHit: "Cache hit",
2747
3020
  usageStatRequests: "Today requests",
3021
+ usageStatFailures: "Failure rate today",
3022
+ usageStatFailureCount: "{n} failed",
3023
+ usageStatLatency: "First token P95",
3024
+ usageStatLatencyDetail: "P50 {p50} ms · {n} samples",
3025
+ usageStatLatencyEmpty: "No successful request yet",
3026
+ modelSpec: "{context} ctx · {output} out",
3027
+ modelSpecTitle: "Context window {context} tokens, max output {output} tokens reported upstream",
3028
+ accountPaused: "Paused",
3029
+ accountPinned: "Pinned",
3030
+ accountPause: "Pause",
3031
+ accountResume: "Resume",
3032
+ accountPin: "Pin",
3033
+ accountUnpin: "Unpin",
3034
+ accountToday: "Today {n} · {failed} failed",
3035
+ doctorTitle: "Health check",
3036
+ doctorHint: "Local checks only (version, credentials, catalog, ledger, pi-ai compat). No network, changes nothing.",
3037
+ doctorRun: "Run check",
3038
+ doctorRunning: "Checking…",
3039
+ doctorFailed: "Health check failed: {message}",
3040
+ doctorCheckAccount: "Account",
3041
+ doctorCheckRuntime: "Runtime",
3042
+ doctorCheckAccounts: "Account count",
3043
+ doctorCheckModels: "Model catalog",
3044
+ doctorCheckUsage: "Usage ledger",
3045
+ doctorCheckPiAi: "pi-ai compat",
3046
+ doctorHintNoAccount: "No account yet: sign in or paste a token first.",
3047
+ doctorHintAccountStale: "An account needs to sign in again.",
3048
+ doctorHintAccountNoKey: "An account has no signing key and cannot refresh automatically.",
3049
+ doctorHintAccountExpired: "An account credential has expired: sign in again to renew it.",
3050
+ doctorHintEmptyCatalog: "Model catalog is empty: refresh it or check upstream connectivity.",
3051
+ doctorHintUsageMissing: "Usage ledger is not wired: restart the host and retry.",
3052
+ doctorHintDshHome: "DSH_HOME is not set: credentials and ledger fall back to the default location.",
3053
+ doctorHintPiAi: "Host pi-ai version differs from what the plugin expects; streaming parsing may be affected.",
3054
+ doctorHintOther: "Unknown hint: {id}",
2748
3055
  usageRequests: "{n} request(s)",
2749
3056
  usageTrendWeek: "This month · tokens per day",
2750
3057
  usageTrendHour: "Today · tokens by hour",