@goodandready/dsh-subscriptions 0.6.1 → 0.6.2
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 +6 -1
- package/README.ru.md +5 -0
- package/lib/client.js +177 -22
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -195,10 +195,15 @@ dsh plugin --profile web add @goodandready/dsh-subscriptions
|
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
> [!IMPORTANT]
|
|
198
|
-
> Restart DSH Web UI after installation (`systemctl --user restart dsh-web`) and navigate to **Settings → Subscriptions** to link your accounts.
|
|
198
|
+
> Restart DSH Web UI after installation (`systemctl --user restart dsh-web`) and navigate to **Settings → Plugins → Plugin Settings → Subscriptions** to link your accounts.
|
|
199
199
|
|
|
200
200
|
---
|
|
201
201
|
|
|
202
|
+
|
|
203
|
+
> [!TIP]
|
|
204
|
+
> **UI Settings Card vs YAML Overrides**:
|
|
205
|
+
> All common options (account slots, autoLoopback, privacyMask, composerQuota, expiryNotifyDays, codexFastMode, codexVerbosity, ollamaFallback/baseUrl/model, and cooldown/probe intervals) can be managed directly in the Web UI card (**Settings → Plugins → Plugin Settings → Subscriptions**). Low-level parameters such as OAuth client IDs/redirect URIs, API base URL overrides, and custom vendors are configured in `settings.yaml`.
|
|
206
|
+
|
|
202
207
|
## ⚙️ Configuration Reference (`settings.yaml`)
|
|
203
208
|
|
|
204
209
|
```yaml
|
package/README.ru.md
CHANGED
|
@@ -172,6 +172,11 @@ dsh plugin --profile web add @goodandready/dsh-subscriptions
|
|
|
172
172
|
|
|
173
173
|
---
|
|
174
174
|
|
|
175
|
+
|
|
176
|
+
> [!TIP]
|
|
177
|
+
> **Карточка настроек в UI vs Настройки в YAML**:
|
|
178
|
+
> Все основные параметры (слоты аккаунтов, перехват autoLoopback, privacyMask, индикатор composerQuota, оповещение expiryNotifyDays, codexFastMode, codexVerbosity, ollamaFallback/baseUrl/model, интервалы cooldown и probe) настраиваются напрямую в Web UI: **«Настройки → Плагины → Настройки плагинов → Subscriptions»**. Низкоуровневые оверрайды (собственные OAuth Client ID / Redirect URI, Base URL для прокси, кастомные вендоры) задаются в `settings.yaml`.
|
|
179
|
+
|
|
175
180
|
## ⚙️ Пример конфигурации (`settings.yaml`)
|
|
176
181
|
|
|
177
182
|
```yaml
|
package/lib/client.js
CHANGED
|
@@ -103,6 +103,10 @@ window.__ModuleLoader__.load({
|
|
|
103
103
|
'.dsub-heroHead{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}' +
|
|
104
104
|
'.dsub-heroTitle{font-size:14px;font-weight:700;display:flex;align-items:center;gap:6px}' +
|
|
105
105
|
'.dsub-heroModel{font-size:11.5px;color:var(--dsw-alias-label-secondary);font-family:ui-monospace,monospace}' +
|
|
106
|
+
'.dsub-select{appearance:none;height:30px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 24px 0 8px;font-size:12px;cursor:pointer}' +
|
|
107
|
+
'.dsub-details{margin-top:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 12px;background:var(--dsw-alias-bg-layer-2)}' +
|
|
108
|
+
'.dsub-summary{cursor:pointer;font-weight:600;font-size:12.5px;color:var(--dsw-alias-label-secondary);user-select:none}' +
|
|
109
|
+
'.dsub-summary:hover{color:var(--dsw-alias-label-primary)}' +
|
|
106
110
|
'.dsub-heroBars{display:flex;flex-direction:column;gap:8px;margin-top:10px}' +
|
|
107
111
|
'.dsub-barLabelRow{display:flex;justify-content:space-between;font-size:11.5px;color:var(--dsw-alias-label-secondary);margin-bottom:3px}' +
|
|
108
112
|
'.dsub-barTrack{height:6px;border-radius:3px;background:var(--dsw-alias-bg-layer-1);overflow:hidden}' +
|
|
@@ -308,6 +312,37 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
308
312
|
'useOriginHint': 'Leave off unless you registered your own OAuth client for this origin. Vendor CLI clients usually require their published redirect URI plus the paste step.',
|
|
309
313
|
'privacyMask': 'Mask emails and account identifiers',
|
|
310
314
|
'privacyMaskHint': 'For demos and screen sharing: emails show as j***n@example.com.',
|
|
315
|
+
'autoLoopback': 'Auto Loopback',
|
|
316
|
+
'autoLoopbackHint': 'Listen on local callback port to catch OAuth tokens automatically without manual copy-paste.',
|
|
317
|
+
'hideDeprecated': 'Hide deprecated models',
|
|
318
|
+
'hideDeprecatedHint': 'Hide older or superseded model variants from model dropdowns.',
|
|
319
|
+
'composerQuota': 'Composer quota indicator',
|
|
320
|
+
'composerQuotaHint': 'Display subscription usage indicator directly in the composer toolbar.',
|
|
321
|
+
'composerQuotaOff': 'Disabled',
|
|
322
|
+
'composerQuotaPercent': 'Percentage',
|
|
323
|
+
'composerQuotaBar': 'Progress Bar',
|
|
324
|
+
'composerQuotaForecast': 'Remaining Forecast',
|
|
325
|
+
'expiryNotifyDays': 'Expiry warning threshold (days)',
|
|
326
|
+
'expiryNotifyDaysHint': 'Notify when subscription renewal or token expiration is within this many days (0 to disable).',
|
|
327
|
+
'codexFastMode': 'Codex fast mode (1.5x)',
|
|
328
|
+
'codexFastModeHint': 'Enable high-throughput mode for OpenAI Codex models if supported by subscription.',
|
|
329
|
+
'codexVerbosity': 'Codex streaming verbosity',
|
|
330
|
+
'codexVerbosityHint': 'Control streaming chunking detail level from the Codex provider.',
|
|
331
|
+
'codexVerbosityDefault': 'Default',
|
|
332
|
+
'codexVerbosityLow': 'Low',
|
|
333
|
+
'codexVerbosityMedium': 'Medium',
|
|
334
|
+
'codexVerbosityHigh': 'High',
|
|
335
|
+
'ollamaFallback': 'Ollama local fallback',
|
|
336
|
+
'ollamaFallbackHint': 'Automatically route queries to a local Ollama instance when cloud quota is exhausted.',
|
|
337
|
+
'ollamaBaseUrl': 'Ollama Base URL',
|
|
338
|
+
'ollamaFallbackModel': 'Ollama Fallback Model',
|
|
339
|
+
'advancedSettings': 'Advanced Settings & Monitoring',
|
|
340
|
+
'cooldownMs': 'Failure cooldown (minutes)',
|
|
341
|
+
'cooldownMsHint': 'How long to pause a failing or rate-limited account before retrying.',
|
|
342
|
+
'probeIntervalMin': 'Health probe interval (minutes)',
|
|
343
|
+
'probeIntervalMinHint': 'Interval for background checks to refresh account status and quota balance.',
|
|
344
|
+
'notifyLimits': 'Notify on rate limits',
|
|
345
|
+
'notifyLimitsHint': 'Show notification alerts when account usage reaches quota ceiling.',
|
|
311
346
|
'resetCredits': 'Reset credits',
|
|
312
347
|
'resetCreditsHint': 'ChatGPT reset cards: emergency reset for the 5-hour window. Requires a 5s confirmation.',
|
|
313
348
|
'resetCreditsAction': 'Reset ChatGPT Limit',
|
|
@@ -847,6 +882,146 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
847
882
|
),
|
|
848
883
|
React.createElement('div', { className: 'dsub-sub' },
|
|
849
884
|
t('privacyMaskHint')),
|
|
885
|
+
React.createElement('label', { className: 'dsub-row' },
|
|
886
|
+
React.createElement('input', {
|
|
887
|
+
type: 'checkbox',
|
|
888
|
+
checked: !!draft.autoLoopback,
|
|
889
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { autoLoopback: e.target.checked })),
|
|
890
|
+
}),
|
|
891
|
+
React.createElement('span', null, t('autoLoopback')),
|
|
892
|
+
),
|
|
893
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
894
|
+
t('autoLoopbackHint')),
|
|
895
|
+
React.createElement('label', { className: 'dsub-row' },
|
|
896
|
+
React.createElement('input', {
|
|
897
|
+
type: 'checkbox',
|
|
898
|
+
checked: !!draft.hideDeprecatedModels,
|
|
899
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { hideDeprecatedModels: e.target.checked })),
|
|
900
|
+
}),
|
|
901
|
+
React.createElement('span', null, t('hideDeprecated')),
|
|
902
|
+
),
|
|
903
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
904
|
+
t('hideDeprecatedHint')),
|
|
905
|
+
React.createElement('div', { className: 'dsub-row' },
|
|
906
|
+
React.createElement('span', { className: 'dsub-h' }, t('composerQuota')),
|
|
907
|
+
React.createElement('select', {
|
|
908
|
+
className: 'dsub-select',
|
|
909
|
+
value: draft.composerQuota || 'percent',
|
|
910
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { composerQuota: e.target.value })),
|
|
911
|
+
},
|
|
912
|
+
React.createElement('option', { value: 'off' }, t('composerQuotaOff')),
|
|
913
|
+
React.createElement('option', { value: 'percent' }, t('composerQuotaPercent')),
|
|
914
|
+
React.createElement('option', { value: 'bar' }, t('composerQuotaBar')),
|
|
915
|
+
React.createElement('option', { value: 'forecast' }, t('composerQuotaForecast')),
|
|
916
|
+
),
|
|
917
|
+
),
|
|
918
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
919
|
+
t('composerQuotaHint')),
|
|
920
|
+
React.createElement('div', { className: 'dsub-row' },
|
|
921
|
+
React.createElement('span', { className: 'dsub-h' }, t('expiryNotifyDays')),
|
|
922
|
+
React.createElement('input', {
|
|
923
|
+
type: 'number',
|
|
924
|
+
className: 'dsub-inp',
|
|
925
|
+
style: { width: '80px', minWidth: '80px' },
|
|
926
|
+
min: 0,
|
|
927
|
+
max: 90,
|
|
928
|
+
value: draft.expiryNotifyDays != null ? draft.expiryNotifyDays : 7,
|
|
929
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { expiryNotifyDays: Number(e.target.value) || 0 })),
|
|
930
|
+
}),
|
|
931
|
+
),
|
|
932
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
933
|
+
t('expiryNotifyDaysHint')),
|
|
934
|
+
React.createElement('label', { className: 'dsub-row' },
|
|
935
|
+
React.createElement('input', {
|
|
936
|
+
type: 'checkbox',
|
|
937
|
+
checked: !!draft.codexFastMode,
|
|
938
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { codexFastMode: e.target.checked })),
|
|
939
|
+
}),
|
|
940
|
+
React.createElement('span', null, t('codexFastMode')),
|
|
941
|
+
),
|
|
942
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
943
|
+
t('codexFastModeHint')),
|
|
944
|
+
React.createElement('div', { className: 'dsub-row' },
|
|
945
|
+
React.createElement('span', { className: 'dsub-h' }, t('codexVerbosity')),
|
|
946
|
+
React.createElement('select', {
|
|
947
|
+
className: 'dsub-select',
|
|
948
|
+
value: draft.codexVerbosity || 'default',
|
|
949
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { codexVerbosity: e.target.value })),
|
|
950
|
+
},
|
|
951
|
+
React.createElement('option', { value: 'default' }, t('codexVerbosityDefault')),
|
|
952
|
+
React.createElement('option', { value: 'low' }, t('codexVerbosityLow')),
|
|
953
|
+
React.createElement('option', { value: 'medium' }, t('codexVerbosityMedium')),
|
|
954
|
+
React.createElement('option', { value: 'high' }, t('codexVerbosityHigh')),
|
|
955
|
+
),
|
|
956
|
+
),
|
|
957
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
958
|
+
t('codexVerbosityHint')),
|
|
959
|
+
React.createElement('label', { className: 'dsub-row' },
|
|
960
|
+
React.createElement('input', {
|
|
961
|
+
type: 'checkbox',
|
|
962
|
+
checked: !!draft.ollamaFallback,
|
|
963
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { ollamaFallback: e.target.checked })),
|
|
964
|
+
}),
|
|
965
|
+
React.createElement('span', null, t('ollamaFallback')),
|
|
966
|
+
),
|
|
967
|
+
React.createElement('div', { className: 'dsub-sub' },
|
|
968
|
+
t('ollamaFallbackHint')),
|
|
969
|
+
draft.ollamaFallback ? React.createElement('div', { className: 'dsub-row' },
|
|
970
|
+
React.createElement('input', {
|
|
971
|
+
type: 'text',
|
|
972
|
+
className: 'dsub-inp dsub-grow',
|
|
973
|
+
placeholder: 'http://localhost:11434',
|
|
974
|
+
value: draft.ollamaBaseUrl || '',
|
|
975
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { ollamaBaseUrl: e.target.value })),
|
|
976
|
+
}),
|
|
977
|
+
React.createElement('input', {
|
|
978
|
+
type: 'text',
|
|
979
|
+
className: 'dsub-inp dsub-grow',
|
|
980
|
+
placeholder: 'llama3:latest',
|
|
981
|
+
value: draft.ollamaFallbackModel || '',
|
|
982
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { ollamaFallbackModel: e.target.value })),
|
|
983
|
+
}),
|
|
984
|
+
) : null,
|
|
985
|
+
React.createElement('details', { className: 'dsub-details' },
|
|
986
|
+
React.createElement('summary', { className: 'dsub-summary' }, t('advancedSettings')),
|
|
987
|
+
React.createElement('div', { className: 'dsub-block' },
|
|
988
|
+
React.createElement('div', { className: 'dsub-row' },
|
|
989
|
+
React.createElement('span', { className: 'dsub-h' }, t('cooldownMs')),
|
|
990
|
+
React.createElement('input', {
|
|
991
|
+
type: 'number',
|
|
992
|
+
className: 'dsub-inp',
|
|
993
|
+
style: { width: '80px', minWidth: '80px' },
|
|
994
|
+
min: 1,
|
|
995
|
+
max: 120,
|
|
996
|
+
value: Math.round((draft.cooldownMs || 600000) / 60000),
|
|
997
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { cooldownMs: (Number(e.target.value) || 10) * 60000 })),
|
|
998
|
+
}),
|
|
999
|
+
),
|
|
1000
|
+
React.createElement('div', { className: 'dsub-sub' }, t('cooldownMsHint')),
|
|
1001
|
+
React.createElement('div', { className: 'dsub-row' },
|
|
1002
|
+
React.createElement('span', { className: 'dsub-h' }, t('probeIntervalMin')),
|
|
1003
|
+
React.createElement('input', {
|
|
1004
|
+
type: 'number',
|
|
1005
|
+
className: 'dsub-inp',
|
|
1006
|
+
style: { width: '80px', minWidth: '80px' },
|
|
1007
|
+
min: 1,
|
|
1008
|
+
max: 1440,
|
|
1009
|
+
value: draft.probeIntervalMin != null ? draft.probeIntervalMin : 15,
|
|
1010
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { probeIntervalMin: Number(e.target.value) || 15 })),
|
|
1011
|
+
}),
|
|
1012
|
+
),
|
|
1013
|
+
React.createElement('div', { className: 'dsub-sub' }, t('probeIntervalMinHint')),
|
|
1014
|
+
React.createElement('label', { className: 'dsub-row' },
|
|
1015
|
+
React.createElement('input', {
|
|
1016
|
+
type: 'checkbox',
|
|
1017
|
+
checked: draft.notifyLimits !== false,
|
|
1018
|
+
onChange: (e) => setDraft((d) => Object.assign({}, d, { notifyLimits: e.target.checked })),
|
|
1019
|
+
}),
|
|
1020
|
+
React.createElement('span', null, t('notifyLimits')),
|
|
1021
|
+
),
|
|
1022
|
+
React.createElement('div', { className: 'dsub-sub' }, t('notifyLimitsHint')),
|
|
1023
|
+
),
|
|
1024
|
+
),
|
|
850
1025
|
),
|
|
851
1026
|
React.createElement('div', { className: 'dsub-block' },
|
|
852
1027
|
React.createElement('div', { className: 'dsub-row' },
|
|
@@ -1258,9 +1433,8 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
1258
1433
|
// The canonical place is the Plugins tab: a card with its own header
|
|
1259
1434
|
// and collapse instead of a row in the side list. The registration key must
|
|
1260
1435
|
// equal the settings namespace, otherwise the tab silently hides the slot.
|
|
1261
|
-
let moved = false
|
|
1262
1436
|
try {
|
|
1263
|
-
|
|
1437
|
+
ctx.slots.inject('settings.plugin.item', () => ctx.slots.register(
|
|
1264
1438
|
{
|
|
1265
1439
|
name: 'settings.plugin.item',
|
|
1266
1440
|
key: NS,
|
|
@@ -1269,27 +1443,8 @@ const cssId = 'dsh-subscriptions/settings.module.css'
|
|
|
1269
1443
|
},
|
|
1270
1444
|
PluginCard,
|
|
1271
1445
|
))
|
|
1272
|
-
} catch { moved = false }
|
|
1273
|
-
if (moved) return
|
|
1274
|
-
// #244: Fallback for harness cores before settings.plugin.item slot was
|
|
1275
|
-
// introduced (< 0.1.2-rc.1). Once all production profiles run a core
|
|
1276
|
-
// that has settings.plugin.item, this block can be safely removed.
|
|
1277
|
-
// Tracked in Gitea #244 — do not remove without verifying minimum core.
|
|
1278
|
-
try {
|
|
1279
|
-
ctx.slots.inject('settings.section', () => ctx.slots.register(
|
|
1280
|
-
{
|
|
1281
|
-
name: 'settings.section',
|
|
1282
|
-
id: '@goodandready/dsh-subscriptions',
|
|
1283
|
-
order: 28,
|
|
1284
|
-
locale: NS,
|
|
1285
|
-
label: () => t('title'),
|
|
1286
|
-
inject: () => ({ ctx: ctx }),
|
|
1287
|
-
},
|
|
1288
|
-
SubsSection,
|
|
1289
|
-
))
|
|
1290
1446
|
} catch (e) {
|
|
1291
|
-
//
|
|
1292
|
-
// This is expected on headless / non-web profiles.
|
|
1447
|
+
// Slot system not available — expected on headless / non-web profiles.
|
|
1293
1448
|
}
|
|
1294
1449
|
}
|
|
1295
1450
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
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",
|
|
@@ -34,9 +34,6 @@
|
|
|
34
34
|
"bugs": {
|
|
35
35
|
"url": "https://github.com/GooDAnDReaDY/dsh-subscriptions/issues"
|
|
36
36
|
},
|
|
37
|
-
"scripts": {
|
|
38
|
-
"test": "eslint lib/ && node --test test/*.test.mjs"
|
|
39
|
-
},
|
|
40
37
|
"dsh": {
|
|
41
38
|
"bundle": {
|
|
42
39
|
"patch": "./cordis.patch.yml"
|
|
@@ -63,5 +60,8 @@
|
|
|
63
60
|
},
|
|
64
61
|
"devDependencies": {
|
|
65
62
|
"@deepseek-ai/dsh-llm": "0.1.0-rc.8"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"test": "eslint lib/ && node --test test/*.test.mjs"
|
|
66
66
|
}
|
|
67
|
-
}
|
|
67
|
+
}
|