@rynfar/meridian 1.34.1 → 1.37.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.
- package/README.md +144 -27
- package/dist/cli-p9swy5t3.js +67 -0
- package/dist/{cli-g9ypdz51.js → cli-pr79d7nw.js} +9 -5
- package/dist/{cli-bwchvbfb.js → cli-ygx1djsx.js} +1838 -147
- package/dist/cli.js +9 -9
- package/dist/{profileCli-5e3p99k0.js → profileCli-5f15dx7k.js} +1 -1
- package/dist/{profilePage-9nkbct3w.js → profilePage-g5t5t6av.js} +4 -2
- package/dist/{profiles-ntgacztq.js → profiles-edzz1ffd.js} +1 -1
- package/dist/proxy/adapter.d.ts +17 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/crush.d.ts.map +1 -1
- package/dist/proxy/auth.d.ts +27 -0
- package/dist/proxy/auth.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts +1 -1
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +21 -1
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts +56 -0
- package/dist/proxy/sdkFeatures.d.ts.map +1 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/types.d.ts +2 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/server.js +3 -3
- package/dist/{setup-5x116vbs.js → setup-v5pnqe04.js} +1 -1
- package/dist/telemetry/index.d.ts +9 -4
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/logStore.d.ts +4 -25
- package/dist/telemetry/logStore.d.ts.map +1 -1
- package/dist/telemetry/percentiles.d.ts +12 -0
- package/dist/telemetry/percentiles.d.ts.map +1 -0
- package/dist/telemetry/profileBar.d.ts +1 -1
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/prometheus.d.ts +10 -0
- package/dist/telemetry/prometheus.d.ts.map +1 -0
- package/dist/telemetry/routes.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +6 -0
- package/dist/telemetry/settingsPage.d.ts.map +1 -0
- package/dist/telemetry/sqlite.d.ts +7 -0
- package/dist/telemetry/sqlite.d.ts.map +1 -0
- package/dist/telemetry/store.d.ts +3 -3
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +51 -0
- package/dist/telemetry/types.d.ts.map +1 -1
- package/dist/{tokenRefresh-ywwpe8k2.js → tokenRefresh-y7d1qvb3.js} +1 -1
- package/package.json +4 -3
- package/dist/cli-a05ws7rb.js +0 -18
package/README.md
CHANGED
|
@@ -23,18 +23,7 @@ Meridian bridges the Claude Code SDK to the standard Anthropic API. No OAuth int
|
|
|
23
23
|
>
|
|
24
24
|
> What Meridian adds is a **presentation and interoperability layer**. We translate Claude Code's output into the standard Anthropic API format so developers can connect the editors, terminals, and workflows they prefer. The SDK does the work; Meridian formats the result.
|
|
25
25
|
>
|
|
26
|
-
>
|
|
27
|
-
|
|
28
|
-
> [!WARNING]
|
|
29
|
-
> ### Why Meridian does not support OpenClaw
|
|
30
|
-
>
|
|
31
|
-
> There is technically a way to make Meridian work with OpenClaw, but we're not interested in pursuing it.
|
|
32
|
-
>
|
|
33
|
-
> The reason Claude Max offers generous usage limits is because Anthropic can justify it through Claude Code — their harness, their optimizations, their control. OpenClaw blows through that with autonomous workflows that Anthropic has little ability to manage or optimize. Using Opus to check an email when a local model would handle it fine isn't efficient use — it's waste that degrades the plan for everyone.
|
|
34
|
-
>
|
|
35
|
-
> I built Meridian because I believe developers should have the right to use the frontend of their choice. But that right comes with a responsibility: don't wreck the subscription for the rest of us. Sloppy autonomous agents that burn through Claude Max tokens are directly counter-productive to developers like me who depend on the plan being sustainable.
|
|
36
|
-
>
|
|
37
|
-
> Meridian's philosophy is simple — play nice with the SDK, let Anthropic optimize how they see fit, and use the frontend you want within the constraints of Claude Code. OpenClaw is not just a frontend; it's an autonomous system that abuses the Max plan. We won't be supporting it.
|
|
26
|
+
> **Our philosophy is simple: work within the SDK's constraints, not around them.** The generous limits on Claude Max exist because Anthropic can optimize and manage usage through Claude Code. Meridian respects that by building only on the tools Anthropic provides — no shortcuts, no workarounds that create friction. We believe this is how developers keep the freedom to choose their own frontends while keeping the platform sustainable for everyone.
|
|
38
27
|
|
|
39
28
|
## Quick Start
|
|
40
29
|
|
|
@@ -81,6 +70,68 @@ The Claude Code SDK provides programmatic access to Claude. But your favorite co
|
|
|
81
70
|
- **Multimodal** — images, documents, and file attachments pass through to Claude
|
|
82
71
|
- **Multi-profile** — switch between Claude accounts instantly, no restart needed
|
|
83
72
|
- **Telemetry dashboard** — real-time performance metrics at `/telemetry`, including token usage and prompt cache efficiency ([`MONITORING.md`](MONITORING.md))
|
|
73
|
+
- **Telemetry persistence** — opt-in SQLite storage for telemetry data that survives proxy restarts, with configurable retention
|
|
74
|
+
- **Prometheus metrics** — `GET /metrics` endpoint for scraping request counters and duration histograms
|
|
75
|
+
- **SDK feature toggles** *(experimental)* — unlock Claude Code features (memory, dreaming, CLAUDE.md) for any connected agent
|
|
76
|
+
|
|
77
|
+
## SDK Feature Toggles (Experimental)
|
|
78
|
+
|
|
79
|
+
Meridian can expose Claude Code features to any connected agent. Capabilities like auto-memory, dreaming, and CLAUDE.md — normally exclusive to Claude Code — become available to OpenCode, Crush, Droid, and any other harness routed through Meridian. Each agent keeps its own toolchain while gaining access to these additional features.
|
|
80
|
+
|
|
81
|
+
Configure per-adapter at **`/settings`** in the Meridian web UI. Changes take effect on the next request — no restart needed. Config is persisted to `~/.config/meridian/sdk-features.json`.
|
|
82
|
+
|
|
83
|
+
### Available features
|
|
84
|
+
|
|
85
|
+
| Setting | Options | Description |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| **Claude Code Prompt** | on / off | Include the SDK's built-in system prompt (tool usage rules, safety guidelines, coding best practices) |
|
|
88
|
+
| **Client Prompt** | on / off | Include the system prompt sent by the connecting agent (e.g. OpenCode or Crush instructions) |
|
|
89
|
+
| **CLAUDE.md** | off / project / full | Load instruction files — `off`: none, `project`: `./CLAUDE.md` only, `full`: `~/.claude/CLAUDE.md` + `./CLAUDE.md` |
|
|
90
|
+
| **Memory** | on / off | Auto-memory: read and write memories across sessions |
|
|
91
|
+
| **Auto-Dream** | on / off | Background memory consolidation between sessions |
|
|
92
|
+
| **Thinking** | disabled / adaptive / enabled | Extended thinking mode for complex reasoning |
|
|
93
|
+
| **Thinking Passthrough** | on / off | Forward thinking blocks to the client for display |
|
|
94
|
+
| **Shared Memory** | on / off | Share memory directory with Claude Code (`~/.claude`) instead of isolated storage |
|
|
95
|
+
|
|
96
|
+
### System prompts
|
|
97
|
+
|
|
98
|
+
The system prompt controls are independent — any combination works:
|
|
99
|
+
|
|
100
|
+
- **Both enabled** (recommended): Claude Code instructions come first, followed by your agent's specific instructions. This gives Claude the full context it needs for features like memory and tool use to work correctly.
|
|
101
|
+
- **Claude Code only**: Just the base Claude Code prompt without agent-specific instructions.
|
|
102
|
+
- **Client only**: Just your agent's prompt, passed through as a raw string.
|
|
103
|
+
- **Neither**: No system prompt at all — Claude operates with just the user message.
|
|
104
|
+
|
|
105
|
+
> **Note:** For features like memory and dreaming to work well, the Claude Code system prompt should be enabled — it contains the instructions Claude needs to read and write memories correctly.
|
|
106
|
+
|
|
107
|
+
## Passthrough Mode and Tool Calling
|
|
108
|
+
|
|
109
|
+
The core question is **who executes the tools** — the SDK or the client?
|
|
110
|
+
|
|
111
|
+
- **Passthrough mode** (default for OpenCode) — Claude generates tool calls, but Meridian captures them and sends them back to the client for execution. The client runs the tool using its own implementation, with its own sandboxing, file tracking, and UI, then sends the result in the next request. This is how OpenCode, oh-my-opencagent (OMO), and most coding agents work — they have their own read/write/bash tools and need to stay in control of what runs on the user's machine.
|
|
112
|
+
- **Internal mode** — Claude Code handles everything. The SDK executes tools directly on the host, runs its full agent loop, and returns the final result. This is for clients that are purely chat interfaces (Open WebUI, simple API consumers) with no tool execution of their own.
|
|
113
|
+
|
|
114
|
+
Most users don't need to configure anything — the adapter sets the right mode automatically. To override:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
MERIDIAN_PASSTHROUGH=1 meridian # force passthrough
|
|
118
|
+
MERIDIAN_PASSTHROUGH=0 meridian # force internal
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### How tool calling works in passthrough
|
|
122
|
+
|
|
123
|
+
1. The client sends a request with tool definitions (read, write, edit, bash, glob, grep)
|
|
124
|
+
2. Meridian registers these as MCP tools so the SDK can generate proper `tool_use` blocks
|
|
125
|
+
3. The SDK produces a tool call → Meridian captures it and returns it to the client
|
|
126
|
+
4. The client executes the tool locally and sends the result back
|
|
127
|
+
|
|
128
|
+
For large tool sets (>15 tools), non-core tools are automatically deferred via the SDK's ToolSearch mechanism. Core tools (read, write, edit, bash, glob, grep) are always loaded eagerly. The deferral threshold is configurable with `MERIDIAN_DEFER_TOOL_THRESHOLD`.
|
|
129
|
+
|
|
130
|
+
### Known limitations
|
|
131
|
+
|
|
132
|
+
- **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.
|
|
133
|
+
- **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.
|
|
134
|
+
- **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.
|
|
84
135
|
|
|
85
136
|
## Multi-Profile Support
|
|
86
137
|
|
|
@@ -156,7 +207,7 @@ meridian setup
|
|
|
156
207
|
This adds the Meridian plugin to your OpenCode global config (`~/.config/opencode/opencode.json`). The plugin enables:
|
|
157
208
|
|
|
158
209
|
- **Session tracking** — reliable conversation continuity across requests
|
|
159
|
-
- **Safe model defaults** — Opus uses 1M context (included with Max subscription); Sonnet uses 200k to avoid Extra Usage charges ([details](#
|
|
210
|
+
- **Safe model defaults** — Opus uses 1M context (included with Max subscription); Sonnet uses 200k to avoid Extra Usage charges ([details](#configuration))
|
|
160
211
|
- **Subagent model selection** — subagents automatically use `sonnet`/`opus` (200k), preserving rate-limit budget
|
|
161
212
|
|
|
162
213
|
If the plugin is missing, Meridian warns at startup and reports `"plugin": "not-configured"` in the health endpoint.
|
|
@@ -174,6 +225,14 @@ export ANTHROPIC_API_KEY=x
|
|
|
174
225
|
export ANTHROPIC_BASE_URL=http://127.0.0.1:3456
|
|
175
226
|
```
|
|
176
227
|
|
|
228
|
+
#### oh-my-opencagent (OMO)
|
|
229
|
+
|
|
230
|
+
[oh-my-opencagent](https://github.com/nicobailey/oh-my-opencagent) adds multi-agent orchestration on top of OpenCode. It works transparently through Meridian with no extra configuration — OMO uses the same OpenCode headers and tool format, so Meridian detects it automatically.
|
|
231
|
+
|
|
232
|
+
Meridian parses OMO's Task tool descriptions to extract subagent names (explore, code-review, etc.) and builds SDK AgentDefinitions so Claude can route to the correct agent. Internal orchestration markers (`<!-- OMO_INTERNAL_INITIATOR -->`, `[SYSTEM DIRECTIVE: OH-MY-OPENCODE ...]`) are stripped automatically to prevent context leakage.
|
|
233
|
+
|
|
234
|
+
OMO requires **passthrough mode** (the default for OpenCode) — subagent delegation flows through tool calls that must be forwarded back to the client.
|
|
235
|
+
|
|
177
236
|
### Crush
|
|
178
237
|
|
|
179
238
|
Add a provider to `~/.config/crush/crush.json`:
|
|
@@ -250,7 +309,7 @@ No plugin needed — Cline uses the standard Anthropic SDK.
|
|
|
250
309
|
|
|
251
310
|
```bash
|
|
252
311
|
ANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http://127.0.0.1:3456 \
|
|
253
|
-
aider --model anthropic/claude-sonnet-4-
|
|
312
|
+
aider --model anthropic/claude-sonnet-4-6
|
|
254
313
|
```
|
|
255
314
|
|
|
256
315
|
> **Note:** `--no-stream` is incompatible due to a litellm parsing issue — use the default streaming mode.
|
|
@@ -282,7 +341,7 @@ Add a custom provider to `~/forge/.forge.toml`:
|
|
|
282
341
|
id = "meridian"
|
|
283
342
|
url = "http://127.0.0.1:3456/v1/messages"
|
|
284
343
|
models = "http://127.0.0.1:3456/v1/models"
|
|
285
|
-
api_key_vars = "
|
|
344
|
+
api_key_vars = "MERIDIAN_FORGE_KEY"
|
|
286
345
|
response_type = "Anthropic"
|
|
287
346
|
auth_methods = ["api_key"]
|
|
288
347
|
|
|
@@ -291,10 +350,10 @@ provider_id = "meridian"
|
|
|
291
350
|
model_id = "claude-opus-4-6"
|
|
292
351
|
```
|
|
293
352
|
|
|
294
|
-
Set the API key env var
|
|
353
|
+
Set the API key env var. Any value works unless you've enabled authentication with `MERIDIAN_API_KEY`, in which case use your auth key here:
|
|
295
354
|
|
|
296
355
|
```bash
|
|
297
|
-
export
|
|
356
|
+
export MERIDIAN_FORGE_KEY=x
|
|
298
357
|
```
|
|
299
358
|
|
|
300
359
|
Then log in and select the model:
|
|
@@ -318,19 +377,19 @@ Pi uses the `@mariozechner/pi-ai` library which supports a configurable `baseUrl
|
|
|
318
377
|
|
|
319
378
|
```json
|
|
320
379
|
{
|
|
321
|
-
"
|
|
322
|
-
"
|
|
380
|
+
"providers": {
|
|
381
|
+
"anthropic": {
|
|
382
|
+
"baseUrl": "http://127.0.0.1:3456",
|
|
383
|
+
"apiKey": "x",
|
|
384
|
+
"headers": {
|
|
385
|
+
"x-meridian-agent": "pi"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
323
388
|
}
|
|
324
389
|
}
|
|
325
390
|
```
|
|
326
391
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
```bash
|
|
330
|
-
MERIDIAN_DEFAULT_AGENT=pi meridian
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
Pi mimics Claude Code's User-Agent, so automatic detection isn't possible. The `MERIDIAN_DEFAULT_AGENT` env var tells Meridian to use the pi adapter for all unrecognized requests. If you run other agents alongside pi, use the `x-meridian-agent: pi` header instead (requires pi-ai support for custom headers).
|
|
392
|
+
Pi mimics Claude Code's User-Agent, so automatic detection isn't possible. The `x-meridian-agent: pi` header in the config above tells Meridian to use the Pi adapter. Alternatively, if Pi is your only agent, you can set `MERIDIAN_DEFAULT_AGENT=pi` as an env var instead.
|
|
334
393
|
|
|
335
394
|
### Any Anthropic-compatible tool
|
|
336
395
|
|
|
@@ -411,8 +470,10 @@ Agents are identified from request headers automatically:
|
|
|
411
470
|
| Signal | Adapter |
|
|
412
471
|
|---|---|
|
|
413
472
|
| `x-meridian-agent` header | Explicit override (any adapter) |
|
|
414
|
-
| `
|
|
473
|
+
| `x-opencode-session` or `x-session-affinity` header | OpenCode |
|
|
474
|
+
| `opencode/` User-Agent | OpenCode |
|
|
415
475
|
| `factory-cli/` User-Agent | Droid |
|
|
476
|
+
| `Charm-Crush/` User-Agent | Crush |
|
|
416
477
|
| `litellm/` UA or `x-litellm-*` headers | LiteLLM passthrough |
|
|
417
478
|
| *(anything else)* | `MERIDIAN_DEFAULT_AGENT` env var, or OpenCode |
|
|
418
479
|
|
|
@@ -420,10 +481,30 @@ Agents are identified from request headers automatically:
|
|
|
420
481
|
|
|
421
482
|
Implement the `AgentAdapter` interface in `src/proxy/adapters/`. See [`adapters/opencode.ts`](src/proxy/adapters/opencode.ts) for a reference.
|
|
422
483
|
|
|
484
|
+
## API Key Authentication
|
|
485
|
+
|
|
486
|
+
By default, Meridian binds to `127.0.0.1` and requires no authentication — anyone on localhost can use it. If you expose Meridian over a network (Tailscale, LAN, Docker with port mapping), you can enable API key authentication to prevent unauthorized access.
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
MERIDIAN_API_KEY=your-secret-key meridian
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
When set:
|
|
493
|
+
- All API routes (`/v1/messages`, `/v1/chat/completions`, etc.) and admin routes (`/telemetry`, `/metrics`, `/profiles`) require a matching key
|
|
494
|
+
- `/` and `/health` remain open (monitoring tools need unauthenticated health checks)
|
|
495
|
+
- Keys are accepted via `x-api-key` header or `Authorization: Bearer` header
|
|
496
|
+
|
|
497
|
+
Clients just set their `ANTHROPIC_API_KEY` to the shared secret — since most tools already send this header, no workflow changes are needed:
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
ANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http://meridian-host:3456 opencode
|
|
501
|
+
```
|
|
502
|
+
|
|
423
503
|
## Configuration
|
|
424
504
|
|
|
425
505
|
| Variable | Alias | Default | Description |
|
|
426
506
|
|----------|-------|---------|-------------|
|
|
507
|
+
| `MERIDIAN_API_KEY` | — | unset | Shared secret for API key authentication. When set, all API and admin routes require a matching `x-api-key` or `Authorization: Bearer` header. `/` and `/health` remain open. |
|
|
427
508
|
| `MERIDIAN_PORT` | `CLAUDE_PROXY_PORT` | `3456` | Port to listen on |
|
|
428
509
|
| `MERIDIAN_HOST` | `CLAUDE_PROXY_HOST` | `127.0.0.1` | Host to bind to |
|
|
429
510
|
| `MERIDIAN_PASSTHROUGH` | `CLAUDE_PROXY_PASSTHROUGH` | unset | Forward tool calls to client instead of executing |
|
|
@@ -437,6 +518,10 @@ Implement the `AgentAdapter` interface in `src/proxy/adapters/`. See [`adapters/
|
|
|
437
518
|
| `MERIDIAN_SONNET_MODEL` | `CLAUDE_PROXY_SONNET_MODEL` | `sonnet` | Sonnet context tier: `sonnet` (200k, default) or `sonnet[1m]` (1M, requires Extra Usage†) |
|
|
438
519
|
| `MERIDIAN_DEFAULT_AGENT` | — | `opencode` | Default adapter for unrecognized agents: `opencode`, `forgecode`, `pi`, `crush`, `droid`, `passthrough`. Requires restart. |
|
|
439
520
|
| `MERIDIAN_PROFILES` | — | unset | JSON array of profile configs (overrides disk discovery). See [Multi-Profile Support](#multi-profile-support). |
|
|
521
|
+
| `MERIDIAN_DEFER_TOOL_THRESHOLD` | — | `15` | Number of tools before non-core tools are deferred via ToolSearch. Set to `0` to disable. |
|
|
522
|
+
| `MERIDIAN_TELEMETRY_PERSIST` | — | unset | Enable SQLite telemetry persistence. Data survives proxy restarts. |
|
|
523
|
+
| `MERIDIAN_TELEMETRY_DB` | — | `~/.config/meridian/telemetry.db` | SQLite database path (when persistence is enabled) |
|
|
524
|
+
| `MERIDIAN_TELEMETRY_RETENTION_DAYS` | — | `7` | Days to retain telemetry data before cleanup |
|
|
440
525
|
| `MERIDIAN_DEFAULT_PROFILE` | — | *(first profile)* | Default profile ID when no header is sent |
|
|
441
526
|
|
|
442
527
|
†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.
|
|
@@ -456,6 +541,7 @@ Implement the `AgentAdapter` interface in `src/proxy/adapters/`. See [`adapters/
|
|
|
456
541
|
| `GET /telemetry/requests` | Recent request metrics (JSON) |
|
|
457
542
|
| `GET /telemetry/summary` | Aggregate statistics (JSON) |
|
|
458
543
|
| `GET /telemetry/logs` | Diagnostic logs (JSON) |
|
|
544
|
+
| `GET /metrics` | Prometheus exposition format metrics |
|
|
459
545
|
| `GET /profiles` | Profile management page |
|
|
460
546
|
| `GET /profiles/list` | List profiles with auth status (JSON) |
|
|
461
547
|
| `POST /profiles/active` | Switch the active profile |
|
|
@@ -465,6 +551,7 @@ Health response example:
|
|
|
465
551
|
```json
|
|
466
552
|
{
|
|
467
553
|
"status": "healthy",
|
|
554
|
+
"version": "1.34.1",
|
|
468
555
|
"auth": { "loggedIn": true, "email": "you@example.com", "subscriptionType": "max" },
|
|
469
556
|
"mode": "internal",
|
|
470
557
|
"plugin": { "opencode": "configured" }
|
|
@@ -503,10 +590,40 @@ await instance.close()
|
|
|
503
590
|
|
|
504
591
|
## Docker
|
|
505
592
|
|
|
593
|
+
Claude Code authentication requires a browser, which isn't available inside containers. Authenticate on your local machine first, then mount the credentials into Docker.
|
|
594
|
+
|
|
595
|
+
### Single account
|
|
596
|
+
|
|
506
597
|
```bash
|
|
598
|
+
# 1. Authenticate locally (one time)
|
|
599
|
+
claude login
|
|
600
|
+
|
|
601
|
+
# 2. Run with mounted credentials
|
|
507
602
|
docker run -v ~/.claude:/home/claude/.claude -p 3456:3456 meridian
|
|
508
603
|
```
|
|
509
604
|
|
|
605
|
+
Meridian refreshes OAuth tokens automatically — once the credentials are mounted, no further browser access is needed.
|
|
606
|
+
|
|
607
|
+
### Multiple profiles in Docker
|
|
608
|
+
|
|
609
|
+
Authenticate each profile locally, then pass them to Docker via the `MERIDIAN_PROFILES` environment variable:
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
# 1. Authenticate each account locally
|
|
613
|
+
meridian profile add personal
|
|
614
|
+
meridian profile add work # sign out of claude.ai first, sign into work account
|
|
615
|
+
|
|
616
|
+
# 2. Run Docker with profile configs pointing to mounted credential directories
|
|
617
|
+
docker run \
|
|
618
|
+
-v ~/.config/meridian/profiles/personal:/profiles/personal \
|
|
619
|
+
-v ~/.config/meridian/profiles/work:/profiles/work \
|
|
620
|
+
-e 'MERIDIAN_PROFILES=[{"id":"personal","claudeConfigDir":"/profiles/personal"},{"id":"work","claudeConfigDir":"/profiles/work"}]' \
|
|
621
|
+
-e MERIDIAN_DEFAULT_PROFILE=personal \
|
|
622
|
+
-p 3456:3456 meridian
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
Switch profiles at runtime via the `x-meridian-profile` header or `meridian profile switch` (see [Multi-Profile Support](#multi-profile-support)).
|
|
626
|
+
|
|
510
627
|
## Testing
|
|
511
628
|
|
|
512
629
|
```bash
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toCommonJS = (from) => {
|
|
34
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
35
|
+
if (entry)
|
|
36
|
+
return entry;
|
|
37
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
38
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
+
for (var key of __getOwnPropNames(from))
|
|
40
|
+
if (!__hasOwnProp.call(entry, key))
|
|
41
|
+
__defProp(entry, key, {
|
|
42
|
+
get: __accessProp.bind(from, key),
|
|
43
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
__moduleCache.set(from, entry);
|
|
47
|
+
return entry;
|
|
48
|
+
};
|
|
49
|
+
var __moduleCache;
|
|
50
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
51
|
+
var __returnValue = (v) => v;
|
|
52
|
+
function __exportSetter(name, newValue) {
|
|
53
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
54
|
+
}
|
|
55
|
+
var __export = (target, all) => {
|
|
56
|
+
for (var name in all)
|
|
57
|
+
__defProp(target, name, {
|
|
58
|
+
get: all[name],
|
|
59
|
+
enumerable: true,
|
|
60
|
+
configurable: true,
|
|
61
|
+
set: __exportSetter.bind(all, name)
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
65
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
66
|
+
|
|
67
|
+
export { __toESM, __toCommonJS, __commonJS, __export, __esm, __require };
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__esm
|
|
3
|
+
} from "./cli-p9swy5t3.js";
|
|
4
|
+
|
|
1
5
|
// src/telemetry/profileBar.ts
|
|
2
6
|
var profileBarCss = `
|
|
3
7
|
.meridian-profile-bar {
|
|
@@ -41,8 +45,7 @@ var profileBarCss = `
|
|
|
41
45
|
}
|
|
42
46
|
.meridian-profile-bar .profile-nav a:hover { color: var(--text, #e6edf3); }
|
|
43
47
|
.meridian-profile-bar .profile-nav a.active { color: var(--accent, #58a6ff); }
|
|
44
|
-
|
|
45
|
-
var profileBarHtml = `
|
|
48
|
+
`, profileBarHtml = `
|
|
46
49
|
<div class="meridian-profile-bar" id="meridianProfileBar">
|
|
47
50
|
<span class="profile-label">Profile</span>
|
|
48
51
|
<select id="meridianProfileSelect"></select>
|
|
@@ -51,12 +54,12 @@ var profileBarHtml = `
|
|
|
51
54
|
<div class="spacer"></div>
|
|
52
55
|
<div class="profile-nav">
|
|
53
56
|
<a href="/" id="nav-home">Home</a>
|
|
57
|
+
<a href="/settings" id="nav-settings">Settings</a>
|
|
54
58
|
<a href="/profiles" id="nav-profiles">Profiles</a>
|
|
55
59
|
<a href="/telemetry" id="nav-telemetry">Telemetry</a>
|
|
56
60
|
</div>
|
|
57
61
|
</div>
|
|
58
|
-
|
|
59
|
-
var profileBarJs = `
|
|
62
|
+
`, profileBarJs = `
|
|
60
63
|
(function() {
|
|
61
64
|
var profileBar = document.getElementById('meridianProfileBar');
|
|
62
65
|
var profileSelect = document.getElementById('meridianProfileSelect');
|
|
@@ -109,5 +112,6 @@ var profileBarJs = `
|
|
|
109
112
|
setInterval(loadProfiles, 10000);
|
|
110
113
|
})();
|
|
111
114
|
`;
|
|
115
|
+
var init_profileBar = () => {};
|
|
112
116
|
|
|
113
|
-
export { profileBarCss, profileBarHtml, profileBarJs };
|
|
117
|
+
export { profileBarCss, profileBarHtml, profileBarJs, init_profileBar };
|