@rynfar/meridian 1.49.1 → 1.51.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 (45) hide show
  1. package/README.md +52 -19
  2. package/assets/banner.svg +28 -21
  3. package/assets/bot-icon-512.png +0 -0
  4. package/assets/bot-icon.svg +49 -43
  5. package/assets/how-it-works.svg +40 -40
  6. package/assets/icon-512.png +0 -0
  7. package/assets/icon.svg +16 -13
  8. package/assets/logo-512.png +0 -0
  9. package/assets/logo.svg +14 -12
  10. package/dist/{cli-mjrt119g.js → cli-7df5eg5d.js} +987 -176
  11. package/dist/{cli-q6dz9r5p.js → cli-aybvv9nb.js} +7 -1
  12. package/dist/cli-xmweegb1.js +179 -0
  13. package/dist/cli.js +4 -4
  14. package/dist/{pluginPage-85s6t6k8.js → pluginPage-03q5j753.js} +4 -10
  15. package/dist/{profileCli-fbhe9p5z.js → profileCli-j01rr99j.js} +1 -1
  16. package/dist/{profilePage-txxpbc44.js → profilePage-naychnb8.js} +6 -5
  17. package/dist/proxy/envelopeIntegrity.d.ts +50 -0
  18. package/dist/proxy/envelopeIntegrity.d.ts.map +1 -0
  19. package/dist/proxy/oauthUsage.d.ts.map +1 -1
  20. package/dist/proxy/passthroughEarlyStop.d.ts +8 -2
  21. package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
  22. package/dist/proxy/plugins/pluginPage.d.ts.map +1 -1
  23. package/dist/proxy/query.d.ts.map +1 -1
  24. package/dist/proxy/server.d.ts.map +1 -1
  25. package/dist/server.js +3 -3
  26. package/dist/telemetry/dashboard.d.ts.map +1 -1
  27. package/dist/telemetry/landing.d.ts +6 -2
  28. package/dist/telemetry/landing.d.ts.map +1 -1
  29. package/dist/telemetry/percentiles.d.ts +5 -1
  30. package/dist/telemetry/percentiles.d.ts.map +1 -1
  31. package/dist/telemetry/pricing.d.ts +63 -0
  32. package/dist/telemetry/pricing.d.ts.map +1 -0
  33. package/dist/telemetry/pricingStore.d.ts +32 -0
  34. package/dist/telemetry/pricingStore.d.ts.map +1 -0
  35. package/dist/telemetry/profileBar.d.ts +19 -9
  36. package/dist/telemetry/profileBar.d.ts.map +1 -1
  37. package/dist/telemetry/profileUsage.d.ts.map +1 -1
  38. package/dist/telemetry/settingsPage.d.ts +1 -1
  39. package/dist/telemetry/settingsPage.d.ts.map +1 -1
  40. package/dist/telemetry/sqlite.d.ts.map +1 -1
  41. package/dist/telemetry/store.d.ts.map +1 -1
  42. package/dist/telemetry/types.d.ts +38 -0
  43. package/dist/telemetry/types.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/dist/cli-4rqtm83g.js +0 -148
package/README.md CHANGED
@@ -3,21 +3,21 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <a href="https://github.com/rynfar/meridian/releases"><img src="https://img.shields.io/github/v/release/rynfar/meridian?style=flat-square&color=6366f1&label=release" alt="Release"></a>
7
- <a href="https://www.npmjs.com/package/@rynfar/meridian"><img src="https://img.shields.io/npm/v/@rynfar/meridian?style=flat-square&color=8b5cf6&label=npm" alt="npm"></a>
8
- <a href="#"><img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-a78bfa?style=flat-square" alt="Platform"></a>
9
- <a href="#"><img src="https://img.shields.io/badge/license-MIT-c4b5fd?style=flat-square" alt="License"></a>
6
+ <a href="https://github.com/rynfar/meridian/releases"><img src="https://img.shields.io/github/v/release/rynfar/meridian?style=flat-square&color=58a6ff&label=release" alt="Release"></a>
7
+ <a href="https://www.npmjs.com/package/@rynfar/meridian"><img src="https://img.shields.io/npm/v/@rynfar/meridian?style=flat-square&color=bc8cff&label=npm" alt="npm"></a>
8
+ <a href="#"><img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-58a6ff?style=flat-square" alt="Platform"></a>
9
+ <a href="#"><img src="https://img.shields.io/badge/license-MIT-bc8cff?style=flat-square" alt="License"></a>
10
10
  <a href="https://discord.gg/jP2a2Z92NZ"><img src="https://img.shields.io/badge/discord-join-5865F2?style=flat-square&logo=discord&logoColor=white" alt="Discord"></a>
11
11
  </p>
12
12
 
13
13
  ---
14
14
 
15
- Meridian bridges the Claude Code SDK to the standard Anthropic API. No OAuth interception. No binary patches. No hacks. Just pure, documented SDK calls. Any tool that speaks the Anthropic or OpenAI protocol — OpenCode, ForgeCode, Crush, Cline, Aider, Pi, Droid, Open WebUI, Claude Code — connects to Meridian and gets Claude, with session management, streaming, and prompt caching handled natively by the SDK.
15
+ Meridian bridges the Claude Agent SDK (formerly the Claude Code SDK) to the standard Anthropic API. No OAuth interception. No binary patches. No hacks. Just pure, documented SDK calls. Any tool that speaks the Anthropic or OpenAI protocol — OpenCode, ForgeCode, Crush, Cline, Aider, Pi, Droid, Open WebUI, Claude Code — connects to Meridian and gets Claude, with session management, streaming, and prompt caching handled natively by the SDK.
16
16
 
17
17
  > [!NOTE]
18
18
  > ### How Meridian works with Anthropic
19
19
  >
20
- > Meridian is built entirely on the [Claude Code SDK](https://docs.anthropic.com/en/docs/claude-code/sdk). Every request flows through `query()` — the same documented function Anthropic provides for programmatic access. No OAuth tokens are extracted, no binaries are patched, nothing is reverse-engineered.
20
+ > Meridian is built entirely on the [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk). Every request flows through `query()` — the same documented function Anthropic provides for programmatic access. No OAuth tokens are extracted, no binaries are patched, nothing is reverse-engineered.
21
21
  >
22
22
  > Because we use the SDK, Anthropic remains in full control of prompt caching, context window management, compaction, rate limiting, and authentication. Meridian doesn't bypass these mechanisms — it depends on them. Max subscription tokens flow through the correct channel, governed by the same guardrails Anthropic built into Claude Code.
23
23
  >
@@ -148,7 +148,7 @@ xdg.configFile."opencode/opencode.json".text = builtins.toJSON {
148
148
 
149
149
  ## Why Meridian?
150
150
 
151
- The Claude Code SDK provides programmatic access to Claude. But your favorite coding tools expect an Anthropic API endpoint. Meridian bridges that gap — it runs locally, accepts standard API requests, and routes them through the SDK. Claude Code does the heavy lifting; Meridian translates the output.
151
+ The Claude Agent SDK provides programmatic access to Claude. But your favorite coding tools expect an Anthropic API endpoint. Meridian bridges that gap — it runs locally, accepts standard API requests, and routes them through the SDK. Claude Code does the heavy lifting; Meridian translates the output.
152
152
 
153
153
  <p align="center">
154
154
  <img src="assets/how-it-works.svg" alt="How Meridian works" width="920"/>
@@ -168,6 +168,8 @@ The Claude Code SDK provides programmatic access to Claude. But your favorite co
168
168
  - **Multi-profile** — switch between Claude accounts instantly, no restart needed; opt-in [sticky session routing](#sticky-session-routing) distributes sessions across accounts while keeping per-account prompt caches warm
169
169
  - **Adapter instances** — run several configurations of the same adapter side by side (per-instance thinking, system prompt, passthrough) selected by header or match rules — see [Adapter instances](#adapter-instances)
170
170
  - **Telemetry dashboard** — real-time performance metrics at `/telemetry`, including token usage and prompt cache efficiency ([`MONITORING.md`](MONITORING.md))
171
+ - **Cost estimation** — estimated API-equivalent value of your traffic, per model and per profile, using current list prices with configurable overrides (`~/.config/meridian/model-pricing.json`, editable at `/settings`)
172
+ - **Envelope integrity auditing** — Meridian validates its own wire output on every response (no dangling blocks, no undelivered or empty tool calls) and surfaces violations on the dashboard
171
173
  - **Telemetry persistence** — opt-in SQLite storage for telemetry data that survives proxy restarts, with configurable retention
172
174
  - **Prometheus metrics** — `GET /metrics` endpoint for scraping request counters and duration histograms
173
175
  - **SDK feature toggles** *(experimental)* — unlock Claude Code features (memory, dreaming, CLAUDE.md) for any connected agent
@@ -229,11 +231,21 @@ For large tool sets (>15 tools), non-core tools are automatically deferred via t
229
231
 
230
232
  ### Known limitations
231
233
 
232
- - **Single tool round-trip per request** — in passthrough mode, the SDK is configured with `maxTurns=2` (or 3 for deferred tools). Multi-step agentic loops where Claude needs several consecutive tool calls require the client to re-send after each round.
233
- - **Blocked tools** — 13 built-in SDK tools (Read, Write, Bash, etc.) are blocked to prevent conflicts with the client's own tools. 15 additional Claude Code-only tools (CronCreate, EnterWorktree, Agent, etc.) are blocked because they require capabilities that external clients don't support.
234
+ - **Single tool round-trip per request** — in passthrough mode, the SDK is configured with `maxTurns=3` (or 4 for deferred tools). Multi-step agentic loops where Claude needs several consecutive tool calls require the client to re-send after each round.
235
+ - **Blocked tools** — 10 built-in SDK tools (Read, Write, Bash, etc.) are blocked to prevent conflicts with the client's own tools. 19 additional Claude Code-only tools (CronCreate, EnterWorktree, Agent, etc.) are blocked because they require capabilities that external clients don't support.
234
236
  - **Subagent extraction** — Meridian parses the client's Task tool description to extract subagent names and build SDK AgentDefinitions. If the client's agent framework uses a non-standard format, subagent routing may not work automatically.
237
+ - **Scratchpad suppression (passthrough)** — the Claude CLI advertises a proxy-host scratchpad directory that clients can't use; OpenCode 1.18+ permission-blocks writes to it. Meridian suppresses it in passthrough mode (`CLAUDE_CODE_SESSION_KIND=bg` on the subprocess). Kill switch: `MERIDIAN_SUPPRESS_SCRATCHPAD=0`.
235
238
  - **Anthropic server tools not supported** — native server-side tools (`web_search_*`, `web_fetch_*`) are a raw Anthropic API feature (billed to an API key) that emits `server_tool_use` / `web_search_tool_result` blocks the Claude Max / Agent SDK path cannot produce. A request carrying one is rejected with a `400` explaining the fix. If a plugin needs server-side web search (e.g. [`opencode-websearch`](https://github.com/emilsvennesson/opencode-websearch)), give it its **own** provider pointed at `https://api.anthropic.com` with your `ANTHROPIC_API_KEY` — don't route that call through Meridian.
236
239
 
240
+ ### Troubleshooting: "aborted" tool calls
241
+
242
+ Two very different things can carry the word "abort" — one is normal, one is always a bug:
243
+
244
+ - **Normal (invisible):** Meridian intentionally stops its internal SDK subprocess after your tool calls are captured — this is the optimization that avoids a wasted, billed model turn per tool call. It never appears in your client; log lines like `passthrough.early_stop` or `sdk_termination reason=aborted` in Meridian's own logs are calm, expected bookkeeping.
245
+ - **A bug (report it):** an **empty tool call in your client UI** — `tool {}` with "Tool execution aborted" — is never expected behavior, on any version. It means a call was cut off in transit.
246
+
247
+ **The definitive check:** the `/telemetry` dashboard's **Envelope** card. Meridian audits its own output on every response — green "wire contract clean" means every tool call was delivered intact regardless of what internal logs say. If it shows red, the logs contain `ENVELOPE VIOLATION` lines with request IDs — include those in a bug report and it can usually be root-caused directly.
248
+
237
249
  ## Multi-Profile Support
238
250
 
239
251
  Meridian can route requests to different Claude accounts. Each **profile** is a named auth context — a separate Claude login with its own OAuth tokens. Switch between personal and work accounts, or share a single Meridian instance across teams.
@@ -289,7 +301,7 @@ meridian profile switch work
289
301
  curl -H "x-meridian-profile: work" ...
290
302
  ```
291
303
 
292
- You can also switch profiles from the web UI at `http://127.0.0.1:3456/profiles` a dropdown appears in the nav bar on all pages when profiles are configured.
304
+ You can also switch profiles from the web UI click an account card on the home page (`http://127.0.0.1:3456/`) or use the Profiles page at `/profiles`. The site header on every page shows which profile is active.
293
305
 
294
306
  ### Sticky session routing
295
307
 
@@ -408,6 +420,7 @@ Add a provider to `~/.config/crush/crush.json`:
408
420
  "base_url": "http://127.0.0.1:3456",
409
421
  "api_key": "dummy",
410
422
  "models": [
423
+ { "id": "claude-fable-5", "name": "Claude Fable 5 (1M)", "context_window": 1000000, "default_max_tokens": 32768, "can_reason": true, "supports_attachments": true },
411
424
  { "id": "claude-opus-4-8", "name": "Claude Opus 4.8 (1M)", "context_window": 1000000, "default_max_tokens": 32768, "can_reason": true, "supports_attachments": true },
412
425
  { "id": "claude-opus-4-7", "name": "Claude Opus 4.7 (1M)", "context_window": 1000000, "default_max_tokens": 32768, "can_reason": true, "supports_attachments": true },
413
426
  { "id": "claude-sonnet-4-6", "name": "Claude Sonnet 4.6 (1M)", "context_window": 1000000, "default_max_tokens": 64000, "can_reason": true, "supports_attachments": true },
@@ -433,6 +446,7 @@ Add Meridian as a custom model provider in `~/.factory/settings.json`:
433
446
  ```json
434
447
  {
435
448
  "customModels": [
449
+ { "model": "claude-fable-5", "name": "Fable 5 (Meridian)", "provider": "anthropic", "baseUrl": "http://127.0.0.1:3456", "apiKey": "x" },
436
450
  { "model": "claude-opus-4-8", "name": "Opus 4.8 (Meridian)", "provider": "anthropic", "baseUrl": "http://127.0.0.1:3456", "apiKey": "x" },
437
451
  { "model": "claude-opus-4-7", "name": "Opus 4.7 (Meridian)", "provider": "anthropic", "baseUrl": "http://127.0.0.1:3456", "apiKey": "x" },
438
452
  { "model": "claude-sonnet-4-6", "name": "Sonnet 4.6 (Meridian)", "provider": "anthropic", "baseUrl": "http://127.0.0.1:3456", "apiKey": "x" },
@@ -645,6 +659,7 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:3456
645
659
  | [Open WebUI](https://github.com/open-webui/open-webui) | ✅ Verified | OpenAI-compatible endpoints — set base URL to `http://127.0.0.1:3456` |
646
660
  | [Pi](https://github.com/mariozechner/pi-coding-agent) | ✅ Verified | models.json config (see above) — full tool support via passthrough; detected via `x-meridian-agent: pi` header |
647
661
  | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | ✅ Verified | `ANTHROPIC_BASE_URL` — remote clients share a Max subscription over the network; client CWD preserved in system prompt |
662
+ | [Cherry Studio](https://github.com/CherryHQ/cherry-studio) | ✅ Verified | `cherry` adapter (see above) — chat client with Claude's built-in web search via internal mode |
648
663
  | [Continue](https://github.com/continuedev/continue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http://127.0.0.1:3456` |
649
664
 
650
665
  Tested an agent or built a plugin? [Open an issue](https://github.com/rynfar/meridian/issues) and we'll add it.
@@ -662,6 +677,9 @@ src/proxy/
662
677
  │ ├── crush.ts ← Crush adapter
663
678
  │ ├── droid.ts ← Droid adapter
664
679
  │ ├── pi.ts ← Pi adapter
680
+ │ ├── cherry.ts ← Cherry Studio adapter (internal mode + web search)
681
+ │ ├── claudecode.ts ← Claude Code adapter (remote clients sharing a Max host)
682
+ │ ├── openai.ts ← OpenAI-endpoint adapter (/v1/chat/completions)
665
683
  │ └── passthrough.ts ← LiteLLM passthrough adapter
666
684
  ├── query.ts ← SDK query options builder
667
685
  ├── errors.ts ← Error classification
@@ -679,7 +697,7 @@ src/proxy/
679
697
  └── passthroughTools.ts ← Tool forwarding mode
680
698
  telemetry/
681
699
  ├── ...
682
- ├── profileBar.ts ← Shared profile switcher bar
700
+ ├── profileBar.ts ← Shared site header (brand, nav, status, active profile)
683
701
  └── profilePage.ts ← Profile management page
684
702
  plugin/
685
703
  └── meridian.ts ← OpenCode plugin (session headers + agent mode)
@@ -709,6 +727,7 @@ Agents are identified from request headers automatically:
709
727
  | `opencode/` User-Agent | OpenCode |
710
728
  | `factory-cli/` User-Agent | Droid |
711
729
  | `Charm-Crush/` User-Agent | Crush |
730
+ | `claude-cli/` User-Agent | Claude Code (unless `MERIDIAN_DEFAULT_AGENT` overrides — Pi mimics this UA) |
712
731
  | `litellm/` UA or `x-litellm-*` headers | LiteLLM passthrough |
713
732
  | *(anything else)* | `MERIDIAN_DEFAULT_AGENT` env var, or OpenCode |
714
733
 
@@ -752,13 +771,23 @@ ANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http://meridian-host:3456 o
752
771
  | `MERIDIAN_NO_FILE_CHANGES` | `CLAUDE_PROXY_NO_FILE_CHANGES` | unset | Disable "Files changed" summary in responses |
753
772
  | `MERIDIAN_SONNET_MODEL` | `CLAUDE_PROXY_SONNET_MODEL` | `sonnet` | Sonnet context tier: `sonnet` (200k, default) or `sonnet[1m]` (1M, requires Extra Usage†) |
754
773
  | `MERIDIAN_1M_CONTEXT_SUPPORT` | `CLAUDE_PROXY_1M_CONTEXT_SUPPORT` | unset | Set to `0`/`false`/`no` to disable 1M context entirely — every model resolves to its 200k base variant, so Meridian never requests the extended window (avoids Extra Usage on 1M). |
755
- | `MERIDIAN_DEFAULT_AGENT` | — | `opencode` | Default adapter for unrecognized agents: `opencode`, `forgecode`, `pi`, `crush`, `droid`, `passthrough`. Requires restart. |
774
+ | `MERIDIAN_DEFAULT_AGENT` | — | `opencode` | Default adapter for unrecognized agents: `opencode`, `forgecode`, `pi`, `crush`, `droid`, `cherry`, `claudecode`, `passthrough`. Requires restart. |
775
+ | `MERIDIAN_ROUTING` | — | `active` | Session-to-profile routing: `active` (all traffic to the active profile) or `sticky` ([sticky session routing](#sticky-session-routing)) |
776
+ | `MERIDIAN_PASSTHROUGH_EARLY_STOP` | — | `1` | Set to `0` to disable [digest-turn elimination](#how-tool-calling-works-in-passthrough) and restore the old end-of-turn behavior |
777
+ | `MERIDIAN_SUPPRESS_SCRATCHPAD` | — | `1` | Set to `0` to let the SDK advertise its proxy-host scratchpad directory in passthrough mode |
778
+ | `MERIDIAN_PRICING_CONFIG` | `CLAUDE_PROXY_PRICING_CONFIG` | `~/.config/meridian/model-pricing.json` | Path to the model pricing overrides file used by cost estimation |
756
779
  | `MERIDIAN_PROFILES` | — | unset | JSON array of profile configs (overrides disk discovery). See [Multi-Profile Support](#multi-profile-support). |
757
780
  | `MERIDIAN_DEFER_TOOL_THRESHOLD` | — | `15` | Number of tools before non-core tools are deferred via ToolSearch. Set to `0` to disable. |
758
- | `MERIDIAN_TELEMETRY_PERSIST` | | unset | Enable SQLite telemetry persistence. Data survives proxy restarts. |
759
- | `MERIDIAN_TELEMETRY_DB` | | `~/.config/meridian/telemetry.db` | SQLite database path (when persistence is enabled) |
760
- | `MERIDIAN_TELEMETRY_RETENTION_DAYS` | | `7` | Days to retain telemetry data before cleanup |
781
+ | `MERIDIAN_TELEMETRY_PERSIST` | `CLAUDE_PROXY_TELEMETRY_PERSIST` | unset | Enable SQLite telemetry persistence. Data survives proxy restarts. |
782
+ | `MERIDIAN_TELEMETRY_DB` | `CLAUDE_PROXY_TELEMETRY_DB` | `~/.config/meridian/telemetry.db` | SQLite database path (when persistence is enabled) |
783
+ | `MERIDIAN_TELEMETRY_RETENTION_DAYS` | `CLAUDE_PROXY_TELEMETRY_RETENTION_DAYS` | `7` | Days to retain telemetry data before cleanup |
761
784
  | `MERIDIAN_DEFAULT_PROFILE` | — | *(first profile)* | Default profile ID when no header is sent |
785
+ | `MERIDIAN_ADAPTER_INSTANCES` | — | unset | JSON [adapter instance](#adapter-instances) definitions, overriding `~/.config/meridian/adapter-instances.json` |
786
+ | `MERIDIAN_BETA_POLICY` | — | `allow-safe` | Client `anthropic-beta` header handling: `allow-safe`, `strip-all`, or `allow-all` |
787
+ | `MERIDIAN_DEFAULT_{FABLE,OPUS,SONNET,HAIKU}_MODEL` | — | canonical ids | Pin the model id the SDK resolves for each tier alias (e.g. `MERIDIAN_DEFAULT_OPUS_MODEL`) |
788
+ | `MERIDIAN_SESSION_DIR` | `CLAUDE_PROXY_SESSION_DIR` | `~/.cache/meridian` | Directory for the persisted session store |
789
+ | `MERIDIAN_DEBUG` | `CLAUDE_PROXY_DEBUG` | unset | Set to `1` for verbose request/session logging |
790
+ | `MERIDIAN_SILENT` | `CLAUDE_PROXY_SILENT` | unset | Set to `1` to suppress startup output (used by embedding plugins) |
762
791
 
763
792
  †Sonnet 1M requires Extra Usage on all plans including Max ([docs](https://code.claude.com/docs/en/model-config#extended-context)). Opus 1M is included with Max/Team/Enterprise at no extra cost.
764
793
 
@@ -781,13 +810,17 @@ ANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http://meridian-host:3456 o
781
810
  | `GET /profiles` | Profile management page |
782
811
  | `GET /profiles/list` | List profiles with auth status (JSON) |
783
812
  | `POST /profiles/active` | Switch the active profile |
813
+ | `GET /v1/usage/quota` | Usage windows for the active profile (JSON) |
814
+ | `GET /v1/usage/quota/all` | Usage windows for every profile (JSON) |
815
+ | `GET /settings` | SDK feature toggles + model pricing UI |
816
+ | `GET /plugins` | Plugin management page (`/plugins/list`, `POST /plugins/reload` for JSON/actions) |
784
817
 
785
818
  Health response example:
786
819
 
787
820
  ```json
788
821
  {
789
822
  "status": "healthy",
790
- "version": "1.34.1",
823
+ "version": "1.50.0",
791
824
  "auth": { "loggedIn": true, "email": "you@example.com", "subscriptionType": "max" },
792
825
  "mode": "internal",
793
826
  "plugin": { "opencode": "configured" }
@@ -855,7 +888,7 @@ Paths must be absolute — the loader does not expand `~`.
855
888
  | `meridian setup` | Configure the OpenCode plugin in `~/.config/opencode/opencode.json` |
856
889
  | `meridian profile add <name> [--headless]` | Add a profile and authenticate via Claude OAuth; `--headless` prints a URL, prompts for the returned code, and stores the exchanged credentials |
857
890
  | `meridian profile add <name> --oauth-token [TOKEN]` | Add a headless profile from a `claude setup-token` value (prompts when `TOKEN` is omitted) |
858
- | `meridian profile list` | List all profiles and their auth status |
891
+ | `meridian profile list` (alias `profile ls`) | List all profiles and their auth status |
859
892
  | `meridian profile switch <name>` | Switch the active profile (requires running proxy) |
860
893
  | `meridian profile login <name> [--headless]` | Re-authenticate an expired profile (browser-login profiles only); `--headless` uses the URL/code flow |
861
894
  | `meridian profile remove <name>` | Remove a profile and its credentials |
@@ -941,10 +974,10 @@ npm run build # build with bun + tsc
941
974
  ## FAQ
942
975
 
943
976
  **Is this allowed by Anthropic's terms?**
944
- Meridian uses the official Claude Code SDK — the same SDK Anthropic publishes and documents for programmatic access. It does not intercept credentials, modify binaries, or bypass any authentication. All requests flow through the SDK's own authentication and rate-limiting mechanisms.
977
+ Meridian uses the official Claude Agent SDK — the same SDK Anthropic publishes and documents for programmatic access. It does not intercept credentials, modify binaries, or bypass any authentication. All requests flow through the SDK's own authentication and rate-limiting mechanisms.
945
978
 
946
979
  **How is this different from using an API key?**
947
- API keys provide direct API access billed per token. Claude Max includes programmatic access through the Claude Code SDK. Meridian translates SDK responses into the standard Anthropic API format, allowing compatible tools to connect through Claude Code.
980
+ API keys provide direct API access billed per token. Claude Max includes programmatic access through the Claude Agent SDK. Meridian translates SDK responses into the standard Anthropic API format, allowing compatible tools to connect through Claude Code.
948
981
 
949
982
  **What happens if my OAuth token expires?**
950
983
  Tokens expire roughly every 8 hours. Meridian detects the expiry, refreshes the token automatically, and retries the request — so requests continue transparently. If the refresh fails (e.g. the refresh token has expired after weeks of inactivity), Meridian returns a clear error telling you to run `claude login`.
package/assets/banner.svg CHANGED
@@ -1,15 +1,30 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 400" fill="none">
2
2
  <defs>
3
3
  <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
- <stop offset="0%" stop-color="#0f0b1a"/>
5
- <stop offset="100%" stop-color="#1a1030"/>
4
+ <stop offset="0%" stop-color="#0d1117"/>
5
+ <stop offset="100%" stop-color="#161b22"/>
6
6
  </linearGradient>
7
+ <linearGradient id="mGrad" x1="0" y1="0" x2="0" y2="190" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="#58a6ff"/>
9
+ <stop offset="1" stop-color="#bc8cff"/>
10
+ </linearGradient>
11
+ <radialGradient id="glowBlue" cx="0.25" cy="0.1" r="0.6">
12
+ <stop stop-color="#58a6ff" stop-opacity="0.10"/>
13
+ <stop offset="1" stop-color="#58a6ff" stop-opacity="0"/>
14
+ </radialGradient>
15
+ <radialGradient id="glowViolet" cx="0.85" cy="0.95" r="0.6">
16
+ <stop stop-color="#bc8cff" stop-opacity="0.10"/>
17
+ <stop offset="1" stop-color="#bc8cff" stop-opacity="0"/>
18
+ </radialGradient>
7
19
  </defs>
8
20
 
9
21
  <rect width="1200" height="400" rx="16" fill="url(#bg)"/>
22
+ <rect width="1200" height="400" rx="16" fill="url(#glowBlue)"/>
23
+ <rect width="1200" height="400" rx="16" fill="url(#glowViolet)"/>
24
+ <rect x="0.5" y="0.5" width="1199" height="399" rx="15.5" stroke="#30363d"/>
10
25
 
11
26
  <!-- Subtle dot grid -->
12
- <g opacity="0.05" fill="#a78bfa">
27
+ <g opacity="0.06" fill="#58a6ff">
13
28
  <circle cx="100" cy="100" r="1.5"/><circle cx="200" cy="100" r="1.5"/><circle cx="300" cy="100" r="1.5"/>
14
29
  <circle cx="100" cy="200" r="1.5"/><circle cx="200" cy="200" r="1.5"/><circle cx="300" cy="200" r="1.5"/>
15
30
  <circle cx="100" cy="300" r="1.5"/><circle cx="200" cy="300" r="1.5"/><circle cx="300" cy="300" r="1.5"/>
@@ -18,29 +33,21 @@
18
33
  <circle cx="900" cy="300" r="1.5"/><circle cx="1000" cy="300" r="1.5"/><circle cx="1100" cy="300" r="1.5"/>
19
34
  </g>
20
35
 
21
- <!-- Logo mark — V2 full globe -->
22
- <g transform="translate(380, 90)">
23
- <!-- Meridian axis -->
24
- <line x1="80" y1="8" x2="80" y2="192" stroke="#8B7CF6" stroke-width="5" stroke-linecap="round"/>
25
- <!-- Latitude arcs outer -->
26
- <path d="M28 50 A60 60 0 0 1 132 50" fill="none" stroke="#C4B5FD" stroke-width="2.5" opacity="0.4"/>
27
- <path d="M28 150 A60 60 0 0 0 132 150" fill="none" stroke="#C4B5FD" stroke-width="2.5" opacity="0.4"/>
28
- <!-- Latitude arcs — inner -->
29
- <path d="M38 78 A46 46 0 0 1 122 78" fill="none" stroke="#C4B5FD" stroke-width="1.5" opacity="0.2"/>
30
- <path d="M38 122 A46 46 0 0 0 122 122" fill="none" stroke="#C4B5FD" stroke-width="1.5" opacity="0.2"/>
31
- <!-- Poles -->
32
- <circle cx="80" cy="8" r="8" fill="#C4B5FD"/>
33
- <circle cx="80" cy="192" r="8" fill="#C4B5FD"/>
34
- <!-- Center node -->
35
- <circle cx="80" cy="100" r="8" fill="#8B7CF6"/>
36
+ <!-- Logo mark — gradient globe -->
37
+ <g transform="translate(365, 105)">
38
+ <circle cx="95" cy="95" r="75" stroke="url(#mGrad)" stroke-width="10"/>
39
+ <ellipse cx="95" cy="95" rx="31" ry="75" stroke="url(#mGrad)" stroke-width="7" opacity="0.8"/>
40
+ <path d="M20 95h150" stroke="url(#mGrad)" stroke-width="6" opacity="0.4"/>
41
+ <circle cx="95" cy="20" r="13" fill="#58a6ff"/>
42
+ <circle cx="95" cy="170" r="13" fill="#bc8cff"/>
36
43
  </g>
37
44
 
38
45
  <!-- Wordmark -->
39
- <text x="540" y="195" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="72" font-weight="700" fill="#e0e7ff" letter-spacing="10">MERIDIAN</text>
46
+ <text x="600" y="195" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="72" font-weight="700" fill="#e6edf3" letter-spacing="10">MERIDIAN</text>
40
47
 
41
48
  <!-- Tagline -->
42
- <text x="543" y="240" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="17" font-weight="600" fill="#8B7CF6" letter-spacing="3">HARNESS CLAUDE, YOUR WAY.</text>
49
+ <text x="603" y="240" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="17" font-weight="600" fill="#58a6ff" letter-spacing="3">HARNESS CLAUDE, YOUR WAY.</text>
43
50
 
44
51
  <!-- Subtitle -->
45
- <text x="543" y="278" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="14" font-weight="300" fill="rgba(255,255,255,0.35)">Local Anthropic API powered by the Claude Code SDK</text>
52
+ <text x="603" y="278" font-family="Inter, -apple-system, 'SF Pro Display', 'Segoe UI', Helvetica, Arial, sans-serif" font-size="14" font-weight="300" fill="#8b949e">Local Anthropic API powered by the Claude Agent SDK</text>
46
53
  </svg>
Binary file
@@ -1,54 +1,60 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none">
2
- <rect width="512" height="512" rx="112" fill="#1C1830"/>
3
-
2
+ <defs>
3
+ <linearGradient id="mGrad" x1="256" y1="40" x2="256" y2="472" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#58a6ff"/>
5
+ <stop offset="1" stop-color="#bc8cff"/>
6
+ </linearGradient>
7
+ <linearGradient id="chestGrad" x1="256" y1="360" x2="256" y2="448" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="#58a6ff"/>
9
+ <stop offset="1" stop-color="#bc8cff"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect width="512" height="512" rx="112" fill="#0d1117"/>
13
+
4
14
  <!-- Antenna -->
5
- <line x1="256" y1="72" x2="256" y2="115" stroke="#A78BFA" stroke-width="8" stroke-linecap="round"/>
6
- <circle cx="256" cy="64" r="14" fill="#C4B5FD"/>
15
+ <line x1="256" y1="72" x2="256" y2="115" stroke="#58a6ff" stroke-width="8" stroke-linecap="round"/>
16
+ <circle cx="256" cy="64" r="14" fill="#58a6ff"/>
7
17
  <!-- Antenna signal arcs -->
8
- <path d="M228 52 A32 32 0 0 1 284 52" fill="none" stroke="#C4B5FD" stroke-width="3" opacity="0.4" stroke-linecap="round"/>
9
- <path d="M216 40 A44 44 0 0 1 296 40" fill="none" stroke="#C4B5FD" stroke-width="2.5" opacity="0.25" stroke-linecap="round"/>
10
-
18
+ <path d="M228 52 A32 32 0 0 1 284 52" fill="none" stroke="#58a6ff" stroke-width="3" opacity="0.4" stroke-linecap="round"/>
19
+ <path d="M216 40 A44 44 0 0 1 296 40" fill="none" stroke="#58a6ff" stroke-width="2.5" opacity="0.25" stroke-linecap="round"/>
20
+
11
21
  <!-- Robot head -->
12
- <rect x="128" y="115" width="256" height="200" rx="40" fill="#2D2750"/>
13
- <rect x="128" y="115" width="256" height="200" rx="40" fill="none" stroke="#8B7CF6" stroke-width="4"/>
14
-
15
- <!-- Eyes — screens with Meridian purple glow -->
16
- <rect x="170" y="165" width="68" height="52" rx="14" fill="#1C1830" stroke="#8B7CF6" stroke-width="3"/>
17
- <rect x="274" y="165" width="68" height="52" rx="14" fill="#1C1830" stroke="#8B7CF6" stroke-width="3"/>
22
+ <rect x="128" y="115" width="256" height="200" rx="40" fill="#161b22"/>
23
+ <rect x="128" y="115" width="256" height="200" rx="40" fill="none" stroke="url(#mGrad)" stroke-width="4"/>
24
+
25
+ <!-- Eyes — screens with a friendly glow -->
26
+ <rect x="170" y="165" width="68" height="52" rx="14" fill="#0d1117" stroke="#58a6ff" stroke-width="3"/>
27
+ <rect x="274" y="165" width="68" height="52" rx="14" fill="#0d1117" stroke="#58a6ff" stroke-width="3"/>
18
28
  <!-- Eye glow -->
19
- <circle cx="204" cy="191" r="16" fill="#8B7CF6" opacity="0.8"/>
20
- <circle cx="308" cy="191" r="16" fill="#8B7CF6" opacity="0.8"/>
29
+ <circle cx="204" cy="191" r="16" fill="#58a6ff" opacity="0.85"/>
30
+ <circle cx="308" cy="191" r="16" fill="#58a6ff" opacity="0.85"/>
21
31
  <!-- Eye highlights -->
22
- <circle cx="210" cy="185" r="5" fill="#C4B5FD" opacity="0.6"/>
23
- <circle cx="314" cy="185" r="5" fill="#C4B5FD" opacity="0.6"/>
24
-
32
+ <circle cx="210" cy="185" r="5" fill="#bc8cff" opacity="0.7"/>
33
+ <circle cx="314" cy="185" r="5" fill="#bc8cff" opacity="0.7"/>
34
+
25
35
  <!-- Mouth — friendly LED strip -->
26
- <rect x="196" y="248" width="120" height="24" rx="12" fill="#1C1830" stroke="#8B7CF6" stroke-width="2"/>
27
- <circle cx="220" cy="260" r="5" fill="#C4B5FD" opacity="0.7"/>
28
- <circle cx="244" cy="260" r="5" fill="#8B7CF6"/>
29
- <circle cx="268" cy="260" r="5" fill="#C4B5FD" opacity="0.7"/>
30
- <circle cx="292" cy="260" r="5" fill="#8B7CF6" opacity="0.5"/>
31
-
36
+ <rect x="196" y="248" width="120" height="24" rx="12" fill="#0d1117" stroke="#58a6ff" stroke-width="2"/>
37
+ <circle cx="220" cy="260" r="5" fill="#58a6ff" opacity="0.7"/>
38
+ <circle cx="244" cy="260" r="5" fill="#bc8cff"/>
39
+ <circle cx="268" cy="260" r="5" fill="#58a6ff" opacity="0.7"/>
40
+ <circle cx="292" cy="260" r="5" fill="#bc8cff" opacity="0.5"/>
41
+
32
42
  <!-- Ear bolts -->
33
- <circle cx="118" cy="200" r="16" fill="#2D2750" stroke="#8B7CF6" stroke-width="3"/>
34
- <circle cx="118" cy="200" r="6" fill="#8B7CF6"/>
35
- <circle cx="394" cy="200" r="16" fill="#2D2750" stroke="#8B7CF6" stroke-width="3"/>
36
- <circle cx="394" cy="200" r="6" fill="#8B7CF6"/>
37
-
43
+ <circle cx="118" cy="200" r="16" fill="#161b22" stroke="#58a6ff" stroke-width="3"/>
44
+ <circle cx="118" cy="200" r="6" fill="#58a6ff"/>
45
+ <circle cx="394" cy="200" r="16" fill="#161b22" stroke="#bc8cff" stroke-width="3"/>
46
+ <circle cx="394" cy="200" r="6" fill="#bc8cff"/>
47
+
38
48
  <!-- Neck -->
39
- <rect x="228" y="315" width="56" height="28" rx="6" fill="#2D2750" stroke="#8B7CF6" stroke-width="2"/>
40
-
49
+ <rect x="228" y="315" width="56" height="28" rx="6" fill="#161b22" stroke="#58a6ff" stroke-width="2"/>
50
+
41
51
  <!-- Body / chest plate -->
42
- <rect x="148" y="343" width="216" height="120" rx="30" fill="#2D2750" stroke="#8B7CF6" stroke-width="4"/>
43
-
44
- <!-- Meridian logo on chest — the globe axis + arcs -->
45
- <line x1="256" y1="365" x2="256" y2="443" stroke="#8B7CF6" stroke-width="6" stroke-linecap="round"/>
46
- <!-- Chest latitude arcs -->
47
- <path d="M212 382 A48 48 0 0 1 300 382" fill="none" stroke="#C4B5FD" stroke-width="3" opacity="0.5"/>
48
- <path d="M212 426 A48 48 0 0 0 300 426" fill="none" stroke="#C4B5FD" stroke-width="3" opacity="0.5"/>
49
- <!-- Chest poles -->
50
- <circle cx="256" cy="365" r="8" fill="#C4B5FD"/>
51
- <circle cx="256" cy="443" r="8" fill="#C4B5FD"/>
52
- <!-- Chest center node -->
53
- <circle cx="256" cy="404" r="6" fill="#8B7CF6"/>
52
+ <rect x="148" y="343" width="216" height="120" rx="30" fill="#161b22" stroke="url(#mGrad)" stroke-width="4"/>
53
+
54
+ <!-- Meridian mark on chest — the gradient globe -->
55
+ <circle cx="256" cy="404" r="40" stroke="url(#chestGrad)" stroke-width="6"/>
56
+ <ellipse cx="256" cy="404" rx="17" ry="40" stroke="url(#chestGrad)" stroke-width="4" opacity="0.8"/>
57
+ <path d="M216 404h80" stroke="url(#chestGrad)" stroke-width="3.5" opacity="0.4"/>
58
+ <circle cx="256" cy="364" r="7" fill="#58a6ff"/>
59
+ <circle cx="256" cy="444" r="7" fill="#bc8cff"/>
54
60
  </svg>
@@ -1,24 +1,24 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 920 310" fill="none">
2
2
  <style>
3
- .title { font-family: 'Inter', -apple-system, sans-serif; font-size: 20px; font-weight: 700; fill: #C4B5FD; }
4
- .box-label { font-family: 'Inter', -apple-system, sans-serif; font-size: 13px; font-weight: 600; fill: #F5F5F7; }
5
- .box-sub { font-family: 'JetBrains Mono', 'SF Mono', monospace; font-size: 10px; fill: #8B7CF6; }
6
- .box-detail { font-family: 'Inter', -apple-system, sans-serif; font-size: 10px; fill: #9898B4; }
7
- .tag { font-family: 'Inter', -apple-system, sans-serif; font-size: 9px; font-weight: 600; fill: #5E5B72; letter-spacing: 1px; }
3
+ .title { font-family: 'Inter', -apple-system, sans-serif; font-size: 20px; font-weight: 700; fill: #58a6ff; }
4
+ .box-label { font-family: 'Inter', -apple-system, sans-serif; font-size: 13px; font-weight: 600; fill: #e6edf3; }
5
+ .box-sub { font-family: 'JetBrains Mono', 'SF Mono', monospace; font-size: 10px; fill: #58a6ff; }
6
+ .box-detail { font-family: 'Inter', -apple-system, sans-serif; font-size: 10px; fill: #8b949e; }
7
+ .tag { font-family: 'Inter', -apple-system, sans-serif; font-size: 9px; font-weight: 600; fill: #6e7681; letter-spacing: 1px; }
8
8
  .step-num { font-family: 'Inter', -apple-system, sans-serif; font-size: 10px; font-weight: 700; }
9
- .footer { font-family: 'Inter', -apple-system, sans-serif; font-size: 11px; fill: #5E5B72; }
10
- .arrow-label { font-family: 'Inter', -apple-system, sans-serif; font-size: 9px; fill: #5E5B72; text-anchor: middle; }
9
+ .footer { font-family: 'Inter', -apple-system, sans-serif; font-size: 11px; fill: #6e7681; }
10
+ .arrow-label { font-family: 'Inter', -apple-system, sans-serif; font-size: 9px; fill: #6e7681; text-anchor: middle; }
11
11
  </style>
12
12
 
13
- <rect width="920" height="310" rx="16" fill="#13111C"/>
14
- <rect x="0.5" y="0.5" width="919" height="309" rx="15.5" stroke="#2A2740" stroke-width="1" fill="none"/>
13
+ <rect width="920" height="310" rx="16" fill="#0d1117"/>
14
+ <rect x="0.5" y="0.5" width="919" height="309" rx="15.5" stroke="#30363d" stroke-width="1" fill="none"/>
15
15
 
16
16
  <text class="title" x="460" y="38" text-anchor="middle">How it works</text>
17
17
 
18
18
  <!-- ═══ STEP 1: YOUR TOOLS ═══ -->
19
- <rect x="32" y="64" width="156" height="140" rx="12" fill="#1C1930" stroke="#2A2740" stroke-width="1"/>
20
- <rect x="44" y="54" width="18" height="18" rx="9" fill="#8B7CF6"/>
21
- <text class="step-num" x="53" y="67" text-anchor="middle" fill="#13111C">1</text>
19
+ <rect x="32" y="64" width="156" height="140" rx="12" fill="#161b22" stroke="#30363d" stroke-width="1"/>
20
+ <rect x="44" y="54" width="18" height="18" rx="9" fill="#58a6ff"/>
21
+ <text class="step-num" x="53" y="67" text-anchor="middle" fill="#0d1117">1</text>
22
22
  <text class="box-label" x="110" y="100" text-anchor="middle">Your tools</text>
23
23
  <text class="box-detail" x="110" y="122" text-anchor="middle">OpenCode, Cline</text>
24
24
  <text class="box-detail" x="110" y="136" text-anchor="middle">Continue, Crush, aider</text>
@@ -26,62 +26,62 @@
26
26
  <text class="tag" x="110" y="192" text-anchor="middle">ANTHROPIC API FORMAT</text>
27
27
 
28
28
  <!-- ═══ ARROWS 1 ↔ 2 ═══ -->
29
- <line x1="200" y1="122" x2="250" y2="122" stroke="#8B7CF6" stroke-width="1.5"/>
30
- <polygon points="248,118 256,122 248,126" fill="#8B7CF6"/>
29
+ <line x1="200" y1="122" x2="250" y2="122" stroke="#58a6ff" stroke-width="1.5"/>
30
+ <polygon points="248,118 256,122 248,126" fill="#58a6ff"/>
31
31
  <text class="arrow-label" x="226" y="114">request</text>
32
- <line x1="250" y1="142" x2="200" y2="142" stroke="#3D3858" stroke-width="1"/>
33
- <polygon points="202,138 194,142 202,146" fill="#3D3858"/>
32
+ <line x1="250" y1="142" x2="200" y2="142" stroke="#484f58" stroke-width="1"/>
33
+ <polygon points="202,138 194,142 202,146" fill="#484f58"/>
34
34
  <text class="arrow-label" x="226" y="162">response</text>
35
35
 
36
36
  <!-- ═══ STEP 2: MERIDIAN ═══ -->
37
- <rect x="264" y="64" width="156" height="140" rx="12" fill="#1C1930" stroke="#8B7CF6" stroke-width="1.5"/>
38
- <rect x="276" y="54" width="18" height="18" rx="9" fill="#8B7CF6"/>
39
- <text class="step-num" x="285" y="67" text-anchor="middle" fill="#13111C">2</text>
37
+ <rect x="264" y="64" width="156" height="140" rx="12" fill="#161b22" stroke="#58a6ff" stroke-width="1.5"/>
38
+ <rect x="276" y="54" width="18" height="18" rx="9" fill="#58a6ff"/>
39
+ <text class="step-num" x="285" y="67" text-anchor="middle" fill="#0d1117">2</text>
40
40
  <text class="box-label" x="342" y="100" text-anchor="middle">Meridian</text>
41
41
  <text class="box-sub" x="342" y="118" text-anchor="middle">localhost:3456</text>
42
42
  <text class="box-detail" x="342" y="140" text-anchor="middle">Local proxy server</text>
43
43
  <text class="box-detail" x="342" y="154" text-anchor="middle">Translates API calls</text>
44
- <text class="box-detail" x="342" y="168" text-anchor="middle">to Claude Code SDK</text>
44
+ <text class="box-detail" x="342" y="168" text-anchor="middle">to the Claude Agent SDK</text>
45
45
  <text class="tag" x="342" y="192" text-anchor="middle">BRIDGES THE GAP</text>
46
46
 
47
47
  <!-- ═══ ARROWS 2 ↔ 3 ═══ -->
48
- <line x1="432" y1="122" x2="482" y2="122" stroke="#8B7CF6" stroke-width="1.5"/>
49
- <polygon points="480,118 488,122 480,126" fill="#8B7CF6"/>
48
+ <line x1="432" y1="122" x2="482" y2="122" stroke="#58a6ff" stroke-width="1.5"/>
49
+ <polygon points="480,118 488,122 480,126" fill="#58a6ff"/>
50
50
  <text class="arrow-label" x="458" y="114">SDK call</text>
51
- <line x1="482" y1="142" x2="432" y2="142" stroke="#3D3858" stroke-width="1"/>
52
- <polygon points="434,138 426,142 434,146" fill="#3D3858"/>
51
+ <line x1="482" y1="142" x2="432" y2="142" stroke="#484f58" stroke-width="1"/>
52
+ <polygon points="434,138 426,142 434,146" fill="#484f58"/>
53
53
  <text class="arrow-label" x="458" y="162">result</text>
54
54
 
55
- <!-- ═══ STEP 3: CLAUDE CODE SDK ═══ -->
56
- <rect x="496" y="64" width="172" height="140" rx="12" fill="#1C1930" stroke="#2A2740" stroke-width="1"/>
57
- <rect x="508" y="54" width="18" height="18" rx="9" fill="#8B7CF6"/>
58
- <text class="step-num" x="517" y="67" text-anchor="middle" fill="#13111C">3</text>
59
- <text class="box-label" x="582" y="100" text-anchor="middle">Claude Code SDK</text>
60
- <text class="box-sub" x="582" y="118" text-anchor="middle">@anthropic-ai/claude-code</text>
55
+ <!-- ═══ STEP 3: CLAUDE AGENT SDK ═══ -->
56
+ <rect x="496" y="64" width="172" height="140" rx="12" fill="#161b22" stroke="#30363d" stroke-width="1"/>
57
+ <rect x="508" y="54" width="18" height="18" rx="9" fill="#58a6ff"/>
58
+ <text class="step-num" x="517" y="67" text-anchor="middle" fill="#0d1117">3</text>
59
+ <text class="box-label" x="582" y="100" text-anchor="middle">Claude Agent SDK</text>
60
+ <text class="box-sub" x="582" y="118" text-anchor="middle">@anthropic-ai/claude-agent-sdk</text>
61
61
  <text class="box-detail" x="582" y="140" text-anchor="middle">Official Anthropic SDK</text>
62
62
  <text class="box-detail" x="582" y="154" text-anchor="middle">Handles auth + sessions</text>
63
63
  <text class="tag" x="582" y="192" text-anchor="middle">ANTHROPIC'S OWN SDK</text>
64
64
 
65
65
  <!-- ═══ ARROWS 3 ↔ 4 ═══ -->
66
- <line x1="680" y1="122" x2="726" y2="122" stroke="#8B7CF6" stroke-width="1.5"/>
67
- <polygon points="724,118 732,122 724,126" fill="#8B7CF6"/>
66
+ <line x1="680" y1="122" x2="726" y2="122" stroke="#58a6ff" stroke-width="1.5"/>
67
+ <polygon points="724,118 732,122 724,126" fill="#58a6ff"/>
68
68
  <text class="arrow-label" x="704" y="114">API call</text>
69
- <line x1="726" y1="142" x2="680" y2="142" stroke="#3D3858" stroke-width="1"/>
70
- <polygon points="682,138 674,142 682,146" fill="#3D3858"/>
69
+ <line x1="726" y1="142" x2="680" y2="142" stroke="#484f58" stroke-width="1"/>
70
+ <polygon points="682,138 674,142 682,146" fill="#484f58"/>
71
71
  <text class="arrow-label" x="704" y="162">stream</text>
72
72
 
73
73
  <!-- ═══ STEP 4: CLAUDE ═══ -->
74
- <rect x="740" y="64" width="140" height="140" rx="12" fill="#1C1930" stroke="#2A2740" stroke-width="1"/>
75
- <rect x="752" y="54" width="18" height="18" rx="9" fill="#8B7CF6"/>
76
- <text class="step-num" x="761" y="67" text-anchor="middle" fill="#13111C">4</text>
74
+ <rect x="740" y="64" width="140" height="140" rx="12" fill="#161b22" stroke="#30363d" stroke-width="1"/>
75
+ <rect x="752" y="54" width="18" height="18" rx="9" fill="#58a6ff"/>
76
+ <text class="step-num" x="761" y="67" text-anchor="middle" fill="#0d1117">4</text>
77
77
  <text class="box-label" x="810" y="100" text-anchor="middle">Claude</text>
78
78
  <text class="box-sub" x="810" y="118" text-anchor="middle">api.anthropic.com</text>
79
- <text class="box-detail" x="810" y="140" text-anchor="middle">Opus, Sonnet, Haiku</text>
80
- <text class="box-detail" x="810" y="154" text-anchor="middle">Extended thinking</text>
79
+ <text class="box-detail" x="810" y="140" text-anchor="middle">Fable, Opus, Sonnet</text>
80
+ <text class="box-detail" x="810" y="154" text-anchor="middle">Haiku, extended thinking</text>
81
81
  <text class="tag" x="810" y="192" text-anchor="middle">YOUR SUBSCRIPTION</text>
82
82
 
83
83
  <!-- ═══ BOTTOM ═══ -->
84
- <line x1="60" y1="246" x2="860" y2="246" stroke="#2A2740" stroke-width="1"/>
84
+ <line x1="60" y1="246" x2="860" y2="246" stroke="#30363d" stroke-width="1"/>
85
85
  <text class="footer" x="460" y="274" text-anchor="middle">No API keys needed — authenticates through your existing Claude Code / Max subscription</text>
86
86
 
87
87
  </svg>
Binary file
package/assets/icon.svg CHANGED
@@ -1,16 +1,19 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
- <rect width="64" height="64" rx="14" fill="#1C1830"/>
3
- <!-- Meridian axis -->
4
- <line x1="32" y1="10" x2="32" y2="54" stroke="#8B7CF6" stroke-width="2.5" stroke-linecap="round"/>
5
- <!-- Latitude arcs — outer -->
6
- <path d="M16 20 A18 18 0 0 1 48 20" fill="none" stroke="#C4B5FD" stroke-width="1.2" opacity="0.4"/>
7
- <path d="M16 44 A18 18 0 0 0 48 44" fill="none" stroke="#C4B5FD" stroke-width="1.2" opacity="0.4"/>
8
- <!-- Latitude arcs inner -->
9
- <path d="M20 30 A14 14 0 0 1 44 30" fill="none" stroke="#C4B5FD" stroke-width="0.8" opacity="0.2"/>
10
- <path d="M20 34 A14 14 0 0 0 44 34" fill="none" stroke="#C4B5FD" stroke-width="0.8" opacity="0.2"/>
2
+ <defs>
3
+ <linearGradient id="mGrad" x1="32" y1="8" x2="32" y2="56" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#58a6ff"/>
5
+ <stop offset="1" stop-color="#bc8cff"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="64" height="64" rx="14" fill="#0d1117"/>
9
+ <rect x="0.5" y="0.5" width="63" height="63" rx="13.5" stroke="#30363d"/>
10
+ <!-- Globe -->
11
+ <circle cx="32" cy="32" r="20" stroke="url(#mGrad)" stroke-width="3"/>
12
+ <!-- Prime meridian -->
13
+ <ellipse cx="32" cy="32" rx="8.5" ry="20" stroke="url(#mGrad)" stroke-width="2" opacity="0.8"/>
14
+ <!-- Equator -->
15
+ <path d="M12 32h40" stroke="url(#mGrad)" stroke-width="1.6" opacity="0.4"/>
11
16
  <!-- Poles -->
12
- <circle cx="32" cy="10" r="3.5" fill="#C4B5FD"/>
13
- <circle cx="32" cy="54" r="3.5" fill="#C4B5FD"/>
14
- <!-- Center node -->
15
- <circle cx="32" cy="32" r="3" fill="#8B7CF6"/>
17
+ <circle cx="32" cy="12" r="3.6" fill="#58a6ff"/>
18
+ <circle cx="32" cy="52" r="3.6" fill="#bc8cff"/>
16
19
  </svg>
Binary file