dsh-opencode-usage-dashboard 1.0.1 → 1.2.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 (4) hide show
  1. package/README.md +49 -17
  2. package/client.js +963 -166
  3. package/package.json +1 -1
  4. package/start.mjs +37 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-opencode-usage-dashboard",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "OpenCode 用量面板:在 DeepSeek Harness 侧栏查看 Go 订阅额度、Console 按量花费、用量趋势与月度预测。OpenCode quota, spend, usage and forecast dashboard for DeepSeek Harness.",
6
6
  "license": "MIT",
package/start.mjs CHANGED
@@ -9,6 +9,13 @@
9
9
  * 包名已从 @local/dsh-opencode-quota 迁移到 dsh-opencode-usage-dashboard;
10
10
  * 脚本会顺手清理旧包名留下的依赖/junction。
11
11
  *
12
+ * 不用先退出 DSH:`dsh plugin` 只是把参数转发给 profile 目录里的 pnpm,
13
+ * 安装动作和运行中的 DSH 不冲突。profile 的 base 层默认启用 `@deepseek-ai/dsh-hmr`
14
+ * (`root` 为空,只盯 profile manifest 与 patch 文件),插件管理器改完包会走
15
+ * `hmr.reconcileProfile()` 就地重新组合,所以 profile 一变 DSH 自己就会换。
16
+ * 只有 reconcile 报 no-hmr / package-moved / host-module 这类原因时才需要重启。
17
+ * 脚本因此不拦进程;真被文件占用(EBUSY/EPERM)时再提示退出 DSH 重跑。
18
+ *
12
19
  * 为什么要先删目录:DSH 当前插件管理器卸载 `link:` 依赖时不会删除
13
20
  * `node_modules` 里的 junction;直接 add 另一种来源会 EPERM。
14
21
  *
@@ -93,7 +100,6 @@ async function chooseSource() {
93
100
  const rl = createInterface({ input: process.stdin, output: process.stdout })
94
101
  const state = installedState()
95
102
  console.log(`当前安装:${currentLabel()}`)
96
- console.log('切换前请先完全退出 DSH。')
97
103
  console.log('')
98
104
  console.log(` 1) 本地 link${state === 'link' ? '(当前)' : ''} ${repoRoot}`)
99
105
  console.log(` 2) GitHub${state === 'github' ? '(当前)' : ''} ${REPO_SPEC}`)
@@ -117,16 +123,19 @@ if (state === source) {
117
123
  console.log(`当前已经是${stateLabel(state)},将重新安装。`)
118
124
  }
119
125
 
120
- if (process.platform === 'win32') {
126
+ /** DSH 是否在跑:只用来决定结尾提示什么,不阻止安装。 */
127
+ function dshRunning() {
128
+ if (process.platform !== 'win32') {
129
+ const check = spawnSync('pgrep', ['-f', 'DeepSeek Harness|dsh (web|desktop)'], { encoding: 'utf8' })
130
+ return check.status === 0 && (check.stdout || '').trim() !== ''
131
+ }
121
132
  const check = spawnSync('tasklist', ['/FI', 'IMAGENAME eq DeepSeek Harness.exe', '/NH'], {
122
133
  encoding: 'utf8',
123
134
  windowsHide: true,
124
135
  })
125
- if (check.status === 0 && /DeepSeek Harness\.exe/i.test(check.stdout || '')) {
126
- console.error('DSH 还在运行。请先完全退出 DeepSeek Harness,再运行本脚本。')
127
- process.exit(1)
128
- }
136
+ return check.status === 0 && /DeepSeek Harness\.exe/i.test(check.stdout || '')
129
137
  }
138
+ const dshLive = dshRunning()
130
139
 
131
140
  /** 用当前平台的 shell 调用 dsh plugin。 */
132
141
  function runDsh(args, childEnv = process.env) {
@@ -173,6 +182,9 @@ function removeTemps(dir) {
173
182
 
174
183
  console.log('')
175
184
  console.log(`目标:${source === 'github' ? 'GitHub 版' : '本地 link 版'}(${PACKAGE_NAME})`)
185
+ if (dshLive) {
186
+ console.log('DSH 正在运行:安装不受影响,profile 一变它会自己重新组合插件。')
187
+ }
176
188
 
177
189
  console.log('[1/3] 卸载当前版本…')
178
190
  const deps = dependencyNames()
@@ -196,10 +208,19 @@ console.log('[2/3] 清理 node_modules 残留…')
196
208
  if (pathState(oldPkgDir) !== 'none' && pathState(pkgDir) === 'none') {
197
209
  console.log(`检测到旧包名 ${OLD_PACKAGE_NAME},清理后会安装 ${PACKAGE_NAME}。`)
198
210
  }
199
- removeInstalled(pkgDir)
200
- removeInstalled(oldPkgDir)
201
- removeTemps(nodeModulesDir)
202
- removeTemps(oldLocalDir)
211
+ try {
212
+ removeInstalled(pkgDir)
213
+ removeInstalled(oldPkgDir)
214
+ removeTemps(nodeModulesDir)
215
+ removeTemps(oldLocalDir)
216
+ } catch (error) {
217
+ if (error && ['EPERM', 'EBUSY', 'ENOTEMPTY', 'EACCES'].includes(error.code)) {
218
+ console.error(`清理失败(${error.code}):${error.path || '目录'} 正被占用。`)
219
+ if (dshLive) console.error('请退出 DSH 后重跑本命令;如果仍失败,手动删掉上面这个路径。')
220
+ process.exit(1)
221
+ }
222
+ throw error
223
+ }
203
224
 
204
225
  /** 中断的插件操作会留下 run.json,清掉避免下次被当成“操作进行中”。 */
205
226
  console.log('清理 plugin-manager 运行标记…')
@@ -226,9 +247,14 @@ if (result.error) {
226
247
  }
227
248
  if (result.status !== 0) {
228
249
  console.error(`dsh plugin 退出码 ${result.status}`)
250
+ if (dshLive) console.error('如果上面是 EBUSY/EPERM,说明 DSH 正在占用目录:退出 DSH 后重跑本命令。')
229
251
  process.exit(result.status || 1)
230
252
  }
231
253
 
232
254
  console.log('')
233
255
  console.log(`完成:profile "${profile}" 现在使用 ${source === 'github' ? 'GitHub 版' : '本地 link 版'}(${PACKAGE_NAME})。`)
234
- console.log('启动 DSH 即可。')
256
+ if (dshLive) {
257
+ console.log('DSH 会按新 profile 重新组合;如果它提示「请重启 DSH 使更改生效」再重启。')
258
+ } else {
259
+ console.log('启动 DSH 即可。')
260
+ }