@goodandready/dsh-clinebot 0.6.22 → 0.6.23
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 +7 -0
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh.md +1 -1
- package/lib/path-safety.js +7 -1
- package/lib/routes/accounts.js +39 -11
- package/lib/transport/cline-transport.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to `@goodandready/dsh-clinebot` will be documented in this f
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.23] - 2026-10-28
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Profile-file path guard** (#269): data paths must be `.json`, must stay inside `$DSH_HOME`, and cannot point at `profiles/**/package.json`, settings, credentials or TypeScript configs.
|
|
12
|
+
- **Explicit credential rollback failure** (#272): if settings persistence and credential rollback both fail, the API now reports `partial`/`credentialOrphan` with the env name and keeps the key available for cleanup/retry instead of hiding it.
|
|
13
|
+
- **Settings merge on account add** (#280): account additions use `settingsApi.update({ accounts })` and a fresh config read, preserving concurrent `timeoutMs` and other setting changes.
|
|
14
|
+
|
|
8
15
|
## [0.6.22] - 2026-10-28
|
|
9
16
|
|
|
10
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h3>Native ClineBot / ClinePass Provider Companion for DeepSeek Harness</h3>
|
|
6
6
|
|
|
7
|
-
<p><b>0.6.
|
|
7
|
+
<p><b>0.6.23</b> closes residual path/rollback/settings-merge races: profile files cannot be targeted through data paths, orphan credentials are reported explicitly, and account additions merge with concurrent settings. It keeps automatic model/free/dated catalog backfill, DSH <code>0.2.1-rc.4</code>, model-scoped credit cooldowns and 402/413 errors. Chat runs on the native <code>ctx.llm</code> adapter; the legacy <code>llm-pi-ai</code>, loopback proxy and <code>llm/stream</code> path are removed.</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/@goodandready/dsh-clinebot"><img src="https://img.shields.io/npm/v/@goodandready/dsh-clinebot.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
package/README.ru.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h3>Нативное подключение провайдера ClineBot / ClinePass для DeepSeek Harness</h3>
|
|
6
6
|
|
|
7
|
-
<p><b>0.6.
|
|
7
|
+
<p><b>0.6.23</b> закрывает остаточные гонки путей, rollback и настроек: файлы профиля нельзя выбрать через data paths, orphan-credential явно репортится, а добавление аккаунта мержится с параллельными настройками. Сохраняются автодобор каталога моделей/FREE/dated, DSH <code>0.2.1-rc.4</code>, cooldown недостатка кредитов для конкретной модели и ошибки 402/413. Чат работает через нативный адаптер <code>ctx.llm</code>; старые <code>llm-pi-ai</code>, loopback-прокси и <code>llm/stream</code> удалены.</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/@goodandready/dsh-clinebot"><img src="https://img.shields.io/npm/v/@goodandready/dsh-clinebot.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
package/README.zh.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h3>适用于 DeepSeek Harness 的 ClineBot / ClinePass 原生模型提供商伴侣插件</h3>
|
|
6
6
|
|
|
7
|
-
<p><b>0.6.
|
|
7
|
+
<p><b>0.6.23</b> 修复剩余的路径、回滚和设置合并竞态:数据路径不能指向配置文件,回滚失败会明确报告孤立凭据,添加账户会与并发设置合并。保留模型/免费/日期变体自动补齐、DSH <code>0.2.1-rc.4</code>、按模型隔离的余额不足冷却和明确的 402/413 错误。聊天使用原生 <code>ctx.llm</code> 适配器;旧的 <code>llm-pi-ai</code>、回环代理和 <code>llm/stream</code> 已删除。</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/@goodandready/dsh-clinebot"><img src="https://img.shields.io/npm/v/@goodandready/dsh-clinebot.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
|
package/lib/path-safety.js
CHANGED
|
@@ -13,5 +13,11 @@ export function isSafeDataPath(value) {
|
|
|
13
13
|
? path.resolve(process.env.HOME || os.homedir(), raw.slice(1))
|
|
14
14
|
: path.resolve(raw)
|
|
15
15
|
const home = dshHome()
|
|
16
|
-
|
|
16
|
+
if (resolved === home || !resolved.startsWith(`${home}${path.sep}`)) return false
|
|
17
|
+
const relative = path.relative(home, resolved).toLowerCase()
|
|
18
|
+
const segments = relative.split(/[\\/]+/)
|
|
19
|
+
const base = path.basename(resolved).toLowerCase()
|
|
20
|
+
if (segments[0] === 'profiles' && !base.startsWith('clinebot-')) return false
|
|
21
|
+
if (path.extname(base) !== '.json') return false
|
|
22
|
+
return !['package.json', 'package-lock.json', 'tsconfig.json', 'settings.json', '.credentials.json'].includes(base)
|
|
17
23
|
}
|
package/lib/routes/accounts.js
CHANGED
|
@@ -66,30 +66,46 @@ export function registerAccountsRoutes(ctx, { live, syncProviderState, getSettin
|
|
|
66
66
|
try {
|
|
67
67
|
if (previous.source === 'credentials' && previous.value) {
|
|
68
68
|
await saveCredentialKey(ctx, targetEnv, previous.value)
|
|
69
|
-
|
|
70
|
-
await deleteCredentialKey(ctx, targetEnv)
|
|
69
|
+
return true
|
|
71
70
|
}
|
|
71
|
+
const result = await deleteCredentialKey(ctx, targetEnv)
|
|
72
|
+
return Boolean(result?.ok)
|
|
72
73
|
} catch {
|
|
73
|
-
|
|
74
|
+
return false
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
await saveCredentialKey(ctx, targetEnv, apiKey)
|
|
78
79
|
|
|
79
|
-
const
|
|
80
|
+
const fresh = plainConfig(live())
|
|
81
|
+
const freshAccounts = Array.isArray(fresh.accounts) ? [...fresh.accounts] : []
|
|
82
|
+
const idx = freshAccounts.findIndex((a) => a && a.apiKeyEnv === targetEnv)
|
|
80
83
|
const accountEntry = { label: accountLabel, apiKeyEnv: targetEnv }
|
|
81
84
|
if (idx >= 0) {
|
|
82
|
-
|
|
85
|
+
freshAccounts[idx] = accountEntry
|
|
83
86
|
} else {
|
|
84
|
-
|
|
87
|
+
freshAccounts.push(accountEntry)
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
const next = plainConfig(Config({ ...
|
|
90
|
+
const next = plainConfig(Config({ ...fresh, accounts: freshAccounts }))
|
|
88
91
|
const settingsApi = getSettingsApi()
|
|
89
92
|
try {
|
|
90
|
-
|
|
93
|
+
if (typeof settingsApi.update === 'function') {
|
|
94
|
+
await settingsApi.update({ accounts: freshAccounts })
|
|
95
|
+
} else {
|
|
96
|
+
await settingsApi.replace(next)
|
|
97
|
+
}
|
|
91
98
|
} catch (err) {
|
|
92
|
-
await restoreCredential()
|
|
99
|
+
const restored = await restoreCredential()
|
|
100
|
+
if (!restored) {
|
|
101
|
+
pendingSecretCleanupAccounts.add(targetEnv)
|
|
102
|
+
const partial = new Error(`Account settings were not persisted and credential rollback failed for "${targetEnv}". Use account delete with secret cleanup to retry.`)
|
|
103
|
+
partial.status = 500
|
|
104
|
+
partial.partial = true
|
|
105
|
+
partial.credentialOrphan = true
|
|
106
|
+
partial.apiKeyEnv = targetEnv
|
|
107
|
+
throw partial
|
|
108
|
+
}
|
|
93
109
|
throw err
|
|
94
110
|
}
|
|
95
111
|
await syncProviderState(next)
|
|
@@ -150,7 +166,13 @@ export function registerAccountsRoutes(ctx, { live, syncProviderState, getSettin
|
|
|
150
166
|
writeJson(res, 200, { ok: true, ...result })
|
|
151
167
|
} catch (err) {
|
|
152
168
|
const status = typeof err?.status === 'number' ? err.status : 500
|
|
153
|
-
writeJson(res, status, {
|
|
169
|
+
writeJson(res, status, {
|
|
170
|
+
ok: false,
|
|
171
|
+
error: String(err?.message || err),
|
|
172
|
+
...(err?.partial ? { partial: true } : {}),
|
|
173
|
+
...(err?.credentialOrphan ? { credentialOrphan: true } : {}),
|
|
174
|
+
...(err?.apiKeyEnv ? { apiKeyEnv: err.apiKeyEnv } : {}),
|
|
175
|
+
})
|
|
154
176
|
}
|
|
155
177
|
},
|
|
156
178
|
}), 'dsh-clinebot: /accounts')
|
|
@@ -394,7 +416,13 @@ export function registerAccountsRoutes(ctx, { live, syncProviderState, getSettin
|
|
|
394
416
|
writeJson(res, 200, { ok: true, ...result })
|
|
395
417
|
} catch (err) {
|
|
396
418
|
const status = typeof err?.status === 'number' ? err.status : 500
|
|
397
|
-
writeJson(res, status, {
|
|
419
|
+
writeJson(res, status, {
|
|
420
|
+
ok: false,
|
|
421
|
+
error: String(err?.message || err),
|
|
422
|
+
...(err?.partial ? { partial: true } : {}),
|
|
423
|
+
...(err?.credentialOrphan ? { credentialOrphan: true } : {}),
|
|
424
|
+
...(err?.apiKeyEnv ? { apiKeyEnv: err.apiKeyEnv } : {}),
|
|
425
|
+
})
|
|
398
426
|
}
|
|
399
427
|
},
|
|
400
428
|
}), 'dsh-clinebot: /keys/discovered/import')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.23",
|
|
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",
|