@goodandready/dsh-clinebot 0.3.15 → 0.3.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/CHANGELOG.md +6 -0
- package/lib/cline-client.js +6 -5
- package/lib/models.js +15 -71
- package/lib/routes/accounts.js +2 -2
- package/lib/routes/auth.js +1 -1
- package/lib/routes/models.js +1 -1
- package/lib/routes/settings.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ 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.3.16] - 2026-09-20
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Strict Active Subscription Plan Model Filtering (#48)**: Correctly parsed `plan.features.included` array from `GET /users/me/plan` to discover exactly the 11 active ClinePass subscription models. Removed non-subscription models from the default `CLINE_MODELS` list (eliminating out-of-plan failures and preventing 400+ models from cluttering the DSH picker).
|
|
12
|
+
- **Array Parsing in `parsePlanIncludedModels`**: Added support for both string and array inputs (extracting feature entries matching `/includes\s+/i`).
|
|
13
|
+
|
|
8
14
|
## [0.3.15] - 2026-09-19
|
|
9
15
|
|
|
10
16
|
### Fixed
|
package/lib/cline-client.js
CHANGED
|
@@ -277,12 +277,13 @@ export async function fetchUsageLimits(baseUrl, apiKey, {
|
|
|
277
277
|
|
|
278
278
|
if (planRes?.ok) {
|
|
279
279
|
const planData = await planRes.json().catch(() => ({}))
|
|
280
|
-
const plan = planData?.data || planData
|
|
281
|
-
if (plan?.title || plan?.name) {
|
|
282
|
-
planDisplayName = `${plan.title || plan.name} ($${((plan.priceInCents || 999) / 100).toFixed(2)}/mo)`
|
|
280
|
+
const plan = planData?.data?.plan || planData?.data || planData?.plan || planData
|
|
281
|
+
if (plan?.displayName || plan?.title || plan?.name) {
|
|
282
|
+
planDisplayName = `${plan.displayName || plan.title || plan.name} ($${((plan.pricePerSeatCents || plan.priceInCents || 999) / 100).toFixed(2)}/mo)`
|
|
283
283
|
}
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
const featuresIncluded = plan?.features?.included || plan?.includedModels
|
|
285
|
+
if (featuresIncluded) {
|
|
286
|
+
dynamicModels = parsePlanIncludedModels(featuresIncluded)
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
289
|
} catch {
|
package/lib/models.js
CHANGED
|
@@ -136,83 +136,27 @@ export const CLINE_MODELS = Object.freeze([
|
|
|
136
136
|
recommended: false,
|
|
137
137
|
isCustom: false,
|
|
138
138
|
},
|
|
139
|
-
{
|
|
140
|
-
id: 'cline-pass/claude-3-7-sonnet',
|
|
141
|
-
name: 'Claude 3.7 Sonnet',
|
|
142
|
-
description: 'Hybrid reasoning and standard generation model with high coding proficiency.',
|
|
143
|
-
contextLength: 200000,
|
|
144
|
-
maxTokens: 8192,
|
|
145
|
-
input: ['text', 'image'],
|
|
146
|
-
category: 'coding',
|
|
147
|
-
recommended: true,
|
|
148
|
-
isCustom: false,
|
|
149
|
-
reasoningEfforts: ['low', 'medium', 'high'],
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
id: 'cline-pass/gpt-4.5-preview',
|
|
153
|
-
name: 'GPT-4.5 Preview',
|
|
154
|
-
description: 'Advanced flagship frontier model with deep world knowledge and intuition.',
|
|
155
|
-
contextLength: 128000,
|
|
156
|
-
maxTokens: 16384,
|
|
157
|
-
input: ['text', 'image'],
|
|
158
|
-
category: 'general',
|
|
159
|
-
recommended: true,
|
|
160
|
-
isCustom: false,
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
id: 'cline-pass/o3-mini',
|
|
164
|
-
name: 'o3-mini',
|
|
165
|
-
description: 'Fast, cost-effective reasoning model specialized for STEM and coding.',
|
|
166
|
-
contextLength: 200000,
|
|
167
|
-
maxTokens: 65536,
|
|
168
|
-
input: ['text'],
|
|
169
|
-
category: 'reasoning',
|
|
170
|
-
recommended: true,
|
|
171
|
-
isCustom: false,
|
|
172
|
-
reasoningEfforts: ['low', 'medium', 'high'],
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
id: 'cline-pass/gemini-2.5-pro',
|
|
176
|
-
name: 'Gemini 2.5 Pro',
|
|
177
|
-
description: 'State-of-the-art multimodal reasoning model with extended context.',
|
|
178
|
-
contextLength: 1000000,
|
|
179
|
-
maxTokens: 8192,
|
|
180
|
-
input: ['text', 'image'],
|
|
181
|
-
category: 'multimodal',
|
|
182
|
-
recommended: true,
|
|
183
|
-
isCustom: false,
|
|
184
|
-
reasoningEfforts: ['low', 'medium', 'high'],
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
id: 'cline-pass/gemini-2.5-flash',
|
|
188
|
-
name: 'Gemini 2.5 Flash',
|
|
189
|
-
description: 'Ultra-fast multimodal model optimized for real-time agent workflows.',
|
|
190
|
-
contextLength: 1000000,
|
|
191
|
-
maxTokens: 8192,
|
|
192
|
-
input: ['text', 'image'],
|
|
193
|
-
category: 'general',
|
|
194
|
-
recommended: false,
|
|
195
|
-
isCustom: false,
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
id: 'cline-pass/qwen-2.5-coder-32b',
|
|
199
|
-
name: 'Qwen 2.5 Coder 32B',
|
|
200
|
-
description: 'Open-weights powerhouse for code generation, refactoring and bug fixing.',
|
|
201
|
-
contextLength: 131072,
|
|
202
|
-
maxTokens: 8192,
|
|
203
|
-
input: ['text'],
|
|
204
|
-
category: 'coding',
|
|
205
|
-
recommended: false,
|
|
206
|
-
isCustom: false,
|
|
207
|
-
},
|
|
208
139
|
])
|
|
209
140
|
|
|
210
141
|
/**
|
|
211
142
|
* Parse human-readable included models string from ClinePass plan features.
|
|
212
143
|
* Example: "Includes Kimi K3, GLM 5.2, Kimi K2.6, Kimi K2.7 Code, Mimo v2.5, Mimo v2.5 Pro, Minimax M3, Qwen3.7 Plus, Qwen3.7 Max, DeepSeek V4 Pro, and DeepSeek V4 Flash"
|
|
213
144
|
*/
|
|
214
|
-
export function parsePlanIncludedModels(
|
|
215
|
-
if (!
|
|
145
|
+
export function parsePlanIncludedModels(includedInput) {
|
|
146
|
+
if (!includedInput) return []
|
|
147
|
+
let includedText = ''
|
|
148
|
+
if (Array.isArray(includedInput)) {
|
|
149
|
+
const foundStr = includedInput.find((item) => typeof item === 'string' && /includes\s+/i.test(item))
|
|
150
|
+
if (foundStr) {
|
|
151
|
+
includedText = foundStr
|
|
152
|
+
} else {
|
|
153
|
+
includedText = includedInput.filter((x) => typeof x === 'string').join(', ')
|
|
154
|
+
}
|
|
155
|
+
} else if (typeof includedInput === 'string') {
|
|
156
|
+
includedText = includedInput
|
|
157
|
+
} else {
|
|
158
|
+
return []
|
|
159
|
+
}
|
|
216
160
|
const clean = includedText
|
|
217
161
|
.replace(/^includes\s+/i, '')
|
|
218
162
|
.replace(/\band\b/gi, ',')
|
package/lib/routes/accounts.js
CHANGED
|
@@ -17,7 +17,7 @@ export function registerAccountsRoutes(ctx, { live, getSettingsApi, syncProvider
|
|
|
17
17
|
try {
|
|
18
18
|
const bodyBuf = await readBody(req)
|
|
19
19
|
let body = {}
|
|
20
|
-
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch {}
|
|
20
|
+
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch { body = {} }
|
|
21
21
|
const account = String(body.account || '').trim()
|
|
22
22
|
|
|
23
23
|
clearUsageCache()
|
|
@@ -49,7 +49,7 @@ export function registerAccountsRoutes(ctx, { live, getSettingsApi, syncProvider
|
|
|
49
49
|
try {
|
|
50
50
|
const bodyBuf = await readBody(req)
|
|
51
51
|
let body = {}
|
|
52
|
-
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch {}
|
|
52
|
+
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch { body = {} }
|
|
53
53
|
const activeModels = body.models || publicConfig(live()).enabledModels
|
|
54
54
|
const result = await upsertPiAiProvider(ctx, live(), activeModels)
|
|
55
55
|
writeJson(res, 200, { ok: true, provider: result })
|
package/lib/routes/auth.js
CHANGED
|
@@ -60,7 +60,7 @@ export function registerAuthRoutes(ctx, { live, getSettingsApi, syncProviderStat
|
|
|
60
60
|
try {
|
|
61
61
|
const bodyBuf = await readBody(req)
|
|
62
62
|
let body = {}
|
|
63
|
-
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch {}
|
|
63
|
+
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch { body = {} }
|
|
64
64
|
|
|
65
65
|
const pub = publicConfig(live())
|
|
66
66
|
const activeKey = await resolveActiveAccountKey(ctx, live())
|
package/lib/routes/models.js
CHANGED
|
@@ -75,7 +75,7 @@ export function registerModelsRoutes(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
75
75
|
try {
|
|
76
76
|
const bodyBuf = await readBody(req)
|
|
77
77
|
let body = {}
|
|
78
|
-
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch {}
|
|
78
|
+
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch { body = {} }
|
|
79
79
|
|
|
80
80
|
const settingsApi = getSettingsApi()
|
|
81
81
|
if (settingsApi?.replace) {
|
package/lib/routes/settings.js
CHANGED
|
@@ -68,7 +68,7 @@ export function registerSettingsRoutes(ctx, { live, getSettingsApi, syncProvider
|
|
|
68
68
|
try {
|
|
69
69
|
const bodyBuf = await readBody(req)
|
|
70
70
|
let body = {}
|
|
71
|
-
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch {}
|
|
71
|
+
try { body = JSON.parse(bodyBuf.toString('utf8')) } catch { body = {} }
|
|
72
72
|
|
|
73
73
|
const apiKey = String(body.apiKey || '').trim()
|
|
74
74
|
if (!apiKey) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
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",
|