@operatingtag/dsh-unclesam 0.0.0-stage → 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.
Files changed (83) hide show
  1. package/CHANGELOG.md +928 -0
  2. package/LICENSE +144 -0
  3. package/README.de.md +274 -0
  4. package/README.es.md +268 -0
  5. package/README.fr.md +272 -0
  6. package/README.hi.md +263 -0
  7. package/README.id.md +264 -0
  8. package/README.it.md +268 -0
  9. package/README.ja.md +263 -0
  10. package/README.ko.md +258 -0
  11. package/README.md +260 -2
  12. package/README.nl.md +266 -0
  13. package/README.pl.md +266 -0
  14. package/README.pt.md +265 -0
  15. package/README.ru.md +269 -0
  16. package/README.tr.md +265 -0
  17. package/README.uk.md +265 -0
  18. package/README.vi.md +263 -0
  19. package/README.zh.md +248 -0
  20. package/client.js +1099 -0
  21. package/cordis.patch.yml +48 -0
  22. package/icon.svg +17 -0
  23. package/index.js +1414 -0
  24. package/install.cmd +43 -0
  25. package/install.ps1 +311 -0
  26. package/lib/cdp.mjs +247 -0
  27. package/lib/engine.mjs +1412 -0
  28. package/lib/i18n.mjs +141 -0
  29. package/lib/prefs.mjs +101 -0
  30. package/lib/prompt.mjs +498 -0
  31. package/lib/savings.mjs +131 -0
  32. package/locale/ar.json +98 -0
  33. package/locale/az.json +98 -0
  34. package/locale/bg.json +98 -0
  35. package/locale/bn.json +98 -0
  36. package/locale/cs.json +98 -0
  37. package/locale/da.json +98 -0
  38. package/locale/de.json +98 -0
  39. package/locale/el.json +98 -0
  40. package/locale/en.json +98 -0
  41. package/locale/es.json +98 -0
  42. package/locale/fa.json +98 -0
  43. package/locale/fi.json +98 -0
  44. package/locale/fr.json +98 -0
  45. package/locale/he.json +98 -0
  46. package/locale/hi.json +98 -0
  47. package/locale/hr.json +98 -0
  48. package/locale/hu.json +98 -0
  49. package/locale/id.json +98 -0
  50. package/locale/it.json +98 -0
  51. package/locale/ja.json +98 -0
  52. package/locale/ka.json +98 -0
  53. package/locale/kk.json +98 -0
  54. package/locale/km.json +98 -0
  55. package/locale/ko.json +98 -0
  56. package/locale/lt.json +98 -0
  57. package/locale/mr.json +98 -0
  58. package/locale/ms.json +98 -0
  59. package/locale/my.json +98 -0
  60. package/locale/ne.json +98 -0
  61. package/locale/nl.json +98 -0
  62. package/locale/no.json +98 -0
  63. package/locale/pl.json +98 -0
  64. package/locale/pt.json +98 -0
  65. package/locale/ro.json +98 -0
  66. package/locale/ru.json +98 -0
  67. package/locale/si.json +98 -0
  68. package/locale/sk.json +98 -0
  69. package/locale/sl.json +98 -0
  70. package/locale/sr.json +98 -0
  71. package/locale/sv.json +98 -0
  72. package/locale/sw.json +98 -0
  73. package/locale/ta.json +98 -0
  74. package/locale/te.json +98 -0
  75. package/locale/th.json +98 -0
  76. package/locale/tl.json +98 -0
  77. package/locale/tr.json +98 -0
  78. package/locale/uk.json +98 -0
  79. package/locale/ur.json +98 -0
  80. package/locale/uz.json +98 -0
  81. package/locale/vi.json +98 -0
  82. package/locale/zh.json +98 -0
  83. package/package.json +89 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,928 @@
1
+ # Changelog
2
+
3
+ All notable changes to Uncle Sam, newest first.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions use
6
+ [semantic versioning](https://semver.org/): breaking behaviour changes bump the major, features the minor,
7
+ fixes the patch.
8
+
9
+ ---
10
+
11
+ ## 1.0.1
12
+
13
+ **The tool line no longer tells the website what is installed on your machine.**
14
+
15
+ MEASURED, on screen, by the person using it: every chat turn was typing this into the box, above their own
16
+ sentence -
17
+
18
+ Tools: ask_user_question, cordis_inspect_list, cordis_inspect_query, create_goal,
19
+ demergo_brave, demergo_busy, demergo_click, demergo_clipboard, demergo_cursor,
20
+ demergo_drag, demergo_elements, demergo_glide, +282 more
21
+
22
+ That list was real. It was the harness's tool inventory for the session - 283 tools, including a separate
23
+ screen-control plugin installed on the same machine - and because a web chat has no system channel, every
24
+ word of it was typed into `chat.deepseek.com` and sent to a third party. An inventory of a private computer
25
+ leaving the computer, on every turn, for no benefit.
26
+
27
+ - The preamble now states a **count** and the call format, and names nothing:
28
+
29
+ [283 tools available · to call one reply only with {"tool":"name","arguments":{}}]
30
+
31
+ - **Proved by test, not by intention.** `dev/test-preamble.mjs` asserts that no tool name reaches the prompt
32
+ on either a greeting or a real task, using real names from this machine (`demergo_`, `cordis_`,
33
+ `ask_user_question`) plus a synthetic set. A name leaking back in fails the suite.
34
+ - **The call format survives verbatim**, because without it the model answers in prose instead of emitting a
35
+ call. Live tool use re-tested after the change - a call still happens.
36
+ - Things that had to change with it: the panel's "last thing sent" view recognised the old `Tools: ` label,
37
+ and `test-answer-language.mjs` asserted it. Both now recognise the new wording. The suite caught the second
38
+ one; it was not spotted by reading.
39
+
40
+ Honest loss: a model can no longer browse the catalogue and pick a tool nobody told it about. On a turn where
41
+ the harness attaches tools, their names must still be sent - a model cannot call a tool it has never heard of.
42
+ This only affects the turn where no particular tool is being offered.
43
+
44
+ ---
45
+
46
+ ## 3.9.17
47
+
48
+ **A page that is thinking is not a page that has died.**
49
+
50
+ MEASURED, by the person reading Brave: a request for about a thousand words was answered, and the plugin
51
+ abandoned it after five silent seconds with "no text arrived". The page had not been silent - it was writing
52
+ its reasoning into a Thinking block, which is a different element from the answer the reader watches. From
53
+ inside the plugin that looked exactly like a dead page. Three earlier theories blamed the website; the
54
+ screenshot showed the answer.
55
+
56
+ - The reader now also samples the page's total text length. The answer element still decides what is emitted,
57
+ but any growth anywhere in the document counts as a sign of life and resets the pause clock. This is
58
+ deliberately blunt: it needs no knowledge of the reasoning element's class name, which the site can rename
59
+ at will.
60
+ - The change is strictly permissive. The sign of life can only ever delay a stall from being declared; it can
61
+ never cause one. Nothing about what reaches the transcript changed - the reasoning is still excluded, and the
62
+ live test confirms no reasoning text appears in the answer.
63
+
64
+ New: `dev/test-paced-think.mjs` - one case on `deepseek-reasoner`, the model whose state is DeepThink on, so
65
+ the page thinks before it answers. Two runs, both correct, both clean of reasoning text.
66
+
67
+ Honest limitation: the exact thousand-word case was not re-run, because a reply that long cannot finish inside
68
+ the one-minute rule. The mechanism is covered by the two shorter thinking runs and by the property above.
69
+
70
+ Tests: 14 suites green, npm run check clean.
71
+
72
+ ---
73
+
74
+ ## 3.9.16
75
+
76
+ **The savings figure can now show a small number.**
77
+
78
+ It printed two decimals, so anything under a cent read `$0.00` - which is exactly what a first test produces.
79
+ One turn of ordinary chat costs about a hundredth of a cent at the API's list rate, so a person could use this
80
+ for an evening and watch a counter that never left zero. A number that cannot move is worse than no number: it
81
+ reads as broken rather than as small.
82
+
83
+ one small turn $0.0001 -> 0.01c
84
+ a few turns $0.0042 -> 0.42c
85
+ one cent $0.01 -> $0.01
86
+ a session $0.42 -> $0.42
87
+ too small $0.000001 -> <0.01c
88
+ zero $0.00 -> 0.00c
89
+
90
+ Whole cents and above keep the familiar `$0.42`. Anything smaller is stated in cents, and anything smaller
91
+ still says `<0.01c` rather than pretending to be zero. Currencies other than USD have no cents convention
92
+ here, so they keep four decimals. Zero reports as zero rather than as a small positive, which can happen
93
+ legitimately when the configured rates are zero.
94
+
95
+ Tests: 14 suites green, npm run check clean.
96
+
97
+ ---
98
+
99
+ ## 3.9.15
100
+
101
+ **The coffee link moved out of the banner and into the Brave recommendation.**
102
+
103
+ It was pinned above the title, where it read as an advertisement and pushed the actual settings down the page.
104
+ It now sits immediately above the Brave recommendation, so the ask belongs to the same thought as the text
105
+ around it - this page is about which browser to use and why the work is worth supporting.
106
+
107
+ Still two links, still one destination: this one and the support block at the foot of the panel. A test
108
+ asserts the placement rather than merely its existence, so it cannot drift back to being a banner.
109
+
110
+ ---
111
+
112
+ ## 3.9.14
113
+
114
+ **Search tested against the real page for the first time - and the two faults that exposed.**
115
+
116
+ The search branch was the last surface with no live coverage. One paced case, model `deepseek-chat-search`:
117
+
118
+ 🔴 Uncle Sam Web search - "what is the latest stable version of Node.js?"
119
+ Sources (2): nodejs.org · ...
120
+ The latest stable version of Node.js is Node.js 26.13.0, codenamed 'Lithium'.
121
+
122
+ Two blocks, the person's own words as the query, real sources, the label, no tool envelope, 9.6 s.
123
+
124
+ - **The five-second pause limit was aborting every search.** MEASURED: the first run died at 5.1 s with
125
+ nothing on screen. A web search fetches before it writes, so silence there is the page working. A search
126
+ call now gets thirty seconds of silence before it is treated as dead; an ordinary message keeps the five
127
+ second rule unchanged. Both are overridable (`DSH_STALL_MS`, `DSH_SEARCH_STALL_MS`).
128
+ - **Search was left switched on after a call.** The plugin only ever turned the site's toggles on, never off,
129
+ so the next ordinary message would search the web without anybody asking - slower, and a silent change of
130
+ behaviour. Every switch the plugin turns on is now restored at the end of the call, and again at the start
131
+ of the next one if the call threw. A switch the person turned on themselves was never in that list, so it is
132
+ left exactly as they set it.
133
+
134
+ New: `dev/test-paced-search.mjs` - one case, sixty-second run limit, browser killed at the end, written
135
+ report.
136
+
137
+ NOT YET PUBLISHED to npm.
138
+
139
+ ---
140
+
141
+ ## 3.9.13
142
+
143
+ **A tool call on its own carried no signature, and the tool path is now tested against the real page.**
144
+
145
+ Two things, both found by running the surface that had never been run.
146
+
147
+ The tool-call path had no live coverage until now. Three cases that need a tool produced correct calls -
148
+ `read`, `glob`, `pwsh`, each with the right arguments - but every one of them came back with **no
149
+ `🔴 Uncle Sam` label**, because a call-only reply has no prose and the label was only written when there was
150
+ prose to write it beside. That breaks the one rule the label exists for. The label now goes out whenever a
151
+ token is a web one, with or without prose. A call is not an empty reply: something happened, so naming the
152
+ route above it is information rather than noise.
153
+
154
+ The pro se-beside-a-call shape - the one 3.9.8 fixed - was then exercised deliberately, by asking for a
155
+ sentence before the call. All three replies kept their prose intact to the final full stop:
156
+
157
+ "I'll read package.json now. " + read({"path":"package.json"})
158
+ "I'll list the files now. " + glob({"pattern":"*"})
159
+ "I'll run a command to print "hello". " + pwsh({"command":"Write-Output 'hello'"})
160
+
161
+ Before 3.9.8 those sentences lost their last characters to an offset error.
162
+
163
+ New: `dev/test-paced-tools.mjs` - four cases with real tool schemas attached, five seconds apart, a
164
+ five-second stall limit, a sixty-second run limit, the browser killed at the end, and a written report.
165
+
166
+ NOT YET PUBLISHED to npm.
167
+
168
+ ---
169
+
170
+ ## 3.9.12
171
+
172
+ **Back to MIT.**
173
+
174
+ The whole point of this plugin is that it costs nothing and asks nothing. A licence that turns a free tool into
175
+ a negotiation works against that, so the stricter licence is withdrawn and the coffee request takes its place.
176
+
177
+ - LICENSE is MIT, and it is a long one on purpose: the grant and the disclaimer first as the law needs them,
178
+ then a plain-English summary of the same thing, then an explicit list of what the licence does NOT ask for
179
+ (no royalties, no copyleft, no attribution in your UI, no patent grab, no revocation).
180
+ - **The coffee ask is in the licence file, and it is labelled as a request, not a condition.** MIT obliges
181
+ nobody to support the project, so the ask is set apart, says it carries no legal weight, and says that
182
+ ignoring it changes nothing. A test asserts both the link and that wording.
183
+ - The README leads with the one-line deal and keeps the same ask.
184
+ - All 204 source headers now declare MIT.
185
+ - **3.9.7 to 3.9.11 were published under the Business Source License 1.1 and those grants remain in force.**
186
+ The LICENSE and README both say so rather than implying the change reaches backwards.
187
+ - `dev/relicence.mjs` is deleted: it existed only to perform the opposite change, and leaving it would leave a
188
+ script whose job is to undo this decision.
189
+
190
+ Tests: 14 suites green, npm run check clean.
191
+
192
+ NOT YET PUBLISHED.
193
+
194
+ ---
195
+
196
+ ## 3.9.11
197
+
198
+ **The fourth reply in a chat was arriving and being thrown away.**
199
+
200
+ MEASURED, by the person watching the browser: the site answered the fourth message - they read the answer on
201
+ screen - while the plugin reported no text at all and abandoned the call as a stall. Three runs in a row
202
+ stalled on the fourth message and only the fourth, with different questions each time. A page that answered
203
+ cannot be a page that stalled, so the fault was in the reader.
204
+
205
+ Cause: "is this a new reply?" was decided by comparing the NUMBER of assistant blocks with the count taken
206
+ before sending. The site adds a `Thinking` block as the answer begins, and recycles earlier blocks, so the
207
+ count stops being a reliable signal after a few turns. The reader then either saw the reasoning block instead
208
+ of the answer, or concluded nothing new had appeared and returned empty.
209
+
210
+ - The baseline now records the shape of the last reply as well as how many there are, and a reply counts as
211
+ new when a block has been added OR the last block's text has changed. Length and tail are compared rather
212
+ than the whole text, so the injected expression stays small on a 70 ms poll.
213
+ - `readReply` reports whether it matched by growth or by replacement, which is what made this visible.
214
+ - The blank-chat check used by the fresh-chat path keeps a plain count, where it is correct.
215
+
216
+ Verified live, paced at five seconds, with the window on screen and watched while it ran:
217
+
218
+ 1/4 4417ms "Hello! How can I help you today?"
219
+ 2/4 1606ms "The capital of Australia is Canberra."
220
+ 3/4 2654ms "The three traditional primary colours…"
221
+ 4/4 2133ms "Goodbye, and take care!" <- the case that failed three runs running
222
+
223
+ Four of four, no stalls, browser killed, report written.
224
+
225
+ NOT YET PUBLISHED.
226
+
227
+ ---
228
+
229
+ ## 3.9.10
230
+
231
+ **Debugging, and a five-second pause limit.**
232
+
233
+ Driven by three runs that ended in a fault with nothing but terminal scrollback to explain them.
234
+
235
+ - **A pause longer than five seconds now abandons the call.** Measured from the last sign of life - a
236
+ character of the answer, or the page becoming ready - not from the start of the call, because launching a
237
+ browser is legitimately slow and must not look like a hang. The error carries code `STALLED` so a test can
238
+ tell it apart from a slow answer and stop cleanly. `DSH_STALL_MS` tunes it, floored at one second.
239
+ - **A stalled case stops the run** instead of moving to the next one, and the browser is killed at once.
240
+ - **`dev/report.mjs`** writes every case to `dev/reports/<run>-<stamp>.jsonl` and `.txt` AS it finishes,
241
+ so a run killed by the one-minute rule still explains what happened up to that point. Each row carries the
242
+ message, the reply, the elapsed time, the chunk count and the failure code.
243
+ - The paced English test now uses the reporter and the stall limit, and exits non-zero when anything failed.
244
+
245
+ NOT YET PUBLISHED.
246
+
247
+ ---
248
+
249
+ ## 3.9.9
250
+
251
+ **An empty assistant block could hold a call for ten minutes.**
252
+
253
+ MEASURED. A test call hung for over eight minutes. The page had created the assistant block, so the poll's
254
+ "is there a new block" test was true, but it never wrote a character into it. The no-reply guard lived INSIDE
255
+ the "no new block" branch, so that shape skipped the guard entirely and the loop ran to the ten-minute cap.
256
+ Anyone watching saw a spinner with no explanation.
257
+
258
+ - The guard is now evaluated on "has any text arrived", independently of whether a block exists.
259
+ - The stall counter counts an empty new block as no progress, so the page-active nudge can fire for it too.
260
+ - The error names the timeout that actually applied instead of a hard-coded 90 seconds.
261
+ - `DSH_FIRST_TOKEN_TIMEOUT_MS` overrides the grace period, so a test fails in twenty seconds instead of
262
+ ninety. A value below one second or a non-number is ignored, so a typo cannot disable the guard.
263
+
264
+ **New operating rule, from the person: no test may run longer than 60 seconds**, and the browsers it opened
265
+ must be killed when it stops. `dev/guard.mjs` enforces it - a 60-second deadline, browser cleanup on expiry,
266
+ on normal exit, on Ctrl-C and on a crash. Proven: a 3-second deadline in a 10-second script exited 124 having
267
+ killed the browser.
268
+
269
+ Also added: `dev/test-no-reply-guard.mjs` asserts the guard cannot be re-nested inside the branch that
270
+ bypassed it, and the paced English test that reproduced the stall.
271
+
272
+ NOT YET PUBLISHED.
273
+
274
+ ---
275
+
276
+ ## 3.9.8
277
+
278
+ **Words were being deleted from answers that contained a tool call.**
279
+
280
+ The tool branch worked out how much prose had not yet streamed by taking the scrubbed whole reply and slicing
281
+ it at an offset measured against the unscrubbed one. Scrubbing trims leading whitespace, so every newline the
282
+ model put before its sentence shifted the offset and the remainder started mid-word:
283
+
284
+ "\n\nHi. {…} more text here" came out as "Hi. ore text here"
285
+ " Hello there. {…} and then" came out as "Hello there. nd then"
286
+ "\n\n{…} trailing words" came out as "ailing words"
287
+
288
+ Models prefix prose with a newline constantly, so this was not rare - it was every tool-calling turn whose
289
+ reply was not flush left. The held slice is now scrubbed on its own, so the offset and the text always belong
290
+ to the same string. Four shapes are asserted in dev/test-tool-tail.mjs.
291
+
292
+ Also: a browser launch now records the call stack that asked for it, to browser-launches.log and to stderr
293
+ when DEBUG_WEB_CHAT is set. Four times tonight a browser appeared with the route on API and every explanation
294
+ was a theory; the next one will name its caller.
295
+
296
+ NOT YET PUBLISHED.
297
+
298
+ ---
299
+
300
+ ## 3.9.7
301
+
302
+ **Licence change: MIT to Business Source License 1.1.**
303
+
304
+ Free for individuals and for any organisation under GBP 250,000 annual revenue. Above that a commercial
305
+ licence is required, arranged through the issue tracker. Four years after each release it converts to the
306
+ Apache License 2.0 and becomes ordinary open source for everyone.
307
+
308
+ - LICENSE rewritten with the parameters; package.json declares BUSL-1.1.
309
+ - Every source header now declares BUSL-1.1. A new test fails the suite if any file still names the old
310
+ licence, so the LICENSE file and the code cannot drift apart.
311
+ - README explains the terms in plain English before the legal text.
312
+ - **Versions 3.9.6 and earlier remain MIT.** That grant is irrevocable and is not being withdrawn; this
313
+ licence starts at 3.9.7.
314
+
315
+ NOT YET PUBLISHED to npm.
316
+
317
+ ---
318
+
319
+ ## 3.9.6
320
+
321
+ **The ask is at the top, and the story now matches the work.**
322
+
323
+ - "BUY ME A COFFEE" is a link at the head of the panel as well as in the support block at the bottom. Same
324
+ destination, same words, drawn twice - a person who opens the page should not have to scroll to the end
325
+ to find out how to help.
326
+ - The support copy was rewritten in all 51 languages. It began as a provider that spoke English; it now
327
+ answers in fifty-one languages, and the text says so. The ask is stated as what the work actually takes:
328
+ an evening to add a language, several more to test it properly, and the part nobody sees.
329
+ - The copy implies the cost and never states it. No dollar amount, no day count - a test asserts that, so the
330
+ rule cannot drift when the text is edited later.
331
+
332
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
333
+
334
+ ---
335
+
336
+ ## 3.9.5
337
+
338
+ **Harness notices are no longer mistaken for the person's message.**
339
+
340
+ MEASURED, not guessed: in one real transcript, 1112 records carried `role: 'user'` but only 770 were typed
341
+ by the person. The other 342 were harness machinery filed under the same role - time context (163), runtime
342
+ context (58), model-selection notices (42), tool-job notices (41), the skill catalog (10), compaction
343
+ checkpoints (8), goal notes (7) and more.
344
+
345
+ - The recorded failure: the person switched from Web Chat to Web Reasoner+Search mid-conversation, and the
346
+ search query became "[model changed: assistant turns above this point were generated by …]". The search
347
+ found nothing, so the answer was written from memory while wearing a "Web search" heading.
348
+ - Only a message whose `source.kind` is `user` counts as the person speaking, in both the prompt builder
349
+ and the search-query picker. Messages with no source at all are still kept, so the API path is unaffected.
350
+ - A greeting no longer gets the tool list. "hola mi gran amigo" prompted "What would you like me to do? I
351
+ have a broad toolset available…" because the preamble invited it. A greeting carries no task, so no tool
352
+ can be the answer; a real request still gets the full tool line.
353
+ - When search is on and the page reports no sources, the reply now says the answer came from the model's
354
+ own memory rather than presenting it as researched.
355
+
356
+ Two of the plugin's own tests were asserting the old behaviour - a greeting with tools, and a tool line
357
+ above a "hola" - and were corrected rather than left to lock the bug in place.
358
+
359
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
360
+
361
+ ---
362
+
363
+ ## 3.9.4
364
+
365
+ **The language choice now survives a restart.**
366
+
367
+ - Reported: "I started harness and it was auto-set to english." The choice had been made and working; a
368
+ restart erased it, the panel silently reverted, and because the page is only told the language when a
369
+ choice exists, answers came back in English too.
370
+ - The choice is written to the harness profile's storage folder as it is made, and restored on load.
371
+ - Cleared choices persist as cleared; a missing, corrupt or read-only file falls back to defaults instead
372
+ of throwing; a write repairs a corrupt file.
373
+ - The dropdown shows what the host actually has. If no choice is stored it reads "auto", which is the
374
+ honest state - previously it could show Español while the page was told nothing.
375
+
376
+ MEASURED BEFORE FIXING: three prompt shapes were sent to the real page - the current one, an inline
377
+ instruction and a leading sentence. All three came back in Spanish, which proved the page obeys the
378
+ instruction and the fault was the lost setting, not the wording.
379
+
380
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
381
+
382
+ ---
383
+
384
+ ## 3.9.3
385
+
386
+ **The answer no longer waits for you to open the window.**
387
+
388
+ - Reported: a message was sent, the elapsed timer climbed past a minute, and the reply only appeared once
389
+ the browser window was raised by hand. The plugin minimises the window on purpose, so this was the normal
390
+ case, and it had never been tested that way.
391
+ - Cause: Chromium throttles timers and rendering in a minimised or occluded window. The reply was finished
392
+ inside the page while this client - which reads it by polling every 70ms - was not allowed to see it.
393
+ - Fix: the browser is launched with background timer throttling, occluded-window backgrounding, renderer
394
+ backgrounding and intensive wake-up throttling disabled, and the window-occlusion calculation removed.
395
+ The page is also told it is active at every connection and again immediately after minimising.
396
+ - If a read still stalls, the page is nudged once and then the call fails with a sentence that says to open
397
+ the window, instead of a timer that climbs forever.
398
+
399
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
400
+
401
+ ---
402
+
403
+ ## 3.9.2
404
+
405
+ **Full-file audit; sixteen bugs fixed.**
406
+
407
+ - A tool reply that began with prose used to have its prose emitted TWICE: the comparison that decided what
408
+ to append included the route label, so it never matched. Emitting is now anchored on the streamed
409
+ position, and a brace-first reply gets its label too.
410
+ - Search answers no longer leak tool envelopes: the answer block is scrubbed and a tool call found in a
411
+ search reply is still executed.
412
+ - Opening the settings panel no longer launches a browser: inspect() reads or reports "nothing to listen
413
+ to", and only an explicit action starts one.
414
+ - A repeated answer only counts as a fault when it arrives within a minute; asking the same question an
415
+ hour later is a correct answer, not a stuck page.
416
+ - Six strings that were rendered in English regardless of language now follow the dictionary: the trust
417
+ panel, the session/provider status details, the "switching…" chip, "Last thing sent", the savings line,
418
+ the tools caption and the "auto" language label. All six translated into all 51 languages.
419
+ - The settings tab title follows the harness locale (Uncle Sam / 山姆大叔).
420
+ - "Start fresh" and "Show browser" are greyed again when no browser is running - the helper that did this
421
+ had silently lost it.
422
+ - Dead config wired up, broken indentation fixed, and a prompt-preview edge case guarded.
423
+
424
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
425
+
426
+ ---
427
+
428
+ ## 3.9.1
429
+
430
+ **Answers now come back in the language the panel is in.**
431
+
432
+ - A Spanish panel used to answer "hola" in English, because the page only ever saw the single word. One
433
+ short line now goes with the message: [Answer in Spanish].
434
+ - The language name is the English one, so the instruction is unambiguous - "Spanish" rather than "Español".
435
+ - English readers get nothing extra: the instruction is omitted when the panel is English.
436
+ - Tested against all 51 languages, including that the tool line, the language line and the person's own
437
+ words appear in that order.
438
+
439
+ NOT YET PUBLISHED. Installed into the local harness for testing only.
440
+
441
+ ---
442
+
443
+ ## 3.9.0
444
+
445
+ **Fifty-one languages.**
446
+
447
+ - Ten more: Nepali, Sinhala, Khmer, Burmese, Georgian, Azerbaijani, Kazakh, Uzbek, Lithuanian and
448
+ Slovenian.
449
+ - The review page and the plain-text sheet now cover all 51: 4,437 strings.
450
+
451
+ NOT YET PUBLISHED. This build is installed into the local harness for testing only.
452
+
453
+ ---
454
+
455
+ ## 3.8.0
456
+
457
+ **Forty-one languages.**
458
+
459
+ - English, Chinese, Spanish, German, French, Portuguese, Russian, Japanese, Korean, Italian, Arabic,
460
+ Hindi, Dutch, Polish, Swedish, Danish, Norwegian, Finnish, Czech, Slovak, Hungarian, Romanian, Greek,
461
+ Bulgarian, Croatian, Serbian, Ukrainian, Thai, Vietnamese, Indonesian, Malay, Filipino, Bengali,
462
+ Tamil, Telugu, Marathi, Persian, Urdu, Turkish, Swahili and Hebrew — each covering the whole panel,
463
+ the model picker and the error messages.
464
+ - Every language is written colloquially rather than literally: "buy me a coffee" uses the idiom for
465
+ treating someone in each language, not a word-for-word translation.
466
+ - Six of them (Bengali, Tamil, Telugu, Marathi, Swahili, Hebrew) are flagged in dev/TRANSLATION-NOTES.md
467
+ as worth a native review.
468
+
469
+ ---
470
+
471
+ ## 3.7.0
472
+
473
+ **Forty-one languages, and the tool line cut down to one.**
474
+
475
+ - Each panel gets a language selector; the words follow it instead of the harness detection.
476
+ - The tool line is still sent, because the chat box has no system channel, but the call format is now a
477
+ clause on that same line rather than a second block above the person's own message. It is also shown in
478
+ the panel's "last thing sent" view, where it belongs.
479
+
480
+ ---
481
+
482
+ ## 3.6.2
483
+
484
+ **The rest of the page, translated.**
485
+
486
+ - Every remaining English string now has a key: the model-route card, the page introduction, the whole Brave
487
+ recommendation with its three reasons, the headless explanation, the browser-in-use line, the Edge
488
+ suggestion and the composer switch with its tooltips.
489
+ - The title is translated too: El Tío Sam, Onkel Sam, Oncle Sam, 山姆大叔.
490
+ - The panel key list, the locale build and the tests now agree on 86 strings.
491
+
492
+ Fixed while doing this: the build checked for missing keys before merging the translations, so it reported
493
+ keys as missing that it had just supplied.
494
+
495
+ ---
496
+
497
+ ## 3.6.1
498
+
499
+ - The language dropdown is painted with the harness's own theme tokens instead of `transparent`, so its
500
+ field and its open list follow the theme rather than falling back to the system's white popup. That was
501
+ the bug: a native select draws its list with system colours, which on a light system sat white over a
502
+ dark panel.
503
+
504
+ ---
505
+
506
+ ## 3.6.0
507
+
508
+ **Five languages, chosen by the harness, overridable in the panel.**
509
+
510
+ - English, Spanish, Chinese, German and French, each covering the whole panel, the model picker and the
511
+ error messages.
512
+ - The language follows the harness's own setting. No IP lookup, no cookies, no network request: the harness
513
+ already knows, so the plugin asks rather than guesses.
514
+ - A small selector under the title lets the reader override it - someone reading English happily on a system
515
+ set to another language should not be forced into that language.
516
+ - A test fails the build if any language loses a key or a %s placeholder, so a translation cannot silently
517
+ fall back to English.
518
+
519
+ ---
520
+
521
+ ## 3.5.5
522
+
523
+ - The author section opens with the coffee link itself, in blue, instead of a heading. Two short sentences
524
+ follow, then the machine and its specification.
525
+ - The name is gone from the panel: there is one person behind this and the reader already knows who.
526
+ - The duplicate link above the title is removed, so the page asks once rather than twice.
527
+
528
+ ---
529
+
530
+ ## 3.5.4
531
+
532
+ - The reason for the machine is now the real one: a faster build-test-fix cycle. The previous wording claimed
533
+ the plugins needed to run models locally, which was not true - the harness does its work over the network
534
+ and the browser, not a local GPU.
535
+
536
+ ---
537
+
538
+ ## 3.5.3
539
+
540
+ - The goal machine is now the ASUS ProArt P16 (H7606WX): AMD Ryzen AI 9 HX 370, AMD XDNA NPU at 50 TOPS,
541
+ and the same 24 GB RTX 5090. Replaces the Intel machine, which was the only 18-inch option but not the
542
+ better fit for running models locally.
543
+
544
+ ---
545
+
546
+ ## 3.5.2
547
+
548
+ - Coffee link is now a blue uppercase link with no icon and no explanation.
549
+ - The author section states the goal: the exact machine being saved for, its specification, and that every
550
+ coffee moves it closer.
551
+
552
+ ---
553
+
554
+ ## 3.5.1
555
+
556
+ - The coffee link moves to the top of the settings page, above the title, and is a plain link rather than a
557
+ button. The bottom button is gone; one ask on a screen is enough.
558
+ - The trust list no longer marks reassurances with a red cross, which read as warnings.
559
+
560
+ ---
561
+
562
+ ## 3.5.0
563
+
564
+ **Customer-facing additions.**
565
+
566
+ - **Savings counter** in the panel: calls, estimated tokens, and the money those tokens would have cost
567
+ through the API, at the published list rate. Labelled as an estimate because the page reports no usage.
568
+ - **Start fresh** button: resets the browser to a blank conversation, which was previously impossible from
569
+ inside the harness.
570
+ - **Show browser** button: raises the Uncle Sam window without hunting the taskbar.
571
+ - **Last thing sent**: the exact text typed into the chat box, so what was sent is visible without opening
572
+ the tab.
573
+ - **Trust panel**: a plain list of what the plugin does and does not do.
574
+
575
+ ---
576
+
577
+ ## 3.4.0
578
+
579
+ **Queue watchdog, so a dropped stream cannot freeze the plugin.**
580
+
581
+ - A call that holds the serialisation slot is released by force after 20 minutes. If the harness abandons
582
+ a stream, the release used to be skipped and every later request waited on a promise that would never
583
+ settle - the plugin appeared frozen until restart. Nothing legitimate holds a slot that long.
584
+ - Deliberately still no minimum interval between requests. A competitor inserts a random 2-4 second gap
585
+ because it re-sends the whole transcript every turn; Uncle Sam continues the chat in the page and sends
586
+ only the newest message, so that gap would cost latency and buy nothing.
587
+
588
+ ---
589
+
590
+ ## 3.3.1
591
+
592
+ - Attribution completed: Operating Tag everywhere a person looks, with the copyright holder named in
593
+ LICENSE only.
594
+ - README install command, badge and installer updated to the `@operatingtag` scope.
595
+
596
+ ---
597
+
598
+ ## 3.3.0
599
+
600
+ **Published under the Operating Tag scope.**
601
+
602
+ - Package published under the `@operatingtag/dsh-unclesam` name.
603
+ - Author field now reads **Operating Tag (@operatingtag)**.
604
+ - Repository links updated. The display name is unchanged: this is still Uncle Sam.
605
+
606
+ ---
607
+
608
+ ## 3.2.0
609
+
610
+ **Windows installer.**
611
+
612
+ - `install.cmd` and `install.ps1` install or remove the plugin without any clicks in the GUI: they find
613
+ the harness profile, back up both files it touches, link the package and add the profile row.
614
+ - `-DryRun` prints every action and writes nothing.
615
+ - `-Uninstall` restores the profile to exactly its previous state, verified by a round-trip test on a
616
+ throwaway profile.
617
+ - Execution policy is bypassed for that one process only; no machine setting is changed.
618
+
619
+ ---
620
+
621
+ ## 3.1.0
622
+
623
+ **Support link added.**
624
+
625
+ - The author section in the plugin panel now carries a **Buy me a coffee** button, pointing at a real
626
+ payment link rather than inviting the reader to go and find one.
627
+ - README gains a Support section with the same link.
628
+
629
+ ---
630
+
631
+ ## 3.0.2
632
+
633
+ **Installation documented and verified end to end.**
634
+
635
+ - README gains an Installing section: requirements, both install routes, what a successful install looks
636
+ like, the first-run sign-in, and how to remove it again.
637
+ - Repository, bugs and homepage fields added to the manifest.
638
+ - `check` and `pack:check` scripts added.
639
+ - Verified by packing the tarball and installing it into a clean directory: all twelve files land, the
640
+ entry point exports `apply()`, and the prompt module runs from the installed copy.
641
+
642
+ ---
643
+
644
+ ## 3.0.1
645
+
646
+ **Renamed the package to `@operatingtag/dsh-unclesam`.** The display name stays *Uncle Sam* — the
647
+ package identifier is what npm resolves, the title is what a person reads.
648
+
649
+ - Package name, bundle row id and client module id all updated together, so the client half still loads.
650
+ - Provider route `deepseek-web` deliberately unchanged: it is recorded inside saved model selections, and
651
+ renaming it would orphan existing conversations.
652
+
653
+ ---
654
+
655
+ ## 3.0.0
656
+
657
+ **First publishable build.**
658
+
659
+ - Every source file carries a header with its name, version, author and licence.
660
+ - `LICENSE` added (MIT), `author` and `license` fields filled in the manifest.
661
+ - Manifest gains keywords and a Node engine requirement; `README` and `LICENSE` ship with the package.
662
+ - Development scratch files moved out of the package so the distributed files are only the real ones.
663
+
664
+ ---
665
+
666
+ ## 2.9.2
667
+
668
+ **Three fixes found by screen recording a real session.**
669
+
670
+ - **Tool-call JSON no longer reaches the visible reply.** The model was writing
671
+ `{"tool":"…","arguments":{}}` immediately followed by prose on the same line; the previous pattern both
672
+ missed it and could not balance the nested braces. Replaced with a brace-counting scan.
673
+ - **Tool list capped at twelve names, with the remainder counted.** A session carrying thirty tools turned
674
+ the preamble into a wall of text in front of the user's own message.
675
+ - **DeepThink and Search are no longer reset.** The plugin treated `false` as an instruction to switch them
676
+ off, so a user who enabled them by hand had them silently cleared on the next message. Only an explicit
677
+ `true` acts now.
678
+
679
+ ---
680
+
681
+ ## 2.9.1
682
+
683
+ - Tool preamble reduced to names only, with descriptions dropped. The previous "compact" form was compact
684
+ for three tools and enormous for thirty.
685
+
686
+ ---
687
+
688
+ ## 2.9.0
689
+
690
+ **Plain conversation sends only the user's words.** The harness system prompt is no longer typed into the
691
+ chat box, so the browser shows what the person typed and nothing else. Tool turns still describe the tools,
692
+ because a model cannot call a tool it was never told about.
693
+
694
+ ---
695
+
696
+ ## 2.8.6
697
+
698
+ - Tool-call leakage scrubbed from the visible text as well as discouraged in the instruction, covering
699
+ calls written before prose, fenced calls, truncated calls and stray narrator lines. Ordinary JSON in
700
+ prose is left untouched.
701
+
702
+ ---
703
+
704
+ ## 2.8.5
705
+
706
+ **Latency reduced by roughly 2.8 seconds per message.**
707
+
708
+ - The fixed 1,400 ms wait after sending replaced with polling, which exits as soon as the composer clears.
709
+ - Reply settle window reduced from 2,000 ms to 600 ms.
710
+ - Poll interval tightened from 110 ms to 70 ms so the settle window is measured accurately.
711
+
712
+ ---
713
+
714
+ ## 2.8.4
715
+
716
+ - Plugin display name changed to **Uncle Sam** across the settings tab, panel heading and description.
717
+ Package identifier unchanged at this release.
718
+
719
+ ---
720
+
721
+ ## 2.8.3
722
+
723
+ - Switch labels changed to `DeepSeek Harness` and `Uncle Sam`, matching the signature on replies so the
724
+ control and the answer use the same name.
725
+
726
+ ---
727
+
728
+ ## 2.8.2
729
+
730
+ - The status dot no longer greys out on startup. Availability now only affects the colour when the active
731
+ route is the web one — a grey light on a working API route invited people to fix something that was not
732
+ broken.
733
+
734
+ ---
735
+
736
+ ## 2.8.1
737
+
738
+ - Labels corrected to `Api` and `Uncle Sam`, with the dot red on the web route and blue on the API route.
739
+
740
+ ---
741
+
742
+ ## 2.8.0
743
+
744
+ - Switch redesigned from a bordered two-segment pill to a single quiet chip: a small status dot and one
745
+ lowercase word, matching the weight of the controls beside it.
746
+ - Hover surface and pointer cursor make it read as clickable without shouting.
747
+
748
+ ---
749
+
750
+ ## 2.7.0
751
+
752
+ - Switch moved from below the composer card into the composer tool row, on the left, where there is room.
753
+ The right side of that row is already full, so adding there squeezed the model name or pushed the send
754
+ button.
755
+
756
+ ---
757
+
758
+ ## 2.6.2
759
+
760
+ - Composer row tidied: model label enlarged and vertically centred, switch right-aligned.
761
+
762
+ ---
763
+
764
+ ## 2.6.1
765
+
766
+ - Tool preamble wrapped in a labelled code block so it reads as harness scaffolding rather than raw JSON
767
+ appearing in the conversation.
768
+
769
+ ---
770
+
771
+ ## 2.6.0
772
+
773
+ **The switch now changes the current conversation.**
774
+
775
+ - The session id is read from the component prop the slot provides, instead of being searched for in the
776
+ client service, sidebar links and address bar. Those searches failed, so the host saved the choice as the
777
+ default for new conversations only, and the badge could show WEB while replies came from the API.
778
+ - Settings keeps no conversation in view, so it changes the route for new conversations and says so.
779
+
780
+ ---
781
+
782
+ ## 2.5.0
783
+
784
+ - One browser chat per harness conversation, so two sessions no longer share a single transcript and answer
785
+ each other's questions.
786
+ - Session-title and history-compaction calls get their own slot and never touch the user's chat.
787
+ - Internal calls carry no route signature.
788
+
789
+ ---
790
+
791
+ ## 2.4.0
792
+
793
+ - **Sending made reliable.** Enter is retried with escalation — a real key press, an in-page key event, a
794
+ click on the send button — and a send only counts as successful when the composer clears.
795
+ - Reported cause: a 16-character message was typed in full and Enter was ignored, with no error anywhere.
796
+
797
+ ---
798
+
799
+ ## 2.3.0
800
+
801
+ - A message that is typed but never submitted now fails immediately with the character count still in the
802
+ box, instead of waiting for a first token that will never arrive.
803
+
804
+ ---
805
+
806
+ ## 2.2.1
807
+
808
+ - Reply signature changed to `🔴 Uncle Sam`, documented in the plugin description and configuration as a
809
+ joke rather than a claim of authority.
810
+
811
+ ---
812
+
813
+ ## 2.2.0
814
+
815
+ - Web replies are signed so the route that produced an answer is visible in the transcript itself, not only
816
+ in a badge beside the composer.
817
+
818
+ ---
819
+
820
+ ## 2.1.1
821
+
822
+ - Panel rows renamed from two ambiguous "Browser" labels to `Running` (is it up) and `Using` (which engine).
823
+
824
+ ---
825
+
826
+ ## 2.1.0
827
+
828
+ - **First-run flow:** the browser window stays visible until the user has signed in, then minimises itself.
829
+ Previously the window minimised immediately, leaving a signed-out browser hidden with no way to log in.
830
+
831
+ ---
832
+
833
+ ## 2.0.0
834
+
835
+ **Collapsed to one browser model.**
836
+
837
+ - Browser selection simplified: Brave when installed, Edge otherwise. Brave is recommended but never
838
+ required, and nothing is installed on the user's behalf.
839
+ - Headless mode removed. It was built and measured: the site answers headless clients with a 403 from
840
+ CloudFront before the application loads, so no flag or setting could make it work.
841
+ - Window is minimised to the taskbar after launch, verified rather than assumed.
842
+ - Mode switches removed; there is one behaviour.
843
+
844
+ ---
845
+
846
+ ## 1.20.0
847
+
848
+ - Returning to the API no longer refuses. When no API model was remembered the plugin now falls back to the
849
+ deployment default, then to any routable model, and only declines if the harness offers none.
850
+
851
+ ---
852
+
853
+ ## 1.19.0
854
+
855
+ - Probe port follows the display mode, so a headless browser launched correctly on its own port is not then
856
+ looked for on the wrong one.
857
+ - A launch that never settles can no longer leave the badge reporting "starting the browser…" forever.
858
+
859
+ ---
860
+
861
+ ## 1.18.0
862
+
863
+ - Web calls continue the browser chat instead of restarting it, so the harness conversation and the browser
864
+ conversation are the same conversation.
865
+ - Prompt size capped: tool descriptions budgeted, and a hard ceiling on the whole prompt.
866
+ - Setup panel waits for the single-page app to hydrate before reporting "not signed in".
867
+
868
+ ---
869
+
870
+ ## 1.17.0
871
+
872
+ - Author attribution added, and the owner name shown in the plugin panel.
873
+
874
+ ---
875
+
876
+ ## 1.16.0
877
+
878
+ - Setup panel also registered as a top-level settings page. The plugin tab lives inside the Plugins section,
879
+ which is not where someone lands after clicking a plugin in the Plugins list.
880
+
881
+ ---
882
+
883
+ ## 1.15.0
884
+
885
+ - Window minimisation performed as an action rather than a launch flag. `--start-minimized` was measured to
886
+ have no effect; the result is now read back and reported.
887
+
888
+ ---
889
+
890
+ ## 1.14.0
891
+
892
+ - Brave recommended, with the reasoning stated in the panel, and Edge used automatically when Brave is
893
+ absent.
894
+
895
+ ---
896
+
897
+ ## 1.13.0
898
+
899
+ - Display modes introduced: headless, minimised, visible.
900
+
901
+ ---
902
+
903
+ ## 1.12.0
904
+
905
+ - Setup panel added, showing browser, session, provider and readiness, with sign-in and check actions.
906
+
907
+ ---
908
+
909
+ ## 1.11.0
910
+
911
+ - Choosing the web route starts the browser itself, so the switch no longer sits on "unavailable" until a
912
+ message happens to be sent.
913
+
914
+ ---
915
+
916
+ ## Earlier builds (1.0.0 – 1.10.x)
917
+
918
+ Pre-release iteration on the provider itself: registering `deepseek-web` as a model provider, driving the
919
+ composer through the DevTools Protocol, streaming deltas into harness chunks, and the two-way switch. These
920
+ builds were development snapshots and were not distributed.
921
+
922
+ ---
923
+
924
+ ## Origins
925
+
926
+ The web route exists because the site requires a proof-of-work challenge per message and is fronted by
927
+ Cloudflare Turnstile. Driving a real signed-in browser satisfies both without impersonating the site's
928
+ private API.