dsh-connect-workbuddy 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 +33 -0
- package/LICENSE +21 -0
- package/README.en.md +141 -0
- package/README.md +143 -0
- package/THIRD_PARTY_NOTICES.md +57 -0
- package/cordis.patch.yml +6 -0
- package/docs/assets/dsh-connect-workbuddy-usage-card.png +0 -0
- package/lib/bin.d.ts +19 -0
- package/lib/bin.js +202 -0
- package/lib/client.js +872 -0
- package/lib/host-heartbeat-DHfQtrSf.js +1118 -0
- package/lib/index.d.ts +651 -0
- package/lib/index.js +792 -0
- package/package.json +114 -0
- package/screenshots.json +3 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-connect-workbuddy",
|
|
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
|
+
*
|
|
14
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
15
|
+
* — 「3 条同源只读路由(usage / models:refresh / accounts:refresh)+ 一份
|
|
16
|
+
* 与浏览器共享的 node-free 类型定义」的 host↔client 桥梁形态来自该项目
|
|
17
|
+
* (其 `status-paths.ts` 亦如此,并注明沿用
|
|
18
|
+
* corrinehu/dsh-workbuddy-connect 的 status-route 模式)。
|
|
19
|
+
* 改动:路由路径改用本插件 id;类型字段按 WorkBuddy 上游实际给出的能力
|
|
20
|
+
* (积分倍率、多模态、推理档位)调整,不保留 trae 的 1M 变体字段。
|
|
21
|
+
*
|
|
22
|
+
* @module dsh-connect-workbuddy/status-paths
|
|
23
|
+
*/
|
|
24
|
+
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
25
|
+
const WORKBUDDY_USAGE_PATH = "/plugins/dsh-connect-workbuddy/usage";
|
|
26
|
+
/** Plugin-owned live model refresh endpoint. */
|
|
27
|
+
const WORKBUDDY_MODELS_REFRESH_PATH = "/plugins/dsh-connect-workbuddy/models/refresh";
|
|
28
|
+
/** Plugin-owned local account rescan endpoint. */
|
|
29
|
+
const WORKBUDDY_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-workbuddy/accounts/refresh";
|
|
30
|
+
/** Plugin-owned daily check-in action endpoint. */
|
|
31
|
+
const WORKBUDDY_CHECKIN_PATH = "/plugins/dsh-connect-workbuddy/checkin";
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/client/icon.ts
|
|
34
|
+
/**
|
|
35
|
+
* Plugin icon (LD brand logo, 64px) shared across the LaoDing plugin family.
|
|
36
|
+
*
|
|
37
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
38
|
+
* — 同一 data URI,其注释说明来自
|
|
39
|
+
* dingminhua/dsh-subagent-default-model(MIT),用于让插件家族的
|
|
40
|
+
* 外观保持一致。本项目沿用同一图标以达到同样目的。
|
|
41
|
+
* 改动:无。
|
|
42
|
+
*
|
|
43
|
+
* @module dsh-connect-workbuddy/client/icon
|
|
44
|
+
*/
|
|
45
|
+
const WORKBUDDY_PLUGIN_ICON = "data:image/png;base64,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";
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/client/styles.ts
|
|
48
|
+
/**
|
|
49
|
+
* Client styles for the WorkBuddy plugin card.
|
|
50
|
+
*
|
|
51
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
52
|
+
* — 整套 `dsm-*` 卡片样式系统(卡片外壳、按钮原语、`--dsw-alias-*`
|
|
53
|
+
* 主题变量与十六进制回退值)逐字沿用自该项目,其又复制自
|
|
54
|
+
* dingminhua/dsh-subagent-default-model(MIT)的 SETTINGS_CSS。
|
|
55
|
+
* 沿用目的是让两个插件共享同一套外部表现语言。
|
|
56
|
+
* 改动:类名由 `dsm-trae-*` 改为 `dsm-workbuddy-*`;
|
|
57
|
+
* 移除 trae 特有的 1M 变体样式,新增按套餐聚合的积分行样式。
|
|
58
|
+
*
|
|
59
|
+
* @module dsh-connect-workbuddy/client/styles
|
|
60
|
+
*/
|
|
61
|
+
const WORKBUDDY_CARD_CSS = `
|
|
62
|
+
.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}
|
|
63
|
+
.dsm-plugin-card:hover{border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
64
|
+
.dsm-plugin-card-open{background:var(--dsw-alias-bg-layer-2,#25262b);border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
65
|
+
.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}
|
|
66
|
+
.dsm-plugin-card-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:-2px}
|
|
67
|
+
.dsm-plugin-card-head{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}
|
|
68
|
+
.dsm-plugin-card-title{color:var(--dsw-alias-label-primary,#e6e6e6);font-size:15px;font-weight:600;line-height:1.4}
|
|
69
|
+
.dsm-plugin-card-description{color:var(--dsw-alias-label-tertiary,#999);font-size:13px;line-height:1.5}
|
|
70
|
+
.dsm-plugin-card-chevron{color:var(--dsw-alias-label-tertiary,#999);flex:none;display:inline-flex;transition:transform .16s}
|
|
71
|
+
.dsm-plugin-card-chevron-open{transform:rotate(180deg)}
|
|
72
|
+
.dsm-plugin-card-body{border-top:1px solid var(--dsw-alias-border-l2,#36373b);margin:0 16px;padding:0 0 8px}
|
|
73
|
+
.dsm-plugin-card-icon{width:32px;height:32px;flex:none;border-radius:7px}
|
|
74
|
+
.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}
|
|
75
|
+
.dsm-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
76
|
+
.dsm-btn:disabled{opacity:.4;cursor:default}
|
|
77
|
+
.dsm-btn-outline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font-weight:500}
|
|
78
|
+
.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)}
|
|
79
|
+
.dsm-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
|
|
80
|
+
.dsm-btn-primary:hover:not(:disabled){opacity:.9}
|
|
81
|
+
.dsm-workbuddy-usage{display:flex;flex-direction:column;gap:16px;margin:0;padding:16px 0 4px}
|
|
82
|
+
.dsm-workbuddy-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)}
|
|
83
|
+
.dsm-workbuddy-usage-account-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
84
|
+
.dsm-workbuddy-usage-expiry{padding-left:19px;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
85
|
+
.dsm-workbuddy-account-picker{display:block}
|
|
86
|
+
.dsm-workbuddy-usage-select-wrap{position:relative}
|
|
87
|
+
.dsm-workbuddy-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}
|
|
88
|
+
.dsm-workbuddy-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)}
|
|
89
|
+
.dsm-workbuddy-usage-select:disabled{opacity:.6;cursor:default}
|
|
90
|
+
.dsm-workbuddy-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}
|
|
91
|
+
.dsm-workbuddy-usage-text{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-label-secondary,#b8b8b8)}
|
|
92
|
+
.dsm-workbuddy-usage-error{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-state-error-primary,#ef4444)}
|
|
93
|
+
.dsm-workbuddy-usage-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
|
|
94
|
+
.dsm-workbuddy-usage-status{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:500;color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
95
|
+
.dsm-workbuddy-credits-panels{display:grid;grid-template-columns:minmax(0,1.6fr) minmax(150px,.8fr);gap:10px}
|
|
96
|
+
.dsm-workbuddy-credit-panel{display:flex;flex-direction:column;min-width:0;gap:7px;padding:14px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#24262c)}
|
|
97
|
+
.dsm-workbuddy-credit-panel-title{color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
98
|
+
.dsm-workbuddy-credit-panel-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:15px;line-height:21px}
|
|
99
|
+
.dsm-workbuddy-credit-panel-meta,.dsm-workbuddy-credit-panel-empty{color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:12px;line-height:18px}
|
|
100
|
+
.dsm-workbuddy-credit-monthly-row{position:relative;display:flex;flex-direction:column;gap:3px;margin:-14px -14px 0;padding:11px 14px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,#36373b);border-radius:14px 14px 0 0;background:var(--dsw-alias-bg-layer-2,#24262c);overflow:hidden}
|
|
101
|
+
.dsm-workbuddy-credit-monthly-row::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;opacity:.9;background:#9ca2aa}
|
|
102
|
+
.dsm-workbuddy-credit-monthly-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
103
|
+
.dsm-workbuddy-credit-monthly-meta{color:var(--dsw-alias-label-tertiary,#999);font-size:11.5px;line-height:17px;font-variant-numeric:tabular-nums}
|
|
104
|
+
.dsm-workbuddy-credit-packages{display:flex;flex-direction:column;gap:5px;margin:0;padding:0;list-style:none}
|
|
105
|
+
.dsm-workbuddy-credit-packages li{display:flex;align-items:baseline;justify-content:space-between;gap:10px;color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:12px;line-height:18px}
|
|
106
|
+
.dsm-workbuddy-credit-packages li span:first-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
107
|
+
.dsm-workbuddy-credit-packages li span:last-child{flex:none;color:var(--dsw-alias-label-tertiary,#999);font-size:11px}
|
|
108
|
+
.dsm-workbuddy-credit-soon{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-top:9px;padding-top:9px;border-top:1px solid var(--dsw-alias-border-l2,#36373b);color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:12px;line-height:18px}
|
|
109
|
+
.dsm-workbuddy-credit-soon strong{color:var(--dsw-alias-label-primary,#e6e6e6);font-size:15px;font-variant-numeric:tabular-nums}
|
|
110
|
+
.dsm-workbuddy-credit-panel-total{position:relative;align-items:center;text-align:center;overflow:hidden}
|
|
111
|
+
.dsm-workbuddy-credit-panel-total::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;opacity:.9;background:#4d9b6d}
|
|
112
|
+
.dsm-workbuddy-credit-total-body{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;width:100%}
|
|
113
|
+
.dsm-workbuddy-credit-total-value{color:#3f8d60;font-size:32px;line-height:36px;font-weight:700;letter-spacing:-.5px;white-space:nowrap;font-variant-numeric:tabular-nums}
|
|
114
|
+
.dsm-workbuddy-checkin{display:flex;flex-direction:column;align-items:center;width:100%;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2,#36373b)}
|
|
115
|
+
.dsm-workbuddy-checkin-button{width:100%;padding:4px 10px;font-size:12px}
|
|
116
|
+
.dsm-workbuddy-checkin-error{color:var(--dsw-alias-state-error-primary,#ef4444);font-size:11px;line-height:16px;text-align:center}
|
|
117
|
+
@media (max-width:760px){.dsm-workbuddy-credits-panels{grid-template-columns:1fr}.dsm-workbuddy-credit-panel-total{align-items:flex-start;text-align:left}.dsm-workbuddy-credit-total-body{align-items:flex-start}}
|
|
118
|
+
.dsm-workbuddy-models{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2,#36373b);padding-top:14px}
|
|
119
|
+
.dsm-workbuddy-models-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
120
|
+
.dsm-workbuddy-models-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
121
|
+
.dsm-workbuddy-models-summary{margin:2px 0 0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
122
|
+
.dsm-workbuddy-model-list{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2,#36373b);border-radius:10px;overflow:hidden}
|
|
123
|
+
.dsm-workbuddy-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}
|
|
124
|
+
.dsm-workbuddy-model-disabled{opacity:.55}
|
|
125
|
+
.dsm-workbuddy-model+.dsm-workbuddy-model{border-top:1px solid var(--dsw-alias-border-l2,#36373b)}
|
|
126
|
+
.dsm-workbuddy-model-head{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
|
|
127
|
+
.dsm-workbuddy-model-enabled{display:flex;align-items:center;gap:8px;min-width:0;cursor:pointer;flex:1}
|
|
128
|
+
.dsm-workbuddy-model-enabled input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe);flex:none}
|
|
129
|
+
.dsm-workbuddy-model-image{display:inline-flex;align-items:center;gap:5px;flex:none;cursor:pointer;color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:11px;line-height:16px}
|
|
130
|
+
.dsm-workbuddy-model-image input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe)}
|
|
131
|
+
.dsm-workbuddy-model-copy{display:flex;align-items:baseline;gap:8px;min-width:0}
|
|
132
|
+
.dsm-workbuddy-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}
|
|
133
|
+
.dsm-workbuddy-model-name-rate{color:var(--dsw-alias-label-tertiary,#999);font-size:11px;font-weight:400;line-height:16px;flex:none}
|
|
134
|
+
.dsm-workbuddy-model-id{color:var(--dsw-alias-label-tertiary,#999);font-size:11px;line-height:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
135
|
+
.dsm-workbuddy-model-desc{margin:0;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
136
|
+
.dsm-workbuddy-model-details{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
|
|
137
|
+
.dsm-workbuddy-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}
|
|
138
|
+
.dsm-workbuddy-model-meta-tag{padding:1px 7px;border-radius:999px;font-size:11px;line-height:15px;background:rgba(174,179,187,.11);color:var(--dsw-alias-label-secondary,#c6c9d0)}
|
|
139
|
+
.dsm-workbuddy-context-budget{display:flex;align-items:center;justify-content:flex-end;gap:12px;flex:none;margin:0;padding:0;border:0;color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:11px;line-height:16px}
|
|
140
|
+
.dsm-workbuddy-context-budget label{display:inline-flex;align-items:center;gap:4px;cursor:pointer}
|
|
141
|
+
.dsm-workbuddy-context-budget input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe)}
|
|
142
|
+
.dsm-workbuddy-model-capability-note{margin:0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
143
|
+
.dsm-workbuddy-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}
|
|
144
|
+
.dsm-workbuddy-model-actions-buttons{display:flex;align-items:center;justify-content:flex-end;gap:8px}
|
|
145
|
+
.dsm-workbuddy-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}
|
|
146
|
+
.dsm-workbuddy-usage-cheer-star{font-size:12px;line-height:1;display:inline-flex}
|
|
147
|
+
.dsm-workbuddy-usage-cheer:hover{color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
148
|
+
.dsm-workbuddy-usage-cheer:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:2px}
|
|
149
|
+
`;
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/client/WorkBuddyCard.tsx
|
|
152
|
+
/**
|
|
153
|
+
* WorkBuddy credits & models card contributed to Harness Plugin configuration.
|
|
154
|
+
*
|
|
155
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
156
|
+
* — 卡片的整体结构(折叠外壳 / 账号状态行 / 账号下拉 / 积分区 / 模型表 /
|
|
157
|
+
* 操作按钮行)、模块加载时注入一次 `<style>` 的写法、
|
|
158
|
+
* 草稿态(draftModels/draftEnabledIds)与 dirty 标记的保存流程、
|
|
159
|
+
* 60 秒轮询与 AbortController 清理、以及
|
|
160
|
+
* `IconChevronDownOutline14` 的使用,均来自该项目的 TraeUsageCard。
|
|
161
|
+
* 折叠卡片外壳与 `settings.plugin.item` 槽位形态来自
|
|
162
|
+
* dingminhua/dsh-subagent-default-model(MIT)。
|
|
163
|
+
* 改动:
|
|
164
|
+
* 1. 积分区改为「合计 + 按套餐名聚合的进度条」,因为实测单个账号下
|
|
165
|
+
* 同名套餐可达 19 个,逐条渲染会淹没卡片(原项目按上游条目直出);
|
|
166
|
+
* 2. 模型行补上 WorkBuddy 上游给出的积分倍率、多模态与推理档位;
|
|
167
|
+
* 3. 移除与 WorkBuddy 上游无关的 1M 变体勾选。
|
|
168
|
+
*
|
|
169
|
+
* @module dsh-connect-workbuddy/client/WorkBuddyCard
|
|
170
|
+
*/
|
|
171
|
+
const POLL_INTERVAL_MS = 6e4;
|
|
172
|
+
const WORKBUDDY_GITHUB_URL = "https://github.com/dingminhua/dsh-connect-workbuddy";
|
|
173
|
+
/** Inject or refresh the shared card CSS for the current client bundle. */
|
|
174
|
+
if (typeof document !== "undefined") {
|
|
175
|
+
const cssId = "dsh-connect-workbuddy/client.css";
|
|
176
|
+
const existing = document.querySelector(`style[data-plugin-css="${cssId}"]`);
|
|
177
|
+
if (existing !== null) existing.textContent = WORKBUDDY_CARD_CSS;
|
|
178
|
+
else {
|
|
179
|
+
const styleTag = document.createElement("style");
|
|
180
|
+
styleTag.dataset.plugin = "dsh-connect-workbuddy";
|
|
181
|
+
styleTag.dataset.pluginCss = cssId;
|
|
182
|
+
styleTag.textContent = WORKBUDDY_CARD_CSS;
|
|
183
|
+
document.head.appendChild(styleTag);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function formatNumber(value) {
|
|
187
|
+
return new Intl.NumberFormat(void 0, {
|
|
188
|
+
minimumFractionDigits: 0,
|
|
189
|
+
maximumFractionDigits: 2
|
|
190
|
+
}).format(value);
|
|
191
|
+
}
|
|
192
|
+
function formatDateTime(value) {
|
|
193
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
194
|
+
year: "numeric",
|
|
195
|
+
month: "2-digit",
|
|
196
|
+
day: "2-digit",
|
|
197
|
+
hour: "2-digit",
|
|
198
|
+
minute: "2-digit"
|
|
199
|
+
}).format(new Date(value));
|
|
200
|
+
}
|
|
201
|
+
/** Compact package-date rendering with time, e.g. 08/25 14:44. */
|
|
202
|
+
function formatDate(value) {
|
|
203
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
204
|
+
month: "2-digit",
|
|
205
|
+
day: "2-digit",
|
|
206
|
+
hour: "2-digit",
|
|
207
|
+
minute: "2-digit"
|
|
208
|
+
}).format(new Date(value));
|
|
209
|
+
}
|
|
210
|
+
function formatCapacity(value, unknown) {
|
|
211
|
+
if (value === void 0) return unknown;
|
|
212
|
+
if (value >= 1e6 && value % 1e6 === 0) return `${value / 1e6}M`;
|
|
213
|
+
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
214
|
+
return formatNumber(value);
|
|
215
|
+
}
|
|
216
|
+
function dotStyle(status) {
|
|
217
|
+
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)" };
|
|
218
|
+
}
|
|
219
|
+
/** Render WorkBuddy sign-in state, credits, and model selection as one card. */
|
|
220
|
+
function WorkBuddyCard({ t, settingsScope }) {
|
|
221
|
+
if (t === void 0) throw new Error("WorkBuddy plugin card requires its translation function");
|
|
222
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
223
|
+
const [status, setStatus] = (0, react.useState)({
|
|
224
|
+
status: "signed-out",
|
|
225
|
+
accounts: []
|
|
226
|
+
});
|
|
227
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
228
|
+
const [settingsRevision, setSettingsRevision] = (0, react.useState)(0);
|
|
229
|
+
const [draftModels, setDraftModels] = (0, react.useState)(void 0);
|
|
230
|
+
const [draftEnabledIds, setDraftEnabledIds] = (0, react.useState)(void 0);
|
|
231
|
+
const [draftImageIds, setDraftImageIds] = (0, react.useState)(void 0);
|
|
232
|
+
const [draftContextBudgets, setDraftContextBudgets] = (0, react.useState)(void 0);
|
|
233
|
+
const [saving, setSaving] = (0, react.useState)(false);
|
|
234
|
+
const [switchingAccount, setSwitchingAccount] = (0, react.useState)(false);
|
|
235
|
+
const [checkingIn, setCheckingIn] = (0, react.useState)(false);
|
|
236
|
+
const [checkinActionError, setCheckinActionError] = (0, react.useState)(void 0);
|
|
237
|
+
const mounted = (0, react.useRef)(true);
|
|
238
|
+
(0, react.useEffect)(() => {
|
|
239
|
+
mounted.current = true;
|
|
240
|
+
return () => {
|
|
241
|
+
mounted.current = false;
|
|
242
|
+
};
|
|
243
|
+
}, []);
|
|
244
|
+
(0, react.useEffect)(() => settingsScope?.subscribe(() => {
|
|
245
|
+
setSettingsRevision((value) => value + 1);
|
|
246
|
+
}), [settingsScope]);
|
|
247
|
+
const refreshUsage = (0, react.useCallback)(async (signal) => {
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(WORKBUDDY_USAGE_PATH, {
|
|
250
|
+
headers: { accept: "application/json" },
|
|
251
|
+
credentials: "same-origin",
|
|
252
|
+
...signal === void 0 ? {} : { signal }
|
|
253
|
+
});
|
|
254
|
+
const value = await response.json().catch(() => void 0);
|
|
255
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
256
|
+
if (mounted.current && signal?.aborted !== true) setStatus(value);
|
|
257
|
+
return value;
|
|
258
|
+
} catch (error) {
|
|
259
|
+
if (mounted.current && signal?.aborted !== true) setStatus({
|
|
260
|
+
status: "error",
|
|
261
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
262
|
+
});
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}, [t]);
|
|
266
|
+
(0, react.useEffect)(() => {
|
|
267
|
+
if (!open) return;
|
|
268
|
+
const controller = new AbortController();
|
|
269
|
+
refreshUsage(controller.signal);
|
|
270
|
+
return () => {
|
|
271
|
+
controller.abort();
|
|
272
|
+
};
|
|
273
|
+
}, [open, refreshUsage]);
|
|
274
|
+
(0, react.useEffect)(() => {
|
|
275
|
+
if (!open || status.status !== "signed-in") return;
|
|
276
|
+
const controller = new AbortController();
|
|
277
|
+
const timer = window.setInterval(() => {
|
|
278
|
+
refreshUsage(controller.signal);
|
|
279
|
+
}, POLL_INTERVAL_MS);
|
|
280
|
+
return () => {
|
|
281
|
+
window.clearInterval(timer);
|
|
282
|
+
controller.abort();
|
|
283
|
+
};
|
|
284
|
+
}, [
|
|
285
|
+
open,
|
|
286
|
+
refreshUsage,
|
|
287
|
+
status.status
|
|
288
|
+
]);
|
|
289
|
+
const rescanAccounts = async () => {
|
|
290
|
+
setBusy(true);
|
|
291
|
+
try {
|
|
292
|
+
const response = await fetch(WORKBUDDY_ACCOUNTS_REFRESH_PATH, {
|
|
293
|
+
method: "POST",
|
|
294
|
+
headers: { accept: "application/json" },
|
|
295
|
+
credentials: "same-origin"
|
|
296
|
+
});
|
|
297
|
+
const body = await response.json();
|
|
298
|
+
if (!response.ok || !Array.isArray(body.accounts)) throw new Error(`HTTP ${response.status}`);
|
|
299
|
+
const selected = body.accounts.find((account) => account.selected)?.id;
|
|
300
|
+
const configured = settingsScope?.getSnapshot().value;
|
|
301
|
+
const configuredId = typeof configured === "object" && configured !== null && typeof configured.accountId === "string" ? configured.accountId : void 0;
|
|
302
|
+
if (selected !== void 0 && selected !== configuredId && settingsScope?.getSnapshot().writable === true) await settingsScope.set("accountId", selected);
|
|
303
|
+
await refreshUsage();
|
|
304
|
+
} finally {
|
|
305
|
+
if (mounted.current) setBusy(false);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const switchAccount = async (accountId) => {
|
|
309
|
+
if (settingsScope === void 0) return;
|
|
310
|
+
setSwitchingAccount(true);
|
|
311
|
+
try {
|
|
312
|
+
await settingsScope.set("accountId", accountId);
|
|
313
|
+
await refreshUsage();
|
|
314
|
+
} finally {
|
|
315
|
+
if (mounted.current) setSwitchingAccount(false);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
const claimDailyCheckin = async () => {
|
|
319
|
+
setCheckingIn(true);
|
|
320
|
+
setCheckinActionError(void 0);
|
|
321
|
+
try {
|
|
322
|
+
const response = await fetch(WORKBUDDY_CHECKIN_PATH, {
|
|
323
|
+
method: "POST",
|
|
324
|
+
headers: { accept: "application/json" },
|
|
325
|
+
credentials: "same-origin"
|
|
326
|
+
});
|
|
327
|
+
const body = await response.json().catch(() => void 0);
|
|
328
|
+
if (!response.ok) throw new Error(body?.error ?? `HTTP ${response.status}`);
|
|
329
|
+
await refreshUsage();
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (mounted.current) setCheckinActionError(error instanceof Error ? error.message : t("row.requestFailed"));
|
|
332
|
+
} finally {
|
|
333
|
+
if (mounted.current) setCheckingIn(false);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
const refreshModels = async () => {
|
|
337
|
+
setBusy(true);
|
|
338
|
+
try {
|
|
339
|
+
const response = await fetch(WORKBUDDY_MODELS_REFRESH_PATH, {
|
|
340
|
+
method: "POST",
|
|
341
|
+
headers: { accept: "application/json" },
|
|
342
|
+
credentials: "same-origin"
|
|
343
|
+
});
|
|
344
|
+
const body = await response.json();
|
|
345
|
+
if (!response.ok || !Array.isArray(body.models)) throw new Error(`HTTP ${response.status}`);
|
|
346
|
+
const fresh = body.models;
|
|
347
|
+
const freshIds = new Set(fresh.map((model) => model.id));
|
|
348
|
+
const stillEnabled = [...activeEnabledIds].filter((id) => freshIds.has(id));
|
|
349
|
+
const stillImages = [...activeImageIds].filter((id) => freshIds.has(id));
|
|
350
|
+
const stillBudgets = {};
|
|
351
|
+
for (const id of freshIds) {
|
|
352
|
+
const budget = activeContextBudgets[id];
|
|
353
|
+
if (typeof budget === "number") stillBudgets[id] = budget;
|
|
354
|
+
}
|
|
355
|
+
setDraftModels(fresh);
|
|
356
|
+
setDraftEnabledIds(new Set(stillEnabled));
|
|
357
|
+
setDraftImageIds(new Set(stillImages));
|
|
358
|
+
setDraftContextBudgets(stillBudgets);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
if (mounted.current) setStatus({
|
|
361
|
+
status: "error",
|
|
362
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
363
|
+
});
|
|
364
|
+
} finally {
|
|
365
|
+
if (mounted.current) setBusy(false);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const visibleModels = draftModels ?? (status.status === "signed-in" ? status.models : []);
|
|
369
|
+
const savedEnabledIds = status.status === "signed-in" ? new Set(status.enabledModelIds) : /* @__PURE__ */ new Set();
|
|
370
|
+
const activeEnabledIds = draftEnabledIds ?? savedEnabledIds;
|
|
371
|
+
const savedImageIds = status.status === "signed-in" ? new Set(status.imageModelIds) : /* @__PURE__ */ new Set();
|
|
372
|
+
const activeImageIds = draftImageIds ?? savedImageIds;
|
|
373
|
+
const configured = settingsScope?.getSnapshot().value;
|
|
374
|
+
const savedContextBudgets = typeof configured === "object" && configured !== null && typeof configured.contextBudgets === "object" ? configured.contextBudgets : {};
|
|
375
|
+
const activeContextBudgets = draftContextBudgets ?? savedContextBudgets;
|
|
376
|
+
const dirty = draftModels !== void 0 || draftEnabledIds !== void 0 || draftImageIds !== void 0 || draftContextBudgets !== void 0;
|
|
377
|
+
const toggleModel = (modelId) => {
|
|
378
|
+
const next = new Set(activeEnabledIds);
|
|
379
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
380
|
+
setDraftEnabledIds(next);
|
|
381
|
+
setDraftModels([...visibleModels]);
|
|
382
|
+
};
|
|
383
|
+
const toggleImage = (modelId) => {
|
|
384
|
+
const next = new Set(activeImageIds);
|
|
385
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
386
|
+
setDraftImageIds(next);
|
|
387
|
+
setDraftModels([...visibleModels]);
|
|
388
|
+
};
|
|
389
|
+
const setContextBudget = (modelId, budget) => {
|
|
390
|
+
setDraftContextBudgets({
|
|
391
|
+
...activeContextBudgets,
|
|
392
|
+
[modelId]: budget
|
|
393
|
+
});
|
|
394
|
+
setDraftModels([...visibleModels]);
|
|
395
|
+
};
|
|
396
|
+
const discardModels = () => {
|
|
397
|
+
setDraftModels(void 0);
|
|
398
|
+
setDraftEnabledIds(void 0);
|
|
399
|
+
setDraftImageIds(void 0);
|
|
400
|
+
setDraftContextBudgets(void 0);
|
|
401
|
+
};
|
|
402
|
+
const saveModels = async () => {
|
|
403
|
+
if (settingsScope === void 0) return;
|
|
404
|
+
setSaving(true);
|
|
405
|
+
try {
|
|
406
|
+
await settingsScope.set("lastCatalog", visibleModels.map((model) => ({
|
|
407
|
+
...model,
|
|
408
|
+
contextWindow: model.nativeContextWindow,
|
|
409
|
+
nativeContextWindow: void 0,
|
|
410
|
+
multimodal: void 0
|
|
411
|
+
})));
|
|
412
|
+
await settingsScope.set("enabledModelIds", [...activeEnabledIds]);
|
|
413
|
+
await settingsScope.set("imageModelIds", [...activeImageIds]);
|
|
414
|
+
await settingsScope.set("contextBudgets", activeContextBudgets);
|
|
415
|
+
discardModels();
|
|
416
|
+
await refreshUsage();
|
|
417
|
+
} finally {
|
|
418
|
+
if (mounted.current) setSaving(false);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
const title = t("row.title");
|
|
422
|
+
const label = status.status === "signed-in" ? t("row.signedIn", { accountName: status.accountName }) : status.status === "error" ? t("row.requestFailed") : t("row.signedOut");
|
|
423
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
424
|
+
className: `dsm-plugin-card${open ? " dsm-plugin-card-open" : ""}`,
|
|
425
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
426
|
+
type: "button",
|
|
427
|
+
className: "dsm-plugin-card-header",
|
|
428
|
+
"aria-expanded": open,
|
|
429
|
+
"aria-label": `${t(open ? "row.collapse" : "row.expand")}: ${title}`,
|
|
430
|
+
onClick: () => {
|
|
431
|
+
setOpen(!open);
|
|
432
|
+
},
|
|
433
|
+
children: [
|
|
434
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
435
|
+
className: "dsm-plugin-card-icon",
|
|
436
|
+
src: WORKBUDDY_PLUGIN_ICON,
|
|
437
|
+
alt: ""
|
|
438
|
+
}),
|
|
439
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
440
|
+
className: "dsm-plugin-card-head",
|
|
441
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
442
|
+
className: "dsm-plugin-card-title",
|
|
443
|
+
children: title
|
|
444
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
445
|
+
className: "dsm-plugin-card-description",
|
|
446
|
+
children: t("row.desc")
|
|
447
|
+
})]
|
|
448
|
+
}),
|
|
449
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
450
|
+
"aria-hidden": "true",
|
|
451
|
+
className: `dsm-plugin-card-chevron${open ? " dsm-plugin-card-chevron-open" : ""}`,
|
|
452
|
+
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
453
|
+
})
|
|
454
|
+
]
|
|
455
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
456
|
+
className: "dsm-plugin-card-body",
|
|
457
|
+
hidden: !open,
|
|
458
|
+
children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
459
|
+
className: "dsm-workbuddy-usage",
|
|
460
|
+
children: [
|
|
461
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
462
|
+
className: "dsm-workbuddy-usage-account",
|
|
463
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
464
|
+
className: "dsm-workbuddy-usage-account-copy",
|
|
465
|
+
role: "status",
|
|
466
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
467
|
+
className: "dsm-workbuddy-usage-status",
|
|
468
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
469
|
+
"aria-hidden": "true",
|
|
470
|
+
className: "dsm-workbuddy-usage-dot",
|
|
471
|
+
style: dotStyle(status.status)
|
|
472
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
|
|
473
|
+
}), status.status === "signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
474
|
+
className: "dsm-workbuddy-usage-expiry",
|
|
475
|
+
children: t("row.tokenExpiry", { expiresAt: formatDateTime(status.tokenExpiresAtMs) })
|
|
476
|
+
}) : null]
|
|
477
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
478
|
+
type: "button",
|
|
479
|
+
className: "dsm-btn dsm-btn-outline",
|
|
480
|
+
disabled: busy,
|
|
481
|
+
onClick: () => {
|
|
482
|
+
rescanAccounts();
|
|
483
|
+
},
|
|
484
|
+
children: busy ? t("row.accountsScanning") : t("row.accountsRescan")
|
|
485
|
+
})]
|
|
486
|
+
}),
|
|
487
|
+
status.status !== "error" && status.accounts.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
488
|
+
className: "dsm-workbuddy-account-picker",
|
|
489
|
+
"aria-label": t("row.accountsTitle"),
|
|
490
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
491
|
+
className: "dsm-workbuddy-usage-select-wrap",
|
|
492
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
493
|
+
className: "dsm-workbuddy-usage-select",
|
|
494
|
+
value: status.status === "signed-in" ? status.accountId : "",
|
|
495
|
+
disabled: switchingAccount || settingsScope?.getSnapshot().writable !== true,
|
|
496
|
+
onChange: (event) => {
|
|
497
|
+
switchAccount(event.currentTarget.value);
|
|
498
|
+
},
|
|
499
|
+
children: status.accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
500
|
+
value: account.id,
|
|
501
|
+
children: [account.accountName, account.domain === "" ? "" : ` · ${account.domain}`]
|
|
502
|
+
}, account.id))
|
|
503
|
+
})
|
|
504
|
+
})
|
|
505
|
+
}) : null,
|
|
506
|
+
status.status === "signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
507
|
+
status.credits === void 0 ? null : (() => {
|
|
508
|
+
const monthly = [...status.credits.packages].filter((pack) => pack.monthly).sort((left, right) => right.remain - left.remain);
|
|
509
|
+
const SOON_MS = 2592e5;
|
|
510
|
+
const now = Date.now();
|
|
511
|
+
const expiring = [...status.credits.packages].filter((pack) => !pack.monthly && pack.remain > 0 && (pack.expiresAtMs ?? Number.MAX_SAFE_INTEGER) - now <= SOON_MS).sort((left, right) => (left.expiresAtMs ?? Number.MAX_SAFE_INTEGER) - (right.expiresAtMs ?? Number.MAX_SAFE_INTEGER));
|
|
512
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
513
|
+
className: "dsm-workbuddy-credits-panels",
|
|
514
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
515
|
+
className: "dsm-workbuddy-credit-panel dsm-workbuddy-credit-panel-activities",
|
|
516
|
+
children: [
|
|
517
|
+
monthly.map((pack, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
518
|
+
className: "dsm-workbuddy-credit-monthly-row",
|
|
519
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
520
|
+
className: "dsm-workbuddy-credit-monthly-name",
|
|
521
|
+
children: pack.packageName
|
|
522
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
523
|
+
className: "dsm-workbuddy-credit-monthly-meta",
|
|
524
|
+
children: t("row.creditsMonthlyRemain", {
|
|
525
|
+
remain: formatNumber(pack.remain),
|
|
526
|
+
size: formatNumber(pack.size),
|
|
527
|
+
at: pack.cycleRefreshMs === void 0 ? "" : formatDate(pack.cycleRefreshMs)
|
|
528
|
+
})
|
|
529
|
+
})]
|
|
530
|
+
}, `monthly-${pack.packageName}-${String(index)}`)),
|
|
531
|
+
expiring.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
532
|
+
className: "dsm-workbuddy-credit-panel-empty",
|
|
533
|
+
children: t("row.creditsNoSoon")
|
|
534
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
535
|
+
className: "dsm-workbuddy-credit-packages",
|
|
536
|
+
children: expiring.map((pack, index) => {
|
|
537
|
+
const at = pack.expiresAtMs;
|
|
538
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: pack.packageName }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [formatNumber(pack.remain), at === void 0 ? "" : ` · ${formatDate(at)}`] })] }, `${pack.packageName}-${String(index)}`);
|
|
539
|
+
})
|
|
540
|
+
}),
|
|
541
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
542
|
+
className: "dsm-workbuddy-credit-soon",
|
|
543
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.creditsExpiringSoon") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: formatNumber(status.credits.expiringSoon) })]
|
|
544
|
+
})
|
|
545
|
+
]
|
|
546
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
547
|
+
className: "dsm-workbuddy-credit-panel dsm-workbuddy-credit-panel-total",
|
|
548
|
+
children: [
|
|
549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
550
|
+
className: "dsm-workbuddy-credit-total-body",
|
|
551
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
552
|
+
className: "dsm-workbuddy-credit-panel-title",
|
|
553
|
+
children: t("row.creditsTotalLabel")
|
|
554
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
555
|
+
className: "dsm-workbuddy-credit-total-value",
|
|
556
|
+
children: formatNumber(status.credits.total)
|
|
557
|
+
})]
|
|
558
|
+
}),
|
|
559
|
+
status.checkin === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
560
|
+
className: "dsm-workbuddy-checkin",
|
|
561
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
562
|
+
type: "button",
|
|
563
|
+
className: "dsm-btn dsm-btn-primary dsm-workbuddy-checkin-button",
|
|
564
|
+
disabled: !status.checkin.active || status.checkin.todayCheckedIn || checkingIn,
|
|
565
|
+
onClick: () => {
|
|
566
|
+
claimDailyCheckin();
|
|
567
|
+
},
|
|
568
|
+
children: checkingIn ? t("row.checkinClaiming") : status.checkin.todayCheckedIn ? t("row.checkinClaimed") : status.checkin.claimButtonText ?? t("row.checkinClaim")
|
|
569
|
+
})
|
|
570
|
+
}),
|
|
571
|
+
status.checkinError === void 0 && checkinActionError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
572
|
+
className: "dsm-workbuddy-checkin-error",
|
|
573
|
+
children: t("row.checkinError", { message: checkinActionError ?? status.checkinError ?? "" })
|
|
574
|
+
})
|
|
575
|
+
]
|
|
576
|
+
})]
|
|
577
|
+
});
|
|
578
|
+
})(),
|
|
579
|
+
status.creditsError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
580
|
+
className: "dsm-workbuddy-usage-error",
|
|
581
|
+
children: t("row.creditsError", { message: status.creditsError })
|
|
582
|
+
}),
|
|
583
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
584
|
+
className: "dsm-workbuddy-models",
|
|
585
|
+
"aria-label": t("row.modelsTitle"),
|
|
586
|
+
children: [
|
|
587
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
588
|
+
className: "dsm-workbuddy-models-head",
|
|
589
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
590
|
+
className: "dsm-workbuddy-models-title",
|
|
591
|
+
children: t("row.modelsTitle")
|
|
592
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
593
|
+
className: "dsm-workbuddy-models-summary",
|
|
594
|
+
children: t("row.modelsSummary", { count: activeEnabledIds.size })
|
|
595
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
596
|
+
type: "button",
|
|
597
|
+
className: "dsm-btn dsm-btn-outline",
|
|
598
|
+
disabled: busy,
|
|
599
|
+
onClick: () => {
|
|
600
|
+
refreshModels();
|
|
601
|
+
},
|
|
602
|
+
children: busy ? t("row.modelsRefreshing") : t("row.modelsRefresh")
|
|
603
|
+
})]
|
|
604
|
+
}),
|
|
605
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
606
|
+
className: "dsm-workbuddy-model-list",
|
|
607
|
+
children: visibleModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
608
|
+
className: `dsm-workbuddy-model${activeEnabledIds.has(model.id) ? "" : " dsm-workbuddy-model-disabled"}`,
|
|
609
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
610
|
+
className: "dsm-workbuddy-model-head",
|
|
611
|
+
children: [
|
|
612
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
613
|
+
className: "dsm-workbuddy-model-enabled",
|
|
614
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
615
|
+
type: "checkbox",
|
|
616
|
+
checked: activeEnabledIds.has(model.id),
|
|
617
|
+
disabled: settingsScope?.getSnapshot().writable !== true || saving,
|
|
618
|
+
onChange: () => {
|
|
619
|
+
toggleModel(model.id);
|
|
620
|
+
}
|
|
621
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
622
|
+
className: "dsm-workbuddy-model-copy",
|
|
623
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
624
|
+
className: "dsm-workbuddy-model-name",
|
|
625
|
+
children: [model.name, model.creditMultiplier === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
626
|
+
className: "dsm-workbuddy-model-name-rate",
|
|
627
|
+
children: [
|
|
628
|
+
"(",
|
|
629
|
+
model.creditMultiplier.toFixed(2),
|
|
630
|
+
"x)"
|
|
631
|
+
]
|
|
632
|
+
})]
|
|
633
|
+
})
|
|
634
|
+
})]
|
|
635
|
+
}),
|
|
636
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
637
|
+
className: "dsm-workbuddy-model-image",
|
|
638
|
+
title: t("row.modelImage"),
|
|
639
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
640
|
+
type: "checkbox",
|
|
641
|
+
checked: activeImageIds.has(model.id),
|
|
642
|
+
disabled: settingsScope?.getSnapshot().writable !== true || saving,
|
|
643
|
+
onChange: () => {
|
|
644
|
+
toggleImage(model.id);
|
|
645
|
+
}
|
|
646
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelImage") })]
|
|
647
|
+
}),
|
|
648
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
649
|
+
className: "dsm-workbuddy-context-budget",
|
|
650
|
+
"aria-label": t("row.contextBudget"),
|
|
651
|
+
children: [model.nativeContextWindow > 2e5 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
652
|
+
type: "radio",
|
|
653
|
+
name: `context-${model.id}`,
|
|
654
|
+
checked: (activeContextBudgets[model.id] ?? 2e5) === 2e5,
|
|
655
|
+
disabled: settingsScope?.getSnapshot().writable !== true || saving,
|
|
656
|
+
onChange: () => {
|
|
657
|
+
setContextBudget(model.id, 2e5);
|
|
658
|
+
}
|
|
659
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "200K" })] }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
660
|
+
type: "radio",
|
|
661
|
+
name: `context-${model.id}`,
|
|
662
|
+
checked: model.nativeContextWindow <= 2e5 || activeContextBudgets[model.id] === model.nativeContextWindow,
|
|
663
|
+
disabled: model.nativeContextWindow <= 2e5 || settingsScope?.getSnapshot().writable !== true || saving,
|
|
664
|
+
onChange: () => {
|
|
665
|
+
setContextBudget(model.id, model.nativeContextWindow);
|
|
666
|
+
}
|
|
667
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatCapacity(model.nativeContextWindow, t("row.modelUnknown")) })] })]
|
|
668
|
+
})
|
|
669
|
+
]
|
|
670
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
671
|
+
className: "dsm-workbuddy-model-details",
|
|
672
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
673
|
+
className: "dsm-workbuddy-model-meta",
|
|
674
|
+
children: [
|
|
675
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelContext", { context: formatCapacity(model.nativeContextWindow, t("row.modelUnknown")) }) }),
|
|
676
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelOutput", { output: formatCapacity(model.maxTokens, t("row.modelUnknown")) }) }),
|
|
677
|
+
model.reasoning === void 0 || model.reasoning.supportedEfforts === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("row.modelReasoning", { efforts: model.reasoning.supportedEfforts.join(" / ") }) })
|
|
678
|
+
]
|
|
679
|
+
})
|
|
680
|
+
})]
|
|
681
|
+
}, model.id))
|
|
682
|
+
}),
|
|
683
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
684
|
+
className: "dsm-workbuddy-model-capability-note",
|
|
685
|
+
children: t("row.modelCapabilityPending")
|
|
686
|
+
}),
|
|
687
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
688
|
+
className: "dsm-workbuddy-model-actions",
|
|
689
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
690
|
+
className: "dsm-workbuddy-usage-cheer",
|
|
691
|
+
href: WORKBUDDY_GITHUB_URL,
|
|
692
|
+
target: "_blank",
|
|
693
|
+
rel: "noopener noreferrer",
|
|
694
|
+
children: [t("row.cheer"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
695
|
+
className: "dsm-workbuddy-usage-cheer-star",
|
|
696
|
+
"aria-hidden": "true",
|
|
697
|
+
children: "★"
|
|
698
|
+
})]
|
|
699
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
700
|
+
className: "dsm-workbuddy-model-actions-buttons",
|
|
701
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
702
|
+
type: "button",
|
|
703
|
+
className: "dsm-btn dsm-btn-outline",
|
|
704
|
+
disabled: !dirty || saving,
|
|
705
|
+
onClick: discardModels,
|
|
706
|
+
children: t("row.discard")
|
|
707
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
708
|
+
type: "button",
|
|
709
|
+
className: "dsm-btn dsm-btn-primary",
|
|
710
|
+
disabled: !dirty || saving || activeEnabledIds.size === 0,
|
|
711
|
+
onClick: () => {
|
|
712
|
+
saveModels();
|
|
713
|
+
},
|
|
714
|
+
children: saving ? t("row.saving") : t("row.save")
|
|
715
|
+
})]
|
|
716
|
+
})]
|
|
717
|
+
})
|
|
718
|
+
]
|
|
719
|
+
})
|
|
720
|
+
] }) : null,
|
|
721
|
+
status.status === "signed-out" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
722
|
+
className: "dsm-workbuddy-usage-text",
|
|
723
|
+
children: status.message ?? t("row.signedOutHint")
|
|
724
|
+
}) : null,
|
|
725
|
+
status.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
726
|
+
className: "dsm-workbuddy-usage-error",
|
|
727
|
+
children: status.message
|
|
728
|
+
}) : null
|
|
729
|
+
]
|
|
730
|
+
}) : null
|
|
731
|
+
})]
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/client/locales.ts
|
|
736
|
+
/**
|
|
737
|
+
* Plugin-card copy registered under the settings.workbuddy locale namespace.
|
|
738
|
+
*
|
|
739
|
+
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
740
|
+
* — `row.*` 的文案键约定与中英 1:1 键对齐(`zh: Record<Key, string>`
|
|
741
|
+
* 强制双语同步)来自该项目,其又继承自
|
|
742
|
+
* dingminhua/dsh-subagent-default-model(MIT)。
|
|
743
|
+
* 改动:文案按 WorkBuddy 的实际情况改写(积分套餐、模型倍率、多账号)。
|
|
744
|
+
*
|
|
745
|
+
* @module dsh-connect-workbuddy/client/locales
|
|
746
|
+
*/
|
|
747
|
+
const en = {
|
|
748
|
+
"row.title": "WorkBuddy credits & models (dsh-connect-workbuddy)",
|
|
749
|
+
"row.desc": "Use the models in the WorkBuddy desktop app directly in DSH, and see your remaining credits at a glance.",
|
|
750
|
+
"row.expand": "Expand",
|
|
751
|
+
"row.collapse": "Collapse",
|
|
752
|
+
"row.signedOut": "Not signed in",
|
|
753
|
+
"row.signedOutHint": "Sign in once in the WorkBuddy desktop app; this plugin follows that sign-in automatically.",
|
|
754
|
+
"row.signedIn": "Signed in: {accountName}",
|
|
755
|
+
"row.tokenExpiry": "Access token expires {expiresAt} (auto-renewal)",
|
|
756
|
+
"row.requestFailed": "Request failed",
|
|
757
|
+
"row.creditsTotalLabel": "Total remaining credits",
|
|
758
|
+
"row.creditsMonthlyRemain": "Remaining {remain} / {size} · Refreshes {at}",
|
|
759
|
+
"row.checkinClaim": "Check in",
|
|
760
|
+
"row.checkinClaiming": "Checking in…",
|
|
761
|
+
"row.checkinClaimed": "Checked in",
|
|
762
|
+
"row.checkinError": "Check-in unavailable: {message}",
|
|
763
|
+
"row.creditsError": "Credit query unavailable: {message}",
|
|
764
|
+
"row.creditsNoSoon": "No packages expire within 3 days.",
|
|
765
|
+
"row.creditsExpiringSoon": "Expiring in 3 days",
|
|
766
|
+
"row.refresh": "Refresh",
|
|
767
|
+
"row.refreshing": "Refreshing…",
|
|
768
|
+
"row.accountsTitle": "WorkBuddy account",
|
|
769
|
+
"row.accountsHint": "Choose from locally detected sign-ins. Tokens are never shown or saved in DSH settings.",
|
|
770
|
+
"row.accountsRescan": "Detect accounts again",
|
|
771
|
+
"row.accountsScanning": "Detecting…",
|
|
772
|
+
"row.modelsTitle": "Models",
|
|
773
|
+
"row.modelsSummary": "{count} enabled",
|
|
774
|
+
"row.modelsRefresh": "Refresh from WorkBuddy",
|
|
775
|
+
"row.modelsRefreshing": "Refreshing models…",
|
|
776
|
+
"row.discard": "Discard changes",
|
|
777
|
+
"row.save": "Save",
|
|
778
|
+
"row.saving": "Saving…",
|
|
779
|
+
"row.modelContext": "Maximum context {context}",
|
|
780
|
+
"row.contextBudget": "DSH context budget",
|
|
781
|
+
"row.modelOutput": "Output {output}",
|
|
782
|
+
"row.modelRate": "{rate}x credits",
|
|
783
|
+
"row.modelMultimodal": "Multimodal",
|
|
784
|
+
"row.modelImage": "Image",
|
|
785
|
+
"row.modelReasoning": "Reasoning: {efforts}",
|
|
786
|
+
"row.modelUnknown": "Unknown",
|
|
787
|
+
"row.modelCapabilityPending": "Only capabilities advertised by WorkBuddy are shown.",
|
|
788
|
+
"row.cheer": "Star on GitHub"
|
|
789
|
+
};
|
|
790
|
+
const zh = {
|
|
791
|
+
"row.title": "接入使用 WorkBuddy 积分与模型(dsh-connect-workbuddy)",
|
|
792
|
+
"row.desc": "在 DSH 中直接使用 WorkBuddy 桌面 App 包含的模型,并随时查看剩余积分。",
|
|
793
|
+
"row.expand": "展开",
|
|
794
|
+
"row.collapse": "收起",
|
|
795
|
+
"row.signedOut": "未登录",
|
|
796
|
+
"row.signedOutHint": "在 WorkBuddy 桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
|
|
797
|
+
"row.signedIn": "已登录:{accountName}",
|
|
798
|
+
"row.tokenExpiry": "访问令牌 {expiresAt} 过期(自动续期)",
|
|
799
|
+
"row.requestFailed": "请求失败",
|
|
800
|
+
"row.creditsTotalLabel": "总剩余积分",
|
|
801
|
+
"row.creditsMonthlyRemain": "剩余 {remain} / {size} · {at} 刷新",
|
|
802
|
+
"row.checkinClaim": "立即签到",
|
|
803
|
+
"row.checkinClaiming": "签到中…",
|
|
804
|
+
"row.checkinClaimed": "今日已签到",
|
|
805
|
+
"row.checkinError": "签到状态获取失败:{message}",
|
|
806
|
+
"row.creditsError": "积分查询失败:{message}",
|
|
807
|
+
"row.creditsNoSoon": "3 天内没有到期礼包。",
|
|
808
|
+
"row.creditsExpiringSoon": "最近 3 天到期",
|
|
809
|
+
"row.refresh": "刷新",
|
|
810
|
+
"row.refreshing": "正在刷新…",
|
|
811
|
+
"row.accountsTitle": "WorkBuddy 账号",
|
|
812
|
+
"row.accountsHint": "选择本机检测到的登录账号;Token 不会显示,也不会保存到 DSH 设置。",
|
|
813
|
+
"row.accountsRescan": "重新检测账号",
|
|
814
|
+
"row.accountsScanning": "正在检测…",
|
|
815
|
+
"row.modelsTitle": "模型",
|
|
816
|
+
"row.modelsSummary": "已启用 {count} 个",
|
|
817
|
+
"row.modelsRefresh": "从 WorkBuddy 刷新",
|
|
818
|
+
"row.modelsRefreshing": "正在刷新模型…",
|
|
819
|
+
"row.discard": "放弃修改",
|
|
820
|
+
"row.save": "保存",
|
|
821
|
+
"row.saving": "保存中…",
|
|
822
|
+
"row.modelContext": "最大上下文 {context}",
|
|
823
|
+
"row.contextBudget": "DSH 上下文预算",
|
|
824
|
+
"row.modelOutput": "最大输出 {output}",
|
|
825
|
+
"row.modelRate": "积分 {rate}x",
|
|
826
|
+
"row.modelMultimodal": "多模态",
|
|
827
|
+
"row.modelImage": "图片",
|
|
828
|
+
"row.modelReasoning": "推理强度:{efforts}",
|
|
829
|
+
"row.modelUnknown": "未知",
|
|
830
|
+
"row.modelCapabilityPending": "仅展示 WorkBuddy 接口明确公布的模型能力。",
|
|
831
|
+
"row.cheer": "鼓励一下"
|
|
832
|
+
};
|
|
833
|
+
//#endregion
|
|
834
|
+
//#region src/client/index.tsx
|
|
835
|
+
/** Stable browser-plugin name. */
|
|
836
|
+
const name = "dsh-connect-workbuddy-client";
|
|
837
|
+
/** Client services required by the Plugin configuration contribution. */
|
|
838
|
+
const inject = [
|
|
839
|
+
"slots",
|
|
840
|
+
"locale",
|
|
841
|
+
"settingsScope"
|
|
842
|
+
];
|
|
843
|
+
/** Register card copy and the WorkBuddy card under Plugin configuration. */
|
|
844
|
+
function apply(ctx) {
|
|
845
|
+
try {
|
|
846
|
+
const namespace = "settings.workbuddy";
|
|
847
|
+
ctx.effect(() => ctx.locale.register(namespace, {
|
|
848
|
+
zh,
|
|
849
|
+
en
|
|
850
|
+
}), "dsh-connect-workbuddy: settings copy");
|
|
851
|
+
const t = ctx.locale.bind(namespace);
|
|
852
|
+
const settingsScope = ctx.settingsScope.bind({ namespace: "workbuddy" });
|
|
853
|
+
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
854
|
+
name: "settings.plugin.item",
|
|
855
|
+
key: "workbuddy",
|
|
856
|
+
priority: 30,
|
|
857
|
+
inject: () => ({
|
|
858
|
+
t,
|
|
859
|
+
settingsScope
|
|
860
|
+
})
|
|
861
|
+
}, WorkBuddyCard));
|
|
862
|
+
} catch (error) {
|
|
863
|
+
console.error("[dsh-connect-workbuddy] client card failed to load (host provider unaffected):", error);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
//#endregion
|
|
867
|
+
exports.apply = apply;
|
|
868
|
+
exports.inject = inject;
|
|
869
|
+
exports.name = name;
|
|
870
|
+
return module.exports;
|
|
871
|
+
}
|
|
872
|
+
});
|