@operatingtag/dsh-unclesam 1.0.0 → 1.0.1

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,7 +1,10 @@
1
- # Uncle Sam — a harness model provider that drives chat.deepseek.com
1
+ **English** · [Español](README.es.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [Português](README.pt.md) · [Italiano](README.it.md) · [Türkçe](README.tr.md) · [한국어](README.ko.md) · [日本語](README.ja.md) · [简体中文](README.zh.md) · [Русский](README.ru.md) · [Polski](README.pl.md) · [हिन्दी](README.hi.md) · [Nederlands](README.nl.md) · [Українська](README.uk.md) · [Tiếng Việt](README.vi.md) · [Bahasa Indonesia](README.id.md)
2
2
 
3
- **☕ [Buy me a coffee](https://revolut.me/operatingtag)** — this is written by one person, at night, funded by
4
- nothing. There is no other revenue model. A star or a bug report is worth just as much.
3
+ # Uncle Sam
4
+
5
+ **A DeepSeek Harness provider that answers through your own browser, on your existing web account, instead of the billed API.**
6
+
7
+ **☕ [Buy me a coffee](https://revolut.me/operatingtag)** — written by one person, at night, funded by nothing. There is no other revenue model. A star or a bug report is worth just as much.
5
8
 
6
9
  > **This product is ongoing and under active development. Expect bugs.**
7
10
  >
@@ -9,38 +12,41 @@ nothing. There is no other revenue model. A star or a bug report is worth just a
9
12
  > depends on a website that changes without telling anyone. If something breaks, a screenshot and the version
10
13
  > number is worth more than a description. Pin a version if you depend on it.
11
14
 
12
- ## Contents
13
-
14
- - [Installing](#installing)
15
- - [Why it is built this way](#why-it-is-built-this-way)
16
- - [Architecture](#architecture)
17
- - [Tool use is emulated](#tool-use-is-emulated-and-that-is-a-real-limitation)
18
- - [Configuration](#configuration)
19
- - [The API-vs-web switch](#the-api-vs-web-switch)
20
- - [Testing](#testing)
21
- - [Licence](#licence)
22
-
23
- Not affiliated with DeepSeek. It drives their public web product exactly as a person would.
24
-
25
- Adds **`deepseek-web`** as a model provider. A real browser answers each call, so the model runs on the
26
- web account already open in a tab — no API key, no per-token billing.
27
-
28
- Replies from the web route are signed **🔴 Uncle Sam**. That name is a joke, not a claim: it marks which
29
- route answered, and API replies carry no signature at all.
30
-
31
15
  ```
32
16
  provider deepseek-web
33
17
  models deepseek-chat · deepseek-chat-search · deepseek-reasoner · deepseek-reasoner-search
18
+ cost nothing per token — it uses the subscription already open in your browser
34
19
  status ongoing development — expect bugs
35
20
  measured first token ~1.9 s · overhead ~0.6 s · a full turn in ~2.5 s
36
21
  ```
37
22
 
23
+ Replies from the web route are signed **🔴 Uncle Sam**. That name is a joke, not a claim: it marks which route
24
+ answered, and API replies carry no signature at all. You always know which of the two answered you.
25
+
26
+ ---
27
+
28
+ ## What it saves you
29
+
30
+ The API bills per token. The web product does not. This plugin registers `deepseek-web` as a model provider and
31
+ answers every call by driving `chat.deepseek.com` in a real browser — the page does the work, the browser holds
32
+ the session, and nothing is metered.
33
+
34
+ | | API route | Web route |
35
+ |---|---|---|
36
+ | Cost | per token, forever | nothing beyond the subscription |
37
+ | Speed | fast | ~2.5 s a turn, measured |
38
+ | Tool calling | native and reliable | emulated, works but weaker |
39
+ | Depends on | the API | a website that changes without notice |
40
+
41
+ **Both routes stay installed.** The model picker is the switch, so you can use the cheap one by default and
42
+ reach for the API when a task needs reliable tool use.
43
+
38
44
  ---
39
45
 
40
46
  ## Installing
41
47
 
42
48
  Uncle Sam is a **DeepSeek Harness plugin**. It does nothing outside the harness, because it registers a model
43
- provider, a host route and two client slots. Installing it into anything else will simply do nothing visible.
49
+ provider, a host route and two client UI slots.
44
50
 
45
51
  **Requirements**
46
52
 
@@ -50,12 +56,20 @@ provider, a host route and two client slots. Installing it into anything else wi
50
56
  | Browser | Brave recommended, Edge used automatically when Brave is absent |
51
57
  | Node | 22 or newer |
52
58
 
53
- **From a package registry, once published**
59
+ **From npm**
54
60
 
55
61
  ```bash
56
62
  pnpm add @operatingtag/dsh-unclesam
57
63
  ```
58
64
 
65
+ **From this repository**
66
+
67
+ ```bash
68
+ git clone https://github.com/operatingtag/dsh-unclesam
69
+ cd dsh-unclesam
70
+ pnpm install
71
+ ```
72
+
59
73
  Then add the bundle row to your profile so the harness loads it:
60
74
 
61
75
  ```yaml
@@ -65,109 +79,99 @@ Then add the bundle row to your profile so the harness loads it:
65
79
  name: '@operatingtag/dsh-unclesam'
66
80
  config:
67
81
  port: 9222
68
- defaultModel: deepseek-chat
82
+ defaultModel: deepseek-chat-search
69
83
  autoMinimise: true
70
84
  ```
71
85
 
72
- **From a folder**
73
-
74
- ```
75
- Settings → Plugins → install from a local path
76
- ```
77
-
78
- pointed at the folder containing `package.json`.
86
+ **Or from a folder:** Settings → Plugins → install from a local path, pointed at the folder holding
87
+ `package.json`.
79
88
 
80
- **What you should see afterwards**
81
-
82
- 1. **Settings → Uncle Sam** — a page with four status rows and a sign-in button.
83
- 2. **Under the chat box** — `● DeepSeek Harness` or `● Uncle Sam`, click to switch.
84
- 3. **The model list** — `deepseek-chat (web)` and `deepseek-reasoner (web)` beside the API models.
85
-
86
- **First run**
89
+ ### First run
87
90
 
88
91
  Click **Sign in / open chat**. The browser opens and **stays visible** until you have signed in at
89
92
  chat.deepseek.com. After that it minimises itself and you will not see it again. The session lives in your
90
- browser profile, so no password is stored by the plugin.
93
+ browser profile, so **no password is stored by the plugin** — there is nothing to leak.
91
94
 
92
- **Removing it**
95
+ You should then see:
93
96
 
94
- ```
95
- Settings → Plugins → Uncle Sam → Uninstall
96
- ```
97
+ 1. **Settings → Uncle Sam** — a page with status rows and a sign-in button.
98
+ 2. **Under the chat box** — `● DeepSeek Harness` or `● Uncle Sam`, click to switch.
99
+ 3. **The model list** — four `(web)` models beside the API models.
97
100
 
98
- Nothing else is written outside the browser profile you signed in to.
101
+ ### Removing it
99
102
 
100
- ---
103
+ Settings → Plugins → Uncle Sam → Uninstall. Nothing is written outside the browser profile you signed in to.
101
104
 
102
- ## Why it is built this way
105
+ ---
103
106
 
104
- The obvious route — call `chat.deepseek.com`'s own HTTP API — was attempted and abandoned, because the
105
- site makes every message clear two gates:
107
+ ## The API / web switch
106
108
 
107
- | Gate | What it means |
108
- |---|---|
109
- | `/api/v0/chat/create_pow_challenge` | a **proof-of-work** challenge per message |
110
- | `challenges.cloudflare.com/turnstile` | a bot gate on the origin |
109
+ **The model picker is the switch.** There is no second control, because a second control that also chose the
110
+ model would be two sources of truth for one decision.
111
111
 
112
- Re-implementing either is a losing game: they are obfuscated, they change, and when they change the
113
- failure looks exactly like a network fault. **The page already solves both for its own requests.**
112
+ | Pick this model | Route | DeepThink | Search |
113
+ |---|---|---|---|
114
+ | `DeepSeek Chat (web)` | browser | off | off |
115
+ | `DeepSeek Chat + Search (web)` | browser | off | **on** |
116
+ | `DeepSeek Reasoner (web)` | browser | **on** | off |
117
+ | `DeepSeek Reasoner + Search (web)` | browser | **on** | **on** |
118
+ | any model without `(web)` | the API | — | — |
114
119
 
115
- So the adapter never speaks HTTP to the site. It drives the page, and the page does the rest. Auth, PoW
116
- and Turnstile stop being our problem and cannot break independently of the site itself.
120
+ A **WEB** or **API** badge renders beside the model label so the active route is visible at a glance. When the
121
+ label is not recognised the badge renders nothing rather than guessing — a wrong badge is worse than none.
117
122
 
118
- **Verified:** a plain `HEAD` to the site returns `403`; the browser path returns answers.
123
+ Your choice persists across restarts. **DeepThink** is the reasoning pass; **Search** lets it read the live web.
119
124
 
120
- ---
125
+ ### Search is visible in the transcript
121
126
 
122
- ## Architecture
127
+ With a search model, a turn produces **two blocks** — the query it searched with, the sources it found, then
128
+ the answer that used them:
123
129
 
124
130
  ```
125
- index.js the adapter: harness StreamChunk ←→ engine
126
- lib/engine.mjs browser + page: type, send, stream, settle
127
- lib/cdp.mjs Chrome DevTools Protocol client, zero dependencies
128
- lib/prompt.mjs flatten messages + tools into one message; recover tool calls from the reply
131
+ Web search — "What is one technology news headline from today?"
132
+ Sources (4): yna.co.kr · fnnews.com · rthk.hk · sina.com.cn
133
+ Links: https://k.sina.com.cn/article_... http://www.21jingji.com/article_...
129
134
  ```
130
135
 
131
- Nothing is installed as a dependency. Node 24 ships a global `WebSocket` and `fetch`, which is all CDP
132
- needs, so the token stream never leaves the host process and there is no IPC hop per delta.
136
+ The page does not expose the query it typed internally, so the quoted query is the prompt that triggered the
137
+ search. Sources and links are read from the page once the answer settles. Because sources only exist at the
138
+ end, **search turns buffer instead of streaming**; ordinary turns still stream token by token.
133
139
 
134
- ### The four failures that shaped the code
140
+ ---
135
141
 
136
- Each of these was observed, not anticipated, and each is now guarded by a comment at the site.
142
+ ## Why a browser, and not their HTTP API
137
143
 
138
- 1. **The answer arrived with the previous answer glued to the front.** The reader took the last
139
- "message-ish" block, and after a failed *New chat* click the previous transcript was still there.
140
- Fixed twice over: the reset is now *verified* (count of assistant blocks must reach zero), and the
141
- reader takes a **baseline index** so only blocks created after the prompt can ever be returned.
144
+ The obvious route — calling `chat.deepseek.com`'s own API — was attempted and abandoned. The site makes every
145
+ message clear two gates:
142
146
 
143
- 2. **The answer was emitted twice.** The DOM held it once; the adapter's fallback branch re-emitted the
144
- whole text for a non-prefix change and the consumer appended it. Deltas now emit **only characters
145
- not yet sent**, computed by longest common prefix. A streaming adapter may never resend text.
147
+ | Gate | What it means |
148
+ |---|---|
149
+ | `/api/v0/chat/create_pow_challenge` | a **proof-of-work** challenge per message |
150
+ | `challenges.cloudflare.com/turnstile` | a bot gate on the origin |
146
151
 
147
- 3. **A `zoompan`-style trap in miniature:** `waitFor` called its probe without a catch, so waiting for the
148
- browser's debug port died on the first `fetch failed` — the normal state for several seconds.
149
- A throw inside the poll now means "not ready yet".
152
+ Re-implementing either is a losing game: they are obfuscated, they change, and when they change the failure
153
+ looks exactly like a network fault. **The page already solves both for its own requests.**
150
154
 
151
- 4. **The tool call JSON leaked into the transcript.** Tool calls are JSON, so a reply beginning with `{`
152
- or a fence is now *buffered*; prose streams immediately, and only a buffered JSON reply is turned
153
- into a tool call. `committed text == concatenated deltas` is asserted in the test.
155
+ So the adapter never speaks HTTP to the site. It drives the page, and the page does the rest. Auth,
156
+ proof-of-work and Turnstile stop being our problem and cannot break independently of the site itself.
154
157
 
155
- ---
158
+ **Verified:** a plain `HEAD` to the site returns `403`; the browser path returns answers.
156
159
 
157
- ## Tool use is emulated, and that is a real limitation
160
+ ---
158
161
 
159
- A web chat has no structured tool channel. Tools are described in the prompt, and a call is recovered by
160
- parsing a JSON object out of the reply:
162
+ ## Limits, stated honestly
161
163
 
162
- ```
163
- {"tool": "get_weather", "arguments": {"city": "Madrid"}}
164
- ```
164
+ **Tool use is emulated.** A web chat has no structured tool channel, so tools are described in the prompt and
165
+ a call is recovered by parsing a JSON object out of the reply. It works — verified — but it is weaker than
166
+ native tool calling: a model that ignores the instruction answers in prose, and the harness sees no tool use
167
+ that turn. **For heavy agentic work the API route is more reliable.** The web route is best for chat, long
168
+ answers, subagents, compaction, and any turn where the model must be the web model.
165
169
 
166
- **This works** — verified returning `get_weather({"city":"Madrid"})` with `finish: tool-calls`.
170
+ **It depends on a website you do not control.** When the page changes shape, the plugin has to change with it.
171
+ That is the ongoing-development warning at the top of this page, not a formality.
167
172
 
168
- **But it is weaker than native tool calling.** A model that ignores the instruction answers in prose, and
169
- the harness sees no tool use that turn. For heavy agentic work the API provider is more reliable; this
170
- provider is best for chat, subagents, compaction, and any turn where the model must be the *web* model.
173
+ **It is not affiliated with DeepSeek.** It is not endorsed by them, and it gives you no rights in their
174
+ service. Your use of that service is governed by their terms.
171
175
 
172
176
  ---
173
177
 
@@ -178,102 +182,35 @@ provider is best for chat, subagents, compaction, and any turn where the model m
178
182
  | key | default | meaning |
179
183
  |---|---|---|
180
184
  | `port` | `9222` | the browser's debugging port |
181
- | `defaultModel` | `deepseek-chat` | used when a call names no model |
185
+ | `defaultModel` | `deepseek-chat-search` | used when a call names no model |
182
186
  | `showBrowser` | `true` | whether the window is visible while it works |
183
187
 
184
- The browser must hold a signed-in `chat.deepseek.com` session. The first call launches Brave on the
185
- **Default** profile if the port is not already open. If Brave is already running *without* a debugging
186
- port, the adapter cannot attach and reports that clearly.
188
+ The browser must hold a signed-in `chat.deepseek.com` session. The first call launches Brave on the **Default**
189
+ profile if the port is not already open. If Brave is already running *without* a debugging port, the adapter
190
+ cannot attach, and says so clearly rather than failing silently.
187
191
 
188
192
  ---
189
193
 
190
- ## The API-vs-web switch
191
-
192
- **The model picker is the switch.** There is no second control, because a second control that also
193
- chose the model would be two sources of truth for one decision.
194
-
195
- | Pick this model | Provider | DeepThink | Search |
196
- |---|---|---|---|
197
- | `DeepSeek Chat (web)` | browser | off | off |
198
- | `DeepSeek Chat + Search (web)` | browser | off | **on** |
199
- | `DeepSeek Reasoner (web)` | browser | **on** | off |
200
- | `DeepSeek Reasoner + Search (web)` | browser | **on** | **on** |
201
- | any model without `(web)` | the API | — | — |
202
-
203
- A **WEB** or **API** badge renders beside the model label so the active route is visible at a glance.
204
- When the label is not recognised the badge renders nothing rather than guessing — a wrong badge would
205
- be worse than none.
206
-
207
- ### Search is visible in the transcript
208
-
209
- With a search model, a turn produces **two blocks**:
194
+ ## Architecture
210
195
 
211
196
  ```
212
- Web search — "What is one technology news headline from today?"
213
- Sources (4): yna.co.kr · fnnews.com · rthk.hk · sina.com.cn
214
- Links: https://k.sina.com.cn/article_... http://www.21jingji.com/article_...
215
- ```
216
-
217
- then the answer that used them. The page does not expose the query it typed internally, so the quoted
218
- query is the prompt that triggered the search; the sources and links are read from the page after the
219
- answer settles, from the `cdn.deepseek.com/site-icons/<domain>` favicons and the external citation
220
- anchors. Because the sources only exist once the answer is finished, **search turns buffer instead of
221
- streaming**; non-search turns still stream token by token.
222
-
223
- ### The two switches
224
-
225
- `DeepThink` is the reasoning pass; `Search` lets it read the live web. Both are per-conversation and are
226
- cleared by *New chat*, which is why the engine sets them **after** the reset and **before** typing. They
227
- are also re-read after clicking, because a click is a request rather than a result.
228
-
229
- ---
230
-
231
- ## Testing
232
-
233
- ```bash
234
- node test-adapter.mjs # prose path: contract checks
235
- node test-adapter.mjs --tools # tool path: JSON must not reach the text channel
236
- node test-search-adapter.mjs # search path: two blocks, query + sources + answer
237
- node test-engine.mjs "prompt" # raw engine timings
238
- DEBUG_WEB_CHAT=1 node test-engine.mjs "prompt" # per-poll trace
197
+ index.js the adapter: harness StreamChunk ←→ engine
198
+ lib/engine.mjs browser + page: type, send, stream, settle
199
+ lib/cdp.mjs Chrome DevTools Protocol client, zero dependencies
200
+ lib/prompt.mjs flatten messages + tools into one message; recover tool calls from the reply
201
+ lib/savings.mjs what the web route saved you, priced against the API
202
+ lib/i18n.mjs 51 languages for the panel
239
203
  ```
240
204
 
241
- `test-adapter.mjs` enforces the three rules that matter: a block is opened before any delta, exactly one
242
- terminal `finish`, and committed text equals the concatenated deltas.
243
-
244
- ---
245
-
246
- ## Verification status
247
-
248
- | Claim | Evidence |
249
- |---|---|
250
- | Engine drives the page end to end | measured across several prompts |
251
- | Adapter emits a valid chunk sequence | `test-adapter.mjs` — **passes** |
252
- | Search emits query + sources + answer | `test-search-adapter.mjs` — **passes**, 4 domains + links, 5.0 s |
253
- | Tool emulation recovers a call | **passes**, `get_weather({"city":"Madrid"})` |
254
- | Bundle installs and activates | `application: applied`, v1.1.0 |
255
- | Row composed into the profile | present in `dsh.profile.bundles` |
256
- | Client half present with `dsh.client` | `client.js` + `platform: web`, `inject` conversation UI |
257
- | **Model selectable in the GUI** | **not visually verified** — the Web UI answers a bare origin with `dsh web authentication required; reopen the URL printed by dsh web`, and that URL is not recoverable from this session |
258
- | **The WEB/API badge rendered** | **not visually verified** — same reason |
259
- | **A live harness turn** | **not run** — needs a model selected in the picker |
260
-
261
- The last three need the harness restarted by the user and one model chosen; they cannot be closed from
262
- inside the running session.
263
-
264
- ---
265
-
266
- ## Changelog
267
-
268
- Every released version, newest first, in [CHANGELOG.md](CHANGELOG.md).
205
+ **No dependencies.** Node 24 ships a global `WebSocket` and `fetch`, which is all CDP needs, so the token
206
+ stream never leaves the host process and there is no IPC hop per delta.
269
207
 
270
208
  ---
271
209
 
272
210
  ## Support
273
211
 
274
- Uncle Sam exists to stop you paying per token. If it has saved you money, and you would like to see the
275
- next one built on hardware that does not run out of memory halfway through, you are welcome to buy me a
276
- coffee:
212
+ Uncle Sam exists so you stop paying per token. If it saved you money, and you would like to see the next one
213
+ built on hardware that does not run out of memory halfway through:
277
214
 
278
215
  **[☕ revolut.me/operatingtag](https://revolut.me/operatingtag)**
279
216
 
@@ -289,67 +226,36 @@ Copyright (c) 2026 Darren T. Weldon, published under the Operating Tag name.
289
226
  **The whole deal, in one line: install it and use it, personally, for free. Do not change it, do not share
290
227
  it, do not sell it, and do not use it in a business.**
291
228
 
292
- That is not open source, and it does not pretend to be. It is a free personal-use grant over software you may
293
- not copy or modify.
294
-
295
- ### What you may do
229
+ That is not open source, and it does not pretend to be.
296
230
 
297
231
  ```
298
- install it from its official source and run it
299
- use it for personal, non-commercial purposes
300
- read the source to understand how it works
301
- keep it installed for as long as you like
232
+ you may install it and run it · use it personally, non-commercially
233
+ read the source to understand it
234
+
235
+ you may not modify, adapt or create a derivative of it
236
+ copy, distribute, publish, mirror or make it available to anyone
237
+ upload it to any code host, registry, website, forum or chat
238
+ sell, resell, rent, or charge for it or for access to it
239
+ bundle it into anything you supply to another person
240
+ use it for any commercial purpose, or in the course of a business
302
241
  ```
303
242
 
304
- ### What you may not do
243
+ **The only two legitimate sources are this repository and the npm package
244
+ [`@operatingtag/dsh-unclesam`](https://www.npmjs.com/package/@operatingtag/dsh-unclesam).** A copy from
245
+ anywhere else is not licensed, whoever supplied it. If you see this software for sale, it is not being sold by
246
+ its author.
305
247
 
306
- ```
307
- modify, adapt, translate or create a derivative of it
308
- copy, distribute, publish, mirror or make it available to anyone else
309
- upload it to any code host, registry, website, forum or chat
310
- sell, resell, rent, or charge for it or for access to it
311
- bundle it into anything you supply to another person
312
- use it for any commercial purpose, or in the course of a business
313
- ```
314
-
315
- ### The official sources
316
-
317
- **Exactly two places** may legitimately supply this software:
318
-
319
- ```
320
- the GitHub repository operated by Operating Tag
321
- the npm package @operatingtag/dsh-unclesam
322
- ```
323
-
324
- A copy from anywhere else is not licensed, whoever supplied it. **If you see this software for sale, it is not
325
- being sold by its author.**
326
-
327
- ### If you need more than that
328
-
329
- Commercial use, and the right to modify and distribute, are available under a **separate written licence**.
248
+ **Commercial use, and the right to modify and distribute, are available under a separate written licence.**
330
249
  Ask Operating Tag and you will get a straight answer and a clear price.
331
250
 
332
- The [LICENSE](LICENSE) file is what actually governs, and it opens with the same summary in plain English
333
- before the licence text.
334
-
335
- ### The ask
336
-
337
- This is written by one person, at night, funded by nothing. Fifty-one languages were written out by hand and
338
- each was tested until it behaved. There is no other revenue model.
339
-
340
- If it saved you money or an afternoon:
341
-
342
- **[☕ revolut.me/operatingtag](https://revolut.me/operatingtag)**
343
-
344
- That is a **request, not a condition.** It carries no legal weight, and ignoring it changes nothing about your
345
- rights.
251
+ The [LICENSE](LICENSE) file governs, and it opens with the same summary in plain English.
346
252
 
347
253
  ---
348
254
 
349
- Uncle Sam is an independent plugin. It is not affiliated with, endorsed by, or supported by DeepSeek.
255
+ Uncle Sam is an independent plugin. Not affiliated with, endorsed by, or supported by DeepSeek.
350
256
 
351
257
  ```
352
- @operatingtag/dsh-unclesam v1.0.0
258
+ @operatingtag/dsh-unclesam v1.0.1
353
259
  Author Operating Tag
354
260
  Licence CC BY-NC-ND 4.0 — free to use, not to change, share or sell
355
261
  ```