@goodandready/dsh-clinebot 0.3.21 → 0.3.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 +14 -0
- package/README.md +2 -2
- package/README.ru.md +2 -2
- package/README.zh.md +2 -2
- package/lib/client.js +36 -35
- package/lib/http.js +31 -0
- package/lib/provider-sync.js +2 -1
- package/lib/routes/auth.js +1 -0
- package/lib/routes/models.js +3 -1
- package/lib/routes/settings.js +2 -0
- package/lib/slash-command.js +1 -1
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.23] - 2026-09-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **React Error #185 Infinite Loop Fix (#74 / GitHub #6)**: Restored stable reference constant `SNAPSHOT_READY` in `SettingsPage.getSnapshot` for `useSyncExternalStore`. Returning an inline object literal caused `Object.is` mismatch on every render, triggering an infinite update depth loop (`Maximum update depth exceeded`). The snapshot fallback now returns frozen `SNAPSHOT_READY`, guaranteeing reference stability while keeping the page unblocked in standalone mode.
|
|
12
|
+
- The settings page binds `configForms.get('dsh-clinebot')` on DSH 0.1.7. The removed `settingsScope` and `lanSettings` services are no longer consulted, so the plugin configuration page can render after install.
|
|
13
|
+
- `GET /dsh-clinebot/status`, `/config`, `/usage`, and `/auth/status` use the same trusted-request check as the write routes. Usage responses keep the quota fields the card shows and omit the raw provider payload.
|
|
14
|
+
- `/cline models` prints the model total in English.
|
|
15
|
+
|
|
16
|
+
## [0.3.22] - 2026-09-24
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **SettingsPage Crash on Cordis Strict Context (#67 / GitHub #4)**: Fixed unhandled `TypeError: cannot get property "settingsScope" without inject` thrown when accessing `ctx?.settingsScope` under DSH 0.17+ / Cordis v3+ strict proxy contexts. Replaced bare property access with defensive `ctx.get('lanSettings') || ctx.get('settingsScope')` inside `try/catch` across both `settings-page.js` and `entry.js`.
|
|
20
|
+
- **Standalone Unblocked UI Rendering**: When `settingsScope` / `lanSettings` service is absent or not injected in the client fiber, `SettingsPage` snapshot now defaults to `{ status: 'ready', view: null }` instead of permanently hanging on `status: 'loading'`. The settings page is entirely functional via its own HTTP REST endpoints (`/dsh-clinebot/status`, `/save-key`, `/models/toggle`, etc.).
|
|
21
|
+
|
|
8
22
|
## [0.3.21] - 2026-09-23
|
|
9
23
|
|
|
10
24
|
### Fixed
|
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ Integrating ClinePass into DeepSeek Harness (DSH) natively poses key challenges:
|
|
|
50
50
|
* 🚀 **One-Click In-App Updater**: Upgrade `@goodandready/dsh-clinebot` directly from the DSH UI or trigger secure loopback updates via `/dsh-clinebot/update`.
|
|
51
51
|
* ⚡ **SWR Quota & Health Caching**: Instantaneous response time (<2ms) on status queries with background revalidation.
|
|
52
52
|
* 🔀 **Smart Quota-Aware Failover**: Automatic multi-account rotation skipping exhausted accounts and recovering when `resetsAt` is reached.
|
|
53
|
-
* 🖥️ **
|
|
53
|
+
* 🖥️ **Plugin configuration page**: Open the installed ClineBot plugin and choose configure. The page shows the credential name, models, quota, and accounts. It is not a separate sidebar section.
|
|
54
54
|
* 🔄 **Dynamic Subscription Model Sync**: Automatically pulls real models included in your ClinePass plan directly from `GET /api/v1/users/me/plan` with one-click DSH provider sync.
|
|
55
55
|
* ⚠️ **Quota Exhaustion Alerts**: Real-time visual warning banners when 5-hour rolling limit reaches 80% (warning) and 95% (exhausted), complete with countdown to reset.
|
|
56
56
|
* 📈 **Session Metrics Telemetry**: Live dashboard tracking request counts, token consumption estimates, latency, and last-request timestamp.
|
|
@@ -118,7 +118,7 @@ graph LR
|
|
|
118
118
|
* **`lib/index.js`**:
|
|
119
119
|
Cordis service module managing routes (including `POST /dsh-clinebot/models/sync`), quota warnings threshold evaluation, credentials, and registering the `/cline` slash command.
|
|
120
120
|
* **`lib/client.js`**:
|
|
121
|
-
|
|
121
|
+
Configuration page on the plugin row (`plugins.row.config`) with live quota bars, an exhaustion warning, session metrics, one-click plan sync, and a fallback plugins card (`settings.plugin.item`). There is no `settings.section` sidebar entry.
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
package/README.ru.md
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* 🚀 **Обновление в один клик**: Обновление плагина прямо из интерфейса DSH или через защищённый loopback-эндпоинт `/dsh-clinebot/update`.
|
|
51
51
|
* ⚡ **SWR-кэширование квот и здоровья**: Мгновенный ответ (<2 мс) на запросы статуса с фоновым обновлением данных без блокировки UI.
|
|
52
52
|
* 🔀 **Smart Quota-Aware Failover**: Интеллектуальная ротация аккаунтов с обходом исчерпанных лимитов и авто-восстановлением при наступлении `resetsAt`.
|
|
53
|
-
* 🖥️
|
|
53
|
+
* 🖥️ **Страница конфигурации плагина**: откройте установленный ClineBot и перейдите в настройки плагина. Там имя учётных данных, модели, квота и аккаунты. Отдельного пункта бокового меню нет.
|
|
54
54
|
* 🔄 **Динамическая синхронизация моделей подписки**: автоматическое получение реального списка моделей из `GET /api/v1/users/me/plan` и мгновенное обновление провайдера DSH в один клик.
|
|
55
55
|
* ⚠️ **Предупреждения об исчерпании квоты**: баннеры предупреждения при достижении 80% (внимание) и 95% (исчерпано) 5-часового лимита с таймером сброса.
|
|
56
56
|
* 📈 **Метрики сессии**: учет количества запросов, расчетных токенов (Prompt / Completion), задержки и времени последнего вызова.
|
|
@@ -115,7 +115,7 @@ graph LR
|
|
|
115
115
|
* `smokeChat`: замер задержки и тестовый пинг с фиксацией статистики.
|
|
116
116
|
* `buildPiAiProvider`: генерация конфигурации провайдера для `llm-pi-ai` (`api: 'openai-completions'`).
|
|
117
117
|
* **`lib/index.js`**: сервис Cordis, регистрация системных маршрутов (включая `/dsh-clinebot/models/sync`), расчет порогов предупреждения квоты и слэш-команды `/cline`.
|
|
118
|
-
* **`lib/client.js`**:
|
|
118
|
+
* **`lib/client.js`**: страница конфигурации строки плагина (`plugins.row.config`) с предупреждениями, статистикой сессии, синхронизацией моделей и запасной карточкой (`settings.plugin.item`). Пункта `settings.section` в боковом меню нет.
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
package/README.zh.md
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* 🚀 **应用内一键更新**:直接在 DSH 界面检查并升级插件,或通过受保护的 `/dsh-clinebot/update` 进行本地安全更新。
|
|
51
51
|
* ⚡ **SWR 配额与健康状态缓存**:状态查询毫秒级响应(<2ms),并在后台静默更新,不阻塞前端渲染。
|
|
52
52
|
* 🔀 **智能配额故障转移 (Smart Failover)**:多账号池自动轮询,避开耗尽账号并在 `resetsAt` 到达后自动恢复。
|
|
53
|
-
* 🖥️
|
|
53
|
+
* 🖥️ **插件配置页**:打开已安装的 ClineBot,进入配置。页面包含凭据名、模型、配额和账号,不单独占用侧边栏。
|
|
54
54
|
* 🔄 **订阅模型动态同步**:从官方 `GET /api/v1/users/me/plan` 自动提取真实包含模型,一键原子级同步至 DSH 提供商配置,无需等待插件更新。
|
|
55
55
|
* ⚠️ **额度耗尽实时预警**:当 5 小时滑动窗口达到 80%(警告黄色)和 95%(即将耗尽红色)时展示醒目预警横幅与重置倒计时。
|
|
56
56
|
* 📈 **会话统计与指标看板**:实时追踪请求调用次数、预估 Token(Prompt / Completion)、最近延迟及最后调用时间。
|
|
@@ -115,7 +115,7 @@ graph LR
|
|
|
115
115
|
* `smokeChat`:毫秒级网络探活与非流式延迟测试,并记录会话指标。
|
|
116
116
|
* `buildPiAiProvider`:构建 DSH `llm-pi-ai` 兼容的服务商定义 (`api: 'openai-completions'`)。
|
|
117
117
|
* **`lib/index.js`**:Cordis 插件主生命周期服务,注册后端 REST API 路由(含 `/dsh-clinebot/models/sync`)、额度预警计算与 `/cline` 聊天斜杠指令。
|
|
118
|
-
* **`lib/client.js
|
|
118
|
+
* **`lib/client.js`**:插件行配置页(`plugins.row.config`),含预警横幅、会话指标、一键模型同步,以及后备插件卡片(`settings.plugin.item`)。没有 `settings.section` 侧边栏项。
|
|
119
119
|
|
|
120
120
|
---
|
|
121
121
|
|
package/lib/client.js
CHANGED
|
@@ -14,7 +14,11 @@ const NS = 'dsh-clinebot'
|
|
|
14
14
|
const ROW_ID = 'dsh-clinebot'
|
|
15
15
|
const ROW_CONFIG_KEY = '@goodandready/dsh-clinebot#' + ROW_ID
|
|
16
16
|
const ROUTE_PREFIX = '/dsh-clinebot'
|
|
17
|
-
const SNAPSHOT_LOADING = { status: 'loading', view: null }
|
|
17
|
+
const SNAPSHOT_LOADING = Object.freeze({ status: 'loading', view: null })
|
|
18
|
+
// Stable (frozen) fallback reference: useSyncExternalStore compares snapshots by
|
|
19
|
+
// identity (Object.is), so returning a fresh object literal causes an infinite render loop
|
|
20
|
+
// (React error #185 "Maximum update depth exceeded"). Keep this module-level.
|
|
21
|
+
const SNAPSHOT_READY = Object.freeze({ status: 'ready', view: null })
|
|
18
22
|
|
|
19
23
|
// --- src/client/locales.js ---
|
|
20
24
|
const en = {
|
|
@@ -834,16 +838,27 @@ Response: ${smokeResult.preview || '(empty)'}`
|
|
|
834
838
|
}
|
|
835
839
|
|
|
836
840
|
// --- src/client/settings-page.js ---
|
|
841
|
+
function readConfigForms(ctx) {
|
|
842
|
+
if (!ctx || typeof ctx.get !== 'function') return undefined
|
|
843
|
+
try {
|
|
844
|
+
return ctx.get('configForms') || undefined
|
|
845
|
+
} catch (err) {
|
|
846
|
+
console.warn('[dsh-clinebot] configForms is not available:', err)
|
|
847
|
+
return undefined
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
837
851
|
function SettingsPage(props) {
|
|
838
852
|
const ctx = props?.ctx
|
|
839
853
|
const t = props?.t || makeT(en, en)
|
|
840
854
|
|
|
841
855
|
const scope = React.useMemo(() => {
|
|
842
|
-
const
|
|
843
|
-
if (!
|
|
856
|
+
const svc = readConfigForms(ctx)
|
|
857
|
+
if (!svc || typeof svc.get !== 'function') return undefined
|
|
844
858
|
try {
|
|
845
|
-
return
|
|
846
|
-
} catch (
|
|
859
|
+
return svc.get(NS)
|
|
860
|
+
} catch (err) {
|
|
861
|
+
console.warn('[dsh-clinebot] configForms.get failed:', err)
|
|
847
862
|
return undefined
|
|
848
863
|
}
|
|
849
864
|
}, [ctx])
|
|
@@ -860,18 +875,19 @@ function SettingsPage(props) {
|
|
|
860
875
|
}, [scope])
|
|
861
876
|
|
|
862
877
|
const getSnapshot = React.useCallback(() => {
|
|
863
|
-
if (!scope?.getSnapshot) return
|
|
878
|
+
if (!scope?.getSnapshot) return SNAPSHOT_READY
|
|
864
879
|
try {
|
|
865
|
-
return scope.getSnapshot() ||
|
|
866
|
-
} catch (
|
|
867
|
-
|
|
880
|
+
return scope.getSnapshot() || SNAPSHOT_READY
|
|
881
|
+
} catch (err) {
|
|
882
|
+
console.warn('[dsh-clinebot] settings snapshot failed:', err)
|
|
883
|
+
return SNAPSHOT_READY
|
|
868
884
|
}
|
|
869
885
|
}, [scope])
|
|
870
886
|
|
|
871
887
|
const snapshot = React.useSyncExternalStore(
|
|
872
888
|
subscribe,
|
|
873
889
|
getSnapshot,
|
|
874
|
-
React.useCallback(() =>
|
|
890
|
+
React.useCallback(() => SNAPSHOT_READY, [])
|
|
875
891
|
)
|
|
876
892
|
const snapshotStatus = snapshot?.status || 'loading'
|
|
877
893
|
|
|
@@ -1368,29 +1384,14 @@ function PluginCard(props) {
|
|
|
1368
1384
|
}
|
|
1369
1385
|
|
|
1370
1386
|
// --- src/client/entry.js ---
|
|
1371
|
-
function
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
return false
|
|
1379
|
-
}
|
|
1387
|
+
function ensureSettingsForm(ctx) {
|
|
1388
|
+
const svc = readConfigForms(ctx)
|
|
1389
|
+
if (!svc || typeof svc.get !== 'function') return
|
|
1390
|
+
try {
|
|
1391
|
+
svc.get(NS)
|
|
1392
|
+
} catch (err) {
|
|
1393
|
+
console.warn('[dsh-clinebot] configForms.get failed:', err)
|
|
1380
1394
|
}
|
|
1381
|
-
if (visible()) return () => {}
|
|
1382
|
-
let tries = 0
|
|
1383
|
-
const timer = setInterval(() => {
|
|
1384
|
-
if (visible() || tries >= 15) { clearInterval(timer); return }
|
|
1385
|
-
tries += 1
|
|
1386
|
-
try {
|
|
1387
|
-
const s = (ctx?.get && ctx.get('lanSettings')) || ctx?.settingsScope
|
|
1388
|
-
s?.describe?.()?.load?.()
|
|
1389
|
-
} catch (e) {
|
|
1390
|
-
console.debug?.('[dsh-clinebot] Polling settings mirror:', e)
|
|
1391
|
-
}
|
|
1392
|
-
}, 1000)
|
|
1393
|
-
return () => clearInterval(timer)
|
|
1394
1395
|
}
|
|
1395
1396
|
|
|
1396
1397
|
function apply(ctx) {
|
|
@@ -1415,8 +1416,8 @@ function apply(ctx) {
|
|
|
1415
1416
|
|
|
1416
1417
|
if (typeof ctx.effect === 'function') {
|
|
1417
1418
|
ctx.effect(
|
|
1418
|
-
() =>
|
|
1419
|
-
'dsh-clinebot:
|
|
1419
|
+
() => { ensureSettingsForm(ctx) },
|
|
1420
|
+
'dsh-clinebot: open the settings form for this namespace',
|
|
1420
1421
|
)
|
|
1421
1422
|
}
|
|
1422
1423
|
|
|
@@ -1494,7 +1495,7 @@ function apply(ctx) {
|
|
|
1494
1495
|
)
|
|
1495
1496
|
}
|
|
1496
1497
|
|
|
1497
|
-
module.exports = { apply, inject: ['slots', 'locale'] }
|
|
1498
|
+
module.exports = { apply, inject: ['slots', 'locale', 'configForms'] }
|
|
1498
1499
|
|
|
1499
1500
|
return module.exports
|
|
1500
1501
|
},
|
package/lib/http.js
CHANGED
|
@@ -92,3 +92,34 @@ export function isTrustedSettingsRequest(request) {
|
|
|
92
92
|
|
|
93
93
|
return false
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
export function publicUsage(usage) {
|
|
97
|
+
if (!usage || typeof usage !== 'object') return null
|
|
98
|
+
const windowView = (window) => {
|
|
99
|
+
if (!window || typeof window !== 'object') return null
|
|
100
|
+
return {
|
|
101
|
+
percentUsed: window.percentUsed,
|
|
102
|
+
remainingPercent: window.remainingPercent,
|
|
103
|
+
resetsAt: window.resetsAt || null,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (usage.ok === false) {
|
|
107
|
+
return {
|
|
108
|
+
ok: false,
|
|
109
|
+
error: typeof usage.error === 'string' ? usage.error : 'usage unavailable',
|
|
110
|
+
checkedAt: usage.checkedAt,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
plan: usage.plan || null,
|
|
116
|
+
user: { email: usage.user?.email || null },
|
|
117
|
+
windows: {
|
|
118
|
+
fiveHour: windowView(usage.windows?.fiveHour),
|
|
119
|
+
weekly: windowView(usage.windows?.weekly),
|
|
120
|
+
monthly: windowView(usage.windows?.monthly),
|
|
121
|
+
},
|
|
122
|
+
checkedAt: usage.checkedAt,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
package/lib/provider-sync.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os from 'node:os'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { publicConfig, Config, LLM_PI_AI_NS } from './config.js'
|
|
4
|
+
import { publicUsage } from './http.js'
|
|
4
5
|
import {
|
|
5
6
|
PROVIDER_ID,
|
|
6
7
|
PROVIDER_DISPLAY_NAME,
|
|
@@ -109,7 +110,7 @@ export async function buildStatus(ctx, cfg) {
|
|
|
109
110
|
})),
|
|
110
111
|
activeAccount: activeAcc.apiKeyEnv,
|
|
111
112
|
health,
|
|
112
|
-
usage,
|
|
113
|
+
usage: publicUsage(usage),
|
|
113
114
|
quotaWarning,
|
|
114
115
|
sessionStats: { ...sessionStats },
|
|
115
116
|
isRegistered,
|
package/lib/routes/auth.js
CHANGED
|
@@ -38,6 +38,7 @@ export function registerAuthRoutes(ctx, { live, getSettingsApi, syncProviderStat
|
|
|
38
38
|
path: '/dsh-clinebot/auth/status',
|
|
39
39
|
handler: async (req, res) => {
|
|
40
40
|
if (req.method !== 'GET') return writeJson(res, 405, { ok: false, error: 'GET only' })
|
|
41
|
+
if (!assertTrustedSettingsRequest(req, res)) return
|
|
41
42
|
writeJson(res, 200, {
|
|
42
43
|
ok: true,
|
|
43
44
|
status: authSession?.state || 'idle',
|
package/lib/routes/models.js
CHANGED
|
@@ -4,6 +4,7 @@ import { publicConfig, Config } from '../config.js'
|
|
|
4
4
|
import { resolveActiveAccountKey, resolvePathWithHome } from '../provider-sync.js'
|
|
5
5
|
import { getAllModels, saveModelsDiskCache } from '../models.js'
|
|
6
6
|
import { fetchUsageLimits } from '../cline-client.js'
|
|
7
|
+
import { publicUsage } from '../http.js'
|
|
7
8
|
|
|
8
9
|
export function registerModelsRoutes(ctx, { live, getSettingsApi, syncProviderState }) {
|
|
9
10
|
// POST /dsh-clinebot/models/sync — dynamically load models from plan
|
|
@@ -103,6 +104,7 @@ export function registerModelsRoutes(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
103
104
|
path: '/dsh-clinebot/usage',
|
|
104
105
|
handler: async (req, res) => {
|
|
105
106
|
if (req.method !== 'GET') return writeJson(res, 405, { ok: false, error: 'GET only' })
|
|
107
|
+
if (!assertTrustedSettingsRequest(req, res)) return
|
|
106
108
|
try {
|
|
107
109
|
const pub = publicConfig(live())
|
|
108
110
|
const activeKey = await resolveActiveAccountKey(ctx, live())
|
|
@@ -113,7 +115,7 @@ export function registerModelsRoutes(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
113
115
|
timeoutMs: pub.timeoutMs,
|
|
114
116
|
bypassCache: true,
|
|
115
117
|
})
|
|
116
|
-
writeJson(res, usageData.ok ? 200 : 502, usageData)
|
|
118
|
+
writeJson(res, usageData.ok ? 200 : 502, publicUsage(usageData))
|
|
117
119
|
} catch (err) {
|
|
118
120
|
writeJson(res, 500, { ok: false, error: String(err?.message || err) })
|
|
119
121
|
}
|
package/lib/routes/settings.js
CHANGED
|
@@ -11,6 +11,7 @@ export function registerSettingsRoutes(ctx, { live, getSettingsApi, syncProvider
|
|
|
11
11
|
path: '/dsh-clinebot/status',
|
|
12
12
|
handler: async (req, res) => {
|
|
13
13
|
if (req.method !== 'GET') return writeJson(res, 405, { ok: false, error: 'GET only' })
|
|
14
|
+
if (!assertTrustedSettingsRequest(req, res)) return
|
|
14
15
|
try {
|
|
15
16
|
const st = await buildStatus(ctx, live())
|
|
16
17
|
writeJson(res, 200, st)
|
|
@@ -26,6 +27,7 @@ export function registerSettingsRoutes(ctx, { live, getSettingsApi, syncProvider
|
|
|
26
27
|
path: '/dsh-clinebot/config',
|
|
27
28
|
handler: async (req, res) => {
|
|
28
29
|
if (req.method === 'GET') {
|
|
30
|
+
if (!assertTrustedSettingsRequest(req, res)) return
|
|
29
31
|
return writeJson(res, 200, { ok: true, config: publicConfig(live()) })
|
|
30
32
|
}
|
|
31
33
|
if (req.method !== 'PUT') {
|
package/lib/slash-command.js
CHANGED
|
@@ -39,7 +39,7 @@ export function registerSlashCommand(ctx, { live, getSettingsApi, syncProviderSt
|
|
|
39
39
|
const disabledSet = new Set(pub.disabledModels || [])
|
|
40
40
|
const lines = [
|
|
41
41
|
'### 🎯 ClinePass Models Catalog',
|
|
42
|
-
`*
|
|
42
|
+
`* **Total models**: ${allModels.length} (${allModels.filter((m) => !disabledSet.has(m.id)).length} active)`,
|
|
43
43
|
'',
|
|
44
44
|
]
|
|
45
45
|
for (const m of allModels) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-clinebot",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -49,7 +49,11 @@
|
|
|
49
49
|
},
|
|
50
50
|
"client": {
|
|
51
51
|
"platform": "web",
|
|
52
|
-
"inject": [
|
|
52
|
+
"inject": [
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
54
|
+
"@deepseek-ai/dsh-client-locale",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
56
|
+
]
|
|
53
57
|
}
|
|
54
58
|
},
|
|
55
59
|
"peerDependencies": {
|