dsh-multi-router 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createAccountClient
4
- } from "./chunk-UFS7ZJKY.js";
4
+ } from "./chunk-YUP77Q3A.js";
5
5
  import {
6
6
  importAccount
7
- } from "./chunk-3VGKH7MF.js";
7
+ } from "./chunk-OMG4FZWV.js";
8
8
  import "./chunk-FTM7RHQV.js";
9
9
  import "./chunk-S5KMFAQM.js";
10
10
  import {
11
11
  Router
12
- } from "./chunk-GGRCX2NR.js";
12
+ } from "./chunk-XV7O2LRF.js";
13
13
  import {
14
14
  DEFAULT_ROUTES,
15
15
  PROVIDERS,
16
16
  validateConfig,
17
17
  writePrivateJson
18
- } from "./chunk-XMXFIV5G.js";
18
+ } from "./chunk-GAQ77CH4.js";
19
19
  import "./chunk-TEZ2FMEO.js";
20
20
 
21
21
  // src/cli.mjs
package/lib/client.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/client.jsx
21
21
  var client_exports = {};
22
22
  __export(client_exports, {
23
+ CheckinPanel: () => CheckinPanel,
23
24
  InitialSetup: () => InitialSetup,
24
25
  PluginUpdatesPanel: () => PluginUpdatesPanel,
25
26
  RestartGuidance: () => RestartGuidance,
@@ -34,7 +35,7 @@ module.exports = __toCommonJS(client_exports);
34
35
  var import_react = require("react");
35
36
 
36
37
  // package.json
37
- var version = "0.4.0";
38
+ var version = "0.5.0";
38
39
 
39
40
  // src/client.jsx
40
41
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -145,7 +146,7 @@ function RouterPage({ view = "page" }) {
145
146
  return () => clearInterval(timer);
146
147
  }, [view, live]);
147
148
  (0, import_react.useEffect)(() => {
148
- if (data?.pluginUpdates?.job?.state !== "running") return;
149
+ if (data?.pluginUpdates?.job?.state !== "running" && !data?.checkins?.running) return;
149
150
  const timer = setInterval(() => {
150
151
  if (polling.current) return;
151
152
  polling.current = true;
@@ -154,7 +155,7 @@ function RouterPage({ view = "page" }) {
154
155
  });
155
156
  }, 2e3);
156
157
  return () => clearInterval(timer);
157
- }, [data?.pluginUpdates?.job?.state]);
158
+ }, [data?.pluginUpdates?.job?.state, data?.checkins?.running]);
158
159
  async function act(action) {
159
160
  if (busy || backendNeedsRestart(data)) return false;
160
161
  setBusy(true);
@@ -165,7 +166,7 @@ function RouterPage({ view = "page" }) {
165
166
  const next = await readManagementResponse(res);
166
167
  const { exported, ...state } = next;
167
168
  setData(state);
168
- setNotice(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");
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");
169
170
  return next;
170
171
  } catch (e) {
171
172
  setError(e.message);
@@ -208,7 +209,7 @@ function RouterPage({ view = "page" }) {
208
209
  }, children: "\u5237\u65B0\u9762\u677F" })
209
210
  ] })
210
211
  ] }),
211
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "\u8DEF\u7531\u63D2\u4EF6\u914D\u7F6E\u9875\u7B7E", children: [["overview", "\u603B\u89C8\u4E0E\u7528\u91CF"], ["usage", "Token \u660E\u7EC6"], ["accounts", "\u8D26\u53F7\u4E0E\u767B\u5F55"], ["models", "\u6A21\u578B\u7BA1\u7406"], ["routes", "\u8DEF\u7531\u89C4\u5219"], ["plugins", "\u63D2\u4EF6\u66F4\u65B0"], ["migration", "\u914D\u7F6E\u8FC1\u79FB"]].map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-pressed": tab === key, onClick: () => {
212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "\u8DEF\u7531\u63D2\u4EF6\u914D\u7F6E\u9875\u7B7E", children: [["overview", "\u603B\u89C8\u4E0E\u7528\u91CF"], ["usage", "Token \u660E\u7EC6"], ["accounts", "\u8D26\u53F7\u4E0E\u767B\u5F55"], ["checkins", "\u79EF\u5206\u7B7E\u5230"], ["models", "\u6A21\u578B\u7BA1\u7406"], ["routes", "\u8DEF\u7531\u89C4\u5219"], ["plugins", "\u63D2\u4EF6\u66F4\u65B0"], ["migration", "\u914D\u7F6E\u8FC1\u79FB"]].map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-pressed": tab === key, onClick: () => {
212
213
  setTab(key);
213
214
  setError("");
214
215
  setNotice("");
@@ -221,6 +222,7 @@ function RouterPage({ view = "page" }) {
221
222
  ["overview", "accounts"].includes(tab) && data.setup?.dismissed !== true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InitialSetup, { data, busy, act, go: (key) => setTab(key) }),
222
223
  tab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overview, { data, live, setLive, busy, act, go: (key) => setTab(key) }),
223
224
  tab === "plugins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluginUpdatesPanel, { data: data.pluginUpdates, busy, act }),
225
+ tab === "checkins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinPanel, { data, busy, act }),
224
226
  tab === "usage" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UsageDetails, { data, busy, act }),
225
227
  tab === "accounts" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
226
228
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
@@ -473,6 +475,79 @@ function RouterPage({ view = "page" }) {
473
475
  }, error, notice }) })
474
476
  ] });
475
477
  }
478
+ function CheckinPanel({ data, busy, act }) {
479
+ 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`);
481
+ 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);
483
+ const ready = (r) => eligible.includes(r) && !beforeWindow;
484
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
485
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
487
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
488
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u6BCF\u65E5\u79EF\u5206\u7B7E\u5230" }),
489
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: info.schedule })
490
+ ] }),
491
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "primary", disabled: blocked || beforeWindow || !eligible.length, onClick: () => {
492
+ void act({ action: "checkins.run", ids: eligible.map((r) => r.id) });
493
+ }, children: [
494
+ "\u7B7E\u5230\u5168\u90E8\u53EF\u7528\u8D26\u53F7\uFF08",
495
+ eligible.length,
496
+ "\uFF09"
497
+ ] })
498
+ ] }),
499
+ /* @__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\u5C1D\u8BD5\u4E00\u6B21\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" }),
500
+ 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" }),
501
+ info.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: "error", children: info.error }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "status", children: info.running ? `\u6B63\u5728\u5904\u7406 ${data.accounts.find((a) => a.id === info.current)?.name || "\u7B7E\u5230\u961F\u5217"}\u2026` : "\u7B7E\u5230\u7ED3\u679C\u548C\u9886\u53D6\u79EF\u5206\u4EE5\u4E0B\u65B9\u5E73\u53F0\u54CD\u5E94\u4E3A\u51C6\u3002" })
503
+ ] }),
504
+ data.providers.map((p) => {
505
+ const accounts = data.accounts.filter((a) => a.provider === p.id);
506
+ if (!accounts.length) return null;
507
+ const supported = rows.some((r) => r.id === accounts[0].id && r.supported), paused = rows.some((r) => accounts.some((a) => a.id === r.id) && r.paused);
508
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
509
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
510
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: p.name }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "badge", children: supported ? paused ? "\u5DF2\u6682\u505C" : "\u652F\u6301\u7B7E\u5230" : "\u5B98\u65B9\u5BA2\u6237\u7AEF\u9886\u53D6" })
512
+ ] }),
513
+ !supported ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: p.id.startsWith("workbuddy") ? "WorkBuddy \u6682\u672A\u63A5\u5165\u53EF\u6838\u9A8C\u7684\u7B7E\u5230\u63A5\u53E3\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u67E5\u770B\u6D3B\u52A8\u4E0E\u9886\u53D6\u5165\u53E3\u3002" : "Trae Global \u6682\u65E0\u5DF2\u6838\u9A8C\u7684\u79EF\u5206\u7B7E\u5230\u63A5\u53E3\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u67E5\u770B\u6743\u76CA\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
514
+ paused && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "steps", children: [
515
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u8BE5\u5E73\u53F0\u7B7E\u5230\u3002\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406\u540E\u518D\u6062\u590D\uFF1B\u6062\u590D\u4ECD\u4FDD\u7559\u4ECA\u65E5\u5C1D\u8BD5\u8BB0\u5F55\u548C\u8BBE\u5907\u9650\u5236\u3002" }),
516
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked, onClick: () => {
517
+ void act({ action: "checkins.resume", provider: p.id });
518
+ }, children: "\u6211\u5DF2\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406\uFF0C\u6062\u590D\u540E\u7EED\u7B7E\u5230" })
519
+ ] }),
520
+ accounts.map((a) => {
521
+ const r = rows.find((r2) => r2.id === a.id) || {};
522
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "item stack", children: [
523
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
525
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: a.name }),
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "notice", children: [
527
+ 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",
528
+ !a.enabled ? " \xB7 \u8D26\u53F7\u5DF2\u505C\u7528" : ""
529
+ ] }),
530
+ r.last && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: when(r.last.at) })
531
+ ] }),
532
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: blocked || !ready(r), onClick: () => {
533
+ void act({ action: "checkins.run", ids: [a.id] });
534
+ }, children: r.last?.day === today ? "\u4ECA\u65E5\u5DF2\u5904\u7406" : "\u7ACB\u5373\u7B7E\u5230" })
535
+ ] }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
537
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `${a.name} \u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230`, type: "checkbox", disabled: blocked, checked: r.auto === true, onChange: (e) => {
538
+ void act({ action: "account.update", id: a.id, autoCheckin: e.target.checked });
539
+ } }),
540
+ "\u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230"
541
+ ] })
542
+ ] }, a.id);
543
+ })
544
+ ] })
545
+ ] }, p.id);
546
+ }),
547
+ !data.accounts.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "box empty", children: "\u5148\u5230\u300C\u8D26\u53F7\u4E0E\u767B\u5F55\u300D\u6DFB\u52A0\u8D26\u53F7\uFF0C\u518D\u5F00\u542F\u6BCF\u65E5\u81EA\u52A8\u7B7E\u5230\u3002" }),
548
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u591A\u53F0\u8BBE\u5907\u7684\u672C\u5730\u8BB0\u5F55\u4E0D\u4F1A\u4E92\u76F8\u540C\u6B65\uFF0C\u6BCF\u6B21\u90FD\u4F1A\u67E5\u8BE2\u5E73\u53F0\u9886\u53D6\u72B6\u6001\uFF1B\u5EFA\u8BAE\u4EC5\u5728\u4E00\u53F0\u5E38\u7528\u8BBE\u5907\u5F00\u542F\u81EA\u52A8\u7B7E\u5230\u3002\u540C\u4E00 Trae \u8BBE\u5907\u6BCF\u5929\u6700\u591A\u5904\u7406\u4E00\u4E2A\u9886\u53D6\u8BF7\u6C42\uFF0C\u91CD\u590D\u8D26\u53F7\u526F\u672C\u4F1A\u53BB\u91CD\uFF1B\u4E0D\u4FDD\u8BC1\u5E73\u53F0\u4E00\u5B9A\u53D1\u653E\u5956\u52B1\u3002" })
549
+ ] });
550
+ }
476
551
  function Overview({ data, live, setLive, busy, act, go }) {
477
552
  const t = data.telemetry || {}, today = t.days?.[t.today] || {}, totals = data.accounts.reduce((s, a) => ({ requests: s.requests + (a.usage?.requests || 0), tokens: s.tokens + (a.usage?.tokens || 0) }), { requests: 0, tokens: 0 });
478
553
  const dates = Array.from({ length: 7 }, (_, i) => {
@@ -555,6 +630,7 @@ function Overview({ data, live, setLive, busy, act, go }) {
555
630
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
556
631
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => go("accounts"), children: "\u67E5\u770B\u8D26\u53F7" }),
557
632
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => go("routes"), children: "\u914D\u7F6E\u8DEF\u7531" }),
633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => go("checkins"), children: "\u79EF\u5206\u7B7E\u5230" }),
558
634
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => go("plugins"), children: "\u68C0\u67E5\u6240\u6709\u63D2\u4EF6\u66F4\u65B0" })
559
635
  ] })
560
636
  ] })