@goodandready/dsh-clinebot 0.5.2 → 0.5.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/CHANGELOG.md +10 -0
- package/lib/provider-sync.js +1 -1
- package/lib/routes/proxy.js +18 -7
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.4
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Peer gate on DSH 0.2.0-rc.1** (#58): DSH skips a profile bundle whose `peerDependencies` exclude the running version, so this plugin was absent from the profile with no error in the UI. Every `@deepseek-ai/dsh-*` peer now names both the 0.1.7-rc.2 and 0.2.0-rc.1 lines, because semver does not admit a prerelease of the next minor into a range that does not name it.
|
|
7
|
+
|
|
3
8
|
All notable changes to `@goodandready/dsh-clinebot` will be documented in this file.
|
|
4
9
|
|
|
5
10
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
11
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
12
|
|
|
13
|
+
## [0.5.3] - 2026-09-28
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Proxy Token Routing via DSH llm-pi-ai & Dual Bearer Auth (Issue #150, GitHub #11)**: In `@deepseek-ai/dsh-llm-pi-ai@0.1.7-rc.2`, the streaming runner (`streamWithSnapshot`) resolves request authorization strictly from `profile.apiKeyEnv` and completely ignores the literal `apiKey` field in the provider descriptor. When `proxyMode` is active, `upsertPiAiProvider` now correctly registers `apiKeyEnv: LOCAL_PROXY_KEY_ENV` (`CLINEBOT_LOCAL_PROXY_TOKEN`), while `lib/proxy-token.js` populates the credential store with the generated token value. In addition, `isAuthorizedProxyRequest` now accepts requests authenticated with either `CLINEBOT_LOCAL_PROXY_TOKEN` or any valid account key configured in the active account pool, ensuring uninterrupted communication across streaming, non-streaming, and diagnostic invocations without HTTP 401 Unauthorized rejections.
|
|
17
|
+
|
|
8
18
|
## [0.5.2] - 2026-09-28
|
|
9
19
|
|
|
10
20
|
### Security
|
package/lib/provider-sync.js
CHANGED
|
@@ -215,7 +215,7 @@ export async function upsertPiAiProvider(ctx, cfg, activeModelIds) {
|
|
|
215
215
|
|
|
216
216
|
const providerObj = buildPiAiProvider({
|
|
217
217
|
baseUrl: effectiveBaseUrl,
|
|
218
|
-
apiKeyEnv: activeAcc?.apiKeyEnv || pub.apiKeyEnv,
|
|
218
|
+
apiKeyEnv: isProxy ? LOCAL_PROXY_KEY_ENV : (activeAcc?.apiKeyEnv || pub.apiKeyEnv),
|
|
219
219
|
apiKey: localToken,
|
|
220
220
|
models: modelsToRegister.length ? modelsToRegister : allModels,
|
|
221
221
|
customModels: [...(pub.dynamicModels || []), ...(pub.customModels || [])],
|
package/lib/routes/proxy.js
CHANGED
|
@@ -24,9 +24,9 @@ import { getAllModels, DEFAULT_MODEL_ID } from '../models.js'
|
|
|
24
24
|
import { getLocalProxyToken } from '../proxy-token.js'
|
|
25
25
|
|
|
26
26
|
const require = createRequire(import.meta.url)
|
|
27
|
-
let packageVersion = '0.5.
|
|
27
|
+
let packageVersion = '0.5.3'
|
|
28
28
|
try {
|
|
29
|
-
packageVersion = require('../../package.json').version || '0.5.
|
|
29
|
+
packageVersion = require('../../package.json').version || '0.5.3'
|
|
30
30
|
} catch (err) {
|
|
31
31
|
/* fallback to default version if manifest is unreadable */
|
|
32
32
|
}
|
|
@@ -44,12 +44,22 @@ export function hasDisallowedBrowserOrigin(req) {
|
|
|
44
44
|
return false
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export function isAuthorizedProxyRequest(req) {
|
|
47
|
+
export function isAuthorizedProxyRequest(req, accountPool = []) {
|
|
48
48
|
const auth = req.headers?.['authorization'] || ''
|
|
49
49
|
const match = auth.match(/^Bearer\s+(.+)$/i)
|
|
50
50
|
if (!match) return false
|
|
51
51
|
const token = match[1].trim()
|
|
52
|
-
|
|
52
|
+
if (!token) return false
|
|
53
|
+
const localToken = getLocalProxyToken()
|
|
54
|
+
if (localToken && token === localToken) {
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(accountPool) && accountPool.length > 0) {
|
|
58
|
+
if (accountPool.some((acc) => acc.value && acc.value === token)) {
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
export function registerProxyRoutes(ctx, { live, getSettingsApi, syncProviderState }) {
|
|
@@ -70,7 +80,8 @@ export function registerProxyRoutes(ctx, { live, getSettingsApi, syncProviderSta
|
|
|
70
80
|
return writeJson(res, 403, { ok: false, error: 'Cross-site or browser requests to proxy are forbidden' })
|
|
71
81
|
}
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
const pool = await resolveAccountPool(ctx, live())
|
|
84
|
+
if (!isAuthorizedProxyRequest(req, pool)) {
|
|
74
85
|
return writeJson(res, 401, { ok: false, error: 'Unauthorized: missing or invalid bearer token' })
|
|
75
86
|
}
|
|
76
87
|
|
|
@@ -114,7 +125,6 @@ export function registerProxyRoutes(ctx, { live, getSettingsApi, syncProviderSta
|
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
const isStreaming = Boolean(body.stream)
|
|
117
|
-
const pool = await resolveAccountPool(ctx, cfg)
|
|
118
128
|
const configuredAccounts = pool.filter(a => a.present && a.value)
|
|
119
129
|
|
|
120
130
|
const maxRetries = Math.max(1, configuredAccounts.length)
|
|
@@ -345,7 +355,8 @@ export function registerProxyRoutes(ctx, { live, getSettingsApi, syncProviderSta
|
|
|
345
355
|
return writeJson(res, 403, { ok: false, error: 'Cross-site or browser requests to proxy are forbidden' })
|
|
346
356
|
}
|
|
347
357
|
|
|
348
|
-
|
|
358
|
+
const pool = await resolveAccountPool(ctx, live())
|
|
359
|
+
if (!isAuthorizedProxyRequest(req, pool)) {
|
|
349
360
|
return writeJson(res, 401, { ok: false, error: 'Unauthorized: missing or invalid bearer token' })
|
|
350
361
|
}
|
|
351
362
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "DeepSeek Harness companion for ClineBot / ClinePass: dynamic subscription models sync, quota exhaustion warnings, session metrics, dedicated settings page, live usage limits, and /cline slash-command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
62
|
-
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.
|
|
63
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.
|
|
62
|
+
"@deepseek-ai/dsh-credentials": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
64
64
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|