@rynfar/meridian 1.37.8 → 1.38.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 +21 -0
- package/dist/{cli-pr79d7nw.js → cli-4rqtm83g.js} +33 -2
- package/dist/{cli-z5r7ptsm.js → cli-bfgya0hb.js} +683 -100
- 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 +17 -10
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/crush.d.ts +2 -0
- package/dist/proxy/adapters/crush.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/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 +8 -3
- 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/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 +1 -1
|
@@ -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";
|
|
@@ -8010,13 +8093,8 @@ var dashboardHtml = `<!DOCTYPE html>
|
|
|
8010
8093
|
<title>Meridian — Telemetry</title>
|
|
8011
8094
|
<link rel="icon" type="image/svg+xml" href="/telemetry/icon.svg">
|
|
8012
8095
|
<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
|
-
}
|
|
8096
|
+
${themeCss}
|
|
8097
|
+
:root { --total: var(--accent); }
|
|
8020
8098
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
8021
8099
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
8022
8100
|
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
|
@@ -8272,9 +8350,11 @@ function render(s, reqs, logs) {
|
|
|
8272
8350
|
const sessionShort = r.sdkSessionId ? r.sdkSessionId.slice(0, 8) : '—';
|
|
8273
8351
|
const msgCount = r.messageCount != null ? r.messageCount : '?';
|
|
8274
8352
|
|
|
8353
|
+
const sourceBadge = r.requestSource ? '<br><span class="mono" style="font-size:9px;color:var(--violet)">' + r.requestSource + '</span>' : '';
|
|
8354
|
+
|
|
8275
8355
|
html += '<tr>'
|
|
8276
8356
|
+ '<td class="mono">' + ago(r.timestamp) + '</td>'
|
|
8277
|
-
+ '<td>' + (r.adapter || '—') + '</td>'
|
|
8357
|
+
+ '<td>' + (r.adapter || '—') + sourceBadge + '</td>'
|
|
8278
8358
|
+ '<td>' + (r.requestModel || r.model) + '<br><span style="font-size:10px;color:var(--muted)">' + r.model + '</span></td>'
|
|
8279
8359
|
+ '<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
8360
|
+ '<td class="mono">' + sessionShort + ' ' + lineageBadge + '<br><span style="font-size:10px;color:var(--muted)">' + msgCount + ' msgs</span></td>'
|
|
@@ -8407,12 +8487,7 @@ var landingHtml = `<!DOCTYPE html>
|
|
|
8407
8487
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8408
8488
|
<title>Meridian</title>
|
|
8409
8489
|
<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
|
-
}
|
|
8490
|
+
${themeCss}
|
|
8416
8491
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
8417
8492
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
8418
8493
|
background: var(--bg); color: var(--text); line-height: 1.6; min-height: 100vh; }
|
|
@@ -9463,6 +9538,85 @@ function fuzzyMatchAgentName(input, validAgents) {
|
|
|
9463
9538
|
return lowered;
|
|
9464
9539
|
}
|
|
9465
9540
|
|
|
9541
|
+
// src/proxy/transforms/opencode.ts
|
|
9542
|
+
var openCodeTransforms = [
|
|
9543
|
+
{
|
|
9544
|
+
name: "opencode-core",
|
|
9545
|
+
adapters: ["opencode"],
|
|
9546
|
+
onRequest(ctx) {
|
|
9547
|
+
const body = ctx.body;
|
|
9548
|
+
const blockedTools = BLOCKED_BUILTIN_TOOLS;
|
|
9549
|
+
const incompatibleTools = CLAUDE_CODE_ONLY_TOOLS;
|
|
9550
|
+
const allowedMcpTools = ALLOWED_MCP_TOOLS;
|
|
9551
|
+
const coreToolNames = ["read", "write", "edit", "bash", "glob", "grep"];
|
|
9552
|
+
const envVal = process.env.MERIDIAN_PASSTHROUGH ?? process.env.CLAUDE_PROXY_PASSTHROUGH;
|
|
9553
|
+
const passthrough = !(envVal === "0" || envVal === "false" || envVal === "no");
|
|
9554
|
+
let sdkAgents = {};
|
|
9555
|
+
if (Array.isArray(body.tools)) {
|
|
9556
|
+
const taskTool = body.tools.find((t) => t.name === "task" || t.name === "Task");
|
|
9557
|
+
if (taskTool?.description) {
|
|
9558
|
+
sdkAgents = buildAgentDefinitions(taskTool.description, [...allowedMcpTools]);
|
|
9559
|
+
}
|
|
9560
|
+
}
|
|
9561
|
+
let sdkHooks = undefined;
|
|
9562
|
+
const validAgentNames = Object.keys(sdkAgents);
|
|
9563
|
+
if (validAgentNames.length > 0) {
|
|
9564
|
+
sdkHooks = {
|
|
9565
|
+
PreToolUse: [{
|
|
9566
|
+
matcher: "Task",
|
|
9567
|
+
hooks: [async (input) => ({
|
|
9568
|
+
hookSpecificOutput: {
|
|
9569
|
+
hookEventName: "PreToolUse",
|
|
9570
|
+
updatedInput: {
|
|
9571
|
+
...input.tool_input,
|
|
9572
|
+
subagent_type: fuzzyMatchAgentName(String(input.tool_input?.subagent_type || ""), validAgentNames)
|
|
9573
|
+
}
|
|
9574
|
+
}
|
|
9575
|
+
})]
|
|
9576
|
+
}]
|
|
9577
|
+
};
|
|
9578
|
+
}
|
|
9579
|
+
let systemContext = ctx.systemContext;
|
|
9580
|
+
if (validAgentNames.length > 0 && systemContext !== undefined) {
|
|
9581
|
+
systemContext += `
|
|
9582
|
+
|
|
9583
|
+
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.`;
|
|
9584
|
+
} else if (validAgentNames.length > 0) {
|
|
9585
|
+
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.`;
|
|
9586
|
+
}
|
|
9587
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
9588
|
+
const input = toolInput;
|
|
9589
|
+
const filePath = input?.filePath ?? input?.file_path ?? input?.path;
|
|
9590
|
+
const lowerName = toolName.toLowerCase();
|
|
9591
|
+
if (lowerName === "write" && filePath) {
|
|
9592
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
9593
|
+
}
|
|
9594
|
+
if ((lowerName === "edit" || lowerName === "multiedit") && filePath) {
|
|
9595
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
9596
|
+
}
|
|
9597
|
+
if (lowerName === "bash" && input?.command) {
|
|
9598
|
+
return extractFileChangesFromBash(String(input.command));
|
|
9599
|
+
}
|
|
9600
|
+
return [];
|
|
9601
|
+
};
|
|
9602
|
+
return {
|
|
9603
|
+
...ctx,
|
|
9604
|
+
blockedTools,
|
|
9605
|
+
incompatibleTools,
|
|
9606
|
+
allowedMcpTools,
|
|
9607
|
+
coreToolNames,
|
|
9608
|
+
passthrough,
|
|
9609
|
+
sdkAgents,
|
|
9610
|
+
sdkHooks,
|
|
9611
|
+
systemContext,
|
|
9612
|
+
supportsThinking: true,
|
|
9613
|
+
shouldTrackFileChanges: false,
|
|
9614
|
+
extractFileChangesFromToolUse
|
|
9615
|
+
};
|
|
9616
|
+
}
|
|
9617
|
+
}
|
|
9618
|
+
];
|
|
9619
|
+
|
|
9466
9620
|
// src/proxy/adapters/opencode.ts
|
|
9467
9621
|
var openCodeAdapter = {
|
|
9468
9622
|
name: "opencode",
|
|
@@ -9555,7 +9709,7 @@ IMPORTANT: When using the task/Task tool, the subagent_type parameter must be on
|
|
|
9555
9709
|
}
|
|
9556
9710
|
};
|
|
9557
9711
|
|
|
9558
|
-
// src/proxy/
|
|
9712
|
+
// src/proxy/transforms/droid.ts
|
|
9559
9713
|
var DROID_MCP_SERVER_NAME = "droid";
|
|
9560
9714
|
var DROID_ALLOWED_MCP_TOOLS = [
|
|
9561
9715
|
`mcp__${DROID_MCP_SERVER_NAME}__read`,
|
|
@@ -9565,6 +9719,34 @@ var DROID_ALLOWED_MCP_TOOLS = [
|
|
|
9565
9719
|
`mcp__${DROID_MCP_SERVER_NAME}__glob`,
|
|
9566
9720
|
`mcp__${DROID_MCP_SERVER_NAME}__grep`
|
|
9567
9721
|
];
|
|
9722
|
+
var droidTransforms = [
|
|
9723
|
+
{
|
|
9724
|
+
name: "droid-core",
|
|
9725
|
+
adapters: ["droid"],
|
|
9726
|
+
onRequest(ctx) {
|
|
9727
|
+
return {
|
|
9728
|
+
...ctx,
|
|
9729
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
9730
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
9731
|
+
allowedMcpTools: DROID_ALLOWED_MCP_TOOLS,
|
|
9732
|
+
sdkAgents: {},
|
|
9733
|
+
passthrough: false,
|
|
9734
|
+
leaksCwdViaSystemReminder: true
|
|
9735
|
+
};
|
|
9736
|
+
}
|
|
9737
|
+
}
|
|
9738
|
+
];
|
|
9739
|
+
|
|
9740
|
+
// src/proxy/adapters/droid.ts
|
|
9741
|
+
var DROID_MCP_SERVER_NAME2 = "droid";
|
|
9742
|
+
var DROID_ALLOWED_MCP_TOOLS2 = [
|
|
9743
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__read`,
|
|
9744
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__write`,
|
|
9745
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__edit`,
|
|
9746
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__bash`,
|
|
9747
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__glob`,
|
|
9748
|
+
`mcp__${DROID_MCP_SERVER_NAME2}__grep`
|
|
9749
|
+
];
|
|
9568
9750
|
function extractDroidCwd(body) {
|
|
9569
9751
|
const messages = body.messages;
|
|
9570
9752
|
if (!Array.isArray(messages))
|
|
@@ -9604,10 +9786,10 @@ var droidAdapter = {
|
|
|
9604
9786
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9605
9787
|
},
|
|
9606
9788
|
getMcpServerName() {
|
|
9607
|
-
return
|
|
9789
|
+
return DROID_MCP_SERVER_NAME2;
|
|
9608
9790
|
},
|
|
9609
9791
|
getAllowedMcpTools() {
|
|
9610
|
-
return
|
|
9792
|
+
return DROID_ALLOWED_MCP_TOOLS2;
|
|
9611
9793
|
},
|
|
9612
9794
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9613
9795
|
return {};
|
|
@@ -9623,7 +9805,7 @@ var droidAdapter = {
|
|
|
9623
9805
|
}
|
|
9624
9806
|
};
|
|
9625
9807
|
|
|
9626
|
-
// src/proxy/
|
|
9808
|
+
// src/proxy/transforms/crush.ts
|
|
9627
9809
|
var CRUSH_MCP_SERVER_NAME = "crush";
|
|
9628
9810
|
var CRUSH_ALLOWED_MCP_TOOLS = [
|
|
9629
9811
|
`mcp__${CRUSH_MCP_SERVER_NAME}__read`,
|
|
@@ -9633,6 +9815,45 @@ var CRUSH_ALLOWED_MCP_TOOLS = [
|
|
|
9633
9815
|
`mcp__${CRUSH_MCP_SERVER_NAME}__glob`,
|
|
9634
9816
|
`mcp__${CRUSH_MCP_SERVER_NAME}__grep`
|
|
9635
9817
|
];
|
|
9818
|
+
var crushTransforms = [
|
|
9819
|
+
{
|
|
9820
|
+
name: "crush-core",
|
|
9821
|
+
adapters: ["crush"],
|
|
9822
|
+
onRequest(ctx) {
|
|
9823
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
9824
|
+
const input = toolInput;
|
|
9825
|
+
const filePath = input?.file_path ?? input?.path;
|
|
9826
|
+
if (toolName === "write" && filePath)
|
|
9827
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
9828
|
+
if ((toolName === "edit" || toolName === "patch") && filePath)
|
|
9829
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
9830
|
+
if (toolName === "bash" && input?.command)
|
|
9831
|
+
return extractFileChangesFromBash(String(input.command));
|
|
9832
|
+
return [];
|
|
9833
|
+
};
|
|
9834
|
+
return {
|
|
9835
|
+
...ctx,
|
|
9836
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
9837
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
9838
|
+
allowedMcpTools: CRUSH_ALLOWED_MCP_TOOLS,
|
|
9839
|
+
sdkAgents: {},
|
|
9840
|
+
supportsThinking: true,
|
|
9841
|
+
extractFileChangesFromToolUse
|
|
9842
|
+
};
|
|
9843
|
+
}
|
|
9844
|
+
}
|
|
9845
|
+
];
|
|
9846
|
+
|
|
9847
|
+
// src/proxy/adapters/crush.ts
|
|
9848
|
+
var CRUSH_MCP_SERVER_NAME2 = "crush";
|
|
9849
|
+
var CRUSH_ALLOWED_MCP_TOOLS2 = [
|
|
9850
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__read`,
|
|
9851
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__write`,
|
|
9852
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__edit`,
|
|
9853
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__bash`,
|
|
9854
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__glob`,
|
|
9855
|
+
`mcp__${CRUSH_MCP_SERVER_NAME2}__grep`
|
|
9856
|
+
];
|
|
9636
9857
|
var crushAdapter = {
|
|
9637
9858
|
name: "crush",
|
|
9638
9859
|
getSessionId(_c) {
|
|
@@ -9651,10 +9872,10 @@ var crushAdapter = {
|
|
|
9651
9872
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9652
9873
|
},
|
|
9653
9874
|
getMcpServerName() {
|
|
9654
|
-
return
|
|
9875
|
+
return CRUSH_MCP_SERVER_NAME2;
|
|
9655
9876
|
},
|
|
9656
9877
|
getAllowedMcpTools() {
|
|
9657
|
-
return
|
|
9878
|
+
return CRUSH_ALLOWED_MCP_TOOLS2;
|
|
9658
9879
|
},
|
|
9659
9880
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9660
9881
|
return {};
|
|
@@ -9684,7 +9905,7 @@ var crushAdapter = {
|
|
|
9684
9905
|
}
|
|
9685
9906
|
};
|
|
9686
9907
|
|
|
9687
|
-
// src/proxy/
|
|
9908
|
+
// src/proxy/transforms/passthrough.ts
|
|
9688
9909
|
var MCP_SERVER_NAME2 = "litellm";
|
|
9689
9910
|
var ALLOWED_MCP_TOOLS2 = [
|
|
9690
9911
|
`mcp__${MCP_SERVER_NAME2}__read`,
|
|
@@ -9694,6 +9915,34 @@ var ALLOWED_MCP_TOOLS2 = [
|
|
|
9694
9915
|
`mcp__${MCP_SERVER_NAME2}__glob`,
|
|
9695
9916
|
`mcp__${MCP_SERVER_NAME2}__grep`
|
|
9696
9917
|
];
|
|
9918
|
+
var passthroughTransforms = [
|
|
9919
|
+
{
|
|
9920
|
+
name: "passthrough-core",
|
|
9921
|
+
adapters: ["passthrough"],
|
|
9922
|
+
onRequest(ctx) {
|
|
9923
|
+
return {
|
|
9924
|
+
...ctx,
|
|
9925
|
+
blockedTools: [],
|
|
9926
|
+
incompatibleTools: [],
|
|
9927
|
+
allowedMcpTools: ALLOWED_MCP_TOOLS2,
|
|
9928
|
+
sdkAgents: {},
|
|
9929
|
+
passthrough: true,
|
|
9930
|
+
prefersStreaming: ctx.body?.stream === true
|
|
9931
|
+
};
|
|
9932
|
+
}
|
|
9933
|
+
}
|
|
9934
|
+
];
|
|
9935
|
+
|
|
9936
|
+
// src/proxy/adapters/passthrough.ts
|
|
9937
|
+
var MCP_SERVER_NAME3 = "litellm";
|
|
9938
|
+
var ALLOWED_MCP_TOOLS3 = [
|
|
9939
|
+
`mcp__${MCP_SERVER_NAME3}__read`,
|
|
9940
|
+
`mcp__${MCP_SERVER_NAME3}__write`,
|
|
9941
|
+
`mcp__${MCP_SERVER_NAME3}__edit`,
|
|
9942
|
+
`mcp__${MCP_SERVER_NAME3}__bash`,
|
|
9943
|
+
`mcp__${MCP_SERVER_NAME3}__glob`,
|
|
9944
|
+
`mcp__${MCP_SERVER_NAME3}__grep`
|
|
9945
|
+
];
|
|
9697
9946
|
function extractCwdFromBody(body) {
|
|
9698
9947
|
if (!body)
|
|
9699
9948
|
return;
|
|
@@ -9741,10 +9990,10 @@ var passthroughAdapter = {
|
|
|
9741
9990
|
return [];
|
|
9742
9991
|
},
|
|
9743
9992
|
getMcpServerName() {
|
|
9744
|
-
return
|
|
9993
|
+
return MCP_SERVER_NAME3;
|
|
9745
9994
|
},
|
|
9746
9995
|
getAllowedMcpTools() {
|
|
9747
|
-
return
|
|
9996
|
+
return ALLOWED_MCP_TOOLS3;
|
|
9748
9997
|
},
|
|
9749
9998
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9750
9999
|
return {};
|
|
@@ -9763,7 +10012,7 @@ var passthroughAdapter = {
|
|
|
9763
10012
|
}
|
|
9764
10013
|
};
|
|
9765
10014
|
|
|
9766
|
-
// src/proxy/
|
|
10015
|
+
// src/proxy/transforms/pi.ts
|
|
9767
10016
|
var PI_MCP_SERVER_NAME = "pi";
|
|
9768
10017
|
var PI_ALLOWED_MCP_TOOLS = [
|
|
9769
10018
|
`mcp__${PI_MCP_SERVER_NAME}__read`,
|
|
@@ -9773,6 +10022,45 @@ var PI_ALLOWED_MCP_TOOLS = [
|
|
|
9773
10022
|
`mcp__${PI_MCP_SERVER_NAME}__glob`,
|
|
9774
10023
|
`mcp__${PI_MCP_SERVER_NAME}__grep`
|
|
9775
10024
|
];
|
|
10025
|
+
var piTransforms = [
|
|
10026
|
+
{
|
|
10027
|
+
name: "pi-core",
|
|
10028
|
+
adapters: ["pi"],
|
|
10029
|
+
onRequest(ctx) {
|
|
10030
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
10031
|
+
const input = toolInput;
|
|
10032
|
+
const filePath = input?.filePath ?? input?.file_path ?? input?.path;
|
|
10033
|
+
if (toolName === "write" && filePath)
|
|
10034
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
10035
|
+
if (toolName === "edit" && filePath)
|
|
10036
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
10037
|
+
if (toolName === "bash" && input?.command)
|
|
10038
|
+
return extractFileChangesFromBash(String(input.command));
|
|
10039
|
+
return [];
|
|
10040
|
+
};
|
|
10041
|
+
return {
|
|
10042
|
+
...ctx,
|
|
10043
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
10044
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
10045
|
+
allowedMcpTools: PI_ALLOWED_MCP_TOOLS,
|
|
10046
|
+
sdkAgents: {},
|
|
10047
|
+
supportsThinking: true,
|
|
10048
|
+
extractFileChangesFromToolUse
|
|
10049
|
+
};
|
|
10050
|
+
}
|
|
10051
|
+
}
|
|
10052
|
+
];
|
|
10053
|
+
|
|
10054
|
+
// src/proxy/adapters/pi.ts
|
|
10055
|
+
var PI_MCP_SERVER_NAME2 = "pi";
|
|
10056
|
+
var PI_ALLOWED_MCP_TOOLS2 = [
|
|
10057
|
+
`mcp__${PI_MCP_SERVER_NAME2}__read`,
|
|
10058
|
+
`mcp__${PI_MCP_SERVER_NAME2}__write`,
|
|
10059
|
+
`mcp__${PI_MCP_SERVER_NAME2}__edit`,
|
|
10060
|
+
`mcp__${PI_MCP_SERVER_NAME2}__bash`,
|
|
10061
|
+
`mcp__${PI_MCP_SERVER_NAME2}__glob`,
|
|
10062
|
+
`mcp__${PI_MCP_SERVER_NAME2}__grep`
|
|
10063
|
+
];
|
|
9776
10064
|
function extractPiCwd(body) {
|
|
9777
10065
|
let systemText = "";
|
|
9778
10066
|
if (typeof body.system === "string") {
|
|
@@ -9804,10 +10092,10 @@ var piAdapter = {
|
|
|
9804
10092
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9805
10093
|
},
|
|
9806
10094
|
getMcpServerName() {
|
|
9807
|
-
return
|
|
10095
|
+
return PI_MCP_SERVER_NAME2;
|
|
9808
10096
|
},
|
|
9809
10097
|
getAllowedMcpTools() {
|
|
9810
|
-
return
|
|
10098
|
+
return PI_ALLOWED_MCP_TOOLS2;
|
|
9811
10099
|
},
|
|
9812
10100
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9813
10101
|
return {};
|
|
@@ -9837,7 +10125,7 @@ var piAdapter = {
|
|
|
9837
10125
|
}
|
|
9838
10126
|
};
|
|
9839
10127
|
|
|
9840
|
-
// src/proxy/
|
|
10128
|
+
// src/proxy/transforms/forgecode.ts
|
|
9841
10129
|
var FORGECODE_MCP_SERVER_NAME = "forgecode";
|
|
9842
10130
|
var FORGECODE_ALLOWED_MCP_TOOLS = [
|
|
9843
10131
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__read`,
|
|
@@ -9847,6 +10135,44 @@ var FORGECODE_ALLOWED_MCP_TOOLS = [
|
|
|
9847
10135
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__glob`,
|
|
9848
10136
|
`mcp__${FORGECODE_MCP_SERVER_NAME}__grep`
|
|
9849
10137
|
];
|
|
10138
|
+
var forgeCodeTransforms = [
|
|
10139
|
+
{
|
|
10140
|
+
name: "forgecode-core",
|
|
10141
|
+
adapters: ["forgecode"],
|
|
10142
|
+
onRequest(ctx) {
|
|
10143
|
+
const extractFileChangesFromToolUse = (toolName, toolInput) => {
|
|
10144
|
+
const input = toolInput;
|
|
10145
|
+
const filePath = input?.file_path ?? input?.filePath ?? input?.path;
|
|
10146
|
+
if (toolName === "write" && filePath)
|
|
10147
|
+
return [{ operation: "wrote", path: String(filePath) }];
|
|
10148
|
+
if ((toolName === "patch" || toolName === "multi_patch") && filePath)
|
|
10149
|
+
return [{ operation: "edited", path: String(filePath) }];
|
|
10150
|
+
if (toolName === "shell" && input?.command)
|
|
10151
|
+
return extractFileChangesFromBash(String(input.command));
|
|
10152
|
+
return [];
|
|
10153
|
+
};
|
|
10154
|
+
return {
|
|
10155
|
+
...ctx,
|
|
10156
|
+
blockedTools: BLOCKED_BUILTIN_TOOLS,
|
|
10157
|
+
incompatibleTools: CLAUDE_CODE_ONLY_TOOLS,
|
|
10158
|
+
allowedMcpTools: FORGECODE_ALLOWED_MCP_TOOLS,
|
|
10159
|
+
sdkAgents: {},
|
|
10160
|
+
extractFileChangesFromToolUse
|
|
10161
|
+
};
|
|
10162
|
+
}
|
|
10163
|
+
}
|
|
10164
|
+
];
|
|
10165
|
+
|
|
10166
|
+
// src/proxy/adapters/forgecode.ts
|
|
10167
|
+
var FORGECODE_MCP_SERVER_NAME2 = "forgecode";
|
|
10168
|
+
var FORGECODE_ALLOWED_MCP_TOOLS2 = [
|
|
10169
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__read`,
|
|
10170
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__write`,
|
|
10171
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__edit`,
|
|
10172
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__bash`,
|
|
10173
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__glob`,
|
|
10174
|
+
`mcp__${FORGECODE_MCP_SERVER_NAME2}__grep`
|
|
10175
|
+
];
|
|
9850
10176
|
function extractForgeCodeCwd(body) {
|
|
9851
10177
|
let systemText = "";
|
|
9852
10178
|
if (typeof body.system === "string") {
|
|
@@ -9878,10 +10204,10 @@ var forgeCodeAdapter = {
|
|
|
9878
10204
|
return CLAUDE_CODE_ONLY_TOOLS;
|
|
9879
10205
|
},
|
|
9880
10206
|
getMcpServerName() {
|
|
9881
|
-
return
|
|
10207
|
+
return FORGECODE_MCP_SERVER_NAME2;
|
|
9882
10208
|
},
|
|
9883
10209
|
getAllowedMcpTools() {
|
|
9884
|
-
return
|
|
10210
|
+
return FORGECODE_ALLOWED_MCP_TOOLS2;
|
|
9885
10211
|
},
|
|
9886
10212
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
9887
10213
|
return {};
|
|
@@ -15677,7 +16003,10 @@ function buildQueryOptions(ctx) {
|
|
|
15677
16003
|
isUndo,
|
|
15678
16004
|
undoRollbackUuid,
|
|
15679
16005
|
sdkHooks,
|
|
15680
|
-
|
|
16006
|
+
blockedTools,
|
|
16007
|
+
incompatibleTools,
|
|
16008
|
+
mcpServerName,
|
|
16009
|
+
allowedMcpTools,
|
|
15681
16010
|
onStderr,
|
|
15682
16011
|
effort,
|
|
15683
16012
|
thinking,
|
|
@@ -15694,9 +16023,7 @@ function buildQueryOptions(ctx) {
|
|
|
15694
16023
|
sdkDebug,
|
|
15695
16024
|
additionalDirectories
|
|
15696
16025
|
} = ctx;
|
|
15697
|
-
const
|
|
15698
|
-
const mcpServerName = adapter.getMcpServerName();
|
|
15699
|
-
const allowedMcpTools = [...adapter.getAllowedMcpTools()];
|
|
16026
|
+
const allBlockedTools = [...blockedTools, ...incompatibleTools];
|
|
15700
16027
|
return {
|
|
15701
16028
|
prompt,
|
|
15702
16029
|
options: {
|
|
@@ -15710,14 +16037,14 @@ function buildQueryOptions(ctx) {
|
|
|
15710
16037
|
allowDangerouslySkipPermissions: true,
|
|
15711
16038
|
...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt),
|
|
15712
16039
|
...passthrough ? {
|
|
15713
|
-
disallowedTools:
|
|
16040
|
+
disallowedTools: [...allBlockedTools],
|
|
15714
16041
|
...passthroughMcp ? {
|
|
15715
|
-
allowedTools: passthroughMcp.toolNames,
|
|
16042
|
+
allowedTools: [...passthroughMcp.toolNames],
|
|
15716
16043
|
mcpServers: { [PASSTHROUGH_MCP_NAME]: passthroughMcp.server }
|
|
15717
16044
|
} : {}
|
|
15718
16045
|
} : {
|
|
15719
|
-
disallowedTools:
|
|
15720
|
-
allowedTools: allowedMcpTools,
|
|
16046
|
+
disallowedTools: [...allBlockedTools],
|
|
16047
|
+
allowedTools: [...allowedMcpTools],
|
|
15721
16048
|
mcpServers: { [mcpServerName]: createOpencodeMcpServer() }
|
|
15722
16049
|
},
|
|
15723
16050
|
plugins: [],
|
|
@@ -15752,6 +16079,176 @@ function buildQueryOptions(ctx) {
|
|
|
15752
16079
|
};
|
|
15753
16080
|
}
|
|
15754
16081
|
|
|
16082
|
+
// src/proxy/transforms/registry.ts
|
|
16083
|
+
var ADAPTER_TRANSFORMS = {
|
|
16084
|
+
opencode: openCodeTransforms,
|
|
16085
|
+
crush: crushTransforms,
|
|
16086
|
+
droid: droidTransforms,
|
|
16087
|
+
pi: piTransforms,
|
|
16088
|
+
forgecode: forgeCodeTransforms,
|
|
16089
|
+
passthrough: passthroughTransforms
|
|
16090
|
+
};
|
|
16091
|
+
function getAdapterTransforms(adapterName) {
|
|
16092
|
+
return ADAPTER_TRANSFORMS[adapterName] ?? [];
|
|
16093
|
+
}
|
|
16094
|
+
|
|
16095
|
+
// src/proxy/plugins/loader.ts
|
|
16096
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
16097
|
+
import { join as join4, isAbsolute as isAbsolute2, extname } from "path";
|
|
16098
|
+
|
|
16099
|
+
// src/proxy/plugins/validation.ts
|
|
16100
|
+
var KNOWN_ADAPTERS = ["opencode", "crush", "droid", "pi", "forgecode", "passthrough"];
|
|
16101
|
+
var KNOWN_HOOKS = ["onRequest", "onResponse", "onTelemetry", "onSession", "onToolUse", "onToolResult", "onError"];
|
|
16102
|
+
function validateTransform(exported) {
|
|
16103
|
+
if (exported == null || typeof exported !== "object") {
|
|
16104
|
+
return { valid: false, hooks: [], error: "Plugin must export an object" };
|
|
16105
|
+
}
|
|
16106
|
+
const obj = exported;
|
|
16107
|
+
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
16108
|
+
return { valid: false, hooks: [], error: "Plugin must have a name: string property" };
|
|
16109
|
+
}
|
|
16110
|
+
const hooks = [];
|
|
16111
|
+
for (const hook of KNOWN_HOOKS) {
|
|
16112
|
+
if (obj[hook] !== undefined) {
|
|
16113
|
+
if (typeof obj[hook] !== "function") {
|
|
16114
|
+
return { valid: false, hooks: [], error: `${hook} must be a function, got ${typeof obj[hook]}` };
|
|
16115
|
+
}
|
|
16116
|
+
hooks.push(hook);
|
|
16117
|
+
}
|
|
16118
|
+
}
|
|
16119
|
+
const warnings = [];
|
|
16120
|
+
if (Array.isArray(obj.adapters)) {
|
|
16121
|
+
for (const adapter of obj.adapters) {
|
|
16122
|
+
if (typeof adapter === "string" && !KNOWN_ADAPTERS.includes(adapter)) {
|
|
16123
|
+
warnings.push(adapter);
|
|
16124
|
+
}
|
|
16125
|
+
}
|
|
16126
|
+
}
|
|
16127
|
+
return {
|
|
16128
|
+
valid: true,
|
|
16129
|
+
hooks,
|
|
16130
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
16131
|
+
};
|
|
16132
|
+
}
|
|
16133
|
+
|
|
16134
|
+
// src/proxy/plugins/loader.ts
|
|
16135
|
+
var loadCounter = 0;
|
|
16136
|
+
function parsePluginConfig(configPath) {
|
|
16137
|
+
if (!existsSync3(configPath))
|
|
16138
|
+
return [];
|
|
16139
|
+
try {
|
|
16140
|
+
const raw2 = readFileSync2(configPath, "utf-8");
|
|
16141
|
+
const parsed = JSON.parse(raw2);
|
|
16142
|
+
return Array.isArray(parsed.plugins) ? parsed.plugins : [];
|
|
16143
|
+
} catch {
|
|
16144
|
+
return [];
|
|
16145
|
+
}
|
|
16146
|
+
}
|
|
16147
|
+
async function loadPlugins(pluginDir, configPath) {
|
|
16148
|
+
resetAllPluginStats();
|
|
16149
|
+
const config = configPath ? parsePluginConfig(configPath) : [];
|
|
16150
|
+
const pluginDirExists = existsSync3(pluginDir);
|
|
16151
|
+
let filenames = [];
|
|
16152
|
+
if (pluginDirExists) {
|
|
16153
|
+
try {
|
|
16154
|
+
filenames = readdirSync2(pluginDir).filter((f) => {
|
|
16155
|
+
const ext2 = extname(f);
|
|
16156
|
+
return ext2 === ".ts" || ext2 === ".js";
|
|
16157
|
+
});
|
|
16158
|
+
} catch {
|
|
16159
|
+
filenames = [];
|
|
16160
|
+
}
|
|
16161
|
+
}
|
|
16162
|
+
if (!pluginDirExists && config.length === 0)
|
|
16163
|
+
return [];
|
|
16164
|
+
const ordered = [];
|
|
16165
|
+
const seen = new Set;
|
|
16166
|
+
for (const entry of config) {
|
|
16167
|
+
const filename = isAbsolute2(entry.path) ? entry.path : entry.path;
|
|
16168
|
+
if (filenames.includes(filename) || isAbsolute2(entry.path)) {
|
|
16169
|
+
ordered.push({ filename, entry });
|
|
16170
|
+
seen.add(filename);
|
|
16171
|
+
}
|
|
16172
|
+
}
|
|
16173
|
+
for (const filename of filenames) {
|
|
16174
|
+
if (!seen.has(filename)) {
|
|
16175
|
+
ordered.push({ filename });
|
|
16176
|
+
}
|
|
16177
|
+
}
|
|
16178
|
+
const loaded = [];
|
|
16179
|
+
const seenNames = new Set;
|
|
16180
|
+
for (const { filename, entry } of ordered) {
|
|
16181
|
+
const filePath = isAbsolute2(filename) ? filename : join4(pluginDir, filename);
|
|
16182
|
+
if (entry && !entry.enabled) {
|
|
16183
|
+
loaded.push({
|
|
16184
|
+
name: filename,
|
|
16185
|
+
status: "disabled",
|
|
16186
|
+
hooks: [],
|
|
16187
|
+
path: filePath,
|
|
16188
|
+
transform: { name: filename }
|
|
16189
|
+
});
|
|
16190
|
+
continue;
|
|
16191
|
+
}
|
|
16192
|
+
try {
|
|
16193
|
+
const cacheBuster = `?t=${Date.now()}-${++loadCounter}`;
|
|
16194
|
+
const mod = await import(filePath + cacheBuster);
|
|
16195
|
+
const exported = mod.default ?? mod;
|
|
16196
|
+
const transforms = Array.isArray(exported) ? exported : [exported];
|
|
16197
|
+
for (const item of transforms) {
|
|
16198
|
+
const validation = validateTransform(item);
|
|
16199
|
+
if (!validation.valid) {
|
|
16200
|
+
loaded.push({
|
|
16201
|
+
name: filename,
|
|
16202
|
+
status: "error",
|
|
16203
|
+
error: validation.error,
|
|
16204
|
+
hooks: [],
|
|
16205
|
+
path: filePath,
|
|
16206
|
+
transform: { name: filename }
|
|
16207
|
+
});
|
|
16208
|
+
continue;
|
|
16209
|
+
}
|
|
16210
|
+
const transform = item;
|
|
16211
|
+
if (seenNames.has(transform.name)) {
|
|
16212
|
+
loaded.push({
|
|
16213
|
+
name: transform.name,
|
|
16214
|
+
status: "error",
|
|
16215
|
+
error: `Skipped: duplicate plugin name "${transform.name}"`,
|
|
16216
|
+
hooks: validation.hooks,
|
|
16217
|
+
path: filePath,
|
|
16218
|
+
transform
|
|
16219
|
+
});
|
|
16220
|
+
continue;
|
|
16221
|
+
}
|
|
16222
|
+
seenNames.add(transform.name);
|
|
16223
|
+
registerPluginStats(transform.name);
|
|
16224
|
+
loaded.push({
|
|
16225
|
+
name: transform.name,
|
|
16226
|
+
description: transform.description,
|
|
16227
|
+
version: transform.version,
|
|
16228
|
+
adapters: transform.adapters,
|
|
16229
|
+
hooks: validation.hooks,
|
|
16230
|
+
status: "active",
|
|
16231
|
+
path: filePath,
|
|
16232
|
+
transform
|
|
16233
|
+
});
|
|
16234
|
+
}
|
|
16235
|
+
} catch (err) {
|
|
16236
|
+
loaded.push({
|
|
16237
|
+
name: filename,
|
|
16238
|
+
status: "error",
|
|
16239
|
+
error: `Failed to load: ${err instanceof Error ? err.message : String(err)}`,
|
|
16240
|
+
hooks: [],
|
|
16241
|
+
path: filePath,
|
|
16242
|
+
transform: { name: filename }
|
|
16243
|
+
});
|
|
16244
|
+
}
|
|
16245
|
+
}
|
|
16246
|
+
return loaded;
|
|
16247
|
+
}
|
|
16248
|
+
function getActiveTransforms(plugins) {
|
|
16249
|
+
return plugins.filter((p) => p.status === "active").map((p) => p.transform);
|
|
16250
|
+
}
|
|
16251
|
+
|
|
15755
16252
|
// src/proxy/betas.ts
|
|
15756
16253
|
var BILLABLE_BETA_PREFIXES_ON_MAX = [
|
|
15757
16254
|
"extended-cache-ttl-"
|
|
@@ -16048,17 +16545,17 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
|
|
|
16048
16545
|
// src/proxy/sessionStore.ts
|
|
16049
16546
|
import {
|
|
16050
16547
|
closeSync,
|
|
16051
|
-
existsSync as
|
|
16548
|
+
existsSync as existsSync4,
|
|
16052
16549
|
mkdirSync,
|
|
16053
16550
|
openSync,
|
|
16054
|
-
readFileSync as
|
|
16551
|
+
readFileSync as readFileSync3,
|
|
16055
16552
|
renameSync,
|
|
16056
16553
|
statSync,
|
|
16057
16554
|
unlinkSync,
|
|
16058
16555
|
writeFileSync
|
|
16059
16556
|
} from "node:fs";
|
|
16060
16557
|
import { homedir as homedir3 } from "node:os";
|
|
16061
|
-
import { join as
|
|
16558
|
+
import { join as join5 } from "node:path";
|
|
16062
16559
|
var DEFAULT_MAX_STORED_SESSIONS = 1e4;
|
|
16063
16560
|
var STALE_LOCK_THRESHOLD_MS = 30000;
|
|
16064
16561
|
function getMaxStoredSessions() {
|
|
@@ -16106,17 +16603,17 @@ var sessionDirOverride = null;
|
|
|
16106
16603
|
var skipLocking = false;
|
|
16107
16604
|
function getStorePath() {
|
|
16108
16605
|
const dir = sessionDirOverride || process.env.MERIDIAN_SESSION_DIR || process.env.CLAUDE_PROXY_SESSION_DIR || getDefaultCacheDir();
|
|
16109
|
-
if (!
|
|
16606
|
+
if (!existsSync4(dir)) {
|
|
16110
16607
|
mkdirSync(dir, { recursive: true });
|
|
16111
16608
|
}
|
|
16112
|
-
return
|
|
16609
|
+
return join5(dir, "sessions.json");
|
|
16113
16610
|
}
|
|
16114
16611
|
function getDefaultCacheDir() {
|
|
16115
|
-
const newDir =
|
|
16116
|
-
const oldDir =
|
|
16117
|
-
if (
|
|
16612
|
+
const newDir = join5(homedir3(), ".cache", "meridian");
|
|
16613
|
+
const oldDir = join5(homedir3(), ".cache", "opencode-claude-max-proxy");
|
|
16614
|
+
if (existsSync4(newDir))
|
|
16118
16615
|
return newDir;
|
|
16119
|
-
if (
|
|
16616
|
+
if (existsSync4(oldDir)) {
|
|
16120
16617
|
try {
|
|
16121
16618
|
const { symlinkSync } = __require("fs");
|
|
16122
16619
|
symlinkSync(oldDir, newDir);
|
|
@@ -16129,10 +16626,10 @@ function getDefaultCacheDir() {
|
|
|
16129
16626
|
}
|
|
16130
16627
|
function readStore() {
|
|
16131
16628
|
const path3 = getStorePath();
|
|
16132
|
-
if (!
|
|
16629
|
+
if (!existsSync4(path3))
|
|
16133
16630
|
return {};
|
|
16134
16631
|
try {
|
|
16135
|
-
const data =
|
|
16632
|
+
const data = readFileSync3(path3, "utf-8");
|
|
16136
16633
|
return JSON.parse(data);
|
|
16137
16634
|
} catch (e) {
|
|
16138
16635
|
console.error("[sessionStore] read failed:", e.message);
|
|
@@ -16631,6 +17128,10 @@ function createProxyServer(config = {}) {
|
|
|
16631
17128
|
const sessionDiscoveredTools = new Map;
|
|
16632
17129
|
const sessionToolCache = new Map;
|
|
16633
17130
|
const sessionMcpCache = new LRUMap(getMaxSessionsLimit());
|
|
17131
|
+
const pluginDir = finalConfig.pluginDir ?? join7(homedir5(), ".config", "meridian", "plugins");
|
|
17132
|
+
const pluginConfigPath = finalConfig.pluginConfigPath ?? join7(homedir5(), ".config", "meridian", "plugins.json");
|
|
17133
|
+
let loadedPlugins = [];
|
|
17134
|
+
let pluginTransforms = [];
|
|
16634
17135
|
const app = new Hono2;
|
|
16635
17136
|
app.use("*", cors());
|
|
16636
17137
|
app.use("/v1/*", requireAuth);
|
|
@@ -16640,6 +17141,8 @@ function createProxyServer(config = {}) {
|
|
|
16640
17141
|
app.use("/metrics", requireAuth);
|
|
16641
17142
|
app.use("/profiles/*", requireAuth);
|
|
16642
17143
|
app.use("/profiles", requireAuth);
|
|
17144
|
+
app.use("/plugins/*", requireAuth);
|
|
17145
|
+
app.use("/plugins", requireAuth);
|
|
16643
17146
|
app.use("/auth/*", requireAuth);
|
|
16644
17147
|
app.get("/", (c) => {
|
|
16645
17148
|
const accept = c.req.header("accept") || "";
|
|
@@ -16697,8 +17200,6 @@ function createProxyServer(config = {}) {
|
|
|
16697
17200
|
const agentMode = c.req.header("x-opencode-agent-mode") ?? null;
|
|
16698
17201
|
const requestSource = c.req.header("x-meridian-source")?.slice(0, 64) || undefined;
|
|
16699
17202
|
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
17203
|
const workingDirectory = (process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR) || adapter.extractWorkingDirectory(body) || process.cwd();
|
|
16703
17204
|
const {
|
|
16704
17205
|
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS,
|
|
@@ -16717,6 +17218,20 @@ function createProxyServer(config = {}) {
|
|
|
16717
17218
|
`);
|
|
16718
17219
|
}
|
|
16719
17220
|
}
|
|
17221
|
+
const adapterTransforms = getAdapterTransforms(adapter.name);
|
|
17222
|
+
const pipeline = buildPipeline(adapterTransforms, pluginTransforms);
|
|
17223
|
+
const pipelineCtx = runTransformHook(pipeline, "onRequest", createRequestContext({
|
|
17224
|
+
adapter: adapter.name,
|
|
17225
|
+
body,
|
|
17226
|
+
headers: c.req.raw.headers,
|
|
17227
|
+
model,
|
|
17228
|
+
messages: body.messages || [],
|
|
17229
|
+
systemContext,
|
|
17230
|
+
tools: body.tools,
|
|
17231
|
+
stream: body.stream ?? false,
|
|
17232
|
+
workingDirectory
|
|
17233
|
+
}), adapter.name);
|
|
17234
|
+
const stream2 = pipelineCtx.prefersStreaming !== undefined ? pipelineCtx.prefersStreaming : body.stream ?? false;
|
|
16720
17235
|
const effortHeader = c.req.header("x-opencode-effort");
|
|
16721
17236
|
const thinkingHeader = c.req.header("x-opencode-thinking");
|
|
16722
17237
|
const taskBudgetHeader = c.req.header("x-opencode-task-budget");
|
|
@@ -16791,14 +17306,14 @@ function createProxyServer(config = {}) {
|
|
|
16791
17306
|
messageCount: Array.isArray(body.messages) ? body.messages.length : 0,
|
|
16792
17307
|
hasSystemPrompt: Boolean(body.system)
|
|
16793
17308
|
});
|
|
16794
|
-
const sdkAgents =
|
|
17309
|
+
const sdkAgents = pipelineCtx.sdkAgents;
|
|
16795
17310
|
const validAgentNames = Object.keys(sdkAgents);
|
|
16796
17311
|
if ((process.env.MERIDIAN_DEBUG ?? process.env.CLAUDE_PROXY_DEBUG) && validAgentNames.length > 0) {
|
|
16797
17312
|
claudeLog("debug.agents", { names: validAgentNames, count: validAgentNames.length });
|
|
16798
17313
|
}
|
|
16799
|
-
systemContext
|
|
17314
|
+
systemContext = pipelineCtx.systemContext ?? systemContext;
|
|
16800
17315
|
const sanitizeOpts = {
|
|
16801
|
-
stripSystemReminder:
|
|
17316
|
+
stripSystemReminder: pipelineCtx.leaksCwdViaSystemReminder
|
|
16802
17317
|
};
|
|
16803
17318
|
const allMessages = body.messages || [];
|
|
16804
17319
|
let messagesToConvert;
|
|
@@ -16862,9 +17377,8 @@ function createProxyServer(config = {}) {
|
|
|
16862
17377
|
|
|
16863
17378
|
`) || "";
|
|
16864
17379
|
}
|
|
16865
|
-
const
|
|
16866
|
-
const
|
|
16867
|
-
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : adapter.getSettingSources?.() ?? [];
|
|
17380
|
+
const passthrough = pipelineCtx.passthrough !== undefined ? pipelineCtx.passthrough : envBool("PASSTHROUGH");
|
|
17381
|
+
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : pipelineCtx.settingSources ?? [];
|
|
16868
17382
|
const capturedToolUses = [];
|
|
16869
17383
|
const fileChanges = [];
|
|
16870
17384
|
let passthroughMcp;
|
|
@@ -16882,7 +17396,7 @@ function createProxyServer(config = {}) {
|
|
|
16882
17396
|
if (cachedMcp && cachedMcp.key === toolSetKey) {
|
|
16883
17397
|
passthroughMcp = cachedMcp.mcp;
|
|
16884
17398
|
} else {
|
|
16885
|
-
passthroughMcp = createPassthroughMcpServer(requestTools,
|
|
17399
|
+
passthroughMcp = createPassthroughMcpServer(requestTools, pipelineCtx.coreToolNames ? [...pipelineCtx.coreToolNames] : undefined);
|
|
16886
17400
|
if (profileSessionId) {
|
|
16887
17401
|
sessionMcpCache.set(profileSessionId, { key: toolSetKey, mcp: passthroughMcp });
|
|
16888
17402
|
if (cachedMcp) {
|
|
@@ -16894,14 +17408,14 @@ function createProxyServer(config = {}) {
|
|
|
16894
17408
|
sessionToolCache.set(profileSessionId, requestTools);
|
|
16895
17409
|
}
|
|
16896
17410
|
const hasDeferredTools = passthroughMcp?.hasDeferredTools ?? false;
|
|
16897
|
-
const coreNames =
|
|
17411
|
+
const coreNames = pipelineCtx.coreToolNames ? [...pipelineCtx.coreToolNames] : undefined;
|
|
16898
17412
|
const coreSet = coreNames ? new Set(coreNames.map((n) => n.toLowerCase())) : undefined;
|
|
16899
17413
|
const deferredToolCount = hasDeferredTools && requestTools.length > 0 ? requestTools.filter((t) => t.defer_loading === true || coreSet && !coreSet.has(String(t.name).toLowerCase())).length : 0;
|
|
16900
17414
|
if (hasDeferredTools) {
|
|
16901
17415
|
console.error(`[PROXY] ${requestMeta.requestId} deferred=${deferredToolCount}/${toolCount} tools (core: ${coreNames?.join(",") ?? "none"})`);
|
|
16902
17416
|
}
|
|
16903
17417
|
const mcpPrefix = `mcp__${adapter.getMcpServerName()}__`;
|
|
16904
|
-
const trackFileChanges = !(process.env.MERIDIAN_NO_FILE_CHANGES ?? process.env.CLAUDE_PROXY_NO_FILE_CHANGES) &&
|
|
17418
|
+
const trackFileChanges = !(process.env.MERIDIAN_NO_FILE_CHANGES ?? process.env.CLAUDE_PROXY_NO_FILE_CHANGES) && pipelineCtx.shouldTrackFileChanges;
|
|
16905
17419
|
const fileChangeHook = trackFileChanges ? createFileChangeHook(fileChanges, mcpPrefix) : undefined;
|
|
16906
17420
|
const discoveredTools = new Set;
|
|
16907
17421
|
const sdkHooks = passthrough ? {
|
|
@@ -16926,7 +17440,7 @@ function createProxyServer(config = {}) {
|
|
|
16926
17440
|
}]
|
|
16927
17441
|
}]
|
|
16928
17442
|
} : {
|
|
16929
|
-
...
|
|
17443
|
+
...pipelineCtx.sdkHooks ?? {},
|
|
16930
17444
|
...fileChangeHook ? { PostToolUse: [fileChangeHook] } : {}
|
|
16931
17445
|
};
|
|
16932
17446
|
const stderrLines = [];
|
|
@@ -16973,7 +17487,10 @@ function createProxyServer(config = {}) {
|
|
|
16973
17487
|
isUndo,
|
|
16974
17488
|
undoRollbackUuid,
|
|
16975
17489
|
sdkHooks,
|
|
16976
|
-
|
|
17490
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17491
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17492
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17493
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
16977
17494
|
onStderr,
|
|
16978
17495
|
effort,
|
|
16979
17496
|
thinking,
|
|
@@ -17027,7 +17544,10 @@ function createProxyServer(config = {}) {
|
|
|
17027
17544
|
isUndo: false,
|
|
17028
17545
|
undoRollbackUuid: undefined,
|
|
17029
17546
|
sdkHooks,
|
|
17030
|
-
|
|
17547
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17548
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17549
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17550
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17031
17551
|
onStderr,
|
|
17032
17552
|
effort,
|
|
17033
17553
|
thinking,
|
|
@@ -17127,7 +17647,7 @@ function createProxyServer(config = {}) {
|
|
|
17127
17647
|
claudeLog("passthrough.toolsearch_filtered", { mode: "non_stream" });
|
|
17128
17648
|
continue;
|
|
17129
17649
|
}
|
|
17130
|
-
if (passthrough && !
|
|
17650
|
+
if (passthrough && !pipelineCtx.supportsThinking && !sdkFeatures.thinkingPassthrough && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
17131
17651
|
claudeLog("passthrough.thinking_stripped", { mode: "non_stream", type: b.type });
|
|
17132
17652
|
continue;
|
|
17133
17653
|
}
|
|
@@ -17191,8 +17711,8 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17191
17711
|
const hasToolUse = contentBlocks.some((b) => b.type === "tool_use");
|
|
17192
17712
|
const stopReason = hasToolUse ? "tool_use" : "end_turn";
|
|
17193
17713
|
if (trackFileChanges) {
|
|
17194
|
-
if (passthrough && stopReason === "end_turn" &&
|
|
17195
|
-
const passthroughChanges = extractFileChangesFromMessages(body.messages || [],
|
|
17714
|
+
if (passthrough && stopReason === "end_turn" && pipelineCtx.extractFileChangesFromToolUse) {
|
|
17715
|
+
const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
|
|
17196
17716
|
fileChanges.push(...passthroughChanges);
|
|
17197
17717
|
}
|
|
17198
17718
|
const fileChangeSummary = formatFileChangeSummary(fileChanges);
|
|
@@ -17227,6 +17747,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17227
17747
|
requestId: requestMeta.requestId,
|
|
17228
17748
|
timestamp: Date.now(),
|
|
17229
17749
|
adapter: adapter.name,
|
|
17750
|
+
requestSource,
|
|
17230
17751
|
model,
|
|
17231
17752
|
requestModel: body.model || undefined,
|
|
17232
17753
|
mode: "non-stream",
|
|
@@ -17342,7 +17863,10 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17342
17863
|
isUndo,
|
|
17343
17864
|
undoRollbackUuid,
|
|
17344
17865
|
sdkHooks,
|
|
17345
|
-
|
|
17866
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17867
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17868
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17869
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17346
17870
|
onStderr,
|
|
17347
17871
|
effort,
|
|
17348
17872
|
thinking,
|
|
@@ -17396,7 +17920,10 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
17396
17920
|
isUndo: false,
|
|
17397
17921
|
undoRollbackUuid: undefined,
|
|
17398
17922
|
sdkHooks,
|
|
17399
|
-
|
|
17923
|
+
blockedTools: pipelineCtx.blockedTools,
|
|
17924
|
+
incompatibleTools: pipelineCtx.incompatibleTools,
|
|
17925
|
+
mcpServerName: adapter.getMcpServerName(),
|
|
17926
|
+
allowedMcpTools: pipelineCtx.allowedMcpTools,
|
|
17400
17927
|
onStderr,
|
|
17401
17928
|
effort,
|
|
17402
17929
|
thinking,
|
|
@@ -17548,7 +18075,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
17548
18075
|
}
|
|
17549
18076
|
if (eventType === "content_block_start") {
|
|
17550
18077
|
const block = event.content_block;
|
|
17551
|
-
if (passthrough && !
|
|
18078
|
+
if (passthrough && !pipelineCtx.supportsThinking && !sdkFeatures.thinkingPassthrough && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
17552
18079
|
if (eventIndex !== undefined)
|
|
17553
18080
|
skipBlockIndices.add(eventIndex);
|
|
17554
18081
|
claudeLog("passthrough.thinking_stripped", { mode: "stream", type: block.type, index: eventIndex });
|
|
@@ -17681,8 +18208,8 @@ data: ${JSON.stringify({
|
|
|
17681
18208
|
|
|
17682
18209
|
`), "passthrough_message_delta");
|
|
17683
18210
|
}
|
|
17684
|
-
if (trackFileChanges && passthrough &&
|
|
17685
|
-
const passthroughChanges = extractFileChangesFromMessages(body.messages || [],
|
|
18211
|
+
if (trackFileChanges && passthrough && pipelineCtx.extractFileChangesFromToolUse) {
|
|
18212
|
+
const passthroughChanges = extractFileChangesFromMessages(body.messages || [], pipelineCtx.extractFileChangesFromToolUse);
|
|
17686
18213
|
fileChanges.push(...passthroughChanges);
|
|
17687
18214
|
}
|
|
17688
18215
|
if (trackFileChanges) {
|
|
@@ -17750,6 +18277,7 @@ data: {"type":"message_stop"}
|
|
|
17750
18277
|
requestId: requestMeta.requestId,
|
|
17751
18278
|
timestamp: Date.now(),
|
|
17752
18279
|
adapter: adapter.name,
|
|
18280
|
+
requestSource,
|
|
17753
18281
|
model,
|
|
17754
18282
|
requestModel: body.model || undefined,
|
|
17755
18283
|
mode: "stream",
|
|
@@ -18005,7 +18533,7 @@ data: ${JSON.stringify({
|
|
|
18005
18533
|
});
|
|
18006
18534
|
});
|
|
18007
18535
|
app.get("/profiles", async (c) => {
|
|
18008
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
18536
|
+
const { profilePageHtml } = await import("./profilePage-77z05e0r.js");
|
|
18009
18537
|
return c.html(profilePageHtml);
|
|
18010
18538
|
});
|
|
18011
18539
|
app.post("/profiles/active", async (c) => {
|
|
@@ -18030,6 +18558,45 @@ data: ${JSON.stringify({
|
|
|
18030
18558
|
console.error(`[PROXY] Active profile switched to: ${body.profile} (session cache cleared)`);
|
|
18031
18559
|
return c.json({ success: true, activeProfile: body.profile });
|
|
18032
18560
|
});
|
|
18561
|
+
app.get("/plugins/list", async (c) => {
|
|
18562
|
+
const { getPluginStats } = await import("./stats-4c4ewmdh.js");
|
|
18563
|
+
return c.json({
|
|
18564
|
+
plugins: loadedPlugins.map((p) => ({
|
|
18565
|
+
name: p.name,
|
|
18566
|
+
description: p.description,
|
|
18567
|
+
version: p.version,
|
|
18568
|
+
adapters: p.adapters,
|
|
18569
|
+
hooks: p.hooks,
|
|
18570
|
+
status: p.status,
|
|
18571
|
+
path: p.path,
|
|
18572
|
+
...p.error ? { error: p.error } : {},
|
|
18573
|
+
...p.status === "active" ? { stats: getPluginStats(p.name) } : {}
|
|
18574
|
+
}))
|
|
18575
|
+
});
|
|
18576
|
+
});
|
|
18577
|
+
app.post("/plugins/reload", async (c) => {
|
|
18578
|
+
try {
|
|
18579
|
+
loadedPlugins = await loadPlugins(pluginDir, pluginConfigPath);
|
|
18580
|
+
pluginTransforms = getActiveTransforms(loadedPlugins);
|
|
18581
|
+
const active = loadedPlugins.filter((p) => p.status === "active").length;
|
|
18582
|
+
console.error(`[PROXY] Plugins reloaded: ${active} active`);
|
|
18583
|
+
return c.json({
|
|
18584
|
+
success: true,
|
|
18585
|
+
plugins: loadedPlugins.map((p) => ({
|
|
18586
|
+
name: p.name,
|
|
18587
|
+
status: p.status,
|
|
18588
|
+
hooks: p.hooks,
|
|
18589
|
+
...p.error ? { error: p.error } : {}
|
|
18590
|
+
}))
|
|
18591
|
+
});
|
|
18592
|
+
} catch (err) {
|
|
18593
|
+
return c.json({ success: false, error: String(err) }, 500);
|
|
18594
|
+
}
|
|
18595
|
+
});
|
|
18596
|
+
app.get("/plugins", async (c) => {
|
|
18597
|
+
const { pluginPageHtml } = await import("./pluginPage-85s6t6k8.js");
|
|
18598
|
+
return c.html(pluginPageHtml);
|
|
18599
|
+
});
|
|
18033
18600
|
app.post("/auth/refresh", async (c) => {
|
|
18034
18601
|
const success = await refreshOAuthToken();
|
|
18035
18602
|
if (success) {
|
|
@@ -18180,11 +18747,27 @@ data: ${JSON.stringify({
|
|
|
18180
18747
|
console.error(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
|
|
18181
18748
|
return c.json({ error: { type: "not_found", message: `Endpoint not supported: ${c.req.method} ${new URL(c.req.url).pathname}` } }, 404);
|
|
18182
18749
|
});
|
|
18183
|
-
|
|
18750
|
+
async function initPluginsAsync() {
|
|
18751
|
+
try {
|
|
18752
|
+
loadedPlugins = await loadPlugins(pluginDir, pluginConfigPath);
|
|
18753
|
+
pluginTransforms = getActiveTransforms(loadedPlugins);
|
|
18754
|
+
if (loadedPlugins.length > 0) {
|
|
18755
|
+
const active = loadedPlugins.filter((p) => p.status === "active").length;
|
|
18756
|
+
const disabled = loadedPlugins.filter((p) => p.status === "disabled").length;
|
|
18757
|
+
const errored = loadedPlugins.filter((p) => p.status === "error").length;
|
|
18758
|
+
console.error(`[PROXY] Plugins loaded: ${active} active, ${disabled} disabled, ${errored} errors`);
|
|
18759
|
+
}
|
|
18760
|
+
} catch (err) {
|
|
18761
|
+
console.error(`[PROXY] Plugin loading failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
18762
|
+
}
|
|
18763
|
+
}
|
|
18764
|
+
return { app, config: finalConfig, initPlugins: initPluginsAsync };
|
|
18184
18765
|
}
|
|
18185
18766
|
async function startProxyServer(config = {}) {
|
|
18186
18767
|
claudeExecutable = await resolveClaudeExecutableAsync();
|
|
18187
|
-
const { app, config: finalConfig } = createProxyServer(config);
|
|
18768
|
+
const { app, config: finalConfig, initPlugins } = createProxyServer(config);
|
|
18769
|
+
if (initPlugins)
|
|
18770
|
+
await initPlugins();
|
|
18188
18771
|
const server = serve({
|
|
18189
18772
|
fetch: app.fetch,
|
|
18190
18773
|
port: finalConfig.port,
|
|
@@ -18245,4 +18828,4 @@ Or use a different port:`);
|
|
|
18245
18828
|
};
|
|
18246
18829
|
}
|
|
18247
18830
|
|
|
18248
|
-
export { computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
|
|
18831
|
+
export { runTransformHook, runObserveHook, buildPipeline, createRequestContext, computeLineageHash, hashMessage, computeMessageHashes, getMaxSessionsLimit, clearSessionCache, createProxyServer, startProxyServer };
|