@goodandready/dsh-clinebot 0.6.4 → 0.6.6
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 +16 -0
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh.md +1 -1
- package/lib/access.js +1 -1
- package/lib/account-pool.js +1 -14
- package/lib/adapter.js +0 -2
- package/lib/client.js +36 -5167
- package/lib/cline-client.js +1 -4
- package/lib/credential-refs.js +1 -1
- package/lib/http.js +1 -1
- package/lib/model-prices.js +1 -1
- package/lib/models.js +1 -1
- package/lib/provider-sync.js +1 -1
- package/lib/slash-command.js +30 -5
- package/lib/stats-storage.js +2 -2
- package/lib/transport/cline-transport.js +5 -5
- package/package.json +2 -1
package/lib/cline-client.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
2
|
export {
|
|
3
|
-
toCredentialRef,
|
|
4
3
|
resolveApiKey,
|
|
5
4
|
saveCredentialKey,
|
|
6
5
|
deleteCredentialKey,
|
|
@@ -16,8 +15,6 @@ export {
|
|
|
16
15
|
|
|
17
16
|
import {
|
|
18
17
|
DEFAULT_MODEL_ID,
|
|
19
|
-
PROVIDER_ID,
|
|
20
|
-
PROVIDER_DISPLAY_NAME,
|
|
21
18
|
parsePlanIncludedModels,
|
|
22
19
|
} from './models.js'
|
|
23
20
|
|
|
@@ -28,7 +25,7 @@ export const DEFAULT_SMOKE_TIMEOUT_MS = 25000
|
|
|
28
25
|
export const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 30000
|
|
29
26
|
const USAGE_CACHE_TTL_MS = 60000
|
|
30
27
|
|
|
31
|
-
export {
|
|
28
|
+
export { DEFAULT_MODEL_ID }
|
|
32
29
|
|
|
33
30
|
// Credentials helpers extracted to ./credential-refs.js
|
|
34
31
|
|
package/lib/credential-refs.js
CHANGED
package/lib/http.js
CHANGED
|
@@ -46,7 +46,7 @@ function header(request, name) {
|
|
|
46
46
|
return Array.isArray(value) ? value[0] : value
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
function isLoopbackAddress(value) {
|
|
50
50
|
const address = String(value || '').toLowerCase().replace(/^\[|\]$/g, '')
|
|
51
51
|
return address === 'localhost' || address === 'localhost.' || address === '::1'
|
|
52
52
|
|| address.startsWith('127.')
|
package/lib/model-prices.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* no known or overridden rate stays `unpriced` rather than being shown as $0.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const PRICE_TABLE_VERSION = 1
|
|
11
11
|
|
|
12
12
|
const OPEN_WEIGHT = Object.freeze({ input: 0.15, output: 0.6, cacheRead: 0.003, cacheWrite: null })
|
|
13
13
|
const CLAUDE = Object.freeze({ input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 })
|
package/lib/models.js
CHANGED
|
@@ -72,7 +72,7 @@ export function getOriginalModelMaxTokens(nameOrId) {
|
|
|
72
72
|
return 16384
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
function getOriginalModelProvider(nameOrId) {
|
|
76
76
|
const norm = String(nameOrId || '').toLowerCase()
|
|
77
77
|
if (norm.includes('kimi')) return 'Moonshot AI'
|
|
78
78
|
if (norm.includes('qwen')) return 'Alibaba Cloud'
|
package/lib/provider-sync.js
CHANGED
package/lib/slash-command.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { publicConfig, plainConfig, Config } from './config.js'
|
|
2
2
|
import { resolveActiveAccountKey, formatProgressBar } from './provider-sync.js'
|
|
3
|
+
import { getBudgetSpend } from './stats-storage.js'
|
|
4
|
+
import { budgetStatus, budgetErrorMessage } from './budget.js'
|
|
3
5
|
import { resolveAccountPool, rotateToNextAccount, getLastRotation } from './account-pool.js'
|
|
4
6
|
import {
|
|
5
7
|
getAllModels,
|
|
@@ -148,7 +150,27 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
148
150
|
return `Cline API Ping Failed: ${health.error || 'Host unreachable'}`
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
// 6. Subcommand /cline
|
|
153
|
+
// 6. Subcommand /cline cost or /cline budget
|
|
154
|
+
if (subcmd === 'cost' || subcmd === 'budget') {
|
|
155
|
+
const spend = getBudgetSpend()
|
|
156
|
+
const daily = budgetStatus({ dailyBudgetUsd: pub.dailyBudgetUsd }, spend)
|
|
157
|
+
const monthly = budgetStatus({ monthlyBudgetUsd: pub.monthlyBudgetUsd }, spend)
|
|
158
|
+
const money = (value) => `$${Number(value || 0).toFixed(4)}`
|
|
159
|
+
const limit = (value) => Number(value) > 0 ? money(value) : 'off'
|
|
160
|
+
const lines = [
|
|
161
|
+
`ClineBot Estimated Spend · today ${money(spend.dayCost)} · month ${money(spend.monthCost)}`,
|
|
162
|
+
'',
|
|
163
|
+
`Today: ${money(spend.dayCost)} / ${limit(pub.dailyBudgetUsd)}`,
|
|
164
|
+
`Month: ${money(spend.monthCost)} / ${limit(pub.monthlyBudgetUsd)}`,
|
|
165
|
+
`Daily guard: ${daily.blocked ? `BLOCKED — ${budgetErrorMessage(daily)}` : 'ok'}`,
|
|
166
|
+
`Monthly guard: ${monthly.blocked ? `BLOCKED — ${budgetErrorMessage(monthly)}` : 'ok'}`,
|
|
167
|
+
'',
|
|
168
|
+
'Set limits in Settings -> ClineBot -> Advanced.',
|
|
169
|
+
]
|
|
170
|
+
return lines.join('\n')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 7. Subcommand /cline stats (real DSH stream metrics)
|
|
152
174
|
if (subcmd === 'stats' || subcmd === 'telemetry') {
|
|
153
175
|
const summary = `ClineBot Telemetry · ${sessionStats.successfulRequests}/${sessionStats.totalRequests} reqs · ~${sessionStats.totalTokensEst} tokens`
|
|
154
176
|
const lines = [
|
|
@@ -177,7 +199,7 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
177
199
|
return lines.join('\n')
|
|
178
200
|
}
|
|
179
201
|
|
|
180
|
-
//
|
|
202
|
+
// 8. Subcommand /cline test [model] / smoke
|
|
181
203
|
if (subcmd === 'test' || subcmd === 'smoke') {
|
|
182
204
|
if (param && !isSupportedModel(param, pub.dynamicModels, pub.modelContextOverrides, pub.customModels)) {
|
|
183
205
|
return `ClineBot: Model "${param}" is not recognized. Use /cline models to see available models.`
|
|
@@ -221,7 +243,7 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
221
243
|
return `Smoke Test Failed: ${outcome.error} (HTTP ${outcome.status || 'timeout'})${failoverNotice}`
|
|
222
244
|
}
|
|
223
245
|
|
|
224
|
-
//
|
|
246
|
+
// 9. Subcommand /cline quota, /cline usage or /cline balance
|
|
225
247
|
const activeKey = await resolveActiveAccountKey(ctx, live())
|
|
226
248
|
if (!activeKey.value) {
|
|
227
249
|
return 'ClineBot: API key is not configured. Open Settings -> Plugins -> ClineBot.'
|
|
@@ -234,9 +256,11 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
234
256
|
|
|
235
257
|
const fiveHour = usage?.windows?.fiveHour
|
|
236
258
|
const weekly = usage?.windows?.weekly
|
|
259
|
+
const monthly = usage?.windows?.monthly
|
|
237
260
|
const reset5h = fiveHour?.resetsAt ? new Date(fiveHour.resetsAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : 'N/A'
|
|
238
261
|
const resetWk = weekly?.resetsAt ? new Date(weekly.resetsAt).toLocaleDateString([], { day: '2-digit', month: '2-digit' }) : 'N/A'
|
|
239
262
|
const resetWkFull = weekly?.resetsAt ? new Date(weekly.resetsAt).toLocaleDateString([], { day: '2-digit', month: '2-digit', year: 'numeric' }) : 'N/A'
|
|
263
|
+
const resetMo = monthly?.resetsAt ? new Date(monthly.resetsAt).toLocaleDateString([], { day: '2-digit', month: '2-digit', year: 'numeric' }) : 'N/A'
|
|
240
264
|
|
|
241
265
|
const planRaw = usage?.plan || 'ClinePass'
|
|
242
266
|
const planShort = planRaw.replace(/\s*\(\$\d+\.\d+\/mo\)/i, '').trim()
|
|
@@ -268,6 +292,7 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
268
292
|
'',
|
|
269
293
|
`${pad('5-Hour Quota')}${formatProgressBar(fiveHour?.percentUsed)} (resets: ${reset5h})`,
|
|
270
294
|
`${pad('Weekly Quota')}${formatProgressBar(weekly?.percentUsed)} (resets: ${resetWkFull})`,
|
|
295
|
+
`${pad('Monthly Quota')}${formatProgressBar(monthly?.percentUsed)} (resets: ${resetMo})`,
|
|
271
296
|
)
|
|
272
297
|
|
|
273
298
|
if (fiveHour?.percentUsed >= 95) {
|
|
@@ -315,8 +340,8 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
315
340
|
const unregister = commands.register({
|
|
316
341
|
definitionId: '@goodandready/dsh-clinebot',
|
|
317
342
|
name: 'cline',
|
|
318
|
-
description: 'Check ClinePass
|
|
319
|
-
input: { hint: '[quota|models|accounts|switch <name>|test [model]|ping|rotate]' },
|
|
343
|
+
description: 'Check ClinePass quota, cost, models, accounts and connectivity (/cline [quota|usage|cost|models|accounts|switch <name>|test [model]|ping|rotate])',
|
|
344
|
+
input: { hint: '[quota|usage|cost|models|accounts|switch <name>|test [model]|ping|rotate]' },
|
|
320
345
|
handler: commandHandler,
|
|
321
346
|
execute: commandExecute,
|
|
322
347
|
})
|
package/lib/stats-storage.js
CHANGED
|
@@ -84,7 +84,7 @@ function localDateKey(date) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/** Get active .dsh directory, respecting DSH_HOME and HOME. */
|
|
87
|
-
|
|
87
|
+
function getDshHome() {
|
|
88
88
|
if (process.env.DSH_HOME) return process.env.DSH_HOME
|
|
89
89
|
const home = process.env.HOME || homedir()
|
|
90
90
|
return path.join(home, '.dsh')
|
|
@@ -412,7 +412,7 @@ export function resetStats(customPath) {
|
|
|
412
412
|
* @param {number} [days]
|
|
413
413
|
* @param {number} [to]
|
|
414
414
|
*/
|
|
415
|
-
|
|
415
|
+
function getHeatmap(days = 7, to = Date.now(), model = '') {
|
|
416
416
|
const count = Math.max(1, Math.min(95, Number(days) || 7))
|
|
417
417
|
const end = new Date(Number.isFinite(Number(to)) ? Number(to) : Date.now())
|
|
418
418
|
const start = new Date(end.getFullYear(), end.getMonth(), end.getDate() - (count - 1))
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
import { createRequire } from 'node:module'
|
|
10
10
|
|
|
11
11
|
const require = createRequire(import.meta.url)
|
|
12
|
-
let packageVersion = '0.6.
|
|
12
|
+
let packageVersion = '0.6.6'
|
|
13
13
|
try {
|
|
14
14
|
packageVersion = require('../../package.json').version || packageVersion
|
|
15
15
|
} catch {
|
|
16
16
|
/* fallback when package.json is unavailable */
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
const USER_AGENT = `@goodandready/dsh-clinebot/${packageVersion}`
|
|
20
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 15000
|
|
21
|
+
const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 30000
|
|
22
|
+
const DEFAULT_MAX_BODY_BYTES = 10 * 1024 * 1024
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Build the abort-shaped error every transport caller understands.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
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",
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
"@deepseek-ai/dsh-llm": "0.2.1-rc.2",
|
|
101
101
|
"@deepseek-ai/schemastery": "~3.18.5",
|
|
102
102
|
"@types/node": "^24.0.0",
|
|
103
|
+
"esbuild": "^0.28.2",
|
|
103
104
|
"eslint": "^9.39.5",
|
|
104
105
|
"typescript": "^6.0.3"
|
|
105
106
|
},
|