clauderipple 0.2.0

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 (71) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/LICENSE +674 -0
  3. package/README.ko.md +328 -0
  4. package/README.md +372 -0
  5. package/bin/clauderipple.js +12 -0
  6. package/dist/app/assets/trayDownTemplate.png +0 -0
  7. package/dist/app/assets/trayDownTemplate@2x.png +0 -0
  8. package/dist/app/assets/trayTemplate.png +0 -0
  9. package/dist/app/assets/trayTemplate@2x.png +0 -0
  10. package/dist/app/assets/trayWarnTemplate.png +0 -0
  11. package/dist/app/assets/trayWarnTemplate@2x.png +0 -0
  12. package/dist/app/assets/trayWin.png +0 -0
  13. package/dist/app/assets/trayWin@2x.png +0 -0
  14. package/dist/app/assets/trayWinDown.png +0 -0
  15. package/dist/app/assets/trayWinDown@2x.png +0 -0
  16. package/dist/app/assets/trayWinWarn.png +0 -0
  17. package/dist/app/assets/trayWinWarn@2x.png +0 -0
  18. package/dist/app/dist/main.js +518 -0
  19. package/dist/cli/src/browser.js +21 -0
  20. package/dist/cli/src/bundle.js +51 -0
  21. package/dist/cli/src/certs.js +33 -0
  22. package/dist/cli/src/claude-auth.js +112 -0
  23. package/dist/cli/src/codex.js +172 -0
  24. package/dist/cli/src/gen-certs.js +7 -0
  25. package/dist/cli/src/hooks/agent-title.js +160 -0
  26. package/dist/cli/src/index.js +489 -0
  27. package/dist/cli/src/launchd.js +183 -0
  28. package/dist/cli/src/picker.js +166 -0
  29. package/dist/cli/src/probe.js +55 -0
  30. package/dist/cli/src/runtime.js +62 -0
  31. package/dist/cli/src/schtasks.js +134 -0
  32. package/dist/cli/src/settings.js +142 -0
  33. package/dist/cli/src/supervisor.js +100 -0
  34. package/dist/cli/src/tray.js +85 -0
  35. package/dist/router/src/admin.js +945 -0
  36. package/dist/router/src/bootstrap.js +80 -0
  37. package/dist/router/src/certs.js +65 -0
  38. package/dist/router/src/compat.js +172 -0
  39. package/dist/router/src/config.js +179 -0
  40. package/dist/router/src/health.js +45 -0
  41. package/dist/router/src/identity.js +51 -0
  42. package/dist/router/src/index.js +144 -0
  43. package/dist/router/src/ingress/models.js +29 -0
  44. package/dist/router/src/ingress/server.js +400 -0
  45. package/dist/router/src/ingress/translate.js +457 -0
  46. package/dist/router/src/log.js +81 -0
  47. package/dist/router/src/picker.js +74 -0
  48. package/dist/router/src/presets.js +267 -0
  49. package/dist/router/src/providers/anthropic-observed.js +88 -0
  50. package/dist/router/src/providers/anthropic-token-file.js +48 -0
  51. package/dist/router/src/providers/anthropic.js +203 -0
  52. package/dist/router/src/providers/chatgpt/auth.js +226 -0
  53. package/dist/router/src/providers/chatgpt/index.js +274 -0
  54. package/dist/router/src/providers/chatgpt/sse.js +28 -0
  55. package/dist/router/src/providers/chatgpt/translate.js +393 -0
  56. package/dist/router/src/providers/claude-oauth.js +252 -0
  57. package/dist/router/src/providers/openai/index.js +193 -0
  58. package/dist/router/src/providers/openai/translate.js +504 -0
  59. package/dist/router/src/proxy.js +724 -0
  60. package/dist/router/src/redact.js +43 -0
  61. package/dist/router/src/requestlog.js +346 -0
  62. package/dist/router/src/routing.js +113 -0
  63. package/dist/router/src/version.js +8 -0
  64. package/dist/router/src/x509.js +203 -0
  65. package/dist/ui/app.js +1228 -0
  66. package/dist/ui/i18n.js +95 -0
  67. package/dist/ui/index.html +104 -0
  68. package/dist/ui/presets-fallback.js +61 -0
  69. package/dist/ui/style.css +347 -0
  70. package/docs/ARCHITECTURE.md +441 -0
  71. package/package.json +66 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,229 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 — 2026-09-16
4
+
5
+ The first release published to npm, and the reason the number moves to 0.2:
6
+ ClaudeRipple is installed with one command instead of a signed application,
7
+ and the Electron window is gone in favour of the dashboard in your own browser.
8
+
9
+ Why 0.1.1 did not help the Windows install that reported the 0.1.1 bugs: the
10
+ fixes were in the files, but the router that kept answering was the old
11
+ process. Nothing restarted it, and nothing could tell.
12
+
13
+ ### Changed
14
+
15
+ - **Distribution is npm.** `npm install -g clauderipple && clauderipple install`.
16
+ There is no per-platform build to make, nothing to sign, nothing to notarize and
17
+ no Windows VM in the loop: one `npm publish` serves both platforms, and the
18
+ arm64 Windows installer bug cannot reach anyone through this path. The cost is
19
+ that the user needs Node 24. The published package is JavaScript, because Node
20
+ refuses to strip types under `node_modules`; the electron-builder path is still
21
+ there for a standalone app but is no longer required for a release.
22
+ - **One command installs everything, Node included.** `curl … install.sh | sh` on
23
+ macOS, `irm … install.ps1 | iex` on Windows. The script uses a Node 24+ already
24
+ on PATH and otherwise downloads the official build into `~/.clauderipple/runtime`,
25
+ checked against the checksum nodejs.org publishes, then runs setup. The package
26
+ goes under its own prefix, so nothing needs elevation and uninstalling is one
27
+ directory. The Node version is resolved at install time rather than pinned.
28
+ - **The tray is a command, and its runtime is fetched on request.** `clauderipple
29
+ tray` starts the menu-bar / tray app; `--install` fetches Electron the first
30
+ time. Electron is 270MB and is not a dependency, so a plain install is under a
31
+ megabyte and every other command works without it.
32
+
33
+ ### Added
34
+
35
+ - **Claude subscription sign-in from the app.** "Connect Claude subscription…"
36
+ in the GUI (and `clauderipple claude-login`) now runs ClaudeRipple's own
37
+ browser sign-in: the same OAuth flow with PKCE that Claude Code uses, with the
38
+ code returning to a loopback listener on port 54545 or, when that port is
39
+ taken, pasted from Anthropic's page. No terminal needed. The grant is stored
40
+ in `~/.clauderipple/claude-auth.json` (mode 0600) and refreshed automatically
41
+ before it expires; a failed refresh becomes a clear 401 instead of a dead
42
+ token. `--setup-token` keeps the previous terminal-only path. Tray →
43
+ "Connect Claude subscription" runs the same flow.
44
+ - **Readiness, not only liveness.** `/api/status.readiness` and `GET /readyz`
45
+ (200, or 503 with `retry-after`) name what stands between a request and a
46
+ model: Claude Code not pointed at ClaudeRipple, Anthropic unreachable, picker
47
+ mode without certificate trust or the app proxy entry, a provider host that
48
+ does not answer. The tray shows the list next to "Connected".
49
+ - **The stored sign-in is reported separately from the one in use.** A live
50
+ Claude Desktop session outranks ClaudeRipple's own credential, so the provider
51
+ screen now names both: the source a request would use, and, on its own line,
52
+ whether a ClaudeRipple sign-in is stored and waiting behind it. Without this a
53
+ successful sign-in changed nothing on screen.
54
+ - **A model removed from a provider leaves the app picker.** Unticking a model
55
+ rewrote the provider but left its entry in `cli.extraModels` and its `direct`
56
+ rule behind, and the next save read that entry back as a selection. Since the
57
+ tick list is built from the providers, such an entry had no checkbox and could
58
+ never be removed; duplicated ids appeared twice in the picker. The selection is
59
+ now rebuilt from what the providers actually offer, deduplicated by model id,
60
+ and a direct rule that served only a removed model goes with it. A prefix rule
61
+ that is not a model id, such as the legacy `gpt-` one, is kept.
62
+ - **Every provider can tell the model what it is.** The identity line and the
63
+ system-prompt addendum were ChatGPT-only, so a mapped DeepSeek read Claude
64
+ Code's own prompt and answered that it was Claude. Anthropic-compatible and
65
+ OpenAI-compatible providers now carry the same two settings, on by default,
66
+ and the GUI offers them under Advanced for every provider.
67
+ - **HTML error pages are called out.** A provider that answers with a web page
68
+ (a bare vendor domain, a login wall) is logged as "HTML page … not an API"
69
+ instead of a quoted markup fragment.
70
+
71
+ ### Fixed
72
+
73
+ - **`uninstall --purge` removes the home directory on Windows.** It unregistered
74
+ the scheduled task but left the router running, and a running router holds
75
+ `router.log` open, so the removal failed with `EPERM` and left everything
76
+ behind. The router is stopped first now, and the removal is retried briefly
77
+ while Windows releases the handle.
78
+
79
+ - **An update now replaces the running router.** Installing a new version only
80
+ replaces files; the supervisor had started the router at logon from the old
81
+ ones, and `start` leaves a running router alone, so the old code kept serving
82
+ after every update. A zip unpacked into a new folder was worse: the
83
+ supervisor and `paths.json` still named the old folder, so even a restart
84
+ brought the old code back. The tray app now compares the running router's
85
+ version and files with its own once per launch; if they differ it re-runs
86
+ `install` (only when this installation's files are not the recorded ones) and
87
+ restarts the router, with a notification. A source checkout recorded in
88
+ `paths.json` is left alone.
89
+ - **Windows: "Restart Router" restarts the router.** The packaged router runs
90
+ as `ClaudeRipple.exe` (Electron as Node), but the process lookup only knew
91
+ `node.exe`, so on every packaged install `restart` found nothing to stop,
92
+ and the scheduled task ignored the start request because it was already
93
+ running. Nothing was restarted, and the command still said "restarted". The
94
+ lookup now matches either executable. Until 0.1.2, the only ways to get a
95
+ new router on a packaged Windows install were the installer (whose own stop
96
+ script did look for `ClaudeRipple.exe`), signing out and in, or a reboot.
97
+ - **The router reports its real version.** It said `0.1.0` in 0.1.1 (a literal
98
+ in two places). One `VERSION` constant now feeds the router, the CLI and the
99
+ status page, and a test fails when it drifts from the package manifests.
100
+ - **Provider errors are logged with their body.** A 4xx/5xx from a provider or
101
+ from Anthropic recorded only the status; a DeepSeek `401` stayed unexplained
102
+ for a day. The first 300 characters of the error body now go into the router
103
+ log and the Logs page, with anything key-shaped reduced to its last four
104
+ characters. `/api/status` also reports which files the router is running and
105
+ when it started.
106
+ - **`claude setup-token` from the app no longer hangs or fails silently.** It
107
+ is an interactive terminal flow; run from the tray or the GUI it waited for
108
+ input that never came or failed with a bare "setup-token failed". That path
109
+ is now `claude-login --setup-token` only, refuses without a terminal with a
110
+ message that says where to run it, and includes what `claude` printed when
111
+ it fails. The app uses the browser sign-in above instead.
112
+
113
+ ## 0.1.1 — 2026-09-15
114
+
115
+ All four were reported from a Windows install and reproduced here.
116
+
117
+ ### Fixed
118
+
119
+ - **A mapped request now carries provider authentication only.** The caller's
120
+ own `authorization` and `x-api-key` are dropped before the provider's headers
121
+ are added. Previously only the header that happened to share a name with the
122
+ provider's was replaced, which differs per provider: DeepSeek and MiniMax
123
+ authenticate with `x-api-key`, everything else with `Authorization: Bearer`.
124
+ A DeepSeek mapping answered `401` on every request while the provider form's
125
+ own "Test connection" stayed green — the test sends the provider's headers
126
+ alone, so it certified a path live traffic did not take. An un-routed request
127
+ is unchanged; it really is going to Anthropic.
128
+ - **Mapping Haiku 4.5 works.** The app sends `claude-haiku-4-5-20251001` while
129
+ the GUI offers the undated `claude-haiku-4-5`, and route lookup was an exact
130
+ key match, so the mapping never fired and Haiku answered itself. Lookup now
131
+ accepts either form.
132
+ - **The native Claude (Anthropic) provider is no longer offered as a mapping
133
+ target.** It serves the OpenAI ingress (Codex) only, but it could be picked in
134
+ Model mapping and given picker entries, and a slot pointed at it failed every
135
+ Claude request with `400`. It is out of the mapping list, creates no picker
136
+ entries, and an existing config that names it passes through instead of
137
+ failing.
138
+ - **Windows: "Connect Claude subscription" works.** CLI discovery looked for an
139
+ extensionless `claude` on `PATH` and for the macOS Application Support cache,
140
+ so it always reported "Claude Code CLI not found". It now looks for the
141
+ `.exe`/`.cmd`/`.bat` launchers, checks both AppData roots for the CLI that
142
+ Claude Desktop caches, and runs a `.cmd` launcher through a shell.
143
+ `clauderipple status` reported the cached CLI version from the macOS path too.
144
+
145
+ ## 0.1.0 — 2026-09-14 (first release: macOS + Windows)
146
+
147
+ The source was published on 2026-09-13; this is the first build. Everything
148
+ under "0.1.0 — 2026-09-13" below is included.
149
+
150
+ ### Windows support
151
+
152
+ ClaudeRipple runs on Windows. Everything was verified end to end against a real
153
+ Claude Desktop on Windows 11 arm64 (VM) and on x64 hardware: the picker lists
154
+ provider models by name, selecting one routes the call, and the model answers
155
+ with its reasoning effort intact.
156
+
157
+ - Supervisor: a per-user scheduled task, registered without administrator rights.
158
+ It starts the router at logon, and the launcher supervises the process itself —
159
+ Task Scheduler's restart setting only covers failing to *start* a task, so a
160
+ crash would otherwise go unnoticed.
161
+ - Certificate trust for the current user only (`Cert:\CurrentUser\Root`). Windows
162
+ shows a confirmation dialog with the fingerprint instead of asking for a
163
+ password; no UAC prompt, and removal asks again.
164
+ - Graceful restart over `POST /api/shutdown`, because Windows has no SIGTERM.
165
+ - Installer: per-user NSIS, no elevation. **Unsigned** — see the README note.
166
+ Reinstalling and uninstalling stop the supervisor and drain the router first
167
+ (it kept running as `ClaudeRipple.exe` after the tray app closed, so the
168
+ installer failed with "could not be closed" and no hint what to close); the
169
+ uninstaller also undoes the settings.json edits and picker mode while the
170
+ bundled runtime still exists.
171
+
172
+ ### Fixed
173
+
174
+ - **"Show in the Claude app picker" did nothing on its own.** The provider form's
175
+ checkbox only recorded which models to show; picker mode stayed off and the
176
+ picker never changed, with no message (Windows x64, 2026-09-14). The form now
177
+ says so and offers to turn picker mode on right after saving.
178
+ - **ChatGPT sign-in from the GUI.** The provider card said "sign-in needed" and
179
+ gave no way to do it; it has a button now, and the sign-in runs in the
180
+ background while the card waits for the browser to finish.
181
+ - **Language.** The tray, notifications and the GUI came up in English on a
182
+ Korean Windows: `app.getLocale()` is Chromium's app locale, not the language
183
+ the user set. The OS preference list is used instead, and the GUI follows it
184
+ unless a language was picked in the GUI itself.
185
+
186
+ - **Startup.** After a reboot the router could listen minutes after login, and
187
+ Claude Desktop was a blank `ERR_PROXY_CONNECTION_FAILED` window the whole time
188
+ (in picker mode the app has no direct fallback). The launchd agent is no longer
189
+ a throttled `Background` job, `listen()` comes before certificate minting, and
190
+ every start logs its budget. `start` is idempotent: it used to kill a router
191
+ that was still coming up.
192
+ - **The app now says what is wrong.** A login item so the tray is there before
193
+ Claude Desktop is, an offline notice that names the cause instead of the
194
+ router-served GUI it cannot load, and a notification after 20s down.
195
+ - **Certificates are issued by `node:crypto`**, with no `openssl` binary and no
196
+ new dependency — which is also what let Windows work at all.
197
+ - **Security: the admin API refused no cross-site requests.** Binding to
198
+ 127.0.0.1 does not keep the browser out: any page could POST to it, and CORS
199
+ hides only the response, not the side effect. Requests carrying another site's
200
+ `Origin` are refused.
201
+ - The model mapping table listed every model twice and offered our own injected
202
+ ids as mapping sources.
203
+ - The settings window opened smaller than its own content.
204
+ - The subagent title hook silently did nothing when its path contained a space.
205
+
206
+ ## 0.1.0 — 2026-09-13 (first public alpha)
207
+
208
+ - Local HTTPS proxy for Claude Code: model mapping (Claude name → any provider
209
+ model), per-request effort, graceful drain on restart, structured request log.
210
+ - ChatGPT subscription provider (Codex backend) with prompt-cache preservation
211
+ (94–99% cache hit on multi-turn sessions), server-side thread fallback, and
212
+ orphan tool-result handling.
213
+ - Anthropic-compatible providers with presets: DeepSeek, Kimi (Moonshot), Z.ai
214
+ (GLM), MiniMax, Qwen (DashScope intl/cn), OpenRouter. Connection test and
215
+ model discovery from the GUI; compatibility layer that strips Anthropic-only
216
+ request features.
217
+ - Picker mode: your provider models appear under their real names in Claude
218
+ Desktop's model picker (login-keychain trust, app config-library proxy).
219
+ - Subagent name tags (real model and effort in the background-task panel) via a
220
+ Claude Code hook.
221
+ - Local GUI (Korean/English): status, model mapping with auto-save, providers,
222
+ request log; menu-bar app that carries its own runtime and sets itself up on
223
+ first launch. Signed and notarized macOS builds (arm64, x64).
224
+ - Works with the Claude Desktop Code tab, the terminal CLI, and mobile Remote
225
+ Control sessions.
226
+
227
+ Known limits: macOS only; presets other than ChatGPT and OpenRouter are verified
228
+ against vendor docs, not with live keys; a model added to the picker is usable
229
+ from the next session.