dsh-workspace-api-key 0.2.15 → 0.2.16

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/README.md CHANGED
@@ -79,7 +79,7 @@ The command forwards its arguments to pnpm inside the profile directory, so the
79
79
  pnpm add dsh-workspace-api-key # or: npm install dsh-workspace-api-key
80
80
  ```
81
81
 
82
- Pin a version with `dsh-workspace-api-key@0.2.15`, or install straight from the repository with `dsh-workspace-api-key@github:COH2357/dsh-workspace-api-key` (a git-hosted plugin is built from source on install).
82
+ Pin a version with `dsh-workspace-api-key@0.2.16`, or install straight from the repository with `dsh-workspace-api-key@github:COH2357/dsh-workspace-api-key` (a git-hosted plugin is built from source on install).
83
83
 
84
84
  Then add `"dsh-workspace-api-key"` to `dsh.profile.bundles` in that profile's `package.json` and restart DSH. For local development, use a link instead:
85
85
 
package/README.zh.md CHANGED
@@ -79,7 +79,7 @@ dsh plugin --profile web add dsh-workspace-api-key
79
79
  pnpm add dsh-workspace-api-key # 或者:npm install dsh-workspace-api-key
80
80
  ```
81
81
 
82
- 锁版本用 `dsh-workspace-api-key@0.2.15`;直接从仓库装则用 `dsh-workspace-api-key@github:COH2357/dsh-workspace-api-key`(git 来源的插件会在安装时现场构建)。
82
+ 锁版本用 `dsh-workspace-api-key@0.2.16`;直接从仓库装则用 `dsh-workspace-api-key@github:COH2357/dsh-workspace-api-key`(git 来源的插件会在安装时现场构建)。
83
83
 
84
84
  然后把 `"dsh-workspace-api-key"` 加进该 profile `package.json` 的 `dsh.profile.bundles`,重启 DSH。本地开发用 link 代替:
85
85
 
package/lib/index.js CHANGED
@@ -83,18 +83,29 @@ const SEARCH_DEFAULT_REF = 'DEEPSEEK_API_KEY_SEARCH'
83
83
  *
84
84
  * 配置本身用缓存:`credentials.resolve` 是热路径,不能每次都去 `settings.describe()`。
85
85
  */
86
- /** 重新读一次官方「网页搜索」配置(同步,无缓存——配置随时可能被官方页改掉)。 */
86
+ let webCache
87
+
88
+ /** 重新读一次官方「网页搜索」配置(只在请求/面板刷新这类「非热路径」里调用)。 */
87
89
  function refreshWebCache(ctx) {
88
90
  try {
89
- return readWebSettings(ctx)
91
+ webCache = readWebSettings(ctx)
90
92
  } catch {
91
- return webDefaults()
93
+ webCache = webCache ?? webDefaults()
92
94
  }
95
+ return webCache
93
96
  }
94
97
 
95
- /** 取官方「网页搜索」配置。 */
98
+ /**
99
+ * 取官方「网页搜索」配置——**只读缓存,绝不在 resolve 热路径里重新解析**。
100
+ *
101
+ * `settings.describe()` 会 interpolate 各条目的配置,而配置里可能有 `credential-ref`,
102
+ * 那等于从 credentials 服务内部再调回 credentials。0.2.15 就是在 resolve 里调 describe:
103
+ * 搜索 → resolve(搜索 ref) → describe → describe 又去 resolve → 服务自己等自己,
104
+ * promise 永远不 settle。表现就是 `web_search` 卡满 60 秒,面板接口也一起挂住。
105
+ * 缓存由 apply()、每个 HTTP 请求入口、面板刷新时更新。
106
+ */
96
107
  function currentWeb(ctx) {
97
- return refreshWebCache(ctx)
108
+ return webCache ?? webDefaults()
98
109
  }
99
110
 
100
111
  /**
@@ -1294,6 +1305,16 @@ export function apply(ctx) {
1294
1305
 
1295
1306
  // ── 1. 包装 credentials.resolve(按 ref 分辨搜索/抓取通道)──────────
1296
1307
  refreshWebCache(ctx)
1308
+ // 官方页改了「网页搜索」配置就丢掉缓存:解析热路径只读缓存,不能自己去 describe。
1309
+ try {
1310
+ ctx.effect(() =>
1311
+ ctx.on('settings/document-updated', () => {
1312
+ webCache = undefined
1313
+ }),
1314
+ )
1315
+ } catch (err) {
1316
+ log('settings listener unavailable: %s', String(err?.message ?? err))
1317
+ }
1297
1318
  installResolver(ctx, state)
1298
1319
  // 「直接禁用官方页面里的搜索 key 设置」:把官方 apiKeyEnv 指到插件自有 ref(异步、失败不影响启动)。
1299
1320
  void reconcileOfficialSearchRef(ctx)
@@ -1634,6 +1655,8 @@ function hasVisibleSession(rows) {
1634
1655
  }
1635
1656
 
1636
1657
  async function snapshot(ctx, state) {
1658
+ // 官方「网页搜索」配置:每次面板刷新都重读一次(缓存只在请求入口更新,解析路径只读)。
1659
+ refreshWebCache(ctx)
1637
1660
  const credentials = ctx.get('credentials')
1638
1661
  const defaultRefName = 'DEEPSEEK_API_KEY'
1639
1662
  const defaultInfo = await describeKey(ctx, defaultRefName)
@@ -1936,6 +1959,20 @@ async function searchStateOf(ctx, state, { sessionId, cwd }) {
1936
1959
  }
1937
1960
 
1938
1961
  async function handle(ctx, state, req, res) {
1962
+ // 每个请求进来先刷新一次网页搜索配置:解析热路径只读缓存。
1963
+ refreshWebCache(ctx)
1964
+ // 看门狗:任何一次 await 卡住都不该让面板/测试按钮一直转圈。
1965
+ const watchdog = setTimeout(() => {
1966
+ if (res.writableEnded === true) return
1967
+ try {
1968
+ res.writeHead(504, { 'content-type': 'application/json; charset=utf-8' })
1969
+ res.end(JSON.stringify({ ok: false, error: '面板请求超时(8 秒):DSH 的某个服务没有响应' }))
1970
+ } catch {
1971
+ /* 已经写过了就忽略 */
1972
+ }
1973
+ }, 8000)
1974
+ watchdog.unref?.()
1975
+ if (typeof res.on === 'function') res.on('close', () => clearTimeout(watchdog))
1939
1976
  if (!isTrusted(req)) {
1940
1977
  res.writeHead(403)
1941
1978
  res.end('forbidden')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-workspace-api-key",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "A DeepSeek Harness plugin that binds a separate DeepSeek API key to each workspace, or to a single session, so the spend of one key stays with the sessions you choose.",
5
5
  "type": "module",
6
6
  "license": "MIT",