@goodandready/dsh-subscriptions 0.6.66 → 0.6.67
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/README.md +4 -0
- package/README.ru.md +4 -0
- package/README.zh.md +4 -0
- package/lib/adapter.js +1 -0
- package/lib/vendors/claude.js +56 -11
- package/lib/vendors/copilot-cli.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,6 +207,10 @@ const res = await ctx.subscriptions.request('codex', '/backend-api/codex/images/
|
|
|
207
207
|
* **In-App Toast Alerts (`enableToasts`)**: Lightweight floating toast alerts in the DSH chat interface notifying you when accounts enter quarantine, recover from cooldowns, or exceed quota safety thresholds.
|
|
208
208
|
* **Automated Webhook Integration**: Instant event notifications dispatched via `notifyQuarantineEntered` and `notifyQuarantineReleased`.
|
|
209
209
|
|
|
210
|
+
### 21. 🛡️ Per-Account Claude Billing Attribution Isolation (v0.6.67)
|
|
211
|
+
* **Per-Account `cc_turn_index` & `cch` Isolation (#530)**: Isolates Claude Code billing attribution state (`cch` session hash and `cc_turn_index` counter) per subscription account (`accountId`) in a bounded module Map instead of `globalThis`, preventing cross-account telemetry mixing in multi-account pools.
|
|
212
|
+
* **Dynamic `cc_prompt_index` & Kill-Switch**: Automatically derives 0-based `cc_prompt_index` from multi-turn `messages` history and supports suppression via `CLAUDE_CODE_ATTRIBUTION_HEADER=0` or `disableBillingHeader: true`.
|
|
213
|
+
|
|
210
214
|
### 20. 🤖 Native Copilot CLI SDK Mode & Local Tool Calling (v0.6.66)
|
|
211
215
|
* **Direct Copilot CLI Integration (#508)**: Native driver `copilot-cli.js` supporting execution via local `copilot` / `github-copilot-cli` binaries with zero network token emulation risk.
|
|
212
216
|
* **Smart Mode Switching (`copilotMode`)**: Choose between `auto` (prefers local CLI with graceful web API fallback), `cli` (strict CLI SDK execution), and `web` (direct OAuth/API).
|
package/README.ru.md
CHANGED
|
@@ -183,6 +183,10 @@ const res = await ctx.subscriptions.request('codex', '/backend-api/codex/images/
|
|
|
183
183
|
* **Всплывающие уведомления (Toast Alerts)**: Легковесные всплывающие тосты в веб-интерфейсе DSH при событиях карантина (с отображением причины), восстановлении доступа и критическом расходе квоты. Включение управляется параметром `enableToasts` (по умолчанию `true`).
|
|
184
184
|
* **Интеграция с вебхуками**: Автоматическая отправка уведомлений через `notifyQuarantineEntered` и `notifyQuarantineReleased`.
|
|
185
185
|
|
|
186
|
+
### 17. 🛡️ Поаккаунтная изоляция атрибуции биллинга Claude (v0.6.67)
|
|
187
|
+
* **Изоляция `cc_turn_index` и `cch` по `accountId` (#530)**: Состояние атрибуции Claude Code (`cch` и счётчик `cc_turn_index`) изолировано по каждому аккаунту в ограниченной таблице модуля вместо `globalThis`, что исключает смешивание телеметрии между подписками в пуле.
|
|
188
|
+
* **Динамический `cc_prompt_index` и Kill-Switch**: Индекс `cc_prompt_index` автоматически вычисляется по числу пользовательских ходов в `messages`, а отключение заголовка поддерживается через `CLAUDE_CODE_ATTRIBUTION_HEADER=0` или `disableBillingHeader: true`.
|
|
189
|
+
|
|
186
190
|
### 16. 🤖 Нативный режим Copilot CLI SDK и локальный Tool Calling (v0.6.66)
|
|
187
191
|
* **Прямая интеграция с Copilot CLI (#508)**: Драйвер `copilot-cli.js` для работы через локальный бинарник `copilot` / `github-copilot-cli` без риска сетевых блокировок при эмуляции токенов.
|
|
188
192
|
* **Гибкие режимы работы (`copilotMode`)**: Поддержка режимов `auto` (приоритет CLI с автоматическим fallback на web-API), `cli` (строгий режим CLI SDK) и `web` (прямое подключение по OAuth/API).
|
package/README.zh.md
CHANGED
|
@@ -132,6 +132,10 @@ graph LR
|
|
|
132
132
|
queueTimeoutMs: 30000 # v0.6.62: 队列最大等待超时时间(毫秒)
|
|
133
133
|
* **自动化 Webhook 告警集成**:通过 `notifyQuarantineEntered` 与 `notifyQuarantineReleased` 自动向外部通知系统派发隔离生命周期事件。
|
|
134
134
|
|
|
135
|
+
### Claude 账户级计费归因隔离与动态轮次索引 (v0.6.67)
|
|
136
|
+
* **按账户隔离 `cc_turn_index` 与 `cch` (#530)**:将 Claude Code 计费归因状态(会话哈希 `cch` 与递增轮次 `cc_turn_index`)按 `accountId` 隔离在有界模块级映射表中,彻底消除 `globalThis` 跨订阅账户状态混用问题。
|
|
137
|
+
* **动态计算 `cc_prompt_index` 与禁用开关**:根据多轮对话消息历史自动计算从 0 开始的 `cc_prompt_index`,并支持通过环境变量 `CLAUDE_CODE_ATTRIBUTION_HEADER=0` 或 `disableBillingHeader: true` 禁用归因头注入。
|
|
138
|
+
|
|
135
139
|
### Antigravity 客户端密钥架构与无感 CLI 令牌刷新 (v0.6.60)
|
|
136
140
|
* **配置架构密钥字段 (`antigravityClientSecret`)**:支持用户在设置中自定义配置 Google Cloud OAuth 客户端密钥(Client Secret),公共接口自动脱敏掩码 (`••••••`),彻底解决机密型 OAuth 客户端刷新令牌被拒的问题。
|
|
137
141
|
* **CLI 令牌零配置平滑刷新**:内置官方 Gemini / Antigravity CLI 客户端的公共应用凭据 (`Google Gemini CLI Client ID` / `Google Gemini CLI Client Secret`),使通过 `📥 从 CLI 导入` 的会话能够持久无限刷新,不再出现 1 小时后失效问题。
|
package/lib/adapter.js
CHANGED
|
@@ -329,6 +329,7 @@ export class SubscriptionAdapter extends LlmAdapter {
|
|
|
329
329
|
if (typeof deps.rememberRequest === 'function') deps.rememberRequest(account.ref)
|
|
330
330
|
for await (const chunk of vendor.streamOnce({
|
|
331
331
|
blob,
|
|
332
|
+
accountId: account.id || account.ref,
|
|
332
333
|
options: opts,
|
|
333
334
|
fetchImpl: quotaFetch,
|
|
334
335
|
headers: attributionHeaders(),
|
package/lib/vendors/claude.js
CHANGED
|
@@ -222,20 +222,65 @@ export async function usage(blob, _cfg, fetchImpl) {
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
const billingAccountState = new Map()
|
|
226
|
+
const MAX_BILLING_ACCOUNTS = 256
|
|
227
|
+
|
|
228
|
+
function resolveAccountKey(cfg, context) {
|
|
229
|
+
const explicit = (context && context.accountId) || (cfg && cfg.accountId)
|
|
230
|
+
if (typeof explicit === 'string' && explicit.trim()) return explicit.trim()
|
|
231
|
+
const blob = (context && context.blob) || (cfg && cfg.blob)
|
|
232
|
+
if (blob && typeof blob === 'object') {
|
|
233
|
+
const id = blob.accountId || blob.id || blob.email
|
|
234
|
+
if (typeof id === 'string' && id.trim()) return id.trim()
|
|
235
|
+
if (typeof blob.accessToken === 'string' && blob.accessToken.length >= 8) {
|
|
236
|
+
return `token:${blob.accessToken.slice(-12)}`
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return 'default'
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function resolvePromptIndex(cfg, context) {
|
|
243
|
+
const explicit = (context && context.promptIndex !== undefined)
|
|
244
|
+
? context.promptIndex
|
|
245
|
+
: (cfg && cfg.promptIndex !== undefined ? cfg.promptIndex : undefined)
|
|
246
|
+
if (typeof explicit === 'number' && Number.isFinite(explicit) && explicit >= 0) {
|
|
247
|
+
return Math.floor(explicit)
|
|
248
|
+
}
|
|
249
|
+
const messages = (context && context.options && Array.isArray(context.options.messages))
|
|
250
|
+
? context.options.messages
|
|
251
|
+
: (context && Array.isArray(context.messages) ? context.messages : null)
|
|
252
|
+
if (messages) {
|
|
253
|
+
const userTurns = messages.filter((m) => m && m.role === 'user').length
|
|
254
|
+
return Math.max(0, userTurns - 1)
|
|
255
|
+
}
|
|
256
|
+
return 0
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function makeClaudeBillingHeader(cfg, context) {
|
|
226
260
|
const ccVersion = (cfg && cfg.claudeCcVersion) || '2.1.289.7e2'
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
261
|
+
const accountKey = resolveAccountKey(cfg, context)
|
|
262
|
+
let state = billingAccountState.get(accountKey)
|
|
263
|
+
if (!state) {
|
|
264
|
+
if (billingAccountState.size >= MAX_BILLING_ACCOUNTS) {
|
|
265
|
+
const oldestKey = billingAccountState.keys().next().value
|
|
266
|
+
if (oldestKey !== undefined) billingAccountState.delete(oldestKey)
|
|
267
|
+
}
|
|
268
|
+
state = {
|
|
269
|
+
cch: Math.random().toString(16).slice(2, 6).padEnd(4, '0'),
|
|
270
|
+
turnIndex: 0,
|
|
271
|
+
}
|
|
272
|
+
billingAccountState.set(accountKey, state)
|
|
273
|
+
}
|
|
274
|
+
state.turnIndex += 1
|
|
275
|
+
const promptIndex = resolvePromptIndex(cfg, context)
|
|
276
|
+
return `x-anthropic-billing-header: cc_version=${ccVersion}; cc_entrypoint=sdk-cli; cch=${state.cch}; cc_turn_origin=sdk; cc_prompt_index=${promptIndex}; cc_turn_index=${state.turnIndex};`
|
|
233
277
|
}
|
|
234
278
|
|
|
235
|
-
export function applyClaudeBillingHeader(payload, cfg) {
|
|
279
|
+
export function applyClaudeBillingHeader(payload, cfg, context) {
|
|
236
280
|
if (process.env.CLAUDE_CODE_ATTRIBUTION_HEADER === '0') return payload
|
|
281
|
+
if (cfg && cfg.disableBillingHeader === true) return payload
|
|
237
282
|
if (!payload) return payload
|
|
238
|
-
const headerText = makeClaudeBillingHeader(cfg)
|
|
283
|
+
const headerText = makeClaudeBillingHeader(cfg, context)
|
|
239
284
|
const headerBlock = { type: 'text', text: headerText }
|
|
240
285
|
if (Array.isArray(payload.system)) {
|
|
241
286
|
if (!payload.system.some((b) => typeof b === 'object' && b && typeof b.text === 'string' && b.text.startsWith('x-anthropic-billing-header:'))) {
|
|
@@ -249,10 +294,10 @@ export function applyClaudeBillingHeader(payload, cfg) {
|
|
|
249
294
|
return payload
|
|
250
295
|
}
|
|
251
296
|
|
|
252
|
-
export async function* streamOnce({ blob, options, fetchImpl, headers, config, signal }) {
|
|
297
|
+
export async function* streamOnce({ blob, options, fetchImpl, headers, config, signal, accountId }) {
|
|
253
298
|
const payload = anthropicPayload(options, config.systemPrefix || IDENTITY)
|
|
254
299
|
applyClaudeThinking(payload, options)
|
|
255
|
-
applyClaudeBillingHeader(payload, config)
|
|
300
|
+
applyClaudeBillingHeader(payload, config, { accountId, blob, options })
|
|
256
301
|
const res = await fetchImpl(API, {
|
|
257
302
|
method: 'POST',
|
|
258
303
|
headers: {
|
|
@@ -184,7 +184,7 @@ export function isCopilotCliAvailable(options = {}) {
|
|
|
184
184
|
* Translate DSH turn options to Copilot CLI arguments and environment.
|
|
185
185
|
* @param {any} options
|
|
186
186
|
* @param {any} [blob]
|
|
187
|
-
* @param {string} [
|
|
187
|
+
* @param {string} [_binaryPath]
|
|
188
188
|
* @returns {{ args: string[], env: NodeJS.ProcessEnv, inputPayload: string }}
|
|
189
189
|
*/
|
|
190
190
|
export function prepareCopilotCliInvocation(options, blob = {}, _binaryPath = 'copilot') {
|
|
@@ -239,7 +239,7 @@ export function prepareCopilotCliInvocation(options, blob = {}, _binaryPath = 'c
|
|
|
239
239
|
* @param {Function} [params.spawnImpl] Test seam for child_process.spawn
|
|
240
240
|
* @returns {AsyncGenerator<any, void, unknown>}
|
|
241
241
|
*/
|
|
242
|
-
export async function* streamCopilotCli({ binaryPath, options, blob, _config, signal, spawnImpl }) {
|
|
242
|
+
export async function* streamCopilotCli({ binaryPath, options, blob, config: _config, signal, spawnImpl }) {
|
|
243
243
|
if (signal && signal.aborted) {
|
|
244
244
|
throw new LlmError('Request aborted by client', 'ABORTED')
|
|
245
245
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.67",
|
|
4
4
|
"description": "Use ChatGPT Codex, Claude, Grok, Antigravity, Kimi, GLM, Cursor, Kiro, Copilot, Qwen, ERNIE, Spark, JetBrains, Perplexity, Replit, and Cody subscriptions as DeepSeek Harness LLM providers via OAuth.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|