@goodandready/dsh-clinebot 0.3.1 → 0.3.3
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 +28 -0
- package/docs/design/DESIGN.md +10 -2
- package/lib/client.js +362 -94
- package/lib/cline-client.js +42 -1
- package/lib/index.js +358 -48
- package/lib/models.js +83 -0
- package/package.json +1 -1
package/lib/models.js
CHANGED
|
@@ -21,6 +21,7 @@ export const CLINE_MODELS = Object.freeze([
|
|
|
21
21
|
category: 'coding',
|
|
22
22
|
recommended: true,
|
|
23
23
|
isCustom: false,
|
|
24
|
+
reasoningEfforts: ['low', 'medium', 'high'],
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
27
|
id: 'cline-pass/deepseek-v4-pro',
|
|
@@ -32,6 +33,7 @@ export const CLINE_MODELS = Object.freeze([
|
|
|
32
33
|
category: 'coding',
|
|
33
34
|
recommended: true,
|
|
34
35
|
isCustom: false,
|
|
36
|
+
reasoningEfforts: ['low', 'medium', 'high', 'max'],
|
|
35
37
|
},
|
|
36
38
|
{
|
|
37
39
|
id: 'cline-pass/glm-5.2',
|
|
@@ -54,6 +56,7 @@ export const CLINE_MODELS = Object.freeze([
|
|
|
54
56
|
category: 'reasoning',
|
|
55
57
|
recommended: true,
|
|
56
58
|
isCustom: false,
|
|
59
|
+
reasoningEfforts: ['low', 'high', 'max'],
|
|
57
60
|
},
|
|
58
61
|
{
|
|
59
62
|
id: 'cline-pass/kimi-k2.7-code',
|
|
@@ -109,6 +112,7 @@ export const CLINE_MODELS = Object.freeze([
|
|
|
109
112
|
category: 'reasoning',
|
|
110
113
|
recommended: false,
|
|
111
114
|
isCustom: false,
|
|
115
|
+
reasoningEfforts: ['low', 'medium', 'high'],
|
|
112
116
|
},
|
|
113
117
|
{
|
|
114
118
|
id: 'cline-pass/mimo-v2.5',
|
|
@@ -218,3 +222,82 @@ export function getDefaultModelIds(dynamicModels = []) {
|
|
|
218
222
|
return getAllModels(dynamicModels).map((m) => m.id)
|
|
219
223
|
}
|
|
220
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Filter out models explicitly disabled by user.
|
|
227
|
+
* Any newly introduced model (not in disabledModelIds) is active by default.
|
|
228
|
+
*/
|
|
229
|
+
export function getActiveModelIds(allModels = [], disabledModelIds = []) {
|
|
230
|
+
const disabledSet = new Set(Array.isArray(disabledModelIds) ? disabledModelIds : [])
|
|
231
|
+
return (Array.isArray(allModels) ? allModels : [])
|
|
232
|
+
.map((m) => (typeof m === 'string' ? m : m?.id))
|
|
233
|
+
.filter((id) => Boolean(id && !disabledSet.has(id)))
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Format context length cleanly (e.g. 200000 -> '200K', 128000 -> '128K').
|
|
238
|
+
*/
|
|
239
|
+
export function formatModelContext(contextLength) {
|
|
240
|
+
const num = Number(contextLength) || 200000
|
|
241
|
+
if (num >= 1000000) return `${Math.round(num / 1000000)}M`
|
|
242
|
+
if (num >= 1000) return `${Math.round(num / 1000)}K`
|
|
243
|
+
return String(num)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Format model description with compact tags for DSH model picker.
|
|
248
|
+
*/
|
|
249
|
+
export function formatModelDescription(model) {
|
|
250
|
+
const parts = []
|
|
251
|
+
const ctx = formatModelContext(model.contextLength || model.contextWindow)
|
|
252
|
+
if (ctx) parts.push(ctx)
|
|
253
|
+
if (model.input?.includes('image') || model.input?.includes('vision')) {
|
|
254
|
+
parts.push('Vision')
|
|
255
|
+
}
|
|
256
|
+
if (model.category && model.category !== 'general') {
|
|
257
|
+
const cat = model.category.charAt(0).toUpperCase() + model.category.slice(1)
|
|
258
|
+
parts.push(cat)
|
|
259
|
+
}
|
|
260
|
+
const prefix = parts.length > 0 ? `[${parts.join(' · ')}] ` : ''
|
|
261
|
+
const baseDesc = model.description || model.name || model.id
|
|
262
|
+
return `${prefix}${baseDesc}`
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Check if a model supports vision input.
|
|
267
|
+
*/
|
|
268
|
+
export function isVisionModel(id, dynamicModels = []) {
|
|
269
|
+
const m = findModel(id, dynamicModels)
|
|
270
|
+
if (!m) return false
|
|
271
|
+
return Boolean(m.input?.includes('image') || m.input?.includes('vision'))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Disk caching for discovered models.
|
|
276
|
+
*/
|
|
277
|
+
export async function saveModelsDiskCache(cachePath, models = []) {
|
|
278
|
+
if (!cachePath || !Array.isArray(models) || !models.length) return false
|
|
279
|
+
try {
|
|
280
|
+
const fs = await import('node:fs/promises')
|
|
281
|
+
const path = await import('node:path')
|
|
282
|
+
const dir = path.dirname(cachePath)
|
|
283
|
+
await fs.mkdir(dir, { recursive: true })
|
|
284
|
+
const payload = JSON.stringify({ savedAt: Date.now(), models }, null, 2)
|
|
285
|
+
await fs.writeFile(cachePath, payload, 'utf8')
|
|
286
|
+
return true
|
|
287
|
+
} catch {
|
|
288
|
+
return false
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export async function loadModelsDiskCache(cachePath) {
|
|
293
|
+
if (!cachePath) return null
|
|
294
|
+
try {
|
|
295
|
+
const fs = await import('node:fs/promises')
|
|
296
|
+
const raw = await fs.readFile(cachePath, 'utf8')
|
|
297
|
+
const parsed = JSON.parse(raw)
|
|
298
|
+
return Array.isArray(parsed?.models) ? parsed.models : null
|
|
299
|
+
} catch {
|
|
300
|
+
return null
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
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",
|