dsh-workspace-api-key 0.2.3 → 0.2.4
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 +2 -2
- package/README.zh.md +3 -3
- package/lib/client.js +44 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Host half (`lib/index.js`):
|
|
|
36
36
|
- keeps its own bookkeeping (which level maps to which ref, invalid flags, the provider a key was recorded for) in `$DSH_HOME/storages/dsh-workspace-api-key.json`;
|
|
37
37
|
- observes failures through the `agent/request-error` waterfall without ever returning `{kind: 'retry'}` — it only records the verdict and calls `next()`.
|
|
38
38
|
|
|
39
|
-
The browser half (`lib/client.js`) registers into the `sidebar.panellist` slot (`order: 1`), the `main` slot (key `workspace-api-key`) and the `shell.overlay` slot (the entering-a-session warning), the same slots `dsh-skill-mcp-panel` and `dsh-429-guard` use. It is plain `React.createElement` with no build step and no bundled dependencies. It merges the host rows with the browser-side `sessions` store (`ctx.get('sessions').list.getSnapshot()`, which is what the sidebar itself renders), so session titles come from `displayTitle
|
|
39
|
+
The browser half (`lib/client.js`) registers into the `sidebar.panellist` slot (`order: 1`), the `main` slot (key `workspace-api-key`) and the `shell.overlay` slot (the entering-a-session warning), the same slots `dsh-skill-mcp-panel` and `dsh-429-guard` use. It is plain `React.createElement` with no build step and no bundled dependencies. It merges the host rows with the browser-side `sessions` store (`ctx.get('sessions').list.getSnapshot()`, which is what the sidebar itself renders), so session titles come from `displayTitle`, host rows are never dropped when that store only knows a subset, and sessions stay visible even when the host cannot list them. That store is provided by `dsh-api-session-controller` *after* the plugin's `apply()`, so both the panel and the overlay retry for it (every 500 ms, at most 40 times) instead of giving up on the first render. The overlay asks `/wsk-api/check?sessionId=…&path=…` about the session that currently owns the main view, asks at most once per session, and its buttons only ever navigate to the panel — the panel is where a key can actually be changed.
|
|
40
40
|
|
|
41
41
|
### HTTP API (loopback only)
|
|
42
42
|
|
|
@@ -72,7 +72,7 @@ Then add `"dsh-workspace-api-key"` to `dsh.profile.bundles` in that profile's `p
|
|
|
72
72
|
|
|
73
73
|
```sh
|
|
74
74
|
node test/host.test.mjs # 125 assertions
|
|
75
|
-
node test/client.test.mjs #
|
|
75
|
+
node test/client.test.mjs # 130 assertions
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
Neither suite needs a running DSH process. The host suite drives `apply()` against a mock context (fake `credentials`, `workspaceRegistry`, `agents`, `sessionController`, `sessions`, `webServer`, stubbed `fetch`) and covers ref derivation, the session → workspace → default cascade, workspace matching, redirecting a second adapter's `apiKeyEnv`, clearing back to the default, 401/402/429/5xx classification, the loopback and origin checks, state persistence, and the session probe including the `{items}` envelope and the live-session fallback. The client suite loads `lib/client.js` through a minimal `window.__ModuleLoader__` plus a small React runtime, renders the panel and the overlay, and asserts slot registration, the first render, session expand/collapse, per-session saving and testing, sessions recovered from the browser-side store when the host has none (with `displayTitle` winning and subagent sessions hidden), the ungrouped-directory card, the stale and mismatch prompts, the "go configure" hand-off, graceful degradation without a session list, and back-navigation when `ctx.get('layout')` only becomes available after the plugin was applied.
|
package/README.zh.md
CHANGED
|
@@ -36,7 +36,7 @@ DSH 只从一个全局凭据 ref(默认 `DEEPSEEK_API_KEY`)解析 DeepSeek k
|
|
|
36
36
|
- 自己的账本(哪一层对应哪个 ref、失效标记、key 是给哪个服务商记的)落在 `$DSH_HOME/storages/dsh-workspace-api-key.json`;
|
|
37
37
|
- 通过 `agent/request-error` waterfall 观察失败,但**从不**返回 `{kind: 'retry'}`——只记录判定结果并 `next()` 放行。
|
|
38
38
|
|
|
39
|
-
浏览器半边(`lib/client.js`)注册到 `sidebar.panellist` 槽(`order: 1`)、`main` 槽(key 为 `workspace-api-key`)与 `shell.overlay` 槽(点进会话时的提醒),和 `dsh-skill-mcp-panel`、`dsh-429-guard` 用的是同一套槽。全部是朴素的 `React.createElement`,没有构建步骤,也不打包任何依赖。它会把宿主行与浏览器端 `sessions` 存储(`ctx.get('sessions').list.getSnapshot()`,也就是侧栏自己渲染的数据)合并起来,因此标题取自 `displayTitle
|
|
39
|
+
浏览器半边(`lib/client.js`)注册到 `sidebar.panellist` 槽(`order: 1`)、`main` 槽(key 为 `workspace-api-key`)与 `shell.overlay` 槽(点进会话时的提醒),和 `dsh-skill-mcp-panel`、`dsh-429-guard` 用的是同一套槽。全部是朴素的 `React.createElement`,没有构建步骤,也不打包任何依赖。它会把宿主行与浏览器端 `sessions` 存储(`ctx.get('sessions').list.getSnapshot()`,也就是侧栏自己渲染的数据)合并起来,因此标题取自 `displayTitle`,浏览器端只认识一部分会话时也不会把宿主行挤掉,宿主列不出会话时面板也照样有会话可列。这个存储由 `dsh-api-session-controller` 在插件 `apply()` **之后**才提供,所以面板与覆盖层都会为它重试(每 500ms 一次,最多 40 次),而不是首次渲染拿不到就放弃。覆盖层向 `/wsk-api/check?sessionId=…&path=…` 查询当前占据主视图的会话,每个会话最多问一次,它的按钮只负责把你带到面板——改 key 只能由面板里的操作完成。
|
|
40
40
|
|
|
41
41
|
### HTTP 接口(仅限回环)
|
|
42
42
|
|
|
@@ -72,10 +72,10 @@ pnpm add "dsh-workspace-api-key@github:COH2357/dsh-workspace-api-key"
|
|
|
72
72
|
|
|
73
73
|
```sh
|
|
74
74
|
node test/host.test.mjs # 125 条断言
|
|
75
|
-
node test/client.test.mjs #
|
|
75
|
+
node test/client.test.mjs # 130 条断言
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
两个套件都不需要启动 DSH。宿主套件用一个假 ctx(假的 `credentials`、`workspaceRegistry`、`agents`、`sessionController`、`sessions`、`webServer`,以及打桩的 `fetch`)驱动 `apply()`,覆盖 ref 派生、会话→工作区→默认的级联、工作区匹配、把第二个适配器的 `apiKeyEnv` 一起重定向、清回默认、401/402/429/5xx 的判定、回环与来源校验、状态落盘,以及会话探针(含 `{items}` 信封与 live 兜底)。浏览器套件通过一个极小的 `window.__ModuleLoader__` 与自制 React 运行时加载 `lib/client.js`,渲染出面板与覆盖层,断言槽注册、首屏渲染、会话折叠/展开、会话级保存与测试、宿主列不出会话时从浏览器端存储恢复会话(标题取 `displayTitle
|
|
78
|
+
两个套件都不需要启动 DSH。宿主套件用一个假 ctx(假的 `credentials`、`workspaceRegistry`、`agents`、`sessionController`、`sessions`、`webServer`,以及打桩的 `fetch`)驱动 `apply()`,覆盖 ref 派生、会话→工作区→默认的级联、工作区匹配、把第二个适配器的 `apiKeyEnv` 一起重定向、清回默认、401/402/429/5xx 的判定、回环与来源校验、状态落盘,以及会话探针(含 `{items}` 信封与 live 兜底)。浏览器套件通过一个极小的 `window.__ModuleLoader__` 与自制 React 运行时加载 `lib/client.js`,渲染出面板与覆盖层,断言槽注册、首屏渲染、会话折叠/展开、会话级保存与测试、宿主列不出会话时从浏览器端存储恢复会话(标题取 `displayTitle`、隐藏子代理会话、浏览器端只认识一部分会话时不挤掉宿主行)、会话列表服务晚于插件提供时的重试、未分组目录卡片、失效与不匹配提醒、「去配置」的交接、没有会话列表时的降级,以及 `ctx.get('layout')` 在插件 apply 之后才可用时返回键仍然有效。
|
|
79
79
|
|
|
80
80
|
## 要求与限制
|
|
81
81
|
|
package/lib/client.js
CHANGED
|
@@ -505,12 +505,31 @@ window.__ModuleLoader__.load({
|
|
|
505
505
|
// 浏览器端的会话列表(含标题、cwd)会随时变化:变了就重渲染。
|
|
506
506
|
const sessionStore = sessionsService(props?.sessions)
|
|
507
507
|
const [sessionTick, setSessionTick] = useState(0)
|
|
508
|
+
// 这个服务由 dsh-api-session-controller 在 effect 里晚于插件 apply 提供:
|
|
509
|
+
// 首次渲染拿不到就轮询一段时间,否则面板永远等不到会话列表。
|
|
510
|
+
const [storeMissing, setStoreMissing] = useState(false)
|
|
508
511
|
useEffect(() => {
|
|
509
512
|
const store = sessionStore?.list
|
|
510
|
-
if (store === undefined || store === null || typeof store.subscribe !== 'function')
|
|
513
|
+
if (store === undefined || store === null || typeof store.subscribe !== 'function') {
|
|
514
|
+
setStoreMissing(true)
|
|
515
|
+
return undefined
|
|
516
|
+
}
|
|
517
|
+
setStoreMissing(false)
|
|
511
518
|
const off = store.subscribe(() => setSessionTick((tick) => tick + 1))
|
|
512
519
|
return () => { if (typeof off === 'function') off() }
|
|
513
520
|
}, [sessionStore])
|
|
521
|
+
useEffect(() => {
|
|
522
|
+
if (!storeMissing) return undefined
|
|
523
|
+
let tries = 0
|
|
524
|
+
const timer = setInterval(() => {
|
|
525
|
+
tries += 1
|
|
526
|
+
if (sessionsService(props?.sessions) !== undefined || tries >= 40) {
|
|
527
|
+
clearInterval(timer)
|
|
528
|
+
setSessionTick((tick) => tick + 1)
|
|
529
|
+
}
|
|
530
|
+
}, 500)
|
|
531
|
+
return () => clearInterval(timer)
|
|
532
|
+
}, [storeMissing])
|
|
514
533
|
|
|
515
534
|
// 让覆盖层能立刻刷新面板(点「去配置」时面板可能已经挂载着)。
|
|
516
535
|
useEffect(() => {
|
|
@@ -1031,13 +1050,15 @@ window.__ModuleLoader__.load({
|
|
|
1031
1050
|
|
|
1032
1051
|
useEffect(() => {
|
|
1033
1052
|
ensureStyles()
|
|
1034
|
-
const sessions = ctx.get('sessions')
|
|
1035
|
-
if (sessions === undefined || sessions === null) return undefined
|
|
1036
|
-
|
|
1037
1053
|
let disposed = false
|
|
1054
|
+
let timer = null
|
|
1055
|
+
let unsubscribe = null
|
|
1056
|
+
let tries = 0
|
|
1057
|
+
let list = null
|
|
1058
|
+
|
|
1038
1059
|
const currentSession = () => {
|
|
1039
1060
|
try {
|
|
1040
|
-
const snapshot =
|
|
1061
|
+
const snapshot = list?.getSnapshot?.()
|
|
1041
1062
|
const byId = snapshot?.byId ?? {}
|
|
1042
1063
|
for (const [id, item] of Object.entries(byId)) {
|
|
1043
1064
|
if (Number(item?.retainedBy?.mainView) > 0) return { id, cwd: item?.cwd }
|
|
@@ -1067,12 +1088,26 @@ window.__ModuleLoader__.load({
|
|
|
1067
1088
|
}
|
|
1068
1089
|
}
|
|
1069
1090
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1091
|
+
// 会话列表服务由 dsh-api-session-controller 在 effect 里晚于插件 apply 提供
|
|
1092
|
+
// (覆盖层更早挂载),所以这里要有上限地重试,否则永远看不到会话。
|
|
1093
|
+
const attach = () => {
|
|
1094
|
+
if (disposed) return
|
|
1095
|
+
const sessions = ctx.get('sessions')
|
|
1096
|
+
if (sessions === null || sessions === undefined) {
|
|
1097
|
+
tries += 1
|
|
1098
|
+
if (tries < 40) timer = setTimeout(attach, 500)
|
|
1099
|
+
return
|
|
1100
|
+
}
|
|
1101
|
+
list = sessions.list ?? null
|
|
1102
|
+
evaluate()
|
|
1103
|
+
unsubscribe = typeof sessions.list?.subscribe === 'function'
|
|
1104
|
+
? sessions.list.subscribe(() => { evaluate() })
|
|
1105
|
+
: null
|
|
1106
|
+
}
|
|
1107
|
+
attach()
|
|
1074
1108
|
return () => {
|
|
1075
1109
|
disposed = true
|
|
1110
|
+
if (timer !== null) clearTimeout(timer)
|
|
1076
1111
|
if (typeof unsubscribe === 'function') unsubscribe()
|
|
1077
1112
|
}
|
|
1078
1113
|
}, [])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-workspace-api-key",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
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",
|