@goodandready/dsh-subscriptions 0.4.15 → 0.4.17

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 CHANGED
@@ -1,233 +1,199 @@
1
- # dsh-subscriptions
2
-
3
- Use **ChatGPT Codex**, **Claude**, **Grok**, and **Antigravity**
4
- subscriptions as DeepSeek Harness LLM providers. Log in from
5
- **Settings Plugins Plugin settings Subscriptions**.
6
- Several accounts per provider rotate on quota inside this plugin.
7
-
8
- This package is original software. It speaks vendor-public OAuth and LLM HTTP
9
- contracts. It does not ship tools (`x_search`, image, or video).
10
-
11
- ## Install
12
-
13
- ```bash
14
- dsh plugin --profile web add @goodandready/dsh-subscriptions
1
+ # 📦 @goodandready/dsh-subscriptions
2
+
3
+ <div align="center">
4
+
5
+ <h3>Personal AI Subscription Bridge, Multi-Account Pool Rotation & Zero-Leak OAuth for DeepSeek Harness</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-subscriptions"><img src="https://img.shields.io/npm/v/@goodandready/dsh-subscriptions.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/All_Author_Projects-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="All Author Projects"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
21
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
22
+ </p>
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ⚡ Overview
29
+
30
+ **`dsh-subscriptions`** bridges your paid personal AI subscriptions directly into **DeepSeek Harness** as first-class LLM providers.
31
+
32
+ Instead of burning expensive pay-as-you-go API credits for everyday agent tasks, `dsh-subscriptions` allows you to authenticate your existing web subscriptions via standard OAuth PKCE. It features **multi-account rotation pools** (automatically switching accounts when a rate limit or cooldown is reached), **preemptive quota switching**, and an **in-process Cordis service (`ctx.subscriptions`)** that safely powers sibling plugins like [`dsh-image-gen`](https://github.com/GooDAnDReaDY/dsh-image-gen) and [`dsh-grok-xsearch`](https://github.com/GooDAnDReaDY/dsh-grok-xsearch) with zero token leakage.
33
+
34
+ ```mermaid
35
+ graph LR
36
+ subgraph DSHCore [DeepSeek Harness Session]
37
+ Agent[🤖 DSH Agent Execution] --> Router{Provider Router}
38
+ end
39
+
40
+ subgraph SubscriptionsCore [dsh-subscriptions Engine]
41
+ Router --> Pool{Multi-Account Vendor Pool}
42
+ Pool -->|Account #1| Acc1[👤 Primary Account: Active]
43
+ Pool -->|Account #2| Acc2[👤 Secondary Account: Standby]
44
+ Pool -->|Account #3| Acc3[👤 Fallback Account: Cooldown]
45
+ Acc1 -->|HTTP 429 / Quota Limit| Rotate[Smart Quota & Cooldown Rotator]
46
+ Rotate -->|Switches Traffic| Acc2
47
+ end
48
+
49
+ subgraph VendorBridges [4 Upstream Vendor Bridges]
50
+ Acc1 --> B1[ChatGPT / Codex Backend]
51
+ Acc1 --> B2[Claude Pro / Max Protocol]
52
+ Acc1 --> B3[xAI / Grok Subscriptions]
53
+ Acc1 --> B4[Google Cloud Code Assist / Antigravity]
54
+ end
55
+
56
+ subgraph EcosystemBridge [In-Process Cordis Service: ctx.subscriptions]
57
+ Pool --> ImgGen[dsh-image-gen: Zero-Cost Image Drawing]
58
+ Pool --> XSearch[dsh-grok-xsearch: Live Twitter Search]
59
+ end
60
+
61
+ style DSHCore fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
62
+ style SubscriptionsCore fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
63
+ style VendorBridges fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
64
+ style EcosystemBridge fill:#181825,stroke:#f38ba8,stroke-width:2px,color:#cdd6f4
15
65
  ```
16
66
 
17
- Local checkout (development):
18
-
19
- ```bash
20
- dsh plugin --profile web add file:/path/to/dsh-subscriptions
21
- ```
22
-
23
- After a `file:` install, remove then add again if you added new files under
24
- `lib/` — pnpm reuses the previous copy otherwise.
25
-
26
- ## Settings
27
-
28
- Settings live on a collapsible card in **Settings → Plugins → Plugin settings**
29
- (not a sidebar entry). Click **Show** to expand it.
30
-
31
- 1. Pick a provider block and click **Connect**. Complete sign-in in the browser.
32
- 2. **+ Add account** adds another account slot for the same provider; every
33
- account participates in rotation.
34
- 3. **Disconnect** removes that account's token; **Reconnect** repeats OAuth on
35
- the same slot. The × button disconnects and drops the slot.
36
- 4. If the provider redirects to a localhost or vendor URL that this host cannot
37
- receive, paste the full redirected URL (or the `code` value) into the
38
- account row and click **Submit code**.
39
- 5. Logged-in providers appear in the session model picker.
40
-
41
- Leave **Use this Web UI origin as OAuth redirect_uri** off unless you registered
42
- your own OAuth client for this origin. Vendor CLI clients typically require
43
- their published redirect URI plus the paste step.
44
-
45
- ## Accounts and rotation
46
-
47
- Each provider holds any number of account slots (`CODEX_OAUTH_1`,
48
- `CODEX_OAUTH_2`, …). On `RATE_LIMIT`, `QUOTA`, or HTTP 429 the plugin cools the
49
- account down (`cooldownMs`, default 30 minutes) and retries the same request on
50
- the next account of the same provider — never a different provider.
51
-
52
- Beyond error-driven rotation, accounts are proactively skipped when:
53
-
54
- - usage is at 100% for the current window (vendor-reported), or
55
- - remaining quota fraction is at or below `switchAtRemaining`
56
- (default `0.01` = 1%), or
57
- - the window resets within one minute (no point spending the tail).
58
-
59
- When every account is below threshold, the request still goes out on the first
60
- exhausted account — a refusal beats silence.
61
-
62
- ## Quota visibility
63
-
64
- Vendors that report usage expose named windows (Claude `5h`/`7d apps`,
65
- Codex primary/secondary, Grok credits). Each window renders as a progress bar
66
- with percent; colors follow theme variables (normal / warning ≥70% / exhausted
67
- 100%). The last known snapshot persists across harness restarts and refreshes
68
- on the next successful request.
69
-
70
- The plugin also estimates remaining requests for the primary window
71
- (`≈ N (5h)`) once enough request history exists — hidden when data is thin.
72
-
73
- ### Limit notifications
74
-
75
- When a window crosses 70%, 90%, or 100%, the plugin logs a warning and emits a
76
- `subscriptions.limit-notice` event (provider, ref, window id, usedPercent,
77
- threshold). Each threshold fires once per window until it resets. Toggle with
78
- `notifyLimits` in Config.
79
-
80
- ## Background maintenance
81
-
82
- Two timers run while the plugin is loaded:
83
-
84
- - **Token refresh ahead**: expiring tokens are refreshed before they are needed
85
- (`refreshAheadMs`, default 5 min). Failures back off via `refreshRetryMs`
86
- (default 10 min) and mark the card as *reconnect required*.
87
- - **Health probe loop**: every `probeIntervalMin` minutes (default 15, 0
88
- disables) each connected account gets a cheap vendor check. Dead accounts
89
- surface in the card; probes never set cooldown.
90
-
91
- Both timers clean up on plugin dispose.
92
-
93
- ## HTTP proxy
67
+ ---
94
68
 
95
- `POST|GET /dsh-subscriptions/proxy/{provider}/{path…}` forwards to the vendor
96
- API on behalf of a logged-in account — through the same allowlist, rotation,
97
- and quota accounting as model traffic. Same-origin only; no token ever appears
98
- in a response or log. Paths outside the per-provider allowlist get 403.
69
+ ## Key Features & Capabilities
99
70
 
100
- Example:
71
+ ### 1. 🌐 4 Supported Built-in Subscription Vendors
101
72
 
102
- ```bash
103
- curl -X POST https://<host>:3080/dsh-subscriptions/proxy/codex/models \
104
- -H 'Content-Type: application/json' -d '{}'
73
+ | Vendor Key | Subscription Tier | Protocol & Features |
74
+ |---|---|---|
75
+ | `codex` | ChatGPT Plus / Pro | Codex streaming responses, tool calling & image drawing (`/backend-api/codex/...`) |
76
+ | `claude` | Claude Pro / Max | Native Claude Messages protocol, usage tracking (`/v1/messages`, `/api/oauth/...`) |
77
+ | `grok` | xAI / X Premium | Real-time reasoning responses, billing checks & social search |
78
+ | `antigravity` | Google Cloud Code Assist | Antigravity engine (`/v1/loadCodeAssist`, `/v1/streamGenerateContent`) |
79
+
80
+ *Custom vendors can also be dynamically registered via the `createVendorFromProfile` factory.*
81
+
82
+ ---
83
+
84
+ ### 2. 🔄 Multi-Account Rotation & Rate-Limit Mitigation (`rotate.js`, `ratelimit.js`)
85
+ * **Multi-Account Pooling**: Attach multiple accounts per vendor (e.g. `CODEX_OAUTH_1`, `CODEX_OAUTH_2`, `CODEX_OAUTH_3`).
86
+ * **Automatic 429 Failover**: When an account encounters a rate limit (`HTTP 429`, `RATE_LIMIT`, `QUOTA_EXCEEDED`), traffic instantly fails over to the next healthy account in the pool.
87
+ * **Preemptive Quota Switching (`switchAtRemaining`)**: Automatically rotates to the next account before hitting zero if the rate-limit window reset is imminent.
88
+ * **Dynamic Cooldown Calculation**: Parses upstream headers (`Retry-After`, `x-ratelimit-reset`, ISO dates, epoch timestamps) and auto-restores cooled-down accounts when their window resets.
89
+
90
+ ---
91
+
92
+ ### 3. 🔒 Zero-Leak Credential Security & Headless OAuth
93
+ * **Zero Token Leakage**: OAuth tokens are **never** returned over HTTP API endpoints or rendered in the Web UI. The UI only receives masked account labels, connection health, and quota bars.
94
+ * **Secure Host Storage**: Tokens reside in encrypted `$DSH_HOME/.credentials.yaml` managed by the host credentials service.
95
+ * **Headless / Remote Login Fallback**: If running DSH on a headless server over SSH where browser popups cannot redirect to `localhost`, simply paste the redirected callback URL or authorization code directly into the account card.
96
+ * **Proactive Background Token Refresh**: Access tokens are refreshed automatically before expiration.
97
+
98
+ ---
99
+
100
+ ### 4. 🧩 In-Process Cordis Service (`ctx.subscriptions`)
101
+ Sibling plugins can tap into subscription capabilities directly in memory via Cordis:
102
+ ```javascript
103
+ // Example in dsh-image-gen or custom plugins:
104
+ const res = await ctx.subscriptions.request('codex', '/backend-api/codex/images/generations', {
105
+ method: 'POST',
106
+ body: JSON.stringify({ prompt: 'Cyberpunk landscape', size: '1024x1024' }),
107
+ })
105
108
  ```
109
+ * **Zero Overhead**: Eliminates intermediate HTTP loops and keeps auth tokens strictly in-memory.
110
+ * **Strict Path Allowlist (`ALLOWLIST`)**: Restricts calls to verified vendor endpoints, preventing SSRF vulnerabilities.
106
111
 
107
- ## Export / import
112
+ ---
108
113
 
109
- Tokens live in the host credentials store and normally tie the installation to
110
- one machine. To move them:
111
-
112
- ```bash
113
- # export (returns an encrypted DSHE1 payload)
114
- curl -X POST https://<host>:3080/dsh-subscriptions/export \
115
- -H 'Content-Type: application/json' -d '{"passphrase":"strong-passphrase"}'
116
-
117
- # import
118
- curl -X POST https://<host>:3080/dsh-subscriptions/import \
119
- -H 'Content-Type: application/json' \
120
- -d '{"passphrase":"strong-passphrase","payload":"DSHE1:…"}'
121
- ```
114
+ ### 5. 🔐 Login Without a Browser: Loopback & Device Code (`v0.4.9`)
115
+ * **Automatic Loopback Callback (`autoLoopback`, on by default)**: For vendors whose OAuth redirect URI is a loopback address (Codex `:1455`, Grok `:56121`), the plugin spins up a temporary local HTTP server and catches the callback by itself — no URL pasting needed. The paste fallback always stays available.
116
+ * **Device Code Login (Codex)**: On fully headless machines (no browser on any reachable host), use the **Device login** button in the Codex account card. The plugin requests a short user code from `auth.openai.com`, you open `https://auth.openai.com/codex/device` on any device, enter the code, and the plugin completes the standard PKCE exchange automatically.
117
+ * **Classic Fallbacks Intact**: Web-origin redirect (`useWebCallback`) and manual paste of the redirected URL / authorization code remain available for custom OAuth clients.
122
118
 
123
- Bundles are AES-256-GCM encrypted with a key derived from your passphrase
124
- (scrypt). Without the passphrase nothing decrypts; wrong passphrase fails with
125
- a clear error. Tokens are never logged.
119
+ ### 6. 🌍 Per-Account HTTP/SOCKS Proxy (`v0.4.9`)
120
+ * **Individual Proxy per Account (`proxyUrl`)**: Every account slot accepts its own proxy URL (`http://`, `https://`, `socks5://[user:pass@]host:port`). All requests for that account OAuth token refresh, vendor checks, model requests — are routed through it. Empty = direct connection.
121
+ * **One-Click Proxy Check**: The account card has a **Check proxy** button: it performs a real request to the vendor base URL through the configured proxy and shows the round-trip latency or the failure reason.
122
+ * **Request History Timings**: Every recorded request now carries its duration (`ms`) in the history store, so you can compare direct vs proxied latency over time.
126
123
 
127
- ## Composer provider switcher
124
+ ### 7. 🕶️ Privacy Masking & Diagnostics Report (`v0.4.9`)
125
+ * **Privacy Masking (`privacyMask`)**: One toggle in the settings card masks personal data across the whole UI: emails render as `j***n@example.com` everywhere (account lists, status labels, check results). Designed for screen sharing and streaming. Server-side masking means labels never leak through API responses either; the underlying account data is never overwritten.
126
+ * **Anonymized Diagnostics Report**: The settings card has a **Generate diagnostics report** block: one click fetches an anonymized report (plugin/runtime versions, OS, per-vendor health counters, aggregate HTTP status counts, last ≥400 errors with timings, non-secret settings) and copies it to the clipboard. Tokens, emails, credential refs and proxy URLs are strictly excluded (verified by tests).
127
+ * **Issue-Ready**: The same block links to the project issue tracker, so a bug report is: generate → paste → submit.
128
128
 
129
- A small widget in the composer bar shows the active subscription provider;
130
- clicking cycles among logged-in providers without opening Settings. It does not
131
- change the session model picker state.
129
+ ### 8. 🔌 HTTP API (added in `v0.4.9`)
130
+ | Route | Method | Purpose |
131
+ |---|---|---|
132
+ | `/dsh-subscriptions/diagnostics` | GET | Anonymized diagnostics report (no secrets, no tokens, no proxy URLs) |
133
+ | `/dsh-subscriptions/proxy-check` | POST | Latency check of a slot's proxy against its vendor base URL |
134
+ | `/dsh-subscriptions/oauth/device/start` | POST | Begin Codex device-code login (returns user code + verification URL) |
135
+ | `/dsh-subscriptions/oauth/device/poll` | POST | Poll device-code authorization status |
132
136
 
133
- ## Session header chip
137
+ ---
134
138
 
135
- A compact chip in the conversation header shows how many subscriptions are
136
- connected. It polls `/dsh-subscriptions/status` every minute and turns green
137
- when at least one account is active.
139
+ ### 9. 🦛 Local Ollama Gateway & Seamless Fallback (`v0.4.17`)
140
+ * **Native Provider (`ollama`)**: When a local Ollama is reachable at `ollamaBaseUrl` (default `http://127.0.0.1:11434`), it appears in the native DSH model picker with the models discovered from `/api/tags`. No API key needed.
141
+ * **Seamless Quota Fallback (`ollamaFallback`, on by default)**: When every account of a provider is exhausted (or unreachable) and nothing has been streamed yet, the chat continues on a local model (`ollamaFallbackModel`, or the first model from `/api/tags`). The fallback is logged and recorded in request history as `kind: fallback`.
142
+ * **Free ($0) Emergency Path**: Works with no internet and no quota — ideal for offline demos.
138
143
 
139
- ## Quota reset countdown
144
+ ### 10. Reasoning Effort, Verbosity & Fast Mode (`v0.4.17`)
145
+ * **Reasoning Effort**: Codex models advertise their supported effort levels from the live catalog; the native picker validates and the chosen effort is transmitted as `reasoning.effort` in the Codex `/responses` protocol. Grok forwards effort with its own catalog-aware filtering.
146
+ * **Verbosity (`codexVerbosity`)**: `low` / `medium` / `high` is sent as `text.verbosity` for Codex reasoning models. Empty = protocol default.
147
+ * **Fast Mode (`codexFastMode`)**: Sends `service_tier: priority` (1.5x speed billing tier) with every Codex request. The active-subscription chip shows a `⚡` prefix while enabled.
140
148
 
141
- When a vendor reports a quota window reset timestamp, the account card shows a
142
- live `reset HH:MM:SS` countdown next to the quota bar, updating every second.
149
+ ### 11. 🚦 Family-Scoped Cooldowns & Model Filtering (`v0.4.17`)
150
+ * **Reasoning vs Standard**: A 429 on a reasoning model (claude `*thinking*`, grok `*reasoning*`, all codex models) cools down only the reasoning family of that account — standard models on the same account keep working immediately. Legacy cooldowns (from older versions) still block the whole account until expiry.
151
+ * **Hide Deprecated Models (`hideDeprecatedModels`)**: Filters `test`/`preview`/`dev`/`alpha`/`beta`/`legacy` model ids out of the native picker (applies to live catalogs and the static fallback).
143
152
 
144
- ## Slash commands
153
+ ---
145
154
 
146
- From the chat, without opening Settings:
155
+ ## 📦 Quick Installation
147
156
 
157
+ ```bash
158
+ dsh plugin --profile web add @goodandready/dsh-subscriptions
148
159
  ```
149
- /login <provider> # start OAuth for codex|claude|grok|antigravity (opens the vendor page)
150
- /login status # insert the connected providers into the composer
151
- /logout <provider> # disconnect that provider
152
- ```
153
-
154
- ## /subscriptions page
155
-
156
- A localhost-only summary page at `/dsh-subscriptions/subscriptions` lists every account slot,
157
- connection status, usage percent, remaining quota and reset time across all
158
- providers. Requests from non-loopback hosts get 403.
159
-
160
- ## Import a token directly
161
-
162
- In any account card, paste an existing refresh token (or API key) and click
163
- **Import token** to sign in without the browser OAuth round trip. The token is
164
- written straight to the host credentials store via
165
- `POST /dsh-subscriptions/import-token { provider, index, refreshToken }`.
166
-
167
-
168
- ## Credential names
169
160
 
170
- Tokens are JSON blobs in the DSH credentials store. Names look like:
171
-
172
- ```text
173
- CODEX_OAUTH_1
174
- CLAUDE_OAUTH_2
161
+ > [!IMPORTANT]
162
+ > Restart DSH Web UI after installation (`systemctl --user restart dsh-web`) and navigate to **Settings → Subscriptions** to link your accounts.
163
+
164
+ ---
165
+
166
+ ## ⚙️ Configuration Reference (`settings.yaml`)
167
+
168
+ ```yaml
169
+ dsh-subscriptions:
170
+ switchAtRemaining: 1
171
+ cooldownMs: 60000
172
+ autoLoopback: true # v0.4.9: catch loopback OAuth callbacks automatically
173
+ privacyMask: false # v0.4.9: mask emails and account identifiers in the UI
174
+ ollamaBaseUrl: http://127.0.0.1:11434 # v0.4.17: local Ollama gateway
175
+ ollamaFallback: true # v0.4.17: seamless fallback when all accounts are exhausted
176
+ ollamaFallbackModel: '' # v0.4.17: e.g. qwen2.5-coder; empty = first model from /api/tags
177
+ hideDeprecatedModels: false # v0.4.17: filter test/preview/beta/legacy model ids
178
+ codexVerbosity: '' # v0.4.17: low | medium | high (text.verbosity)
179
+ codexFastMode: false # v0.4.17: service_tier priority (1.5x speed tier)
180
+ # Per-slot fields (v0.4.9): expiresAt (ms epoch), proxyUrl (http/https/socks5://)
181
+ accounts:
182
+ codex:
183
+ - ref: CODEX_OAUTH_1
184
+ label: "Work Pro Account"
185
+ - ref: CODEX_OAUTH_2
186
+ label: "Personal Plus Account"
187
+ claude:
188
+ - ref: CLAUDE_OAUTH_1
189
+ label: "Claude Max"
190
+ grok:
191
+ - ref: GROK_OAUTH_1
192
+ label: "X Premium"
175
193
  ```
176
194
 
177
- `<PROVIDER>` is `CODEX`, `CLAUDE`, `GROK`, or `ANTIGRAVITY`.
178
- Settings GET never returns access or refresh tokens — only
179
- `{ configured, label, usagePercent, cooldownUntil, ref }`.
180
-
181
- ## Providers
182
-
183
- | Key | Subscription | Default OAuth client |
184
- |---|---|---|
185
- | `codex` | ChatGPT / Codex | Vendor-public Codex CLI client id |
186
- | `claude` | Claude Pro/Max | Vendor-public Claude Code client id |
187
- | `grok` | xAI / SuperGrok | Vendor-public Grok CLI client id |
188
- | `antigravity` | Google Antigravity | Your OAuth client id + secret in Config |
189
-
190
- Override `codexClientId`, `claudeClientId`, and the other empty Config fields
191
- if you register your own OAuth app.
192
-
193
- Live requests use the vendor subscription surfaces, not API-key hosts:
194
- Codex `chatgpt.com/backend-api/codex/responses`, Claude Messages with the
195
- OAuth beta header, Grok `cli-chat-proxy.grok.com` with CLI identity headers,
196
- and Antigravity Cloud Code Assist (`loadCodeAssist` then
197
- `streamGenerateContent`). Usage endpoints, when they answer, feed the skip
198
- logic above. If a live model list fails, the built-in catalog is used.
199
-
200
- Antigravity uses a confidential Google OAuth client: set `antigravityClientId`
201
- and `antigravityClientSecret` in plugin Config (Settings) — nothing is baked
202
- into the repository.
203
-
204
- Default model catalogs are built-in lists you can replace with
205
- `codexModels`, `claudeModels`, `grokModels`, `antigravityModels`
206
- in the plugin Config.
207
-
208
- ### Config reference
209
-
210
- | Key | Default | Meaning |
211
- |---|---|---|
212
- | `cooldownMs` | 1800000 | Cooldown after RATE_LIMIT/QUOTA/429 |
213
- | `switchAtRemaining` | 0.01 | Skip account when remaining ≤ this (fraction <1 or absolute ≥1); 0 disables |
214
- | `refreshAheadMs` | 300000 | Refresh tokens expiring within this window |
215
- | `refreshRetryMs` | 600000 | Backoff after a failed background refresh |
216
- | `probeIntervalMin` | 15 | Account health-check interval, minutes; 0 disables |
217
- | `notifyLimits` | true | Emit notices when usage crosses 70/90/100% |
218
- | `useWebCallback` | false | Use Web UI origin as OAuth redirect_uri |
219
- | `<vendor>Models` | built-in | Replace default model catalog per vendor |
220
-
221
- ## Identity
222
-
223
- These three names must match:
224
-
225
- | Place | Value |
226
- |---|---|
227
- | `package.json` `name` | `@goodandready/dsh-subscriptions` |
228
- | `cordis.patch.yml` `name:` | `@goodandready/dsh-subscriptions` |
229
- | `lib/client.js` loader `id` | `@goodandready/dsh-subscriptions` |
195
+ ---
230
196
 
231
- ## License
197
+ ## 📄 License
232
198
 
233
- MIT
199
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
package/README.ru.md ADDED
@@ -0,0 +1,196 @@
1
+ # 📦 @goodandready/dsh-subscriptions
2
+
3
+ <div align="center">
4
+
5
+ <h3>Мост персональных подписок на ИИ, ротация пула аккаунтов и безопасный OAuth без утечки токенов для DeepSeek Harness</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-subscriptions"><img src="https://img.shields.io/npm/v/@goodandready/dsh-subscriptions.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/Все_проекты_автора-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="Все проекты автора"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a> •
21
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
22
+ </p>
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ⚡ Обзор
29
+
30
+ **`dsh-subscriptions`** подключает ваши платные персональные подписки на нейросети напрямую в **DeepSeek Harness** в качестве полноценных LLM-провайдеров.
31
+
32
+ Вместо поминутной оплаты дорогих API-ключей для повседневных задач агента, плагин позволяет авторизовать ваши существующие веб-подписки через безопасный протокол OAuth PKCE. Поддерживаются **пулы из нескольких аккаунтов** с автоматической ротацией при исчерпании лимитов, **упреждающее переключение квот** и **внутрипроцессный сервис Cordis (`ctx.subscriptions`)**, который питает соседние плагины (например, [`dsh-image-gen`](https://github.com/GooDAnDReaDY/dsh-image-gen) и [`dsh-grok-xsearch`](https://github.com/GooDAnDReaDY/dsh-grok-xsearch)) без утечки токенов в сеть.
33
+
34
+ ```mermaid
35
+ graph LR
36
+ subgraph DSHCore [Сессия диалога DeepSeek Harness]
37
+ Agent[🤖 Выполнение задач агентом] --> Router{Маршрутизатор провайдеров}
38
+ end
39
+
40
+ subgraph SubscriptionsCore [Ядро dsh-subscriptions]
41
+ Router --> Pool{Пул аккаунтов вендора}
42
+ Pool -->|Аккаунт 1| Acc1[👤 Основной аккаунт: Активен]
43
+ Pool -->|Аккаунт 2| Acc2[👤 Второй аккаунт: Ожидание]
44
+ Pool -->|Аккаунт 3| Acc3[👤 Запасной аккаунт: Cooldown]
45
+ Acc1 -->|HTTP 429 / Превышение квоты| Rotate[Умный ротатор квот и задержек]
46
+ Rotate -->|Перенаправление трафика| Acc2
47
+ end
48
+
49
+ subgraph VendorBridges [4 Адаптера вендоров]
50
+ Acc1 --> B1[Бэкенд ChatGPT / Codex]
51
+ Acc1 --> B2[Протокол Claude Pro / Max]
52
+ Acc1 --> B3[Подписки xAI / Grok]
53
+ Acc1 --> B4[Google Cloud Code Assist / Antigravity]
54
+ end
55
+
56
+ subgraph EcosystemBridge [Сервис Cordis: ctx.subscriptions]
57
+ Pool --> ImgGen[dsh-image-gen: Бесплатная генерация картинок]
58
+ Pool --> XSearch[dsh-grok-xsearch: Поиск в X Twitter]
59
+ end
60
+
61
+ style DSHCore fill:#1e1e2e,stroke:#89b4fa,stroke-width:2px,color:#cdd6f4
62
+ style SubscriptionsCore fill:#181825,stroke:#cba6f7,stroke-width:2px,color:#cdd6f4
63
+ style VendorBridges fill:#11111b,stroke:#a6e3a1,stroke-width:2px,color:#cdd6f4
64
+ style EcosystemBridge fill:#181825,stroke:#f38ba8,stroke-width:2px,color:#cdd6f4
65
+ ```
66
+
67
+ ---
68
+
69
+ ## ✨ Ключевые возможности
70
+
71
+ ### 1. 🌐 4 Поддерживаемых встроенных вендора подписок
72
+
73
+ | Ключ вендора | Тариф подписки | Протокол и возможности |
74
+ |---|---|---|
75
+ | `codex` | ChatGPT Plus / Pro | Стриминг Codex, вызов инструментов и генерация картинок (`/backend-api/codex/...`) |
76
+ | `claude` | Claude Pro / Max | Нативный протокол Claude Messages, трекинг расхода (`/v1/messages`, `/api/oauth/...`) |
77
+ | `grok` | xAI / X Premium | Ответы с рассуждениями, проверка баланса и поиск в соцсети |
78
+ | `antigravity` | Google Cloud Code Assist | Движок Antigravity (`/v1/loadCodeAssist`, `/v1/streamGenerateContent`) |
79
+
80
+ *Также поддерживается регистрация кастомных вендоров через фабрику профилей `createVendorFromProfile`.*
81
+
82
+ ---
83
+
84
+ ### 2. 🔄 Ротация аккаунтов и защита от лимитов (`rotate.js`, `ratelimit.js`)
85
+ * **Пулы из нескольких аккаунтов**: привязка нескольких аккаунтов на вендора (`CODEX_OAUTH_1`, `CODEX_OAUTH_2`...).
86
+ * **Автоматическое переключение при 429**: при превышении лимита запросов трафик мгновенно переключается на следующий свободный аккаунт.
87
+ * **Упреждающее переключение квот (`switchAtRemaining`)**: смена аккаунта до падения в ошибку, если окно сброса близко.
88
+ * **Динамический расчёт Cooldown**: парсинг заголовков `Retry-After`, `x-ratelimit-reset`, дат ISO и миллисекундных меток с автоматическим возвратом остывших аккаунтов в строй.
89
+
90
+ ---
91
+
92
+ ### 3. 🔒 Безопасность и авторизация на headless-серверах
93
+ * **Нулевая утечка токенов**: токен OAuth **никогда** не отдаётся в браузер или через публичный HTTP API. В интерфейсе видны только статус, имя и остаток квоты.
94
+ * **Хранилище хоста**: токены шифруются в `$DSH_HOME/.credentials.yaml`.
95
+ * **Вход без браузера (SSH / Remote)**: если сервер запущен удалённо, авторизацию можно завершить, просто вставив итоговый redirect URL или authorization code в карточку аккаунта.
96
+ * **Фоновое продление токенов**: плагин автоматически обновляет токены до истечения их срока действия.
97
+
98
+ ---
99
+
100
+ ### 4. 🧩 Внутрипроцессный сервис Cordis (`ctx.subscriptions`)
101
+ Другие плагины могут использовать подключенные подписки напрямую в памяти:
102
+ ```javascript
103
+ // Пример вызова из dsh-image-gen:
104
+ const res = await ctx.subscriptions.request('codex', '/backend-api/codex/images/generations', {
105
+ method: 'POST',
106
+ body: JSON.stringify({ prompt: 'Cyberpunk landscape', size: '1024x1024' }),
107
+ })
108
+ ```
109
+ * **Нулевой оверхед**: прямое общение без лишних HTTP-запросов.
110
+ * **Белый список путей (`ALLOWLIST`)**: строгий контроль вызываемых эндпоинтов для защиты от SSRF.
111
+
112
+ ---
113
+
114
+ ### 5. 🔐 Вход без браузера: loopback и device-код (`v0.4.9`)
115
+ * **Автоматический loopback-callback (`autoLoopback`, включён по умолчанию)**: если redirect_uri вендора — loopback-адрес (Codex `:1455`, Grok `:56121`), плагин сам поднимает временный локальный HTTP-сервер и ловит callback без ручной вставки ссылки. Ручная вставка остаётся как запасной путь.
116
+ * **Вход по коду устройства (Codex)**: на полностью headless-машинах нажмите **Device login** в карточке аккаунта Codex: плагин запросит короткий код на `auth.openai.com`, вы открываете `https://auth.openai.com/codex/device` с любого устройства, вводите код — плагин сам завершает стандартный PKCE-обмен.
117
+ * **Классические варианты на месте**: redirect на origin веб-интерфейса (`useWebCallback`) и ручная вставка адреса/кода доступны как раньше.
118
+
119
+ ### 6. 🌍 Индивидуальный HTTP/SOCKS-прокси на аккаунт (`v0.4.9`)
120
+ * **Прокси на слот (`proxyUrl`)**: каждый аккаунт принимает свой адрес `http://`, `https://`, `socks5://[user:pass@]host:port`. Через него идут все запросы аккаунта — обновление токенов, проверки вендора, запросы моделей. Пусто = прямое соединение.
121
+ * **Проверка в один клик**: кнопка **Check proxy** в карточке аккаунта делает реальный запрос к базовому URL вендора через прокси и показывает задержку или причину отказа.
122
+ * **Тайминги в истории**: каждая запись истории запросов теперь содержит длительность (`ms`) — удобно сравнивать прямое соединение и прокси.
123
+
124
+ ### 7. 🕶️ Режим приватности и диагностический отчёт (`v0.4.9`)
125
+ * **Маскирование (`privacyMask`)**: один тумблер в карточке настроек скрывает персональные данные во всём интерфейсе: email отображается как `j***n@example.com` (списки аккаунтов, статусы, результаты проверок). Маскирование выполняется на сервере — личные данные не утекут и через ответы API; сами данные аккаунтов при этом не перезаписываются. Задумано для демонстраций экрана и стримов.
126
+ * **Анонимизированный диагностический отчёт**: блок **Generate diagnostics report**: один клик — отчёт (версии плагина/рантайма, ОС, счётчики здоровья по вендорам, агрегаты HTTP-статусов, последние ошибки ≥400 с таймингами, не-секретные настройки) скачан и скопирован в буфер. Токены, email, имена учётных записей и адреса прокси исключены (покрыто тестами).
127
+ * **Готово для issue**: рядом ссылка на трекер задач — баг-репорт это «сгенерировать → вставить → отправить».
128
+
129
+ ### 8. 🔌 HTTP API (добавлено в `v0.4.9`)
130
+ | Маршрут | Метод | Назначение |
131
+ |---|---|---|
132
+ | `/dsh-subscriptions/diagnostics` | GET | Анонимизированный диагностический отчёт (без секретов, токенов и адресов прокси) |
133
+ | `/dsh-subscriptions/proxy-check` | POST | Проверка задержки прокси слота через базовый URL вендора |
134
+ | `/dsh-subscriptions/oauth/device/start` | POST | Начать вход Codex по коду устройства (возвращает код и адрес подтверждения) |
135
+ | `/dsh-subscriptions/oauth/device/poll` | POST | Опрос статуса авторизации по коду устройства |
136
+
137
+ ---
138
+
139
+ ### 9. 🦛 Локальный шлюз Ollama и бесшовный фолбэк (`v0.4.17`)
140
+ * **Нативный провайдер (`ollama`)**: если локальный Ollama доступен по `ollamaBaseUrl` (по умолчанию `http://127.0.0.1:11434`), он появляется в нативном селекторе моделей DSH с моделями из `/api/tags`. Ключ не нужен.
141
+ * **Бесшовный фолбэк (`ollamaFallback`, включён по умолчанию)**: когда все аккаунты провайдера исчерпаны (или недоступны) и ещё ничего не выведено, чат продолжается на локальной модели (`ollamaFallbackModel`, либо первая из `/api/tags`). Фолбэк пишется в журнал и в историю запросов как `kind: fallback`.
142
+ * **Бесплатный ($0) аварийный путь**: работает без интернета и без квот — удобно для офлайн-демо.
143
+
144
+ ### 10. ⚡ Effort, Verbosity и Fast Mode (`v0.4.17`)
145
+ * **Уровень рассуждений (Effort)**: модели Codex объявляют поддерживаемые уровни из живого каталога; нативный селектор валидирует выбор, и выбранный уровень передаётся как `reasoning.effort` в протокол `/responses`. Grok передаёт effort со своей каталог-осознанной фильтрацией.
146
+ * **Детализация (`codexVerbosity`)**: `low` / `medium` / `high` передаётся как `text.verbosity` для reasoning-моделей Codex. Пусто = дефолт протокола.
147
+ * **Fast Mode (`codexFastMode`)**: c каждым Codex-запросом передаётся `service_tier: priority` (платный скоростной тир 1.5x). В чипе активной подписки при включённом режиме отображается `⚡`.
148
+
149
+ ### 11. 🚦 Кулдауны по семействам и фильтрация моделей (`v0.4.17`)
150
+ * **Reasoning vs Standard**: 429 на reasoning-модели (claude `*thinking*`, grok `*reasoning*`, все codex-модели) охлаждает только семейство reasoning этого аккаунта — standard-модели того же аккаунта продолжают работать. Legacy-кулдауны (от старых версий) по-прежнему блокируют весь аккаунт до истечения.
151
+ * **Скрыть устаревшие модели (`hideDeprecatedModels`)**: убирает из нативного селектора id с `test`/`preview`/`dev`/`alpha`/`beta`/`legacy` (действует и на живые каталоги, и на статичный фолбэк).
152
+
153
+ ---
154
+
155
+ ## 📦 Быстрая установка
156
+
157
+ ```bash
158
+ dsh plugin --profile web add @goodandready/dsh-subscriptions
159
+ ```
160
+
161
+ ---
162
+
163
+ ## ⚙️ Пример конфигурации (`settings.yaml`)
164
+
165
+ ```yaml
166
+ dsh-subscriptions:
167
+ switchAtRemaining: 1
168
+ cooldownMs: 60000
169
+ autoLoopback: true # v0.4.9: автоматически ловить loopback-callback
170
+ privacyMask: false # v0.4.9: маскировать email и учётные записи в UI
171
+ ollamaBaseUrl: http://127.0.0.1:11434 # v0.4.17: локальный шлюз Ollama
172
+ ollamaFallback: true # v0.4.17: бесшовный фолбэк при исчерпании всех аккаунтов
173
+ ollamaFallbackModel: '' # v0.4.17: например qwen2.5-coder; пусто = первая модель из /api/tags
174
+ hideDeprecatedModels: false # v0.4.17: фильтровать test/preview/beta/legacy id моделей
175
+ codexVerbosity: '' # v0.4.17: low | medium | high (text.verbosity)
176
+ codexFastMode: false # v0.4.17: service_tier priority (скоростной тир 1.5x)
177
+ # Поля слота (v0.4.9): expiresAt (ms), proxyUrl (http/https/socks5://)
178
+ accounts:
179
+ codex:
180
+ - ref: CODEX_OAUTH_1
181
+ label: "Рабочий Pro-аккаунт"
182
+ - ref: CODEX_OAUTH_2
183
+ label: "Личный Plus-аккаунт"
184
+ claude:
185
+ - ref: CLAUDE_OAUTH_1
186
+ label: "Claude Max"
187
+ grok:
188
+ - ref: GROK_OAUTH_1
189
+ label: "X Premium"
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 📄 Лицензия
195
+
196
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)