@rynfar/meridian 1.37.3 → 1.37.5
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 +89 -0
- package/dist/{cli-76s66ede.js → cli-yahkdc3h.js} +180 -171
- package/dist/cli.js +1 -1
- package/dist/proxy/adapter.d.ts +10 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/droid.d.ts.map +1 -1
- package/dist/proxy/passthroughTools.d.ts +10 -0
- package/dist/proxy/passthroughTools.d.ts.map +1 -1
- package/dist/proxy/sanitize.d.ts +6 -1
- package/dist/proxy/sanitize.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/cache.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -49,6 +49,95 @@ ANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http://127.0.0.1:3456 opencode
|
|
|
49
49
|
|
|
50
50
|
The API key value is a placeholder — Meridian authenticates through the Claude Code SDK, not API keys. Most Anthropic-compatible tools require this field to be set, but any value works.
|
|
51
51
|
|
|
52
|
+
### NixOS / Nix Flake
|
|
53
|
+
|
|
54
|
+
Meridian provides a Nix flake for declarative installation.
|
|
55
|
+
|
|
56
|
+
**Add to your flake inputs:**
|
|
57
|
+
|
|
58
|
+
```nix
|
|
59
|
+
{
|
|
60
|
+
inputs.meridian.url = "github:rynfar/meridian";
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Install the package** (via overlay or directly):
|
|
65
|
+
|
|
66
|
+
```nix
|
|
67
|
+
# Option A: overlay
|
|
68
|
+
nixpkgs.overlays = [ meridian.overlays.default ];
|
|
69
|
+
environment.systemPackages = [ pkgs.meridian ];
|
|
70
|
+
|
|
71
|
+
# Option B: direct reference
|
|
72
|
+
environment.systemPackages = [ meridian.packages.${system}.meridian ];
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**OpenCode plugin** -- the plugin file is included at `${pkgs.meridian}/lib/meridian/plugin/meridian.ts`. Since this path lives in the Nix store, you need to make it available to OpenCode:
|
|
76
|
+
|
|
77
|
+
If you generate your OpenCode config from Nix (e.g. via Home Manager), interpolate the path directly:
|
|
78
|
+
|
|
79
|
+
```nix
|
|
80
|
+
# home-manager example
|
|
81
|
+
xdg.configFile."opencode/opencode.json".text = builtins.toJSON {
|
|
82
|
+
plugin = [ "${pkgs.meridian}/lib/meridian/plugin/meridian.ts" ];
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If you don't manage your OpenCode config through Nix, symlink the plugin to a stable path and reference that instead:
|
|
87
|
+
|
|
88
|
+
```nix
|
|
89
|
+
# configuration.nix or home-manager
|
|
90
|
+
environment.etc."meridian/plugin/meridian.ts".source =
|
|
91
|
+
"${pkgs.meridian}/lib/meridian/plugin/meridian.ts";
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then in `~/.config/opencode/opencode.json`:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{ "plugin": ["/etc/meridian/plugin/meridian.ts"] }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
> **Important:** Do not use `meridian setup` on NixOS. It writes an absolute Nix store path (e.g. `/nix/store/...-meridian-1.x.x/lib/...`) into your OpenCode config, which will break on the next `nixos-rebuild switch` or `home-manager switch` when the store path changes. Use one of the approaches above instead.
|
|
101
|
+
|
|
102
|
+
**Home Manager service** -- run Meridian as a user systemd service:
|
|
103
|
+
|
|
104
|
+
```nix
|
|
105
|
+
# flake.nix
|
|
106
|
+
{
|
|
107
|
+
inputs.meridian.url = "github:rynfar/meridian";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# home-manager config
|
|
111
|
+
{
|
|
112
|
+
imports = [ meridian.homeManagerModules.default ];
|
|
113
|
+
|
|
114
|
+
services.meridian = {
|
|
115
|
+
enable = true;
|
|
116
|
+
settings = {
|
|
117
|
+
port = 3456;
|
|
118
|
+
host = "127.0.0.1";
|
|
119
|
+
# passthrough = true;
|
|
120
|
+
# defaultAgent = "opencode";
|
|
121
|
+
# sonnetModel = "sonnet";
|
|
122
|
+
};
|
|
123
|
+
# Extra env vars not covered by settings
|
|
124
|
+
# environment = {
|
|
125
|
+
# MERIDIAN_MAX_CONCURRENT = "20";
|
|
126
|
+
# };
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The service starts automatically on login. Manage it with `systemctl --user {start,stop,restart,status} meridian`.
|
|
132
|
+
|
|
133
|
+
The plugin path is also available as `config.services.meridian.opencode.pluginPath` for use in your OpenCode config:
|
|
134
|
+
|
|
135
|
+
```nix
|
|
136
|
+
xdg.configFile."opencode/opencode.json".text = builtins.toJSON {
|
|
137
|
+
plugin = [ config.services.meridian.opencode.pluginPath ];
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
52
141
|
## Why Meridian?
|
|
53
142
|
|
|
54
143
|
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.
|
|
@@ -7782,6 +7782,23 @@ function shouldAlwaysLoad(tool, coreSet) {
|
|
|
7782
7782
|
return coreSet.has(tool.name.toLowerCase());
|
|
7783
7783
|
return true;
|
|
7784
7784
|
}
|
|
7785
|
+
function computeToolSetKey(tools) {
|
|
7786
|
+
const entries = tools.map((t) => ({
|
|
7787
|
+
name: t.name,
|
|
7788
|
+
defer: t.defer_loading === true,
|
|
7789
|
+
schema: stableStringify(t.input_schema ?? null)
|
|
7790
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
7791
|
+
return JSON.stringify(entries);
|
|
7792
|
+
}
|
|
7793
|
+
function stableStringify(value) {
|
|
7794
|
+
if (value === null || typeof value !== "object")
|
|
7795
|
+
return JSON.stringify(value);
|
|
7796
|
+
if (Array.isArray(value))
|
|
7797
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
7798
|
+
const keys = Object.keys(value).sort();
|
|
7799
|
+
const parts = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`);
|
|
7800
|
+
return `{${parts.join(",")}}`;
|
|
7801
|
+
}
|
|
7785
7802
|
function stripMcpPrefix(toolName) {
|
|
7786
7803
|
if (toolName.startsWith(PASSTHROUGH_MCP_PREFIX)) {
|
|
7787
7804
|
return toolName.slice(PASSTHROUGH_MCP_PREFIX.length);
|
|
@@ -7789,6 +7806,71 @@ function stripMcpPrefix(toolName) {
|
|
|
7789
7806
|
return toolName;
|
|
7790
7807
|
}
|
|
7791
7808
|
|
|
7809
|
+
// src/utils/lruMap.ts
|
|
7810
|
+
class LRUMap {
|
|
7811
|
+
maxSize;
|
|
7812
|
+
onEvict;
|
|
7813
|
+
map = new Map;
|
|
7814
|
+
constructor(maxSize, onEvict) {
|
|
7815
|
+
this.maxSize = maxSize;
|
|
7816
|
+
this.onEvict = onEvict;
|
|
7817
|
+
}
|
|
7818
|
+
get size() {
|
|
7819
|
+
return this.map.size;
|
|
7820
|
+
}
|
|
7821
|
+
get(key) {
|
|
7822
|
+
const value = this.map.get(key);
|
|
7823
|
+
if (value === undefined)
|
|
7824
|
+
return;
|
|
7825
|
+
this.map.delete(key);
|
|
7826
|
+
this.map.set(key, value);
|
|
7827
|
+
return value;
|
|
7828
|
+
}
|
|
7829
|
+
set(key, value) {
|
|
7830
|
+
if (this.map.has(key)) {
|
|
7831
|
+
this.map.delete(key);
|
|
7832
|
+
} else if (this.map.size >= this.maxSize) {
|
|
7833
|
+
this.evictOldest();
|
|
7834
|
+
}
|
|
7835
|
+
this.map.set(key, value);
|
|
7836
|
+
return this;
|
|
7837
|
+
}
|
|
7838
|
+
has(key) {
|
|
7839
|
+
return this.map.has(key);
|
|
7840
|
+
}
|
|
7841
|
+
delete(key) {
|
|
7842
|
+
return this.map.delete(key);
|
|
7843
|
+
}
|
|
7844
|
+
clear() {
|
|
7845
|
+
this.map.clear();
|
|
7846
|
+
}
|
|
7847
|
+
entries() {
|
|
7848
|
+
return this.map.entries();
|
|
7849
|
+
}
|
|
7850
|
+
keys() {
|
|
7851
|
+
return this.map.keys();
|
|
7852
|
+
}
|
|
7853
|
+
values() {
|
|
7854
|
+
return this.map.values();
|
|
7855
|
+
}
|
|
7856
|
+
forEach(callbackfn) {
|
|
7857
|
+
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
7858
|
+
}
|
|
7859
|
+
[Symbol.iterator]() {
|
|
7860
|
+
return this.map[Symbol.iterator]();
|
|
7861
|
+
}
|
|
7862
|
+
evictOldest() {
|
|
7863
|
+
const oldestKey = this.map.keys().next().value;
|
|
7864
|
+
if (oldestKey === undefined)
|
|
7865
|
+
return;
|
|
7866
|
+
const oldestValue = this.map.get(oldestKey);
|
|
7867
|
+
if (oldestValue === undefined)
|
|
7868
|
+
return;
|
|
7869
|
+
this.map.delete(oldestKey);
|
|
7870
|
+
this.onEvict?.(oldestKey, oldestValue);
|
|
7871
|
+
}
|
|
7872
|
+
}
|
|
7873
|
+
|
|
7792
7874
|
// src/telemetry/index.ts
|
|
7793
7875
|
import { join } from "node:path";
|
|
7794
7876
|
import { homedir } from "node:os";
|
|
@@ -9325,7 +9407,7 @@ function fuzzyMatchAgentName(input, validAgents) {
|
|
|
9325
9407
|
var openCodeAdapter = {
|
|
9326
9408
|
name: "opencode",
|
|
9327
9409
|
getSessionId(c) {
|
|
9328
|
-
return c.req.header("x-opencode-session");
|
|
9410
|
+
return c.req.header("x-opencode-session") ?? c.req.header("x-session-affinity");
|
|
9329
9411
|
},
|
|
9330
9412
|
extractWorkingDirectory(body) {
|
|
9331
9413
|
return extractClientCwd(body);
|
|
@@ -9452,6 +9534,9 @@ var droidAdapter = {
|
|
|
9452
9534
|
normalizeContent(content) {
|
|
9453
9535
|
return normalizeContent(content);
|
|
9454
9536
|
},
|
|
9537
|
+
leaksCwdViaSystemReminder() {
|
|
9538
|
+
return true;
|
|
9539
|
+
},
|
|
9455
9540
|
getBlockedBuiltinTools() {
|
|
9456
9541
|
return BLOCKED_BUILTIN_TOOLS;
|
|
9457
9542
|
},
|
|
@@ -15725,7 +15810,6 @@ function formatUsageSummary(usage) {
|
|
|
15725
15810
|
|
|
15726
15811
|
// src/proxy/sanitize.ts
|
|
15727
15812
|
var ORCHESTRATION_TAGS = [
|
|
15728
|
-
"system-reminder",
|
|
15729
15813
|
"env",
|
|
15730
15814
|
"system_information",
|
|
15731
15815
|
"current_working_directory",
|
|
@@ -15754,9 +15838,14 @@ var ALL_PATTERNS = [
|
|
|
15754
15838
|
...SELF_CLOSING_TAG_PATTERNS,
|
|
15755
15839
|
...NON_XML_PATTERNS
|
|
15756
15840
|
];
|
|
15757
|
-
|
|
15841
|
+
var SYSTEM_REMINDER_PATTERNS = [
|
|
15842
|
+
/<system-reminder\b[^>]*>[\s\S]*?<\/system-reminder>/gi,
|
|
15843
|
+
/<system-reminder\b[^>]*\/>/gi
|
|
15844
|
+
];
|
|
15845
|
+
function sanitizeTextContent(text, opts = {}) {
|
|
15758
15846
|
let result = text;
|
|
15759
|
-
|
|
15847
|
+
const patterns = opts.stripSystemReminder ? [...ALL_PATTERNS, ...SYSTEM_REMINDER_PATTERNS] : ALL_PATTERNS;
|
|
15848
|
+
for (const pattern of patterns) {
|
|
15760
15849
|
pattern.lastIndex = 0;
|
|
15761
15850
|
result = result.replace(pattern, "");
|
|
15762
15851
|
}
|
|
@@ -15896,71 +15985,6 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
|
|
|
15896
15985
|
return { type: "diverged" };
|
|
15897
15986
|
}
|
|
15898
15987
|
|
|
15899
|
-
// src/utils/lruMap.ts
|
|
15900
|
-
class LRUMap {
|
|
15901
|
-
maxSize;
|
|
15902
|
-
onEvict;
|
|
15903
|
-
map = new Map;
|
|
15904
|
-
constructor(maxSize, onEvict) {
|
|
15905
|
-
this.maxSize = maxSize;
|
|
15906
|
-
this.onEvict = onEvict;
|
|
15907
|
-
}
|
|
15908
|
-
get size() {
|
|
15909
|
-
return this.map.size;
|
|
15910
|
-
}
|
|
15911
|
-
get(key) {
|
|
15912
|
-
const value = this.map.get(key);
|
|
15913
|
-
if (value === undefined)
|
|
15914
|
-
return;
|
|
15915
|
-
this.map.delete(key);
|
|
15916
|
-
this.map.set(key, value);
|
|
15917
|
-
return value;
|
|
15918
|
-
}
|
|
15919
|
-
set(key, value) {
|
|
15920
|
-
if (this.map.has(key)) {
|
|
15921
|
-
this.map.delete(key);
|
|
15922
|
-
} else if (this.map.size >= this.maxSize) {
|
|
15923
|
-
this.evictOldest();
|
|
15924
|
-
}
|
|
15925
|
-
this.map.set(key, value);
|
|
15926
|
-
return this;
|
|
15927
|
-
}
|
|
15928
|
-
has(key) {
|
|
15929
|
-
return this.map.has(key);
|
|
15930
|
-
}
|
|
15931
|
-
delete(key) {
|
|
15932
|
-
return this.map.delete(key);
|
|
15933
|
-
}
|
|
15934
|
-
clear() {
|
|
15935
|
-
this.map.clear();
|
|
15936
|
-
}
|
|
15937
|
-
entries() {
|
|
15938
|
-
return this.map.entries();
|
|
15939
|
-
}
|
|
15940
|
-
keys() {
|
|
15941
|
-
return this.map.keys();
|
|
15942
|
-
}
|
|
15943
|
-
values() {
|
|
15944
|
-
return this.map.values();
|
|
15945
|
-
}
|
|
15946
|
-
forEach(callbackfn) {
|
|
15947
|
-
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
15948
|
-
}
|
|
15949
|
-
[Symbol.iterator]() {
|
|
15950
|
-
return this.map[Symbol.iterator]();
|
|
15951
|
-
}
|
|
15952
|
-
evictOldest() {
|
|
15953
|
-
const oldestKey = this.map.keys().next().value;
|
|
15954
|
-
if (oldestKey === undefined)
|
|
15955
|
-
return;
|
|
15956
|
-
const oldestValue = this.map.get(oldestKey);
|
|
15957
|
-
if (oldestValue === undefined)
|
|
15958
|
-
return;
|
|
15959
|
-
this.map.delete(oldestKey);
|
|
15960
|
-
this.onEvict?.(oldestKey, oldestValue);
|
|
15961
|
-
}
|
|
15962
|
-
}
|
|
15963
|
-
|
|
15964
15988
|
// src/proxy/sessionStore.ts
|
|
15965
15989
|
import {
|
|
15966
15990
|
closeSync,
|
|
@@ -16360,7 +16384,7 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
|
|
|
16360
16384
|
if (sessionId)
|
|
16361
16385
|
sessionCache.set(sessionId, state);
|
|
16362
16386
|
const fp = getConversationFingerprint(messages, workingDirectory);
|
|
16363
|
-
if (fp)
|
|
16387
|
+
if (fp && !sessionId)
|
|
16364
16388
|
fingerprintCache.set(fp, state);
|
|
16365
16389
|
const key = sessionId || fp;
|
|
16366
16390
|
if (key) {
|
|
@@ -16371,7 +16395,43 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
|
|
|
16371
16395
|
// src/proxy/server.ts
|
|
16372
16396
|
var exec3 = promisify3(execCallback2);
|
|
16373
16397
|
var claudeExecutable = "";
|
|
16374
|
-
function
|
|
16398
|
+
function flattenAssistantContent(content) {
|
|
16399
|
+
if (typeof content === "string")
|
|
16400
|
+
return content;
|
|
16401
|
+
if (!Array.isArray(content))
|
|
16402
|
+
return String(content ?? "");
|
|
16403
|
+
return content.map((b) => b?.type === "text" && b.text ? b.text : "").filter(Boolean).join(`
|
|
16404
|
+
`);
|
|
16405
|
+
}
|
|
16406
|
+
function flattenUserContent(content, sanitizeOpts = {}) {
|
|
16407
|
+
if (typeof content === "string")
|
|
16408
|
+
return sanitizeTextContent(content, sanitizeOpts);
|
|
16409
|
+
if (!Array.isArray(content))
|
|
16410
|
+
return String(content ?? "");
|
|
16411
|
+
return content.map((b) => {
|
|
16412
|
+
if (b?.type === "text" && b.text)
|
|
16413
|
+
return sanitizeTextContent(b.text, sanitizeOpts);
|
|
16414
|
+
if (b?.type === "tool_result") {
|
|
16415
|
+
const inner = b.content;
|
|
16416
|
+
if (typeof inner === "string")
|
|
16417
|
+
return inner;
|
|
16418
|
+
if (Array.isArray(inner)) {
|
|
16419
|
+
return inner.map((ib) => ib?.type === "text" && ib.text ? ib.text : "").filter(Boolean).join(`
|
|
16420
|
+
`);
|
|
16421
|
+
}
|
|
16422
|
+
return "";
|
|
16423
|
+
}
|
|
16424
|
+
if (b?.type === "image")
|
|
16425
|
+
return "[Image attached]";
|
|
16426
|
+
if (b?.type === "document")
|
|
16427
|
+
return "[Document attached]";
|
|
16428
|
+
if (b?.type === "file")
|
|
16429
|
+
return "[File attached]";
|
|
16430
|
+
return "";
|
|
16431
|
+
}).filter(Boolean).join(`
|
|
16432
|
+
`);
|
|
16433
|
+
}
|
|
16434
|
+
function buildFreshPrompt(messages, stripCacheControl, sanitizeOpts = {}) {
|
|
16375
16435
|
const MULTIMODAL_TYPES = new Set(["image", "document", "file"]);
|
|
16376
16436
|
const hasMultimodal = messages.some((m) => Array.isArray(m.content) && m.content.some((b) => MULTIMODAL_TYPES.has(b.type)));
|
|
16377
16437
|
if (hasMultimodal) {
|
|
@@ -16384,28 +16444,14 @@ function buildFreshPrompt(messages, stripCacheControl) {
|
|
|
16384
16444
|
parent_tool_use_id: null
|
|
16385
16445
|
});
|
|
16386
16446
|
} else {
|
|
16387
|
-
|
|
16388
|
-
if (
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
if (b.type === "tool_use")
|
|
16395
|
-
return `[Tool Use: ${b.name}(${JSON.stringify(b.input)})]`;
|
|
16396
|
-
if (b.type === "tool_result")
|
|
16397
|
-
return `[Tool Result: ${typeof b.content === "string" ? b.content : JSON.stringify(b.content)}]`;
|
|
16398
|
-
return "";
|
|
16399
|
-
}).filter(Boolean).join(`
|
|
16400
|
-
`);
|
|
16401
|
-
} else {
|
|
16402
|
-
text = `[Assistant: ${String(m.content)}]`;
|
|
16447
|
+
const assistantText = flattenAssistantContent(m.content);
|
|
16448
|
+
if (assistantText) {
|
|
16449
|
+
structured.push({
|
|
16450
|
+
type: "user",
|
|
16451
|
+
message: { role: "user", content: `[Assistant: ${assistantText}]` },
|
|
16452
|
+
parent_tool_use_id: null
|
|
16453
|
+
});
|
|
16403
16454
|
}
|
|
16404
|
-
structured.push({
|
|
16405
|
-
type: "user",
|
|
16406
|
-
message: { role: "user", content: text },
|
|
16407
|
-
parent_tool_use_id: null
|
|
16408
|
-
});
|
|
16409
16455
|
}
|
|
16410
16456
|
}
|
|
16411
16457
|
return async function* () {
|
|
@@ -16415,31 +16461,9 @@ function buildFreshPrompt(messages, stripCacheControl) {
|
|
|
16415
16461
|
}
|
|
16416
16462
|
return messages.map((m) => {
|
|
16417
16463
|
const role = m.role === "assistant" ? "Assistant" : "Human";
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
} else if (Array.isArray(m.content)) {
|
|
16422
|
-
content = m.content.map((block) => {
|
|
16423
|
-
if (block.type === "text" && block.text)
|
|
16424
|
-
return sanitizeTextContent(block.text);
|
|
16425
|
-
if (block.type === "tool_use")
|
|
16426
|
-
return `[Tool Use: ${block.name}(${JSON.stringify(block.input)})]`;
|
|
16427
|
-
if (block.type === "tool_result")
|
|
16428
|
-
return `[Tool Result for ${block.tool_use_id}: ${typeof block.content === "string" ? block.content : JSON.stringify(block.content)}]`;
|
|
16429
|
-
if (block.type === "image")
|
|
16430
|
-
return "[Image attached]";
|
|
16431
|
-
if (block.type === "document")
|
|
16432
|
-
return "[Document attached]";
|
|
16433
|
-
if (block.type === "file")
|
|
16434
|
-
return "[File attached]";
|
|
16435
|
-
return "";
|
|
16436
|
-
}).filter(Boolean).join(`
|
|
16437
|
-
`);
|
|
16438
|
-
} else {
|
|
16439
|
-
content = String(m.content);
|
|
16440
|
-
}
|
|
16441
|
-
return `${role}: ${content}`;
|
|
16442
|
-
}).join(`
|
|
16464
|
+
const content = m.role === "assistant" ? flattenAssistantContent(m.content) : flattenUserContent(m.content, sanitizeOpts);
|
|
16465
|
+
return content ? `${role}: ${content}` : "";
|
|
16466
|
+
}).filter(Boolean).join(`
|
|
16443
16467
|
|
|
16444
16468
|
`) || "";
|
|
16445
16469
|
}
|
|
@@ -16495,6 +16519,7 @@ function createProxyServer(config = {}) {
|
|
|
16495
16519
|
restoreActiveProfile(finalConfig.profiles);
|
|
16496
16520
|
const sessionDiscoveredTools = new Map;
|
|
16497
16521
|
const sessionToolCache = new Map;
|
|
16522
|
+
const sessionMcpCache = new LRUMap(getMaxSessionsLimit());
|
|
16498
16523
|
const app = new Hono2;
|
|
16499
16524
|
app.use("*", cors());
|
|
16500
16525
|
app.use("/v1/*", requireAuth);
|
|
@@ -16569,6 +16594,7 @@ function createProxyServer(config = {}) {
|
|
|
16569
16594
|
const profile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile, c.req.header("x-meridian-profile") || undefined);
|
|
16570
16595
|
const authStatus = await getClaudeAuthStatusAsync(profile.id !== "default" ? profile.id : undefined, Object.keys(profile.env).length > 0 ? profile.env : undefined);
|
|
16571
16596
|
const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
|
|
16597
|
+
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
16572
16598
|
let model = mapModelToClaudeModel(body.model || "sonnet", authStatus?.subscriptionType, agentMode);
|
|
16573
16599
|
const adapterStreamPref = adapter.prefersStreaming?.(body);
|
|
16574
16600
|
const stream2 = adapterStreamPref !== undefined ? adapterStreamPref : body.stream ?? false;
|
|
@@ -16628,7 +16654,11 @@ function createProxyServer(config = {}) {
|
|
|
16628
16654
|
const agentSessionId = adapter.getSessionId(c);
|
|
16629
16655
|
const profileSessionId = profile.id !== "default" && agentSessionId ? `${profile.id}:${agentSessionId}` : agentSessionId;
|
|
16630
16656
|
const profileScopedCwd = profile.id !== "default" ? `${workingDirectory}::profile=${profile.id}` : workingDirectory;
|
|
16631
|
-
const
|
|
16657
|
+
const isIndependentSession = requestSource?.startsWith("fork-") || requestSource?.startsWith("subagent-") || false;
|
|
16658
|
+
let lineageResult = isIndependentSession ? { type: "diverged" } : lookupSession(profileSessionId, body.messages || [], profileScopedCwd);
|
|
16659
|
+
if (lineageResult.type === "undo" && adapter.name === "opencode" && !agentSessionId) {
|
|
16660
|
+
lineageResult = { type: "diverged" };
|
|
16661
|
+
}
|
|
16632
16662
|
const isResume = lineageResult.type === "continuation" || lineageResult.type === "compaction";
|
|
16633
16663
|
const isUndo = lineageResult.type === "undo";
|
|
16634
16664
|
const cachedSession = lineageResult.type !== "diverged" ? lineageResult.session : undefined;
|
|
@@ -16641,10 +16671,10 @@ function createProxyServer(config = {}) {
|
|
|
16641
16671
|
const lineageType = lineageResult.type === "diverged" && !cachedSession ? "new" : lineageResult.type;
|
|
16642
16672
|
const msgCount = Array.isArray(body.messages) ? body.messages.length : 0;
|
|
16643
16673
|
const toolCount = body.tools?.length ?? 0;
|
|
16644
|
-
const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name} model=${model} stream=${stream2} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
|
|
16674
|
+
const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name}${requestSource ? ` source=${requestSource}` : ""} model=${model} stream=${stream2} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
|
|
16645
16675
|
console.error(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
|
|
16646
16676
|
diagnosticLog2.session(`${requestLogLine}`, requestMeta.requestId);
|
|
16647
|
-
if (lineageResult.type === "diverged" && profileSessionId) {
|
|
16677
|
+
if (lineageResult.type === "diverged" && profileSessionId && !isIndependentSession) {
|
|
16648
16678
|
const recovery = lookupSessionRecovery(profileSessionId);
|
|
16649
16679
|
if (recovery) {
|
|
16650
16680
|
const prevId = recovery.previousClaudeSessionId || recovery.claudeSessionId;
|
|
@@ -16666,6 +16696,9 @@ function createProxyServer(config = {}) {
|
|
|
16666
16696
|
claudeLog("debug.agents", { names: validAgentNames, count: validAgentNames.length });
|
|
16667
16697
|
}
|
|
16668
16698
|
systemContext += adapter.buildSystemContextAddendum?.(body, sdkAgents) ?? "";
|
|
16699
|
+
const sanitizeOpts = {
|
|
16700
|
+
stripSystemReminder: adapter.leaksCwdViaSystemReminder?.() ?? false
|
|
16701
|
+
};
|
|
16669
16702
|
const allMessages = body.messages || [];
|
|
16670
16703
|
let messagesToConvert;
|
|
16671
16704
|
if ((isResume || isUndo) && cachedSession) {
|
|
@@ -16709,59 +16742,23 @@ function createProxyServer(config = {}) {
|
|
|
16709
16742
|
parent_tool_use_id: null
|
|
16710
16743
|
});
|
|
16711
16744
|
} else {
|
|
16712
|
-
|
|
16713
|
-
if (
|
|
16714
|
-
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
if (b.type === "tool_use")
|
|
16720
|
-
return `[Tool Use: ${b.name}(${JSON.stringify(b.input)})]`;
|
|
16721
|
-
if (b.type === "tool_result")
|
|
16722
|
-
return `[Tool Result: ${typeof b.content === "string" ? b.content : JSON.stringify(b.content)}]`;
|
|
16723
|
-
return "";
|
|
16724
|
-
}).filter(Boolean).join(`
|
|
16725
|
-
`);
|
|
16726
|
-
} else {
|
|
16727
|
-
text = `[Assistant: ${String(m.content)}]`;
|
|
16745
|
+
const assistantText = flattenAssistantContent(m.content);
|
|
16746
|
+
if (assistantText) {
|
|
16747
|
+
structuredMessages.push({
|
|
16748
|
+
type: "user",
|
|
16749
|
+
message: { role: "user", content: `[Assistant: ${assistantText}]` },
|
|
16750
|
+
parent_tool_use_id: null
|
|
16751
|
+
});
|
|
16728
16752
|
}
|
|
16729
|
-
structuredMessages.push({
|
|
16730
|
-
type: "user",
|
|
16731
|
-
message: { role: "user", content: text },
|
|
16732
|
-
parent_tool_use_id: null
|
|
16733
|
-
});
|
|
16734
16753
|
}
|
|
16735
16754
|
}
|
|
16736
16755
|
}
|
|
16737
16756
|
} else {
|
|
16738
16757
|
textPrompt = messagesToConvert?.map((m) => {
|
|
16739
16758
|
const role = m.role === "assistant" ? "Assistant" : "Human";
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
} else if (Array.isArray(m.content)) {
|
|
16744
|
-
content = m.content.map((block) => {
|
|
16745
|
-
if (block.type === "text" && block.text)
|
|
16746
|
-
return sanitizeTextContent(block.text);
|
|
16747
|
-
if (block.type === "tool_use")
|
|
16748
|
-
return `[Tool Use: ${block.name}(${JSON.stringify(block.input)})]`;
|
|
16749
|
-
if (block.type === "tool_result")
|
|
16750
|
-
return `[Tool Result for ${block.tool_use_id}: ${typeof block.content === "string" ? block.content : JSON.stringify(block.content)}]`;
|
|
16751
|
-
if (block.type === "image")
|
|
16752
|
-
return "[Image attached]";
|
|
16753
|
-
if (block.type === "document")
|
|
16754
|
-
return "[Document attached]";
|
|
16755
|
-
if (block.type === "file")
|
|
16756
|
-
return "[File attached]";
|
|
16757
|
-
return "";
|
|
16758
|
-
}).filter(Boolean).join(`
|
|
16759
|
-
`);
|
|
16760
|
-
} else {
|
|
16761
|
-
content = String(m.content);
|
|
16762
|
-
}
|
|
16763
|
-
return `${role}: ${content}`;
|
|
16764
|
-
}).join(`
|
|
16759
|
+
const content = m.role === "assistant" ? flattenAssistantContent(m.content) : flattenUserContent(m.content, sanitizeOpts);
|
|
16760
|
+
return content ? `${role}: ${content}` : "";
|
|
16761
|
+
}).filter(Boolean).join(`
|
|
16765
16762
|
|
|
16766
16763
|
`) || "";
|
|
16767
16764
|
}
|
|
@@ -16780,7 +16777,19 @@ function createProxyServer(config = {}) {
|
|
|
16780
16777
|
}
|
|
16781
16778
|
}
|
|
16782
16779
|
if (passthrough && requestTools.length > 0) {
|
|
16783
|
-
|
|
16780
|
+
const toolSetKey = computeToolSetKey(requestTools);
|
|
16781
|
+
const cachedMcp = profileSessionId ? sessionMcpCache.get(profileSessionId) : undefined;
|
|
16782
|
+
if (cachedMcp && cachedMcp.key === toolSetKey) {
|
|
16783
|
+
passthroughMcp = cachedMcp.mcp;
|
|
16784
|
+
} else {
|
|
16785
|
+
passthroughMcp = createPassthroughMcpServer(requestTools, adapter.getCoreToolNames?.());
|
|
16786
|
+
if (profileSessionId) {
|
|
16787
|
+
sessionMcpCache.set(profileSessionId, { key: toolSetKey, mcp: passthroughMcp });
|
|
16788
|
+
if (cachedMcp) {
|
|
16789
|
+
console.error(`[PROXY] ${requestMeta.requestId} tools_changed: MCP server recreated (prompt cache likely invalidates)`);
|
|
16790
|
+
}
|
|
16791
|
+
}
|
|
16792
|
+
}
|
|
16784
16793
|
if (profileSessionId)
|
|
16785
16794
|
sessionToolCache.set(profileSessionId, requestTools);
|
|
16786
16795
|
}
|
|
@@ -16903,7 +16912,7 @@ function createProxyServer(config = {}) {
|
|
|
16903
16912
|
for (let i = 0;i < allMessages.length; i++)
|
|
16904
16913
|
sdkUuidMap.push(null);
|
|
16905
16914
|
yield* query(buildQueryOptions({
|
|
16906
|
-
prompt: buildFreshPrompt(allMessages, stripCacheControl),
|
|
16915
|
+
prompt: buildFreshPrompt(allMessages, stripCacheControl, sanitizeOpts),
|
|
16907
16916
|
model,
|
|
16908
16917
|
workingDirectory,
|
|
16909
16918
|
systemContext,
|
|
@@ -17146,7 +17155,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17146
17155
|
cacheCreationInputTokens: lastUsage?.cache_creation_input_tokens,
|
|
17147
17156
|
cacheHitRate: computeCacheHitRate(lastUsage)
|
|
17148
17157
|
});
|
|
17149
|
-
if (currentSessionId) {
|
|
17158
|
+
if (currentSessionId && !isIndependentSession) {
|
|
17150
17159
|
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
|
|
17151
17160
|
}
|
|
17152
17161
|
const responseSessionId = currentSessionId || resumeSessionId || `session_${Date.now()}`;
|
|
@@ -17272,7 +17281,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17272
17281
|
for (let i = 0;i < allMessages.length; i++)
|
|
17273
17282
|
sdkUuidMap.push(null);
|
|
17274
17283
|
yield* query(buildQueryOptions({
|
|
17275
|
-
prompt: buildFreshPrompt(allMessages, stripCacheControl),
|
|
17284
|
+
prompt: buildFreshPrompt(allMessages, stripCacheControl, sanitizeOpts),
|
|
17276
17285
|
model,
|
|
17277
17286
|
workingDirectory,
|
|
17278
17287
|
systemContext,
|
|
@@ -17530,7 +17539,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
17530
17539
|
const allNames = [...sessionDiscoveredTools.get(sessId)];
|
|
17531
17540
|
console.error(`[PROXY] ${requestMeta.requestId} discovered=${discoveredTools.size} (${newNames}) session_total=${allNames.length}`);
|
|
17532
17541
|
}
|
|
17533
|
-
if (currentSessionId) {
|
|
17542
|
+
if (currentSessionId && !isIndependentSession) {
|
|
17534
17543
|
storeSession(profileSessionId, body.messages || [], currentSessionId, profileScopedCwd, sdkUuidMap, lastUsage);
|
|
17535
17544
|
}
|
|
17536
17545
|
if (!streamClosed) {
|
package/dist/cli.js
CHANGED
package/dist/proxy/adapter.d.ts
CHANGED
|
@@ -125,6 +125,16 @@ export interface AgentAdapter {
|
|
|
125
125
|
* the extra block is noisy. When undefined, the proxy defaults to true.
|
|
126
126
|
*/
|
|
127
127
|
shouldTrackFileChanges?(): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Whether this agent leaks CWD/env info through `<system-reminder>` blocks
|
|
130
|
+
* in user messages (Droid). When true, the proxy strips those blocks before
|
|
131
|
+
* flattening to a text prompt so they don't echo back to the model.
|
|
132
|
+
*
|
|
133
|
+
* Most agents (OpenCode, Crush, ForgeCode) use `<system-reminder>` to surface
|
|
134
|
+
* harness state the model needs to see (e.g. oh-my-opencode background task
|
|
135
|
+
* IDs), so the default is false — preserve them.
|
|
136
|
+
*/
|
|
137
|
+
leaksCwdViaSystemReminder?(): boolean;
|
|
128
138
|
/**
|
|
129
139
|
* Map a client-side tool_use block to file changes (passthrough mode).
|
|
130
140
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5C;;;OAGG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;IAE1B;;OAEG;IACH,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAA;IAEvC;;;;OAIG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEhF;;;OAGG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAA;IAE9D;;;OAGG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IAE9E;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAA;IAErC;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAAE,CAAA;IAEtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAA;IAErC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,OAAO,CAAA;IAE5B;;;;;;OAMG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAA;IAElC;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5C;;;OAGG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;IAE1B;;OAEG;IACH,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAA;IAEvC;;;;OAIG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEhF;;;OAGG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAA;IAE9D;;;OAGG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IAE9E;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAA;IAErC;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAAE,CAAA;IAEtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAA;IAErC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,OAAO,CAAA;IAE5B;;;;;;OAMG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAA;IAElC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,IAAI,OAAO,CAAA;IAErC;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"droid.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/droid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAwC9C,eAAO,MAAM,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"droid.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/droid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAwC9C,eAAO,MAAM,YAAY,EAAE,YA8E1B,CAAA"}
|
|
@@ -30,6 +30,16 @@ export declare function createPassthroughMcpServer(tools: Array<{
|
|
|
30
30
|
toolNames: string[];
|
|
31
31
|
hasDeferredTools: boolean;
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Stable cache key for a tool set — name + input schema, sorted.
|
|
35
|
+
* Schema is included so silently-updated tool definitions force a rebuild
|
|
36
|
+
* of the cached MCP server.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeToolSetKey(tools: Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
input_schema?: unknown;
|
|
41
|
+
defer_loading?: boolean;
|
|
42
|
+
}>): string;
|
|
33
43
|
/**
|
|
34
44
|
* Strip the MCP prefix from a tool name to get the OpenCode tool name.
|
|
35
45
|
* e.g., "mcp__oc__todowrite" → "todowrite"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passthroughTools.d.ts","sourceRoot":"","sources":["../../src/proxy/passthroughTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AACxC,eAAO,MAAM,sBAAsB,cAAmC,CAAA;AA0CtE,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EACjG,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE;;;;EA4DlC;AAqBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD"}
|
|
1
|
+
{"version":3,"file":"passthroughTools.d.ts","sourceRoot":"","sources":["../../src/proxy/passthroughTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AACxC,eAAO,MAAM,sBAAsB,cAAmC,CAAA;AA0CtE,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EACjG,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE;;;;EA4DlC;AAqBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC9E,MAAM,CASR;AAUD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD"}
|
package/dist/proxy/sanitize.d.ts
CHANGED
|
@@ -16,11 +16,16 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Fixes: https://github.com/rynfar/meridian/issues/167
|
|
18
18
|
*/
|
|
19
|
+
export interface SanitizeOptions {
|
|
20
|
+
/** Strip `<system-reminder>` blocks. Enable for adapters (Droid) that leak
|
|
21
|
+
* CWD/env through this tag. */
|
|
22
|
+
stripSystemReminder?: boolean;
|
|
23
|
+
}
|
|
19
24
|
/**
|
|
20
25
|
* Strip orchestration wrappers from a single text string.
|
|
21
26
|
*
|
|
22
27
|
* Designed to be called on individual content blocks (not concatenated
|
|
23
28
|
* prompt strings) to eliminate cross-block regex matching risk.
|
|
24
29
|
*/
|
|
25
|
-
export declare function sanitizeTextContent(text: string): string;
|
|
30
|
+
export declare function sanitizeTextContent(text: string, opts?: SanitizeOptions): string;
|
|
26
31
|
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/proxy/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/proxy/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAwEH,MAAM,WAAW,eAAe;IAC9B;oCACgC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,eAAoB,GAAG,MAAM,CAapF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AA0BvD,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAGzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AAgL7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAy6DhF;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAiEhG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,aAAa,EACnB,MAAM,WAAW,CAAA;AAMlB,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAqCD;kGACkG;AAClG,wBAAgB,iBAAiB,SAYhC;AAED;iFACiF;AACjF,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,CAAC,EAAE,MAAM,EACzB,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAC/C,IAAI,CAoBN;AAUD;;uDAEuD;AACvD,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,EAC/C,gBAAgB,CAAC,EAAE,MAAM,GACxB,aAAa,CAuDf;AAED;;uFAEuF;AACvF,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CA2BtF;AAED;;;yFAGyF;AACzF,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,EACnD,eAAe,EAAE,MAAM,EACvB,gBAAgB,CAAC,EAAE,MAAM,EACzB,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EACtC,YAAY,CAAC,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/proxy/session/cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,aAAa,EACnB,MAAM,WAAW,CAAA;AAMlB,wBAAgB,mBAAmB,IAAI,MAAM,CAW5C;AAqCD;kGACkG;AAClG,wBAAgB,iBAAiB,SAYhC;AAED;iFACiF;AACjF,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,CAAC,EAAE,MAAM,EACzB,QAAQ,CAAC,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,GAC/C,IAAI,CAoBN;AAUD;;uDAEuD;AACvD,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,CAAC,EAC/C,gBAAgB,CAAC,EAAE,MAAM,GACxB,aAAa,CAuDf;AAED;;uFAEuF;AACvF,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CA2BtF;AAED;;;yFAGyF;AACzF,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,EACnD,eAAe,EAAE,MAAM,EACvB,gBAAgB,CAAC,EAAE,MAAM,EACzB,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EACtC,YAAY,CAAC,EAAE,UAAU,QAoC1B"}
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynfar/meridian",
|
|
3
|
-
"version": "1.37.
|
|
3
|
+
"version": "1.37.5",
|
|
4
4
|
"description": "Local Anthropic API powered by your Claude Max subscription. One subscription, every agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"postbuild": "node --check dist/cli.js && node --check dist/server.js && test -f dist/proxy/server.d.ts",
|
|
26
26
|
"prepublishOnly": "bun run build",
|
|
27
27
|
"test": "bun test --path-ignore-patterns '**/*session-store*' --path-ignore-patterns '**/*proxy-async-ops*' --path-ignore-patterns '**/*proxy-extra-usage-fallback*' --path-ignore-patterns '**/*models-auth-status*' --path-ignore-patterns '**/*proxy-context-usage-store*' --path-ignore-patterns '**/*proxy-passthrough-thinking*' --path-ignore-patterns '**/*profile-switch-integration*' --path-ignore-patterns '**/*session-recovery*' --path-ignore-patterns '**/*models.test*' --path-ignore-patterns '**/*proxy-health-degraded*' --path-ignore-patterns '**/*proxy-subagent-model-selection*' && bun test src/__tests__/profile-switch-integration.test.ts && bun test src/__tests__/proxy-extra-usage-fallback.test.ts && bun test src/__tests__/proxy-async-ops.test.ts && bun test src/__tests__/proxy-session-store.test.ts && bun test src/__tests__/session-store-pruning.test.ts && bun test src/__tests__/proxy-session-store-locking.test.ts && bun test src/__tests__/proxy-context-usage-store.test.ts && bun test src/__tests__/models-auth-status.test.ts && bun test src/__tests__/proxy-passthrough-thinking.test.ts && bun test src/__tests__/proxy-session-recovery.test.ts && bun test src/__tests__/models.test.ts && bun test src/__tests__/proxy-health-degraded.test.ts && bun test src/__tests__/proxy-subagent-model-selection.test.ts",
|
|
28
|
+
"nix:lock": "bun2nix -o bun.nix",
|
|
28
29
|
"typecheck": "tsc --noEmit",
|
|
29
30
|
"proxy:direct": "bun run ./bin/cli.ts"
|
|
30
31
|
},
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
"@hono/node-server": "^1.19.11",
|
|
37
38
|
"@types/bun": "^1.3.11",
|
|
38
39
|
"@types/node": "^22.0.0",
|
|
40
|
+
"bun2nix": "^2.0.8",
|
|
39
41
|
"glob": "^13.0.0",
|
|
40
42
|
"hono": "^4.11.4",
|
|
41
43
|
"typescript": "^5.8.2"
|