dsh-connect-trae 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.en.md +76 -0
- package/README.md +95 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/cordis.patch.yml +4 -0
- package/docs/assets/dsh-connect-trae-usage-card.png +0 -0
- package/lib/client.js +752 -0
- package/lib/index.d.ts +975 -0
- package/lib/index.js +3118 -0
- package/package.json +111 -0
- package/screenshots.json +3 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-connect-trae",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
//#region src/status-paths.ts
|
|
11
|
+
/**
|
|
12
|
+
* Node-free constants and types shared by the Host and browser halves.
|
|
13
|
+
* Mirrors the `dsh-workbuddy-connect` status-route pattern so the plugin card
|
|
14
|
+
* stays consistent with that project's external presentation.
|
|
15
|
+
*/
|
|
16
|
+
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
17
|
+
const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
18
|
+
/** Plugin-owned live model refresh endpoint. */
|
|
19
|
+
const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
|
|
20
|
+
/** Plugin-owned local account rescan endpoint. */
|
|
21
|
+
const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/client/icon.ts
|
|
24
|
+
/**
|
|
25
|
+
* Plugin icon (LD brand logo, 64px) shared across the LaoDing plugin family.
|
|
26
|
+
* Same data URI used by `dsh-subagent-default-model` so the external image
|
|
27
|
+
* stays consistent.
|
|
28
|
+
*/
|
|
29
|
+
const TRAE_PLUGIN_ICON = "data:image/png;base64,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";
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/client/styles.ts
|
|
32
|
+
/**
|
|
33
|
+
* Client styles for the Trae plugin card.
|
|
34
|
+
* Copied verbatim from `dsh-subagent-default-model`'s SETTINGS_CSS so the two
|
|
35
|
+
* plugins share one external-presentation language (same card shell, same
|
|
36
|
+
* button primitives, same `--dsw-alias-*` token palette).
|
|
37
|
+
*/
|
|
38
|
+
const TRAE_CARD_CSS = `
|
|
39
|
+
.dsm-plugin-card{border:1px solid var(--dsw-alias-border-l2,#36373b);background:var(--dsw-alias-bg-layer-3,#202126);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}
|
|
40
|
+
.dsm-plugin-card:hover{border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
41
|
+
.dsm-plugin-card-open{background:var(--dsw-alias-bg-layer-2,#25262b);border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
42
|
+
.dsm-plugin-card-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:transparent;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}
|
|
43
|
+
.dsm-plugin-card-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:-2px}
|
|
44
|
+
.dsm-plugin-card-head{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}
|
|
45
|
+
.dsm-plugin-card-title{color:var(--dsw-alias-label-primary,#e6e6e6);font-size:15px;font-weight:600;line-height:1.4}
|
|
46
|
+
.dsm-plugin-card-description{color:var(--dsw-alias-label-tertiary,#999);font-size:13px;line-height:1.5}
|
|
47
|
+
.dsm-plugin-card-chevron{color:var(--dsw-alias-label-tertiary,#999);flex:none;display:inline-flex;transition:transform .16s}
|
|
48
|
+
.dsm-plugin-card-chevron-open{transform:rotate(180deg)}
|
|
49
|
+
.dsm-plugin-card-body{border-top:1px solid var(--dsw-alias-border-l2,#36373b);margin:0 16px;padding:0 0 8px}
|
|
50
|
+
.dsm-plugin-card-icon{width:32px;height:32px;flex:none;border-radius:7px}
|
|
51
|
+
.dsm-plugin-card-body .dsm-model-settings{margin:0;padding:12px 0 0;background:transparent;border:0;border-radius:0}
|
|
52
|
+
.dsm-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}
|
|
53
|
+
.dsm-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
54
|
+
.dsm-btn:disabled{opacity:.4;cursor:default}
|
|
55
|
+
.dsm-btn-outline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font-weight:500}
|
|
56
|
+
.dsm-btn-outline:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:rgba(255,255,255,.04)}
|
|
57
|
+
.dsm-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
|
|
58
|
+
.dsm-btn-primary:hover:not(:disabled){opacity:.9}
|
|
59
|
+
.dsm-trae-usage{display:flex;flex-direction:column;gap:16px;margin:0;padding:16px 0 4px}
|
|
60
|
+
.dsm-trae-usage-account{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#24262c)}
|
|
61
|
+
.dsm-trae-usage-account-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
62
|
+
.dsm-trae-usage-expiry{padding-left:19px;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
63
|
+
.dsm-trae-account-picker{display:block}
|
|
64
|
+
.dsm-trae-usage-select-wrap{position:relative}
|
|
65
|
+
.dsm-trae-usage-select{appearance:none;width:100%;font:inherit;padding:10px 34px 10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:10px;color:var(--dsw-alias-label-primary,#e6e6e6);background:var(--dsw-alias-bg-layer-3,#2a2c33);cursor:pointer;transition:border-color .15s,box-shadow .15s}
|
|
66
|
+
.dsm-trae-usage-select:focus-visible{outline:none;border-color:var(--dsw-alias-brand-primary,#5686fe);box-shadow:0 0 0 3px rgba(86,134,254,.22)}
|
|
67
|
+
.dsm-trae-usage-select:disabled{opacity:.6;cursor:default}
|
|
68
|
+
.dsm-trae-usage-select-wrap::after{content:"";position:absolute;top:50%;right:12px;width:7px;height:7px;transform:translateY(-65%) rotate(45deg);border-right:1.6px solid var(--dsw-alias-label-secondary,#c6c9d0);border-bottom:1.6px solid var(--dsw-alias-label-secondary,#c6c9d0);pointer-events:none}
|
|
69
|
+
.dsm-trae-mark{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:5px;font-size:11px;font-weight:700;color:#111;background:linear-gradient(135deg,#ffd36e,#ffb84d);margin-right:6px}
|
|
70
|
+
.dsm-trae-usage-list{display:flex;flex-direction:column;gap:10px}
|
|
71
|
+
.dsm-trae-usage-text{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-label-secondary,#b8b8b8)}
|
|
72
|
+
.dsm-trae-usage-error{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-state-error-primary,#ef4444)}
|
|
73
|
+
.dsm-trae-usage-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
|
|
74
|
+
.dsm-trae-usage-status{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:500;color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
75
|
+
.dsm-trae-usage-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:2px}
|
|
76
|
+
.dsm-trae-usage-stats-two{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
|
|
77
|
+
.dsm-trae-usage-stat{position:relative;display:flex;flex-direction:column;gap:9px;padding:16px 16px 14px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#24262c);overflow:hidden;min-width:0}
|
|
78
|
+
.dsm-trae-usage-stat::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;opacity:.9}
|
|
79
|
+
.dsm-trae-usage-stat-work::before{background:#9ca2aa}
|
|
80
|
+
.dsm-trae-usage-stat-general::before{background:#4d9b6d}
|
|
81
|
+
.dsm-trae-usage-stat-head{display:flex;align-items:center;gap:7px;min-width:0}
|
|
82
|
+
.dsm-trae-usage-stat-label{font-size:13px;line-height:18px;font-weight:600;color:var(--dsw-alias-label-secondary,#c6c9d0);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
83
|
+
.dsm-trae-usage-stat-badge{margin-left:auto;flex:0 0 auto;padding:2px 8px;border-radius:999px;font-size:11px;line-height:15px;font-weight:600;letter-spacing:.2px}
|
|
84
|
+
.dsm-trae-usage-stat-badge-off{color:#aeb3bb;background:rgba(174,179,187,.11)}
|
|
85
|
+
.dsm-trae-usage-stat-badge-on{color:#3f8d60;background:rgba(63,141,96,.13)}
|
|
86
|
+
.dsm-trae-usage-stat-value{font-size:32px;line-height:36px;font-weight:700;letter-spacing:-.5px;white-space:nowrap;font-variant-numeric:tabular-nums}
|
|
87
|
+
.dsm-trae-usage-stat-value-general{color:#3f8d60}
|
|
88
|
+
.dsm-trae-usage-stat-value-work{color:#9298a0}
|
|
89
|
+
.dsm-trae-usage-stat-hint{margin:2px 0 0;font-size:12px;line-height:17px;color:var(--dsw-alias-label-tertiary,#9aa0a8)}
|
|
90
|
+
.dsm-trae-models{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2,#36373b);padding-top:14px}
|
|
91
|
+
.dsm-trae-models-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
92
|
+
.dsm-trae-models-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
93
|
+
.dsm-trae-models-summary{margin:2px 0 0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
94
|
+
.dsm-trae-model-list{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2,#36373b);border-radius:10px;overflow:hidden}
|
|
95
|
+
.dsm-trae-model{display:grid;grid-template-columns:minmax(0,1fr);gap:7px;padding:10px 12px;background:var(--dsw-alias-bg-layer-2,#232529);transition:opacity .16s}
|
|
96
|
+
.dsm-trae-model-disabled{opacity:.55}
|
|
97
|
+
.dsm-trae-model+.dsm-trae-model{border-top:1px solid var(--dsw-alias-border-l2,#36373b)}
|
|
98
|
+
.dsm-trae-model-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
|
|
99
|
+
.dsm-trae-model-enabled{display:flex;align-items:center;gap:8px;min-width:0;cursor:pointer}
|
|
100
|
+
.dsm-trae-model-enabled input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe);flex:none}
|
|
101
|
+
.dsm-trae-model-copy{display:flex;align-items:baseline;gap:8px;min-width:0}
|
|
102
|
+
.dsm-trae-model-name{display:inline-flex;align-items:baseline;gap:7px;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:13px;font-weight:500;line-height:19px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
103
|
+
.dsm-trae-model-name-rate{color:var(--dsw-alias-label-tertiary,#999);font-size:11px;font-weight:400;line-height:16px;flex:none}
|
|
104
|
+
.dsm-trae-model-id{color:var(--dsw-alias-label-tertiary,#999);font-size:11px;line-height:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
105
|
+
.dsm-trae-model-meta{display:flex;align-items:center;gap:7px 12px;flex-wrap:wrap;color:var(--dsw-alias-label-tertiary,#999);font-size:11px;line-height:16px}
|
|
106
|
+
.dsm-trae-model-toggle{display:inline-flex;align-items:center;gap:5px;color:var(--dsw-alias-label-secondary,#b8b8b8);cursor:pointer;font-size:13px;line-height:19px;font-weight:500}
|
|
107
|
+
.dsm-trae-model-toggle input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe)}
|
|
108
|
+
.dsm-trae-model-capability-note{margin:0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
109
|
+
.dsm-trae-model-actions{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--dsw-alias-border-l2,#36373b);padding-top:12px}
|
|
110
|
+
.dsm-trae-model-actions-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px}
|
|
111
|
+
.dsm-trae-usage-cheer{display:inline-flex;align-items:center;gap:4px;flex:none;text-decoration:underline;text-underline-offset:2px;color:var(--dsw-alias-label-tertiary,#999);font-size:13px;line-height:1.5;transition:color .16s}
|
|
112
|
+
.dsm-trae-usage-cheer-star{font-size:12px;line-height:1;display:inline-flex}
|
|
113
|
+
.dsm-trae-usage-cheer:hover{color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
114
|
+
.dsm-trae-usage-cheer:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:2px}
|
|
115
|
+
`;
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/client/TraeUsageCard.tsx
|
|
118
|
+
/**
|
|
119
|
+
* Trae usage card contributed to Harness Plugin configuration.
|
|
120
|
+
*
|
|
121
|
+
* Structure, CSS classes, and button primitives mirror `dsh-subagent-default-model`'s
|
|
122
|
+
* `SubagentModelCard` so the two plugins share one external-presentation language.
|
|
123
|
+
*/
|
|
124
|
+
const POLL_INTERVAL_MS = 6e4;
|
|
125
|
+
const TRAE_GITHUB_URL = "https://github.com/dingminhua/dsh-connect-trae";
|
|
126
|
+
/** Inject the shared card CSS once. */
|
|
127
|
+
if (typeof document !== "undefined") {
|
|
128
|
+
const cssId = "dsh-connect-trae/client.css";
|
|
129
|
+
if (!document.querySelector(`style[data-plugin-css="${cssId}"]`)) {
|
|
130
|
+
const styleTag = document.createElement("style");
|
|
131
|
+
styleTag.dataset.plugin = "dsh-connect-trae";
|
|
132
|
+
styleTag.dataset.pluginCss = cssId;
|
|
133
|
+
styleTag.textContent = TRAE_CARD_CSS;
|
|
134
|
+
document.head.appendChild(styleTag);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function formatNumber(value) {
|
|
138
|
+
return new Intl.NumberFormat(void 0, {
|
|
139
|
+
minimumFractionDigits: 0,
|
|
140
|
+
maximumFractionDigits: 2
|
|
141
|
+
}).format(value);
|
|
142
|
+
}
|
|
143
|
+
function formatDateTime(value) {
|
|
144
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
145
|
+
year: "numeric",
|
|
146
|
+
month: "2-digit",
|
|
147
|
+
day: "2-digit",
|
|
148
|
+
hour: "2-digit",
|
|
149
|
+
minute: "2-digit"
|
|
150
|
+
}).format(new Date(value));
|
|
151
|
+
}
|
|
152
|
+
function formatCapacity(value, unknown) {
|
|
153
|
+
if (value === void 0) return unknown;
|
|
154
|
+
if (value >= 1e6 && value % 1e6 === 0) return `${value / 1e6}M`;
|
|
155
|
+
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
156
|
+
return formatNumber(value);
|
|
157
|
+
}
|
|
158
|
+
const EFFORT_LABELS = {
|
|
159
|
+
low: "轻",
|
|
160
|
+
high: "高",
|
|
161
|
+
xhigh: "极高"
|
|
162
|
+
};
|
|
163
|
+
function dotStyle(status) {
|
|
164
|
+
return { background: status === "signed-in" ? "var(--dsw-alias-state-success-primary, #22a06b)" : status === "error" ? "var(--dsw-alias-state-error-primary, #d92d20)" : "var(--dsw-alias-label-dimmed, #9aa0a6)" };
|
|
165
|
+
}
|
|
166
|
+
/** Render Trae sign-in state and the total usage summary as one expandable card. */
|
|
167
|
+
function TraeUsageCard({ t, settingsScope }) {
|
|
168
|
+
if (t === void 0) throw new Error("Trae usage card requires its translation function");
|
|
169
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
170
|
+
const [status, setStatus] = (0, react.useState)({
|
|
171
|
+
status: "signed-out",
|
|
172
|
+
accounts: []
|
|
173
|
+
});
|
|
174
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
175
|
+
const [settingsRevision, setSettingsRevision] = (0, react.useState)(0);
|
|
176
|
+
const [draftModels, setDraftModels] = (0, react.useState)(void 0);
|
|
177
|
+
const [draftEnabledIds, setDraftEnabledIds] = (0, react.useState)(void 0);
|
|
178
|
+
const [draft1mIds, setDraft1mIds] = (0, react.useState)(void 0);
|
|
179
|
+
const [saving, setSaving] = (0, react.useState)(false);
|
|
180
|
+
const [switchingAccount, setSwitchingAccount] = (0, react.useState)(false);
|
|
181
|
+
const mounted = (0, react.useRef)(true);
|
|
182
|
+
(0, react.useEffect)(() => {
|
|
183
|
+
mounted.current = true;
|
|
184
|
+
return () => {
|
|
185
|
+
mounted.current = false;
|
|
186
|
+
};
|
|
187
|
+
}, []);
|
|
188
|
+
(0, react.useEffect)(() => settingsScope?.subscribe(() => {
|
|
189
|
+
setSettingsRevision((value) => value + 1);
|
|
190
|
+
}), [settingsScope]);
|
|
191
|
+
const refreshUsage = (0, react.useCallback)(async (signal) => {
|
|
192
|
+
try {
|
|
193
|
+
const response = await fetch(TRAE_USAGE_PATH, {
|
|
194
|
+
headers: { accept: "application/json" },
|
|
195
|
+
credentials: "same-origin",
|
|
196
|
+
...signal === void 0 ? {} : { signal }
|
|
197
|
+
});
|
|
198
|
+
const value = await response.json().catch(() => void 0);
|
|
199
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
200
|
+
if (mounted.current && signal?.aborted !== true) setStatus(value);
|
|
201
|
+
return value;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (mounted.current && signal?.aborted !== true) setStatus({
|
|
204
|
+
status: "error",
|
|
205
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}, [t]);
|
|
210
|
+
(0, react.useEffect)(() => {
|
|
211
|
+
if (!open) return;
|
|
212
|
+
const controller = new AbortController();
|
|
213
|
+
refreshUsage(controller.signal);
|
|
214
|
+
return () => {
|
|
215
|
+
controller.abort();
|
|
216
|
+
};
|
|
217
|
+
}, [open, refreshUsage]);
|
|
218
|
+
(0, react.useEffect)(() => {
|
|
219
|
+
if (!open || status.status !== "signed-in") return;
|
|
220
|
+
const controller = new AbortController();
|
|
221
|
+
const timer = window.setInterval(() => {
|
|
222
|
+
refreshUsage(controller.signal);
|
|
223
|
+
}, POLL_INTERVAL_MS);
|
|
224
|
+
return () => {
|
|
225
|
+
window.clearInterval(timer);
|
|
226
|
+
controller.abort();
|
|
227
|
+
};
|
|
228
|
+
}, [
|
|
229
|
+
open,
|
|
230
|
+
refreshUsage,
|
|
231
|
+
status.status
|
|
232
|
+
]);
|
|
233
|
+
const rescanAccounts = async () => {
|
|
234
|
+
setBusy(true);
|
|
235
|
+
try {
|
|
236
|
+
const response = await fetch(TRAE_ACCOUNTS_REFRESH_PATH, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: { accept: "application/json" },
|
|
239
|
+
credentials: "same-origin"
|
|
240
|
+
});
|
|
241
|
+
const body = await response.json();
|
|
242
|
+
if (!response.ok || !Array.isArray(body.accounts)) throw new Error(`HTTP ${response.status}`);
|
|
243
|
+
const selected = body.accounts.find((account) => account.selected)?.id;
|
|
244
|
+
const configured = settingsScope?.getSnapshot().value;
|
|
245
|
+
const configuredId = typeof configured === "object" && configured !== null && typeof configured.accountId === "string" ? configured.accountId : void 0;
|
|
246
|
+
if (selected !== void 0 && selected !== configuredId && settingsScope?.getSnapshot().writable === true) await settingsScope.set("accountId", selected);
|
|
247
|
+
await refreshUsage();
|
|
248
|
+
} finally {
|
|
249
|
+
if (mounted.current) setBusy(false);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const switchAccount = async (accountId) => {
|
|
253
|
+
if (settingsScope === void 0) return;
|
|
254
|
+
setSwitchingAccount(true);
|
|
255
|
+
try {
|
|
256
|
+
await settingsScope.set("accountId", accountId);
|
|
257
|
+
await refreshUsage();
|
|
258
|
+
} finally {
|
|
259
|
+
if (mounted.current) setSwitchingAccount(false);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const refreshModels = async () => {
|
|
263
|
+
setBusy(true);
|
|
264
|
+
try {
|
|
265
|
+
const response = await fetch(TRAE_MODELS_REFRESH_PATH, {
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers: { accept: "application/json" },
|
|
268
|
+
credentials: "same-origin"
|
|
269
|
+
});
|
|
270
|
+
const body = await response.json();
|
|
271
|
+
if (!response.ok || !Array.isArray(body.models)) throw new Error(`HTTP ${response.status}`);
|
|
272
|
+
const fresh = body.models.filter((model) => model.maxContext !== true);
|
|
273
|
+
const oldEnabled = status.status === "signed-in" ? new Set(status.enabledModelIds) : /* @__PURE__ */ new Set();
|
|
274
|
+
const old1m = status.status === "signed-in" ? new Set(status.enabled1mModelIds) : /* @__PURE__ */ new Set();
|
|
275
|
+
const freshIds = new Set(fresh.map((model) => model.id));
|
|
276
|
+
const stillEnabled = [...oldEnabled].filter((id) => freshIds.has(id));
|
|
277
|
+
const still1m = [...old1m].filter((id) => freshIds.has(id));
|
|
278
|
+
setDraftModels(fresh);
|
|
279
|
+
setDraftEnabledIds(new Set(stillEnabled));
|
|
280
|
+
setDraft1mIds(new Set(still1m));
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (mounted.current) setStatus({
|
|
283
|
+
status: "error",
|
|
284
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
285
|
+
});
|
|
286
|
+
} finally {
|
|
287
|
+
if (mounted.current) setBusy(false);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const settingsValue = settingsScope?.getSnapshot().value;
|
|
291
|
+
new Set(typeof settingsValue === "object" && settingsValue !== null && Array.isArray(settingsValue.enabled1mModels) ? settingsValue.enabled1mModels.filter((value) => typeof value === "string") : []);
|
|
292
|
+
const visibleModels = draftModels ?? (status.status === "signed-in" ? status.models : []);
|
|
293
|
+
const savedEnabledIds = status.status === "signed-in" ? new Set(status.enabledModelIds) : /* @__PURE__ */ new Set();
|
|
294
|
+
const saved1mIds = status.status === "signed-in" ? new Set(status.enabled1mModelIds) : /* @__PURE__ */ new Set();
|
|
295
|
+
const activeEnabledIds = draftEnabledIds ?? savedEnabledIds;
|
|
296
|
+
const active1mIds = draft1mIds ?? saved1mIds;
|
|
297
|
+
const dirty = draftModels !== void 0 || draftEnabledIds !== void 0 || draft1mIds !== void 0;
|
|
298
|
+
const toggleModel = (modelId) => {
|
|
299
|
+
const next = new Set(activeEnabledIds);
|
|
300
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
301
|
+
setDraftEnabledIds(next);
|
|
302
|
+
setDraftModels([...visibleModels]);
|
|
303
|
+
};
|
|
304
|
+
const toggle1m = (modelId) => {
|
|
305
|
+
const next = new Set(active1mIds);
|
|
306
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
307
|
+
setDraft1mIds(next);
|
|
308
|
+
setDraftModels([...visibleModels]);
|
|
309
|
+
};
|
|
310
|
+
const discardModels = () => {
|
|
311
|
+
setDraftModels(void 0);
|
|
312
|
+
setDraftEnabledIds(void 0);
|
|
313
|
+
setDraft1mIds(void 0);
|
|
314
|
+
};
|
|
315
|
+
const saveModels = async () => {
|
|
316
|
+
if (settingsScope === void 0) return;
|
|
317
|
+
setSaving(true);
|
|
318
|
+
try {
|
|
319
|
+
await settingsScope.set("lastCatalog", visibleModels.filter((model) => model.maxContext !== true));
|
|
320
|
+
await settingsScope.set("enabledModelIds", [...activeEnabledIds]);
|
|
321
|
+
await settingsScope.set("enabled1mModels", [...active1mIds].filter((id) => activeEnabledIds.has(id)));
|
|
322
|
+
discardModels();
|
|
323
|
+
await refreshUsage();
|
|
324
|
+
} finally {
|
|
325
|
+
if (mounted.current) setSaving(false);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const title = t("row.title");
|
|
329
|
+
const label = status.status === "signed-in" ? t("row.signedIn", { accountName: status.accountName }) : status.status === "error" ? t("row.requestFailed") : t("row.signedOut");
|
|
330
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
331
|
+
className: `dsm-plugin-card${open ? " dsm-plugin-card-open" : ""}`,
|
|
332
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
333
|
+
type: "button",
|
|
334
|
+
className: "dsm-plugin-card-header",
|
|
335
|
+
"aria-expanded": open,
|
|
336
|
+
"aria-label": `${t(open ? "row.collapse" : "row.expand")}: ${title}`,
|
|
337
|
+
onClick: () => {
|
|
338
|
+
setOpen(!open);
|
|
339
|
+
},
|
|
340
|
+
children: [
|
|
341
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
342
|
+
className: "dsm-plugin-card-icon",
|
|
343
|
+
src: TRAE_PLUGIN_ICON,
|
|
344
|
+
alt: ""
|
|
345
|
+
}),
|
|
346
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
347
|
+
className: "dsm-plugin-card-head",
|
|
348
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
349
|
+
className: "dsm-plugin-card-title",
|
|
350
|
+
children: title
|
|
351
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
352
|
+
className: "dsm-plugin-card-description",
|
|
353
|
+
children: t("row.desc")
|
|
354
|
+
})]
|
|
355
|
+
}),
|
|
356
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
357
|
+
"aria-hidden": "true",
|
|
358
|
+
className: `dsm-plugin-card-chevron${open ? " dsm-plugin-card-chevron-open" : ""}`,
|
|
359
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
363
|
+
className: "dsm-plugin-card-body",
|
|
364
|
+
hidden: !open,
|
|
365
|
+
children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
366
|
+
className: "dsm-trae-usage",
|
|
367
|
+
children: [
|
|
368
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
369
|
+
className: "dsm-trae-usage-account",
|
|
370
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
371
|
+
className: "dsm-trae-usage-account-copy",
|
|
372
|
+
role: "status",
|
|
373
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
374
|
+
className: "dsm-trae-usage-status",
|
|
375
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
376
|
+
"aria-hidden": "true",
|
|
377
|
+
className: "dsm-trae-usage-dot",
|
|
378
|
+
style: dotStyle(status.status)
|
|
379
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
|
|
380
|
+
}), status.status === "signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
381
|
+
className: "dsm-trae-usage-expiry",
|
|
382
|
+
children: t("row.tokenExpiry", { expiresAt: formatDateTime(status.tokenExpiresAtMs) })
|
|
383
|
+
}) : null]
|
|
384
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
385
|
+
type: "button",
|
|
386
|
+
className: "dsm-btn dsm-btn-outline",
|
|
387
|
+
disabled: busy,
|
|
388
|
+
onClick: () => {
|
|
389
|
+
rescanAccounts();
|
|
390
|
+
},
|
|
391
|
+
children: busy ? t("row.accountsScanning") : t("row.refreshTokens")
|
|
392
|
+
})]
|
|
393
|
+
}),
|
|
394
|
+
status.status !== "error" && status.accounts.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
395
|
+
className: "dsm-trae-account-picker",
|
|
396
|
+
"aria-label": t("row.accountsTitle"),
|
|
397
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
398
|
+
className: "dsm-trae-usage-select-wrap",
|
|
399
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
400
|
+
className: "dsm-trae-usage-select",
|
|
401
|
+
value: status.status === "signed-in" ? status.accountId : "",
|
|
402
|
+
disabled: switchingAccount || settingsScope?.getSnapshot().writable !== true,
|
|
403
|
+
onChange: (event) => {
|
|
404
|
+
switchAccount(event.currentTarget.value);
|
|
405
|
+
},
|
|
406
|
+
children: status.accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
407
|
+
value: account.id,
|
|
408
|
+
children: [
|
|
409
|
+
account.accountName,
|
|
410
|
+
" · ",
|
|
411
|
+
account.edition
|
|
412
|
+
]
|
|
413
|
+
}, account.id))
|
|
414
|
+
})
|
|
415
|
+
})
|
|
416
|
+
}) : null,
|
|
417
|
+
status.status === "signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
418
|
+
status.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
419
|
+
className: "dsm-trae-usage-list",
|
|
420
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
421
|
+
className: "dsm-trae-usage-stats dsm-trae-usage-stats-two",
|
|
422
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
423
|
+
className: "dsm-trae-usage-stat dsm-trae-usage-stat-work",
|
|
424
|
+
children: [
|
|
425
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
426
|
+
className: "dsm-trae-usage-stat-head",
|
|
427
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
428
|
+
className: "dsm-trae-usage-stat-label",
|
|
429
|
+
children: t("row.workCreditsLabel")
|
|
430
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
431
|
+
className: "dsm-trae-usage-stat-badge dsm-trae-usage-stat-badge-off",
|
|
432
|
+
children: t("row.workNotUsable")
|
|
433
|
+
})]
|
|
434
|
+
}),
|
|
435
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
436
|
+
className: "dsm-trae-usage-stat-value dsm-trae-usage-stat-value-work",
|
|
437
|
+
children: formatNumber(status.credits.workAvailable)
|
|
438
|
+
}),
|
|
439
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
440
|
+
className: "dsm-trae-usage-stat-hint",
|
|
441
|
+
children: t("row.workUsableHint")
|
|
442
|
+
})
|
|
443
|
+
]
|
|
444
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
445
|
+
className: "dsm-trae-usage-stat dsm-trae-usage-stat-general",
|
|
446
|
+
children: [
|
|
447
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
448
|
+
className: "dsm-trae-usage-stat-head",
|
|
449
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
450
|
+
className: "dsm-trae-usage-stat-label",
|
|
451
|
+
children: t("row.generalCreditsLabel")
|
|
452
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
453
|
+
className: "dsm-trae-usage-stat-badge dsm-trae-usage-stat-badge-on",
|
|
454
|
+
children: t("row.generalUsable")
|
|
455
|
+
})]
|
|
456
|
+
}),
|
|
457
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
458
|
+
className: "dsm-trae-usage-stat-value dsm-trae-usage-stat-value-general",
|
|
459
|
+
children: formatNumber(status.credits.generalAvailable)
|
|
460
|
+
}),
|
|
461
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
462
|
+
className: "dsm-trae-usage-stat-hint",
|
|
463
|
+
children: t("row.generalUsableHint")
|
|
464
|
+
})
|
|
465
|
+
]
|
|
466
|
+
})]
|
|
467
|
+
})
|
|
468
|
+
}),
|
|
469
|
+
status.creditsError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
470
|
+
className: "dsm-trae-usage-error",
|
|
471
|
+
children: t("row.creditsError", { message: status.creditsError })
|
|
472
|
+
}),
|
|
473
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
474
|
+
className: "dsm-trae-models",
|
|
475
|
+
"aria-label": t("row.modelsTitle"),
|
|
476
|
+
children: [
|
|
477
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
478
|
+
className: "dsm-trae-models-head",
|
|
479
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
480
|
+
className: "dsm-trae-models-title",
|
|
481
|
+
children: t("row.modelsTitle")
|
|
482
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
483
|
+
className: "dsm-trae-models-summary",
|
|
484
|
+
children: t("row.modelsSummary", { count: activeEnabledIds.size })
|
|
485
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
486
|
+
type: "button",
|
|
487
|
+
className: "dsm-btn dsm-btn-outline",
|
|
488
|
+
disabled: busy,
|
|
489
|
+
onClick: () => {
|
|
490
|
+
refreshModels();
|
|
491
|
+
},
|
|
492
|
+
children: busy ? t("row.modelsRefreshing") : t("row.modelsRefresh")
|
|
493
|
+
})]
|
|
494
|
+
}),
|
|
495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
496
|
+
className: "dsm-trae-model-list",
|
|
497
|
+
children: visibleModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
498
|
+
className: `dsm-trae-model${activeEnabledIds.has(model.id) ? "" : " dsm-trae-model-disabled"}`,
|
|
499
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
500
|
+
className: "dsm-trae-model-head",
|
|
501
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
502
|
+
className: "dsm-trae-model-enabled",
|
|
503
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
504
|
+
type: "checkbox",
|
|
505
|
+
checked: activeEnabledIds.has(model.id),
|
|
506
|
+
disabled: settingsScope?.getSnapshot().writable !== true || saving,
|
|
507
|
+
onChange: () => {
|
|
508
|
+
toggleModel(model.id);
|
|
509
|
+
}
|
|
510
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
511
|
+
className: "dsm-trae-model-copy",
|
|
512
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
513
|
+
className: "dsm-trae-model-name",
|
|
514
|
+
children: [model.name, model.creditMultiplier === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
515
|
+
className: "dsm-trae-model-name-rate",
|
|
516
|
+
children: [
|
|
517
|
+
"(",
|
|
518
|
+
model.creditMultiplier.toFixed(2),
|
|
519
|
+
"x)"
|
|
520
|
+
]
|
|
521
|
+
})]
|
|
522
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
523
|
+
className: "dsm-trae-model-id",
|
|
524
|
+
children: model.id
|
|
525
|
+
})]
|
|
526
|
+
})]
|
|
527
|
+
}), model.maxContextWindow === void 0 || model.maxContext === true ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
528
|
+
className: "dsm-trae-model-toggle",
|
|
529
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
530
|
+
type: "checkbox",
|
|
531
|
+
checked: active1mIds.has(model.id),
|
|
532
|
+
disabled: !activeEnabledIds.has(model.id) || settingsScope?.getSnapshot().writable !== true || busy || saving,
|
|
533
|
+
onChange: () => {
|
|
534
|
+
toggle1m(model.id);
|
|
535
|
+
}
|
|
536
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelEnable1m") })]
|
|
537
|
+
})]
|
|
538
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
539
|
+
className: "dsm-trae-model-meta",
|
|
540
|
+
children: [
|
|
541
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelContext", { context: formatCapacity(model.contextWindow, t("row.modelUnknown")) }) }),
|
|
542
|
+
model.maxTokens === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelOutput", { output: formatCapacity(model.maxTokens, t("row.modelUnknown")) }) }),
|
|
543
|
+
model.maxContext === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelMaxContext") }) : null,
|
|
544
|
+
model.reasoning === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelReasoning", { efforts: model.reasoning.supported.map((effort) => EFFORT_LABELS[effort] ?? effort).join(" / ") }) })
|
|
545
|
+
]
|
|
546
|
+
})]
|
|
547
|
+
}, model.id))
|
|
548
|
+
}),
|
|
549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
550
|
+
className: "dsm-trae-model-capability-note",
|
|
551
|
+
children: t("row.modelCapabilityPending")
|
|
552
|
+
}),
|
|
553
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
554
|
+
className: "dsm-trae-model-actions",
|
|
555
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
556
|
+
className: "dsm-trae-usage-cheer",
|
|
557
|
+
href: TRAE_GITHUB_URL,
|
|
558
|
+
target: "_blank",
|
|
559
|
+
rel: "noopener noreferrer",
|
|
560
|
+
children: [t("row.cheer"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
561
|
+
className: "dsm-trae-usage-cheer-star",
|
|
562
|
+
"aria-hidden": "true",
|
|
563
|
+
children: "★"
|
|
564
|
+
})]
|
|
565
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
566
|
+
className: "dsm-trae-model-actions-buttons",
|
|
567
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
568
|
+
type: "button",
|
|
569
|
+
className: "dsm-btn dsm-btn-outline",
|
|
570
|
+
disabled: !dirty || saving,
|
|
571
|
+
onClick: discardModels,
|
|
572
|
+
children: t("row.discard")
|
|
573
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
574
|
+
type: "button",
|
|
575
|
+
className: "dsm-btn dsm-btn-primary",
|
|
576
|
+
disabled: !dirty || saving || activeEnabledIds.size === 0,
|
|
577
|
+
onClick: () => {
|
|
578
|
+
saveModels();
|
|
579
|
+
},
|
|
580
|
+
children: saving ? t("row.saving") : t("row.save")
|
|
581
|
+
})]
|
|
582
|
+
})]
|
|
583
|
+
})
|
|
584
|
+
]
|
|
585
|
+
})
|
|
586
|
+
] }) : null,
|
|
587
|
+
status.status === "signed-out" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
588
|
+
className: "dsm-trae-usage-text",
|
|
589
|
+
children: status.message ?? t("row.signedOutHint")
|
|
590
|
+
}) : null,
|
|
591
|
+
status.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
592
|
+
className: "dsm-trae-usage-error",
|
|
593
|
+
children: status.message
|
|
594
|
+
}) : null
|
|
595
|
+
]
|
|
596
|
+
}) : null
|
|
597
|
+
})]
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
//#endregion
|
|
601
|
+
//#region src/client/locales.ts
|
|
602
|
+
/**
|
|
603
|
+
* Plugin-card copy registered under the settings.trae locale namespace.
|
|
604
|
+
* Key shape follows `dsh-subagent-default-model`'s `row.*` convention so the
|
|
605
|
+
* two plugins share one external-presentation language.
|
|
606
|
+
*/
|
|
607
|
+
const en = {
|
|
608
|
+
"row.title": "Trae credits & models (dsh-connect-trae)",
|
|
609
|
+
"row.desc": "Use the models in the Trae desktop app directly in DSH, and see your remaining credits at a glance.",
|
|
610
|
+
"row.expand": "Expand",
|
|
611
|
+
"row.collapse": "Collapse",
|
|
612
|
+
"row.signedOut": "Not signed in",
|
|
613
|
+
"row.signedOutHint": "Sign in once in the Trae desktop app; this plugin follows that sign-in automatically.",
|
|
614
|
+
"row.signedIn": "Signed in: {accountName}",
|
|
615
|
+
"row.tokenExpiry": "Access token expires {expiresAt} (auto-renewal)",
|
|
616
|
+
"row.requestFailed": "Request failed",
|
|
617
|
+
"row.creditsAvailableLabel": "Available",
|
|
618
|
+
"row.workCreditsLabel": "Work credits",
|
|
619
|
+
"row.generalCreditsLabel": "General credits",
|
|
620
|
+
"row.workNotUsable": "Not usable in DSH",
|
|
621
|
+
"row.generalUsable": "Usable",
|
|
622
|
+
"row.workUsableHint": "Only inside the Trae app",
|
|
623
|
+
"row.generalUsableHint": "Powers DSH chat & tools",
|
|
624
|
+
"row.creditsConsumedLabel": "Consumed",
|
|
625
|
+
"row.creditsTotalLabel": "Total",
|
|
626
|
+
"row.creditsError": "Usage unavailable: {message}",
|
|
627
|
+
"row.refresh": "Refresh",
|
|
628
|
+
"row.refreshTokens": "Refresh accounts & tokens",
|
|
629
|
+
"row.refreshCredits": "Refresh usage",
|
|
630
|
+
"row.refreshing": "Refreshing…",
|
|
631
|
+
"row.accountsTitle": "Trae account",
|
|
632
|
+
"row.accountsHint": "Choose from locally detected sign-ins. Tokens are never shown or saved in DSH settings.",
|
|
633
|
+
"row.accountsRescan": "Detect accounts again",
|
|
634
|
+
"row.accountsScanning": "Detecting…",
|
|
635
|
+
"row.modelsTitle": "Models",
|
|
636
|
+
"row.modelsSummary": "{count} enabled",
|
|
637
|
+
"row.modelsRefresh": "Refresh from Trae",
|
|
638
|
+
"row.modelsRefreshing": "Refreshing models…",
|
|
639
|
+
"row.modelEnabled": "Enabled",
|
|
640
|
+
"row.discard": "Discard changes",
|
|
641
|
+
"row.save": "Save",
|
|
642
|
+
"row.saving": "Saving…",
|
|
643
|
+
"row.modelContext": "Context {context}",
|
|
644
|
+
"row.modelOutput": "Output {output}",
|
|
645
|
+
"row.modelRate": "{rate}x credits",
|
|
646
|
+
"row.modelReasoning": "Reasoning: {efforts}",
|
|
647
|
+
"row.modelReasoningSupported": "Reasoning: supported",
|
|
648
|
+
"row.modelUnknown": "Unknown",
|
|
649
|
+
"row.modelMaxContext": "1M variant",
|
|
650
|
+
"row.modelEnable1m": "Enable 1M model",
|
|
651
|
+
"row.modelCapabilityPending": "Only capabilities advertised by Trae are shown.",
|
|
652
|
+
"row.cheer": "Star on GitHub"
|
|
653
|
+
};
|
|
654
|
+
const zh = {
|
|
655
|
+
"row.title": "接入使用Trae积分与模型(dsh-connect-trae)",
|
|
656
|
+
"row.desc": "在 DSH 中直接使用 Trae 桌面 App 包含的模型,并随时查看剩余积分。",
|
|
657
|
+
"row.expand": "展开",
|
|
658
|
+
"row.collapse": "收起",
|
|
659
|
+
"row.signedOut": "未登录",
|
|
660
|
+
"row.signedOutHint": "在 Trae 桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
|
|
661
|
+
"row.signedIn": "已登录:{accountName}",
|
|
662
|
+
"row.tokenExpiry": "访问令牌 {expiresAt} 过期(自动续期)",
|
|
663
|
+
"row.requestFailed": "请求失败",
|
|
664
|
+
"row.creditsAvailableLabel": "可用",
|
|
665
|
+
"row.workCreditsLabel": "Work 积分",
|
|
666
|
+
"row.generalCreditsLabel": "通用积分",
|
|
667
|
+
"row.workNotUsable": "DSH 不可用",
|
|
668
|
+
"row.generalUsable": "可用",
|
|
669
|
+
"row.workUsableHint": "仅限 Trae 客户端内使用",
|
|
670
|
+
"row.generalUsableHint": "供 DSH 聊天与工具使用",
|
|
671
|
+
"row.creditsConsumedLabel": "消耗",
|
|
672
|
+
"row.creditsTotalLabel": "合计",
|
|
673
|
+
"row.creditsError": "用量查询失败:{message}",
|
|
674
|
+
"row.refresh": "刷新",
|
|
675
|
+
"row.refreshTokens": "刷新账号与 Token",
|
|
676
|
+
"row.refreshCredits": "刷新用量",
|
|
677
|
+
"row.refreshing": "正在刷新…",
|
|
678
|
+
"row.accountsTitle": "Trae 账号",
|
|
679
|
+
"row.accountsHint": "选择本机检测到的登录账号;Token 不会显示,也不会保存到 DSH 设置。",
|
|
680
|
+
"row.accountsRescan": "重新检测账号",
|
|
681
|
+
"row.accountsScanning": "正在检测…",
|
|
682
|
+
"row.modelsTitle": "模型",
|
|
683
|
+
"row.modelsSummary": "已启用 {count} 个",
|
|
684
|
+
"row.modelsRefresh": "从 Trae 刷新",
|
|
685
|
+
"row.modelsRefreshing": "正在刷新模型…",
|
|
686
|
+
"row.modelEnabled": "启用模型",
|
|
687
|
+
"row.discard": "放弃修改",
|
|
688
|
+
"row.save": "保存",
|
|
689
|
+
"row.saving": "保存中…",
|
|
690
|
+
"row.modelContext": "上下文 {context}",
|
|
691
|
+
"row.modelOutput": "最大输出 {output}",
|
|
692
|
+
"row.modelRate": "积分 {rate}x",
|
|
693
|
+
"row.modelReasoning": "推理强度:{efforts}",
|
|
694
|
+
"row.modelReasoningSupported": "推理:支持",
|
|
695
|
+
"row.modelUnknown": "未知",
|
|
696
|
+
"row.modelMaxContext": "1M 变体",
|
|
697
|
+
"row.modelEnable1m": "启用 1M 模型",
|
|
698
|
+
"row.modelCapabilityPending": "仅展示 Trae 接口明确公布的模型能力。",
|
|
699
|
+
"row.cheer": "鼓励一下"
|
|
700
|
+
};
|
|
701
|
+
//#endregion
|
|
702
|
+
//#region src/client/index.tsx
|
|
703
|
+
/** Stable browser-plugin name. */
|
|
704
|
+
const name = "dsh-connect-trae-client";
|
|
705
|
+
/** Client services required by the Plugin configuration contribution. */
|
|
706
|
+
const inject = [
|
|
707
|
+
"slots",
|
|
708
|
+
"locale",
|
|
709
|
+
"settingsScope"
|
|
710
|
+
];
|
|
711
|
+
/**
|
|
712
|
+
* Register card copy and the Trae card under Plugin configuration.
|
|
713
|
+
*
|
|
714
|
+
* The entire body is wrapped so that a DSH slot-API breaking change (for
|
|
715
|
+
* example the rc.6→rc.7 `id`→`key` / `order`→`priority` rename) degrades
|
|
716
|
+
* to a `console.error` instead of throwing into the DSH loader and raising
|
|
717
|
+
* the red "Failed to load plugins" banner. The host provider keeps working:
|
|
718
|
+
* the `trae` model channel is unaffected.
|
|
719
|
+
*
|
|
720
|
+
* NOTE: the try/catch boundary of this function is mirrored (duplicated) in
|
|
721
|
+
* `tests/client-fallback.spec.ts`, because the real client entry imports
|
|
722
|
+
* browser-only DSH packages that cannot load in the Node test environment.
|
|
723
|
+
*/
|
|
724
|
+
function apply(ctx) {
|
|
725
|
+
try {
|
|
726
|
+
const namespace = "settings.trae";
|
|
727
|
+
ctx.effect(() => ctx.locale.register(namespace, {
|
|
728
|
+
zh,
|
|
729
|
+
en
|
|
730
|
+
}), "dsh-connect-trae: settings copy");
|
|
731
|
+
const t = ctx.locale.bind(namespace);
|
|
732
|
+
const settingsScope = ctx.settingsScope.bind({ namespace: "trae" });
|
|
733
|
+
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
734
|
+
name: "settings.plugin.item",
|
|
735
|
+
key: "trae",
|
|
736
|
+
priority: 30,
|
|
737
|
+
inject: () => ({
|
|
738
|
+
t,
|
|
739
|
+
settingsScope
|
|
740
|
+
})
|
|
741
|
+
}, TraeUsageCard));
|
|
742
|
+
} catch (error) {
|
|
743
|
+
console.error("[dsh-connect-trae] client card failed to load (host provider unaffected):", error);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
//#endregion
|
|
747
|
+
exports.apply = apply;
|
|
748
|
+
exports.inject = inject;
|
|
749
|
+
exports.name = name;
|
|
750
|
+
return module.exports;
|
|
751
|
+
}
|
|
752
|
+
});
|