@rynfar/meridian 1.37.8 → 1.39.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 +54 -3
- package/dist/{cli-pr79d7nw.js → cli-4rqtm83g.js} +33 -2
- package/dist/{cli-z5r7ptsm.js → cli-jbdchsr4.js} +1109 -231
- package/dist/cli-sry5aqdj.js +54 -0
- package/dist/cli.js +5 -4
- package/dist/pluginPage-85s6t6k8.js +405 -0
- package/dist/{profilePage-g5t5t6av.js → profilePage-77z05e0r.js} +4 -8
- package/dist/proxy/adapter.d.ts +45 -12
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts +21 -0
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -0
- package/dist/proxy/adapters/crush.d.ts +2 -0
- package/dist/proxy/adapters/crush.d.ts.map +1 -1
- package/dist/proxy/adapters/detect.d.ts +3 -2
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/adapters/droid.d.ts +2 -0
- package/dist/proxy/adapters/droid.d.ts.map +1 -1
- package/dist/proxy/adapters/forgecode.d.ts +2 -0
- package/dist/proxy/adapters/forgecode.d.ts.map +1 -1
- package/dist/proxy/adapters/opencode.d.ts +2 -0
- package/dist/proxy/adapters/opencode.d.ts.map +1 -1
- package/dist/proxy/adapters/passthrough.d.ts +2 -0
- package/dist/proxy/adapters/passthrough.d.ts.map +1 -1
- package/dist/proxy/adapters/pi.d.ts +2 -0
- package/dist/proxy/adapters/pi.d.ts.map +1 -1
- package/dist/proxy/agentDefs.d.ts +2 -0
- package/dist/proxy/agentDefs.d.ts.map +1 -1
- package/dist/proxy/agentMatch.d.ts +11 -1
- package/dist/proxy/agentMatch.d.ts.map +1 -1
- package/dist/proxy/messages.d.ts +11 -0
- package/dist/proxy/messages.d.ts.map +1 -1
- package/dist/proxy/models.d.ts +25 -0
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/passthroughTools.d.ts +18 -0
- package/dist/proxy/passthroughTools.d.ts.map +1 -1
- package/dist/proxy/plugins/loader.d.ts +6 -0
- package/dist/proxy/plugins/loader.d.ts.map +1 -0
- package/dist/proxy/plugins/pluginPage.d.ts +7 -0
- package/dist/proxy/plugins/pluginPage.d.ts.map +1 -0
- package/dist/proxy/plugins/stats.d.ts +61 -0
- package/dist/proxy/plugins/stats.d.ts.map +1 -0
- package/dist/proxy/plugins/types.d.ts +21 -0
- package/dist/proxy/plugins/types.d.ts.map +1 -0
- package/dist/proxy/plugins/validation.d.ts +8 -0
- package/dist/proxy/plugins/validation.d.ts.map +1 -0
- package/dist/proxy/query.d.ts +27 -4
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/server.d.ts +2 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts +10 -1
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/transform.d.ts +137 -0
- package/dist/proxy/transform.d.ts.map +1 -0
- package/dist/proxy/transforms/crush.d.ts +3 -0
- package/dist/proxy/transforms/crush.d.ts.map +1 -0
- package/dist/proxy/transforms/droid.d.ts +3 -0
- package/dist/proxy/transforms/droid.d.ts.map +1 -0
- package/dist/proxy/transforms/forgecode.d.ts +3 -0
- package/dist/proxy/transforms/forgecode.d.ts.map +1 -0
- package/dist/proxy/transforms/opencode.d.ts +3 -0
- package/dist/proxy/transforms/opencode.d.ts.map +1 -0
- package/dist/proxy/transforms/passthrough.d.ts +3 -0
- package/dist/proxy/transforms/passthrough.d.ts.map +1 -0
- package/dist/proxy/transforms/pi.d.ts +3 -0
- package/dist/proxy/transforms/pi.d.ts.map +1 -0
- package/dist/proxy/transforms/registry.d.ts +3 -0
- package/dist/proxy/transforms/registry.d.ts.map +1 -0
- package/dist/proxy/types.d.ts +6 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/server.js +14 -5
- package/dist/stats-4c4ewmdh.js +17 -0
- package/dist/telemetry/dashboard.d.ts.map +1 -1
- package/dist/telemetry/landing.d.ts.map +1 -1
- package/dist/telemetry/profileBar.d.ts +13 -1
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +1 -1
- package/dist/telemetry/settingsPage.d.ts.map +1 -1
- package/dist/telemetry/sqlite.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +4 -0
- package/dist/telemetry/types.d.ts.map +1 -1
- package/package.json +4 -2
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getActiveProfileId,
|
|
3
|
+
getEffectiveProfiles,
|
|
4
|
+
listProfiles,
|
|
5
|
+
resolveProfile,
|
|
6
|
+
restoreActiveProfile,
|
|
7
|
+
setActiveProfile
|
|
8
|
+
} from "./cli-vdp9s10c.js";
|
|
9
|
+
import {
|
|
10
|
+
isTrackedPlugin,
|
|
11
|
+
recordError,
|
|
12
|
+
recordInvocation,
|
|
13
|
+
registerPluginStats,
|
|
14
|
+
resetAllPluginStats
|
|
15
|
+
} from "./cli-sry5aqdj.js";
|
|
1
16
|
import {
|
|
2
17
|
init_profileBar,
|
|
3
18
|
profileBarCss,
|
|
4
19
|
profileBarHtml,
|
|
5
|
-
profileBarJs
|
|
6
|
-
|
|
20
|
+
profileBarJs,
|
|
21
|
+
themeCss
|
|
22
|
+
} from "./cli-4rqtm83g.js";
|
|
7
23
|
import {
|
|
8
24
|
checkPluginConfigured
|
|
9
25
|
} from "./cli-rtab0qa6.js";
|
|
@@ -12,14 +28,6 @@ import {
|
|
|
12
28
|
refreshOAuthToken,
|
|
13
29
|
withClaudeLogContext
|
|
14
30
|
} from "./cli-m9pfb7h9.js";
|
|
15
|
-
import {
|
|
16
|
-
getActiveProfileId,
|
|
17
|
-
getEffectiveProfiles,
|
|
18
|
-
listProfiles,
|
|
19
|
-
resolveProfile,
|
|
20
|
-
restoreActiveProfile,
|
|
21
|
-
setActiveProfile
|
|
22
|
-
} from "./cli-vdp9s10c.js";
|
|
23
31
|
import {
|
|
24
32
|
__commonJS,
|
|
25
33
|
__esm,
|
|
@@ -849,6 +857,11 @@ function openDatabase(dbPath) {
|
|
|
849
857
|
db.pragma("synchronous = NORMAL");
|
|
850
858
|
db.exec(METRICS_SCHEMA);
|
|
851
859
|
db.exec(LOGS_SCHEMA);
|
|
860
|
+
for (const sql of METRICS_MIGRATIONS) {
|
|
861
|
+
try {
|
|
862
|
+
db.exec(sql);
|
|
863
|
+
} catch {}
|
|
864
|
+
}
|
|
852
865
|
return db;
|
|
853
866
|
}
|
|
854
867
|
|
|
@@ -863,7 +876,7 @@ class SqliteTelemetryStore {
|
|
|
863
876
|
this.retentionMs = retentionDays * 24 * 60 * 60 * 1000;
|
|
864
877
|
this.insertStmt = db.prepare(`
|
|
865
878
|
INSERT INTO metrics (
|
|
866
|
-
request_id, timestamp, adapter, model, request_model, mode,
|
|
879
|
+
request_id, timestamp, adapter, request_source, model, request_model, mode,
|
|
867
880
|
is_resume, is_passthrough, lineage_type,
|
|
868
881
|
has_deferred_tools, deferred_tool_count, tool_count, discovered_tools, session_discovered_count,
|
|
869
882
|
message_count, sdk_session_id,
|
|
@@ -872,7 +885,7 @@ class SqliteTelemetryStore {
|
|
|
872
885
|
input_tokens, output_tokens, cache_read_input_tokens,
|
|
873
886
|
cache_creation_input_tokens, cache_hit_rate
|
|
874
887
|
) VALUES (
|
|
875
|
-
@requestId, @timestamp, @adapter, @model, @requestModel, @mode,
|
|
888
|
+
@requestId, @timestamp, @adapter, @requestSource, @model, @requestModel, @mode,
|
|
876
889
|
@isResume, @isPassthrough, @lineageType,
|
|
877
890
|
@hasDeferredTools, @deferredToolCount, @toolCount, @discoveredTools, @sessionDiscoveredCount,
|
|
878
891
|
@messageCount, @sdkSessionId,
|
|
@@ -890,6 +903,7 @@ class SqliteTelemetryStore {
|
|
|
890
903
|
requestId: metric.requestId,
|
|
891
904
|
timestamp: metric.timestamp,
|
|
892
905
|
adapter: metric.adapter ?? null,
|
|
906
|
+
requestSource: metric.requestSource ?? null,
|
|
893
907
|
model: metric.model,
|
|
894
908
|
requestModel: metric.requestModel ?? null,
|
|
895
909
|
mode: metric.mode,
|
|
@@ -1054,6 +1068,7 @@ function rowToMetric(r) {
|
|
|
1054
1068
|
requestId: r.request_id,
|
|
1055
1069
|
timestamp: r.timestamp,
|
|
1056
1070
|
adapter: r.adapter ?? undefined,
|
|
1071
|
+
requestSource: r.request_source ?? undefined,
|
|
1057
1072
|
model: r.model,
|
|
1058
1073
|
requestModel: r.request_model ?? undefined,
|
|
1059
1074
|
mode: r.mode,
|
|
@@ -1101,6 +1116,7 @@ CREATE TABLE IF NOT EXISTS metrics (
|
|
|
1101
1116
|
request_id TEXT NOT NULL,
|
|
1102
1117
|
timestamp INTEGER NOT NULL,
|
|
1103
1118
|
adapter TEXT,
|
|
1119
|
+
request_source TEXT,
|
|
1104
1120
|
model TEXT NOT NULL,
|
|
1105
1121
|
request_model TEXT,
|
|
1106
1122
|
mode TEXT NOT NULL,
|
|
@@ -1132,7 +1148,7 @@ CREATE TABLE IF NOT EXISTS metrics (
|
|
|
1132
1148
|
CREATE INDEX IF NOT EXISTS idx_metrics_ts ON metrics(timestamp);
|
|
1133
1149
|
CREATE INDEX IF NOT EXISTS idx_metrics_model ON metrics(model);
|
|
1134
1150
|
CREATE INDEX IF NOT EXISTS idx_metrics_session_success ON metrics(sdk_session_id, timestamp DESC, id DESC);
|
|
1135
|
-
`, LOGS_SCHEMA = `
|
|
1151
|
+
`, METRICS_MIGRATIONS, LOGS_SCHEMA = `
|
|
1136
1152
|
CREATE TABLE IF NOT EXISTS diagnostic_logs (
|
|
1137
1153
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1138
1154
|
timestamp INTEGER NOT NULL,
|
|
@@ -1147,6 +1163,9 @@ CREATE INDEX IF NOT EXISTS idx_logs_cat ON diagnostic_logs(category);
|
|
|
1147
1163
|
var init_sqlite = __esm(() => {
|
|
1148
1164
|
init_percentiles();
|
|
1149
1165
|
import_libsql = __toESM(require_libsql(), 1);
|
|
1166
|
+
METRICS_MIGRATIONS = [
|
|
1167
|
+
"ALTER TABLE metrics ADD COLUMN request_source TEXT"
|
|
1168
|
+
];
|
|
1150
1169
|
});
|
|
1151
1170
|
|
|
1152
1171
|
// src/proxy/sdkFeatures.ts
|
|
@@ -1158,14 +1177,14 @@ __export(exports_sdkFeatures, {
|
|
|
1158
1177
|
getFeaturesForAdapter: () => getFeaturesForAdapter,
|
|
1159
1178
|
getAllFeatureConfigs: () => getAllFeatureConfigs
|
|
1160
1179
|
});
|
|
1161
|
-
import { existsSync as
|
|
1162
|
-
import { join as
|
|
1180
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync as renameSync2 } from "node:fs";
|
|
1181
|
+
import { join as join6 } from "node:path";
|
|
1163
1182
|
import { homedir as homedir4 } from "node:os";
|
|
1164
1183
|
function getConfigPath() {
|
|
1165
|
-
const dir =
|
|
1166
|
-
if (!
|
|
1184
|
+
const dir = join6(homedir4(), ".config", "meridian");
|
|
1185
|
+
if (!existsSync5(dir))
|
|
1167
1186
|
mkdirSync2(dir, { recursive: true });
|
|
1168
|
-
return
|
|
1187
|
+
return join6(dir, "sdk-features.json");
|
|
1169
1188
|
}
|
|
1170
1189
|
function readConfig() {
|
|
1171
1190
|
const now = Date.now();
|
|
@@ -1173,8 +1192,8 @@ function readConfig() {
|
|
|
1173
1192
|
return cachedConfig;
|
|
1174
1193
|
const path3 = getConfigPath();
|
|
1175
1194
|
try {
|
|
1176
|
-
if (
|
|
1177
|
-
cachedConfig = JSON.parse(
|
|
1195
|
+
if (existsSync5(path3)) {
|
|
1196
|
+
cachedConfig = JSON.parse(readFileSync4(path3, "utf-8"));
|
|
1178
1197
|
} else {
|
|
1179
1198
|
cachedConfig = {};
|
|
1180
1199
|
}
|
|
@@ -1297,12 +1316,7 @@ var init_settingsPage = __esm(() => {
|
|
|
1297
1316
|
<title>Meridian — SDK Features</title>
|
|
1298
1317
|
<link rel="icon" type="image/svg+xml" href="/telemetry/icon.svg">
|
|
1299
1318
|
<style>
|
|
1300
|
-
|
|
1301
|
-
--bg: #0d1117; --surface: #161b22; --border: #30363d;
|
|
1302
|
-
--text: #e6edf3; --muted: #8b949e; --accent: #58a6ff;
|
|
1303
|
-
--green: #3fb950; --yellow: #d29922; --red: #f85149;
|
|
1304
|
-
--purple: #bc8cff;
|
|
1305
|
-
}
|
|
1319
|
+
${themeCss}
|
|
1306
1320
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1307
1321
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
1308
1322
|
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
|
@@ -3688,6 +3702,8 @@ var serve = (options, listeningListener) => {
|
|
|
3688
3702
|
};
|
|
3689
3703
|
|
|
3690
3704
|
// src/proxy/server.ts
|
|
3705
|
+
import { homedir as homedir5 } from "node:os";
|
|
3706
|
+
import { join as join7 } from "node:path";
|
|
3691
3707
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
3692
3708
|
|
|
3693
3709
|
// src/proxy/types.ts
|
|
@@ -3718,6 +3734,73 @@ function envInt(suffix, defaultValue) {
|
|
|
3718
3734
|
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
3719
3735
|
}
|
|
3720
3736
|
|
|
3737
|
+
// src/proxy/transform.ts
|
|
3738
|
+
function runTransformHook(transforms, hook, ctx, adapterName) {
|
|
3739
|
+
return transforms.reduce((acc, transform) => {
|
|
3740
|
+
const fn = transform[hook];
|
|
3741
|
+
if (!fn)
|
|
3742
|
+
return acc;
|
|
3743
|
+
if (transform.adapters && !transform.adapters.includes(adapterName))
|
|
3744
|
+
return acc;
|
|
3745
|
+
const tracked = isTrackedPlugin(transform.name);
|
|
3746
|
+
const startAt = tracked ? performance.now() : 0;
|
|
3747
|
+
try {
|
|
3748
|
+
const result = fn.call(transform, acc);
|
|
3749
|
+
if (tracked)
|
|
3750
|
+
recordInvocation(transform.name, hook, performance.now() - startAt);
|
|
3751
|
+
return result;
|
|
3752
|
+
} catch (err) {
|
|
3753
|
+
if (tracked)
|
|
3754
|
+
recordError(transform.name, hook, err);
|
|
3755
|
+
console.error(`[PLUGIN] Transform "${transform.name}" threw in ${hook}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3756
|
+
return acc;
|
|
3757
|
+
}
|
|
3758
|
+
}, ctx);
|
|
3759
|
+
}
|
|
3760
|
+
function runObserveHook(transforms, hook, ctx, adapterName) {
|
|
3761
|
+
for (const transform of transforms) {
|
|
3762
|
+
const fn = transform[hook];
|
|
3763
|
+
if (!fn)
|
|
3764
|
+
continue;
|
|
3765
|
+
if (transform.adapters && !transform.adapters.includes(adapterName))
|
|
3766
|
+
continue;
|
|
3767
|
+
const tracked = isTrackedPlugin(transform.name);
|
|
3768
|
+
const startAt = tracked ? performance.now() : 0;
|
|
3769
|
+
try {
|
|
3770
|
+
fn.call(transform, ctx);
|
|
3771
|
+
if (tracked)
|
|
3772
|
+
recordInvocation(transform.name, hook, performance.now() - startAt);
|
|
3773
|
+
} catch (err) {
|
|
3774
|
+
if (tracked)
|
|
3775
|
+
recordError(transform.name, hook, err);
|
|
3776
|
+
console.error(`[PLUGIN] Transform "${transform.name}" threw in ${hook}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
function buildPipeline(adapterTransforms, pluginTransforms) {
|
|
3781
|
+
return [...adapterTransforms, ...pluginTransforms];
|
|
3782
|
+
}
|
|
3783
|
+
function createRequestContext(params) {
|
|
3784
|
+
return {
|
|
3785
|
+
adapter: params.adapter,
|
|
3786
|
+
body: params.body,
|
|
3787
|
+
headers: params.headers,
|
|
3788
|
+
model: params.model,
|
|
3789
|
+
messages: params.messages,
|
|
3790
|
+
systemContext: params.systemContext,
|
|
3791
|
+
tools: params.tools,
|
|
3792
|
+
stream: params.stream,
|
|
3793
|
+
workingDirectory: params.workingDirectory,
|
|
3794
|
+
blockedTools: [],
|
|
3795
|
+
incompatibleTools: [],
|
|
3796
|
+
allowedMcpTools: [],
|
|
3797
|
+
sdkAgents: {},
|
|
3798
|
+
supportsThinking: false,
|
|
3799
|
+
shouldTrackFileChanges: true,
|
|
3800
|
+
leaksCwdViaSystemReminder: false,
|
|
3801
|
+
metadata: {}
|
|
3802
|
+
};
|
|
3803
|
+
}
|
|
3721
3804
|
// src/proxy/server.ts
|
|
3722
3805
|
import { exec as execCallback2 } from "child_process";
|
|
3723
3806
|
import { promisify as promisify3 } from "util";
|
|
@@ -7805,6 +7888,184 @@ function stripMcpPrefix(toolName) {
|
|
|
7805
7888
|
}
|
|
7806
7889
|
return toolName;
|
|
7807
7890
|
}
|
|
7891
|
+
function toCamelCase(s) {
|
|
7892
|
+
return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
7893
|
+
}
|
|
7894
|
+
function toSnakeCase(s) {
|
|
7895
|
+
return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
|
|
7896
|
+
}
|
|
7897
|
+
function normalizeToolInput(input, clientSchema) {
|
|
7898
|
+
if (!input || !clientSchema?.properties)
|
|
7899
|
+
return input;
|
|
7900
|
+
const schemaKeys = new Set(Object.keys(clientSchema.properties));
|
|
7901
|
+
const required = new Set(clientSchema.required ?? []);
|
|
7902
|
+
const missingRequired = [...required].filter((k) => input[k] === undefined);
|
|
7903
|
+
if (missingRequired.length === 0)
|
|
7904
|
+
return input;
|
|
7905
|
+
const normalized = { ...input };
|
|
7906
|
+
for (const key of Object.keys(normalized)) {
|
|
7907
|
+
if (schemaKeys.has(key))
|
|
7908
|
+
continue;
|
|
7909
|
+
const camel = toCamelCase(key);
|
|
7910
|
+
if (camel !== key && schemaKeys.has(camel) && normalized[camel] === undefined) {
|
|
7911
|
+
normalized[camel] = normalized[key];
|
|
7912
|
+
delete normalized[key];
|
|
7913
|
+
continue;
|
|
7914
|
+
}
|
|
7915
|
+
const snake = toSnakeCase(key);
|
|
7916
|
+
if (snake !== key && schemaKeys.has(snake) && normalized[snake] === undefined) {
|
|
7917
|
+
normalized[snake] = normalized[key];
|
|
7918
|
+
delete normalized[key];
|
|
7919
|
+
}
|
|
7920
|
+
}
|
|
7921
|
+
return normalized;
|
|
7922
|
+
}
|
|
7923
|
+
|
|
7924
|
+
// src/proxy/agentDefs.ts
|
|
7925
|
+
var FALLBACK_AGENT_NAME = "general";
|
|
7926
|
+
var DEFAULT_AGENT_TYPES = {
|
|
7927
|
+
build: "The default agent. Executes tools based on configured permissions.",
|
|
7928
|
+
plan: "Plan mode. Disallows all edit tools.",
|
|
7929
|
+
explore: "Contextual grep for codebases. Answers 'Where is X?', 'Which file has Y?'.",
|
|
7930
|
+
general: "General-purpose agent for researching complex questions and executing multi-step tasks."
|
|
7931
|
+
};
|
|
7932
|
+
function parseAgentDescriptions(taskDescription) {
|
|
7933
|
+
const agents = new Map;
|
|
7934
|
+
const agentSection = taskDescription.match(/Available agent types.*?:\n((?:- [\w][\w-]*:.*\n?)+)/s);
|
|
7935
|
+
if (!agentSection)
|
|
7936
|
+
return agents;
|
|
7937
|
+
const entries = agentSection[1].matchAll(/^- ([\w][\w-]*):\s*(.+)/gm);
|
|
7938
|
+
for (const match2 of entries) {
|
|
7939
|
+
agents.set(match2[1], match2[2].trim());
|
|
7940
|
+
}
|
|
7941
|
+
return agents;
|
|
7942
|
+
}
|
|
7943
|
+
function buildAgentDefinitions(taskDescription, mcpToolNames) {
|
|
7944
|
+
const descriptions = parseAgentDescriptions(taskDescription);
|
|
7945
|
+
const agents = {};
|
|
7946
|
+
for (const [name, description] of descriptions) {
|
|
7947
|
+
agents[name] = {
|
|
7948
|
+
description,
|
|
7949
|
+
prompt: buildAgentPrompt(name, description),
|
|
7950
|
+
model: "inherit",
|
|
7951
|
+
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
7952
|
+
};
|
|
7953
|
+
}
|
|
7954
|
+
if (descriptions.size > 0) {
|
|
7955
|
+
ensureDefaultAgents(agents, mcpToolNames);
|
|
7956
|
+
addCaseVariants(agents);
|
|
7957
|
+
}
|
|
7958
|
+
return agents;
|
|
7959
|
+
}
|
|
7960
|
+
function ensureDefaultAgents(agents, mcpToolNames) {
|
|
7961
|
+
for (const [name, description] of Object.entries(DEFAULT_AGENT_TYPES)) {
|
|
7962
|
+
if (!agents[name]) {
|
|
7963
|
+
agents[name] = {
|
|
7964
|
+
description,
|
|
7965
|
+
prompt: buildAgentPrompt(name, description),
|
|
7966
|
+
model: "inherit",
|
|
7967
|
+
...mcpToolNames?.length ? { tools: [...mcpToolNames] } : {}
|
|
7968
|
+
};
|
|
7969
|
+
}
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
function addCaseVariants(agents) {
|
|
7973
|
+
const baseNames = Object.keys(agents);
|
|
7974
|
+
for (const name of baseNames) {
|
|
7975
|
+
const def = agents[name];
|
|
7976
|
+
const titleCase = name.replace(/(^|-)(\w)/g, (_m, sep, ch) => sep + ch.toUpperCase());
|
|
7977
|
+
if (titleCase !== name && !agents[titleCase]) {
|
|
7978
|
+
agents[titleCase] = def;
|
|
7979
|
+
}
|
|
7980
|
+
}
|
|
7981
|
+
const ALIASES = {
|
|
7982
|
+
"general-purpose": "general",
|
|
7983
|
+
"General-Purpose": "general"
|
|
7984
|
+
};
|
|
7985
|
+
for (const [alias, target] of Object.entries(ALIASES)) {
|
|
7986
|
+
if (!agents[alias] && agents[target]) {
|
|
7987
|
+
agents[alias] = agents[target];
|
|
7988
|
+
}
|
|
7989
|
+
}
|
|
7990
|
+
}
|
|
7991
|
+
function buildAgentPrompt(name, description) {
|
|
7992
|
+
return `You are the "${name}" agent. ${description}
|
|
7993
|
+
|
|
7994
|
+
Focus on your specific role and complete the task thoroughly. Return a clear, concise result.`;
|
|
7995
|
+
}
|
|
7996
|
+
|
|
7997
|
+
// src/proxy/agentMatch.ts
|
|
7998
|
+
var KNOWN_ALIASES = {
|
|
7999
|
+
"general-purpose": "general",
|
|
8000
|
+
default: "general",
|
|
8001
|
+
"code-reviewer": "oracle",
|
|
8002
|
+
reviewer: "oracle",
|
|
8003
|
+
"code-review": "oracle",
|
|
8004
|
+
review: "oracle",
|
|
8005
|
+
consultation: "oracle",
|
|
8006
|
+
analyzer: "oracle",
|
|
8007
|
+
debugger: "oracle",
|
|
8008
|
+
search: "explore",
|
|
8009
|
+
grep: "explore",
|
|
8010
|
+
find: "explore",
|
|
8011
|
+
"codebase-search": "explore",
|
|
8012
|
+
research: "librarian",
|
|
8013
|
+
docs: "librarian",
|
|
8014
|
+
documentation: "librarian",
|
|
8015
|
+
lookup: "librarian",
|
|
8016
|
+
reference: "librarian",
|
|
8017
|
+
consult: "oracle",
|
|
8018
|
+
architect: "oracle",
|
|
8019
|
+
"image-analyzer": "multimodal-looker",
|
|
8020
|
+
image: "multimodal-looker",
|
|
8021
|
+
pdf: "multimodal-looker",
|
|
8022
|
+
visual: "multimodal-looker",
|
|
8023
|
+
planner: "plan",
|
|
8024
|
+
planning: "plan",
|
|
8025
|
+
builder: "build",
|
|
8026
|
+
coder: "build",
|
|
8027
|
+
developer: "build",
|
|
8028
|
+
writer: "build",
|
|
8029
|
+
executor: "build"
|
|
8030
|
+
};
|
|
8031
|
+
var STRIP_SUFFIXES = ["-agent", "-tool", "-worker", "-task", " agent", " tool"];
|
|
8032
|
+
function resolveAgentAlias(input) {
|
|
8033
|
+
const lowered = input.toLowerCase();
|
|
8034
|
+
return KNOWN_ALIASES[lowered] ?? lowered;
|
|
8035
|
+
}
|
|
8036
|
+
function fuzzyMatchAgentName(input, validAgents) {
|
|
8037
|
+
if (!input)
|
|
8038
|
+
return input;
|
|
8039
|
+
if (validAgents.length === 0)
|
|
8040
|
+
return input.toLowerCase();
|
|
8041
|
+
const lowered = input.toLowerCase();
|
|
8042
|
+
const exact = validAgents.find((a) => a.toLowerCase() === lowered);
|
|
8043
|
+
if (exact)
|
|
8044
|
+
return exact;
|
|
8045
|
+
const alias = KNOWN_ALIASES[lowered];
|
|
8046
|
+
if (alias && validAgents.includes(alias))
|
|
8047
|
+
return alias;
|
|
8048
|
+
const prefixMatch = validAgents.find((a) => a.toLowerCase().startsWith(lowered));
|
|
8049
|
+
if (prefixMatch)
|
|
8050
|
+
return prefixMatch;
|
|
8051
|
+
const substringMatch = validAgents.find((a) => a.toLowerCase().includes(lowered));
|
|
8052
|
+
if (substringMatch)
|
|
8053
|
+
return substringMatch;
|
|
8054
|
+
for (const suffix of STRIP_SUFFIXES) {
|
|
8055
|
+
if (lowered.endsWith(suffix)) {
|
|
8056
|
+
const stripped = lowered.slice(0, -suffix.length);
|
|
8057
|
+
const strippedMatch = validAgents.find((a) => a.toLowerCase() === stripped);
|
|
8058
|
+
if (strippedMatch)
|
|
8059
|
+
return strippedMatch;
|
|
8060
|
+
}
|
|
8061
|
+
}
|
|
8062
|
+
const reverseMatch = validAgents.find((a) => lowered.includes(a.toLowerCase()));
|
|
8063
|
+
if (reverseMatch)
|
|
8064
|
+
return reverseMatch;
|
|
8065
|
+
if (validAgents.includes(FALLBACK_AGENT_NAME))
|
|
8066
|
+
return FALLBACK_AGENT_NAME;
|
|
8067
|
+
return lowered;
|
|
8068
|
+
}
|
|
7808
8069
|
|
|
7809
8070
|
// src/utils/lruMap.ts
|
|
7810
8071
|
class LRUMap {
|
|
@@ -8010,13 +8271,8 @@ var dashboardHtml = `<!DOCTYPE html>
|
|
|
8010
8271
|
<title>Meridian — Telemetry</title>
|
|
8011
8272
|
<link rel="icon" type="image/svg+xml" href="/telemetry/icon.svg">
|
|
8012
8273
|
<style>
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
--text: #e6edf3; --muted: #8b949e; --accent: #58a6ff;
|
|
8016
|
-
--green: #3fb950; --yellow: #d29922; --red: #f85149;
|
|
8017
|
-
--blue: #58a6ff; --purple: #bc8cff;
|
|
8018
|
-
--queue: #d29922; --ttfb: #58a6ff; --upstream: #3fb950; --total: #bc8cff;
|
|
8019
|
-
}
|
|
8274
|
+
${themeCss}
|
|
8275
|
+
:root { --total: var(--accent); }
|
|
8020
8276
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
8021
8277
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
8022
8278
|
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
|
@@ -8272,9 +8528,11 @@ function render(s, reqs, logs) {
|
|
|
8272
8528
|
const sessionShort = r.sdkSessionId ? r.sdkSessionId.slice(0, 8) : '—';
|
|
8273
8529
|
const msgCount = r.messageCount != null ? r.messageCount : '?';
|
|
8274
8530
|
|
|
8531
|
+
const sourceBadge = r.requestSource ? '<br><span class="mono" style="font-size:9px;color:var(--violet)">' + r.requestSource + '</span>' : '';
|
|
8532
|
+
|
|
8275
8533
|
html += '<tr>'
|
|
8276
8534
|
+ '<td class="mono">' + ago(r.timestamp) + '</td>'
|
|
8277
|
-
+ '<td>' + (r.adapter || '—') + '</td>'
|
|
8535
|
+
+ '<td>' + (r.adapter || '—') + sourceBadge + '</td>'
|
|
8278
8536
|
+ '<td>' + (r.requestModel || r.model) + '<br><span style="font-size:10px;color:var(--muted)">' + r.model + '</span></td>'
|
|
8279
8537
|
+ '<td>' + r.mode + (r.hasDeferredTools ? (function() { var sessDisc = r.sessionDiscoveredCount || 0; var loaded = ((r.toolCount || 0) - (r.deferredToolCount || 0)) + sessDisc; var deferred = Math.max(0, (r.deferredToolCount || 0) - sessDisc); var newDisc = r.discoveredTools || []; return '<br><span style="font-size:10px;color:var(--purple)">loaded=' + loaded + ' deferred=' + deferred + '</span>' + (newDisc.length > 0 ? '<br><span style="font-size:10px;color:var(--green)">+' + newDisc.join(', +') + '</span>' : ''); })() : '') + '</td>'
|
|
8280
8538
|
+ '<td class="mono">' + sessionShort + ' ' + lineageBadge + '<br><span style="font-size:10px;color:var(--muted)">' + msgCount + ' msgs</span></td>'
|
|
@@ -8407,12 +8665,7 @@ var landingHtml = `<!DOCTYPE html>
|
|
|
8407
8665
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8408
8666
|
<title>Meridian</title>
|
|
8409
8667
|
<style>
|
|
8410
|
-
|
|
8411
|
-
--bg: #0f0b1a; --surface: #1a1030; --surface2: #221840; --border: #2d2545;
|
|
8412
|
-
--text: #e0e7ff; --muted: #8b8aa0; --accent: #8b5cf6; --accent2: #6366f1;
|
|
8413
|
-
--green: #3fb950; --yellow: #d29922; --red: #f85149;
|
|
8414
|
-
--violet: #a78bfa; --lavender: #c4b5fd;
|
|
8415
|
-
}
|
|
8668
|
+
${themeCss}
|
|
8416
8669
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
8417
8670
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
8418
8671
|
background: var(--bg); color: var(--text); line-height: 1.6; min-height: 100vh; }
|
|
@@ -8722,6 +8975,16 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
8722
8975
|
import { join as join2, dirname as dirname2 } from "path";
|
|
8723
8976
|
import { promisify } from "util";
|
|
8724
8977
|
var exec = promisify(execCallback);
|
|
8978
|
+
var CANONICAL_OPUS_MODEL = "claude-opus-4-7";
|
|
8979
|
+
var CANONICAL_SONNET_MODEL = "claude-sonnet-4-6";
|
|
8980
|
+
var CANONICAL_HAIKU_MODEL = "claude-haiku-4-5";
|
|
8981
|
+
function resolveSdkModelDefaults() {
|
|
8982
|
+
return {
|
|
8983
|
+
ANTHROPIC_DEFAULT_OPUS_MODEL: process.env.MERIDIAN_DEFAULT_OPUS_MODEL ?? CANONICAL_OPUS_MODEL,
|
|
8984
|
+
ANTHROPIC_DEFAULT_SONNET_MODEL: process.env.MERIDIAN_DEFAULT_SONNET_MODEL ?? CANONICAL_SONNET_MODEL,
|
|
8985
|
+
ANTHROPIC_DEFAULT_HAIKU_MODEL: process.env.MERIDIAN_DEFAULT_HAIKU_MODEL ?? CANONICAL_HAIKU_MODEL
|
|
8986
|
+
};
|
|
8987
|
+
}
|
|
8725
8988
|
var AUTH_STATUS_CACHE_TTL_MS = 60000;
|
|
8726
8989
|
var AUTH_STATUS_FAILURE_TTL_MS = 5000;
|
|
8727
8990
|
var cachedAuthStatus = null;
|
|
@@ -8858,16 +9121,14 @@ async function resolveClaudeExecutableAsync() {
|
|
|
8858
9121
|
return cachedClaudePathPromise;
|
|
8859
9122
|
cachedClaudePathPromise = (async () => {
|
|
8860
9123
|
const runningUnderBun = typeof process.versions.bun !== "undefined";
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
} catch {}
|
|
8870
|
-
}
|
|
9124
|
+
try {
|
|
9125
|
+
const pkgPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-code/package.json"));
|
|
9126
|
+
const bundledBinary = join2(dirname2(pkgPath), "bin", "claude.exe");
|
|
9127
|
+
if (existsSync2(bundledBinary)) {
|
|
9128
|
+
cachedClaudePath = bundledBinary;
|
|
9129
|
+
return bundledBinary;
|
|
9130
|
+
}
|
|
9131
|
+
} catch {}
|
|
8871
9132
|
try {
|
|
8872
9133
|
const { stdout } = await exec("which claude");
|
|
8873
9134
|
const claudePath = stdout.trim();
|
|
@@ -8876,7 +9137,7 @@ async function resolveClaudeExecutableAsync() {
|
|
|
8876
9137
|
return claudePath;
|
|
8877
9138
|
}
|
|
8878
9139
|
} catch {}
|
|
8879
|
-
if (
|
|
9140
|
+
if (runningUnderBun) {
|
|
8880
9141
|
try {
|
|
8881
9142
|
const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
|
|
8882
9143
|
const sdkCliJs = join2(dirname2(sdkPath), "cli.js");
|
|
@@ -9089,7 +9350,15 @@ function buildModelList(isMaxSubscription, now = Math.floor(Date.now() / 1000))
|
|
|
9089
9350
|
context_window: isMaxSubscription ? 1e6 : 200000
|
|
9090
9351
|
},
|
|
9091
9352
|
{
|
|
9092
|
-
id: "claude-
|
|
9353
|
+
id: "claude-opus-4-7",
|
|
9354
|
+
object: "model",
|
|
9355
|
+
created: now,
|
|
9356
|
+
owned_by: "anthropic",
|
|
9357
|
+
display_name: "Claude Opus 4.7",
|
|
9358
|
+
context_window: isMaxSubscription ? 1e6 : 200000
|
|
9359
|
+
},
|
|
9360
|
+
{
|
|
9361
|
+
id: "claude-haiku-4-5",
|
|
9093
9362
|
object: "model",
|
|
9094
9363
|
created: now,
|
|
9095
9364
|
owned_by: "anthropic",
|
|
@@ -9129,6 +9398,27 @@ function normalizeContent(content) {
|
|
|
9129
9398
|
}
|
|
9130
9399
|
return String(content);
|
|
9131
9400
|
}
|
|
9401
|
+
function extractAdvisorModel(tools) {
|
|
9402
|
+
if (!Array.isArray(tools))
|
|
9403
|
+
return;
|
|
9404
|
+
for (const tool of tools) {
|
|
9405
|
+
if (!tool || typeof tool !== "object")
|
|
9406
|
+
continue;
|
|
9407
|
+
const candidate = tool;
|
|
9408
|
+
if (typeof candidate.type === "string" && candidate.type.startsWith("advisor_") && typeof candidate.model === "string" && candidate.model.length > 0) {
|
|
9409
|
+
return candidate.model;
|
|
9410
|
+
}
|
|
9411
|
+
}
|
|
9412
|
+
return;
|
|
9413
|
+
}
|
|
9414
|
+
function stripAdvisorTools(tools) {
|
|
9415
|
+
return tools.filter((tool) => {
|
|
9416
|
+
if (!tool || typeof tool !== "object")
|
|
9417
|
+
return true;
|
|
9418
|
+
const candidate = tool;
|
|
9419
|
+
return !(typeof candidate.type === "string" && candidate.type.startsWith("advisor_"));
|
|
9420
|
+
});
|
|
9421
|
+
}
|
|
9132
9422
|
function getLastUserMessage(messages) {
|
|
9133
9423
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
9134
9424
|
if (messages[i]?.role === "user")
|
|
@@ -9365,103 +9655,84 @@ var ALLOWED_MCP_TOOLS = [
|
|
|
9365
9655
|
`mcp__${MCP_SERVER_NAME}__grep`
|
|
9366
9656
|
];
|
|
9367
9657
|
|
|
9368
|
-
// src/proxy/
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9658
|
+
// src/proxy/transforms/opencode.ts
|
|
9659
|
+
var openCodeTransforms = [
|
|
9660
|
+
{
|
|
9661
|
+
name: "opencode-core",
|
|
9662
|
+
adapters: ["opencode"],
|
|
9663
|
+
onRequest(ctx) {
|
|
9664
|
+
const body = ctx.body;
|
|
9665
|
+
const blockedTools = BLOCKED_BUILTIN_TOOLS;
|
|
9666
|
+
const incompatibleTools = CLAUDE_CODE_ONLY_TOOLS;
|
|
9667
|
+
const allowedMcpTools = ALLOWED_MCP_TOOLS;
|
|
9668
|
+
const coreToolNames = ["read", "write", "edit", "bash", "glob", "grep"];
|
|
9669
|
+
const envVal = process.env.MERIDIAN_PASSTHROUGH ?? process.env.CLAUDE_PROXY_PASSTHROUGH;
|
|
9670
|
+
const passthrough = !(envVal === "0" || envVal === "false" || envVal === "no");
|
|
9671
|
+
let sdkAgents = {};
|
|
9672
|
+
if (Array.isArray(body.tools)) {
|
|
9673
|
+
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
9674
|
+
if (taskTool?.description) {
|
|
9675
|
+
sdkAgents = buildAgentDefinitions(taskTool.description, [...allowedMcpTools]);
|
|
9676
|
+
}
|
|
9677
|
+
}
|
|
9678
|
+
let sdkHooks = undefined;
|
|
9679
|
+
const validAgentNames = Object.keys(sdkAgents);
|
|
9680
|
+
if (validAgentNames.length > 0) {
|
|
9681
|
+
sdkHooks = {
|
|
9682
|
+
PreToolUse: [{
|
|
9683
|
+
matcher: "Task",
|
|
9684
|
+
hooks: [async (input) => ({
|
|
9685
|
+
hookSpecificOutput: {
|
|
9686
|
+
hookEventName: "PreToolUse",
|
|
9687
|
+
updatedInput: {
|
|
9688
|
+
...input.tool_input,
|
|
9689
|
+
subagent_type: fuzzyMatchAgentName(String(input.tool_input?.subagent_type || ""), validAgentNames)
|
|
9690
|
+
}
|
|
9691
|
+
}
|
|
9692
|
+
})]
|
|
9693
|
+
}]
|
|
9694
|
+
};
|
|
9695
|
+
}
|
|
9696
|
+
let systemContext = ctx.systemContext;
|
|
9697
|
+
if (validAgentNames.length > 0 && systemContext !== undefined) {
|
|
9698
|
+
systemContext += `
|
|
9398
9699
|
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
};
|
|
9433
|
-
var STRIP_SUFFIXES = ["-agent", "-tool", "-worker", "-task", " agent", " tool"];
|
|
9434
|
-
function fuzzyMatchAgentName(input, validAgents) {
|
|
9435
|
-
if (!input)
|
|
9436
|
-
return input;
|
|
9437
|
-
if (validAgents.length === 0)
|
|
9438
|
-
return input.toLowerCase();
|
|
9439
|
-
const lowered = input.toLowerCase();
|
|
9440
|
-
const exact = validAgents.find((a) => a.toLowerCase() === lowered);
|
|
9441
|
-
if (exact)
|
|
9442
|
-
return exact;
|
|
9443
|
-
const alias = KNOWN_ALIASES[lowered];
|
|
9444
|
-
if (alias && validAgents.includes(alias))
|
|
9445
|
-
return alias;
|
|
9446
|
-
const prefixMatch = validAgents.find((a) => a.toLowerCase().startsWith(lowered));
|
|
9447
|
-
if (prefixMatch)
|
|
9448
|
-
return prefixMatch;
|
|
9449
|
-
const substringMatch = validAgents.find((a) => a.toLowerCase().includes(lowered));
|
|
9450
|
-
if (substringMatch)
|
|
9451
|
-
return substringMatch;
|
|
9452
|
-
for (const suffix of STRIP_SUFFIXES) {
|
|
9453
|
-
if (lowered.endsWith(suffix)) {
|
|
9454
|
-
const stripped = lowered.slice(0, -suffix.length);
|
|
9455
|
-
const strippedMatch = validAgents.find((a) => a.toLowerCase() === stripped);
|
|
9456
|
-
if (strippedMatch)
|
|
9457
|
-
return strippedMatch;
|
|
9700
|
+
IMPORTANT: When using the task/Task tool, the subagent_type parameter must be one of these exact values (case-sensitive, lowercase): ${validAgentNames.join(", ")}. Do NOT capitalize or modify these names.`;
|
|
9701
|
+
} else if (validAgentNames.length > 0) {
|
|
9702
|
+
systemContext = `IMPORTANT: When using the task/Task tool, the subagent_type parameter must be one of these exact values (case-sensitive, lowercase): ${validAgentNames.join(", ")}. Do NOT capitalize or modify these names.`;
|
|
9703
|
+
}
|
|
9704
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
9705
|
+
const input = toolInput;
|
|
9706
|
+
const filePath = input?.filePath ?? input?.file_path ?? input?.path;
|
|
9707
|
+
const lowerName = toolName.toLowerCase();
|
|
9708
|
+
if (lowerName === "write" && filePath) {
|
|
9709
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
9710
|
+
}
|
|
9711
|
+
if ((lowerName === "edit" || lowerName === "multiedit") && filePath) {
|
|
9712
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
9713
|
+
}
|
|
9714
|
+
if (lowerName === "bash" && input?.command) {
|
|
9715
|
+
return extractFileChangesFromBash(String(input.command));
|
|
9716
|
+
}
|
|
9717
|
+
return [];
|
|
9718
|
+
};
|
|
9719
|
+
return {
|
|
9720
|
+
...ctx,
|
|
9721
|
+
blockedTools,
|
|
9722
|
+
incompatibleTools,
|
|
9723
|
+
allowedMcpTools,
|
|
9724
|
+
coreToolNames,
|
|
9725
|
+
passthrough,
|
|
9726
|
+
sdkAgents,
|
|
9727
|
+
sdkHooks,
|
|
9728
|
+
systemContext,
|
|
9729
|
+
supportsThinking: true,
|
|
9730
|
+
shouldTrackFileChanges: false,
|
|
9731
|
+
extractFileChangesFromToolUse
|
|
9732
|
+
};
|
|
9458
9733
|
}
|
|
9459
9734
|
}
|
|
9460
|
-
|
|
9461
|
-
if (reverseMatch)
|
|
9462
|
-
return reverseMatch;
|
|
9463
|
-
return lowered;
|
|
9464
|
-
}
|
|
9735
|
+
];
|
|
9465
9736
|
|
|
9466
9737
|
// src/proxy/adapters/opencode.ts
|
|
9467
9738
|
var openCodeAdapter = {
|
|
@@ -9555,7 +9826,7 @@ IMPORTANT: When using the task/Task tool, the subagent_type parameter must be on
|
|
|
9555
9826
|
}
|
|
9556
9827
|
};
|
|
9557
9828
|
|
|
9558
|
-
// src/proxy/
|
|
9829
|
+
// src/proxy/transforms/droid.ts
|
|
9559
9830
|
var DROID_MCP_SERVER_NAME = "droid";
|
|
9560
9831
|
var DROID_ALLOWED_MCP_TOOLS = [
|
|
9561
9832
|
`mcp__${DROID_MCP_SERVER_NAME}__read`,
|
|
@@ -9565,6 +9836,34 @@ var DROID_ALLOWED_MCP_TOOLS = [
|
|
|
9565
9836
|
`mcp__${DROID_MCP_SERVER_NAME}__glob`,
|
|
9566
9837
|
`mcp__${DROID_MCP_SERVER_NAME}__grep`
|
|
9567
9838
|
];
|
|
9839
|
+
var droidTransforms = [
|
|
9840
|
+
{
|
|
9841
|
+
name: "droid-core",
|
|
9842
|
+
adapters: ["droid"],
|
|
9843
|
+
onRequest(ctx) {
|
|
9844
|
+
return {
|
|
9845
|
+
...ctx,
|
|
9846
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
9847
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
9848
|
+
allowedMcpTools: DROID_ALLOWED_MCP_TOOLS,
|
|
9849
|
+
sdkAgents: {},
|
|
9850
|
+
passthrough: false,
|
|
9851
|
+
leaksCwdViaSystemReminder: true
|
|
9852
|
+
};
|
|
9853
|
+
}
|
|
9854
|
+
}
|
|
9855
|
+
];
|
|
9856
|
+
|
|
9857
|
+
// src/proxy/adapters/droid.ts
|
|
9858
|
+
var DROID_MCP_SERVER_NAME2 = "droid";
|
|
9859
|
+
var DROID_ALLOWED_MCP_TOOLS2 = [
|
|
9860
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__read`,
|
|
9861
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__write`,
|
|
9862
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__edit`,
|
|
9863
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__bash`,
|
|
9864
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__glob`,
|
|
9865
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__grep`
|
|
9866
|
+
];
|
|
9568
9867
|
function extractDroidCwd(body) {
|
|
9569
9868
|
const messages = body.messages;
|
|
9570
9869
|
if (!Array.isArray(messages))
|
|
@@ -9604,10 +9903,10 @@ var droidAdapter = {
|
|
|
9604
9903
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9605
9904
|
},
|
|
9606
9905
|
getMcpServerName() {
|
|
9607
|
-
return
|
|
9906
|
+
return DROID_MCP_SERVER_NAME2;
|
|
9608
9907
|
},
|
|
9609
9908
|
getAllowedMcpTools() {
|
|
9610
|
-
return
|
|
9909
|
+
return DROID_ALLOWED_MCP_TOOLS2;
|
|
9611
9910
|
},
|
|
9612
9911
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9613
9912
|
return {};
|
|
@@ -9623,7 +9922,7 @@ var droidAdapter = {
|
|
|
9623
9922
|
}
|
|
9624
9923
|
};
|
|
9625
9924
|
|
|
9626
|
-
// src/proxy/
|
|
9925
|
+
// src/proxy/transforms/crush.ts
|
|
9627
9926
|
var CRUSH_MCP_SERVER_NAME = "crush";
|
|
9628
9927
|
var CRUSH_ALLOWED_MCP_TOOLS = [
|
|
9629
9928
|
`mcp__${CRUSH_MCP_SERVER_NAME}__read`,
|
|
@@ -9633,6 +9932,45 @@ var CRUSH_ALLOWED_MCP_TOOLS = [
|
|
|
9633
9932
|
`mcp__${CRUSH_MCP_SERVER_NAME}__glob`,
|
|
9634
9933
|
`mcp__${CRUSH_MCP_SERVER_NAME}__grep`
|
|
9635
9934
|
];
|
|
9935
|
+
var crushTransforms = [
|
|
9936
|
+
{
|
|
9937
|
+
name: "crush-core",
|
|
9938
|
+
adapters: ["crush"],
|
|
9939
|
+
onRequest(ctx) {
|
|
9940
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
9941
|
+
const input = toolInput;
|
|
9942
|
+
const filePath = input?.file_path ?? input?.path;
|
|
9943
|
+
if (toolName === "write" && filePath)
|
|
9944
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
9945
|
+
if ((toolName === "edit" || toolName === "patch") && filePath)
|
|
9946
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
9947
|
+
if (toolName === "bash" && input?.command)
|
|
9948
|
+
return extractFileChangesFromBash(String(input.command));
|
|
9949
|
+
return [];
|
|
9950
|
+
};
|
|
9951
|
+
return {
|
|
9952
|
+
...ctx,
|
|
9953
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
9954
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
9955
|
+
allowedMcpTools: CRUSH_ALLOWED_MCP_TOOLS,
|
|
9956
|
+
sdkAgents: {},
|
|
9957
|
+
supportsThinking: true,
|
|
9958
|
+
extractFileChangesFromToolUse
|
|
9959
|
+
};
|
|
9960
|
+
}
|
|
9961
|
+
}
|
|
9962
|
+
];
|
|
9963
|
+
|
|
9964
|
+
// src/proxy/adapters/crush.ts
|
|
9965
|
+
var CRUSH_MCP_SERVER_NAME2 = "crush";
|
|
9966
|
+
var CRUSH_ALLOWED_MCP_TOOLS2 = [
|
|
9967
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__read`,
|
|
9968
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__write`,
|
|
9969
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__edit`,
|
|
9970
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__bash`,
|
|
9971
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__glob`,
|
|
9972
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__grep`
|
|
9973
|
+
];
|
|
9636
9974
|
var crushAdapter = {
|
|
9637
9975
|
name: "crush",
|
|
9638
9976
|
getSessionId(_c) {
|
|
@@ -9651,10 +9989,10 @@ var crushAdapter = {
|
|
|
9651
9989
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9652
9990
|
},
|
|
9653
9991
|
getMcpServerName() {
|
|
9654
|
-
return
|
|
9992
|
+
return CRUSH_MCP_SERVER_NAME2;
|
|
9655
9993
|
},
|
|
9656
9994
|
getAllowedMcpTools() {
|
|
9657
|
-
return
|
|
9995
|
+
return CRUSH_ALLOWED_MCP_TOOLS2;
|
|
9658
9996
|
},
|
|
9659
9997
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9660
9998
|
return {};
|
|
@@ -9684,7 +10022,7 @@ var crushAdapter = {
|
|
|
9684
10022
|
}
|
|
9685
10023
|
};
|
|
9686
10024
|
|
|
9687
|
-
// src/proxy/
|
|
10025
|
+
// src/proxy/transforms/passthrough.ts
|
|
9688
10026
|
var MCP_SERVER_NAME2 = "litellm";
|
|
9689
10027
|
var ALLOWED_MCP_TOOLS2 = [
|
|
9690
10028
|
`mcp__${MCP_SERVER_NAME2}__read`,
|
|
@@ -9694,6 +10032,34 @@ var ALLOWED_MCP_TOOLS2 = [
|
|
|
9694
10032
|
`mcp__${MCP_SERVER_NAME2}__glob`,
|
|
9695
10033
|
`mcp__${MCP_SERVER_NAME2}__grep`
|
|
9696
10034
|
];
|
|
10035
|
+
var passthroughTransforms = [
|
|
10036
|
+
{
|
|
10037
|
+
name: "passthrough-core",
|
|
10038
|
+
adapters: ["passthrough"],
|
|
10039
|
+
onRequest(ctx) {
|
|
10040
|
+
return {
|
|
10041
|
+
...ctx,
|
|
10042
|
+
blockedTools: [],
|
|
10043
|
+
incompatibleTools: [],
|
|
10044
|
+
allowedMcpTools: ALLOWED_MCP_TOOLS2,
|
|
10045
|
+
sdkAgents: {},
|
|
10046
|
+
passthrough: true,
|
|
10047
|
+
prefersStreaming: ctx.body?.stream === true
|
|
10048
|
+
};
|
|
10049
|
+
}
|
|
10050
|
+
}
|
|
10051
|
+
];
|
|
10052
|
+
|
|
10053
|
+
// src/proxy/adapters/passthrough.ts
|
|
10054
|
+
var MCP_SERVER_NAME3 = "litellm";
|
|
10055
|
+
var ALLOWED_MCP_TOOLS3 = [
|
|
10056
|
+
`mcp__${MCP_SERVER_NAME3}__read`,
|
|
10057
|
+
`mcp__${MCP_SERVER_NAME3}__write`,
|
|
10058
|
+
`mcp__${MCP_SERVER_NAME3}__edit`,
|
|
10059
|
+
`mcp__${MCP_SERVER_NAME3}__bash`,
|
|
10060
|
+
`mcp__${MCP_SERVER_NAME3}__glob`,
|
|
10061
|
+
`mcp__${MCP_SERVER_NAME3}__grep`
|
|
10062
|
+
];
|
|
9697
10063
|
function extractCwdFromBody(body) {
|
|
9698
10064
|
if (!body)
|
|
9699
10065
|
return;
|
|
@@ -9741,10 +10107,10 @@ var passthroughAdapter = {
|
|
|
9741
10107
|
return [];
|
|
9742
10108
|
},
|
|
9743
10109
|
getMcpServerName() {
|
|
9744
|
-
return
|
|
10110
|
+
return MCP_SERVER_NAME3;
|
|
9745
10111
|
},
|
|
9746
10112
|
getAllowedMcpTools() {
|
|
9747
|
-
return
|
|
10113
|
+
return ALLOWED_MCP_TOOLS3;
|
|
9748
10114
|
},
|
|
9749
10115
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9750
10116
|
return {};
|
|
@@ -9763,7 +10129,7 @@ var passthroughAdapter = {
|
|
|
9763
10129
|
}
|
|
9764
10130
|
};
|
|
9765
10131
|
|
|
9766
|
-
// src/proxy/
|
|
10132
|
+
// src/proxy/transforms/pi.ts
|
|
9767
10133
|
var PI_MCP_SERVER_NAME = "pi";
|
|
9768
10134
|
var PI_ALLOWED_MCP_TOOLS = [
|
|
9769
10135
|
`mcp__${PI_MCP_SERVER_NAME}__read`,
|
|
@@ -9773,6 +10139,45 @@ var PI_ALLOWED_MCP_TOOLS = [
|
|
|
9773
10139
|
`mcp__${PI_MCP_SERVER_NAME}__glob`,
|
|
9774
10140
|
`mcp__${PI_MCP_SERVER_NAME}__grep`
|
|
9775
10141
|
];
|
|
10142
|
+
var piTransforms = [
|
|
10143
|
+
{
|
|
10144
|
+
name: "pi-core",
|
|
10145
|
+
adapters: ["pi"],
|
|
10146
|
+
onRequest(ctx) {
|
|
10147
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
10148
|
+
const input = toolInput;
|
|
10149
|
+
const filePath = input?.filePath ?? input?.file_path ?? input?.path;
|
|
10150
|
+
if (toolName === "write" && filePath)
|
|
10151
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
10152
|
+
if (toolName === "edit" && filePath)
|
|
10153
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
10154
|
+
if (toolName === "bash" && input?.command)
|
|
10155
|
+
return extractFileChangesFromBash(String(input.command));
|
|
10156
|
+
return [];
|
|
10157
|
+
};
|
|
10158
|
+
return {
|
|
10159
|
+
...ctx,
|
|
10160
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
10161
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
10162
|
+
allowedMcpTools: PI_ALLOWED_MCP_TOOLS,
|
|
10163
|
+
sdkAgents: {},
|
|
10164
|
+
supportsThinking: true,
|
|
10165
|
+
extractFileChangesFromToolUse
|
|
10166
|
+
};
|
|
10167
|
+
}
|
|
10168
|
+
}
|
|
10169
|
+
];
|
|
10170
|
+
|
|
10171
|
+
// src/proxy/adapters/pi.ts
|
|
10172
|
+
var PI_MCP_SERVER_NAME2 = "pi";
|
|
10173
|
+
var PI_ALLOWED_MCP_TOOLS2 = [
|
|
10174
|
+
`mcp__${PI_MCP_SERVER_NAME2}__read`,
|
|
10175
|
+
`mcp__${PI_MCP_SERVER_NAME2}__write`,
|
|
10176
|
+
`mcp__${PI_MCP_SERVER_NAME2}__edit`,
|
|
10177
|
+
`mcp__${PI_MCP_SERVER_NAME2}__bash`,
|
|
10178
|
+
`mcp__${PI_MCP_SERVER_NAME2}__glob`,
|
|
10179
|
+
`mcp__${PI_MCP_SERVER_NAME2}__grep`
|
|
10180
|
+
];
|
|
9776
10181
|
function extractPiCwd(body) {
|
|
9777
10182
|
let systemText = "";
|
|
9778
10183
|
if (typeof body.system === "string") {
|
|
@@ -9794,6 +10199,9 @@ var piAdapter = {
|
|
|
9794
10199
|
extractWorkingDirectory(body) {
|
|
9795
10200
|
return extractPiCwd(body);
|
|
9796
10201
|
},
|
|
10202
|
+
extractClientWorkingDirectory(body) {
|
|
10203
|
+
return extractPiCwd(body);
|
|
10204
|
+
},
|
|
9797
10205
|
normalizeContent(content) {
|
|
9798
10206
|
return normalizeContent(content);
|
|
9799
10207
|
},
|
|
@@ -9804,10 +10212,10 @@ var piAdapter = {
|
|
|
9804
10212
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9805
10213
|
},
|
|
9806
10214
|
getMcpServerName() {
|
|
9807
|
-
return
|
|
10215
|
+
return PI_MCP_SERVER_NAME2;
|
|
9808
10216
|
},
|
|
9809
10217
|
getAllowedMcpTools() {
|
|
9810
|
-
return
|
|
10218
|
+
return PI_ALLOWED_MCP_TOOLS2;
|
|
9811
10219
|
},
|
|
9812
10220
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9813
10221
|
return {};
|
|
@@ -9837,7 +10245,7 @@ var piAdapter = {
|
|
|
9837
10245
|
}
|
|
9838
10246
|
};
|
|
9839
10247
|
|
|
9840
|
-
// src/proxy/
|
|
10248
|
+
// src/proxy/transforms/forgecode.ts
|
|
9841
10249
|
var FORGECODE_MCP_SERVER_NAME = "forgecode";
|
|
9842
10250
|
var FORGECODE_ALLOWED_MCP_TOOLS = [
|
|
9843
10251
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__read`,
|
|
@@ -9847,6 +10255,44 @@ var FORGECODE_ALLOWED_MCP_TOOLS = [
|
|
|
9847
10255
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__glob`,
|
|
9848
10256
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__grep`
|
|
9849
10257
|
];
|
|
10258
|
+
var forgeCodeTransforms = [
|
|
10259
|
+
{
|
|
10260
|
+
name: "forgecode-core",
|
|
10261
|
+
adapters: ["forgecode"],
|
|
10262
|
+
onRequest(ctx) {
|
|
10263
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
10264
|
+
const input = toolInput;
|
|
10265
|
+
const filePath = input?.file_path ?? input?.filePath ?? input?.path;
|
|
10266
|
+
if (toolName === "write" && filePath)
|
|
10267
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
10268
|
+
if ((toolName === "patch" || toolName === "multi_patch") && filePath)
|
|
10269
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
10270
|
+
if (toolName === "shell" && input?.command)
|
|
10271
|
+
return extractFileChangesFromBash(String(input.command));
|
|
10272
|
+
return [];
|
|
10273
|
+
};
|
|
10274
|
+
return {
|
|
10275
|
+
...ctx,
|
|
10276
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
10277
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
10278
|
+
allowedMcpTools: FORGECODE_ALLOWED_MCP_TOOLS,
|
|
10279
|
+
sdkAgents: {},
|
|
10280
|
+
extractFileChangesFromToolUse
|
|
10281
|
+
};
|
|
10282
|
+
}
|
|
10283
|
+
}
|
|
10284
|
+
];
|
|
10285
|
+
|
|
10286
|
+
// src/proxy/adapters/forgecode.ts
|
|
10287
|
+
var FORGECODE_MCP_SERVER_NAME2 = "forgecode";
|
|
10288
|
+
var FORGECODE_ALLOWED_MCP_TOOLS2 = [
|
|
10289
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__read`,
|
|
10290
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__write`,
|
|
10291
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__edit`,
|
|
10292
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__bash`,
|
|
10293
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__glob`,
|
|
10294
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__grep`
|
|
10295
|
+
];
|
|
9850
10296
|
function extractForgeCodeCwd(body) {
|
|
9851
10297
|
let systemText = "";
|
|
9852
10298
|
if (typeof body.system === "string") {
|
|
@@ -9878,10 +10324,10 @@ var forgeCodeAdapter = {
|
|
|
9878
10324
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9879
10325
|
},
|
|
9880
10326
|
getMcpServerName() {
|
|
9881
|
-
return
|
|
10327
|
+
return FORGECODE_MCP_SERVER_NAME2;
|
|
9882
10328
|
},
|
|
9883
10329
|
getAllowedMcpTools() {
|
|
9884
|
-
return
|
|
10330
|
+
return FORGECODE_ALLOWED_MCP_TOOLS2;
|
|
9885
10331
|
},
|
|
9886
10332
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9887
10333
|
return {};
|
|
@@ -9908,6 +10354,79 @@ var forgeCodeAdapter = {
|
|
|
9908
10354
|
}
|
|
9909
10355
|
};
|
|
9910
10356
|
|
|
10357
|
+
// src/proxy/adapters/claudecode.ts
|
|
10358
|
+
function extractClaudeCodeClientCwd(body) {
|
|
10359
|
+
let systemText = "";
|
|
10360
|
+
if (typeof body.system === "string") {
|
|
10361
|
+
systemText = body.system;
|
|
10362
|
+
} else if (Array.isArray(body.system)) {
|
|
10363
|
+
systemText = body.system.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(`
|
|
10364
|
+
`);
|
|
10365
|
+
}
|
|
10366
|
+
if (!systemText)
|
|
10367
|
+
return;
|
|
10368
|
+
const match2 = systemText.match(/Primary working directory:\s*([^\n<]+)/i);
|
|
10369
|
+
return match2?.[1]?.trim() || undefined;
|
|
10370
|
+
}
|
|
10371
|
+
var claudeCodeAdapter = {
|
|
10372
|
+
name: "claude-code",
|
|
10373
|
+
getSessionId(_c) {
|
|
10374
|
+
return;
|
|
10375
|
+
},
|
|
10376
|
+
extractWorkingDirectory(_body) {
|
|
10377
|
+
return;
|
|
10378
|
+
},
|
|
10379
|
+
extractClientWorkingDirectory(body) {
|
|
10380
|
+
return extractClaudeCodeClientCwd(body);
|
|
10381
|
+
},
|
|
10382
|
+
normalizeContent(content) {
|
|
10383
|
+
return normalizeContent(content);
|
|
10384
|
+
},
|
|
10385
|
+
getBlockedBuiltinTools() {
|
|
10386
|
+
return BLOCKED_BUILTIN_TOOLS;
|
|
10387
|
+
},
|
|
10388
|
+
getAgentIncompatibleTools() {
|
|
10389
|
+
return CLAUDE_CODE_ONLY_TOOLS;
|
|
10390
|
+
},
|
|
10391
|
+
getMcpServerName() {
|
|
10392
|
+
return MCP_SERVER_NAME;
|
|
10393
|
+
},
|
|
10394
|
+
getAllowedMcpTools() {
|
|
10395
|
+
return ALLOWED_MCP_TOOLS;
|
|
10396
|
+
},
|
|
10397
|
+
getCoreToolNames() {
|
|
10398
|
+
return ["Read", "Write", "Edit", "Bash", "Glob", "Grep"];
|
|
10399
|
+
},
|
|
10400
|
+
usesPassthrough() {
|
|
10401
|
+
const envVal = process.env.MERIDIAN_PASSTHROUGH ?? process.env.CLAUDE_PROXY_PASSTHROUGH;
|
|
10402
|
+
if (envVal === "0" || envVal === "false" || envVal === "no") {
|
|
10403
|
+
return false;
|
|
10404
|
+
}
|
|
10405
|
+
return true;
|
|
10406
|
+
},
|
|
10407
|
+
supportsThinking() {
|
|
10408
|
+
return true;
|
|
10409
|
+
},
|
|
10410
|
+
shouldTrackFileChanges() {
|
|
10411
|
+
return false;
|
|
10412
|
+
},
|
|
10413
|
+
extractFileChangesFromToolUse(toolName, toolInput) {
|
|
10414
|
+
const input = toolInput;
|
|
10415
|
+
const filePath = input?.file_path ?? input?.filePath ?? input?.path;
|
|
10416
|
+
const lowerName = toolName.toLowerCase();
|
|
10417
|
+
if (lowerName === "write" && filePath) {
|
|
10418
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
10419
|
+
}
|
|
10420
|
+
if ((lowerName === "edit" || lowerName === "multiedit") && filePath) {
|
|
10421
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
10422
|
+
}
|
|
10423
|
+
if (lowerName === "bash" && input?.command) {
|
|
10424
|
+
return extractFileChangesFromBash(String(input.command));
|
|
10425
|
+
}
|
|
10426
|
+
return [];
|
|
10427
|
+
}
|
|
10428
|
+
};
|
|
10429
|
+
|
|
9911
10430
|
// src/proxy/adapters/detect.ts
|
|
9912
10431
|
var ADAPTER_MAP = {
|
|
9913
10432
|
opencode: openCodeAdapter,
|
|
@@ -9915,7 +10434,9 @@ var ADAPTER_MAP = {
|
|
|
9915
10434
|
crush: crushAdapter,
|
|
9916
10435
|
passthrough: passthroughAdapter,
|
|
9917
10436
|
pi: piAdapter,
|
|
9918
|
-
forgecode: forgeCodeAdapter
|
|
10437
|
+
forgecode: forgeCodeAdapter,
|
|
10438
|
+
"claude-code": claudeCodeAdapter,
|
|
10439
|
+
claudecode: claudeCodeAdapter
|
|
9919
10440
|
};
|
|
9920
10441
|
var envDefault = process.env.MERIDIAN_DEFAULT_AGENT || "";
|
|
9921
10442
|
if (envDefault && !ADAPTER_MAP[envDefault]) {
|
|
@@ -9946,6 +10467,9 @@ function detectAdapter(c) {
|
|
|
9946
10467
|
if (userAgent.startsWith("Charm-Crush/")) {
|
|
9947
10468
|
return crushAdapter;
|
|
9948
10469
|
}
|
|
10470
|
+
if (userAgent.startsWith("claude-cli/")) {
|
|
10471
|
+
return claudeCodeAdapter;
|
|
10472
|
+
}
|
|
9949
10473
|
if (isLiteLLMRequest(c)) {
|
|
9950
10474
|
return passthroughAdapter;
|
|
9951
10475
|
}
|
|
@@ -15648,16 +16172,35 @@ function createOpencodeMcpServer() {
|
|
|
15648
16172
|
}
|
|
15649
16173
|
|
|
15650
16174
|
// src/proxy/query.ts
|
|
15651
|
-
function
|
|
16175
|
+
function computePassthroughMaxTurns(resumeSessionId, hasDeferredTools, advisorModel) {
|
|
16176
|
+
const hasResume = !!resumeSessionId;
|
|
16177
|
+
const base = hasResume && hasDeferredTools ? 4 : hasResume || hasDeferredTools ? 3 : 2;
|
|
16178
|
+
const advisorBump = advisorModel ? 3 : 0;
|
|
16179
|
+
return base + advisorBump;
|
|
16180
|
+
}
|
|
16181
|
+
function buildCwdNote(sdkCwd, clientCwd) {
|
|
16182
|
+
if (!clientCwd || clientCwd === sdkCwd)
|
|
16183
|
+
return "";
|
|
16184
|
+
return `
|
|
16185
|
+
|
|
16186
|
+
<env>
|
|
16187
|
+
` + `Working directory: ${clientCwd}
|
|
16188
|
+
` + `</env>
|
|
16189
|
+
` + `<meridian-note>
|
|
16190
|
+
` + `You are reached through a proxy. The subprocess running you resides at ` + `"${sdkCwd}" on the proxy host, but that is not the user's working directory. ` + `Always treat "${clientCwd}" as the working directory when referring to files or paths.
|
|
16191
|
+
` + `</meridian-note>`;
|
|
16192
|
+
}
|
|
16193
|
+
function resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt, cwdNote) {
|
|
15652
16194
|
const hasSettings = settingSources != null && settingSources.length > 0;
|
|
15653
16195
|
const usePreset = codeSystemPrompt ?? (hasSettings || !passthrough && !!systemContext);
|
|
15654
16196
|
const includeClient = clientSystemPrompt ?? true;
|
|
15655
16197
|
const clientContext = includeClient ? systemContext : undefined;
|
|
16198
|
+
const append = [clientContext, cwdNote].filter(Boolean).join("") || undefined;
|
|
15656
16199
|
if (usePreset) {
|
|
15657
|
-
return
|
|
16200
|
+
return append ? { systemPrompt: { type: "preset", preset: "claude_code", append } } : { systemPrompt: { type: "preset", preset: "claude_code" } };
|
|
15658
16201
|
}
|
|
15659
|
-
if (
|
|
15660
|
-
return { systemPrompt:
|
|
16202
|
+
if (append)
|
|
16203
|
+
return { systemPrompt: append };
|
|
15661
16204
|
return {};
|
|
15662
16205
|
}
|
|
15663
16206
|
function buildQueryOptions(ctx) {
|
|
@@ -15665,6 +16208,7 @@ function buildQueryOptions(ctx) {
|
|
|
15665
16208
|
prompt,
|
|
15666
16209
|
model,
|
|
15667
16210
|
workingDirectory,
|
|
16211
|
+
clientWorkingDirectory,
|
|
15668
16212
|
systemContext,
|
|
15669
16213
|
claudeExecutable,
|
|
15670
16214
|
passthrough,
|
|
@@ -15677,7 +16221,10 @@ function buildQueryOptions(ctx) {
|
|
|
15677
16221
|
isUndo,
|
|
15678
16222
|
undoRollbackUuid,
|
|
15679
16223
|
sdkHooks,
|
|
15680
|
-
|
|
16224
|
+
blockedTools,
|
|
16225
|
+
incompatibleTools,
|
|
16226
|
+
mcpServerName,
|
|
16227
|
+
allowedMcpTools,
|
|
15681
16228
|
onStderr,
|
|
15682
16229
|
effort,
|
|
15683
16230
|
thinking,
|
|
@@ -15694,30 +16241,29 @@ function buildQueryOptions(ctx) {
|
|
|
15694
16241
|
sdkDebug,
|
|
15695
16242
|
additionalDirectories
|
|
15696
16243
|
} = ctx;
|
|
15697
|
-
const
|
|
15698
|
-
const
|
|
15699
|
-
const allowedMcpTools = [...adapter.getAllowedMcpTools()];
|
|
16244
|
+
const cwdNote = buildCwdNote(workingDirectory, clientWorkingDirectory);
|
|
16245
|
+
const allBlockedTools = [...blockedTools, ...incompatibleTools];
|
|
15700
16246
|
return {
|
|
15701
16247
|
prompt,
|
|
15702
16248
|
options: {
|
|
15703
16249
|
executable: "node",
|
|
15704
|
-
maxTurns: passthrough ? resumeSessionId
|
|
16250
|
+
maxTurns: passthrough ? computePassthroughMaxTurns(resumeSessionId, hasDeferredTools, ctx.advisorModel) : 200,
|
|
15705
16251
|
cwd: workingDirectory,
|
|
15706
16252
|
model,
|
|
15707
16253
|
pathToClaudeCodeExecutable: claudeExecutable,
|
|
15708
16254
|
...stream2 ? { includePartialMessages: true } : {},
|
|
15709
16255
|
permissionMode: "bypassPermissions",
|
|
15710
16256
|
allowDangerouslySkipPermissions: true,
|
|
15711
|
-
...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt),
|
|
16257
|
+
...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt, cwdNote),
|
|
15712
16258
|
...passthrough ? {
|
|
15713
|
-
disallowedTools:
|
|
16259
|
+
disallowedTools: [...allBlockedTools],
|
|
15714
16260
|
...passthroughMcp ? {
|
|
15715
|
-
allowedTools: passthroughMcp.toolNames,
|
|
16261
|
+
allowedTools: [...passthroughMcp.toolNames],
|
|
15716
16262
|
mcpServers: { [PASSTHROUGH_MCP_NAME]: passthroughMcp.server }
|
|
15717
16263
|
} : {}
|
|
15718
16264
|
} : {
|
|
15719
|
-
disallowedTools:
|
|
15720
|
-
allowedTools: allowedMcpTools,
|
|
16265
|
+
disallowedTools: [...allBlockedTools],
|
|
16266
|
+
allowedTools: [...allowedMcpTools],
|
|
15721
16267
|
mcpServers: { [mcpServerName]: createOpencodeMcpServer() }
|
|
15722
16268
|
},
|
|
15723
16269
|
plugins: [],
|
|
@@ -15747,11 +16293,182 @@ function buildQueryOptions(ctx) {
|
|
|
15747
16293
|
...maxBudgetUsd && maxBudgetUsd > 0 ? { maxBudgetUsd } : {},
|
|
15748
16294
|
...fallbackModel ? { fallbackModel } : {},
|
|
15749
16295
|
...sdkDebug ? { debug: true } : {},
|
|
15750
|
-
...additionalDirectories && additionalDirectories.length > 0 ? { additionalDirectories } : {}
|
|
16296
|
+
...additionalDirectories && additionalDirectories.length > 0 ? { additionalDirectories } : {},
|
|
16297
|
+
...ctx.advisorModel ? { advisorModel: ctx.advisorModel } : {}
|
|
16298
|
+
}
|
|
16299
|
+
};
|
|
16300
|
+
}
|
|
16301
|
+
|
|
16302
|
+
// src/proxy/transforms/registry.ts
|
|
16303
|
+
var ADAPTER_TRANSFORMS = {
|
|
16304
|
+
opencode: openCodeTransforms,
|
|
16305
|
+
crush: crushTransforms,
|
|
16306
|
+
droid: droidTransforms,
|
|
16307
|
+
pi: piTransforms,
|
|
16308
|
+
forgecode: forgeCodeTransforms,
|
|
16309
|
+
passthrough: passthroughTransforms
|
|
16310
|
+
};
|
|
16311
|
+
function getAdapterTransforms(adapterName) {
|
|
16312
|
+
return ADAPTER_TRANSFORMS[adapterName] ?? [];
|
|
16313
|
+
}
|
|
16314
|
+
|
|
16315
|
+
// src/proxy/plugins/loader.ts
|
|
16316
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
16317
|
+
import { join as join4, isAbsolute as isAbsolute2, extname } from "path";
|
|
16318
|
+
|
|
16319
|
+
// src/proxy/plugins/validation.ts
|
|
16320
|
+
var KNOWN_ADAPTERS = ["opencode", "crush", "droid", "pi", "forgecode", "passthrough"];
|
|
16321
|
+
var KNOWN_HOOKS = ["onRequest", "onResponse", "onTelemetry", "onSession", "onToolUse", "onToolResult", "onError"];
|
|
16322
|
+
function validateTransform(exported) {
|
|
16323
|
+
if (exported == null || typeof exported !== "object") {
|
|
16324
|
+
return { valid: false, hooks: [], error: "Plugin must export an object" };
|
|
16325
|
+
}
|
|
16326
|
+
const obj = exported;
|
|
16327
|
+
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
16328
|
+
return { valid: false, hooks: [], error: "Plugin must have a name: string property" };
|
|
16329
|
+
}
|
|
16330
|
+
const hooks = [];
|
|
16331
|
+
for (const hook of KNOWN_HOOKS) {
|
|
16332
|
+
if (obj[hook] !== undefined) {
|
|
16333
|
+
if (typeof obj[hook] !== "function") {
|
|
16334
|
+
return { valid: false, hooks: [], error: `${hook} must be a function, got ${typeof obj[hook]}` };
|
|
16335
|
+
}
|
|
16336
|
+
hooks.push(hook);
|
|
16337
|
+
}
|
|
16338
|
+
}
|
|
16339
|
+
const warnings = [];
|
|
16340
|
+
if (Array.isArray(obj.adapters)) {
|
|
16341
|
+
for (const adapter of obj.adapters) {
|
|
16342
|
+
if (typeof adapter === "string" && !KNOWN_ADAPTERS.includes(adapter)) {
|
|
16343
|
+
warnings.push(adapter);
|
|
16344
|
+
}
|
|
15751
16345
|
}
|
|
16346
|
+
}
|
|
16347
|
+
return {
|
|
16348
|
+
valid: true,
|
|
16349
|
+
hooks,
|
|
16350
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
15752
16351
|
};
|
|
15753
16352
|
}
|
|
15754
16353
|
|
|
16354
|
+
// src/proxy/plugins/loader.ts
|
|
16355
|
+
var loadCounter = 0;
|
|
16356
|
+
function parsePluginConfig(configPath) {
|
|
16357
|
+
if (!existsSync3(configPath))
|
|
16358
|
+
return [];
|
|
16359
|
+
try {
|
|
16360
|
+
const raw2 = readFileSync2(configPath, "utf-8");
|
|
16361
|
+
const parsed = JSON.parse(raw2);
|
|
16362
|
+
return Array.isArray(parsed.plugins) ? parsed.plugins : [];
|
|
16363
|
+
} catch {
|
|
16364
|
+
return [];
|
|
16365
|
+
}
|
|
16366
|
+
}
|
|
16367
|
+
async function loadPlugins(pluginDir, configPath) {
|
|
16368
|
+
resetAllPluginStats();
|
|
16369
|
+
const config = configPath ? parsePluginConfig(configPath) : [];
|
|
16370
|
+
const pluginDirExists = existsSync3(pluginDir);
|
|
16371
|
+
let filenames = [];
|
|
16372
|
+
if (pluginDirExists) {
|
|
16373
|
+
try {
|
|
16374
|
+
filenames = readdirSync2(pluginDir).filter((f) => {
|
|
16375
|
+
const ext2 = extname(f);
|
|
16376
|
+
return ext2 === ".ts" || ext2 === ".js";
|
|
16377
|
+
});
|
|
16378
|
+
} catch {
|
|
16379
|
+
filenames = [];
|
|
16380
|
+
}
|
|
16381
|
+
}
|
|
16382
|
+
if (!pluginDirExists && config.length === 0)
|
|
16383
|
+
return [];
|
|
16384
|
+
const ordered = [];
|
|
16385
|
+
const seen = new Set;
|
|
16386
|
+
for (const entry of config) {
|
|
16387
|
+
const filename = isAbsolute2(entry.path) ? entry.path : entry.path;
|
|
16388
|
+
if (filenames.includes(filename) || isAbsolute2(entry.path)) {
|
|
16389
|
+
ordered.push({ filename, entry });
|
|
16390
|
+
seen.add(filename);
|
|
16391
|
+
}
|
|
16392
|
+
}
|
|
16393
|
+
for (const filename of filenames) {
|
|
16394
|
+
if (!seen.has(filename)) {
|
|
16395
|
+
ordered.push({ filename });
|
|
16396
|
+
}
|
|
16397
|
+
}
|
|
16398
|
+
const loaded = [];
|
|
16399
|
+
const seenNames = new Set;
|
|
16400
|
+
for (const { filename, entry } of ordered) {
|
|
16401
|
+
const filePath = isAbsolute2(filename) ? filename : join4(pluginDir, filename);
|
|
16402
|
+
if (entry && !entry.enabled) {
|
|
16403
|
+
loaded.push({
|
|
16404
|
+
name: filename,
|
|
16405
|
+
status: "disabled",
|
|
16406
|
+
hooks: [],
|
|
16407
|
+
path: filePath,
|
|
16408
|
+
transform: { name: filename }
|
|
16409
|
+
});
|
|
16410
|
+
continue;
|
|
16411
|
+
}
|
|
16412
|
+
try {
|
|
16413
|
+
const cacheBuster = `?t=${Date.now()}-${++loadCounter}`;
|
|
16414
|
+
const mod = await import(filePath + cacheBuster);
|
|
16415
|
+
const exported = mod.default ?? mod;
|
|
16416
|
+
const transforms = Array.isArray(exported) ? exported : [exported];
|
|
16417
|
+
for (const item of transforms) {
|
|
16418
|
+
const validation = validateTransform(item);
|
|
16419
|
+
if (!validation.valid) {
|
|
16420
|
+
loaded.push({
|
|
16421
|
+
name: filename,
|
|
16422
|
+
status: "error",
|
|
16423
|
+
error: validation.error,
|
|
16424
|
+
hooks: [],
|
|
16425
|
+
path: filePath,
|
|
16426
|
+
transform: { name: filename }
|
|
16427
|
+
});
|
|
16428
|
+
continue;
|
|
16429
|
+
}
|
|
16430
|
+
const transform = item;
|
|
16431
|
+
if (seenNames.has(transform.name)) {
|
|
16432
|
+
loaded.push({
|
|
16433
|
+
name: transform.name,
|
|
16434
|
+
status: "error",
|
|
16435
|
+
error: `Skipped: duplicate plugin name "${transform.name}"`,
|
|
16436
|
+
hooks: validation.hooks,
|
|
16437
|
+
path: filePath,
|
|
16438
|
+
transform
|
|
16439
|
+
});
|
|
16440
|
+
continue;
|
|
16441
|
+
}
|
|
16442
|
+
seenNames.add(transform.name);
|
|
16443
|
+
registerPluginStats(transform.name);
|
|
16444
|
+
loaded.push({
|
|
16445
|
+
name: transform.name,
|
|
16446
|
+
description: transform.description,
|
|
16447
|
+
version: transform.version,
|
|
16448
|
+
adapters: transform.adapters,
|
|
16449
|
+
hooks: validation.hooks,
|
|
16450
|
+
status: "active",
|
|
16451
|
+
path: filePath,
|
|
16452
|
+
transform
|
|
16453
|
+
});
|
|
16454
|
+
}
|
|
16455
|
+
} catch (err) {
|
|
16456
|
+
loaded.push({
|
|
16457
|
+
name: filename,
|
|
16458
|
+
status: "error",
|
|
16459
|
+
error: `Failed to load: ${err instanceof Error ? err.message : String(err)}`,
|
|
16460
|
+
hooks: [],
|
|
16461
|
+
path: filePath,
|
|
16462
|
+
transform: { name: filename }
|
|
16463
|
+
});
|
|
16464
|
+
}
|
|
16465
|
+
}
|
|
16466
|
+
return loaded;
|
|
16467
|
+
}
|
|
16468
|
+
function getActiveTransforms(plugins) {
|
|
16469
|
+
return plugins.filter((p) => p.status === "active").map((p) => p.transform);
|
|
16470
|
+
}
|
|
16471
|
+
|
|
15755
16472
|
// src/proxy/betas.ts
|
|
15756
16473
|
var BILLABLE_BETA_PREFIXES_ON_MAX = [
|
|
15757
16474
|
"extended-cache-ttl-"
|
|
@@ -15917,6 +16634,10 @@ function sanitizeTextContent(text, opts = {}) {
|
|
|
15917
16634
|
|
|
15918
16635
|
// src/proxy/session/lineage.ts
|
|
15919
16636
|
import { createHash as createHash2 } from "crypto";
|
|
16637
|
+
function normalizeContextUsage(usage) {
|
|
16638
|
+
const lastIteration = usage.iterations?.at(-1);
|
|
16639
|
+
return lastIteration ?? usage;
|
|
16640
|
+
}
|
|
15920
16641
|
var MIN_SUFFIX_FOR_COMPACTION = 2;
|
|
15921
16642
|
function computeLineageHash(messages) {
|
|
15922
16643
|
if (!messages || messages.length === 0)
|
|
@@ -16048,17 +16769,17 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
|
|
|
16048
16769
|
// src/proxy/sessionStore.ts
|
|
16049
16770
|
import {
|
|
16050
16771
|
closeSync,
|
|
16051
|
-
existsSync as
|
|
16772
|
+
existsSync as existsSync4,
|
|
16052
16773
|
mkdirSync,
|
|
16053
16774
|
openSync,
|
|
16054
|
-
readFileSync as
|
|
16775
|
+
readFileSync as readFileSync3,
|
|
16055
16776
|
renameSync,
|
|
16056
16777
|
statSync,
|
|
16057
16778
|
unlinkSync,
|
|
16058
16779
|
writeFileSync
|
|
16059
16780
|
} from "node:fs";
|
|
16060
16781
|
import { homedir as homedir3 } from "node:os";
|
|
16061
|
-
import { join as
|
|
16782
|
+
import { join as join5 } from "node:path";
|
|
16062
16783
|
var DEFAULT_MAX_STORED_SESSIONS = 1e4;
|
|
16063
16784
|
var STALE_LOCK_THRESHOLD_MS = 30000;
|
|
16064
16785
|
function getMaxStoredSessions() {
|
|
@@ -16106,17 +16827,17 @@ var sessionDirOverride = null;
|
|
|
16106
16827
|
var skipLocking = false;
|
|
16107
16828
|
function getStorePath() {
|
|
16108
16829
|
const dir = sessionDirOverride || process.env.MERIDIAN_SESSION_DIR || process.env.CLAUDE_PROXY_SESSION_DIR || getDefaultCacheDir();
|
|
16109
|
-
if (!
|
|
16830
|
+
if (!existsSync4(dir)) {
|
|
16110
16831
|
mkdirSync(dir, { recursive: true });
|
|
16111
16832
|
}
|
|
16112
|
-
return
|
|
16833
|
+
return join5(dir, "sessions.json");
|
|
16113
16834
|
}
|
|
16114
16835
|
function getDefaultCacheDir() {
|
|
16115
|
-
const newDir =
|
|
16116
|
-
const oldDir =
|
|
16117
|
-
if (
|
|
16836
|
+
const newDir = join5(homedir3(), ".cache", "meridian");
|
|
16837
|
+
const oldDir = join5(homedir3(), ".cache", "opencode-claude-max-proxy");
|
|
16838
|
+
if (existsSync4(newDir))
|
|
16118
16839
|
return newDir;
|
|
16119
|
-
if (
|
|
16840
|
+
if (existsSync4(oldDir)) {
|
|
16120
16841
|
try {
|
|
16121
16842
|
const { symlinkSync } = __require("fs");
|
|
16122
16843
|
symlinkSync(oldDir, newDir);
|
|
@@ -16129,10 +16850,10 @@ function getDefaultCacheDir() {
|
|
|
16129
16850
|
}
|
|
16130
16851
|
function readStore() {
|
|
16131
16852
|
const path3 = getStorePath();
|
|
16132
|
-
if (!
|
|
16853
|
+
if (!existsSync4(path3))
|
|
16133
16854
|
return {};
|
|
16134
16855
|
try {
|
|
16135
|
-
const data =
|
|
16856
|
+
const data = readFileSync3(path3, "utf-8");
|
|
16136
16857
|
return JSON.parse(data);
|
|
16137
16858
|
} catch (e) {
|
|
16138
16859
|
console.error("[sessionStore] read failed:", e.message);
|
|
@@ -16631,6 +17352,10 @@ function createProxyServer(config = {}) {
|
|
|
16631
17352
|
const sessionDiscoveredTools = new Map;
|
|
16632
17353
|
const sessionToolCache = new Map;
|
|
16633
17354
|
const sessionMcpCache = new LRUMap(getMaxSessionsLimit());
|
|
17355
|
+
const pluginDir = finalConfig.pluginDir ?? join7(homedir5(), ".config", "meridian", "plugins");
|
|
17356
|
+
const pluginConfigPath = finalConfig.pluginConfigPath ?? join7(homedir5(), ".config", "meridian", "plugins.json");
|
|
17357
|
+
let loadedPlugins = [];
|
|
17358
|
+
let pluginTransforms = [];
|
|
16634
17359
|
const app = new Hono2;
|
|
16635
17360
|
app.use("*", cors());
|
|
16636
17361
|
app.use("/v1/*", requireAuth);
|
|
@@ -16640,6 +17365,8 @@ function createProxyServer(config = {}) {
|
|
|
16640
17365
|
app.use("/metrics", requireAuth);
|
|
16641
17366
|
app.use("/profiles/*", requireAuth);
|
|
16642
17367
|
app.use("/profiles", requireAuth);
|
|
17368
|
+
app.use("/plugins/*", requireAuth);
|
|
17369
|
+
app.use("/plugins", requireAuth);
|
|
16643
17370
|
app.use("/auth/*", requireAuth);
|
|
16644
17371
|
app.get("/", (c) => {
|
|
16645
17372
|
const accept = c.req.header("accept") || "";
|
|
@@ -16697,9 +17424,8 @@ function createProxyServer(config = {}) {
|
|
|
16697
17424
|
const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
|
|
16698
17425
|
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
16699
17426
|
let model = mapModelToClaudeModel(body.model || "sonnet", authStatus?.subscriptionType, agentMode);
|
|
16700
|
-
const adapterStreamPref = adapter.prefersStreaming?.(body);
|
|
16701
|
-
const stream2 = adapterStreamPref !== undefined ? adapterStreamPref : body.stream ?? false;
|
|
16702
17427
|
const workingDirectory = (process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR) || adapter.extractWorkingDirectory(body) || process.cwd();
|
|
17428
|
+
const clientWorkingDirectory = adapter.extractClientWorkingDirectory?.(body) || workingDirectory;
|
|
16703
17429
|
const {
|
|
16704
17430
|
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS,
|
|
16705
17431
|
ANTHROPIC_API_KEY: _dropApiKey,
|
|
@@ -16707,7 +17433,8 @@ function createProxyServer(config = {}) {
|
|
|
16707
17433
|
ANTHROPIC_AUTH_TOKEN: _dropAuthToken,
|
|
16708
17434
|
...cleanEnv
|
|
16709
17435
|
} = process.env;
|
|
16710
|
-
const
|
|
17436
|
+
const sdkModelDefaults = resolveSdkModelDefaults();
|
|
17437
|
+
const profileEnv = { ...sdkModelDefaults, ...cleanEnv, ...profile.env };
|
|
16711
17438
|
let systemContext = "";
|
|
16712
17439
|
if (body.system) {
|
|
16713
17440
|
if (typeof body.system === "string") {
|
|
@@ -16717,6 +17444,20 @@ function createProxyServer(config = {}) {
|
|
|
16717
17444
|
`);
|
|
16718
17445
|
}
|
|
16719
17446
|
}
|
|
17447
|
+
const adapterTransforms = getAdapterTransforms(adapter.name);
|
|
17448
|
+
const pipeline = buildPipeline(adapterTransforms, pluginTransforms);
|
|
17449
|
+
const pipelineCtx = runTransformHook(pipeline, "onRequest", createRequestContext({
|
|
17450
|
+
adapter: adapter.name,
|
|
17451
|
+
body,
|
|
17452
|
+
headers: c.req.raw.headers,
|
|
17453
|
+
model,
|
|
17454
|
+
messages: body.messages || [],
|
|
17455
|
+
systemContext,
|
|
17456
|
+
tools: body.tools,
|
|
17457
|
+
stream: body.stream ?? false,
|
|
17458
|
+
workingDirectory
|
|
17459
|
+
}), adapter.name);
|
|
17460
|
+
const stream2 = pipelineCtx.prefersStreaming !== undefined ? pipelineCtx.prefersStreaming : body.stream ?? false;
|
|
16720
17461
|
const effortHeader = c.req.header("x-opencode-effort");
|
|
16721
17462
|
const thinkingHeader = c.req.header("x-opencode-thinking");
|
|
16722
17463
|
const taskBudgetHeader = c.req.header("x-opencode-task-budget");
|
|
@@ -16754,7 +17495,7 @@ function createProxyServer(config = {}) {
|
|
|
16754
17495
|
const betas = betaFilter.forwarded;
|
|
16755
17496
|
const agentSessionId = adapter.getSessionId(c);
|
|
16756
17497
|
const profileSessionId = profile.id !== "default" && agentSessionId ? `${profile.id}:${agentSessionId}` : agentSessionId;
|
|
16757
|
-
const profileScopedCwd = profile.id !== "default" ? `${
|
|
17498
|
+
const profileScopedCwd = profile.id !== "default" ? `${clientWorkingDirectory}::profile=${profile.id}` : clientWorkingDirectory;
|
|
16758
17499
|
const isIndependentSession = requestSource?.startsWith("fork-") || requestSource?.startsWith("subagent-") || false;
|
|
16759
17500
|
let lineageResult = isIndependentSession ? { type: "diverged" } : lookupSession(profileSessionId, body.messages || [], profileScopedCwd);
|
|
16760
17501
|
if (lineageResult.type === "undo" && adapter.name === "opencode" && !agentSessionId) {
|
|
@@ -16791,14 +17532,14 @@ function createProxyServer(config = {}) {
|
|
|
16791
17532
|
messageCount: Array.isArray(body.messages) ? body.messages.length : 0,
|
|
16792
17533
|
hasSystemPrompt: Boolean(body.system)
|
|
16793
17534
|
});
|
|
16794
|
-
const sdkAgents =
|
|
17535
|
+
const sdkAgents = pipelineCtx.sdkAgents;
|
|
16795
17536
|
const validAgentNames = Object.keys(sdkAgents);
|
|
16796
17537
|
if ((process.env.MERIDIAN_DEBUG ?? process.env.CLAUDE_PROXY_DEBUG) && validAgentNames.length > 0) {
|
|
16797
17538
|
claudeLog("debug.agents", { names: validAgentNames, count: validAgentNames.length });
|
|
16798
17539
|
}
|
|
16799
|
-
systemContext
|
|
17540
|
+
systemContext = pipelineCtx.systemContext ?? systemContext;
|
|
16800
17541
|
const sanitizeOpts = {
|
|
16801
|
-
stripSystemReminder:
|
|
17542
|
+
stripSystemReminder: pipelineCtx.leaksCwdViaSystemReminder
|
|
16802
17543
|
};
|
|
16803
17544
|
const allMessages = body.messages || [];
|
|
16804
17545
|
let messagesToConvert;
|
|
@@ -16862,13 +17603,16 @@ function createProxyServer(config = {}) {
|
|
|
16862
17603
|
|
|
16863
17604
|
`) || "";
|
|
16864
17605
|
}
|
|
16865
|
-
const
|
|
16866
|
-
const
|
|
16867
|
-
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : adapter.getSettingSources?.() ?? [];
|
|
17606
|
+
const passthrough = pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
17607
|
+
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
|
|
16868
17608
|
const capturedToolUses = [];
|
|
16869
17609
|
const fileChanges = [];
|
|
16870
17610
|
let passthroughMcp;
|
|
16871
17611
|
let requestTools = Array.isArray(body.tools) ? body.tools : [];
|
|
17612
|
+
const advisorModel = extractAdvisorModel(requestTools);
|
|
17613
|
+
if (advisorModel) {
|
|
17614
|
+
requestTools = stripAdvisorTools(requestTools);
|
|
17615
|
+
}
|
|
16872
17616
|
if (passthrough && requestTools.length === 0 && profileSessionId) {
|
|
16873
17617
|
const cached = sessionToolCache.get(profileSessionId);
|
|
16874
17618
|
if (cached && cached.length > 0) {
|
|
@@ -16882,7 +17626,7 @@ function createProxyServer(config = {}) {
|
|
|
16882
17626
|
if (cachedMcp && cachedMcp.key === toolSetKey) {
|
|
16883
17627
|
passthroughMcp = cachedMcp.mcp;
|
|
16884
17628
|
} else {
|
|
16885
|
-
passthroughMcp = createPassthroughMcpServer(requestTools,
|
|
17629
|
+
passthroughMcp = createPassthroughMcpServer(requestTools, pipelineCtx.coreToolNames ? [...pipelineCtx.coreToolNames] : undefined);
|
|
16886
17630
|
if (profileSessionId) {
|
|
16887
17631
|
sessionMcpCache.set(profileSessionId, { key: toolSetKey, mcp: passthroughMcp });
|
|
16888
17632
|
if (cachedMcp) {
|
|
@@ -16894,14 +17638,14 @@ function createProxyServer(config = {}) {
|
|
|
16894
17638
|
sessionToolCache.set(profileSessionId, requestTools);
|
|
16895
17639
|
}
|
|
16896
17640
|
const hasDeferredTools = passthroughMcp?.hasDeferredTools ?? false;
|
|
16897
|
-
const coreNames =
|
|
17641
|
+
const coreNames = pipelineCtx.coreToolNames ? [...pipelineCtx.coreToolNames] : undefined;
|
|
16898
17642
|
const coreSet = coreNames ? new Set(coreNames.map((n) => n.toLowerCase())) : undefined;
|
|
16899
17643
|
const deferredToolCount = hasDeferredTools && requestTools.length > 0 ? requestTools.filter((t) => t.defer_loading === true || coreSet && !coreSet.has(String(t.name).toLowerCase())).length : 0;
|
|
16900
17644
|
if (hasDeferredTools) {
|
|
16901
17645
|
console.error(`[PROXY] ${requestMeta.requestId} deferred=${deferredToolCount}/${toolCount} tools (core: ${coreNames?.join(",") ?? "none"})`);
|
|
16902
17646
|
}
|
|
16903
17647
|
const mcpPrefix = `mcp__${adapter.getMcpServerName()}__`;
|
|
16904
|
-
const trackFileChanges = !(process.env.MERIDIAN_NO_FILE_CHANGES ?? process.env.CLAUDE_PROXY_NO_FILE_CHANGES) &&
|
|
17648
|
+
const trackFileChanges = !(process.env.MERIDIAN_NO_FILE_CHANGES ?? process.env.CLAUDE_PROXY_NO_FILE_CHANGES) && pipelineCtx.shouldTrackFileChanges;
|
|
16905
17649
|
const fileChangeHook = trackFileChanges ? createFileChangeHook(fileChanges, mcpPrefix) : undefined;
|
|
16906
17650
|
const discoveredTools = new Set;
|
|
16907
17651
|
const sdkHooks = passthrough ? {
|
|
@@ -16914,10 +17658,15 @@ function createProxyServer(config = {}) {
|
|
|
16914
17658
|
if (hasDeferredTools && coreSet && !coreSet.has(toolName.toLowerCase())) {
|
|
16915
17659
|
discoveredTools.add(toolName);
|
|
16916
17660
|
}
|
|
17661
|
+
const clientTool = requestTools.find((t) => t.name === toolName);
|
|
17662
|
+
let toolInput = normalizeToolInput(input.tool_input, clientTool?.input_schema);
|
|
17663
|
+
if (toolName.toLowerCase() === "task" && toolInput?.subagent_type && typeof toolInput.subagent_type === "string") {
|
|
17664
|
+
toolInput = { ...toolInput, subagent_type: resolveAgentAlias(toolInput.subagent_type) };
|
|
17665
|
+
}
|
|
16917
17666
|
capturedToolUses.push({
|
|
16918
17667
|
id: input.tool_use_id,
|
|
16919
17668
|
name: toolName,
|
|
16920
|
-
input:
|
|
17669
|
+
input: toolInput
|
|
16921
17670
|
});
|
|
16922
17671
|
return {
|
|
16923
17672
|
decision: "block",
|
|
@@ -16926,7 +17675,7 @@ function createProxyServer(config = {}) {
|
|
|
16926
17675
|
}]
|
|
16927
17676
|
}]
|
|
16928
17677
|
} : {
|
|
16929
|
-
...
|
|
17678
|
+
...pipelineCtx.sdkHooks ?? {},
|
|
16930
17679
|
...fileChangeHook ? { PostToolUse: [fileChangeHook] } : {}
|
|
16931
17680
|
};
|
|
16932
17681
|
const stderrLines = [];
|
|
@@ -16945,6 +17694,7 @@ function createProxyServer(config = {}) {
|
|
|
16945
17694
|
sdkUuidMap.push(null);
|
|
16946
17695
|
claudeLog("upstream.start", { mode: "non_stream", model });
|
|
16947
17696
|
let lastUsage;
|
|
17697
|
+
let lastStopReason;
|
|
16948
17698
|
try {
|
|
16949
17699
|
if (!claudeExecutable) {
|
|
16950
17700
|
claudeExecutable = await resolveClaudeExecutableAsync();
|
|
@@ -16961,6 +17711,7 @@ function createProxyServer(config = {}) {
|
|
|
16961
17711
|
prompt: makePrompt(),
|
|
16962
17712
|
model,
|
|
16963
17713
|
workingDirectory,
|
|
17714
|
+
clientWorkingDirectory,
|
|
16964
17715
|
systemContext,
|
|
16965
17716
|
claudeExecutable,
|
|
16966
17717
|
passthrough,
|
|
@@ -16973,7 +17724,10 @@ function createProxyServer(config = {}) {
|
|
|
16973
17724
|
isUndo,
|
|
16974
17725
|
undoRollbackUuid,
|
|
16975
17726
|
sdkHooks,
|
|
16976
|
-
|
|
17727
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17728
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17729
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17730
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
16977
17731
|
onStderr,
|
|
16978
17732
|
effort,
|
|
16979
17733
|
thinking,
|
|
@@ -16988,7 +17742,8 @@ function createProxyServer(config = {}) {
|
|
|
16988
17742
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
16989
17743
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
16990
17744
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
16991
|
-
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
17745
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
|
|
17746
|
+
advisorModel
|
|
16992
17747
|
}))) {
|
|
16993
17748
|
if (event.type === "assistant" && !event.error) {
|
|
16994
17749
|
didYieldContent = true;
|
|
@@ -17015,6 +17770,7 @@ function createProxyServer(config = {}) {
|
|
|
17015
17770
|
prompt: buildFreshPrompt(allMessages, sanitizeOpts),
|
|
17016
17771
|
model,
|
|
17017
17772
|
workingDirectory,
|
|
17773
|
+
clientWorkingDirectory,
|
|
17018
17774
|
systemContext,
|
|
17019
17775
|
claudeExecutable,
|
|
17020
17776
|
passthrough,
|
|
@@ -17027,7 +17783,10 @@ function createProxyServer(config = {}) {
|
|
|
17027
17783
|
isUndo: false,
|
|
17028
17784
|
undoRollbackUuid: undefined,
|
|
17029
17785
|
sdkHooks,
|
|
17030
|
-
|
|
17786
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17787
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17788
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17789
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17031
17790
|
onStderr,
|
|
17032
17791
|
effort,
|
|
17033
17792
|
thinking,
|
|
@@ -17042,7 +17801,8 @@ function createProxyServer(config = {}) {
|
|
|
17042
17801
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17043
17802
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
17044
17803
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
17045
|
-
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
17804
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
|
|
17805
|
+
advisorModel
|
|
17046
17806
|
}));
|
|
17047
17807
|
return;
|
|
17048
17808
|
}
|
|
@@ -17127,7 +17887,7 @@ function createProxyServer(config = {}) {
|
|
|
17127
17887
|
claudeLog("passthrough.toolsearch_filtered", { mode: "non_stream" });
|
|
17128
17888
|
continue;
|
|
17129
17889
|
}
|
|
17130
|
-
if (passthrough && !
|
|
17890
|
+
if (passthrough && !pipelineCtx.supportsThinking && !sdkFeatures.thinkingPassthrough && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
17131
17891
|
claudeLog("passthrough.thinking_stripped", { mode: "non_stream", type: b.type });
|
|
17132
17892
|
continue;
|
|
17133
17893
|
}
|
|
@@ -17140,6 +17900,9 @@ function createProxyServer(config = {}) {
|
|
|
17140
17900
|
const msgUsage = message.message.usage;
|
|
17141
17901
|
if (msgUsage)
|
|
17142
17902
|
lastUsage = { ...lastUsage, ...msgUsage };
|
|
17903
|
+
if (typeof message.message.stop_reason === "string") {
|
|
17904
|
+
lastStopReason = message.message.stop_reason;
|
|
17905
|
+
}
|
|
17143
17906
|
}
|
|
17144
17907
|
}
|
|
17145
17908
|
claudeLog("upstream.completed", {
|
|
@@ -17177,22 +17940,30 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17177
17940
|
throw error;
|
|
17178
17941
|
}
|
|
17179
17942
|
if (passthrough && capturedToolUses.length > 0) {
|
|
17180
|
-
|
|
17181
|
-
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
});
|
|
17943
|
+
const capturedById = new Map(capturedToolUses.map((tu) => [tu.id, tu]));
|
|
17944
|
+
for (const block of contentBlocks) {
|
|
17945
|
+
if (block.type === "tool_use" && capturedById.has(block.id)) {
|
|
17946
|
+
const captured = capturedById.get(block.id);
|
|
17947
|
+
block.name = captured.name;
|
|
17948
|
+
block.input = captured.input;
|
|
17949
|
+
capturedById.delete(block.id);
|
|
17188
17950
|
}
|
|
17189
17951
|
}
|
|
17952
|
+
for (const tu of capturedById.values()) {
|
|
17953
|
+
contentBlocks.push({
|
|
17954
|
+
type: "tool_use",
|
|
17955
|
+
id: tu.id,
|
|
17956
|
+
name: tu.name,
|
|
17957
|
+
input: tu.input
|
|
17958
|
+
});
|
|
17959
|
+
}
|
|
17190
17960
|
}
|
|
17191
17961
|
const hasToolUse = contentBlocks.some((b) => b.type === "tool_use");
|
|
17192
|
-
const
|
|
17962
|
+
const heuristicStopReason = hasToolUse ? "tool_use" : "end_turn";
|
|
17963
|
+
const stopReason = lastStopReason && lastStopReason !== "end_turn" && lastStopReason !== "tool_use" ? lastStopReason : heuristicStopReason;
|
|
17193
17964
|
if (trackFileChanges) {
|
|
17194
|
-
if (passthrough && stopReason === "end_turn" &&
|
|
17195
|
-
const passthroughChanges = extractFileChangesFromMessages(body.messages || [],
|
|
17965
|
+
if (passthrough && stopReason === "end_turn" && pipelineCtx.extractFileChangesFromToolUse) {
|
|
17966
|
+
const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
|
|
17196
17967
|
fileChanges.push(...passthroughChanges);
|
|
17197
17968
|
}
|
|
17198
17969
|
const fileChangeSummary = formatFileChangeSummary(fileChanges);
|
|
@@ -17227,6 +17998,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17227
17998
|
requestId: requestMeta.requestId,
|
|
17228
17999
|
timestamp: Date.now(),
|
|
17229
18000
|
adapter: adapter.name,
|
|
18001
|
+
requestSource,
|
|
17230
18002
|
model,
|
|
17231
18003
|
requestModel: body.model || undefined,
|
|
17232
18004
|
mode: "non-stream",
|
|
@@ -17330,6 +18102,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17330
18102
|
prompt: makePrompt(),
|
|
17331
18103
|
model,
|
|
17332
18104
|
workingDirectory,
|
|
18105
|
+
clientWorkingDirectory,
|
|
17333
18106
|
systemContext,
|
|
17334
18107
|
claudeExecutable,
|
|
17335
18108
|
passthrough,
|
|
@@ -17342,7 +18115,10 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17342
18115
|
isUndo,
|
|
17343
18116
|
undoRollbackUuid,
|
|
17344
18117
|
sdkHooks,
|
|
17345
|
-
|
|
18118
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
18119
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
18120
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
18121
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17346
18122
|
onStderr,
|
|
17347
18123
|
effort,
|
|
17348
18124
|
thinking,
|
|
@@ -17357,7 +18133,8 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17357
18133
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17358
18134
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
17359
18135
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
17360
|
-
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
18136
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
|
|
18137
|
+
advisorModel
|
|
17361
18138
|
}))) {
|
|
17362
18139
|
if (event.type === "stream_event") {
|
|
17363
18140
|
didYieldClientEvent = true;
|
|
@@ -17384,6 +18161,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17384
18161
|
prompt: buildFreshPrompt(allMessages, sanitizeOpts),
|
|
17385
18162
|
model,
|
|
17386
18163
|
workingDirectory,
|
|
18164
|
+
clientWorkingDirectory,
|
|
17387
18165
|
systemContext,
|
|
17388
18166
|
claudeExecutable,
|
|
17389
18167
|
passthrough,
|
|
@@ -17396,7 +18174,10 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17396
18174
|
isUndo: false,
|
|
17397
18175
|
undoRollbackUuid: undefined,
|
|
17398
18176
|
sdkHooks,
|
|
17399
|
-
|
|
18177
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
18178
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
18179
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
18180
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17400
18181
|
onStderr,
|
|
17401
18182
|
effort,
|
|
17402
18183
|
thinking,
|
|
@@ -17411,7 +18192,8 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17411
18192
|
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17412
18193
|
fallbackModel: sdkFeatures.fallbackModel,
|
|
17413
18194
|
sdkDebug: sdkFeatures.sdkDebug,
|
|
17414
|
-
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
18195
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined,
|
|
18196
|
+
advisorModel
|
|
17415
18197
|
}));
|
|
17416
18198
|
return;
|
|
17417
18199
|
}
|
|
@@ -17491,6 +18273,8 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17491
18273
|
}
|
|
17492
18274
|
}, 15000);
|
|
17493
18275
|
const skipBlockIndices = new Set;
|
|
18276
|
+
const taskToolBlockIndices = new Set;
|
|
18277
|
+
const taskToolJsonBuffer = new Map;
|
|
17494
18278
|
const streamedToolUseIds = new Set;
|
|
17495
18279
|
let nextClientBlockIndex = 0;
|
|
17496
18280
|
const sdkToClientIndex = new Map;
|
|
@@ -17548,7 +18332,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
17548
18332
|
}
|
|
17549
18333
|
if (eventType === "content_block_start") {
|
|
17550
18334
|
const block = event.content_block;
|
|
17551
|
-
if (passthrough && !
|
|
18335
|
+
if (passthrough && !pipelineCtx.supportsThinking && !sdkFeatures.thinkingPassthrough && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
17552
18336
|
if (eventIndex !== undefined)
|
|
17553
18337
|
skipBlockIndices.add(eventIndex);
|
|
17554
18338
|
claudeLog("passthrough.thinking_stripped", { mode: "stream", type: block.type, index: eventIndex });
|
|
@@ -17571,6 +18355,9 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
17571
18355
|
} else if (passthrough && block.id) {
|
|
17572
18356
|
streamedToolUseIds.add(block.id);
|
|
17573
18357
|
}
|
|
18358
|
+
if (passthrough && eventIndex !== undefined && block.name.toLowerCase() === "task") {
|
|
18359
|
+
taskToolBlockIndices.add(eventIndex);
|
|
18360
|
+
}
|
|
17574
18361
|
}
|
|
17575
18362
|
if (eventIndex !== undefined) {
|
|
17576
18363
|
sdkToClientIndex.set(eventIndex, nextClientBlockIndex++);
|
|
@@ -17591,6 +18378,39 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
17591
18378
|
continue;
|
|
17592
18379
|
}
|
|
17593
18380
|
}
|
|
18381
|
+
if (passthrough && eventIndex !== undefined && taskToolBlockIndices.has(eventIndex)) {
|
|
18382
|
+
if (eventType === "content_block_delta") {
|
|
18383
|
+
const delta = event.delta;
|
|
18384
|
+
if (delta?.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
18385
|
+
const prev = taskToolJsonBuffer.get(eventIndex) ?? "";
|
|
18386
|
+
taskToolJsonBuffer.set(eventIndex, prev + delta.partial_json);
|
|
18387
|
+
continue;
|
|
18388
|
+
}
|
|
18389
|
+
}
|
|
18390
|
+
if (eventType === "content_block_stop") {
|
|
18391
|
+
const buffered = taskToolJsonBuffer.get(eventIndex);
|
|
18392
|
+
if (buffered) {
|
|
18393
|
+
let fixed = buffered;
|
|
18394
|
+
try {
|
|
18395
|
+
const parsed = JSON.parse(buffered);
|
|
18396
|
+
if (typeof parsed.subagent_type === "string") {
|
|
18397
|
+
parsed.subagent_type = resolveAgentAlias(parsed.subagent_type);
|
|
18398
|
+
}
|
|
18399
|
+
fixed = JSON.stringify(parsed);
|
|
18400
|
+
} catch {}
|
|
18401
|
+
const clientIdx = sdkToClientIndex.get(eventIndex) ?? eventIndex;
|
|
18402
|
+
safeEnqueue(encoder.encode(`event: content_block_delta
|
|
18403
|
+
data: ${JSON.stringify({
|
|
18404
|
+
type: "content_block_delta",
|
|
18405
|
+
index: clientIdx,
|
|
18406
|
+
delta: { type: "input_json_delta", partial_json: fixed }
|
|
18407
|
+
})}
|
|
18408
|
+
|
|
18409
|
+
`), "task_tool_fixed_delta");
|
|
18410
|
+
taskToolJsonBuffer.delete(eventIndex);
|
|
18411
|
+
}
|
|
18412
|
+
}
|
|
18413
|
+
}
|
|
17594
18414
|
const payload = encoder.encode(`event: ${eventType}
|
|
17595
18415
|
data: ${JSON.stringify(event)}
|
|
17596
18416
|
|
|
@@ -17681,8 +18501,8 @@ data: ${JSON.stringify({
|
|
|
17681
18501
|
|
|
17682
18502
|
`), "passthrough_message_delta");
|
|
17683
18503
|
}
|
|
17684
|
-
if (trackFileChanges && passthrough &&
|
|
17685
|
-
const passthroughChanges = extractFileChangesFromMessages(body.messages || [],
|
|
18504
|
+
if (trackFileChanges && passthrough && pipelineCtx.extractFileChangesFromToolUse) {
|
|
18505
|
+
const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
|
|
17686
18506
|
fileChanges.push(...passthroughChanges);
|
|
17687
18507
|
}
|
|
17688
18508
|
if (trackFileChanges) {
|
|
@@ -17750,6 +18570,7 @@ data: {"type":"message_stop"}
|
|
|
17750
18570
|
requestId: requestMeta.requestId,
|
|
17751
18571
|
timestamp: Date.now(),
|
|
17752
18572
|
adapter: adapter.name,
|
|
18573
|
+
requestSource,
|
|
17753
18574
|
model,
|
|
17754
18575
|
requestModel: body.model || undefined,
|
|
17755
18576
|
mode: "stream",
|
|
@@ -18005,7 +18826,7 @@ data: ${JSON.stringify({
|
|
|
18005
18826
|
});
|
|
18006
18827
|
});
|
|
18007
18828
|
app.get("/profiles", async (c) => {
|
|
18008
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
18829
|
+
const { profilePageHtml } = await import("./profilePage-77z05e0r.js");
|
|
18009
18830
|
return c.html(profilePageHtml);
|
|
18010
18831
|
});
|
|
18011
18832
|
app.post("/profiles/active", async (c) => {
|
|
@@ -18030,6 +18851,45 @@ data: ${JSON.stringify({
|
|
|
18030
18851
|
console.error(`[PROXY] Active profile switched to: ${body.profile} (session cache cleared)`);
|
|
18031
18852
|
return c.json({ success: true, activeProfile: body.profile });
|
|
18032
18853
|
});
|
|
18854
|
+
app.get("/plugins/list", async (c) => {
|
|
18855
|
+
const { getPluginStats } = await import("./stats-4c4ewmdh.js");
|
|
18856
|
+
return c.json({
|
|
18857
|
+
plugins: loadedPlugins.map((p) => ({
|
|
18858
|
+
name: p.name,
|
|
18859
|
+
description: p.description,
|
|
18860
|
+
version: p.version,
|
|
18861
|
+
adapters: p.adapters,
|
|
18862
|
+
hooks: p.hooks,
|
|
18863
|
+
status: p.status,
|
|
18864
|
+
path: p.path,
|
|
18865
|
+
...p.error ? { error: p.error } : {},
|
|
18866
|
+
...p.status === "active" ? { stats: getPluginStats(p.name) } : {}
|
|
18867
|
+
}))
|
|
18868
|
+
});
|
|
18869
|
+
});
|
|
18870
|
+
app.post("/plugins/reload", async (c) => {
|
|
18871
|
+
try {
|
|
18872
|
+
loadedPlugins = await loadPlugins(pluginDir, pluginConfigPath);
|
|
18873
|
+
pluginTransforms = getActiveTransforms(loadedPlugins);
|
|
18874
|
+
const active = loadedPlugins.filter((p) => p.status === "active").length;
|
|
18875
|
+
console.error(`[PROXY] Plugins reloaded: ${active} active`);
|
|
18876
|
+
return c.json({
|
|
18877
|
+
success: true,
|
|
18878
|
+
plugins: loadedPlugins.map((p) => ({
|
|
18879
|
+
name: p.name,
|
|
18880
|
+
status: p.status,
|
|
18881
|
+
hooks: p.hooks,
|
|
18882
|
+
...p.error ? { error: p.error } : {}
|
|
18883
|
+
}))
|
|
18884
|
+
});
|
|
18885
|
+
} catch (err) {
|
|
18886
|
+
return c.json({ success: false, error: String(err) }, 500);
|
|
18887
|
+
}
|
|
18888
|
+
});
|
|
18889
|
+
app.get("/plugins", async (c) => {
|
|
18890
|
+
const { pluginPageHtml } = await import("./pluginPage-85s6t6k8.js");
|
|
18891
|
+
return c.html(pluginPageHtml);
|
|
18892
|
+
});
|
|
18033
18893
|
app.post("/auth/refresh", async (c) => {
|
|
18034
18894
|
const success = await refreshOAuthToken();
|
|
18035
18895
|
if (success) {
|
|
@@ -18134,7 +18994,7 @@ data: ${JSON.stringify({
|
|
|
18134
18994
|
if (!session.contextUsage) {
|
|
18135
18995
|
return c.json({ error: "No usage data available for this session" }, 404);
|
|
18136
18996
|
}
|
|
18137
|
-
return c.json({ session_id: claudeSessionId, context_usage: session.contextUsage });
|
|
18997
|
+
return c.json({ session_id: claudeSessionId, context_usage: normalizeContextUsage(session.contextUsage) });
|
|
18138
18998
|
});
|
|
18139
18999
|
app.get("/v1/sessions/recover", (c) => {
|
|
18140
19000
|
const sessions = listStoredSessions();
|
|
@@ -18180,11 +19040,27 @@ data: ${JSON.stringify({
|
|
|
18180
19040
|
console.error(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
|
|
18181
19041
|
return c.json({ error: { type: "not_found", message: `Endpoint not supported: ${c.req.method} ${new URL(c.req.url).pathname}` } }, 404);
|
|
18182
19042
|
});
|
|
18183
|
-
|
|
19043
|
+
async function initPluginsAsync() {
|
|
19044
|
+
try {
|
|
19045
|
+
loadedPlugins = await loadPlugins(pluginDir, pluginConfigPath);
|
|
19046
|
+
pluginTransforms = getActiveTransforms(loadedPlugins);
|
|
19047
|
+
if (loadedPlugins.length > 0) {
|
|
19048
|
+
const active = loadedPlugins.filter((p) => p.status === "active").length;
|
|
19049
|
+
const disabled = loadedPlugins.filter((p) => p.status === "disabled").length;
|
|
19050
|
+
const errored = loadedPlugins.filter((p) => p.status === "error").length;
|
|
19051
|
+
console.error(`[PROXY] Plugins loaded: ${active} active, ${disabled} disabled, ${errored} errors`);
|
|
19052
|
+
}
|
|
19053
|
+
} catch (err) {
|
|
19054
|
+
console.error(`[PROXY] Plugin loading failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
19055
|
+
}
|
|
19056
|
+
}
|
|
19057
|
+
return { app, config: finalConfig, initPlugins: initPluginsAsync };
|
|
18184
19058
|
}
|
|
18185
19059
|
async function startProxyServer(config = {}) {
|
|
18186
19060
|
claudeExecutable = await resolveClaudeExecutableAsync();
|
|
18187
|
-
const { app, config: finalConfig } = createProxyServer(config);
|
|
19061
|
+
const { app, config: finalConfig, initPlugins } = createProxyServer(config);
|
|
19062
|
+
if (initPlugins)
|
|
19063
|
+
await initPlugins();
|
|
18188
19064
|
const server = serve({
|
|
18189
19065
|
fetch: app.fetch,
|
|
18190
19066
|
port: finalConfig.port,
|
|
@@ -18194,6 +19070,8 @@ async function startProxyServer(config = {}) {
|
|
|
18194
19070
|
if (!finalConfig.silent) {
|
|
18195
19071
|
console.log(`Meridian running at http://${finalConfig.host}:${info.port}`);
|
|
18196
19072
|
console.log(`Telemetry dashboard: http://${finalConfig.host}:${info.port}/telemetry`);
|
|
19073
|
+
const pins = resolveSdkModelDefaults();
|
|
19074
|
+
console.log(`Model pins: opus=${pins.ANTHROPIC_DEFAULT_OPUS_MODEL} sonnet=${pins.ANTHROPIC_DEFAULT_SONNET_MODEL} haiku=${pins.ANTHROPIC_DEFAULT_HAIKU_MODEL}`);
|
|
18197
19075
|
console.log(`
|
|
18198
19076
|
Point any Anthropic-compatible tool at this endpoint:`);
|
|
18199
19077
|
console.log(` ANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http://${finalConfig.host}:${info.port}`);
|
|
@@ -18245,4 +19123,4 @@ Or use a different port:`);
|
|
|
18245
19123
|
};
|
|
18246
19124
|
}
|
|
18247
19125
|
|
|
18248
|
-
export { computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
|
|
19126
|
+
export { runTransformHook, runObserveHook, buildPipeline, createRequestContext, computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
|