@eddyskywalker/dsh-chatgpt-subscription 0.5.0 → 0.6.5
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/CHANGELOG.md +36 -1
- package/README.md +67 -1
- package/lib/client.js +1425 -222
- package/lib/client.js.map +1 -1
- package/lib/index.js +4884 -1114
- package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
- package/lib/types/client/common/AccountPoolSection.d.ts +14 -0
- package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +26 -0
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +1 -0
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts +41 -0
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -0
- package/lib/types/client/workbuddy/locales.d.ts +485 -0
- package/lib/types/client/workbuddy/locales.d.ts.map +1 -0
- package/lib/types/client/workbuddy/styles.d.ts +15 -0
- package/lib/types/client/workbuddy/styles.d.ts.map +1 -0
- package/lib/types/host/common/account-pool.d.ts +18 -0
- package/lib/types/host/common/account-pool.d.ts.map +1 -1
- package/lib/types/host/workbuddy/account-pool.d.ts +106 -0
- package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -0
- package/lib/types/host/workbuddy/adapter.d.ts +97 -0
- package/lib/types/host/workbuddy/adapter.d.ts.map +1 -0
- package/lib/types/host/workbuddy/client.d.ts +90 -0
- package/lib/types/host/workbuddy/client.d.ts.map +1 -0
- package/lib/types/host/workbuddy/mapper.d.ts +114 -0
- package/lib/types/host/workbuddy/mapper.d.ts.map +1 -0
- package/lib/types/host/workbuddy/model-catalog.d.ts +108 -0
- package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -0
- package/lib/types/host/workbuddy/oauth.d.ts +38 -0
- package/lib/types/host/workbuddy/oauth.d.ts.map +1 -0
- package/lib/types/host/workbuddy/routes.d.ts +33 -0
- package/lib/types/host/workbuddy/routes.d.ts.map +1 -0
- package/lib/types/host/workbuddy/token-store.d.ts +216 -0
- package/lib/types/host/workbuddy/token-store.d.ts.map +1 -0
- package/lib/types/host/workbuddy/types.d.ts +127 -0
- package/lib/types/host/workbuddy/types.d.ts.map +1 -0
- package/lib/types/index.d.ts +5 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/account-pool-contracts.d.ts +8 -0
- package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
- package/lib/types/shared/workbuddy-contracts.d.ts +210 -0
- package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -56,7 +56,7 @@ window.__ModuleLoader__.load({
|
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/client/CodexComposerQuota.tsx
|
|
58
58
|
function CodexComposerQuota({ api, directory, loadModelDirectory, t }) {
|
|
59
|
-
const modelState = useStore$
|
|
59
|
+
const modelState = useStore$4(directory);
|
|
60
60
|
const [status, setStatus] = (0, react.useState)(null);
|
|
61
61
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
62
62
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -103,7 +103,7 @@ window.__ModuleLoader__.load({
|
|
|
103
103
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quickQuotaLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota === null ? loading ? t("quickQuotaLoading") : "—" : formatPercent$1(quota.remainingPercent) })]
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
-
function useStore$
|
|
106
|
+
function useStore$4(store) {
|
|
107
107
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
108
108
|
}
|
|
109
109
|
function formatPercent$1(value) {
|
|
@@ -479,7 +479,7 @@ window.__ModuleLoader__.load({
|
|
|
479
479
|
formatPoolLabel(t.accountCount, { count: accounts.length }),
|
|
480
480
|
")"
|
|
481
481
|
]
|
|
482
|
-
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
482
|
+
})] }), props.renderLoginActions !== void 0 ? props.renderLoginActions() : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
483
483
|
className: "dsha-btn dsha-btn-primary",
|
|
484
484
|
disabled: props.busy !== null,
|
|
485
485
|
onClick: props.onLogin,
|
|
@@ -565,6 +565,7 @@ window.__ModuleLoader__.load({
|
|
|
565
565
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
566
566
|
className: "dsha-account-actions",
|
|
567
567
|
children: [
|
|
568
|
+
props.renderAccountActions?.(account),
|
|
568
569
|
!account.isPrimary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
569
570
|
className: "dsha-btn",
|
|
570
571
|
disabled: props.busy !== null,
|
|
@@ -583,7 +584,7 @@ window.__ModuleLoader__.load({
|
|
|
583
584
|
onClick: () => props.onRelogin(account.id),
|
|
584
585
|
children: t.relogin
|
|
585
586
|
}),
|
|
586
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
587
|
+
account.removable !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
587
588
|
className: "dsha-btn",
|
|
588
589
|
disabled: props.busy !== null,
|
|
589
590
|
onClick: () => props.onDelete(account.id),
|
|
@@ -1008,7 +1009,7 @@ window.__ModuleLoader__.load({
|
|
|
1008
1009
|
}),
|
|
1009
1010
|
connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
|
|
1010
1011
|
label: t("latency"),
|
|
1011
|
-
value: `${connection.latencyMs} ms · ${formatDate$
|
|
1012
|
+
value: `${connection.latencyMs} ms · ${formatDate$3(connection.checkedAt)}`
|
|
1012
1013
|
}) : null,
|
|
1013
1014
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1014
1015
|
className: "dsha-muted dsha-models-hint",
|
|
@@ -1281,7 +1282,7 @@ window.__ModuleLoader__.load({
|
|
|
1281
1282
|
id: inputId,
|
|
1282
1283
|
type: "text",
|
|
1283
1284
|
inputMode: "numeric",
|
|
1284
|
-
value: draft ?? formatCapacity$
|
|
1285
|
+
value: draft ?? formatCapacity$4(fallback),
|
|
1285
1286
|
disabled: busy !== null,
|
|
1286
1287
|
"aria-label": entry.name + " " + t("contextWindow"),
|
|
1287
1288
|
onChange: (event) => {
|
|
@@ -1395,7 +1396,7 @@ window.__ModuleLoader__.load({
|
|
|
1395
1396
|
children: [
|
|
1396
1397
|
t("updated"),
|
|
1397
1398
|
": ",
|
|
1398
|
-
formatDate$
|
|
1399
|
+
formatDate$3(quota.fetchedAt)
|
|
1399
1400
|
]
|
|
1400
1401
|
}) : null
|
|
1401
1402
|
]
|
|
@@ -1487,7 +1488,7 @@ window.__ModuleLoader__.load({
|
|
|
1487
1488
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
|
|
1488
1489
|
t("resetCreditExpires"),
|
|
1489
1490
|
": ",
|
|
1490
|
-
resetCredits.expiresAt == null ? t("unknown") : formatReset$
|
|
1491
|
+
resetCredits.expiresAt == null ? t("unknown") : formatReset$3(resetCredits.expiresAt)
|
|
1491
1492
|
] })
|
|
1492
1493
|
]
|
|
1493
1494
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
@@ -1520,7 +1521,7 @@ window.__ModuleLoader__.load({
|
|
|
1520
1521
|
}),
|
|
1521
1522
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1522
1523
|
className: "dsh-codex-meter-meta",
|
|
1523
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset$
|
|
1524
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset$3(window.resetsAt)}` })]
|
|
1524
1525
|
})
|
|
1525
1526
|
]
|
|
1526
1527
|
});
|
|
@@ -1546,7 +1547,7 @@ window.__ModuleLoader__.load({
|
|
|
1546
1547
|
return `${value} ${t("limitWindow")}`;
|
|
1547
1548
|
}
|
|
1548
1549
|
}
|
|
1549
|
-
function parsePositiveCapacity$
|
|
1550
|
+
function parsePositiveCapacity$4(value) {
|
|
1550
1551
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
1551
1552
|
if (matched === null) return null;
|
|
1552
1553
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
@@ -1554,10 +1555,10 @@ window.__ModuleLoader__.load({
|
|
|
1554
1555
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
1555
1556
|
}
|
|
1556
1557
|
function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
|
|
1557
|
-
const parsed = parsePositiveCapacity$
|
|
1558
|
+
const parsed = parsePositiveCapacity$4(value);
|
|
1558
1559
|
return parsed !== null && parsed <= maxContextWindow ? parsed : null;
|
|
1559
1560
|
}
|
|
1560
|
-
function formatCapacity$
|
|
1561
|
+
function formatCapacity$4(value) {
|
|
1561
1562
|
if (value % 1e3 === 0) return `${value / 1e3}K`;
|
|
1562
1563
|
return String(value);
|
|
1563
1564
|
}
|
|
@@ -1574,11 +1575,11 @@ window.__ModuleLoader__.load({
|
|
|
1574
1575
|
limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
|
|
1575
1576
|
limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
|
|
1576
1577
|
limit.used !== null && limit.used !== void 0 ? `${t("used")}: ${limit.used}` : null,
|
|
1577
|
-
limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$
|
|
1578
|
+
limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$3(limit.resetsAt)}` : null
|
|
1578
1579
|
].filter((part) => part !== null);
|
|
1579
1580
|
return parts.length > 0 ? parts.join(" · ") : t("unknown");
|
|
1580
1581
|
}
|
|
1581
|
-
function formatDate$
|
|
1582
|
+
function formatDate$3(seconds) {
|
|
1582
1583
|
if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
|
|
1583
1584
|
const ms = seconds > 1e10 ? seconds : seconds * 1e3;
|
|
1584
1585
|
try {
|
|
@@ -1590,10 +1591,10 @@ window.__ModuleLoader__.load({
|
|
|
1590
1591
|
return "—";
|
|
1591
1592
|
}
|
|
1592
1593
|
}
|
|
1593
|
-
function formatReset$
|
|
1594
|
+
function formatReset$3(seconds) {
|
|
1594
1595
|
if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
|
|
1595
1596
|
const ms = seconds > 1e10 ? seconds : seconds * 1e3;
|
|
1596
|
-
const absolute = formatDate$
|
|
1597
|
+
const absolute = formatDate$3(seconds);
|
|
1597
1598
|
const diff = ms - Date.now();
|
|
1598
1599
|
const abs = Math.abs(diff);
|
|
1599
1600
|
const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
|
|
@@ -1609,7 +1610,7 @@ window.__ModuleLoader__.load({
|
|
|
1609
1610
|
//#endregion
|
|
1610
1611
|
//#region src/client/antigravity/locales.ts
|
|
1611
1612
|
const NS_ANTIGRAVITY = "dsh-antigravity";
|
|
1612
|
-
const zh$
|
|
1613
|
+
const zh$4 = {
|
|
1613
1614
|
...accountPoolZh,
|
|
1614
1615
|
title: "Antigravity",
|
|
1615
1616
|
pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
|
|
@@ -1675,7 +1676,7 @@ window.__ModuleLoader__.load({
|
|
|
1675
1676
|
loginFailed: "登录失败",
|
|
1676
1677
|
tokens: "tokens"
|
|
1677
1678
|
};
|
|
1678
|
-
const en$
|
|
1679
|
+
const en$4 = {
|
|
1679
1680
|
...accountPoolEn,
|
|
1680
1681
|
title: "Antigravity",
|
|
1681
1682
|
pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
|
|
@@ -1741,17 +1742,17 @@ window.__ModuleLoader__.load({
|
|
|
1741
1742
|
loginFailed: "Login failed",
|
|
1742
1743
|
tokens: "tokens"
|
|
1743
1744
|
};
|
|
1744
|
-
const dictionaries$
|
|
1745
|
-
zh: zh$
|
|
1746
|
-
"zh-CN": zh$
|
|
1747
|
-
en: en$
|
|
1748
|
-
"en-US": en$
|
|
1745
|
+
const dictionaries$4 = {
|
|
1746
|
+
zh: zh$4,
|
|
1747
|
+
"zh-CN": zh$4,
|
|
1748
|
+
en: en$4,
|
|
1749
|
+
"en-US": en$4
|
|
1749
1750
|
};
|
|
1750
1751
|
//#endregion
|
|
1751
1752
|
//#region src/client/antigravity/AntigravitySection.tsx
|
|
1752
|
-
const API$
|
|
1753
|
-
async function fetchApi$
|
|
1754
|
-
const res = await fetch(`${API$
|
|
1753
|
+
const API$7 = "/antigravity/api";
|
|
1754
|
+
async function fetchApi$7(path, options) {
|
|
1755
|
+
const res = await fetch(`${API$7}${path}`, {
|
|
1755
1756
|
...options,
|
|
1756
1757
|
headers: {
|
|
1757
1758
|
"Content-Type": "application/json",
|
|
@@ -1762,14 +1763,14 @@ window.__ModuleLoader__.load({
|
|
|
1762
1763
|
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
1763
1764
|
return json.value;
|
|
1764
1765
|
}
|
|
1765
|
-
function parsePositiveCapacity$
|
|
1766
|
+
function parsePositiveCapacity$3(value) {
|
|
1766
1767
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
1767
1768
|
if (matched === null) return null;
|
|
1768
1769
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
1769
1770
|
const parsed = Number(matched[1]) * multiplier;
|
|
1770
1771
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
1771
1772
|
}
|
|
1772
|
-
function formatCapacity$
|
|
1773
|
+
function formatCapacity$3(value) {
|
|
1773
1774
|
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
1774
1775
|
if (value % 1e3 === 0) return `${value / 1e3}K`;
|
|
1775
1776
|
return String(value);
|
|
@@ -1785,7 +1786,7 @@ window.__ModuleLoader__.load({
|
|
|
1785
1786
|
if (hours > 0) return `${hours}h ${mins % 60}m`;
|
|
1786
1787
|
return `${mins}m`;
|
|
1787
1788
|
}
|
|
1788
|
-
function formatDate$
|
|
1789
|
+
function formatDate$2(ms) {
|
|
1789
1790
|
if (!ms || ms <= 0) return "—";
|
|
1790
1791
|
try {
|
|
1791
1792
|
return new Intl.DateTimeFormat(void 0, {
|
|
@@ -1805,7 +1806,7 @@ window.__ModuleLoader__.load({
|
|
|
1805
1806
|
const [loginProgress, setLoginProgress] = (0, react.useState)(null);
|
|
1806
1807
|
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
1807
1808
|
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
1808
|
-
const t = zh$
|
|
1809
|
+
const t = zh$4;
|
|
1809
1810
|
const notifyChange = (0, react.useCallback)(() => {
|
|
1810
1811
|
onModelChange?.();
|
|
1811
1812
|
loadModelDirectory?.();
|
|
@@ -1816,12 +1817,12 @@ window.__ModuleLoader__.load({
|
|
|
1816
1817
|
setValidationUrl(null);
|
|
1817
1818
|
}
|
|
1818
1819
|
try {
|
|
1819
|
-
const data = await fetchApi$
|
|
1820
|
+
const data = await fetchApi$7("/status");
|
|
1820
1821
|
setStatus(data);
|
|
1821
1822
|
const drafts = {};
|
|
1822
1823
|
for (const m of data.models) {
|
|
1823
1824
|
const val = data.contextWindowOverrides[m.id] || m.defaultContextWindow;
|
|
1824
|
-
drafts[m.id] = formatCapacity$
|
|
1825
|
+
drafts[m.id] = formatCapacity$3(val);
|
|
1825
1826
|
}
|
|
1826
1827
|
setContextDrafts(drafts);
|
|
1827
1828
|
} catch (err) {
|
|
@@ -1848,11 +1849,11 @@ window.__ModuleLoader__.load({
|
|
|
1848
1849
|
setError(null);
|
|
1849
1850
|
setValidationUrl(null);
|
|
1850
1851
|
setLoginProgress(null);
|
|
1851
|
-
const flow = await fetchApi$
|
|
1852
|
+
const flow = await fetchApi$7("/login", { method: "POST" });
|
|
1852
1853
|
if (flow.authUrl) window.open(flow.authUrl, "_blank");
|
|
1853
1854
|
const pollTimer = setInterval(async () => {
|
|
1854
1855
|
try {
|
|
1855
|
-
const pollStatus = await fetchApi$
|
|
1856
|
+
const pollStatus = await fetchApi$7("/login/status");
|
|
1856
1857
|
if (pollStatus.progress) setLoginProgress(pollStatus.progress);
|
|
1857
1858
|
if (pollStatus.status === "complete") {
|
|
1858
1859
|
clearInterval(pollTimer);
|
|
@@ -1884,7 +1885,7 @@ window.__ModuleLoader__.load({
|
|
|
1884
1885
|
try {
|
|
1885
1886
|
setBusy("quota");
|
|
1886
1887
|
setError(null);
|
|
1887
|
-
const updated = await fetchApi$
|
|
1888
|
+
const updated = await fetchApi$7("/quota", { method: "POST" });
|
|
1888
1889
|
setStatus(updated);
|
|
1889
1890
|
} catch (err) {
|
|
1890
1891
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -1896,7 +1897,7 @@ window.__ModuleLoader__.load({
|
|
|
1896
1897
|
try {
|
|
1897
1898
|
setBusy(`primary-${accountId}`);
|
|
1898
1899
|
setError(null);
|
|
1899
|
-
const updated = await fetchApi$
|
|
1900
|
+
const updated = await fetchApi$7("/accounts", {
|
|
1900
1901
|
method: "POST",
|
|
1901
1902
|
body: JSON.stringify({
|
|
1902
1903
|
action: "set-primary",
|
|
@@ -1915,7 +1916,7 @@ window.__ModuleLoader__.load({
|
|
|
1915
1916
|
try {
|
|
1916
1917
|
setBusy(`delete-${accountId}`);
|
|
1917
1918
|
setError(null);
|
|
1918
|
-
const updated = await fetchApi$
|
|
1919
|
+
const updated = await fetchApi$7("/accounts", {
|
|
1919
1920
|
method: "POST",
|
|
1920
1921
|
body: JSON.stringify({
|
|
1921
1922
|
action: "delete",
|
|
@@ -1934,7 +1935,7 @@ window.__ModuleLoader__.load({
|
|
|
1934
1935
|
try {
|
|
1935
1936
|
setBusy(`cooldown-${accountId}`);
|
|
1936
1937
|
setError(null);
|
|
1937
|
-
const updated = await fetchApi$
|
|
1938
|
+
const updated = await fetchApi$7("/accounts", {
|
|
1938
1939
|
method: "POST",
|
|
1939
1940
|
body: JSON.stringify({
|
|
1940
1941
|
action: "clear-cooldown",
|
|
@@ -1952,7 +1953,7 @@ window.__ModuleLoader__.load({
|
|
|
1952
1953
|
try {
|
|
1953
1954
|
setBusy("strategy");
|
|
1954
1955
|
setError(null);
|
|
1955
|
-
const updated = await fetchApi$
|
|
1956
|
+
const updated = await fetchApi$7("/accounts", {
|
|
1956
1957
|
method: "POST",
|
|
1957
1958
|
body: JSON.stringify({
|
|
1958
1959
|
action: "strategy",
|
|
@@ -1972,7 +1973,7 @@ window.__ModuleLoader__.load({
|
|
|
1972
1973
|
enabled
|
|
1973
1974
|
} : prev);
|
|
1974
1975
|
try {
|
|
1975
|
-
const updated = await fetchApi$
|
|
1976
|
+
const updated = await fetchApi$7("/settings", {
|
|
1976
1977
|
method: "POST",
|
|
1977
1978
|
body: JSON.stringify({ enabled })
|
|
1978
1979
|
});
|
|
@@ -1988,7 +1989,7 @@ window.__ModuleLoader__.load({
|
|
|
1988
1989
|
const currentEnabled = status.models.filter((m) => m.enabled).map((m) => m.id);
|
|
1989
1990
|
const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
|
|
1990
1991
|
try {
|
|
1991
|
-
const updated = await fetchApi$
|
|
1992
|
+
const updated = await fetchApi$7("/models", {
|
|
1992
1993
|
method: "POST",
|
|
1993
1994
|
body: JSON.stringify({ enabledModelIds: nextEnabled })
|
|
1994
1995
|
});
|
|
@@ -2002,7 +2003,7 @@ window.__ModuleLoader__.load({
|
|
|
2002
2003
|
if (!status) return;
|
|
2003
2004
|
const nextEnabled = selectAll ? status.models.map((m) => m.id) : [];
|
|
2004
2005
|
try {
|
|
2005
|
-
const updated = await fetchApi$
|
|
2006
|
+
const updated = await fetchApi$7("/models", {
|
|
2006
2007
|
method: "POST",
|
|
2007
2008
|
body: JSON.stringify({ enabledModelIds: nextEnabled })
|
|
2008
2009
|
});
|
|
@@ -2014,7 +2015,7 @@ window.__ModuleLoader__.load({
|
|
|
2014
2015
|
};
|
|
2015
2016
|
const handleUpdateEffort = async (effort) => {
|
|
2016
2017
|
try {
|
|
2017
|
-
const updated = await fetchApi$
|
|
2018
|
+
const updated = await fetchApi$7("/settings", {
|
|
2018
2019
|
method: "POST",
|
|
2019
2020
|
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
2020
2021
|
});
|
|
@@ -2026,7 +2027,7 @@ window.__ModuleLoader__.load({
|
|
|
2026
2027
|
};
|
|
2027
2028
|
const handleSaveContextWindow = async (modelId) => {
|
|
2028
2029
|
const raw = contextDrafts[modelId] || "";
|
|
2029
|
-
const parsed = parsePositiveCapacity$
|
|
2030
|
+
const parsed = parsePositiveCapacity$3(raw);
|
|
2030
2031
|
if (parsed === null) {
|
|
2031
2032
|
setError(`无效的上下文容量值: ${raw}`);
|
|
2032
2033
|
return;
|
|
@@ -2034,14 +2035,14 @@ window.__ModuleLoader__.load({
|
|
|
2034
2035
|
try {
|
|
2035
2036
|
setSavingModel(modelId);
|
|
2036
2037
|
setError(null);
|
|
2037
|
-
const updated = await fetchApi$
|
|
2038
|
+
const updated = await fetchApi$7("/settings", {
|
|
2038
2039
|
method: "POST",
|
|
2039
2040
|
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
2040
2041
|
});
|
|
2041
2042
|
setStatus(updated);
|
|
2042
2043
|
setContextDrafts((prev) => ({
|
|
2043
2044
|
...prev,
|
|
2044
|
-
[modelId]: formatCapacity$
|
|
2045
|
+
[modelId]: formatCapacity$3(parsed)
|
|
2045
2046
|
}));
|
|
2046
2047
|
notifyChange();
|
|
2047
2048
|
} catch (err) {
|
|
@@ -2089,12 +2090,12 @@ window.__ModuleLoader__.load({
|
|
|
2089
2090
|
account.expiresAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
2090
2091
|
t.expires,
|
|
2091
2092
|
": ",
|
|
2092
|
-
formatDate$
|
|
2093
|
+
formatDate$2(account.expiresAt)
|
|
2093
2094
|
] }),
|
|
2094
2095
|
account.lastUsedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
2095
2096
|
t.lastUsed,
|
|
2096
2097
|
": ",
|
|
2097
|
-
formatDate$
|
|
2098
|
+
formatDate$2(account.lastUsedAt)
|
|
2098
2099
|
] })
|
|
2099
2100
|
] })
|
|
2100
2101
|
}),
|
|
@@ -2350,7 +2351,7 @@ window.__ModuleLoader__.load({
|
|
|
2350
2351
|
//#endregion
|
|
2351
2352
|
//#region src/client/command-code/locales.ts
|
|
2352
2353
|
const NS_COMMAND_CODE = "dsh-command-code";
|
|
2353
|
-
const zh$
|
|
2354
|
+
const zh$3 = {
|
|
2354
2355
|
...accountPoolZh,
|
|
2355
2356
|
title: "Command Code",
|
|
2356
2357
|
pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
|
|
@@ -2418,7 +2419,7 @@ window.__ModuleLoader__.load({
|
|
|
2418
2419
|
loginFailed: "登录失败",
|
|
2419
2420
|
tokens: "tokens"
|
|
2420
2421
|
};
|
|
2421
|
-
const en$
|
|
2422
|
+
const en$3 = {
|
|
2422
2423
|
...accountPoolEn,
|
|
2423
2424
|
title: "Command Code",
|
|
2424
2425
|
pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
|
|
@@ -2486,11 +2487,11 @@ window.__ModuleLoader__.load({
|
|
|
2486
2487
|
loginFailed: "Sign-in failed",
|
|
2487
2488
|
tokens: "tokens"
|
|
2488
2489
|
};
|
|
2489
|
-
const dictionaries$
|
|
2490
|
-
zh: zh$
|
|
2491
|
-
"zh-CN": zh$
|
|
2492
|
-
en: en$
|
|
2493
|
-
"en-US": en$
|
|
2490
|
+
const dictionaries$3 = {
|
|
2491
|
+
zh: zh$3,
|
|
2492
|
+
"zh-CN": zh$3,
|
|
2493
|
+
en: en$3,
|
|
2494
|
+
"en-US": en$3
|
|
2494
2495
|
};
|
|
2495
2496
|
//#endregion
|
|
2496
2497
|
//#region src/client/command-code/CommandCodeSection.tsx
|
|
@@ -2498,7 +2499,7 @@ window.__ModuleLoader__.load({
|
|
|
2498
2499
|
* Display label per reasoning level. The locale dictionary only accepts flat
|
|
2499
2500
|
* string values, so this nested table lives with the control that renders it.
|
|
2500
2501
|
*/
|
|
2501
|
-
const EFFORT_LABELS = {
|
|
2502
|
+
const EFFORT_LABELS$1 = {
|
|
2502
2503
|
minimal: "Minimal",
|
|
2503
2504
|
low: "Low",
|
|
2504
2505
|
medium: "Medium",
|
|
@@ -2506,9 +2507,9 @@ window.__ModuleLoader__.load({
|
|
|
2506
2507
|
xhigh: "X-High",
|
|
2507
2508
|
max: "Max"
|
|
2508
2509
|
};
|
|
2509
|
-
const API$
|
|
2510
|
-
async function fetchApi$
|
|
2511
|
-
const res = await fetch(`${API$
|
|
2510
|
+
const API$6 = "/command-code/api";
|
|
2511
|
+
async function fetchApi$6(path, options) {
|
|
2512
|
+
const res = await fetch(`${API$6}${path}`, {
|
|
2512
2513
|
...options,
|
|
2513
2514
|
headers: {
|
|
2514
2515
|
"Content-Type": "application/json",
|
|
@@ -2520,19 +2521,19 @@ window.__ModuleLoader__.load({
|
|
|
2520
2521
|
return json.value;
|
|
2521
2522
|
}
|
|
2522
2523
|
/** Parse "1M", "512K", "200000" into a positive integer token count. */
|
|
2523
|
-
function parsePositiveCapacity$
|
|
2524
|
+
function parsePositiveCapacity$2(value) {
|
|
2524
2525
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
2525
2526
|
if (matched === null) return null;
|
|
2526
2527
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
2527
2528
|
const parsed = Number(matched[1]) * multiplier;
|
|
2528
2529
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
2529
2530
|
}
|
|
2530
|
-
function formatCapacity$
|
|
2531
|
+
function formatCapacity$2(value) {
|
|
2531
2532
|
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
2532
2533
|
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
2533
2534
|
return String(value);
|
|
2534
2535
|
}
|
|
2535
|
-
function formatReset$
|
|
2536
|
+
function formatReset$2(resetsAt) {
|
|
2536
2537
|
if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
|
|
2537
2538
|
const diff = resetsAt - Date.now();
|
|
2538
2539
|
if (diff <= 0) return "now";
|
|
@@ -2552,7 +2553,7 @@ window.__ModuleLoader__.load({
|
|
|
2552
2553
|
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
2553
2554
|
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
2554
2555
|
const [apiKey, setApiKey] = (0, react.useState)("");
|
|
2555
|
-
const t = zh$
|
|
2556
|
+
const t = zh$3;
|
|
2556
2557
|
const notifyChange = (0, react.useCallback)(() => {
|
|
2557
2558
|
onModelChange?.();
|
|
2558
2559
|
loadModelDirectory?.();
|
|
@@ -2560,10 +2561,10 @@ window.__ModuleLoader__.load({
|
|
|
2560
2561
|
const loadStatus = (0, react.useCallback)(async (quiet = false) => {
|
|
2561
2562
|
if (!quiet) setError(null);
|
|
2562
2563
|
try {
|
|
2563
|
-
const data = await fetchApi$
|
|
2564
|
+
const data = await fetchApi$6("/status");
|
|
2564
2565
|
setStatus(data);
|
|
2565
2566
|
const drafts = {};
|
|
2566
|
-
for (const model of data.models) drafts[model.id] = formatCapacity$
|
|
2567
|
+
for (const model of data.models) drafts[model.id] = formatCapacity$2(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
2567
2568
|
setContextDrafts(drafts);
|
|
2568
2569
|
} catch (err) {
|
|
2569
2570
|
if (!quiet) setError(err instanceof Error ? err.message : String(err));
|
|
@@ -2588,12 +2589,12 @@ window.__ModuleLoader__.load({
|
|
|
2588
2589
|
setBusy("login");
|
|
2589
2590
|
setError(null);
|
|
2590
2591
|
setLoginProgress(null);
|
|
2591
|
-
const flow = await fetchApi$
|
|
2592
|
+
const flow = await fetchApi$6("/login", { method: "POST" });
|
|
2592
2593
|
if (flow.authUrl) window.open(flow.authUrl, "_blank");
|
|
2593
2594
|
const pollTimer = window.setInterval(() => {
|
|
2594
2595
|
(async () => {
|
|
2595
2596
|
try {
|
|
2596
|
-
const poll = await fetchApi$
|
|
2597
|
+
const poll = await fetchApi$6("/login/status");
|
|
2597
2598
|
if (poll.progress) setLoginProgress(poll.progress);
|
|
2598
2599
|
if (poll.status === "complete") {
|
|
2599
2600
|
window.clearInterval(pollTimer);
|
|
@@ -2625,7 +2626,7 @@ window.__ModuleLoader__.load({
|
|
|
2625
2626
|
try {
|
|
2626
2627
|
setBusy("apikey");
|
|
2627
2628
|
setError(null);
|
|
2628
|
-
const updated = await fetchApi$
|
|
2629
|
+
const updated = await fetchApi$6("/login/apikey", {
|
|
2629
2630
|
method: "POST",
|
|
2630
2631
|
body: JSON.stringify({ apiKey })
|
|
2631
2632
|
});
|
|
@@ -2643,7 +2644,7 @@ window.__ModuleLoader__.load({
|
|
|
2643
2644
|
try {
|
|
2644
2645
|
setBusy(`${action}-${accountId}`);
|
|
2645
2646
|
setError(null);
|
|
2646
|
-
const updated = await fetchApi$
|
|
2647
|
+
const updated = await fetchApi$6("/accounts", {
|
|
2647
2648
|
method: "POST",
|
|
2648
2649
|
body: JSON.stringify({
|
|
2649
2650
|
action,
|
|
@@ -2662,7 +2663,7 @@ window.__ModuleLoader__.load({
|
|
|
2662
2663
|
try {
|
|
2663
2664
|
setBusy("strategy");
|
|
2664
2665
|
setError(null);
|
|
2665
|
-
const updated = await fetchApi$
|
|
2666
|
+
const updated = await fetchApi$6("/accounts", {
|
|
2666
2667
|
method: "POST",
|
|
2667
2668
|
body: JSON.stringify({
|
|
2668
2669
|
action: "strategy",
|
|
@@ -2685,7 +2686,7 @@ window.__ModuleLoader__.load({
|
|
|
2685
2686
|
const handleRelogin = (accountId) => {
|
|
2686
2687
|
(async () => {
|
|
2687
2688
|
try {
|
|
2688
|
-
const updated = await fetchApi$
|
|
2689
|
+
const updated = await fetchApi$6("/accounts", {
|
|
2689
2690
|
method: "POST",
|
|
2690
2691
|
body: JSON.stringify({
|
|
2691
2692
|
action: "relogin",
|
|
@@ -2704,7 +2705,7 @@ window.__ModuleLoader__.load({
|
|
|
2704
2705
|
try {
|
|
2705
2706
|
setBusy("quota");
|
|
2706
2707
|
setError(null);
|
|
2707
|
-
const updated = await fetchApi$
|
|
2708
|
+
const updated = await fetchApi$6("/quota", { method: "POST" });
|
|
2708
2709
|
setStatus(updated);
|
|
2709
2710
|
} catch (err) {
|
|
2710
2711
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -2716,10 +2717,10 @@ window.__ModuleLoader__.load({
|
|
|
2716
2717
|
try {
|
|
2717
2718
|
setBusy("catalog");
|
|
2718
2719
|
setError(null);
|
|
2719
|
-
const updated = await fetchApi$
|
|
2720
|
+
const updated = await fetchApi$6("/catalog/refresh", { method: "POST" });
|
|
2720
2721
|
setStatus(updated);
|
|
2721
2722
|
const drafts = {};
|
|
2722
|
-
for (const model of updated.models) drafts[model.id] = formatCapacity$
|
|
2723
|
+
for (const model of updated.models) drafts[model.id] = formatCapacity$2(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
2723
2724
|
setContextDrafts(drafts);
|
|
2724
2725
|
notifyChange();
|
|
2725
2726
|
} catch (err) {
|
|
@@ -2732,7 +2733,7 @@ window.__ModuleLoader__.load({
|
|
|
2732
2733
|
try {
|
|
2733
2734
|
setBusy("connection");
|
|
2734
2735
|
setError(null);
|
|
2735
|
-
await fetchApi$
|
|
2736
|
+
await fetchApi$6("/connection/test", { method: "POST" });
|
|
2736
2737
|
await loadStatus(true);
|
|
2737
2738
|
} catch (err) {
|
|
2738
2739
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -2742,7 +2743,7 @@ window.__ModuleLoader__.load({
|
|
|
2742
2743
|
};
|
|
2743
2744
|
const applyEnabled = async (enabledModelIds) => {
|
|
2744
2745
|
try {
|
|
2745
|
-
const updated = await fetchApi$
|
|
2746
|
+
const updated = await fetchApi$6("/models", {
|
|
2746
2747
|
method: "POST",
|
|
2747
2748
|
body: JSON.stringify({ enabledModelIds })
|
|
2748
2749
|
});
|
|
@@ -2758,7 +2759,7 @@ window.__ModuleLoader__.load({
|
|
|
2758
2759
|
enabled
|
|
2759
2760
|
} : prev);
|
|
2760
2761
|
try {
|
|
2761
|
-
const updated = await fetchApi$
|
|
2762
|
+
const updated = await fetchApi$6("/settings", {
|
|
2762
2763
|
method: "POST",
|
|
2763
2764
|
body: JSON.stringify({ enabled })
|
|
2764
2765
|
});
|
|
@@ -2781,7 +2782,7 @@ window.__ModuleLoader__.load({
|
|
|
2781
2782
|
};
|
|
2782
2783
|
const handleUpdateEffort = async (effort) => {
|
|
2783
2784
|
try {
|
|
2784
|
-
const updated = await fetchApi$
|
|
2785
|
+
const updated = await fetchApi$6("/settings", {
|
|
2785
2786
|
method: "POST",
|
|
2786
2787
|
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
2787
2788
|
});
|
|
@@ -2793,7 +2794,7 @@ window.__ModuleLoader__.load({
|
|
|
2793
2794
|
};
|
|
2794
2795
|
const handleSaveContextWindow = async (modelId) => {
|
|
2795
2796
|
const raw = contextDrafts[modelId] || "";
|
|
2796
|
-
const parsed = parsePositiveCapacity$
|
|
2797
|
+
const parsed = parsePositiveCapacity$2(raw);
|
|
2797
2798
|
if (parsed === null) {
|
|
2798
2799
|
setError(`Invalid context capacity: ${raw}`);
|
|
2799
2800
|
return;
|
|
@@ -2801,14 +2802,14 @@ window.__ModuleLoader__.load({
|
|
|
2801
2802
|
try {
|
|
2802
2803
|
setSavingModel(modelId);
|
|
2803
2804
|
setError(null);
|
|
2804
|
-
const updated = await fetchApi$
|
|
2805
|
+
const updated = await fetchApi$6("/settings", {
|
|
2805
2806
|
method: "POST",
|
|
2806
2807
|
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
2807
2808
|
});
|
|
2808
2809
|
setStatus(updated);
|
|
2809
2810
|
setContextDrafts((prev) => ({
|
|
2810
2811
|
...prev,
|
|
2811
|
-
[modelId]: formatCapacity$
|
|
2812
|
+
[modelId]: formatCapacity$2(parsed)
|
|
2812
2813
|
}));
|
|
2813
2814
|
notifyChange();
|
|
2814
2815
|
} catch (err) {
|
|
@@ -3004,7 +3005,7 @@ window.__ModuleLoader__.load({
|
|
|
3004
3005
|
children: t.defaultEffortAuto
|
|
3005
3006
|
}), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3006
3007
|
value: effort,
|
|
3007
|
-
children: EFFORT_LABELS[effort]
|
|
3008
|
+
children: EFFORT_LABELS$1[effort]
|
|
3008
3009
|
}, effort))]
|
|
3009
3010
|
})]
|
|
3010
3011
|
})]
|
|
@@ -3098,7 +3099,7 @@ window.__ModuleLoader__.load({
|
|
|
3098
3099
|
}),
|
|
3099
3100
|
window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3100
3101
|
className: "dsha-meter-meta",
|
|
3101
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$
|
|
3102
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(window.resetsAt)] })
|
|
3102
3103
|
})
|
|
3103
3104
|
]
|
|
3104
3105
|
}, window.id)),
|
|
@@ -3123,7 +3124,7 @@ window.__ModuleLoader__.load({
|
|
|
3123
3124
|
meter.used ?? "—",
|
|
3124
3125
|
" / ",
|
|
3125
3126
|
meter.limit ?? "—"
|
|
3126
|
-
] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$
|
|
3127
|
+
] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(meter.resetsAt)] })]
|
|
3127
3128
|
}) : meter.description !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3128
3129
|
className: "dsha-meter-meta",
|
|
3129
3130
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.description })
|
|
@@ -3162,7 +3163,7 @@ window.__ModuleLoader__.load({
|
|
|
3162
3163
|
//#endregion
|
|
3163
3164
|
//#region src/client/kimi-code/locales.ts
|
|
3164
3165
|
const NS_KIMI_CODE = "dsh-kimi-code";
|
|
3165
|
-
const zh$
|
|
3166
|
+
const zh$2 = {
|
|
3166
3167
|
...accountPoolZh,
|
|
3167
3168
|
title: "Kimi Code",
|
|
3168
3169
|
pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
|
|
@@ -3275,7 +3276,7 @@ window.__ModuleLoader__.load({
|
|
|
3275
3276
|
requests: "次请求",
|
|
3276
3277
|
tokens: "tokens"
|
|
3277
3278
|
};
|
|
3278
|
-
const en$
|
|
3279
|
+
const en$2 = {
|
|
3279
3280
|
...accountPoolEn,
|
|
3280
3281
|
title: "Kimi Code",
|
|
3281
3282
|
pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
|
|
@@ -3388,11 +3389,11 @@ window.__ModuleLoader__.load({
|
|
|
3388
3389
|
requests: "requests",
|
|
3389
3390
|
tokens: "tokens"
|
|
3390
3391
|
};
|
|
3391
|
-
const dictionaries$
|
|
3392
|
-
zh: zh$
|
|
3393
|
-
"zh-CN": zh$
|
|
3394
|
-
en: en$
|
|
3395
|
-
"en-US": en$
|
|
3392
|
+
const dictionaries$2 = {
|
|
3393
|
+
zh: zh$2,
|
|
3394
|
+
"zh-CN": zh$2,
|
|
3395
|
+
en: en$2,
|
|
3396
|
+
"en-US": en$2
|
|
3396
3397
|
};
|
|
3397
3398
|
//#endregion
|
|
3398
3399
|
//#region src/client/kimi-code/KimiModelCapabilities.tsx
|
|
@@ -3405,7 +3406,7 @@ window.__ModuleLoader__.load({
|
|
|
3405
3406
|
* Capabilities are now short tags in their own columns, with the per-model
|
|
3406
3407
|
* detail kept in a hover title.
|
|
3407
3408
|
*/
|
|
3408
|
-
const t = zh$
|
|
3409
|
+
const t = zh$2;
|
|
3409
3410
|
function KimiModelCapabilities({ models }) {
|
|
3410
3411
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3411
3412
|
className: "dsha-cap-table",
|
|
@@ -3449,9 +3450,9 @@ window.__ModuleLoader__.load({
|
|
|
3449
3450
|
}
|
|
3450
3451
|
//#endregion
|
|
3451
3452
|
//#region src/client/kimi-code/KimiCodeSection.tsx
|
|
3452
|
-
const API$
|
|
3453
|
-
async function fetchApi$
|
|
3454
|
-
const res = await fetch(`${API$
|
|
3453
|
+
const API$5 = "/kimi-code/api";
|
|
3454
|
+
async function fetchApi$5(path, options) {
|
|
3455
|
+
const res = await fetch(`${API$5}${path}`, {
|
|
3455
3456
|
...options,
|
|
3456
3457
|
headers: {
|
|
3457
3458
|
"Content-Type": "application/json",
|
|
@@ -3463,19 +3464,19 @@ window.__ModuleLoader__.load({
|
|
|
3463
3464
|
return json.value;
|
|
3464
3465
|
}
|
|
3465
3466
|
/** Parse "1M", "512K", "200000" into a positive integer token count. */
|
|
3466
|
-
function parsePositiveCapacity(value) {
|
|
3467
|
+
function parsePositiveCapacity$1(value) {
|
|
3467
3468
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
3468
3469
|
if (matched === null) return null;
|
|
3469
3470
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
3470
3471
|
const parsed = Number(matched[1]) * multiplier;
|
|
3471
3472
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
3472
3473
|
}
|
|
3473
|
-
function formatCapacity(value) {
|
|
3474
|
+
function formatCapacity$1(value) {
|
|
3474
3475
|
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
3475
3476
|
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
3476
3477
|
return String(value);
|
|
3477
3478
|
}
|
|
3478
|
-
function formatDate(ms) {
|
|
3479
|
+
function formatDate$1(ms) {
|
|
3479
3480
|
if (ms === void 0 || ms === null || ms <= 0) return "—";
|
|
3480
3481
|
try {
|
|
3481
3482
|
return new Intl.DateTimeFormat(void 0, {
|
|
@@ -3486,7 +3487,7 @@ window.__ModuleLoader__.load({
|
|
|
3486
3487
|
return "—";
|
|
3487
3488
|
}
|
|
3488
3489
|
}
|
|
3489
|
-
function formatReset(resetsAt) {
|
|
3490
|
+
function formatReset$1(resetsAt) {
|
|
3490
3491
|
if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
|
|
3491
3492
|
const diff = resetsAt - Date.now();
|
|
3492
3493
|
if (diff <= 0) return "now";
|
|
@@ -3511,10 +3512,10 @@ window.__ModuleLoader__.load({
|
|
|
3511
3512
|
}
|
|
3512
3513
|
}
|
|
3513
3514
|
const EFFORT_LABEL = {
|
|
3514
|
-
low: zh$
|
|
3515
|
-
high: zh$
|
|
3516
|
-
max: zh$
|
|
3517
|
-
none: zh$
|
|
3515
|
+
low: zh$2.effortLow,
|
|
3516
|
+
high: zh$2.effortHigh,
|
|
3517
|
+
max: zh$2.effortMax,
|
|
3518
|
+
none: zh$2.effortNone
|
|
3518
3519
|
};
|
|
3519
3520
|
function KimiCodeSection({ onModelChange, loadModelDirectory }) {
|
|
3520
3521
|
const [status, setStatus] = (0, react.useState)(null);
|
|
@@ -3526,7 +3527,7 @@ window.__ModuleLoader__.load({
|
|
|
3526
3527
|
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
3527
3528
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
3528
3529
|
const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
|
|
3529
|
-
const t = zh$
|
|
3530
|
+
const t = zh$2;
|
|
3530
3531
|
const notifyChange = (0, react.useCallback)(() => {
|
|
3531
3532
|
onModelChange?.();
|
|
3532
3533
|
loadModelDirectory?.();
|
|
@@ -3534,10 +3535,10 @@ window.__ModuleLoader__.load({
|
|
|
3534
3535
|
const loadStatus = (0, react.useCallback)(async (quiet = false) => {
|
|
3535
3536
|
if (!quiet) setError(null);
|
|
3536
3537
|
try {
|
|
3537
|
-
const data = await fetchApi$
|
|
3538
|
+
const data = await fetchApi$5("/status");
|
|
3538
3539
|
setStatus(data);
|
|
3539
3540
|
const drafts = {};
|
|
3540
|
-
for (const model of data.models) drafts[model.id] = formatCapacity(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3541
|
+
for (const model of data.models) drafts[model.id] = formatCapacity$1(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3541
3542
|
setContextDrafts(drafts);
|
|
3542
3543
|
} catch (err) {
|
|
3543
3544
|
if (!quiet) setError(err instanceof Error ? err.message : String(err));
|
|
@@ -3562,7 +3563,7 @@ window.__ModuleLoader__.load({
|
|
|
3562
3563
|
const timer = window.setInterval(() => {
|
|
3563
3564
|
(async () => {
|
|
3564
3565
|
try {
|
|
3565
|
-
const poll = await fetchApi$
|
|
3566
|
+
const poll = await fetchApi$5("/login/status");
|
|
3566
3567
|
setFlow(poll);
|
|
3567
3568
|
if (poll.status === "complete") {
|
|
3568
3569
|
await loadStatus();
|
|
@@ -3583,7 +3584,7 @@ window.__ModuleLoader__.load({
|
|
|
3583
3584
|
setBusy("login");
|
|
3584
3585
|
setError(null);
|
|
3585
3586
|
setCopied(false);
|
|
3586
|
-
const next = await fetchApi$
|
|
3587
|
+
const next = await fetchApi$5("/login", {
|
|
3587
3588
|
method: "POST",
|
|
3588
3589
|
body: JSON.stringify({})
|
|
3589
3590
|
});
|
|
@@ -3596,7 +3597,7 @@ window.__ModuleLoader__.load({
|
|
|
3596
3597
|
};
|
|
3597
3598
|
const handleCancelLogin = async () => {
|
|
3598
3599
|
try {
|
|
3599
|
-
await fetchApi$
|
|
3600
|
+
await fetchApi$5("/login/cancel", { method: "POST" });
|
|
3600
3601
|
setFlow({ status: "idle" });
|
|
3601
3602
|
} catch (err) {
|
|
3602
3603
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -3616,7 +3617,7 @@ window.__ModuleLoader__.load({
|
|
|
3616
3617
|
try {
|
|
3617
3618
|
setBusy(`${action}-${accountId}`);
|
|
3618
3619
|
setError(null);
|
|
3619
|
-
const updated = await fetchApi$
|
|
3620
|
+
const updated = await fetchApi$5("/accounts", {
|
|
3620
3621
|
method: "POST",
|
|
3621
3622
|
body: JSON.stringify({
|
|
3622
3623
|
action,
|
|
@@ -3636,7 +3637,7 @@ window.__ModuleLoader__.load({
|
|
|
3636
3637
|
try {
|
|
3637
3638
|
setBusy("strategy");
|
|
3638
3639
|
setError(null);
|
|
3639
|
-
const updated = await fetchApi$
|
|
3640
|
+
const updated = await fetchApi$5("/accounts", {
|
|
3640
3641
|
method: "POST",
|
|
3641
3642
|
body: JSON.stringify({
|
|
3642
3643
|
action: "strategy",
|
|
@@ -3659,7 +3660,7 @@ window.__ModuleLoader__.load({
|
|
|
3659
3660
|
const handleRelogin = (accountId) => {
|
|
3660
3661
|
(async () => {
|
|
3661
3662
|
try {
|
|
3662
|
-
const updated = await fetchApi$
|
|
3663
|
+
const updated = await fetchApi$5("/accounts", {
|
|
3663
3664
|
method: "POST",
|
|
3664
3665
|
body: JSON.stringify({
|
|
3665
3666
|
action: "relogin",
|
|
@@ -3678,7 +3679,7 @@ window.__ModuleLoader__.load({
|
|
|
3678
3679
|
try {
|
|
3679
3680
|
setBusy("quota");
|
|
3680
3681
|
setError(null);
|
|
3681
|
-
const updated = await fetchApi$
|
|
3682
|
+
const updated = await fetchApi$5("/quota", { method: "POST" });
|
|
3682
3683
|
setStatus(updated);
|
|
3683
3684
|
} catch (err) {
|
|
3684
3685
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -3691,10 +3692,10 @@ window.__ModuleLoader__.load({
|
|
|
3691
3692
|
try {
|
|
3692
3693
|
setBusy("catalog");
|
|
3693
3694
|
setError(null);
|
|
3694
|
-
const updated = await fetchApi$
|
|
3695
|
+
const updated = await fetchApi$5("/catalog/refresh", { method: "POST" });
|
|
3695
3696
|
setStatus(updated);
|
|
3696
3697
|
const drafts = {};
|
|
3697
|
-
for (const model of updated.models) drafts[model.id] = formatCapacity(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3698
|
+
for (const model of updated.models) drafts[model.id] = formatCapacity$1(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3698
3699
|
setContextDrafts(drafts);
|
|
3699
3700
|
notifyChange();
|
|
3700
3701
|
} catch (err) {
|
|
@@ -3708,7 +3709,7 @@ window.__ModuleLoader__.load({
|
|
|
3708
3709
|
setBusy("connection");
|
|
3709
3710
|
setError(null);
|
|
3710
3711
|
setConnectionNotice(null);
|
|
3711
|
-
const result = await fetchApi$
|
|
3712
|
+
const result = await fetchApi$5("/connection/test", { method: "POST" });
|
|
3712
3713
|
setConnectionNotice(result.connected ? `${t.testSuccess} · ${result.latencyMs} ms` : t.testFailed);
|
|
3713
3714
|
await loadStatus(true);
|
|
3714
3715
|
} catch (err) {
|
|
@@ -3719,7 +3720,7 @@ window.__ModuleLoader__.load({
|
|
|
3719
3720
|
};
|
|
3720
3721
|
const applyEnabled = async (enabledModelIds) => {
|
|
3721
3722
|
try {
|
|
3722
|
-
const updated = await fetchApi$
|
|
3723
|
+
const updated = await fetchApi$5("/models", {
|
|
3723
3724
|
method: "POST",
|
|
3724
3725
|
body: JSON.stringify({ enabledModelIds })
|
|
3725
3726
|
});
|
|
@@ -3735,7 +3736,7 @@ window.__ModuleLoader__.load({
|
|
|
3735
3736
|
enabled
|
|
3736
3737
|
} : prev);
|
|
3737
3738
|
try {
|
|
3738
|
-
const updated = await fetchApi$
|
|
3739
|
+
const updated = await fetchApi$5("/settings", {
|
|
3739
3740
|
method: "POST",
|
|
3740
3741
|
body: JSON.stringify({ enabled })
|
|
3741
3742
|
});
|
|
@@ -3758,7 +3759,7 @@ window.__ModuleLoader__.load({
|
|
|
3758
3759
|
};
|
|
3759
3760
|
const handleUpdateEffort = async (effort) => {
|
|
3760
3761
|
try {
|
|
3761
|
-
const updated = await fetchApi$
|
|
3762
|
+
const updated = await fetchApi$5("/settings", {
|
|
3762
3763
|
method: "POST",
|
|
3763
3764
|
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
3764
3765
|
});
|
|
@@ -3770,7 +3771,7 @@ window.__ModuleLoader__.load({
|
|
|
3770
3771
|
};
|
|
3771
3772
|
const handleSaveContextWindow = async (modelId) => {
|
|
3772
3773
|
const raw = contextDrafts[modelId] || "";
|
|
3773
|
-
const parsed = parsePositiveCapacity(raw);
|
|
3774
|
+
const parsed = parsePositiveCapacity$1(raw);
|
|
3774
3775
|
if (parsed === null) {
|
|
3775
3776
|
setError(`Invalid context capacity: ${raw}`);
|
|
3776
3777
|
return;
|
|
@@ -3778,14 +3779,14 @@ window.__ModuleLoader__.load({
|
|
|
3778
3779
|
try {
|
|
3779
3780
|
setSavingModel(modelId);
|
|
3780
3781
|
setError(null);
|
|
3781
|
-
const updated = await fetchApi$
|
|
3782
|
+
const updated = await fetchApi$5("/settings", {
|
|
3782
3783
|
method: "POST",
|
|
3783
3784
|
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
3784
3785
|
});
|
|
3785
3786
|
setStatus(updated);
|
|
3786
3787
|
setContextDrafts((prev) => ({
|
|
3787
3788
|
...prev,
|
|
3788
|
-
[modelId]: formatCapacity(parsed)
|
|
3789
|
+
[modelId]: formatCapacity$1(parsed)
|
|
3789
3790
|
}));
|
|
3790
3791
|
notifyChange();
|
|
3791
3792
|
} catch (err) {
|
|
@@ -3872,7 +3873,7 @@ window.__ModuleLoader__.load({
|
|
|
3872
3873
|
children: t.codeExpires
|
|
3873
3874
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3874
3875
|
className: "dsha-value",
|
|
3875
|
-
children: formatDate(flow?.expiresAt)
|
|
3876
|
+
children: formatDate$1(flow?.expiresAt)
|
|
3876
3877
|
})]
|
|
3877
3878
|
}),
|
|
3878
3879
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4075,7 +4076,7 @@ window.__ModuleLoader__.load({
|
|
|
4075
4076
|
title: model.id,
|
|
4076
4077
|
children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4077
4078
|
className: "dsha-model-meta",
|
|
4078
|
-
children: formatCapacity(model.contextWindow)
|
|
4079
|
+
children: formatCapacity$1(model.contextWindow)
|
|
4079
4080
|
})]
|
|
4080
4081
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4081
4082
|
className: "dsha-capacity-control",
|
|
@@ -4160,7 +4161,7 @@ window.__ModuleLoader__.load({
|
|
|
4160
4161
|
window.limit ?? "—",
|
|
4161
4162
|
" ",
|
|
4162
4163
|
t.requests
|
|
4163
|
-
] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset(window.resetsAt)) })]
|
|
4164
|
+
] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset$1(window.resetsAt)) })]
|
|
4164
4165
|
})
|
|
4165
4166
|
]
|
|
4166
4167
|
}, window.id);
|
|
@@ -4199,71 +4200,1120 @@ window.__ModuleLoader__.load({
|
|
|
4199
4200
|
});
|
|
4200
4201
|
}
|
|
4201
4202
|
//#endregion
|
|
4202
|
-
//#region src/
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
},
|
|
4212
|
-
{
|
|
4213
|
-
id: "command-code",
|
|
4214
|
-
label: "Command Code"
|
|
4215
|
-
},
|
|
4216
|
-
{
|
|
4217
|
-
id: "kimi-code",
|
|
4218
|
-
label: "Kimi Code"
|
|
4219
|
-
}
|
|
4203
|
+
//#region src/shared/workbuddy-contracts.ts
|
|
4204
|
+
/** Every level this route can name, in escalating order (the card's sort key). */
|
|
4205
|
+
const WORKBUDDY_REASONING_EFFORTS = [
|
|
4206
|
+
"minimal",
|
|
4207
|
+
"low",
|
|
4208
|
+
"medium",
|
|
4209
|
+
"high",
|
|
4210
|
+
"xhigh",
|
|
4211
|
+
"max"
|
|
4220
4212
|
];
|
|
4213
|
+
//#endregion
|
|
4214
|
+
//#region src/client/workbuddy/locales.ts
|
|
4215
|
+
const NS_WORKBUDDY = "dsh-workbuddy";
|
|
4216
|
+
const zh$1 = {
|
|
4217
|
+
title: "WorkBuddy",
|
|
4218
|
+
pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
|
|
4219
|
+
account: "账号",
|
|
4220
|
+
noAccounts: "暂无账号。点击右上角「添加账号」完成浏览器授权,或登录 CodeBuddy 桌面端后重新扫描;桌面账号只能从本插件隐藏,绝不删除 CodeBuddy 的原凭据。",
|
|
4221
|
+
signedOut: "未找到凭据",
|
|
4222
|
+
nickname: "昵称",
|
|
4223
|
+
uin: "UIN",
|
|
4224
|
+
region: "区域",
|
|
4225
|
+
regionCn: "国区",
|
|
4226
|
+
regionIntl: "国际区",
|
|
4227
|
+
accountType: "账号类型",
|
|
4228
|
+
sourceFile: "凭据文件",
|
|
4229
|
+
authDirectory: "凭据目录",
|
|
4230
|
+
storage: "凭据存储",
|
|
4231
|
+
storageNotice: "桌面端账号仍读取 CodeBuddy 自己的凭据文件,插件不会删除这些文件;通过这里添加的账号保存在系统加密存储中(Windows DPAPI / macOS Keychain / Linux Secret Service),token 不进入浏览器。",
|
|
4232
|
+
routeUnreachable: "无法读取 WorkBuddy 设置路由",
|
|
4233
|
+
routeUnreachableHint: "浏览器里加载的插件版本可能比 Host 进程里运行的新(客户端资源是现读磁盘的,Host 只在启动时加载)。请重启 DSH,让两端来自同一份构建。",
|
|
4234
|
+
rescan: "重新扫描",
|
|
4235
|
+
rescanning: "扫描中...",
|
|
4236
|
+
accounts: "账号管理",
|
|
4237
|
+
addCnAccount: "添加国区账号",
|
|
4238
|
+
addIntlAccount: "添加国际区账号",
|
|
4239
|
+
authorizing: "授权中…",
|
|
4240
|
+
loginWaiting: "请在新打开的浏览器页面完成登录与授权。",
|
|
4241
|
+
loginFailed: "账号授权失败",
|
|
4242
|
+
encryptedStorage: "系统加密存储",
|
|
4243
|
+
hiddenAccount: "已隐藏",
|
|
4244
|
+
hideAccount: "从插件隐藏",
|
|
4245
|
+
restoreAccount: "恢复显示",
|
|
4246
|
+
deleteAccount: "删除账号",
|
|
4247
|
+
deleteConfirm: "确定删除这个插件托管的账号吗?加密存储中的登录凭据会被移除。",
|
|
4248
|
+
connection: "连接",
|
|
4249
|
+
provider: "Provider",
|
|
4250
|
+
providerValue: "WorkBuddy Subscription · workbuddy-subscription",
|
|
4251
|
+
connectionState: "连接状态",
|
|
4252
|
+
connected: "已连接",
|
|
4253
|
+
untested: "未测试",
|
|
4254
|
+
testConnection: "测试连接",
|
|
4255
|
+
testingConnection: "测试中...",
|
|
4256
|
+
latency: "延迟",
|
|
4257
|
+
routeOwned: "模型路由由本插件提供",
|
|
4258
|
+
routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
|
|
4259
|
+
modelsSection: "模型",
|
|
4260
|
+
enableProvider: "启用此供应商",
|
|
4261
|
+
modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;未勾选或关闭上方开关可在列表中隐藏该供应商。目录与上下文窗口来自订阅网关的模型目录,并按账号所在区域过滤——跨区调用会被上游拒绝。",
|
|
4262
|
+
refreshCatalog: "刷新模型目录",
|
|
4263
|
+
refreshingCatalog: "刷新中...",
|
|
4264
|
+
selectAll: "全选",
|
|
4265
|
+
unselectAll: "全不选",
|
|
4266
|
+
imageSupport: "图片",
|
|
4267
|
+
textOnly: "纯文本",
|
|
4268
|
+
regionBadge: "区域",
|
|
4269
|
+
unavailableHere: "当前区域不可用",
|
|
4270
|
+
enhanced: "增强功能",
|
|
4271
|
+
defaultReasoningEffort: "默认思考深度",
|
|
4272
|
+
defaultReasoningEffortHint: "控制支持推理的模型在未单独指定时的思考强度。",
|
|
4273
|
+
defaultEffortAuto: "使用模型默认值",
|
|
4274
|
+
effortUnsupported: "当前模型不支持",
|
|
4275
|
+
noReasoningModels: "当前账号的模型都没有声明可用的思考档位,因此没有可选的默认档位。",
|
|
4276
|
+
defaultEffortKept: "已保存的档位不被当前任何模型支持,已保留但不会生效。",
|
|
4277
|
+
contextWindowSection: "模型上下文窗口",
|
|
4278
|
+
contextWindowHint: "默认值来自订阅网关的模型目录(每个模型的真实上下文上限);可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
|
|
4279
|
+
save: "保存",
|
|
4280
|
+
saved: "已保存",
|
|
4281
|
+
saving: "保存中...",
|
|
4282
|
+
quotaSection: "用量与配额",
|
|
4283
|
+
quotaDesc: "数据来自订阅的计费接口,页面可见时最多每 60 秒刷新一次。",
|
|
4284
|
+
refreshQuota: "刷新用量",
|
|
4285
|
+
refreshingQuota: "刷新中...",
|
|
4286
|
+
quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
|
|
4287
|
+
quotaPackage: "套餐",
|
|
4288
|
+
quotaRemaining: "剩余额度",
|
|
4289
|
+
quotaCycle: "本周期已用",
|
|
4290
|
+
quotaReset: "重置时间",
|
|
4291
|
+
updatedAt: "更新时间:{time}",
|
|
4292
|
+
loading: "加载中...",
|
|
4293
|
+
credits: "credits",
|
|
4294
|
+
composerLabel: "额度"
|
|
4295
|
+
};
|
|
4296
|
+
const en$1 = {
|
|
4297
|
+
title: "WorkBuddy",
|
|
4298
|
+
pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
|
|
4299
|
+
account: "Account",
|
|
4300
|
+
noAccounts: "No accounts yet. Use “Add account” above to authorize, or sign in with the CodeBuddy desktop client and rescan; desktop accounts can only be hidden here, never removed from CodeBuddy.",
|
|
4301
|
+
signedOut: "No credential found",
|
|
4302
|
+
nickname: "Nickname",
|
|
4303
|
+
uin: "UIN",
|
|
4304
|
+
region: "Region",
|
|
4305
|
+
regionCn: "China",
|
|
4306
|
+
regionIntl: "International",
|
|
4307
|
+
accountType: "Account type",
|
|
4308
|
+
sourceFile: "Credential file",
|
|
4309
|
+
authDirectory: "Credential directory",
|
|
4310
|
+
storage: "Credential storage",
|
|
4311
|
+
storageNotice: "Desktop accounts continue to use CodeBuddy’s credential files, which this plugin never deletes. Accounts added here use encrypted OS storage (Windows DPAPI, macOS Keychain, or Linux Secret Service); tokens never enter the browser.",
|
|
4312
|
+
routeUnreachable: "The WorkBuddy settings route could not be read",
|
|
4313
|
+
routeUnreachableHint: "The plugin loaded in the browser may be newer than the one running in the Host: client assets are read from disk on demand, while the Host loads them only at startup. Restart DSH so both halves come from the same build.",
|
|
4314
|
+
rescan: "Rescan",
|
|
4315
|
+
rescanning: "Scanning...",
|
|
4316
|
+
accounts: "Account Management",
|
|
4317
|
+
addCnAccount: "Add China account",
|
|
4318
|
+
addIntlAccount: "Add international account",
|
|
4319
|
+
authorizing: "Authorizing…",
|
|
4320
|
+
loginWaiting: "Complete sign-in and authorization in the newly opened browser page.",
|
|
4321
|
+
loginFailed: "Account authorization failed",
|
|
4322
|
+
encryptedStorage: "Encrypted OS storage",
|
|
4323
|
+
hiddenAccount: "Hidden",
|
|
4324
|
+
hideAccount: "Hide from plugin",
|
|
4325
|
+
restoreAccount: "Restore",
|
|
4326
|
+
deleteAccount: "Delete account",
|
|
4327
|
+
deleteConfirm: "Delete this plugin-managed account? Its encrypted credential will be removed.",
|
|
4328
|
+
connection: "Connection",
|
|
4329
|
+
provider: "Provider",
|
|
4330
|
+
providerValue: "WorkBuddy Subscription · workbuddy-subscription",
|
|
4331
|
+
connectionState: "Connection state",
|
|
4332
|
+
connected: "Connected",
|
|
4333
|
+
untested: "Untested",
|
|
4334
|
+
testConnection: "Test connection",
|
|
4335
|
+
testingConnection: "Testing...",
|
|
4336
|
+
latency: "Latency",
|
|
4337
|
+
routeOwned: "This plugin serves the model route",
|
|
4338
|
+
routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
|
|
4339
|
+
modelsSection: "Models",
|
|
4340
|
+
enableProvider: "Enable this provider",
|
|
4341
|
+
modelsHint: "Checked models appear in the DSH conversation model list. The catalog and its context windows come from the subscription gateway and are filtered by the account’s region — the upstream rejects a model asked of the wrong region.",
|
|
4342
|
+
refreshCatalog: "Refresh catalog",
|
|
4343
|
+
refreshingCatalog: "Refreshing...",
|
|
4344
|
+
selectAll: "Select all",
|
|
4345
|
+
unselectAll: "Deselect all",
|
|
4346
|
+
imageSupport: "Images",
|
|
4347
|
+
textOnly: "Text only",
|
|
4348
|
+
regionBadge: "Regions",
|
|
4349
|
+
unavailableHere: "Unavailable in this region",
|
|
4350
|
+
enhanced: "Enhanced features",
|
|
4351
|
+
defaultReasoningEffort: "Default reasoning effort",
|
|
4352
|
+
defaultReasoningEffortHint: "Reasoning effort for models that support it when the conversation does not specify one.",
|
|
4353
|
+
defaultEffortAuto: "Use the model default",
|
|
4354
|
+
effortUnsupported: "unsupported by the current models",
|
|
4355
|
+
noReasoningModels: "None of this account’s models declare a reasoning level, so there is no default to choose.",
|
|
4356
|
+
defaultEffortKept: "The saved level is not supported by any current model; it is kept but has no effect.",
|
|
4357
|
+
contextWindowSection: "Model context window",
|
|
4358
|
+
contextWindowHint: "Defaults come from the subscription gateway’s own catalog (each model’s real context cap); override one with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
|
|
4359
|
+
save: "Save",
|
|
4360
|
+
saved: "Saved",
|
|
4361
|
+
saving: "Saving...",
|
|
4362
|
+
quotaSection: "Usage & quota",
|
|
4363
|
+
quotaDesc: "Read from the subscription billing endpoint; refreshes at most once every 60 seconds while visible.",
|
|
4364
|
+
refreshQuota: "Refresh quota",
|
|
4365
|
+
refreshingQuota: "Refreshing...",
|
|
4366
|
+
quotaEmpty: "No quota data yet — use “Refresh quota” to retry.",
|
|
4367
|
+
quotaPackage: "Package",
|
|
4368
|
+
quotaRemaining: "Remaining credits",
|
|
4369
|
+
quotaCycle: "Used this cycle",
|
|
4370
|
+
quotaReset: "Resets",
|
|
4371
|
+
updatedAt: "Updated at: {time}",
|
|
4372
|
+
loading: "Loading...",
|
|
4373
|
+
credits: "credits",
|
|
4374
|
+
composerLabel: "Quota"
|
|
4375
|
+
};
|
|
4376
|
+
const dictionaries$1 = {
|
|
4377
|
+
zh: zh$1,
|
|
4378
|
+
"zh-CN": zh$1,
|
|
4379
|
+
en: en$1,
|
|
4380
|
+
"en-US": en$1
|
|
4381
|
+
};
|
|
4382
|
+
//#endregion
|
|
4383
|
+
//#region src/client/workbuddy/WorkBuddySection.tsx
|
|
4221
4384
|
/**
|
|
4222
|
-
*
|
|
4223
|
-
* so
|
|
4224
|
-
* the active tab is mounted, mirroring the shell's previous behavior of
|
|
4225
|
-
* mounting just the selected settings page (each provider section refetches
|
|
4226
|
-
* its status on mount).
|
|
4385
|
+
* Display label per reasoning level. The locale dictionary only accepts flat
|
|
4386
|
+
* string values, so this nested table lives with the control that renders it.
|
|
4227
4387
|
*/
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4388
|
+
const EFFORT_LABELS = {
|
|
4389
|
+
minimal: "Minimal",
|
|
4390
|
+
low: "Low",
|
|
4391
|
+
medium: "Medium",
|
|
4392
|
+
high: "High",
|
|
4393
|
+
xhigh: "X-High",
|
|
4394
|
+
max: "Max"
|
|
4395
|
+
};
|
|
4396
|
+
const API$4 = "/workbuddy/api";
|
|
4397
|
+
/**
|
|
4398
|
+
* The shared card's label set.
|
|
4399
|
+
*
|
|
4400
|
+
* Only the three labels WorkBuddy genuinely words differently are taken from
|
|
4401
|
+
* this tab's dictionary; everything else is the shared set, so the five
|
|
4402
|
+
* provider tabs cannot drift apart in wording.
|
|
4403
|
+
*/
|
|
4404
|
+
function accountPoolLabels(t) {
|
|
4405
|
+
return {
|
|
4406
|
+
...accountPoolZh,
|
|
4407
|
+
noAccounts: t.noAccounts,
|
|
4408
|
+
storageNotice: t.storageNotice,
|
|
4409
|
+
email: t.nickname
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4412
|
+
/**
|
|
4413
|
+
* Call one settings route and unwrap its `{ ok, value }` envelope.
|
|
4414
|
+
*
|
|
4415
|
+
* The response body is read as text first, because a route that is not mounted
|
|
4416
|
+
* answers with an empty body — and `res.json()` on that throws a bare
|
|
4417
|
+
* "Unexpected end of JSON input" that says nothing about what actually failed.
|
|
4418
|
+
* That is exactly what happens when the client bundle is newer than the Host
|
|
4419
|
+
* process (a stale Host has no route to answer), so the error is reported as
|
|
4420
|
+
* such instead of as a credential problem.
|
|
4421
|
+
*/
|
|
4422
|
+
async function fetchApi$4(path, options) {
|
|
4423
|
+
const res = await fetch(`${API$4}${path}`, {
|
|
4424
|
+
...options,
|
|
4425
|
+
headers: {
|
|
4426
|
+
"Content-Type": "application/json",
|
|
4427
|
+
...options?.headers
|
|
4428
|
+
}
|
|
4429
|
+
});
|
|
4430
|
+
const text = await res.text();
|
|
4431
|
+
if (text.trim() === "") throw new Error(`The WorkBuddy settings route did not answer (HTTP ${res.status} ${res.statusText || "no body"}). The plugin loaded in the browser may be newer than the one running in the Host — restart DSH so both halves come from the same build.`);
|
|
4432
|
+
let json;
|
|
4433
|
+
try {
|
|
4434
|
+
json = JSON.parse(text);
|
|
4435
|
+
} catch {
|
|
4436
|
+
throw new Error(`The WorkBuddy settings route returned a non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`);
|
|
4437
|
+
}
|
|
4438
|
+
if (!res.ok || json.ok !== true) throw new Error(json.error || `HTTP ${res.status}`);
|
|
4439
|
+
return json.value;
|
|
4440
|
+
}
|
|
4441
|
+
/** Parse "1M", "512K", "200000" into a positive integer token count. */
|
|
4442
|
+
function parsePositiveCapacity(value) {
|
|
4443
|
+
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
4444
|
+
if (matched === null) return null;
|
|
4445
|
+
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
4446
|
+
const parsed = Number(matched[1]) * multiplier;
|
|
4447
|
+
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
4448
|
+
}
|
|
4449
|
+
function formatCapacity(value) {
|
|
4450
|
+
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
4451
|
+
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
4452
|
+
return String(value);
|
|
4453
|
+
}
|
|
4454
|
+
function formatDate(ms) {
|
|
4455
|
+
if (ms === void 0 || ms === null || ms <= 0) return "—";
|
|
4456
|
+
try {
|
|
4457
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
4458
|
+
dateStyle: "medium",
|
|
4459
|
+
timeStyle: "short"
|
|
4460
|
+
}).format(ms);
|
|
4461
|
+
} catch {
|
|
4462
|
+
return "—";
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
function formatReset(resetsAt) {
|
|
4466
|
+
if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
|
|
4467
|
+
const diff = resetsAt - Date.now();
|
|
4468
|
+
if (diff <= 0) return "now";
|
|
4469
|
+
const mins = Math.floor(diff / 6e4);
|
|
4470
|
+
const hours = Math.floor(mins / 60);
|
|
4471
|
+
const days = Math.floor(hours / 24);
|
|
4472
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
4473
|
+
if (hours > 0) return `${hours}h ${mins % 60}m`;
|
|
4474
|
+
return `${mins}m`;
|
|
4475
|
+
}
|
|
4476
|
+
/** Mask a UIN so the card shows identity without publishing the full number. */
|
|
4477
|
+
function maskUin(uin) {
|
|
4478
|
+
if (uin === void 0 || uin === null || uin === "") return "—";
|
|
4479
|
+
if (uin.length <= 6) return uin;
|
|
4480
|
+
return `${uin.slice(0, 4)}****${uin.slice(-2)}`;
|
|
4481
|
+
}
|
|
4482
|
+
/** Shorten an absolute credential path to its file name for display. */
|
|
4483
|
+
function displayFile(file) {
|
|
4484
|
+
if (file === void 0 || file === null || file === "") return "—";
|
|
4485
|
+
const parts = file.split(/[\\/]/);
|
|
4486
|
+
return parts[parts.length - 1] || file;
|
|
4487
|
+
}
|
|
4488
|
+
/**
|
|
4489
|
+
* Reasoning levels the default-effort control may offer.
|
|
4490
|
+
*
|
|
4491
|
+
* The levels come from what this account's models actually declare — never from
|
|
4492
|
+
* the shipped enum alone. The setting is one global default applied to whichever
|
|
4493
|
+
* model a conversation uses, so the list is their union; each entry carries the
|
|
4494
|
+
* models behind it, and a level only some models accept is labelled as such.
|
|
4495
|
+
* Order follows {@link WORKBUDDY_REASONING_EFFORTS}, which is the escalating
|
|
4496
|
+
* order the upstream ladder uses.
|
|
4497
|
+
*/
|
|
4498
|
+
function reasoningEffortChoices(models) {
|
|
4499
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4500
|
+
for (const model of models) for (const effort of model.reasoningEfforts ?? []) {
|
|
4501
|
+
const names = declared.get(effort);
|
|
4502
|
+
if (names === void 0) declared.set(effort, [model.name]);
|
|
4503
|
+
else names.push(model.name);
|
|
4504
|
+
}
|
|
4505
|
+
return WORKBUDDY_REASONING_EFFORTS.filter((effort) => declared.has(effort)).map((effort) => ({
|
|
4506
|
+
value: effort,
|
|
4507
|
+
models: declared.get(effort)
|
|
4508
|
+
}));
|
|
4509
|
+
}
|
|
4510
|
+
/**
|
|
4511
|
+
* Whether a saved default is unusable for every model on this account.
|
|
4512
|
+
*
|
|
4513
|
+
* The adapter drops a level the chosen model does not accept instead of sending
|
|
4514
|
+
* it, so a value that no model declares silently does nothing. Reporting it is
|
|
4515
|
+
* what keeps that from looking like the setting was applied.
|
|
4516
|
+
*/
|
|
4517
|
+
function unsupportedReasoningEffort(configured, models) {
|
|
4518
|
+
if (configured === null || configured === void 0) return null;
|
|
4519
|
+
return models.some((model) => (model.reasoningEfforts ?? []).includes(configured)) ? null : configured;
|
|
4520
|
+
}
|
|
4521
|
+
/** Defend against a response that omits the arrays the card renders. */
|
|
4522
|
+
function normalizeStatus(data) {
|
|
4523
|
+
return {
|
|
4524
|
+
...data,
|
|
4525
|
+
models: Array.isArray(data?.models) ? data.models : [],
|
|
4526
|
+
contextWindowOverrides: data?.contextWindowOverrides ?? {},
|
|
4527
|
+
accounts: Array.isArray(data?.accounts) ? data.accounts : []
|
|
4528
|
+
};
|
|
4529
|
+
}
|
|
4530
|
+
function WorkBuddySection({ onModelChange, loadModelDirectory }) {
|
|
4531
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
4532
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
4533
|
+
const [busy, setBusy] = (0, react.useState)(null);
|
|
4534
|
+
const [error, setError] = (0, react.useState)(null);
|
|
4535
|
+
const [statusFailed, setStatusFailed] = (0, react.useState)(false);
|
|
4536
|
+
const [connection, setConnection] = (0, react.useState)(null);
|
|
4537
|
+
const [loginProgress, setLoginProgress] = (0, react.useState)(null);
|
|
4538
|
+
const loginIntervalRef = (0, react.useRef)(null);
|
|
4539
|
+
const loginTimeoutRef = (0, react.useRef)(null);
|
|
4540
|
+
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
4541
|
+
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
4542
|
+
const t = zh$1;
|
|
4543
|
+
const notifyChange = (0, react.useCallback)(() => {
|
|
4544
|
+
onModelChange?.();
|
|
4545
|
+
loadModelDirectory?.();
|
|
4546
|
+
}, [onModelChange, loadModelDirectory]);
|
|
4547
|
+
const effortChoices = (0, react.useMemo)(() => reasoningEffortChoices(status?.models ?? []), [status?.models]);
|
|
4548
|
+
const allModels = status?.models ?? [];
|
|
4549
|
+
const poolAccounts = (0, react.useMemo)(() => Array.isArray(status?.accounts) ? status.accounts : [], [status?.accounts]);
|
|
4550
|
+
const strayEffort = unsupportedReasoningEffort(status?.defaultReasoningEffort, allModels);
|
|
4551
|
+
const loadStatus = (0, react.useCallback)(async (quiet = false) => {
|
|
4552
|
+
if (!quiet) setError(null);
|
|
4553
|
+
try {
|
|
4554
|
+
const normalized = normalizeStatus(await fetchApi$4("/status"));
|
|
4555
|
+
setStatus(normalized);
|
|
4556
|
+
setStatusFailed(false);
|
|
4557
|
+
const drafts = {};
|
|
4558
|
+
for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
4559
|
+
setContextDrafts(drafts);
|
|
4560
|
+
} catch (err) {
|
|
4561
|
+
setStatusFailed(true);
|
|
4562
|
+
if (!quiet) setError(err instanceof Error ? err.message : String(err));
|
|
4563
|
+
} finally {
|
|
4564
|
+
setLoading(false);
|
|
4565
|
+
}
|
|
4566
|
+
}, []);
|
|
4567
|
+
(0, react.useEffect)(() => {
|
|
4568
|
+
loadStatus();
|
|
4569
|
+
const refreshWhenVisible = () => {
|
|
4570
|
+
if (document.visibilityState === "visible") loadStatus(true);
|
|
4571
|
+
};
|
|
4572
|
+
document.addEventListener("visibilitychange", refreshWhenVisible);
|
|
4573
|
+
return () => {
|
|
4574
|
+
document.removeEventListener("visibilitychange", refreshWhenVisible);
|
|
4575
|
+
if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
|
|
4576
|
+
if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
|
|
4577
|
+
};
|
|
4578
|
+
}, [loadStatus]);
|
|
4579
|
+
const handleRescan = async () => {
|
|
4580
|
+
try {
|
|
4581
|
+
setBusy("rescan");
|
|
4582
|
+
setError(null);
|
|
4583
|
+
const updated = await fetchApi$4("/rescan", { method: "POST" });
|
|
4584
|
+
setStatus(normalizeStatus(updated));
|
|
4585
|
+
notifyChange();
|
|
4586
|
+
} catch (err) {
|
|
4587
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4588
|
+
} finally {
|
|
4589
|
+
setBusy(null);
|
|
4590
|
+
}
|
|
4591
|
+
};
|
|
4592
|
+
const handleAddAccount = async (region) => {
|
|
4593
|
+
try {
|
|
4594
|
+
setBusy(`login:${region}`);
|
|
4595
|
+
setError(null);
|
|
4596
|
+
setLoginProgress(t.loginWaiting);
|
|
4597
|
+
const flow = await fetchApi$4("/accounts/login", {
|
|
4598
|
+
method: "POST",
|
|
4599
|
+
body: JSON.stringify({ region })
|
|
4600
|
+
});
|
|
4601
|
+
if (flow.authUrl) window.open(flow.authUrl, "_blank", "noopener,noreferrer");
|
|
4602
|
+
if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
|
|
4603
|
+
if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
|
|
4604
|
+
const timer = window.setInterval(() => {
|
|
4605
|
+
(async () => {
|
|
4606
|
+
try {
|
|
4607
|
+
const poll = await fetchApi$4("/accounts/login/status");
|
|
4608
|
+
if (poll.progress) setLoginProgress(poll.progress);
|
|
4609
|
+
if (poll.status === "complete") {
|
|
4610
|
+
window.clearInterval(timer);
|
|
4611
|
+
loginIntervalRef.current = null;
|
|
4612
|
+
if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
|
|
4613
|
+
loginTimeoutRef.current = null;
|
|
4614
|
+
setBusy(null);
|
|
4615
|
+
setLoginProgress(null);
|
|
4616
|
+
if (poll.accountId) await fetchApi$4("/settings", {
|
|
4617
|
+
method: "POST",
|
|
4618
|
+
body: JSON.stringify({ selectedAccountId: poll.accountId })
|
|
4619
|
+
});
|
|
4620
|
+
await loadStatus();
|
|
4621
|
+
notifyChange();
|
|
4622
|
+
} else if (poll.status === "error") {
|
|
4623
|
+
window.clearInterval(timer);
|
|
4624
|
+
loginIntervalRef.current = null;
|
|
4625
|
+
if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
|
|
4626
|
+
loginTimeoutRef.current = null;
|
|
4627
|
+
setBusy(null);
|
|
4628
|
+
setLoginProgress(null);
|
|
4629
|
+
setError(poll.error || t.loginFailed);
|
|
4630
|
+
}
|
|
4631
|
+
} catch {}
|
|
4632
|
+
})();
|
|
4633
|
+
}, 1500);
|
|
4634
|
+
loginIntervalRef.current = timer;
|
|
4635
|
+
loginTimeoutRef.current = window.setTimeout(() => {
|
|
4636
|
+
window.clearInterval(timer);
|
|
4637
|
+
loginIntervalRef.current = null;
|
|
4638
|
+
loginTimeoutRef.current = null;
|
|
4639
|
+
setBusy(null);
|
|
4640
|
+
setLoginProgress(null);
|
|
4641
|
+
}, 300 * 1e3);
|
|
4642
|
+
} catch (err) {
|
|
4643
|
+
setBusy(null);
|
|
4644
|
+
setLoginProgress(null);
|
|
4645
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4646
|
+
}
|
|
4647
|
+
};
|
|
4648
|
+
/**
|
|
4649
|
+
* One account action, whether it is a pool action (`set-primary`, `hide`) or a
|
|
4650
|
+
* credential action (`delete`). The host route dispatches on `action`.
|
|
4651
|
+
*/
|
|
4652
|
+
const handlePoolAction = async (action, accountId) => {
|
|
4653
|
+
try {
|
|
4654
|
+
setBusy(`${action}:${accountId}`);
|
|
4655
|
+
setError(null);
|
|
4656
|
+
const updated = await fetchApi$4("/accounts/action", {
|
|
4657
|
+
method: "POST",
|
|
4658
|
+
body: JSON.stringify({
|
|
4659
|
+
action,
|
|
4660
|
+
accountId
|
|
4661
|
+
})
|
|
4662
|
+
});
|
|
4663
|
+
setStatus(normalizeStatus(updated));
|
|
4664
|
+
notifyChange();
|
|
4665
|
+
} catch (err) {
|
|
4666
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4667
|
+
} finally {
|
|
4668
|
+
setBusy(null);
|
|
4669
|
+
}
|
|
4670
|
+
};
|
|
4671
|
+
const handleDeleteAccount = async (accountId) => {
|
|
4672
|
+
if (!window.confirm(t.deleteConfirm)) return;
|
|
4673
|
+
await handlePoolAction("delete", accountId);
|
|
4674
|
+
};
|
|
4675
|
+
const handleSetStrategy = async (strategy) => {
|
|
4676
|
+
try {
|
|
4677
|
+
setBusy("strategy");
|
|
4678
|
+
setError(null);
|
|
4679
|
+
const updated = await fetchApi$4("/accounts/strategy", {
|
|
4680
|
+
method: "POST",
|
|
4681
|
+
body: JSON.stringify({ strategy })
|
|
4682
|
+
});
|
|
4683
|
+
setStatus(normalizeStatus(updated));
|
|
4684
|
+
} catch (err) {
|
|
4685
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4686
|
+
} finally {
|
|
4687
|
+
setBusy(null);
|
|
4688
|
+
}
|
|
4689
|
+
};
|
|
4690
|
+
const handleTestConnection = async () => {
|
|
4691
|
+
try {
|
|
4692
|
+
setBusy("connection");
|
|
4693
|
+
setError(null);
|
|
4694
|
+
setConnection(await fetchApi$4("/connection/test", { method: "POST" }));
|
|
4695
|
+
} catch (err) {
|
|
4696
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4697
|
+
} finally {
|
|
4698
|
+
setBusy(null);
|
|
4699
|
+
}
|
|
4700
|
+
};
|
|
4701
|
+
const handleRefreshQuota = async () => {
|
|
4702
|
+
try {
|
|
4703
|
+
setBusy("quota");
|
|
4704
|
+
setError(null);
|
|
4705
|
+
const updated = await fetchApi$4("/quota", { method: "POST" });
|
|
4706
|
+
setStatus(updated);
|
|
4707
|
+
} catch (err) {
|
|
4708
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4709
|
+
} finally {
|
|
4710
|
+
setBusy(null);
|
|
4711
|
+
}
|
|
4712
|
+
};
|
|
4713
|
+
const toggleEnabled = async (enabled) => {
|
|
4714
|
+
try {
|
|
4715
|
+
setBusy("enabled");
|
|
4716
|
+
setError(null);
|
|
4717
|
+
const updated = await fetchApi$4("/settings", {
|
|
4718
|
+
method: "POST",
|
|
4719
|
+
body: JSON.stringify({ enabled })
|
|
4720
|
+
});
|
|
4721
|
+
setStatus(updated);
|
|
4722
|
+
notifyChange();
|
|
4723
|
+
} catch (err) {
|
|
4724
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4725
|
+
} finally {
|
|
4726
|
+
setBusy(null);
|
|
4727
|
+
}
|
|
4728
|
+
};
|
|
4729
|
+
const toggleModel = async (modelId, enabled) => {
|
|
4730
|
+
if (status === null) return;
|
|
4731
|
+
const current = status.models.filter((model) => model.enabled).map((model) => model.id);
|
|
4732
|
+
const next = enabled ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
|
|
4733
|
+
try {
|
|
4734
|
+
setBusy(`model:${modelId}`);
|
|
4735
|
+
setError(null);
|
|
4736
|
+
const updated = await fetchApi$4("/settings", {
|
|
4737
|
+
method: "POST",
|
|
4738
|
+
body: JSON.stringify({ enabledModelIds: next })
|
|
4739
|
+
});
|
|
4740
|
+
setStatus(updated);
|
|
4741
|
+
notifyChange();
|
|
4742
|
+
} catch (err) {
|
|
4743
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4744
|
+
} finally {
|
|
4745
|
+
setBusy(null);
|
|
4746
|
+
}
|
|
4747
|
+
};
|
|
4748
|
+
const setAllModels = async (enabled) => {
|
|
4749
|
+
if (status === null) return;
|
|
4750
|
+
try {
|
|
4751
|
+
setBusy("models-all");
|
|
4752
|
+
setError(null);
|
|
4753
|
+
const updated = await fetchApi$4("/settings", {
|
|
4754
|
+
method: "POST",
|
|
4755
|
+
body: JSON.stringify({ enabledModelIds: enabled ? status.models.map((model) => model.id) : [] })
|
|
4756
|
+
});
|
|
4757
|
+
setStatus(updated);
|
|
4758
|
+
notifyChange();
|
|
4759
|
+
} catch (err) {
|
|
4760
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4761
|
+
} finally {
|
|
4762
|
+
setBusy(null);
|
|
4763
|
+
}
|
|
4764
|
+
};
|
|
4765
|
+
const handleUpdateEffort = async (effort) => {
|
|
4766
|
+
try {
|
|
4767
|
+
setBusy("effort");
|
|
4768
|
+
setError(null);
|
|
4769
|
+
const updated = await fetchApi$4("/settings", {
|
|
4770
|
+
method: "POST",
|
|
4771
|
+
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
4772
|
+
});
|
|
4773
|
+
setStatus(updated);
|
|
4774
|
+
notifyChange();
|
|
4775
|
+
} catch (err) {
|
|
4776
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4777
|
+
} finally {
|
|
4778
|
+
setBusy(null);
|
|
4779
|
+
}
|
|
4780
|
+
};
|
|
4781
|
+
const handleRefreshCatalog = async () => {
|
|
4782
|
+
try {
|
|
4783
|
+
setBusy("catalog");
|
|
4784
|
+
setError(null);
|
|
4785
|
+
const updated = await fetchApi$4("/catalog/refresh", { method: "POST" });
|
|
4786
|
+
const normalized = {
|
|
4787
|
+
...updated,
|
|
4788
|
+
models: Array.isArray(updated?.models) ? updated.models : [],
|
|
4789
|
+
contextWindowOverrides: updated?.contextWindowOverrides ?? {}
|
|
4790
|
+
};
|
|
4791
|
+
setStatus(normalized);
|
|
4792
|
+
const drafts = {};
|
|
4793
|
+
for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
4794
|
+
setContextDrafts(drafts);
|
|
4795
|
+
notifyChange();
|
|
4796
|
+
} catch (err) {
|
|
4797
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4798
|
+
} finally {
|
|
4799
|
+
setBusy(null);
|
|
4800
|
+
}
|
|
4801
|
+
};
|
|
4802
|
+
const handleSaveContextWindow = async (modelId) => {
|
|
4803
|
+
const raw = contextDrafts[modelId] || "";
|
|
4804
|
+
const parsed = parsePositiveCapacity(raw);
|
|
4805
|
+
if (parsed === null) {
|
|
4806
|
+
setError(`Invalid context capacity: ${raw}`);
|
|
4807
|
+
return;
|
|
4808
|
+
}
|
|
4809
|
+
try {
|
|
4810
|
+
setSavingModel(modelId);
|
|
4811
|
+
setError(null);
|
|
4812
|
+
const updated = await fetchApi$4("/settings", {
|
|
4813
|
+
method: "POST",
|
|
4814
|
+
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
4815
|
+
});
|
|
4816
|
+
setStatus(updated);
|
|
4817
|
+
setContextDrafts((prev) => ({
|
|
4818
|
+
...prev,
|
|
4819
|
+
[modelId]: formatCapacity(parsed)
|
|
4820
|
+
}));
|
|
4821
|
+
notifyChange();
|
|
4822
|
+
} catch (err) {
|
|
4823
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
4824
|
+
} finally {
|
|
4825
|
+
setSavingModel(null);
|
|
4826
|
+
}
|
|
4827
|
+
};
|
|
4828
|
+
if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4829
|
+
className: "dsha-page",
|
|
4830
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4831
|
+
className: "dsha-empty",
|
|
4832
|
+
children: t.loading
|
|
4833
|
+
})
|
|
4834
|
+
});
|
|
4835
|
+
const quota = status?.quota;
|
|
4836
|
+
const authenticated = status?.authenticated === true;
|
|
4837
|
+
const unreachable = statusFailed && status === null;
|
|
4838
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4839
|
+
className: "dsha-page",
|
|
4840
|
+
children: [
|
|
4841
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(AccountPoolSection, {
|
|
4842
|
+
accounts: poolAccounts,
|
|
4843
|
+
activeAccountId: status?.activeAccountId,
|
|
4844
|
+
rotationStrategy: status?.rotationStrategy ?? "sequential",
|
|
4845
|
+
labels: accountPoolLabels(t),
|
|
4846
|
+
busy,
|
|
4847
|
+
onLogin: () => void handleAddAccount("cn"),
|
|
4848
|
+
onSetPrimary: (id) => void handlePoolAction("set-primary", id),
|
|
4849
|
+
onDelete: (id) => void handleDeleteAccount(id),
|
|
4850
|
+
onClearCooldown: (id) => void handlePoolAction("clear-cooldown", id),
|
|
4851
|
+
onRelogin: (id) => void handlePoolAction("relogin", id),
|
|
4852
|
+
onSetStrategy: (strategy) => void handleSetStrategy(strategy),
|
|
4853
|
+
storageValue: status?.managedStoragePath,
|
|
4854
|
+
renderLoginActions: () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4855
|
+
className: "dsha-account-add-actions",
|
|
4856
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4857
|
+
className: "dsha-btn dsha-btn-primary",
|
|
4858
|
+
disabled: busy !== null,
|
|
4859
|
+
onClick: () => void handleAddAccount("cn"),
|
|
4860
|
+
children: busy === "login:cn" ? t.authorizing : t.addCnAccount
|
|
4861
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4862
|
+
className: "dsha-btn dsha-btn-primary",
|
|
4863
|
+
disabled: busy !== null,
|
|
4864
|
+
onClick: () => void handleAddAccount("intl"),
|
|
4865
|
+
children: busy === "login:intl" ? t.authorizing : t.addIntlAccount
|
|
4866
|
+
})]
|
|
4867
|
+
}),
|
|
4868
|
+
renderAccountActions: (candidate) => candidate.removable ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [candidate.hidden === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4869
|
+
className: "dsha-btn",
|
|
4870
|
+
disabled: busy !== null,
|
|
4871
|
+
onClick: () => void handlePoolAction("restore", candidate.id),
|
|
4872
|
+
children: t.restoreAccount
|
|
4873
|
+
}), candidate.hidden !== true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4874
|
+
className: "dsha-btn",
|
|
4875
|
+
disabled: busy !== null,
|
|
4876
|
+
onClick: () => void handlePoolAction("hide", candidate.id),
|
|
4877
|
+
children: t.hideAccount
|
|
4878
|
+
})] }),
|
|
4879
|
+
renderDetails: (candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4880
|
+
candidate.uin ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
4881
|
+
t.uin,
|
|
4882
|
+
": ",
|
|
4883
|
+
maskUin(candidate.uin)
|
|
4884
|
+
] }) : null,
|
|
4885
|
+
candidate.accountType ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
4886
|
+
t.accountType,
|
|
4887
|
+
": ",
|
|
4888
|
+
candidate.accountType
|
|
4889
|
+
] }) : null,
|
|
4890
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
4891
|
+
t.region,
|
|
4892
|
+
": ",
|
|
4893
|
+
candidate.region === "intl" ? t.regionIntl : t.regionCn
|
|
4894
|
+
] }),
|
|
4895
|
+
candidate.domain ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4896
|
+
className: "dshwb-mono",
|
|
4897
|
+
title: `${candidate.domain} · ${candidate.backend ?? ""}`,
|
|
4898
|
+
children: candidate.domain
|
|
4899
|
+
}) : null,
|
|
4900
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4901
|
+
className: "dshwb-mono",
|
|
4902
|
+
children: candidate.source === "managed" ? t.encryptedStorage : displayFile(candidate.sourceFile)
|
|
4903
|
+
}),
|
|
4904
|
+
candidate.hidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.hiddenAccount }) : null
|
|
4905
|
+
] }),
|
|
4906
|
+
children: [
|
|
4907
|
+
unreachable ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4908
|
+
className: "dsha-empty",
|
|
4909
|
+
children: t.routeUnreachable
|
|
4910
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4911
|
+
className: "dsha-notice",
|
|
4912
|
+
children: t.routeUnreachableHint
|
|
4913
|
+
})] }) : null,
|
|
4914
|
+
loginProgress ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4915
|
+
className: "dsha-notice",
|
|
4916
|
+
children: loginProgress
|
|
4917
|
+
}) : null,
|
|
4918
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4919
|
+
className: "dsha-row",
|
|
4920
|
+
style: { marginTop: 12 },
|
|
4921
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4922
|
+
className: "dsha-label",
|
|
4923
|
+
children: t.authDirectory
|
|
4924
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4925
|
+
className: "dsha-value dshwb-mono",
|
|
4926
|
+
title: status?.authDirectory || "",
|
|
4927
|
+
children: status?.authDirectory || "—"
|
|
4928
|
+
})]
|
|
4929
|
+
}),
|
|
4930
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4931
|
+
className: "dsha-actions",
|
|
4932
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4933
|
+
className: "dsha-btn",
|
|
4934
|
+
disabled: busy !== null,
|
|
4935
|
+
onClick: () => void handleRescan(),
|
|
4936
|
+
children: busy === "rescan" ? t.rescanning : t.rescan
|
|
4937
|
+
})
|
|
4938
|
+
})
|
|
4939
|
+
]
|
|
4940
|
+
}),
|
|
4941
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
4942
|
+
className: "dsha-group",
|
|
4943
|
+
children: [
|
|
4944
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4945
|
+
className: "dsha-grouphead",
|
|
4946
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
|
|
4947
|
+
}),
|
|
4948
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4949
|
+
className: "dsha-row",
|
|
4950
|
+
style: { marginBottom: 12 },
|
|
4951
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4952
|
+
className: "dsha-label",
|
|
4953
|
+
style: { fontWeight: 600 },
|
|
4954
|
+
children: t.enableProvider
|
|
4955
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4956
|
+
type: "checkbox",
|
|
4957
|
+
checked: status?.enabled !== false,
|
|
4958
|
+
disabled: busy !== null,
|
|
4959
|
+
onChange: (e) => void toggleEnabled(e.currentTarget.checked)
|
|
4960
|
+
})]
|
|
4961
|
+
}),
|
|
4962
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4963
|
+
className: "dsha-row",
|
|
4964
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4965
|
+
className: "dsha-label",
|
|
4966
|
+
children: t.provider
|
|
4967
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4968
|
+
className: "dsha-value",
|
|
4969
|
+
children: t.providerValue
|
|
4970
|
+
})]
|
|
4971
|
+
}),
|
|
4972
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4973
|
+
className: "dsha-row",
|
|
4974
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4975
|
+
className: "dsha-label",
|
|
4976
|
+
children: t.connectionState
|
|
4977
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4978
|
+
className: "dsha-value",
|
|
4979
|
+
children: [connection?.connected ? t.connected : authenticated ? t.untested : t.signedOut, connection?.connected ? ` · ${connection.latencyMs}ms · ${connection.model}` : ""]
|
|
4980
|
+
})]
|
|
4981
|
+
}),
|
|
4982
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4983
|
+
className: "dsha-notice",
|
|
4984
|
+
children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
|
|
4985
|
+
}),
|
|
4986
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4987
|
+
className: "dsha-actions",
|
|
4988
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4989
|
+
className: "dsha-btn",
|
|
4990
|
+
disabled: busy !== null || !authenticated,
|
|
4991
|
+
onClick: () => void handleTestConnection(),
|
|
4992
|
+
children: busy === "connection" ? t.testingConnection : t.testConnection
|
|
4993
|
+
})
|
|
4994
|
+
})
|
|
4995
|
+
]
|
|
4996
|
+
}),
|
|
4997
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
4998
|
+
className: "dsha-group",
|
|
4999
|
+
children: [
|
|
5000
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5001
|
+
className: "dsha-grouphead",
|
|
5002
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5003
|
+
className: "dsha-btn",
|
|
5004
|
+
disabled: busy !== null || !authenticated,
|
|
5005
|
+
onClick: () => void handleRefreshCatalog(),
|
|
5006
|
+
children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
|
|
5007
|
+
})]
|
|
5008
|
+
}),
|
|
5009
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5010
|
+
className: "dsha-muted dsha-models-hint",
|
|
5011
|
+
children: t.modelsHint
|
|
5012
|
+
}),
|
|
5013
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5014
|
+
className: "dsha-models",
|
|
5015
|
+
"aria-label": "WorkBuddy Models",
|
|
5016
|
+
children: status?.models.map((model) => {
|
|
5017
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
5018
|
+
title: [
|
|
5019
|
+
model.id,
|
|
5020
|
+
formatCapacity(model.contextWindow),
|
|
5021
|
+
model.supportsImage ? t.imageSupport : t.textOnly,
|
|
5022
|
+
...model.reasoningEfforts && model.reasoningEfforts.length > 0 ? [model.reasoningEfforts.join("/")] : []
|
|
5023
|
+
].join(" · "),
|
|
5024
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5025
|
+
type: "checkbox",
|
|
5026
|
+
checked: model.enabled,
|
|
5027
|
+
disabled: busy !== null,
|
|
5028
|
+
onChange: (event) => void toggleModel(model.id, event.currentTarget.checked)
|
|
5029
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
|
|
5030
|
+
}, model.id);
|
|
5031
|
+
})
|
|
5032
|
+
}),
|
|
5033
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5034
|
+
className: "dsha-actions",
|
|
5035
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5036
|
+
className: "dsha-btn",
|
|
5037
|
+
disabled: busy !== null,
|
|
5038
|
+
onClick: () => void setAllModels(true),
|
|
5039
|
+
children: t.selectAll
|
|
5040
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5041
|
+
className: "dsha-btn",
|
|
5042
|
+
disabled: busy !== null,
|
|
5043
|
+
onClick: () => void setAllModels(false),
|
|
5044
|
+
children: t.unselectAll
|
|
5045
|
+
})]
|
|
5046
|
+
})
|
|
5047
|
+
]
|
|
5048
|
+
}),
|
|
5049
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5050
|
+
className: "dsha-group",
|
|
5051
|
+
children: [
|
|
5052
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5053
|
+
className: "dsha-grouphead",
|
|
5054
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
|
|
5055
|
+
}),
|
|
5056
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5057
|
+
className: "dsha-pref-row",
|
|
5058
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
5059
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }),
|
|
5060
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5061
|
+
className: "dsha-muted",
|
|
5062
|
+
children: t.defaultReasoningEffortHint
|
|
5063
|
+
}),
|
|
5064
|
+
strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5065
|
+
className: "dsha-muted",
|
|
5066
|
+
children: t.defaultEffortKept
|
|
5067
|
+
}) : null
|
|
5068
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
5069
|
+
className: "dsha-select",
|
|
5070
|
+
"aria-label": t.defaultReasoningEffort,
|
|
5071
|
+
value: status?.defaultReasoningEffort ?? "",
|
|
5072
|
+
disabled: busy !== null,
|
|
5073
|
+
onChange: (event) => {
|
|
5074
|
+
const value = event.currentTarget.value;
|
|
5075
|
+
handleUpdateEffort(value === "" ? null : value);
|
|
5076
|
+
},
|
|
5077
|
+
children: [
|
|
5078
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5079
|
+
value: "",
|
|
5080
|
+
children: t.defaultEffortAuto
|
|
5081
|
+
}),
|
|
5082
|
+
strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5083
|
+
value: strayEffort,
|
|
5084
|
+
children: `${EFFORT_LABELS[strayEffort]} (${t.effortUnsupported})`
|
|
5085
|
+
}) : null,
|
|
5086
|
+
effortChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5087
|
+
value: choice.value,
|
|
5088
|
+
children: choice.models.length === allModels.length ? EFFORT_LABELS[choice.value] : `${EFFORT_LABELS[choice.value]} (${choice.models.length}/${allModels.length})`
|
|
5089
|
+
}, choice.value))
|
|
5090
|
+
]
|
|
5091
|
+
})]
|
|
5092
|
+
}),
|
|
5093
|
+
effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5094
|
+
className: "dsha-muted",
|
|
5095
|
+
children: t.noReasoningModels
|
|
5096
|
+
}) : null
|
|
5097
|
+
]
|
|
5098
|
+
}),
|
|
5099
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5100
|
+
className: "dsha-group",
|
|
5101
|
+
children: [
|
|
5102
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5103
|
+
className: "dsha-grouphead",
|
|
5104
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
|
|
5105
|
+
}),
|
|
5106
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5107
|
+
className: "dsha-muted",
|
|
5108
|
+
children: t.contextWindowHint
|
|
5109
|
+
}),
|
|
5110
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5111
|
+
className: "dsha-context-settings",
|
|
5112
|
+
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5113
|
+
className: "dsha-context-row",
|
|
5114
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5115
|
+
title: model.id,
|
|
5116
|
+
children: model.name
|
|
5117
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5118
|
+
className: "dsha-capacity-control",
|
|
5119
|
+
children: [
|
|
5120
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5121
|
+
type: "text",
|
|
5122
|
+
"aria-label": `${model.name} context window`,
|
|
5123
|
+
value: contextDrafts[model.id] ?? "",
|
|
5124
|
+
onChange: (event) => setContextDrafts({
|
|
5125
|
+
...contextDrafts,
|
|
5126
|
+
[model.id]: event.currentTarget.value
|
|
5127
|
+
}),
|
|
5128
|
+
onKeyDown: (event) => {
|
|
5129
|
+
if (event.key === "Enter") handleSaveContextWindow(model.id);
|
|
5130
|
+
}
|
|
5131
|
+
}),
|
|
5132
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
|
|
5133
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5134
|
+
type: "button",
|
|
5135
|
+
className: "dsha-context-save",
|
|
5136
|
+
disabled: savingModel === model.id,
|
|
5137
|
+
onClick: () => void handleSaveContextWindow(model.id),
|
|
5138
|
+
children: savingModel === model.id ? t.saving : t.save
|
|
5139
|
+
})
|
|
5140
|
+
]
|
|
5141
|
+
})]
|
|
5142
|
+
}, model.id))
|
|
5143
|
+
})
|
|
5144
|
+
]
|
|
5145
|
+
}),
|
|
5146
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5147
|
+
className: "dsha-group",
|
|
5148
|
+
children: [
|
|
5149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5150
|
+
className: "dsha-grouphead",
|
|
5151
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5152
|
+
className: "dsha-btn",
|
|
5153
|
+
disabled: busy !== null || !authenticated,
|
|
5154
|
+
onClick: () => void handleRefreshQuota(),
|
|
5155
|
+
children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
|
|
5156
|
+
})]
|
|
5157
|
+
}),
|
|
5158
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5159
|
+
className: "dsha-muted",
|
|
5160
|
+
children: t.quotaDesc
|
|
5161
|
+
}),
|
|
5162
|
+
!authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5163
|
+
className: "dsha-empty",
|
|
5164
|
+
children: t.signedOut
|
|
5165
|
+
}) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5166
|
+
className: "dsha-empty",
|
|
5167
|
+
children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
|
|
5168
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5169
|
+
className: "dsha-quota-card",
|
|
5170
|
+
children: [
|
|
5171
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5172
|
+
className: "dsha-quota-title",
|
|
5173
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.packageName || t.quotaPackage }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.remainingCredits !== null ? `${quota.remainingCredits} ${t.credits}` : "—" })]
|
|
5174
|
+
}),
|
|
5175
|
+
quota.cycleUsedCredits !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5176
|
+
className: "dsha-row",
|
|
5177
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5178
|
+
className: "dsha-label",
|
|
5179
|
+
children: t.quotaCycle
|
|
5180
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5181
|
+
className: "dsha-value",
|
|
5182
|
+
children: [
|
|
5183
|
+
quota.cycleUsedCredits,
|
|
5184
|
+
quota.cycleCredits !== null ? ` / ${quota.cycleCredits}` : "",
|
|
5185
|
+
` ${t.credits}`
|
|
5186
|
+
]
|
|
5187
|
+
})]
|
|
5188
|
+
}),
|
|
5189
|
+
quota.cycleEndsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5190
|
+
className: "dsha-row",
|
|
5191
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5192
|
+
className: "dsha-label",
|
|
5193
|
+
children: t.quotaReset
|
|
5194
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5195
|
+
className: "dsha-value",
|
|
5196
|
+
children: [formatDate(quota.cycleEndsAt), formatReset(quota.cycleEndsAt) ? ` · ${formatReset(quota.cycleEndsAt)}` : ""]
|
|
5197
|
+
})]
|
|
5198
|
+
}),
|
|
5199
|
+
quota.meters.map((meter) => {
|
|
5200
|
+
const remaining = meter.remainingFraction;
|
|
5201
|
+
const percent = remaining === null ? null : Math.round(remaining * 100);
|
|
5202
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5203
|
+
className: "dsha-meter-wrap",
|
|
5204
|
+
children: [
|
|
5205
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5206
|
+
className: "dsha-meter-label",
|
|
5207
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: percent === null ? meter.limit ?? "—" : `${percent}% left` })]
|
|
5208
|
+
}),
|
|
5209
|
+
percent !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5210
|
+
className: "dsha-meter dsha-meter-green",
|
|
5211
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${percent}%` } })
|
|
5212
|
+
}),
|
|
5213
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5214
|
+
className: "dsha-meter-meta",
|
|
5215
|
+
children: [meter.used !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
5216
|
+
meter.used,
|
|
5217
|
+
" / ",
|
|
5218
|
+
meter.limit ?? "—"
|
|
5219
|
+
] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
5220
|
+
t.quotaReset,
|
|
5221
|
+
": ",
|
|
5222
|
+
formatReset(meter.resetsAt)
|
|
5223
|
+
] })]
|
|
5224
|
+
})
|
|
5225
|
+
]
|
|
5226
|
+
}, meter.id);
|
|
5227
|
+
}),
|
|
5228
|
+
quota.meters.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5229
|
+
className: "dsha-empty",
|
|
5230
|
+
children: t.quotaEmpty
|
|
5231
|
+
}),
|
|
5232
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5233
|
+
className: "dsha-timestamp",
|
|
5234
|
+
children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
|
|
5235
|
+
})
|
|
5236
|
+
]
|
|
5237
|
+
})
|
|
5238
|
+
]
|
|
5239
|
+
}),
|
|
5240
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5241
|
+
className: "dsha-error",
|
|
5242
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
|
|
5243
|
+
})
|
|
5244
|
+
]
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
//#endregion
|
|
5248
|
+
//#region src/client/ProviderHubSection.tsx
|
|
5249
|
+
const HUB_TABS = [
|
|
5250
|
+
{
|
|
5251
|
+
id: "chatgpt",
|
|
5252
|
+
label: "ChatGPT"
|
|
5253
|
+
},
|
|
5254
|
+
{
|
|
5255
|
+
id: "antigravity",
|
|
5256
|
+
label: "Antigravity"
|
|
5257
|
+
},
|
|
5258
|
+
{
|
|
5259
|
+
id: "command-code",
|
|
5260
|
+
label: "Command Code"
|
|
5261
|
+
},
|
|
5262
|
+
{
|
|
5263
|
+
id: "kimi-code",
|
|
5264
|
+
label: "Kimi Code"
|
|
5265
|
+
},
|
|
5266
|
+
{
|
|
5267
|
+
id: "workbuddy",
|
|
5268
|
+
label: "WorkBuddy"
|
|
5269
|
+
}
|
|
5270
|
+
];
|
|
5271
|
+
/**
|
|
5272
|
+
* Single settings page that hosts every subscription provider behind tabs,
|
|
5273
|
+
* so the settings sidebar shows one entry instead of one per provider. Only
|
|
5274
|
+
* the active tab is mounted, mirroring the shell's previous behavior of
|
|
5275
|
+
* mounting just the selected settings page (each provider section refetches
|
|
5276
|
+
* its status on mount).
|
|
5277
|
+
*/
|
|
5278
|
+
function ProviderHubSection({ t, onModelChange, ...runtime }) {
|
|
5279
|
+
const [active, setActive] = (0, react.useState)("chatgpt");
|
|
5280
|
+
const onTabKeyDown = (0, react.useCallback)((event) => {
|
|
5281
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
5282
|
+
event.preventDefault();
|
|
5283
|
+
const index = HUB_TABS.findIndex((tab) => tab.id === active);
|
|
5284
|
+
const delta = event.key === "ArrowRight" ? 1 : -1;
|
|
5285
|
+
const next = HUB_TABS[(index + delta + HUB_TABS.length) % HUB_TABS.length];
|
|
5286
|
+
setActive(next.id);
|
|
5287
|
+
document.getElementById(`dsh-hub-tab-${next.id}`)?.focus();
|
|
5288
|
+
}, [active]);
|
|
5289
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5290
|
+
className: "dsh-codex-page",
|
|
5291
|
+
"aria-labelledby": "dsh-hub-title",
|
|
5292
|
+
children: [
|
|
5293
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
5294
|
+
id: "dsh-hub-title",
|
|
5295
|
+
className: "dsh-codex-title",
|
|
5296
|
+
children: t("hubTitle")
|
|
5297
|
+
}) }),
|
|
5298
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5299
|
+
className: "dsh-codex-segments dsh-hub-tabs",
|
|
5300
|
+
role: "tablist",
|
|
5301
|
+
"aria-label": t("hubTitle"),
|
|
5302
|
+
children: HUB_TABS.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5303
|
+
type: "button",
|
|
5304
|
+
role: "tab",
|
|
5305
|
+
id: `dsh-hub-tab-${tab.id}`,
|
|
5306
|
+
"aria-selected": active === tab.id,
|
|
5307
|
+
"aria-controls": `dsh-hub-panel-${tab.id}`,
|
|
5308
|
+
className: active === tab.id ? "active" : void 0,
|
|
5309
|
+
tabIndex: active === tab.id ? 0 : -1,
|
|
5310
|
+
onClick: () => setActive(tab.id),
|
|
5311
|
+
onKeyDown: onTabKeyDown,
|
|
5312
|
+
children: tab.label
|
|
5313
|
+
}, tab.id))
|
|
5314
|
+
}),
|
|
5315
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5316
|
+
role: "tabpanel",
|
|
4267
5317
|
id: `dsh-hub-panel-${active}`,
|
|
4268
5318
|
"aria-labelledby": `dsh-hub-tab-${active}`,
|
|
4269
5319
|
children: [
|
|
@@ -4273,7 +5323,8 @@ window.__ModuleLoader__.load({
|
|
|
4273
5323
|
}) : null,
|
|
4274
5324
|
active === "antigravity" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AntigravitySection, { onModelChange }) : null,
|
|
4275
5325
|
active === "command-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandCodeSection, { onModelChange }) : null,
|
|
4276
|
-
active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null
|
|
5326
|
+
active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null,
|
|
5327
|
+
active === "workbuddy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange }) : null
|
|
4277
5328
|
]
|
|
4278
5329
|
})
|
|
4279
5330
|
]
|
|
@@ -4544,7 +5595,7 @@ window.__ModuleLoader__.load({
|
|
|
4544
5595
|
};
|
|
4545
5596
|
//#endregion
|
|
4546
5597
|
//#region src/client/styles.ts
|
|
4547
|
-
const STYLE_ID$
|
|
5598
|
+
const STYLE_ID$3 = "@eddyskywalker/dsh-chatgpt-subscription/main";
|
|
4548
5599
|
const CSS = `
|
|
4549
5600
|
.dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
4550
5601
|
.dsh-codex-page *{box-sizing:border-box}
|
|
@@ -4653,21 +5704,21 @@ window.__ModuleLoader__.load({
|
|
|
4653
5704
|
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
4654
5705
|
`;
|
|
4655
5706
|
function installStyles() {
|
|
4656
|
-
if (document.querySelector(`style[data-plugin-css="${STYLE_ID$
|
|
5707
|
+
if (document.querySelector(`style[data-plugin-css="${STYLE_ID$3}"]`) !== null) return () => void 0;
|
|
4657
5708
|
const element = document.createElement("style");
|
|
4658
5709
|
element.dataset.plugin = "@eddyskywalker/dsh-chatgpt-subscription";
|
|
4659
|
-
element.dataset.pluginCss = STYLE_ID$
|
|
5710
|
+
element.dataset.pluginCss = STYLE_ID$3;
|
|
4660
5711
|
element.textContent = CSS;
|
|
4661
5712
|
document.head.appendChild(element);
|
|
4662
5713
|
return () => element.remove();
|
|
4663
5714
|
}
|
|
4664
5715
|
//#endregion
|
|
4665
5716
|
//#region src/client/antigravity/styles.ts
|
|
4666
|
-
const STYLE_ID$
|
|
5717
|
+
const STYLE_ID$2 = "dsh-antigravity-settings-style";
|
|
4667
5718
|
function installAntigravityStyles() {
|
|
4668
5719
|
if (typeof document === "undefined" || document.getElementById("dsh-antigravity-settings-style")) return;
|
|
4669
5720
|
const style = document.createElement("style");
|
|
4670
|
-
style.id = STYLE_ID$
|
|
5721
|
+
style.id = STYLE_ID$2;
|
|
4671
5722
|
style.textContent = `
|
|
4672
5723
|
.dsha-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
4673
5724
|
.dsha-page *{box-sizing:border-box}
|
|
@@ -4690,7 +5741,7 @@ window.__ModuleLoader__.load({
|
|
|
4690
5741
|
.dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
4691
5742
|
.dsha-models label{cursor:pointer;display:block;position:relative}
|
|
4692
5743
|
.dsha-models input{position:absolute;opacity:0;pointer-events:none}
|
|
4693
|
-
.dsha-models
|
|
5744
|
+
.dsha-models>label>span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
|
|
4694
5745
|
.dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
|
|
4695
5746
|
.dsha-models input:disabled+span{cursor:default;opacity:.5}
|
|
4696
5747
|
.dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
@@ -4766,9 +5817,9 @@ window.__ModuleLoader__.load({
|
|
|
4766
5817
|
}
|
|
4767
5818
|
//#endregion
|
|
4768
5819
|
//#region src/client/antigravity/AntigravityComposerQuota.tsx
|
|
4769
|
-
const API$
|
|
4770
|
-
async function fetchApi$
|
|
4771
|
-
const res = await fetch(`${API$
|
|
5820
|
+
const API$3 = "/antigravity/api";
|
|
5821
|
+
async function fetchApi$3(path, options) {
|
|
5822
|
+
const res = await fetch(`${API$3}${path}`, {
|
|
4772
5823
|
...options,
|
|
4773
5824
|
headers: {
|
|
4774
5825
|
"Content-Type": "application/json",
|
|
@@ -4809,7 +5860,7 @@ window.__ModuleLoader__.load({
|
|
|
4809
5860
|
}
|
|
4810
5861
|
}
|
|
4811
5862
|
function AntigravityComposerQuota({ directory, loadModelDirectory }) {
|
|
4812
|
-
const modelState = useStore$
|
|
5863
|
+
const modelState = useStore$3(directory);
|
|
4813
5864
|
const [status, setStatus] = (0, react.useState)(null);
|
|
4814
5865
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
4815
5866
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -4828,7 +5879,7 @@ window.__ModuleLoader__.load({
|
|
|
4828
5879
|
if (!mountedRef.current) return;
|
|
4829
5880
|
setLoading(true);
|
|
4830
5881
|
try {
|
|
4831
|
-
const data = refresh ? await fetchApi$
|
|
5882
|
+
const data = refresh ? await fetchApi$3("/quota", { method: "POST" }) : await fetchApi$3("/status");
|
|
4832
5883
|
if (mountedRef.current) setStatus(data);
|
|
4833
5884
|
} catch {} finally {
|
|
4834
5885
|
if (mountedRef.current) setLoading(false);
|
|
@@ -4866,14 +5917,14 @@ window.__ModuleLoader__.load({
|
|
|
4866
5917
|
})]
|
|
4867
5918
|
});
|
|
4868
5919
|
}
|
|
4869
|
-
function useStore$
|
|
5920
|
+
function useStore$3(store) {
|
|
4870
5921
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
4871
5922
|
}
|
|
4872
5923
|
//#endregion
|
|
4873
5924
|
//#region src/client/command-code/CommandCodeComposerQuota.tsx
|
|
4874
|
-
const API$
|
|
4875
|
-
async function fetchApi$
|
|
4876
|
-
const res = await fetch(`${API$
|
|
5925
|
+
const API$2 = "/command-code/api";
|
|
5926
|
+
async function fetchApi$2(path, options) {
|
|
5927
|
+
const res = await fetch(`${API$2}${path}`, {
|
|
4877
5928
|
...options,
|
|
4878
5929
|
headers: {
|
|
4879
5930
|
"Content-Type": "application/json",
|
|
@@ -4890,7 +5941,7 @@ window.__ModuleLoader__.load({
|
|
|
4890
5941
|
* A bounded usage window is the number a user actually spends down, so it wins
|
|
4891
5942
|
* over a credit balance; the balance shows only when no window is reported.
|
|
4892
5943
|
*/
|
|
4893
|
-
function selectBadgeFacts$
|
|
5944
|
+
function selectBadgeFacts$2(status) {
|
|
4894
5945
|
const quota = status?.quota;
|
|
4895
5946
|
if (quota === null || quota === void 0) return {
|
|
4896
5947
|
text: "—",
|
|
@@ -4932,7 +5983,7 @@ window.__ModuleLoader__.load({
|
|
|
4932
5983
|
};
|
|
4933
5984
|
}
|
|
4934
5985
|
function CommandCodeComposerQuota({ directory, loadModelDirectory }) {
|
|
4935
|
-
const modelState = useStore$
|
|
5986
|
+
const modelState = useStore$2(directory);
|
|
4936
5987
|
const [status, setStatus] = (0, react.useState)(null);
|
|
4937
5988
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
4938
5989
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -4950,7 +6001,7 @@ window.__ModuleLoader__.load({
|
|
|
4950
6001
|
if (!mountedRef.current) return;
|
|
4951
6002
|
setLoading(true);
|
|
4952
6003
|
try {
|
|
4953
|
-
const data = refresh ? await fetchApi$
|
|
6004
|
+
const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
|
|
4954
6005
|
if (mountedRef.current) setStatus(data);
|
|
4955
6006
|
} catch {} finally {
|
|
4956
6007
|
if (mountedRef.current) setLoading(false);
|
|
@@ -4966,7 +6017,7 @@ window.__ModuleLoader__.load({
|
|
|
4966
6017
|
window.clearInterval(timer);
|
|
4967
6018
|
};
|
|
4968
6019
|
}, [fetchStatus, isCommandCode]);
|
|
4969
|
-
const facts = (0, react.useMemo)(() => selectBadgeFacts$
|
|
6020
|
+
const facts = (0, react.useMemo)(() => selectBadgeFacts$2(status), [status]);
|
|
4970
6021
|
if (!isCommandCode || !status?.authenticated || facts === null) return null;
|
|
4971
6022
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4972
6023
|
className: "dsha-composer-quota",
|
|
@@ -4983,14 +6034,14 @@ window.__ModuleLoader__.load({
|
|
|
4983
6034
|
})]
|
|
4984
6035
|
});
|
|
4985
6036
|
}
|
|
4986
|
-
function useStore$
|
|
6037
|
+
function useStore$2(store) {
|
|
4987
6038
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
4988
6039
|
}
|
|
4989
6040
|
//#endregion
|
|
4990
6041
|
//#region src/client/kimi-code/KimiCodeComposerQuota.tsx
|
|
4991
|
-
const API = "/kimi-code/api";
|
|
4992
|
-
async function fetchApi(path, options) {
|
|
4993
|
-
const res = await fetch(`${API}${path}`, {
|
|
6042
|
+
const API$1 = "/kimi-code/api";
|
|
6043
|
+
async function fetchApi$1(path, options) {
|
|
6044
|
+
const res = await fetch(`${API$1}${path}`, {
|
|
4994
6045
|
...options,
|
|
4995
6046
|
headers: {
|
|
4996
6047
|
"Content-Type": "application/json",
|
|
@@ -5008,7 +6059,7 @@ window.__ModuleLoader__.load({
|
|
|
5008
6059
|
* blocks work soonest, so it wins over the longer pools; the 7-day allowance
|
|
5009
6060
|
* shows only when no 5-hour window is reported.
|
|
5010
6061
|
*/
|
|
5011
|
-
function selectBadgeFacts(status) {
|
|
6062
|
+
function selectBadgeFacts$1(status) {
|
|
5012
6063
|
const quota = status?.quota;
|
|
5013
6064
|
if (quota === null || quota === void 0) return {
|
|
5014
6065
|
text: "—",
|
|
@@ -5040,7 +6091,7 @@ window.__ModuleLoader__.load({
|
|
|
5040
6091
|
};
|
|
5041
6092
|
}
|
|
5042
6093
|
function KimiCodeComposerQuota({ directory, loadModelDirectory }) {
|
|
5043
|
-
const modelState = useStore(directory);
|
|
6094
|
+
const modelState = useStore$1(directory);
|
|
5044
6095
|
const [status, setStatus] = (0, react.useState)(null);
|
|
5045
6096
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
5046
6097
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -5058,7 +6109,7 @@ window.__ModuleLoader__.load({
|
|
|
5058
6109
|
if (!mountedRef.current) return;
|
|
5059
6110
|
setLoading(true);
|
|
5060
6111
|
try {
|
|
5061
|
-
const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
|
|
6112
|
+
const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
|
|
5062
6113
|
if (mountedRef.current) setStatus(data);
|
|
5063
6114
|
} catch {} finally {
|
|
5064
6115
|
if (mountedRef.current) setLoading(false);
|
|
@@ -5074,7 +6125,7 @@ window.__ModuleLoader__.load({
|
|
|
5074
6125
|
window.clearInterval(timer);
|
|
5075
6126
|
};
|
|
5076
6127
|
}, [fetchStatus, isKimiCode]);
|
|
5077
|
-
const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
|
|
6128
|
+
const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
|
|
5078
6129
|
if (!isKimiCode || !status?.authenticated || facts === null) return null;
|
|
5079
6130
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5080
6131
|
className: "dsha-composer-quota",
|
|
@@ -5091,12 +6142,12 @@ window.__ModuleLoader__.load({
|
|
|
5091
6142
|
})]
|
|
5092
6143
|
});
|
|
5093
6144
|
}
|
|
5094
|
-
function useStore(store) {
|
|
6145
|
+
function useStore$1(store) {
|
|
5095
6146
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
5096
6147
|
}
|
|
5097
6148
|
//#endregion
|
|
5098
6149
|
//#region src/client/kimi-code/styles.ts
|
|
5099
|
-
const STYLE_ID = "dsh-kimi-code-settings-style";
|
|
6150
|
+
const STYLE_ID$1 = "dsh-kimi-code-settings-style";
|
|
5100
6151
|
/**
|
|
5101
6152
|
* Node the base control styles come from.
|
|
5102
6153
|
*
|
|
@@ -5126,7 +6177,7 @@ window.__ModuleLoader__.load({
|
|
|
5126
6177
|
.dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
5127
6178
|
.dsha-models label{cursor:pointer;display:block;position:relative}
|
|
5128
6179
|
.dsha-models input{position:absolute;opacity:0;pointer-events:none}
|
|
5129
|
-
.dsha-models
|
|
6180
|
+
.dsha-models>label>span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
|
|
5130
6181
|
.dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
|
|
5131
6182
|
.dsha-models input:disabled+span{cursor:default;opacity:.5}
|
|
5132
6183
|
.dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
@@ -5186,11 +6237,143 @@ window.__ModuleLoader__.load({
|
|
|
5186
6237
|
function installKimiCodeStyles() {
|
|
5187
6238
|
if (typeof document === "undefined" || document.getElementById("dsh-kimi-code-settings-style")) return;
|
|
5188
6239
|
const style = document.createElement("style");
|
|
5189
|
-
style.id = STYLE_ID;
|
|
6240
|
+
style.id = STYLE_ID$1;
|
|
5190
6241
|
style.textContent = BASE;
|
|
5191
6242
|
document.head.appendChild(style);
|
|
5192
6243
|
}
|
|
5193
6244
|
//#endregion
|
|
6245
|
+
//#region src/client/workbuddy/WorkBuddyComposerQuota.tsx
|
|
6246
|
+
const API = "/workbuddy/api";
|
|
6247
|
+
async function fetchApi(path, options) {
|
|
6248
|
+
const res = await fetch(`${API}${path}`, {
|
|
6249
|
+
...options,
|
|
6250
|
+
headers: {
|
|
6251
|
+
"Content-Type": "application/json",
|
|
6252
|
+
...options?.headers
|
|
6253
|
+
}
|
|
6254
|
+
});
|
|
6255
|
+
const json = await res.json();
|
|
6256
|
+
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
6257
|
+
return json.value;
|
|
6258
|
+
}
|
|
6259
|
+
/**
|
|
6260
|
+
* Pick the most meaningful number for the badge.
|
|
6261
|
+
*
|
|
6262
|
+
* A bounded allowance is what a user spends down, so it wins over a bare credit
|
|
6263
|
+
* balance; the balance shows only when no percentage is reported. The billing
|
|
6264
|
+
* payload reports both a cycle meter and a package meter, and the cycle meter
|
|
6265
|
+
* is the one that actually resets, so it is preferred when both exist.
|
|
6266
|
+
*/
|
|
6267
|
+
function selectBadgeFacts(status) {
|
|
6268
|
+
const quota = status?.quota;
|
|
6269
|
+
if (quota === null || quota === void 0) return {
|
|
6270
|
+
text: "—",
|
|
6271
|
+
tooltip: "WorkBuddy quota unavailable — click to refresh",
|
|
6272
|
+
level: "normal"
|
|
6273
|
+
};
|
|
6274
|
+
const meter = (quota.meters ?? []).find((candidate) => candidate.id === "cycle" && candidate.remainingFraction !== null) ?? (quota.meters ?? []).find((candidate) => candidate.remainingFraction !== null);
|
|
6275
|
+
if (meter !== void 0 && meter.remainingFraction !== null) {
|
|
6276
|
+
const remaining = Math.round(meter.remainingFraction * 100);
|
|
6277
|
+
return {
|
|
6278
|
+
text: `${remaining}%`,
|
|
6279
|
+
tooltip: `[WorkBuddy] ${meter.label}: ${remaining}% left`,
|
|
6280
|
+
level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
|
|
6281
|
+
};
|
|
6282
|
+
}
|
|
6283
|
+
if (quota.remainingCredits !== null) return {
|
|
6284
|
+
text: String(quota.remainingCredits),
|
|
6285
|
+
tooltip: `[WorkBuddy] Remaining credits: ${quota.remainingCredits}`,
|
|
6286
|
+
level: "normal"
|
|
6287
|
+
};
|
|
6288
|
+
return {
|
|
6289
|
+
text: "—",
|
|
6290
|
+
tooltip: "WorkBuddy quota unavailable — click to refresh",
|
|
6291
|
+
level: "normal"
|
|
6292
|
+
};
|
|
6293
|
+
}
|
|
6294
|
+
function WorkBuddyComposerQuota({ directory, loadModelDirectory }) {
|
|
6295
|
+
const modelState = useStore(directory);
|
|
6296
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
6297
|
+
const [loading, setLoading] = (0, react.useState)(false);
|
|
6298
|
+
const mountedRef = (0, react.useRef)(false);
|
|
6299
|
+
const isWorkBuddy = modelState.current?.provider === "workbuddy-subscription";
|
|
6300
|
+
(0, react.useEffect)(() => {
|
|
6301
|
+
loadModelDirectory();
|
|
6302
|
+
}, [loadModelDirectory]);
|
|
6303
|
+
(0, react.useEffect)(() => {
|
|
6304
|
+
mountedRef.current = true;
|
|
6305
|
+
return () => {
|
|
6306
|
+
mountedRef.current = false;
|
|
6307
|
+
};
|
|
6308
|
+
}, []);
|
|
6309
|
+
const fetchStatus = (0, react.useCallback)(async (refresh = false) => {
|
|
6310
|
+
if (!mountedRef.current) return;
|
|
6311
|
+
setLoading(true);
|
|
6312
|
+
try {
|
|
6313
|
+
const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
|
|
6314
|
+
if (mountedRef.current) setStatus(data);
|
|
6315
|
+
} catch {} finally {
|
|
6316
|
+
if (mountedRef.current) setLoading(false);
|
|
6317
|
+
}
|
|
6318
|
+
}, []);
|
|
6319
|
+
(0, react.useEffect)(() => {
|
|
6320
|
+
if (!isWorkBuddy) return;
|
|
6321
|
+
fetchStatus(false);
|
|
6322
|
+
const timer = window.setInterval(() => {
|
|
6323
|
+
if (document.visibilityState === "visible") fetchStatus(false);
|
|
6324
|
+
}, 6e4);
|
|
6325
|
+
return () => {
|
|
6326
|
+
window.clearInterval(timer);
|
|
6327
|
+
};
|
|
6328
|
+
}, [fetchStatus, isWorkBuddy]);
|
|
6329
|
+
const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
|
|
6330
|
+
if (!isWorkBuddy || !status?.authenticated || facts === null) return null;
|
|
6331
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6332
|
+
className: "dsha-composer-quota",
|
|
6333
|
+
"data-level": facts.level,
|
|
6334
|
+
title: facts.tooltip,
|
|
6335
|
+
"aria-label": facts.tooltip,
|
|
6336
|
+
onClick: () => void fetchStatus(true),
|
|
6337
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6338
|
+
className: "dsha-composer-quota-label",
|
|
6339
|
+
children: "额度"
|
|
6340
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
6341
|
+
className: "dsha-composer-quota-val",
|
|
6342
|
+
children: loading ? "…" : facts.text
|
|
6343
|
+
})]
|
|
6344
|
+
});
|
|
6345
|
+
}
|
|
6346
|
+
function useStore(store) {
|
|
6347
|
+
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
6348
|
+
}
|
|
6349
|
+
//#endregion
|
|
6350
|
+
//#region src/client/workbuddy/styles.ts
|
|
6351
|
+
const STYLE_ID = "dsh-workbuddy-settings-style";
|
|
6352
|
+
/**
|
|
6353
|
+
* WorkBuddy-only additions to the shared settings design system.
|
|
6354
|
+
*
|
|
6355
|
+
* The base control styles (`.dsha-page`, `.dsha-group`, `.dsha-models`, the
|
|
6356
|
+
* account card, …) come from the stylesheet the sibling routes install, in the
|
|
6357
|
+
* same order the client installs them, so this file declares only what stays
|
|
6358
|
+
* unique to this card: the mono credential paths and the login-progress line.
|
|
6359
|
+
*
|
|
6360
|
+
* Everything this tab used to declare locally — the per-model capability line
|
|
6361
|
+
* and the account-region headings — is gone: the model pill is name-only like
|
|
6362
|
+
* every sibling tab, and the account card is the shared one.
|
|
6363
|
+
*/
|
|
6364
|
+
function installWorkBuddyStyles() {
|
|
6365
|
+
if (typeof document === "undefined" || document.getElementById("dsh-workbuddy-settings-style")) return;
|
|
6366
|
+
const style = document.createElement("style");
|
|
6367
|
+
style.id = STYLE_ID;
|
|
6368
|
+
style.textContent = `
|
|
6369
|
+
.dshwb-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px}
|
|
6370
|
+
.dsha-account-add-actions{display:flex;flex-wrap:wrap;gap:8px}
|
|
6371
|
+
.dsha-account-add-actions .dsha-btn{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
6372
|
+
.dsha-account-add-actions .dsha-btn:hover:not(:disabled){opacity:.9;background:var(--dsw-alias-button-info-fill,#397ee8)}
|
|
6373
|
+
`;
|
|
6374
|
+
document.head.append(style);
|
|
6375
|
+
}
|
|
6376
|
+
//#endregion
|
|
5194
6377
|
//#region src/client/mermaid/sanitize.ts
|
|
5195
6378
|
const STRIP_ELEMENTS = /* @__PURE__ */ new Set([
|
|
5196
6379
|
"foreignobject",
|
|
@@ -5530,17 +6713,22 @@ window.__ModuleLoader__.load({
|
|
|
5530
6713
|
function apply(ctx) {
|
|
5531
6714
|
ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
|
|
5532
6715
|
ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
|
|
5533
|
-
ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$
|
|
6716
|
+
ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$4), "dsh-antigravity: dictionaries");
|
|
5534
6717
|
ctx.effect(() => {
|
|
5535
6718
|
installAntigravityStyles();
|
|
5536
6719
|
return () => {};
|
|
5537
6720
|
}, "dsh-antigravity: styles");
|
|
5538
|
-
ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$
|
|
5539
|
-
ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$
|
|
6721
|
+
ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$3), "dsh-command-code: dictionaries");
|
|
6722
|
+
ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$2), "dsh-kimi-code: dictionaries");
|
|
5540
6723
|
ctx.effect(() => {
|
|
5541
6724
|
installKimiCodeStyles();
|
|
5542
6725
|
return () => {};
|
|
5543
6726
|
}, "dsh-kimi-code: styles");
|
|
6727
|
+
ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$1), "dsh-workbuddy: dictionaries");
|
|
6728
|
+
ctx.effect(() => {
|
|
6729
|
+
installWorkBuddyStyles();
|
|
6730
|
+
return () => {};
|
|
6731
|
+
}, "dsh-workbuddy: styles");
|
|
5544
6732
|
ctx.effect(() => {
|
|
5545
6733
|
installPoolStyles();
|
|
5546
6734
|
return () => {};
|
|
@@ -5628,6 +6816,21 @@ window.__ModuleLoader__.load({
|
|
|
5628
6816
|
};
|
|
5629
6817
|
}
|
|
5630
6818
|
}, KimiCodeComposerQuota));
|
|
6819
|
+
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
6820
|
+
name: "conversation.input.right",
|
|
6821
|
+
id: "workbuddy-quota",
|
|
6822
|
+
order: 39,
|
|
6823
|
+
locale: NS_WORKBUDDY,
|
|
6824
|
+
inject: (sessionId) => {
|
|
6825
|
+
const directory = ctx.modelDirectories.directoryFor(sessionId);
|
|
6826
|
+
return {
|
|
6827
|
+
directory: directory.store,
|
|
6828
|
+
loadModelDirectory: () => {
|
|
6829
|
+
directory.load().catch(() => void 0);
|
|
6830
|
+
}
|
|
6831
|
+
};
|
|
6832
|
+
}
|
|
6833
|
+
}, WorkBuddyComposerQuota));
|
|
5631
6834
|
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
5632
6835
|
name: "tool.call.toolview",
|
|
5633
6836
|
key: CODEX_IMAGE_TOOL_NAME,
|