dsh-multi-router 0.5.2 → 0.5.4

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
@@ -20,22 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/client.jsx
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
+ AccountPool: () => AccountPool,
23
24
  CheckinPanel: () => CheckinPanel,
24
25
  InitialSetup: () => InitialSetup,
25
26
  PluginUpdatesPanel: () => PluginUpdatesPanel,
26
27
  RestartGuidance: () => RestartGuidance,
27
28
  RouterPage: () => RouterPage,
29
+ UsageDetails: () => UsageDetails,
28
30
  apply: () => apply,
29
31
  backendNeedsRestart: () => backendNeedsRestart,
30
32
  inject: () => inject,
31
33
  name: () => name,
32
- readManagementResponse: () => readManagementResponse
34
+ readManagementResponse: () => readManagementResponse,
35
+ usageDateBounds: () => usageDateBounds
33
36
  });
34
37
  module.exports = __toCommonJS(client_exports);
35
38
  var import_react = require("react");
36
39
 
37
40
  // package.json
38
- var version = "0.5.2";
41
+ var version = "0.5.4";
39
42
 
40
43
  // src/client.jsx
41
44
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -91,7 +94,16 @@ var styles = `
91
94
  .mr .box{border:1px solid var(--mr-border);border-radius:12px;padding:20px;background:var(--mr-card)}.mr .metric strong{font-size:26px;line-height:1.3;display:block;margin:8px 0}.mr .metric small{font-size:12px}.mr .item{padding:16px 0;border-top:1px solid var(--mr-border)}.mr .item:first-child{border-top:0}.mr .item:last-child{padding-bottom:0}.mr .badge{border:1px solid var(--mr-border);border-radius:6px;padding:3px 8px;font-size:12px;white-space:nowrap}.mr .empty{padding:24px 0;text-align:center;color:var(--mr-muted)}
92
95
  .mr nav{display:flex;flex-wrap:wrap;gap:8px;border-bottom:1px solid var(--mr-border);padding:18px 0;margin-bottom:20px}.mr button,.mr input,.mr select,.mr textarea,.mr .link{font:inherit;color:inherit;border:1px solid var(--mr-border);border-radius:8px;background:var(--mr-bg);min-height:44px;padding:9px 12px}.mr button,.mr .link{cursor:pointer;transition:background .15s}.mr button:hover,.mr .link:hover{background:var(--mr-card)}.mr button:disabled{opacity:.45;cursor:default}.mr button.primary,.mr button[aria-pressed=true]{background:var(--mr-accent);color:#fff;border-color:transparent}.mr button.quiet{border-color:transparent;background:transparent}.mr :is(button,input,select,textarea,a):focus-visible{outline:2px solid var(--mr-accent);outline-offset:3px}.mr input:not([type=checkbox]),.mr select,.mr textarea{width:100%;min-width:0}.mr input[type=checkbox]{width:18px;height:18px;min-height:0;accent-color:var(--mr-accent)}.mr label{display:flex;flex-direction:column;gap:6px;font-size:13px}.mr label.check{flex-direction:row;align-items:center;gap:8px;min-height:44px}.mr .filter{min-width:170px;max-width:240px}.mr .feedback{padding:12px 16px;border-radius:8px;border:1px solid var(--mr-border)}.mr .error{color:var(--dsw-alias-state-error-primary,#ef9393)}.mr .good{color:var(--dsw-alias-state-success-primary,#77ca9d)}.mr .route-path{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.mr .route-path span{padding:4px 9px;border:1px solid var(--mr-border);border-radius:6px}.mr details{border-top:1px solid var(--mr-border);padding-top:14px}.mr summary{cursor:pointer;color:var(--mr-muted)}.mr progress{width:100%;height:7px;accent-color:var(--mr-accent)}.mr .trend{height:100px;display:flex;align-items:flex-end;gap:8px;margin:16px 0}.mr .trend>div{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;min-width:0}.mr .trend i{display:block;width:100%;min-height:3px;border-radius:4px 4px 0 0;background:var(--mr-accent)}.mr .trend small{font-size:11px;white-space:nowrap}.mr .table{width:100%;border-collapse:collapse;font-size:13px}.mr th,.mr td{text-align:left;border-bottom:1px solid var(--mr-border);padding:10px 8px}.mr th{font-weight:500;color:var(--mr-muted)}.mr .scroll{overflow:auto}.mr .steps{padding:14px 16px;border-left:3px solid var(--mr-accent);background:var(--mr-bg);border-radius:8px}.mr .link{text-decoration:none;display:inline-flex;align-items:center}
93
96
  .mr dialog{color:var(--mr-text);background:var(--mr-bg);border:1px solid var(--mr-border);border-radius:16px;width:min(900px,calc(100vw - 32px));max-height:calc(100vh - 40px);padding:0;box-shadow:0 24px 80px #0008}.mr dialog::backdrop{background:#000a}.mr .modal-head,.mr .modal-foot{padding:18px 24px;background:var(--mr-bg);position:sticky;z-index:1}.mr .modal-head{top:0;border-bottom:1px solid var(--mr-border)}.mr .modal-foot{bottom:0;border-top:1px solid var(--mr-border)}.mr .modal-body{padding:24px}.mr .target-head strong{font-size:14px}.mr .subtle{background:var(--mr-bg)}
94
- @media(max-width:850px){.mr .providers{grid-template-columns:1fr}.mr .metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){.mr .grid{grid-template-columns:1fr}.mr .box{padding:16px}.mr nav{flex-wrap:wrap}.mr .modal-body,.mr .modal-head,.mr .modal-foot{padding:16px}.mr .metrics{gap:8px}.mr .metric strong{font-size:22px}}@media(prefers-reduced-motion:reduce){.mr *{transition:none!important}}
97
+ @media(max-width:850px){.mr .providers{grid-template-columns:1fr}.mr .metrics{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:600px){.mr .grid{grid-template-columns:1fr}.mr .box{padding:16px}.mr nav{flex-wrap:wrap}.mr .modal-body,.mr .modal-head,.mr .modal-foot{padding:16px}.mr .metrics{gap:8px}.mr .metric strong{font-size:22px}}
98
+ .mr{--mr-soft:color-mix(in srgb,var(--mr-text) 3%,var(--mr-card));--mr-selected:color-mix(in srgb,var(--mr-accent) 7%,var(--mr-card));max-width:1280px;min-width:0;line-height:1.55}
99
+ .mr h2{font-size:24px;letter-spacing:-.5px;font-weight:650}.mr h3{font-weight:600}.mr .stack{gap:20px}.mr .row{gap:8px}.mr .box{border-radius:14px;background:var(--mr-card)}.mr .box.stack{gap:16px}
100
+ .mr nav{gap:4px;padding:16px 0 0;margin-bottom:24px}.mr nav button{border:0;border-radius:0;background:transparent;padding:12px 14px;border-bottom:2px solid transparent;color:var(--mr-muted)}.mr nav button[aria-pressed=true]{background:transparent;color:var(--mr-text);border-bottom-color:var(--mr-text);font-weight:600}.mr nav button:hover{background:var(--mr-soft)}
101
+ .mr button.primary{background:var(--mr-text);color:var(--mr-card);border-color:var(--mr-text)}.mr button.primary:hover{opacity:.85}.mr button:active:not(:disabled){filter:brightness(.9)}.mr button.quiet{color:var(--mr-muted)}.mr .badge{border-radius:100px;background:var(--mr-soft);padding:4px 10px}.mr .metric{background:var(--mr-soft)}.mr .metric strong{font-size:28px;font-variant-numeric:tabular-nums;letter-spacing:-.5px;margin:10px 0 4px}.mr .metrics{gap:16px}
102
+ .mr .status{display:inline-flex;align-items:center;gap:7px;font-size:13px;white-space:nowrap}.mr .status i{width:8px;height:8px;border-radius:50%;background:var(--mr-muted);display:inline-block;flex-shrink:0}.mr .status i.good{background:var(--dsw-alias-state-success-primary,#38a16a)}.mr .status i.warn{background:var(--dsw-alias-state-warning-primary,#c48b28)}.mr .warn{color:var(--dsw-alias-state-warning-primary,#c48b28)}
103
+ .mr .table-shell{padding:0;overflow:hidden}.mr .scroll>.table{min-width:760px}.mr .table{font-size:14px}.mr .table th{background:var(--mr-soft);font-size:12px;letter-spacing:.02em;font-weight:500;white-space:nowrap}.mr .table th,.mr .table td{padding:16px 20px;vertical-align:middle}.mr .table tbody tr:last-child td{border-bottom:0}.mr .table td small{display:block;font-size:12px;margin-top:3px}.mr .table td>strong{font-weight:600}.mr .table tr.selected{background:var(--mr-selected)}.mr .table tbody tr:hover{background:var(--mr-soft)}.mr .table .account-name{max-width:230px;overflow-wrap:anywhere}.mr .table .amount{font-size:20px;line-height:1.35;font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}.mr .table .cell-actions{white-space:nowrap;text-align:right}.mr .table .account-check{min-width:44px;min-height:44px;justify-content:center;flex-shrink:0}.mr .table .account-cell{display:flex;gap:10px;align-items:center}.mr .table .account-cell .check{margin-left:-12px}.mr .table .account-cell input{accent-color:var(--mr-text)}.mr .table .row{flex-wrap:nowrap}.mr .section-title{margin-bottom:4px}.mr .toolbar{align-items:flex-end;gap:16px}.mr .search{max-width:280px;flex:1;min-width:160px}.mr .table-footer{padding:14px 20px;background:var(--mr-soft)}.mr .hint{font-size:13px;color:var(--mr-muted)}.mr details.help{border:0;padding:0}.mr details.help>div{padding:12px 0;max-width:76ch}.mr .plan-form{align-items:flex-end;padding:16px 0 0;border-top:1px solid var(--mr-border)}.mr .plan-form .filter{min-width:180px}.mr .steps{border:1px solid var(--mr-border);border-radius:10px;background:var(--mr-soft);padding:14px 16px}.mr .route-path span{background:var(--mr-soft);border-color:transparent;font-size:12px}.mr .route-card details{padding-top:10px}.mr .feedback{margin-bottom:16px}.mr .box .feedback{margin-bottom:0}.mr .scroll{max-width:100%}.mr .scroll:focus-visible{outline:2px solid var(--mr-accent);outline-offset:-3px}
104
+ @media(max-width:850px){.mr .metrics{gap:10px}.mr nav{gap:0}.mr nav button{padding:12px 10px}}@media(max-width:600px){.mr h2{font-size:22px}.mr nav{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))}.mr nav button{padding:10px 4px;font-size:12px;white-space:nowrap}.mr .toolbar>.row{width:100%}.mr .toolbar .search{max-width:none}.mr .metric strong{font-size:24px}.mr .table th,.mr .table td{padding:14px 16px}.mr .filter{max-width:none}.mr .plan-form label{flex:1}.mr .box.table-shell{padding:0}}
105
+
106
+ @media(prefers-reduced-motion:reduce){.mr *{transition:none!important}}
95
107
  `;
96
108
  function apply(ctx) {
97
109
  ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-multi-router" }, RouterPage));
@@ -166,7 +178,7 @@ function RouterPage({ view = "page" }) {
166
178
  const next = await readManagementResponse(res);
167
179
  const { exported, ...state } = next;
168
180
  setData(state);
169
- setNotice(action.action.startsWith("checkins.") || action.action.startsWith("plugins.") || action.action === "setup.dismiss" ? "" : action.action === "accounts.discover" || action.action === "monitor.refresh" ? "\u5DF2\u91CD\u65B0\u68C0\u6D4B\u672C\u673A\u767B\u5F55\u5E76\u5237\u65B0\u7528\u91CF\uFF1B\u68C0\u6D4B\u7ED3\u679C\u89C1\u4E0B\u65B9\u3002" : action.action.includes("refresh") ? "\u5DF2\u5237\u65B0\u3002\u65E0\u6CD5\u83B7\u53D6\u7684\u8D26\u53F7\u4F1A\u4FDD\u7559\u4E0A\u6B21\u6570\u636E\u5E76\u6807\u8BB0\u3002" : action.action === "config.import" ? "\u914D\u7F6E\u5DF2\u5BFC\u5165\u5E76\u751F\u6548\uFF0C\u539F\u914D\u7F6E\u5DF2\u5907\u4EFD\uFF1B\u6A21\u578B\u548C\u7528\u91CF\u6B63\u5728\u540E\u53F0\u66F4\u65B0\u3002" : action.action.startsWith("config.") || action.action === "account.export" ? "" : "\u5DF2\u4FDD\u5B58\u5E76\u751F\u6548\u3002");
181
+ setNotice(action.action === "checkins.settings" ? "\u7B7E\u5230\u8BA1\u5212\u5DF2\u4FDD\u5B58\uFF1B\u4ECA\u65E5\u5DF2\u5904\u7406\u8BB0\u5F55\u4FDD\u6301\u4E0D\u53D8\u3002" : action.action.startsWith("checkins.") || action.action.startsWith("plugins.") || action.action === "setup.dismiss" ? "" : action.action === "accounts.discover" || action.action === "monitor.refresh" ? "\u5DF2\u91CD\u65B0\u68C0\u6D4B\u672C\u673A\u767B\u5F55\u5E76\u5237\u65B0\u7528\u91CF\uFF1B\u68C0\u6D4B\u7ED3\u679C\u89C1\u4E0B\u65B9\u3002" : action.action.includes("refresh") ? "\u5DF2\u5237\u65B0\u3002\u65E0\u6CD5\u83B7\u53D6\u7684\u8D26\u53F7\u4F1A\u4FDD\u7559\u4E0A\u6B21\u6570\u636E\u5E76\u6807\u8BB0\u3002" : action.action === "config.import" ? "\u914D\u7F6E\u5DF2\u5BFC\u5165\u5E76\u751F\u6548\uFF0C\u539F\u914D\u7F6E\u5DF2\u5907\u4EFD\uFF1B\u6A21\u578B\u548C\u7528\u91CF\u6B63\u5728\u540E\u53F0\u66F4\u65B0\u3002" : action.action.startsWith("config.") || action.action === "account.export" ? "" : "\u5DF2\u4FDD\u5B58\u5E76\u751F\u6548\u3002");
170
182
  return next;
171
183
  } catch (e) {
172
184
  setError(e.message);
@@ -186,7 +198,7 @@ function RouterPage({ view = "page" }) {
186
198
  setNotice("");
187
199
  setDraft({ ...structuredClone(route), revision: data.revision, previousId: route.id, strategy: route.strategy ?? "failover", targets: route.targets.map(newTarget) });
188
200
  }
189
- const p = data?.providers.find((p2) => p2.id === provider), accounts = data?.accounts.filter((a) => a.provider === provider) ?? [];
201
+ const p = data?.providers.find((p2) => p2.id === provider);
190
202
  const providerSelect = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
191
203
  "\u4F9B\u5E94\u5546 / \u533A\u57DF",
192
204
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { value: provider, onChange: (e) => {
@@ -199,11 +211,14 @@ function RouterPage({ view = "page" }) {
199
211
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: styles }),
200
212
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
201
213
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
202
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "\u4E09\u5BB6\u8D26\u53F7\u4E0E\u7EDF\u4E00\u8DEF\u7531" }),
203
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: "\u8FDE\u63A5\u8D26\u53F7\uFF0C\u9009\u62E9\u6A21\u578B\uFF0C\u6309\u4F60\u7684\u89C4\u5219\u81EA\u52A8\u5207\u6362\u3002" })
214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "\u8D26\u53F7\u4E0E\u8DEF\u7531" }),
215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: "\u7BA1\u7406\u4E09\u5BB6\u8D26\u53F7\u3001\u6A21\u578B\u4E0E\u7528\u91CF" })
204
216
  ] }),
205
217
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
206
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "badge", children: busy ? "\u6B63\u5728\u5904\u7406\u2026" : "\u672C\u673A\u7BA1\u7406" }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "status", children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", { className: busy ? "warn" : "good", "aria-hidden": "true" }),
220
+ busy ? "\u6B63\u5728\u5904\u7406\u2026" : "\u672C\u673A\u8FD0\u884C"
221
+ ] }),
207
222
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
208
223
  void load().catch((e) => setError(e.message));
209
224
  }, children: "\u5237\u65B0\u9762\u677F" })
@@ -224,84 +239,7 @@ function RouterPage({ view = "page" }) {
224
239
  tab === "plugins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluginUpdatesPanel, { data: data.pluginUpdates, busy, act }),
225
240
  tab === "checkins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinPanel, { data, busy, act }),
226
241
  tab === "usage" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UsageDetails, { data, busy, act }),
227
- tab === "accounts" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
228
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
229
- providerSelect,
230
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
231
- !provider.startsWith("qoder") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
232
- void act({ action: "accounts.discover", provider });
233
- }, children: "\u91CD\u65B0\u68C0\u6D4B\u672C\u673A\u767B\u5F55" }),
234
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
235
- void act({ action: "monitor.refresh", provider });
236
- }, children: "\u5237\u65B0\u767B\u5F55\u4E0E\u7528\u91CF" }),
237
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "primary", disabled: busy, onClick: () => openAccount("add"), children: "\u6DFB\u52A0\u8D26\u53F7" })
238
- ] })
239
- ] }),
240
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "steps", children: "WorkBuddy \u4E0E Trae \u542F\u52A8\u65F6\u81EA\u52A8\u8BFB\u53D6\u672C\u673A\u5DF2\u767B\u5F55\u8D26\u53F7\uFF0C\u6BCF\u5206\u949F\u91CD\u65B0\u68C0\u6D4B\uFF1BTrae \u81EA\u52A8\u8BC6\u522B CN\u3001Global \u4E0E SOLO\u3002\u4E5F\u53EF\u6DFB\u52A0\u624B\u52A8\u51ED\u8BC1\u6216\u5BFC\u5165\u5176\u5B83\u8BBE\u5907\u8D26\u53F7\u3002\u5404\u8D26\u53F7\u4FDD\u7559\u72EC\u7ACB\u526F\u672C\u3002" }),
241
- data.localDiscovery?.filter((s) => s.provider === provider).map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
242
- s.state === "found" ? "\u5DF2\u53D1\u73B0\u672C\u673A\u5BA2\u6237\u7AEF\u767B\u5F55\u3002" : s.state === "unreadable" ? "\u672C\u673A\u767B\u5F55\u6587\u4EF6\u65E0\u6CD5\u8BFB\u53D6\u3002\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u91CD\u65B0\u767B\u5F55\u540E\u91CD\u8BD5\uFF0C\u6216\u5728\u300C\u6DFB\u52A0\u8D26\u53F7\u300D\u4E2D\u624B\u52A8\u586B\u5199\u51ED\u8BC1\u3002" : "\u672A\u627E\u5230\u672C\u673A\u5DF2\u767B\u5F55\u8D26\u53F7\u3002\u8BF7\u5148\u5B89\u88C5\u5E76\u767B\u5F55\u5BF9\u5E94\u533A\u57DF\u7684\u5B98\u65B9\u5BA2\u6237\u7AEF\uFF0C\u7136\u540E\u91CD\u65B0\u68C0\u6D4B\u3002",
243
- " \xB7 ",
244
- when(s.checkedAt)
245
- ] }, s.provider)),
246
- !accounts.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "box empty", children: provider.startsWith("qoder") ? "Qoder \u9700\u8981\u6DFB\u52A0 PAT\uFF0C\u6216\u8BFB\u53D6\u539F\u8FDE\u63A5\u5668\u5DF2\u4FDD\u5B58\u7684 PAT\u3002" : `\u8FD8\u6CA1\u6709 ${p?.name} \u8D26\u53F7\u3002\u767B\u5F55\u5B98\u65B9\u5BA2\u6237\u7AEF\u540E\u4F1A\u81EA\u52A8\u68C0\u6D4B\uFF0C\u4E5F\u53EF\u70B9\u51FB\u300C\u6DFB\u52A0\u8D26\u53F7\u300D\u624B\u52A8\u5BFC\u5165\u3002` }),
247
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid", children: accounts.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
248
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
249
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
250
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: a.name }),
251
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mono muted", children: a.id })
252
- ] }),
253
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "badge", children: a.status.cooldowns.length ? "\u51B7\u5374\u4E2D" : a.enabled ? "\u5DF2\u542F\u7528" : "\u5DF2\u505C\u7528" })
254
- ] }),
255
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
256
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: a.login?.state === "valid" ? "good" : "muted", children: loginNames[a.login?.state] || "\u5C1A\u672A\u67E5\u8BE2" }),
257
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
258
- a.login?.name || "\u70B9\u51FB\u5237\u65B0\u83B7\u53D6\u8EAB\u4EFD",
259
- a.login?.expiresAt ? ` \xB7 \u6709\u6548\u81F3 ${when(a.login.expiresAt)}` : a.login?.kind === "PAT" ? " \xB7 PAT \u6709\u6548\u671F\u7531\u5E73\u53F0\u7BA1\u7406" : ""
260
- ] })
261
- ] }),
262
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
263
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
264
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: "\u5E73\u53F0\u5269\u4F59\u989D\u5EA6" }),
265
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
266
- a.usage?.balance?.unlimited ? "\u4E0D\u9650\u91CF" : fmt(a.usage?.balance?.remaining),
267
- " ",
268
- a.usage?.balance?.unit === "credits" ? "\u79EF\u5206" : ""
269
- ] })
270
- ] }),
271
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
272
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: "\u672C\u63D2\u4EF6\u7D2F\u8BA1 Token" }),
273
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: fmt(a.usage?.tokens || 0) })
274
- ] })
275
- ] }),
276
- a.usage?.balance?.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice error", children: [
277
- "\u7528\u91CF\u8BFB\u53D6\u5931\u8D25\uFF0C\u663E\u793A\u4E0A\u6B21\u6570\u636E \xB7 ",
278
- when(a.usage.balance.fetchedAt)
279
- ] }),
280
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
281
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "notice", children: [
282
- a.modelCount,
283
- " \u4E2A\u6A21\u578B \xB7 ",
284
- fmt(a.usage?.requests || 0),
285
- " \u6B21\u8BF7\u6C42"
286
- ] }),
287
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => openAccount("edit", a), children: "\u767B\u5F55\u8BE6\u60C5 / \u7BA1\u7406" })
288
- ] }),
289
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
290
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy || i === 0, onClick: () => {
291
- void act({ action: "account.move", id: a.id, direction: -1 });
292
- }, children: "\u524D\u79FB" }),
293
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy || i === accounts.length - 1, onClick: () => {
294
- void act({ action: "account.move", id: a.id, direction: 1 });
295
- }, children: "\u540E\u79FB" }),
296
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
297
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", disabled: busy, checked: a.enabled, onChange: (e) => {
298
- void act({ action: "account.update", id: a.id, enabled: e.target.checked });
299
- } }),
300
- "\u53C2\u4E0E\u8DEF\u7531"
301
- ] })
302
- ] })
303
- ] }, a.id)) })
304
- ] }),
242
+ tab === "accounts" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccountPool, { data, provider, providerSelect, busy, act, manage: (a) => openAccount("edit", a), add: () => openAccount("add") }, provider),
305
243
  tab === "models" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
306
244
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
307
245
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
@@ -382,7 +320,7 @@ function RouterPage({ view = "page" }) {
382
320
  ] })
383
321
  ] }),
384
322
  data.routes.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "box empty", children: "\u5148\u6DFB\u52A0\u4E09\u5BB6\u5171\u6709\u6A21\u578B\u9884\u914D\u7F6E\uFF0C\u6216\u521B\u5EFA\u4F60\u81EA\u5DF1\u7684\u8DEF\u7531\u3002" }),
385
- data.routes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
323
+ data.routes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack route-card", children: [
386
324
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
387
325
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: r.name }) }),
388
326
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
@@ -415,10 +353,13 @@ function RouterPage({ view = "page" }) {
415
353
  ] })
416
354
  ] }),
417
355
  r.freeOnly && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FreeStatus, { route: r, busy, act }),
418
- !r.freeOnly && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
419
- "\u63A8\u7406\u6A21\u5F0F\uFF1A\u5E73\u53F0\u9ED8\u8BA4",
420
- r.reasoning?.supportedEfforts?.length ? `\u3001${r.reasoning.supportedEfforts.map((e) => effortNames[e] || e).join("\u3001")}` : "\uFF08\u5E73\u53F0\u672A\u58F0\u660E\u53EF\u8C03\u6863\u4F4D\uFF09",
421
- "\u3002\u9009\u62E9\u6863\u4F4D\u540E\uFF0C\u53EA\u5728\u652F\u6301\u8BE5\u6863\u4F4D\u7684\u76EE\u6807\u95F4\u5207\u6362\u3002"
356
+ !r.freeOnly && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "\u63A8\u7406\u6A21\u5F0F\u4E0E\u517C\u5BB9\u6027" }),
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
359
+ "\u63A8\u7406\u6A21\u5F0F\uFF1A\u5E73\u53F0\u9ED8\u8BA4",
360
+ r.reasoning?.supportedEfforts?.length ? `\u3001${r.reasoning.supportedEfforts.map((e) => effortNames[e] || e).join("\u3001")}` : "\uFF08\u5E73\u53F0\u672A\u58F0\u660E\u53EF\u8C03\u6863\u4F4D\uFF09",
361
+ "\u3002\u9009\u62E9\u6863\u4F4D\u540E\uFF0C\u53EA\u5728\u652F\u6301\u8BE5\u6863\u4F4D\u7684\u76EE\u6807\u95F4\u5207\u6362\u3002"
362
+ ] })
422
363
  ] }),
423
364
  r.preferExpiringCredits && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExpiryStatus, { route: r, act, busy, revision: data.revision })
424
365
  ] }, r.id)),
@@ -475,22 +416,168 @@ function RouterPage({ view = "page" }) {
475
416
  }, error, notice }) })
476
417
  ] });
477
418
  }
419
+ var displayName = (a) => (a?.name || a?.id || "\u672A\u77E5\u8D26\u53F7").replace(/(?<!\d)(\+?\d{2,3})\d{3,8}(\d{4})(?!\d)/g, "$1****$2");
420
+ var resultLabels = { claimed: "\u7B7E\u5230\u6210\u529F", "already-claimed": "\u5DF2\u9886\u53D6", "no-campaign": "\u65E0\u6D3B\u52A8", retryable: "\u67E5\u8BE2\u5931\u8D25", "before-window": "\u7A97\u53E3\u672A\u5F00", "auth-invalid": "\u4EE4\u724C\u5931\u6548", paused: "\u5E73\u53F0\u6682\u505C", uncertain: "\u5F85\u6838\u5BF9", "device-used": "\u8BBE\u5907\u5DF2\u53C2\u4E0E" };
421
+ function Balance({ account }) {
422
+ const b = account.usage?.balance, now = Date.now();
423
+ const expiring = b?.unit === "credits" && !b.error ? (b.packages || []).filter((p) => Number.isFinite(p.remaining) && p.remaining > 0 && p.expiresAt > now && p.expiresAt <= now + 3 * 864e5).reduce((n, p) => n + p.remaining, 0) : 0;
424
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "amount", children: [
426
+ b?.unlimited ? "\u4E0D\u9650\u91CF" : fmt(b?.remaining),
427
+ b?.unit === "credits" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", style: { display: "inline", marginLeft: 5 }, children: "\u79EF\u5206" })
428
+ ] }),
429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: b?.error ? "error" : expiring ? "warn" : "muted", children: b?.error ? "\u67E5\u8BE2\u5931\u8D25 \xB7 \u4FDD\u7559\u4E0A\u6B21\u4F59\u989D" : expiring ? `${fmt(expiring)} \u79EF\u5206 3 \u5929\u5185\u5230\u671F` : b?.fetchedAt ? `\u66F4\u65B0\u4E8E ${when(b.fetchedAt)}` : "\u7B49\u5F85\u5237\u65B0\u5E73\u53F0\u7528\u91CF" })
430
+ ] });
431
+ }
432
+ function CheckinResult({ row, compact = false }) {
433
+ const last = row?.last, today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" });
434
+ const current = last?.day === today;
435
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
436
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: current && ["claimed", "already-claimed"].includes(last.status) ? "good" : last && ["auth-invalid", "paused", "uncertain", "retryable"].includes(last.status) ? "warn" : "muted", children: !row?.supported ? "\u6682\u4E0D\u652F\u6301" : current || last?.status === "auth-invalid" ? resultLabels[last.status] || "\u5DF2\u5904\u7406" : "\u4ECA\u65E5\u672A\u7B7E\u5230" }),
437
+ (!compact || current && last.amount !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: current && last.amount !== void 0 ? `\u672C\u6B21 ${fmt(last.amount)} \u79EF\u5206` : row?.auto ? "\u81EA\u52A8\u7B7E\u5230\u5DF2\u5F00\u542F" : "\u81EA\u52A8\u7B7E\u5230\u672A\u5F00\u542F" })
438
+ ] });
439
+ }
440
+ function AccountPool({ data, provider, providerSelect, busy, act, manage, add }) {
441
+ const [search, setSearch] = (0, import_react.useState)("");
442
+ const accounts = data.accounts.filter((a) => a.provider === provider), chosen = accounts.filter((a) => a.enabled !== false).length;
443
+ const visible = accounts.filter((a) => `${a.name} ${a.id}`.toLowerCase().includes(search.toLowerCase()));
444
+ const rows = data.checkins?.accounts || [], eligible = rows.filter((r) => accounts.some((a) => a.id === r.id && a.enabled !== false) && r.ready);
445
+ const setAll = (enabled) => {
446
+ void act({ action: "accounts.enabled", provider, enabled });
447
+ };
448
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
449
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
450
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
451
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "section-title", children: "\u8D26\u53F7\u6C60" }),
452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "muted", children: [
453
+ accounts.length,
454
+ " \u4E2A\u8D26\u53F7 \xB7 ",
455
+ chosen,
456
+ " \u4E2A\u53C2\u4E0E\u8DEF\u7531"
457
+ ] })
458
+ ] }),
459
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "primary", disabled: busy, onClick: add, children: "\u6DFB\u52A0\u8D26\u53F7" })
460
+ ] }),
461
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar toolbar", children: [
462
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
463
+ providerSelect,
464
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "search", children: [
465
+ "\u641C\u7D22\u8D26\u53F7",
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "search", value: search, placeholder: "\u540D\u79F0\u6216\u8D26\u53F7 ID", onChange: (e) => setSearch(e.target.value) })
467
+ ] })
468
+ ] }),
469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
470
+ !provider.startsWith("qoder") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
471
+ void act({ action: "accounts.discover", provider });
472
+ }, children: "\u83B7\u53D6\u672C\u673A\u767B\u5F55" }),
473
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
474
+ void act({ action: "monitor.refresh", provider });
475
+ }, children: "\u5237\u65B0\u72B6\u6001\u4E0E\u7528\u91CF" })
476
+ ] })
477
+ ] }),
478
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
479
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "hint", children: "\u52FE\u9009\u7684\u8D26\u53F7\u53C2\u4E0E\u8DEF\u7531\uFF1B\u81EA\u52A8\u7B7E\u5230\u5728\u300C\u79EF\u5206\u7B7E\u5230\u300D\u4E2D\u5355\u72EC\u8BBE\u7F6E\u3002" }),
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "notice", children: [
482
+ "\u5DF2\u9009 ",
483
+ chosen,
484
+ " / ",
485
+ accounts.length
486
+ ] }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy || !accounts.length || chosen === accounts.length, onClick: () => setAll(true), children: "\u5168\u9009" }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy || !chosen, onClick: () => setAll(false), children: "\u5168\u4E0D\u9009" }),
489
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { disabled: busy || data.checkins?.running || data.checkins?.error || !eligible.length, onClick: () => {
490
+ void act({ action: "checkins.run", ids: eligible.map((r) => r.id) });
491
+ }, children: [
492
+ "\u7B7E\u5230\u53EF\u7528\u8D26\u53F7\uFF08",
493
+ eligible.length,
494
+ "\uFF09"
495
+ ] })
496
+ ] })
497
+ ] }),
498
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "box table-shell", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "scroll", role: "region", "aria-label": "\u8D26\u53F7\u6C60\u5217\u8868", tabIndex: "0", children: [
499
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "table", children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
501
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u8D26\u53F7 / \u8DEF\u7531\u53C2\u4E0E" }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u5E73\u53F0\u79EF\u5206" }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u6A21\u578B\u4E0E\u8C03\u7528" }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u4ECA\u65E5\u7B7E\u5230" }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "cell-actions", children: "\u7BA1\u7406" })
506
+ ] }) }),
507
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: visible.map((a) => {
508
+ const cooldown = a.status?.cooldowns || [], active = a.status?.activeFor?.length, enabled = a.enabled !== false;
509
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: enabled ? "selected" : "", children: [
510
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "account-cell", children: [
511
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "check account-check", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `${displayName(a)} \u53C2\u4E0E\u8DEF\u7531`, type: "checkbox", disabled: busy, checked: enabled, onChange: (e) => {
512
+ void act({ action: "account.update", id: a.id, enabled: e.target.checked });
513
+ } }) }),
514
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "account-name", children: [
515
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: displayName(a) }),
516
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "status", children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", { className: !enabled ? "" : cooldown.length ? "warn" : "good", "aria-hidden": "true" }),
518
+ !enabled ? "\u672A\u5165\u6C60" : active ? "\u6B63\u5728\u8C03\u7528" : cooldown.length ? "\u90E8\u5206\u8DEF\u7531\u51B7\u5374\u4E2D" : "\u5DF2\u5728\u6C60\u4E2D"
519
+ ] }) }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: loginNames[a.login?.state] || "\u5C1A\u672A\u67E5\u8BE2\u767B\u5F55" })
521
+ ] })
522
+ ] }) }),
523
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Balance, { account: a }) }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
525
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
526
+ fmt(a.modelCount || 0),
527
+ " \u4E2A\u76EE\u5F55\u6A21\u578B"
528
+ ] }),
529
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { className: "muted", children: [
530
+ fmt(a.usage?.requests || 0),
531
+ " \u6B21\u8C03\u7528 \xB7 ",
532
+ fmt(a.usage?.tokens || 0),
533
+ " Token"
534
+ ] }),
535
+ cooldown.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { className: "warn", children: [
536
+ "\u6700\u957F\u7EA6 ",
537
+ Math.ceil(Math.max(...cooldown.map((c) => c.remainingMs)) / 6e4),
538
+ " \u5206\u949F\u540E\u6062\u590D"
539
+ ] })
540
+ ] }),
541
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinResult, { row: rows.find((r) => r.id === a.id) }) }),
542
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cell-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => manage(a), children: "\u7BA1\u7406\u8D26\u53F7" }) })
543
+ ] }, a.id);
544
+ }) })
545
+ ] }),
546
+ !visible.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "empty", children: accounts.length ? "\u6CA1\u6709\u5339\u914D\u7684\u8D26\u53F7\uFF0C\u8BF7\u8C03\u6574\u641C\u7D22\u3002" : "\u8FD8\u6CA1\u6709\u8D26\u53F7\uFF0C\u70B9\u51FB\u300C\u6DFB\u52A0\u8D26\u53F7\u300D\u83B7\u53D6\u767B\u5F55\u6216\u586B\u5199\u51ED\u8BC1\u3002" })
547
+ ] }) }),
548
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "help", children: [
549
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "\u672C\u673A\u8D26\u53F7\u83B7\u53D6\u4E0E\u51ED\u8BC1\u8BF4\u660E" }),
550
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
551
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "WorkBuddy \u4E0E Trae \u542F\u52A8\u65F6\u81EA\u52A8\u8BFB\u53D6\u672C\u673A\u5DF2\u767B\u5F55\u8D26\u53F7\uFF0C\u6BCF\u5206\u949F\u91CD\u65B0\u68C0\u6D4B\uFF1BTrae \u81EA\u52A8\u8BC6\u522B CN\u3001Global \u4E0E SOLO\u3002\u4E5F\u53EF\u6DFB\u52A0\u624B\u52A8\u51ED\u8BC1\u6216\u5BFC\u5165\u5176\u5B83\u8BBE\u5907\u8D26\u53F7\uFF0C\u5404\u8D26\u53F7\u72EC\u7ACB\u4FDD\u5B58\u3002Qoder \u9700\u6DFB\u52A0 PAT\u3002" }),
552
+ data.localDiscovery?.filter((s) => s.provider === provider).map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
553
+ s.state === "found" ? "\u5DF2\u53D1\u73B0\u672C\u673A\u5BA2\u6237\u7AEF\u767B\u5F55\u3002" : s.state === "unreadable" ? "\u65E0\u6CD5\u8BFB\u53D6\u672C\u673A\u767B\u5F55\u6587\u4EF6\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u91CD\u65B0\u767B\u5F55\uFF0C\u6216\u624B\u52A8\u586B\u5199\u51ED\u8BC1\u3002" : "\u672A\u627E\u5230\u672C\u673A\u767B\u5F55\uFF0C\u8BF7\u5148\u767B\u5F55\u5BF9\u5E94\u533A\u57DF\u7684\u5B98\u65B9\u5BA2\u6237\u7AEF\u3002",
554
+ " \xB7 ",
555
+ when(s.checkedAt)
556
+ ] }, s.provider))
557
+ ] })
558
+ ] })
559
+ ] });
560
+ }
478
561
  function CheckinPanel({ data, busy, act }) {
479
562
  const info = data.checkins || {}, rows = info.accounts || [], today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" });
480
- const beforeWindow = Date.now() < Date.parse(`${today}T10:05:00+08:00`);
563
+ const saved = info.settings ?? { mode: "scheduled", time: "10:05" };
564
+ const [schedule, setSchedule] = (0, import_react.useState)(saved);
565
+ (0, import_react.useEffect)(() => {
566
+ setSchedule(saved);
567
+ }, [saved.mode, saved.time]);
568
+ const changed = schedule.mode !== saved.mode || schedule.time !== saved.time;
481
569
  const blocked = busy || info.running || !!info.error;
482
- const eligible = rows.filter((r) => r.supported && !r.paused && data.accounts.find((a) => a.id === r.id)?.enabled && (r.last?.day !== today || r.last?.retryReady));
483
- const ready = (r) => eligible.includes(r) && !beforeWindow;
484
- const displayName = (a) => a?.name?.replace(/(1\d{2})\d{4}(\d{4})/g, "$1****$2");
485
- const resultLabels = { claimed: "\u6210\u529F", "already-claimed": "\u5DF2\u9886\u53D6", "no-campaign": "\u65E0\u6D3B\u52A8", retryable: "\u67E5\u8BE2\u5931\u8D25", "before-window": "\u7A97\u53E3\u672A\u5F00", "auth-invalid": "\u4EE4\u724C\u5931\u6548", paused: "\u5E73\u53F0\u6682\u505C", uncertain: "\u5F85\u6838\u5BF9", "device-used": "\u8BBE\u5907\u5DF2\u53C2\u4E0E" };
570
+ const eligible = rows.filter((r) => r.supported && !r.paused && data.accounts.find((a) => a.id === r.id)?.enabled && r.ready === true);
571
+ const ready = (r) => eligible.includes(r);
486
572
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
487
573
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
488
574
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
489
575
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
490
576
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u6BCF\u65E5\u79EF\u5206\u7B7E\u5230" }),
491
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: info.schedule })
577
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: info.schedule }),
578
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u81EA\u52A8\u7B7E\u5230\u9ED8\u8BA4\u5173\u95ED\uFF0C\u8BF7\u5728\u4E0B\u65B9\u9010\u4E2A\u5F00\u542F\u3002" })
492
579
  ] }),
493
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "primary", disabled: blocked || beforeWindow || !eligible.length, onClick: () => {
580
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "primary", disabled: blocked || !eligible.length, onClick: () => {
494
581
  void act({ action: "checkins.run", ids: eligible.map((r) => r.id) });
495
582
  }, children: [
496
583
  "\u7B7E\u5230\u5168\u90E8\u53EF\u7528\u8D26\u53F7\uFF08",
@@ -498,8 +585,31 @@ function CheckinPanel({ data, busy, act }) {
498
585
  "\uFF09"
499
586
  ] })
500
587
  ] }),
501
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "steps", children: "\u81EA\u52A8\u7B7E\u5230\u9ED8\u8BA4\u5173\u95ED\uFF0C\u6309\u8D26\u53F7\u5F00\u542F\u3002\u5148\u67E5\u9886\u53D6\u72B6\u6001\u3001\u4E32\u884C\u63D0\u4EA4\uFF0C\u8D26\u53F7\u95F4\u9694\u81F3\u5C11 10 \u79D2\uFF1B\u6BCF\u4E2A\u8D26\u53F7\u6BCF\u5929\u6700\u591A\u63D0\u4EA4\u4E00\u6B21\u9886\u53D6\u3002\u786E\u8BA4\u5C1A\u672A\u63D0\u4EA4\u7684\u67E5\u8BE2\u5931\u8D25\uFF0C20:05 \u540E\u6700\u591A\u8865\u67E5\u4E00\u6B21\uFF1B\u5DF2\u9886\u53D6\u3001\u65E0\u6D3B\u52A8\u548C\u7ED3\u679C\u4E0D\u660E\u7684\u8D26\u53F7\u8DF3\u8FC7\u3002\u9047\u5230\u9A8C\u8BC1\u3001\u9650\u6D41\u6216\u8BBE\u5907\u9650\u5236\u5C31\u505C\u6B62\uFF0C\u4E0D\u4F1A\u4FEE\u6539\u8BBE\u5907\u8EAB\u4EFD\u6216\u5207\u6362\u8D26\u53F7\u91CD\u8BD5\u3002" }),
502
- beforeWindow && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u4ECA\u65E5\u7B7E\u5230\u5C06\u5728\u5317\u4EAC\u65F6\u95F4 10:05 \u540E\u5F00\u653E\u3002DSH \u5173\u95ED\u671F\u95F4\u4E0D\u4F1A\u6267\u884C\uFF0C\u542F\u7528\u81EA\u52A8\u7B7E\u5230\u7684\u8D26\u53F7\u4F1A\u5728\u4E0B\u6B21\u542F\u52A8\u540E\u8865\u67E5\u3002" }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "row plan-form", onSubmit: (e) => {
589
+ e.preventDefault();
590
+ void act({ action: "checkins.settings", schedule });
591
+ }, children: [
592
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
593
+ "\u81EA\u52A8\u7B7E\u5230\u65B9\u5F0F",
594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { "aria-label": "\u81EA\u52A8\u7B7E\u5230\u65B9\u5F0F", value: schedule.mode, disabled: blocked, onChange: (e) => setSchedule({ ...schedule, mode: e.target.value }), children: [
595
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "startup", children: "\u6BCF\u65E5\u542F\u52A8\u65F6\u7B7E\u5230" }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "scheduled", children: "\u6BCF\u5929\u5B9A\u65F6\u7B7E\u5230" })
597
+ ] })
598
+ ] }),
599
+ schedule.mode === "scheduled" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
600
+ "\u7B7E\u5230\u65F6\u95F4\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09",
601
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": "\u7B7E\u5230\u65F6\u95F4\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09", type: "time", required: true, value: schedule.time, disabled: blocked, onChange: (e) => setSchedule({ ...schedule, time: e.target.value }) })
602
+ ] }),
603
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked || !changed, children: "\u4FDD\u5B58\u7B7E\u5230\u8BA1\u5212" })
604
+ ] }),
605
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "help", children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "\u6267\u884C\u89C4\u5219\u3001\u8865\u67E5\u4E0E\u8BBE\u5907\u9650\u5236" }),
607
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
608
+ " ",
609
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u81EA\u52A8\u7B7E\u5230\u9ED8\u8BA4\u5173\u95ED\uFF0C\u6309\u8D26\u53F7\u5F00\u542F\u3002\u5148\u67E5\u9886\u53D6\u72B6\u6001\u3001\u4E32\u884C\u63D0\u4EA4\uFF0C\u8D26\u53F7\u95F4\u9694\u81F3\u5C11 10 \u79D2\uFF1B\u6BCF\u4E2A\u8D26\u53F7\u6BCF\u5929\u6700\u591A\u63D0\u4EA4\u4E00\u6B21\u9886\u53D6\u3002\u786E\u8BA4\u5C1A\u672A\u63D0\u4EA4\u7684\u67E5\u8BE2\u5931\u8D25\uFF0C20:05 \u540E\u6700\u591A\u8865\u67E5\u4E00\u6B21\uFF1B\u5DF2\u9886\u53D6\u3001\u65E0\u6D3B\u52A8\u548C\u7ED3\u679C\u4E0D\u660E\u7684\u8D26\u53F7\u8DF3\u8FC7\u3002\u9047\u5230\u9A8C\u8BC1\u3001\u9650\u6D41\u6216\u8BBE\u5907\u9650\u5236\u5C31\u505C\u6B62\uFF0C\u4E0D\u4F1A\u4FEE\u6539\u8BBE\u5907\u8EAB\u4EFD\u6216\u5207\u6362\u8D26\u53F7\u91CD\u8BD5\u3002" }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u542F\u52A8\u6A21\u5F0F\u5728\u5F53\u5929\u9996\u6B21\u8FD0\u884C\u65F6\u6267\u884C\uFF0C\u6301\u7EED\u8FD0\u884C\u5219\u65B0\u4E00\u5929\u81EA\u52A8\u6267\u884C\uFF1B\u5B9A\u65F6\u6A21\u5F0F\u5728\u8BBE\u5B9A\u65F6\u95F4\u540E\u6267\u884C\uFF0C\u9519\u8FC7\u65F6\u4E0B\u6B21\u542F\u52A8\u8865\u67E5\u3002Qoder \u6700\u65E9\u5317\u4EAC\u65F6\u95F4 10:05 \u67E5\u8BE2\u5F53\u65E5\u6D3B\u52A8\u3002DSH \u5173\u95ED\u671F\u95F4\u4E0D\u6267\u884C\uFF0C\u8FD0\u884C\u65F6\u7EA6\u4E00\u5206\u949F\u5185\u89E6\u53D1\u3002\u4FEE\u6539\u8BA1\u5212\u3001\u5237\u65B0\u9762\u677F\u6216\u91CD\u542F\u4E0D\u4F1A\u6E05\u9664\u5DF2\u5904\u7406\u8BB0\u5F55\uFF1B\u4EE4\u724C\u5931\u6548\u540E\u8BF7\u66F4\u65B0\u51ED\u8BC1\u518D\u6062\u590D\u3002" })
611
+ ] })
612
+ ] }),
503
613
  info.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: "error", children: info.error }),
504
614
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", children: info.running ? `\u6B63\u5728\u5904\u7406 ${displayName(data.accounts.find((a) => a.id === info.current)) || "\u7B7E\u5230\u961F\u5217"}\u2026` : "\u7B7E\u5230\u7ED3\u679C\u548C\u9886\u53D6\u79EF\u5206\u4EE5\u4E0B\u65B9\u5E73\u53F0\u54CD\u5E94\u4E3A\u51C6\u3002" }),
505
615
  info.report && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
@@ -526,34 +636,46 @@ function CheckinPanel({ data, busy, act }) {
526
636
  void act({ action: "checkins.resume", provider: p.id });
527
637
  }, children: "\u6211\u5DF2\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406\uFF0C\u6062\u590D\u540E\u7EED\u7B7E\u5230" })
528
638
  ] }),
529
- accounts.map((a) => {
530
- const r = rows.find((r2) => r2.id === a.id) || {}, last = r.last?.day === today ? r.last : void 0;
531
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "item stack", children: [
532
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
533
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "scroll", role: "region", "aria-label": `${p.name} \u7B7E\u5230\u8BB0\u5F55`, tabIndex: "0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "table", children: [
640
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
641
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u8D26\u53F7" }),
642
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u81EA\u52A8\u7B7E\u5230" }),
643
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u4ECA\u65E5\u7ED3\u679C" }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u6700\u8FD1\u8BB0\u5F55" }),
645
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "cell-actions", children: "\u64CD\u4F5C" })
646
+ ] }) }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: accounts.map((a) => {
648
+ const r = rows.find((r2) => r2.id === a.id) || {}, last = r.last?.day === today ? r.last : void 0;
649
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: info.current === a.id ? "selected" : "", children: [
650
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
534
651
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: displayName(a) }),
535
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
536
- r.last ? `${r.last.day} \xB7 ${r.last.message}${r.last.amount !== void 0 ? ` \xB7 ${fmt(r.last.amount)} \u79EF\u5206` : ""}` : "\u5C1A\u65E0\u7B7E\u5230\u8BB0\u5F55",
537
- !a.enabled ? " \xB7 \u8D26\u53F7\u5DF2\u505C\u7528" : ""
538
- ] }),
539
- r.last && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { children: [
540
- when(r.last.at),
541
- last?.retryAt ? ` \xB7 \u8865\u67E5\u65F6\u95F4 ${when(last.retryAt)}` : last?.status === "retryable" ? " \xB7 \u4ECA\u65E5\u4E0D\u518D\u8865\u67E5\uFF0C\u660E\u65E5\u518D\u8BD5" : ""
652
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: a.enabled === false ? "\u8D26\u53F7\u5DF2\u505C\u7528" : "\u5DF2\u5728\u8D26\u53F7\u6C60\u4E2D" })
653
+ ] }),
654
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
655
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `${displayName(a)} \u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230`, type: "checkbox", disabled: blocked, checked: r.auto === true, onChange: (e) => {
656
+ void act({ action: "account.update", id: a.id, autoCheckin: e.target.checked });
657
+ } }),
658
+ "\u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230"
659
+ ] }) }),
660
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinResult, { row: r, compact: true }) }),
661
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
662
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: r.last ? when(r.last.at) : "\u5C1A\u65E0\u8BB0\u5F55" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: r.last?.message || "\u7B49\u5F85\u9996\u6B21\u7B7E\u5230" }),
664
+ last?.retryAt && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { className: "warn", children: [
665
+ "\u8865\u67E5\u65F6\u95F4 ",
666
+ when(last.retryAt)
542
667
  ] }),
543
- r.last?.activity && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: [r.last.activity.streakDays !== void 0 && `\u8FDE\u7B7E ${fmt(r.last.activity.streakDays)} \u5929`, r.last.activity.totalCredits !== void 0 && `\u6D3B\u52A8\u7D2F\u8BA1 ${fmt(r.last.activity.totalCredits)} \u79EF\u5206`, r.last.activity.nextStreakDay !== void 0 && `\u4E0B\u4E00\u8FDE\u7B7E\u6863\u4F4D ${fmt(r.last.activity.nextStreakDay)} \u5929`, r.last.activity.endsAt !== void 0 && `\u6D3B\u52A8\u622A\u6B62 ${when(r.last.activity.endsAt)}`].filter(Boolean).join(" \xB7 ") })
668
+ r.last?.activity && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "\u6D3B\u52A8\u8BE6\u60C5" }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: [r.last.activity.streakDays !== void 0 && `\u8FDE\u7B7E ${fmt(r.last.activity.streakDays)} \u5929`, r.last.activity.totalCredits !== void 0 && `\u6D3B\u52A8\u7D2F\u8BA1 ${fmt(r.last.activity.totalCredits)} \u79EF\u5206`, r.last.activity.nextStreakDay !== void 0 && `\u4E0B\u4E00\u8FDE\u7B7E\u6863\u4F4D ${fmt(r.last.activity.nextStreakDay)} \u5929`, r.last.activity.endsAt !== void 0 && `\u6D3B\u52A8\u622A\u6B62 ${when(r.last.activity.endsAt)}`].filter(Boolean).join(" \xB7 ") })
671
+ ] })
544
672
  ] }),
545
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked || !ready(r), onClick: () => {
673
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cell-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked || !ready(r), onClick: () => {
546
674
  void act({ action: "checkins.run", ids: [a.id] });
547
- }, children: last?.status === "auth-invalid" ? "\u8BF7\u66F4\u65B0\u51ED\u8BC1" : last?.retryReady ? "\u8865\u67E5\u7B7E\u5230" : last?.retryAt ? "\u7B49\u5F85\u665A\u95F4\u8865\u67E5" : last ? "\u4ECA\u65E5\u5DF2\u5904\u7406" : "\u7ACB\u5373\u7B7E\u5230" })
548
- ] }),
549
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
550
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `${displayName(a)} \u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230`, type: "checkbox", disabled: blocked, checked: r.auto === true, onChange: (e) => {
551
- void act({ action: "account.update", id: a.id, autoCheckin: e.target.checked });
552
- } }),
553
- "\u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230"
554
- ] })
555
- ] }, a.id);
556
- })
675
+ }, children: r.last?.status === "auth-invalid" ? "\u8BF7\u66F4\u65B0\u51ED\u8BC1" : last?.retryReady ? "\u8865\u67E5\u7B7E\u5230" : last?.retryAt ? "\u7B49\u5F85\u665A\u95F4\u8865\u67E5" : last ? "\u4ECA\u65E5\u5DF2\u5904\u7406" : "\u7ACB\u5373\u7B7E\u5230" }) })
676
+ ] }, a.id);
677
+ }) })
678
+ ] }) })
557
679
  ] })
558
680
  ] }, p.id);
559
681
  }),
@@ -589,34 +711,37 @@ function Overview({ data, live, setLive, busy, act, go }) {
589
711
  }, children: "\u5237\u65B0\u5E73\u53F0\u7528\u91CF" })
590
712
  ] })
591
713
  ] }),
592
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "providers", children: ["workbuddy", "trae", "qoder"].map((base) => {
593
- const accounts = data.accounts.filter((a) => a.provider === base || a.provider.startsWith(base + "-") || base === "trae" && a.provider === "trae-global");
594
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
595
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
596
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: base === "workbuddy" ? "WorkBuddy" : base === "trae" ? "Trae" : "Qoder" }),
597
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "badge", children: [
598
- accounts.length,
599
- " \u4E2A\u8D26\u53F7"
600
- ] })
714
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box table-shell", children: [
715
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "scroll", role: "region", "aria-label": "\u5404\u5E73\u53F0\u8D26\u53F7\u989D\u5EA6", tabIndex: "0", children: [
716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "table", children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u8D26\u53F7" }),
719
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u4F9B\u5E94\u5546 / \u533A\u57DF" }),
720
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u5E73\u53F0\u79EF\u5206" }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u4ECA\u65E5\u7B7E\u5230" }),
722
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "cell-actions", children: "\u8DEF\u7531\u72B6\u6001" })
723
+ ] }) }),
724
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: data.accounts.map((a) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
725
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: displayName(a) }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: loginNames[a.login?.state] || "\u5C1A\u672A\u67E5\u8BE2\u767B\u5F55" })
728
+ ] }),
729
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: data.providers.find((p) => p.id === a.provider)?.name || a.provider }),
730
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Balance, { account: a }) }),
731
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinResult, { row: data.checkins?.accounts.find((r) => r.id === a.id) }) }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cell-actions", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "status", children: [
733
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", { className: a.enabled === false ? "" : a.status?.cooldowns?.length ? "warn" : "good", "aria-hidden": "true" }),
734
+ a.enabled === false ? "\u672A\u5165\u6C60" : a.status?.cooldowns?.length ? "\u90E8\u5206\u8DEF\u7531\u51B7\u5374" : "\u5DF2\u5728\u6C60\u4E2D"
735
+ ] }) })
736
+ ] }, a.id)) })
601
737
  ] }),
602
- !accounts.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5C1A\u672A\u8FDE\u63A5\u8D26\u53F7" }),
603
- accounts.map((a) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
605
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: a.name }),
606
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { children: [
607
- a.usage?.balance?.unlimited ? "\u4E0D\u9650\u91CF" : fmt(a.usage?.balance?.remaining),
608
- " ",
609
- a.usage?.balance?.unit === "credits" ? "\u79EF\u5206" : ""
610
- ] })
611
- ] }),
612
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
613
- a.usage?.balance?.error ? "\u67E5\u8BE2\u5931\u8D25 \xB7 \u4E0A\u6B21\u6570\u636E " : "\u66F4\u65B0\u4E8E ",
614
- when(a.usage?.balance?.fetchedAt)
615
- ] })
616
- ] }, a.id)),
617
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => go("accounts"), children: "\u7BA1\u7406\u8D26\u53F7" })
618
- ] }, base);
619
- }) }),
738
+ !data.accounts.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "empty", children: "\u5C1A\u672A\u8FDE\u63A5\u8D26\u53F7\uFF0C\u8BF7\u5148\u83B7\u53D6\u672C\u673A\u767B\u5F55\u6216\u6DFB\u52A0\u51ED\u8BC1\u3002" })
739
+ ] }),
740
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "table-footer bar", children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5404\u5E73\u53F0\u79EF\u5206\u72EC\u7ACB\u5C55\u793A\uFF0C\u4E34\u671F\u63D0\u9192\u4EC5\u663E\u793A\u5DF2\u786E\u8BA4\u7684\u4F59\u989D\u3002" }),
742
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => go("accounts"), children: "\u7BA1\u7406\u8D26\u53F7\u6C60" })
743
+ ] })
744
+ ] }),
620
745
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5E73\u53F0\u4F59\u989D\u6BCF\u5206\u949F\u67E5\u8BE2\uFF1BToken \u4EC5\u7EDF\u8BA1\u672C\u63D2\u4EF6\u8BF7\u6C42\uFF0C\u4ECE\u5347\u7EA7\u5F00\u59CB\u8BB0\u5F55\u3002\u79EF\u5206\u4E0B\u964D\u53EF\u80FD\u5305\u542B\u5BA2\u6237\u7AEF\u6216\u5176\u4ED6\u5E94\u7528\u7684\u6D88\u8017\uFF0C\u4E09\u5BB6\u79EF\u5206\u5206\u522B\u5C55\u793A\u3002" }),
621
746
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid", children: [
622
747
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box", children: [
@@ -675,10 +800,19 @@ function Overview({ data, live, setLive, busy, act, go }) {
675
800
  ] })
676
801
  ] });
677
802
  }
803
+ function usageDateBounds(period, start, end, now = Date.now()) {
804
+ const today = new Date(now).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" });
805
+ const midnight = (day) => Date.parse(`${day}T00:00:00+08:00`);
806
+ if (period === "custom") return [midnight(start), midnight(end) + 864e5];
807
+ if (period === "all") return [-Infinity, Infinity];
808
+ return [midnight(today) - (Number(period) - 1) * 864e5, midnight(today) + 864e5];
809
+ }
678
810
  function UsageDetails({ data, busy, act }) {
679
811
  const [account, setAccount] = (0, import_react.useState)(""), [route, setRoute] = (0, import_react.useState)(""), [outcome, setOutcome] = (0, import_react.useState)(""), [page, setPage] = (0, import_react.useState)(0);
812
+ const [period, setPeriod] = (0, import_react.useState)("30"), [start, setStart] = (0, import_react.useState)(() => new Date(Date.now() - 29 * 864e5).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" })), [end, setEnd] = (0, import_react.useState)(() => (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" }));
680
813
  const all = data.telemetry?.events || [], retention = data.options.usageRetentionDays;
681
- const events = all.filter((e) => (!account || e.account === account) && (!route || e.alias === route) && (!outcome || e.outcome === outcome));
814
+ const [from, until] = usageDateBounds(period, start, end), invalidRange = !(from < until);
815
+ const events = all.filter((e) => e.at >= from && e.at < until && (!account || e.account === account) && (!route || e.alias === route) && (!outcome || e.outcome === outcome));
682
816
  const pages = Math.max(1, Math.ceil(events.length / 50)), current = Math.min(page, pages - 1);
683
817
  const accountName = (id) => data.accounts.find((a) => a.id === id)?.name || id;
684
818
  const routeName = (id) => data.routes.find((r) => r.id === id)?.name || id;
@@ -699,17 +833,50 @@ function UsageDetails({ data, busy, act }) {
699
833
  " \u6761"
700
834
  ] })
701
835
  ] }),
702
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "row", onSubmit: (e) => {
703
- e.preventDefault();
704
- void act({ action: "options.save", usageRetentionDays: Number(new FormData(e.currentTarget).get("days")) });
705
- }, children: [
706
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
707
- "\u660E\u7EC6\u4FDD\u7559\u5929\u6570",
708
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { name: "days", type: "number", min: "1", max: "365", step: "1", required: true, disabled: busy, defaultValue: retention })
836
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "help", children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
838
+ "\u8C03\u6574\u660E\u7EC6\u4FDD\u7559\u5929\u6570\uFF08\u5F53\u524D ",
839
+ retention,
840
+ " \u5929\uFF09"
709
841
  ] }),
710
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", disabled: busy, children: "\u4FDD\u5B58\u4FDD\u7559\u671F\u9650" })
711
- ] }, retention),
712
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u9ED8\u8BA4\u4FDD\u7559\u6700\u8FD1 3 \xD7 24 \u5C0F\u65F6\uFF0C\u53EF\u8BBE\u7F6E 1\u2013365 \u5929\u3002\u7F29\u77ED\u671F\u9650\u4F1A\u5220\u9664\u8D85\u671F\u660E\u7EC6\uFF0C\u5EF6\u957F\u4E0D\u80FD\u6062\u590D\u5DF2\u5220\u9664\u8BB0\u5F55\uFF1B\u7D2F\u8BA1\u7EDF\u8BA1\u3001\u989D\u5EA6\u8F6E\u6362\u548C\u4E34\u671F\u51B7\u5374\u4E0D\u53D7\u5F71\u54CD\u3002" })
842
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
843
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "row", onSubmit: (e) => {
844
+ e.preventDefault();
845
+ void act({ action: "options.save", usageRetentionDays: Number(new FormData(e.currentTarget).get("days")) });
846
+ }, children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
848
+ "\u660E\u7EC6\u4FDD\u7559\u5929\u6570",
849
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { name: "days", type: "number", min: "1", max: "365", step: "1", required: true, disabled: busy, defaultValue: retention })
850
+ ] }),
851
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", disabled: busy, children: "\u4FDD\u5B58\u4FDD\u7559\u671F\u9650" })
852
+ ] }, retention),
853
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u9ED8\u8BA4\u6EDA\u52A8\u4FDD\u7559\u6700\u8FD1 30 \u5929\uFF0C\u53EF\u8BBE\u7F6E 1\u2013365 \u5929\u3002\u7F29\u77ED\u671F\u9650\u4F1A\u5220\u9664\u8D85\u671F\u660E\u7EC6\uFF0C\u5EF6\u957F\u4E0D\u80FD\u6062\u590D\u5DF2\u5220\u9664\u8BB0\u5F55\uFF1B\u7D2F\u8BA1\u7EDF\u8BA1\u3001\u989D\u5EA6\u8F6E\u6362\u548C\u4E34\u671F\u51B7\u5374\u4E0D\u53D7\u5F71\u54CD\u3002" })
854
+ ] })
855
+ ] })
856
+ ] }),
857
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "row", role: "group", "aria-label": "\u660E\u7EC6\u65F6\u95F4\u8303\u56F4", children: [["1", "\u4ECA\u65E5"], ["3", "\u8FD1 3 \u65E5"], ["7", "\u8FD1 7 \u65E5"], ["30", "\u8FD1 30 \u65E5"], ["all", "\u5168\u90E8\u5DF2\u4FDD\u7559"], ["custom", "\u81EA\u5B9A\u4E49"]].map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-pressed": period === value, onClick: () => {
859
+ setPeriod(value);
860
+ setPage(0);
861
+ }, children: label }, value)) }),
862
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u6309\u5317\u4EAC\u65F6\u95F4\u81EA\u7136\u65E5\u7B5B\u9009" })
863
+ ] }),
864
+ period === "custom" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
866
+ "\u5F00\u59CB\u65E5\u671F\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09",
867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "date", value: start, max: end || void 0, required: true, onChange: (e) => {
868
+ setStart(e.target.value);
869
+ setPage(0);
870
+ } })
871
+ ] }),
872
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
873
+ "\u7ED3\u675F\u65E5\u671F\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09",
874
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "date", value: end, min: start || void 0, required: true, onChange: (e) => {
875
+ setEnd(e.target.value);
876
+ setPage(0);
877
+ } })
878
+ ] }),
879
+ invalidRange && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: "error", children: "\u8BF7\u9009\u62E9\u6709\u6548\u7684\u8D77\u6B62\u65E5\u671F\uFF0C\u7ED3\u675F\u65E5\u671F\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65E5\u671F\u3002" })
713
880
  ] }),
714
881
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
715
882
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
@@ -827,6 +994,7 @@ function UsageDetails({ data, busy, act }) {
827
994
  ] });
828
995
  }
829
996
  function AccountForm({ modal, provider, data, busy, act, close, replace, error, notice }) {
997
+ const [revision, setRevision] = (0, import_react.useState)(modal.revision);
830
998
  const edit = modal.mode === "edit", account = edit ? data.accounts.find((a) => a.id === modal.account.id) : null;
831
999
  return edit ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "modal-body stack", children: [
832
1000
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Feedback, { error, notice }),
@@ -854,6 +1022,19 @@ function AccountForm({ modal, provider, data, busy, act, close, replace, error,
854
1022
  }, children: "\u5237\u65B0\u767B\u5F55\u4E0E\u7528\u91CF" }),
855
1023
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: replace, children: "\u8865\u5145 / \u66F4\u65B0\u51ED\u8BC1" })
856
1024
  ] }),
1025
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
1026
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1027
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u8DEF\u7531\u8D26\u53F7\u987A\u5E8F" }),
1028
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u6545\u969C\u5207\u6362\u6309\u6B64\u987A\u5E8F\u5C1D\u8BD5\uFF1B\u6743\u91CD\u6216\u989D\u5EA6\u7B56\u7565\u4EE5\u8DEF\u7531\u914D\u7F6E\u4E3A\u51C6\u3002" })
1029
+ ] }),
1030
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "row", children: [-1, 1].map((direction) => {
1031
+ const group = data.accounts.filter((a) => a.provider === account.provider), i = group.findIndex((a) => a.id === account.id);
1032
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: busy || (direction < 0 ? i === 0 : i === group.length - 1), onClick: async () => {
1033
+ const next = await act({ action: "account.move", id: account.id, direction });
1034
+ if (next) setRevision(next.revision);
1035
+ }, children: direction < 0 ? "\u524D\u79FB" : "\u540E\u79FB" }, direction);
1036
+ }) })
1037
+ ] }),
857
1038
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CredentialTransfer, { account, busy, act }),
858
1039
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box", children: [
859
1040
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5E73\u53F0\u5957\u9910\u4E0E\u989D\u5EA6" }),
@@ -872,7 +1053,7 @@ function AccountForm({ modal, provider, data, busy, act, close, replace, error,
872
1053
  ] }),
873
1054
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "stack", onSubmit: async (e) => {
874
1055
  e.preventDefault();
875
- if (await act({ action: "account.update", revision: modal.revision, id: account.id, name: new FormData(e.currentTarget).get("name") })) close();
1056
+ if (await act({ action: "account.update", revision, id: account.id, name: new FormData(e.currentTarget).get("name") })) close();
876
1057
  }, children: [
877
1058
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
878
1059
  "\u8D26\u53F7\u663E\u793A\u540D\u79F0",
@@ -1533,11 +1714,11 @@ function InitialSetup({ data, busy, act, go }) {
1533
1714
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u9996\u6B21\u542F\u52A8\u81EA\u52A8\u6267\u884C\u4E00\u6B21\uFF0C\u4E4B\u540E\u6BCF\u5206\u949F\u68C0\u6D4B\u65B0\u589E\u767B\u5F55\u3002Qoder \u4F7F\u7528 PAT\uFF0C\u8BF7\u5230\u300C\u8D26\u53F7\u4E0E\u767B\u5F55\u300D\u6DFB\u52A0\uFF1B\u672A\u5B89\u88C5\u5BA2\u6237\u7AEF\u4E5F\u53EF\u4EE5\u624B\u52A8\u586B\u5199\u51ED\u8BC1\u3002" })
1534
1715
  ] });
1535
1716
  }
1536
- var updateNames = { unchecked: "\u5F85\u68C0\u67E5", available: "\u53EF\u66F4\u65B0", current: "\u5DF2\u540C\u6B65", pinned: "\u56FA\u5B9A\u63D0\u4EA4", builtin: "\u968F DSH \u5347\u7EA7", unsupported: "\u672C\u5730\u6765\u6E90", failed: "\u68C0\u67E5 / \u5B89\u88C5\u5931\u8D25", installed: "\u5DF2\u5B89\u88C5" };
1717
+ var updateNames = { unchecked: "\u5F85\u68C0\u67E5", available: "\u53EF\u66F4\u65B0", current: "\u5DF2\u540C\u6B65", pinned: "\u56FA\u5B9A\u63D0\u4EA4", unsupported: "\u672C\u5730\u6765\u6E90", failed: "\u68C0\u67E5 / \u5B89\u88C5\u5931\u8D25", installed: "\u5DF2\u5B89\u88C5" };
1537
1718
  function PluginUpdatesPanel({ data, busy, act }) {
1538
1719
  const [query, setQuery] = (0, import_react.useState)(""), [selected, setSelected] = (0, import_react.useState)([]), [plan, setPlan] = (0, import_react.useState)(null), [registry, setRegistry] = (0, import_react.useState)(""), [filter, setFilter] = (0, import_react.useState)("all"), [pluginSearch, setPluginSearch] = (0, import_react.useState)("");
1539
1720
  const running = data?.job?.state === "running", blocked = busy || running;
1540
- const rows = data?.rows ?? [], available = rows.filter((r) => r.status === "available" || r.status === "failed" && r.target);
1721
+ const rows = (data?.rows ?? []).filter((r) => r.source.kind !== "builtin"), available = rows.filter((r) => r.status === "available" || r.status === "failed" && r.target);
1541
1722
  (0, import_react.useEffect)(() => {
1542
1723
  if (data?.available && !running) void act({ action: !data.checkedAt || Date.now() - data.checkedAt > 864e5 ? "plugins.check" : "plugins.list" });
1543
1724
  }, []);
@@ -1551,13 +1732,13 @@ function PluginUpdatesPanel({ data, busy, act }) {
1551
1732
  }
1552
1733
  if (!data?.available) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
1553
1734
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5F53\u524D DSH \u672A\u63D0\u4F9B\u63D2\u4EF6\u7BA1\u7406\u63A5\u53E3" }),
1554
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u8BF7\u5347\u7EA7 DeepSeek Harness \u540E\u91CD\u8BD5\u3002\u672C\u9875\u7BA1\u7406\u5F53\u524D DSH \u914D\u7F6E\u4E2D\u7684\u5168\u90E8\u5DF2\u5B89\u88C5\u63D2\u4EF6\u3002" })
1735
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u8BF7\u5347\u7EA7 DeepSeek Harness \u540E\u91CD\u8BD5\u3002\u672C\u9875\u7BA1\u7406\u5F53\u524D DSH \u914D\u7F6E\u4E2D\u7531\u7528\u6237\u5B89\u88C5\u7684\u63D2\u4EF6\u3002" })
1555
1736
  ] });
1556
1737
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
1557
1738
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
1558
1739
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
1559
1740
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1560
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5DF2\u5B89\u88C5\u63D2\u4EF6\u4E0E\u66F4\u65B0" }),
1741
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u7528\u6237\u5B89\u88C5\u7684\u63D2\u4EF6\u4E0E\u66F4\u65B0" }),
1561
1742
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "npm \u6309\u7248\u672C / \u53D1\u5E03\u9891\u9053\u68C0\u67E5\uFF1BGitHub \u6309\u5206\u652F\u63D0\u4EA4\u68C0\u67E5\uFF0C\u7248\u672C\u53F7\u4E0D\u53D8\u4E5F\u80FD\u53D1\u73B0\u66F4\u65B0\u3002" })
1562
1743
  ] }),
1563
1744
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "primary", disabled: blocked, onClick: () => {
@@ -1567,7 +1748,7 @@ function PluginUpdatesPanel({ data, busy, act }) {
1567
1748
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
1568
1749
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
1569
1750
  rows.length,
1570
- " \u4E2A\u5DF2\u5B89\u88C5\u63D2\u4EF6 \xB7 ",
1751
+ " \u4E2A\u7528\u6237\u5B89\u88C5\u63D2\u4EF6 \xB7 ",
1571
1752
  available.length,
1572
1753
  " \u4E2A\u53EF\u66F4\u65B0 \xB7 \u4E0A\u6B21\u68C0\u67E5 ",
1573
1754
  when(data.checkedAt)
@@ -1581,7 +1762,7 @@ function PluginUpdatesPanel({ data, busy, act }) {
1581
1762
  ] })
1582
1763
  ] })
1583
1764
  ] }),
1584
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u66F4\u65B0\u6CBF\u7528\u539F npm / GitHub \u6765\u6E90\uFF0C\u5E76\u4FDD\u7559\u542F\u7528\u72B6\u6001\uFF1Bnpm \u56FA\u5B9A\u7248\u672C\u548C\u8303\u56F4\u5347\u7EA7\u5230\u6240\u5728\u9891\u9053\u7684\u6700\u65B0\u7248\u672C\uFF0CGit \u56FA\u5B9A\u63D0\u4EA4\u4FDD\u6301\u4E0D\u52A8\u3002\u5B98\u65B9\u5185\u7F6E\u7EC4\u4EF6\u968F DSH \u66F4\u65B0\u3002" })
1765
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u66F4\u65B0\u6CBF\u7528\u539F npm / GitHub \u6765\u6E90\uFF0C\u5E76\u4FDD\u7559\u542F\u7528\u72B6\u6001\uFF1Bnpm \u56FA\u5B9A\u7248\u672C\u548C\u8303\u56F4\u5347\u7EA7\u5230\u6240\u5728\u9891\u9053\u7684\u6700\u65B0\u7248\u672C\uFF0CGit \u56FA\u5B9A\u63D0\u4EA4\u4FDD\u6301\u4E0D\u52A8\u3002" })
1585
1766
  ] }),
1586
1767
  data.job && !(data.job.kind === "check" && data.job.state === "done") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", "aria-live": "polite", children: [
1587
1768
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
@@ -1629,36 +1810,42 @@ function PluginUpdatesPanel({ data, busy, act }) {
1629
1810
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
1630
1811
  "\u663E\u793A\u8303\u56F4",
1631
1812
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { value: filter, onChange: (e) => setFilter(e.target.value), children: [
1632
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "all", children: "\u5168\u90E8\u5DF2\u5B89\u88C5\u63D2\u4EF6" }),
1813
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "all", children: "\u5168\u90E8\u7528\u6237\u5B89\u88C5\u63D2\u4EF6" }),
1633
1814
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "updates", children: "\u53EF\u66F4\u65B0 / \u91CD\u8BD5" }),
1634
1815
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "npm", children: "npm \u6765\u6E90" }),
1635
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "github", children: "GitHub \u6765\u6E90" }),
1636
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "builtin", children: "DSH \u5185\u7F6E\u7EC4\u4EF6" })
1816
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "github", children: "GitHub \u6765\u6E90" })
1637
1817
  ] })
1638
1818
  ] })
1639
1819
  ] }),
1640
- visibleRows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "item stack", children: [
1641
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
1642
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
1643
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", disabled: blocked || !available.includes(r), checked: selected.includes(r.name), onChange: (e) => setSelected(e.target.checked ? [...selected, r.name] : selected.filter((n) => n !== r.name)) }),
1644
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "mono", children: r.name })
1645
- ] }),
1646
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "badge", children: [
1647
- updateNames[r.status],
1648
- " \xB7 ",
1649
- r.enabled ? "\u542F\u7528" : "\u505C\u7528"
1650
- ] })
1820
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "scroll", role: "region", "aria-label": "\u7528\u6237\u5B89\u88C5\u63D2\u4EF6\u5217\u8868", tabIndex: "0", children: [
1821
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "table", children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
1823
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u63D2\u4EF6 / \u9009\u62E9" }),
1824
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u6765\u6E90\u4E0E\u7248\u672C" }),
1825
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: "\u72B6\u6001" }),
1826
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "cell-actions", children: "\u64CD\u4F5C" })
1827
+ ] }) }),
1828
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: visibleRows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: selected.includes(r.name) ? "selected" : "", children: [
1829
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
1830
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
1831
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `\u9009\u62E9\u66F4\u65B0 ${r.name}`, type: "checkbox", disabled: blocked || !available.includes(r), checked: selected.includes(r.name), onChange: (e) => setSelected(e.target.checked ? [...selected, r.name] : selected.filter((n) => n !== r.name)) }),
1832
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "mono", children: r.name })
1833
+ ] }),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: r.enabled ? "\u542F\u7528" : "\u505C\u7528" })
1835
+ ] }),
1836
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
1837
+ r.source.kind === "npm" ? `npm \xB7 ${r.version || "\u672A\u77E5"}${r.latestVersion ? " \u2192 " + r.latestVersion : ""}` : r.source.kind === "github" ? `GitHub \xB7 ${r.version || "\u672A\u77E5\u7248\u672C"}` : "\u672C\u5730\u6587\u4EF6 / \u5F00\u53D1\u94FE\u63A5",
1838
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted mono", children: r.source.kind === "npm" ? r.source.tag : r.source.kind === "github" ? `${r.commit?.slice(0, 8) || "\u672A\u77E5\u63D0\u4EA4"}${r.latestCommit ? " \u2192 " + r.latestCommit.slice(0, 8) : ""}` : "" })
1839
+ ] }),
1840
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
1841
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: r.status === "failed" ? "error" : r.status === "available" ? "good" : "muted", children: updateNames[r.status] }),
1842
+ r.message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: r.status === "failed" ? "error" : "muted", children: r.message })
1843
+ ] }),
1844
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "cell-actions", children: available.includes(r) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked, onClick: () => setPlan({ kind: "update", rows: [r] }), children: "\u67E5\u770B\u5E76\u66F4\u65B0" }) : "\u2014" })
1845
+ ] }, r.name)) })
1651
1846
  ] }),
1652
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
1653
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1654
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: r.source.kind === "npm" ? `npm \xB7 ${r.version || "\u672A\u77E5"}${r.latestVersion ? " \u2192 " + r.latestVersion : ""} \xB7 ${r.source.tag}` : r.source.kind === "github" ? `GitHub \xB7 ${r.version || "\u672A\u77E5\u7248\u672C"} \xB7 ${r.commit?.slice(0, 8) || "\u672A\u77E5\u63D0\u4EA4"}${r.latestCommit ? " \u2192 " + r.latestCommit.slice(0, 8) : ""}` : r.source.kind === "builtin" ? `DSH \u5185\u7F6E\u7EC4\u4EF6 \xB7 ${r.version || "\u672A\u77E5\u7248\u672C"}` : "\u672C\u5730\u6587\u4EF6 / \u5F00\u53D1\u94FE\u63A5" }),
1655
- r.source.kind === "github" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice mono", children: r.source.source }),
1656
- r.message && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: r.status === "failed" ? "notice error" : "notice", children: r.message })
1657
- ] }),
1658
- available.includes(r) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked, onClick: () => setPlan({ kind: "update", rows: [r] }), children: "\u67E5\u770B\u5E76\u66F4\u65B0" })
1659
- ] })
1660
- ] }, r.name)),
1661
- !visibleRows.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "empty", children: running ? "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u6E05\u5355\u2026" : rows.length ? "\u6CA1\u6709\u5339\u914D\u7684\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002" : "\u5F53\u524D\u914D\u7F6E\u5C1A\u672A\u8BFB\u53D6\u63D2\u4EF6\uFF0C\u8BF7\u68C0\u67E5\u66F4\u65B0\u3002" })
1847
+ !visibleRows.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "empty", children: running ? "\u6B63\u5728\u8BFB\u53D6\u63D2\u4EF6\u6E05\u5355\u2026" : rows.length ? "\u6CA1\u6709\u5339\u914D\u7684\u5DF2\u5B89\u88C5\u63D2\u4EF6\uFF0C\u8BF7\u8C03\u6574\u7B5B\u9009\u3002" : "\u5F53\u524D\u914D\u7F6E\u5C1A\u672A\u8BFB\u53D6\u63D2\u4EF6\uFF0C\u8BF7\u68C0\u67E5\u66F4\u65B0\u3002" })
1848
+ ] })
1662
1849
  ] }),
1663
1850
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
1664
1851
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5B89\u88C5 npm / GitHub \u63D2\u4EF6" }),