@virzz/dsh-plugin-deepseek-balance 1.0.0 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +95 -11
  2. package/lib/client.js +20 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@ official account balance as a row in the sidebar footer, above **Settings**.
5
5
 
6
6
  ```
7
7
  ◆ Cordis Plugin 0 running
8
- ▤ DeepSeek 余额 $1058.69 · ¥-0.01
8
+ ▤ DeepSeek 余额 $1058.69
9
9
  ⚙ 设置
10
10
  ```
11
11
 
@@ -34,36 +34,120 @@ Design notes:
34
34
  the browser. The read route returns only balance figures.
35
35
  - **Two cadences.** The child collects every 60s; the row re-reads the host's cached
36
36
  snapshot every 15s, so no polling happens from the browser.
37
+ - **Positive balances only.** A currency whose total is zero or negative says nothing useful
38
+ in a balance read-out, so it is left out of both the row and its tooltip. The tooltip
39
+ reports how many entries were hidden, and the row reads `0` when nothing is positive. The
40
+ host still returns every currency it receives — the rule is presentation, not data.
37
41
 
38
- ## Install
42
+ ## Install into DSH
39
43
 
40
- Published to npmjs on every release:
44
+ A DSH plugin is a package plus a row. The package has to be resolvable **from the profile
45
+ that mounts it**, and the row has to name it — the browser half only reaches the page as part
46
+ of that profile's client roster, which is composed at boot.
47
+
48
+ ### 1. Add the package to the profile
49
+
50
+ ```sh
51
+ dsh plugin --profile web add @virzz/dsh-plugin-deepseek-balance
52
+ ```
53
+
54
+ `dsh plugin` forwards everything after `--profile <name>` to pnpm **in the profile
55
+ directory**, so this is an ordinary `pnpm add` in `$DSH_HOME/profiles/web` — which is exactly
56
+ the `node_modules` tree the loader resolves row names from.
57
+
58
+ To leave the shipped `web` profile untouched, derive your own from it and install there:
41
59
 
42
60
  ```sh
43
- npm install @virzz/dsh-plugin-deepseek-balance
61
+ dsh --profile balance --from-default-profile web
62
+ dsh plugin --profile balance add @virzz/dsh-plugin-deepseek-balance
44
63
  ```
45
64
 
46
- Also mirrored to the GitHub npm registry:
65
+ The package is published to npmjs and to GitHub Packages. The command above resolves from
66
+ npmjs by default; to install from GitHub Packages, point the scope at it first:
47
67
 
48
68
  ```sh
49
69
  npm config set @virzz:registry https://npm.pkg.github.com
50
- npm install @virzz/dsh-plugin-deepseek-balance
51
70
  ```
52
71
 
53
- To mount it in a DSH profile, the package must also be resolvable from that profile and named
54
- by a row. With pnpm available that is `dsh plugin --profile web add <spec>`; without pnpm a
55
- link plus one patch row is equivalent:
72
+ <details>
73
+ <summary>Without pnpm</summary>
74
+
75
+ `dsh plugin add` does two things; both can be done by hand — put the package where the
76
+ profile can resolve it, and name it in the profile's own patch layer.
56
77
 
57
78
  ```sh
58
- ln -s /path/to/dsh-plugin-deepseek-balance ~/.dsh/profiles/web/node_modules/@virzz/dsh-plugin-deepseek-balance
79
+ mkdir -p ~/.dsh/profiles/web/node_modules/@virzz
80
+ ln -s /path/to/dsh-plugin-deepseek-balance \
81
+ ~/.dsh/profiles/web/node_modules/@virzz/dsh-plugin-deepseek-balance
59
82
  ```
60
83
 
61
84
  ```yaml
62
- # ~/.dsh/profiles/web/cordis.patch.yml
85
+ # ~/.dsh/profiles/web/cordis.patch.yml — applied after every bundle layer
63
86
  - insert:
64
87
  - id: deepseek-balance
65
88
  name: '@virzz/dsh-plugin-deepseek-balance'
66
89
  ```
90
+ </details>
91
+
92
+ ### 2. Provide the DeepSeek API key
93
+
94
+ The host half re-resolves the credential reference `DEEPSEEK_API_KEY` on every collector
95
+ start. Either of these works:
96
+
97
+ - **Settings → Models**, on the DeepSeek provider card — stored in `$DSH_HOME/.credentials.yaml`; or
98
+ - export it where DSH boots: `export DEEPSEEK_API_KEY=sk-...`
99
+
100
+ Nothing else needs it. The key never reaches the browser and never appears on a command
101
+ line: the collector receives it in its environment, and the read route exposes balance
102
+ figures only.
103
+
104
+ ### 3. Boot
105
+
106
+ ```sh
107
+ dsh --profile web # or: dsh web
108
+ ```
109
+
110
+ The row appears in the sidebar footer, directly above **Settings**:
111
+
112
+ ```
113
+ ◆ Cordis Plugin 0 running
114
+ ▤ DeepSeek 余额 $1058.69
115
+ ⚙ 设置
116
+ ```
117
+
118
+ Hover it for the per-currency breakdown (total, granted, topped up) and the collection time;
119
+ click it to re-read the host's cache immediately.
120
+
121
+ ### 4. Verify without opening the UI
122
+
123
+ ```sh
124
+ dsh --profile web --dump-config | grep -A2 deepseek-balance # is the row composed?
125
+ curl -s http://127.0.0.1:8021/deepseek-balance # does the host half answer?
126
+ ```
127
+
128
+ The launcher prints its URL on boot; adjust the port if yours differs. A healthy answer:
129
+
130
+ ```json
131
+ {"ok":true,"available":true,"balances":[{"currency":"USD","total":"1058.69","granted":"0.00","toppedUp":"1058.69"}],"fetchedAt":1789030816379}
132
+ ```
133
+
134
+ ### Troubleshooting
135
+
136
+ | Symptom | What to check |
137
+ | --- | --- |
138
+ | Row reads `未配置密钥` | `DEEPSEEK_API_KEY` is not resolvable — set it in Settings → Models, or in the environment that boots DSH |
139
+ | Row reads `不可用` | Hover it: the tooltip carries the exact cause (`http-401`, `request-failed`, `poller-exited`, …) |
140
+ | Row reads `不可用`, tooltip says `subprocess 服务不可用` | The row activated before the subprocess service. It declares that as a hard dependency *and* retries every 5s, so it clears itself |
141
+ | No row at all | The client roster is composed at boot — restart the profile. `--dump-config` above shows whether the row is composed at all |
142
+ | Row only visible when the sidebar is expanded | Expected: in the 56px rail it collapses to a 36px circle showing the primary currency symbol |
143
+
144
+ ### Uninstall
145
+
146
+ ```sh
147
+ dsh plugin --profile web remove @virzz/dsh-plugin-deepseek-balance
148
+ ```
149
+
150
+ Or delete the row from `cordis.patch.yml` plus the `node_modules` entry, then restart.
67
151
 
68
152
  `dsh.client` in `package.json` puts `lib/client.js` into the browser roster that
69
153
  `@deepseek-ai/dsh-client-modules` composes into `window.__DSH_BOOT__`. The module id inside
package/lib/client.js CHANGED
@@ -45,13 +45,18 @@ window.__ModuleLoader__.load({
45
45
  return symbolOf(entry.currency) + entry.total;
46
46
  }
47
47
 
48
- /** The entry whose figure stands for the account: the first non-zero one, else the first. */
49
- function primaryOf(balances) {
48
+ /**
49
+ * The balances worth showing. A currency whose total is zero or negative carries no
50
+ * information for a balance read-out, so it is left out of both the row and its
51
+ * tooltip — and only counted, so the tooltip can say that something was hidden.
52
+ */
53
+ function positiveOf(balances) {
54
+ const shown = [];
50
55
  for (let index = 0; index < balances.length; index += 1) {
51
56
  const value = Number(balances[index].total);
52
- if (Number.isFinite(value) && value !== 0) return balances[index];
57
+ if (Number.isFinite(value) && value > 0) shown.push(balances[index]);
53
58
  }
54
- return balances.length > 0 ? balances[0] : undefined;
59
+ return shown;
55
60
  }
56
61
 
57
62
  function timeText(ms) {
@@ -131,6 +136,8 @@ window.__ModuleLoader__.load({
131
136
  }, []);
132
137
 
133
138
  const balances = state.balances;
139
+ const shown = positiveOf(balances);
140
+ const hidden = balances.length - shown.length;
134
141
  let tone = "loading";
135
142
  let label = "DeepSeek 余额";
136
143
  let value = "…";
@@ -138,12 +145,14 @@ window.__ModuleLoader__.load({
138
145
 
139
146
  if (state.phase === "ok") {
140
147
  tone = state.available ? "ok" : "error";
141
- value = balances.slice(0, 2).map(amountOf).join(" · ");
148
+ value = shown.length > 0 ? shown.slice(0, 2).map(amountOf).join(" · ") : "0";
142
149
  const lines = ["DeepSeek 余额(常驻 node 采集)"];
143
- for (let index = 0; index < balances.length; index += 1) {
144
- const entry = balances[index];
150
+ for (let index = 0; index < shown.length; index += 1) {
151
+ const entry = shown[index];
145
152
  lines.push(entry.currency + " " + entry.total + "(赠金 " + entry.granted + " · 充值 " + entry.toppedUp + ")");
146
153
  }
154
+ if (shown.length === 0) lines.push("所有币种余额均不大于 0")
155
+ else if (hidden > 0) lines.push("已隐藏 " + hidden + " 项非正余额")
147
156
  if (state.available !== true) lines.push("该账户当前不可调用");
148
157
  const updated = timeText(state.fetchedAt);
149
158
  if (updated !== "") lines.push("采集于 " + updated);
@@ -156,8 +165,10 @@ window.__ModuleLoader__.load({
156
165
  }
157
166
 
158
167
  if (wide !== true) {
159
- const primary = primaryOf(balances);
160
- const glyph = state.phase === "ok" ? symbolOf(primary === undefined ? "" : primary.currency) : state.phase === "error" ? "!" : "…";
168
+ const primary = shown.length > 0 ? shown[0] : undefined;
169
+ const glyph = state.phase === "ok"
170
+ ? (primary === undefined ? "0" : symbolOf(primary.currency))
171
+ : state.phase === "error" ? "!" : "…";
161
172
  return React.createElement("button", {
162
173
  type: "button",
163
174
  className: "dsb-row dsb-rail",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@virzz/dsh-plugin-deepseek-balance",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "DeepSeek official account balance as a DSH sidebar status row, collected by one resident node process",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",