@rynfar/meridian 1.35.0 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -18
- package/dist/{cli-g9ypdz51.js → cli-pr79d7nw.js} +9 -5
- package/dist/{cli-0kfa6j99.js → cli-ygx1djsx.js} +575 -21
- package/dist/cli.js +2 -2
- package/dist/{profilePage-e90fq8ye.js → profilePage-g5t5t6av.js} +3 -1
- package/dist/proxy/adapter.d.ts +17 -0
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/crush.d.ts.map +1 -1
- package/dist/proxy/auth.d.ts +27 -0
- package/dist/proxy/auth.d.ts.map +1 -0
- package/dist/proxy/errors.d.ts +1 -1
- package/dist/proxy/errors.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +21 -1
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts +56 -0
- package/dist/proxy/sdkFeatures.d.ts.map +1 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/telemetry/profileBar.d.ts +1 -1
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +6 -0
- package/dist/telemetry/settingsPage.d.ts.map +1 -0
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
init_profileBar,
|
|
2
3
|
profileBarCss,
|
|
3
4
|
profileBarHtml,
|
|
4
5
|
profileBarJs
|
|
5
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-pr79d7nw.js";
|
|
6
7
|
import {
|
|
7
8
|
checkPluginConfigured
|
|
8
9
|
} from "./cli-rtab0qa6.js";
|
|
@@ -1148,6 +1149,392 @@ var init_sqlite = __esm(() => {
|
|
|
1148
1149
|
import_libsql = __toESM(require_libsql(), 1);
|
|
1149
1150
|
});
|
|
1150
1151
|
|
|
1152
|
+
// src/proxy/sdkFeatures.ts
|
|
1153
|
+
var exports_sdkFeatures = {};
|
|
1154
|
+
__export(exports_sdkFeatures, {
|
|
1155
|
+
validateFeatureUpdate: () => validateFeatureUpdate,
|
|
1156
|
+
updateAdapterFeatures: () => updateAdapterFeatures,
|
|
1157
|
+
resetAdapterFeatures: () => resetAdapterFeatures,
|
|
1158
|
+
getFeaturesForAdapter: () => getFeaturesForAdapter,
|
|
1159
|
+
getAllFeatureConfigs: () => getAllFeatureConfigs
|
|
1160
|
+
});
|
|
1161
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2 } from "node:fs";
|
|
1162
|
+
import { join as join5 } from "node:path";
|
|
1163
|
+
import { homedir as homedir4 } from "node:os";
|
|
1164
|
+
function getConfigPath() {
|
|
1165
|
+
const dir = join5(homedir4(), ".config", "meridian");
|
|
1166
|
+
if (!existsSync4(dir))
|
|
1167
|
+
mkdirSync2(dir, { recursive: true });
|
|
1168
|
+
return join5(dir, "sdk-features.json");
|
|
1169
|
+
}
|
|
1170
|
+
function readConfig() {
|
|
1171
|
+
const now = Date.now();
|
|
1172
|
+
if (cachedConfig && now - lastReadTime < CACHE_TTL_MS)
|
|
1173
|
+
return cachedConfig;
|
|
1174
|
+
const path3 = getConfigPath();
|
|
1175
|
+
try {
|
|
1176
|
+
if (existsSync4(path3)) {
|
|
1177
|
+
cachedConfig = JSON.parse(readFileSync3(path3, "utf-8"));
|
|
1178
|
+
} else {
|
|
1179
|
+
cachedConfig = {};
|
|
1180
|
+
}
|
|
1181
|
+
} catch {
|
|
1182
|
+
cachedConfig = {};
|
|
1183
|
+
}
|
|
1184
|
+
lastReadTime = now;
|
|
1185
|
+
return cachedConfig;
|
|
1186
|
+
}
|
|
1187
|
+
function writeConfig(config) {
|
|
1188
|
+
const path3 = getConfigPath();
|
|
1189
|
+
const tmp = `${path3}.tmp`;
|
|
1190
|
+
try {
|
|
1191
|
+
writeFileSync2(tmp, JSON.stringify(config, null, 2));
|
|
1192
|
+
renameSync2(tmp, path3);
|
|
1193
|
+
cachedConfig = config;
|
|
1194
|
+
lastReadTime = Date.now();
|
|
1195
|
+
} catch (e) {
|
|
1196
|
+
console.error("[sdk-features] write failed:", e.message);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
function getFeaturesForAdapter(adapterName) {
|
|
1200
|
+
const config = readConfig();
|
|
1201
|
+
const userOverrides = config[adapterName] ?? {};
|
|
1202
|
+
const adapterDefaults = ADAPTER_DEFAULTS[adapterName] ?? {};
|
|
1203
|
+
return {
|
|
1204
|
+
...DEFAULT_FEATURES,
|
|
1205
|
+
...adapterDefaults,
|
|
1206
|
+
...userOverrides
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function getAllFeatureConfigs() {
|
|
1210
|
+
const adapters = ["opencode", "crush", "forgecode", "pi", "droid", "passthrough"];
|
|
1211
|
+
const result = {};
|
|
1212
|
+
for (const name of adapters) {
|
|
1213
|
+
result[name] = getFeaturesForAdapter(name);
|
|
1214
|
+
}
|
|
1215
|
+
return result;
|
|
1216
|
+
}
|
|
1217
|
+
function validateFeatureUpdate(raw2) {
|
|
1218
|
+
if (raw2 === null || typeof raw2 !== "object" || Array.isArray(raw2)) {
|
|
1219
|
+
throw new Error("body must be a JSON object");
|
|
1220
|
+
}
|
|
1221
|
+
const input = raw2;
|
|
1222
|
+
const result = {};
|
|
1223
|
+
for (const [key, value] of Object.entries(input)) {
|
|
1224
|
+
if (!(key in DEFAULT_FEATURES))
|
|
1225
|
+
continue;
|
|
1226
|
+
const expected = typeof DEFAULT_FEATURES[key];
|
|
1227
|
+
if (key === "claudeMd") {
|
|
1228
|
+
if (typeof value !== "string" || !VALID_CLAUDE_MD_VALUES.has(value)) {
|
|
1229
|
+
throw new Error(`claudeMd must be one of: ${[...VALID_CLAUDE_MD_VALUES].join(", ")}`);
|
|
1230
|
+
}
|
|
1231
|
+
result[key] = value;
|
|
1232
|
+
} else if (key === "thinking") {
|
|
1233
|
+
if (typeof value !== "string" || !VALID_THINKING_VALUES.has(value)) {
|
|
1234
|
+
throw new Error(`thinking must be one of: ${[...VALID_THINKING_VALUES].join(", ")}`);
|
|
1235
|
+
}
|
|
1236
|
+
result[key] = value;
|
|
1237
|
+
} else if (expected === "boolean") {
|
|
1238
|
+
if (typeof value !== "boolean")
|
|
1239
|
+
throw new Error(`${key} must be a boolean`);
|
|
1240
|
+
result[key] = value;
|
|
1241
|
+
} else if (expected === "number") {
|
|
1242
|
+
if (typeof value !== "number" || !isFinite(value))
|
|
1243
|
+
throw new Error(`${key} must be a finite number`);
|
|
1244
|
+
result[key] = value;
|
|
1245
|
+
} else if (expected === "string") {
|
|
1246
|
+
if (typeof value !== "string")
|
|
1247
|
+
throw new Error(`${key} must be a string`);
|
|
1248
|
+
result[key] = value;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return result;
|
|
1252
|
+
}
|
|
1253
|
+
function updateAdapterFeatures(adapterName, features) {
|
|
1254
|
+
const config = readConfig();
|
|
1255
|
+
config[adapterName] = { ...config[adapterName] ?? {}, ...features };
|
|
1256
|
+
writeConfig(config);
|
|
1257
|
+
}
|
|
1258
|
+
function resetAdapterFeatures(adapterName) {
|
|
1259
|
+
const config = readConfig();
|
|
1260
|
+
delete config[adapterName];
|
|
1261
|
+
writeConfig(config);
|
|
1262
|
+
}
|
|
1263
|
+
var DEFAULT_FEATURES, ADAPTER_DEFAULTS, cachedConfig = null, lastReadTime = 0, CACHE_TTL_MS = 5000, VALID_CLAUDE_MD_VALUES, VALID_THINKING_VALUES;
|
|
1264
|
+
var init_sdkFeatures = __esm(() => {
|
|
1265
|
+
DEFAULT_FEATURES = {
|
|
1266
|
+
codeSystemPrompt: false,
|
|
1267
|
+
clientSystemPrompt: true,
|
|
1268
|
+
claudeMd: "off",
|
|
1269
|
+
memory: false,
|
|
1270
|
+
dreaming: false,
|
|
1271
|
+
thinking: "disabled",
|
|
1272
|
+
thinkingPassthrough: false,
|
|
1273
|
+
sharedMemory: false,
|
|
1274
|
+
maxBudgetUsd: 0,
|
|
1275
|
+
fallbackModel: "",
|
|
1276
|
+
sdkDebug: false,
|
|
1277
|
+
additionalDirectories: ""
|
|
1278
|
+
};
|
|
1279
|
+
ADAPTER_DEFAULTS = {};
|
|
1280
|
+
VALID_CLAUDE_MD_VALUES = new Set(["off", "project", "full"]);
|
|
1281
|
+
VALID_THINKING_VALUES = new Set(["adaptive", "enabled", "disabled"]);
|
|
1282
|
+
});
|
|
1283
|
+
|
|
1284
|
+
// src/telemetry/settingsPage.ts
|
|
1285
|
+
var exports_settingsPage = {};
|
|
1286
|
+
__export(exports_settingsPage, {
|
|
1287
|
+
settingsPageHtml: () => settingsPageHtml
|
|
1288
|
+
});
|
|
1289
|
+
var settingsPageHtml;
|
|
1290
|
+
var init_settingsPage = __esm(() => {
|
|
1291
|
+
init_profileBar();
|
|
1292
|
+
settingsPageHtml = `<!DOCTYPE html>
|
|
1293
|
+
<html lang="en">
|
|
1294
|
+
<head>
|
|
1295
|
+
<meta charset="utf-8">
|
|
1296
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1297
|
+
<title>Meridian — SDK Features</title>
|
|
1298
|
+
<link rel="icon" type="image/svg+xml" href="/telemetry/icon.svg">
|
|
1299
|
+
<style>
|
|
1300
|
+
:root {
|
|
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
|
+
}
|
|
1306
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1307
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
1308
|
+
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
|
1309
|
+
${profileBarCss}
|
|
1310
|
+
.content { max-width: 900px; margin: 0 auto; padding: 24px; }
|
|
1311
|
+
h1 { font-size: 20px; font-weight: 600; margin-bottom: 4px; }
|
|
1312
|
+
.subtitle { color: var(--muted); font-size: 13px; margin-bottom: 24px; }
|
|
1313
|
+
.nav { display: flex; gap: 16px; margin-bottom: 24px; font-size: 13px; }
|
|
1314
|
+
.nav a { color: var(--muted); text-decoration: none; }
|
|
1315
|
+
.nav a:hover { color: var(--accent); }
|
|
1316
|
+
.nav a.active { color: var(--accent); }
|
|
1317
|
+
|
|
1318
|
+
.adapter-card {
|
|
1319
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
|
|
1320
|
+
padding: 20px; margin-bottom: 16px;
|
|
1321
|
+
}
|
|
1322
|
+
.adapter-header {
|
|
1323
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
1324
|
+
margin-bottom: 16px;
|
|
1325
|
+
}
|
|
1326
|
+
.adapter-name { font-size: 16px; font-weight: 600; }
|
|
1327
|
+
.adapter-badge {
|
|
1328
|
+
font-size: 10px; padding: 2px 8px; border-radius: 10px;
|
|
1329
|
+
text-transform: uppercase; letter-spacing: 0.5px;
|
|
1330
|
+
}
|
|
1331
|
+
.badge-active { background: rgba(63, 185, 80, 0.15); color: var(--green); }
|
|
1332
|
+
.badge-inactive { background: rgba(139, 148, 158, 0.15); color: var(--muted); }
|
|
1333
|
+
|
|
1334
|
+
.feature-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
1335
|
+
@media (max-width: 600px) { .feature-grid { grid-template-columns: 1fr; } }
|
|
1336
|
+
|
|
1337
|
+
.feature-row {
|
|
1338
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
1339
|
+
padding: 10px 14px; border-radius: 6px;
|
|
1340
|
+
background: var(--bg); border: 1px solid var(--border);
|
|
1341
|
+
}
|
|
1342
|
+
.feature-info { display: flex; flex-direction: column; }
|
|
1343
|
+
.feature-label { font-size: 13px; font-weight: 500; }
|
|
1344
|
+
.feature-desc { font-size: 11px; color: var(--muted); margin-top: 2px; }
|
|
1345
|
+
|
|
1346
|
+
/* Toggle switch */
|
|
1347
|
+
.toggle { position: relative; width: 36px; height: 20px; flex-shrink: 0; }
|
|
1348
|
+
.toggle input { opacity: 0; width: 0; height: 0; }
|
|
1349
|
+
.toggle-track {
|
|
1350
|
+
position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0;
|
|
1351
|
+
background: var(--border); border-radius: 10px; transition: background 0.2s;
|
|
1352
|
+
}
|
|
1353
|
+
.toggle-track::after {
|
|
1354
|
+
content: ""; position: absolute; height: 14px; width: 14px;
|
|
1355
|
+
left: 3px; bottom: 3px; background: var(--muted); border-radius: 50%;
|
|
1356
|
+
transition: transform 0.2s, background 0.2s;
|
|
1357
|
+
}
|
|
1358
|
+
.toggle input:checked + .toggle-track { background: var(--accent); }
|
|
1359
|
+
.toggle input:checked + .toggle-track::after {
|
|
1360
|
+
transform: translateX(16px); background: var(--text);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/* Select dropdown */
|
|
1364
|
+
.feature-select {
|
|
1365
|
+
background: var(--surface); color: var(--text); border: 1px solid var(--border);
|
|
1366
|
+
border-radius: 6px; padding: 4px 8px; font-size: 12px; cursor: pointer;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.save-indicator {
|
|
1370
|
+
position: fixed; bottom: 24px; right: 24px;
|
|
1371
|
+
background: var(--green); color: #000; padding: 8px 16px;
|
|
1372
|
+
border-radius: 6px; font-size: 13px; font-weight: 500;
|
|
1373
|
+
opacity: 0; transition: opacity 0.3s; pointer-events: none;
|
|
1374
|
+
}
|
|
1375
|
+
.save-indicator.visible { opacity: 1; }
|
|
1376
|
+
|
|
1377
|
+
.reset-btn {
|
|
1378
|
+
background: none; border: 1px solid var(--border); color: var(--muted);
|
|
1379
|
+
border-radius: 6px; padding: 4px 12px; font-size: 11px; cursor: pointer;
|
|
1380
|
+
}
|
|
1381
|
+
.reset-btn:hover { border-color: var(--red); color: var(--red); }
|
|
1382
|
+
</style>
|
|
1383
|
+
</head>
|
|
1384
|
+
<body>
|
|
1385
|
+
${profileBarHtml}
|
|
1386
|
+
<div class="content">
|
|
1387
|
+
<h1>SDK Features <span style="font-size:11px;padding:2px 8px;border-radius:10px;background:rgba(210,153,34,0.15);color:var(--yellow);vertical-align:middle;margin-left:8px">Experimental</span></h1>
|
|
1388
|
+
<p class="subtitle" style="max-width:720px;line-height:1.6">
|
|
1389
|
+
Unlock Claude Code features for any connected agent. Capabilities like auto-memory, dreaming, and CLAUDE.md — normally
|
|
1390
|
+
exclusive to Claude Code — become available to OpenCode, Crush, Droid, and any other harness routed through Meridian.
|
|
1391
|
+
Each agent keeps its own toolchain while gaining access to these additional features.<br><br>
|
|
1392
|
+
<strong style="color:var(--text)">System prompts:</strong> For these features to work correctly, both the Claude Code prompt and your client prompt
|
|
1393
|
+
should be enabled. When both are active, they are appended together — Claude Code's base instructions come first,
|
|
1394
|
+
followed by your agent's specific instructions.
|
|
1395
|
+
</p>
|
|
1396
|
+
|
|
1397
|
+
<div id="adapters"></div>
|
|
1398
|
+
</div>
|
|
1399
|
+
|
|
1400
|
+
<div class="save-indicator" id="saveIndicator">Saved</div>
|
|
1401
|
+
|
|
1402
|
+
<script>
|
|
1403
|
+
const FEATURES = [
|
|
1404
|
+
{ key: 'codeSystemPrompt', label: 'Claude Code Prompt', desc: 'Include the built-in Claude Code system prompt (tool usage rules, safety guidelines, coding best practices)', type: 'toggle' },
|
|
1405
|
+
{ key: 'clientSystemPrompt', label: 'Client Prompt', desc: 'Include the system prompt sent by the connecting agent (e.g. OpenCode or Crush instructions)', type: 'toggle' },
|
|
1406
|
+
{ key: 'claudeMd', label: 'CLAUDE.md', desc: 'Load CLAUDE.md instruction files — Off: none, Project: ./CLAUDE.md only, Full: ~/.claude/CLAUDE.md + ./CLAUDE.md', type: 'select', options: ['off', 'project', 'full'] },
|
|
1407
|
+
{ key: 'memory', label: 'Memory', desc: 'Read and write memories across sessions', type: 'toggle' },
|
|
1408
|
+
{ key: 'dreaming', label: 'Auto-Dream', desc: 'Background memory consolidation', type: 'toggle' },
|
|
1409
|
+
{ key: 'thinking', label: 'Thinking', desc: 'Extended thinking mode', type: 'select', options: ['disabled', 'adaptive', 'enabled'] },
|
|
1410
|
+
{ key: 'thinkingPassthrough', label: 'Thinking Passthrough', desc: 'Forward thinking blocks to the client', type: 'toggle' },
|
|
1411
|
+
{ key: 'sharedMemory', label: 'Shared Memory', desc: 'Share memory with Claude Code (~/.claude) instead of isolated storage', type: 'toggle' },
|
|
1412
|
+
{ key: 'maxBudgetUsd', label: 'Max Budget (USD)', desc: 'Per-request cost cap — query aborts if exceeded (0 = disabled)', type: 'number' },
|
|
1413
|
+
{ key: 'fallbackModel', label: 'Fallback Model', desc: 'Auto-fallback model if primary fails', type: 'select', options: ['', 'sonnet', 'opus', 'haiku', 'sonnet[1m]', 'opus[1m]'] },
|
|
1414
|
+
{ key: 'sdkDebug', label: 'SDK Debug Logging', desc: 'Enable verbose SDK debug output to proxy stderr', type: 'toggle' },
|
|
1415
|
+
{ key: 'additionalDirectories', label: 'Additional Directories', desc: 'Comma-separated extra paths Claude can access (monorepo libs, etc.)', type: 'text' },
|
|
1416
|
+
];
|
|
1417
|
+
|
|
1418
|
+
const ADAPTER_LABELS = {
|
|
1419
|
+
opencode: 'OpenCode',
|
|
1420
|
+
crush: 'Crush',
|
|
1421
|
+
forgecode: 'ForgeCode',
|
|
1422
|
+
pi: 'Pi',
|
|
1423
|
+
droid: 'Droid',
|
|
1424
|
+
passthrough: 'LiteLLM / Passthrough',
|
|
1425
|
+
};
|
|
1426
|
+
|
|
1427
|
+
let currentConfig = {};
|
|
1428
|
+
|
|
1429
|
+
async function loadConfig() {
|
|
1430
|
+
const res = await fetch('/settings/api/features');
|
|
1431
|
+
currentConfig = await res.json();
|
|
1432
|
+
render();
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
async function saveFeature(adapter, key, value) {
|
|
1436
|
+
const patch = {};
|
|
1437
|
+
patch[key] = value;
|
|
1438
|
+
await fetch('/settings/api/features/' + adapter, {
|
|
1439
|
+
method: 'PATCH',
|
|
1440
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1441
|
+
body: JSON.stringify(patch),
|
|
1442
|
+
});
|
|
1443
|
+
currentConfig[adapter][key] = value;
|
|
1444
|
+
showSaved();
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
async function resetAdapter(adapter) {
|
|
1448
|
+
await fetch('/settings/api/features/' + adapter, { method: 'DELETE' });
|
|
1449
|
+
await loadConfig();
|
|
1450
|
+
showSaved();
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
function showSaved() {
|
|
1454
|
+
const el = document.getElementById('saveIndicator');
|
|
1455
|
+
el.classList.add('visible');
|
|
1456
|
+
setTimeout(() => el.classList.remove('visible'), 1500);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
function hasAnyEnabled(features) {
|
|
1460
|
+
return features.codeSystemPrompt || !features.clientSystemPrompt || features.claudeMd !== 'off' || features.memory || features.dreaming ||
|
|
1461
|
+
features.thinking !== 'disabled' || features.thinkingPassthrough ||
|
|
1462
|
+
features.sharedMemory || features.maxBudgetUsd > 0 ||
|
|
1463
|
+
features.fallbackModel || features.sdkDebug ||
|
|
1464
|
+
features.additionalDirectories;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
function render() {
|
|
1468
|
+
const container = document.getElementById('adapters');
|
|
1469
|
+
container.innerHTML = '';
|
|
1470
|
+
|
|
1471
|
+
for (const [adapter, label] of Object.entries(ADAPTER_LABELS)) {
|
|
1472
|
+
const features = currentConfig[adapter] || {};
|
|
1473
|
+
const active = hasAnyEnabled(features);
|
|
1474
|
+
|
|
1475
|
+
const card = document.createElement('div');
|
|
1476
|
+
card.className = 'adapter-card';
|
|
1477
|
+
card.innerHTML = '<div class="adapter-header">' +
|
|
1478
|
+
'<span class="adapter-name">' + label + '</span>' +
|
|
1479
|
+
'<div style="display:flex;gap:8px;align-items:center">' +
|
|
1480
|
+
'<span class="adapter-badge ' + (active ? 'badge-active' : 'badge-inactive') + '">' +
|
|
1481
|
+
(active ? 'Active' : 'Default') +
|
|
1482
|
+
'</span>' +
|
|
1483
|
+
'<button class="reset-btn" onclick="resetAdapter(\\''+adapter+'\\')">Reset</button>' +
|
|
1484
|
+
'</div>' +
|
|
1485
|
+
'</div>';
|
|
1486
|
+
|
|
1487
|
+
const grid = document.createElement('div');
|
|
1488
|
+
grid.className = 'feature-grid';
|
|
1489
|
+
|
|
1490
|
+
for (const feat of FEATURES) {
|
|
1491
|
+
const row = document.createElement('div');
|
|
1492
|
+
row.className = 'feature-row';
|
|
1493
|
+
|
|
1494
|
+
const info = '<div class="feature-info"><span class="feature-label">' +
|
|
1495
|
+
feat.label + '</span><span class="feature-desc">' + feat.desc + '</span></div>';
|
|
1496
|
+
|
|
1497
|
+
if (feat.type === 'toggle') {
|
|
1498
|
+
const checked = features[feat.key] ? 'checked' : '';
|
|
1499
|
+
row.innerHTML = info +
|
|
1500
|
+
'<label class="toggle"><input type="checkbox" ' + checked +
|
|
1501
|
+
' onchange="saveFeature(\\''+adapter+'\\', \\''+feat.key+'\\', this.checked)">' +
|
|
1502
|
+
'<span class="toggle-track"></span></label>';
|
|
1503
|
+
} else if (feat.type === 'select') {
|
|
1504
|
+
const options = feat.options.map(o => {
|
|
1505
|
+
const label = o === '' ? '(None)' : o.charAt(0).toUpperCase()+o.slice(1);
|
|
1506
|
+
return '<option value="'+o+'"'+(features[feat.key]===o?' selected':'')+'>'+label+'</option>';
|
|
1507
|
+
}).join('');
|
|
1508
|
+
row.innerHTML = info +
|
|
1509
|
+
'<select class="feature-select" onchange="saveFeature(\\''+adapter+'\\', \\''+feat.key+'\\', this.value)">' +
|
|
1510
|
+
options + '</select>';
|
|
1511
|
+
} else if (feat.type === 'number') {
|
|
1512
|
+
const value = features[feat.key] ?? 0;
|
|
1513
|
+
row.innerHTML = info +
|
|
1514
|
+
'<input type="number" class="feature-select" style="width:80px;text-align:right" min="0" step="0.01" value="'+value+'"' +
|
|
1515
|
+
' onchange="saveFeature(\\''+adapter+'\\', \\''+feat.key+'\\', parseFloat(this.value)||0)">';
|
|
1516
|
+
} else if (feat.type === 'text') {
|
|
1517
|
+
const value = (features[feat.key] ?? '').toString().replace(/"/g, '"');
|
|
1518
|
+
row.innerHTML = info +
|
|
1519
|
+
'<input type="text" class="feature-select" style="width:180px" value="'+value+'"' +
|
|
1520
|
+
' onchange="saveFeature(\\''+adapter+'\\', \\''+feat.key+'\\', this.value)">';
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
grid.appendChild(row);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
card.appendChild(grid);
|
|
1527
|
+
container.appendChild(card);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
loadConfig();
|
|
1532
|
+
${profileBarJs}
|
|
1533
|
+
</script>
|
|
1534
|
+
</body>
|
|
1535
|
+
</html>`;
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1151
1538
|
// node_modules/hono/dist/compose.js
|
|
1152
1539
|
var compose = (middleware, onError, onNotFound) => {
|
|
1153
1540
|
return (context, next) => {
|
|
@@ -7532,6 +7919,7 @@ import { resolve, dirname } from "node:path";
|
|
|
7532
7919
|
import { fileURLToPath } from "node:url";
|
|
7533
7920
|
|
|
7534
7921
|
// src/telemetry/dashboard.ts
|
|
7922
|
+
init_profileBar();
|
|
7535
7923
|
var dashboardHtml = `<!DOCTYPE html>
|
|
7536
7924
|
<html lang="en">
|
|
7537
7925
|
<head>
|
|
@@ -7929,6 +8317,7 @@ function createTelemetryRoutes() {
|
|
|
7929
8317
|
return routes;
|
|
7930
8318
|
}
|
|
7931
8319
|
// src/telemetry/landing.ts
|
|
8320
|
+
init_profileBar();
|
|
7932
8321
|
var landingHtml = `<!DOCTYPE html>
|
|
7933
8322
|
<html lang="en">
|
|
7934
8323
|
<head>
|
|
@@ -8041,7 +8430,7 @@ function render(h,s){
|
|
|
8041
8430
|
o+='</div>';
|
|
8042
8431
|
if(s.byModel&&Object.keys(s.byModel).length>0){o+='<div class="section"><div class="section-title">Models (24h)</div><div class="grid">';for(const[n,d]of Object.entries(s.byModel))o+=card(n,d.count,'avg '+ms(d.avgTotalMs),'');o+='</div></div>'}
|
|
8043
8432
|
o+='<div class="section"><div class="section-title">Connect an Agent</div><div class="snippet"><div class="snippet-tabs"><div class="snippet-tab active" onclick="showTab(this,'opencode')">OpenCode</div><div class="snippet-tab" onclick="showTab(this,'crush')">Crush</div><div class="snippet-tab" onclick="showTab(this,'generic')">Any Tool</div></div><div id="tab-opencode"><code>ANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http://'+location.host+' opencode</code></div><div id="tab-crush" style="display:none"><code>'+JSON.stringify({providers:{meridian:{type:"anthropic",base_url:"http://"+location.host,api_key:"x",models:[{id:"claude-sonnet-4-5-20250514",name:"Sonnet 4.5"}]}}},null,2)+'</code></div><div id="tab-generic" style="display:none"><code>export ANTHROPIC_API_KEY=x\\nexport ANTHROPIC_BASE_URL=http://'+location.host+'</code></div></div></div>';
|
|
8044
|
-
o+='<div class="links"><a href="/telemetry" class="link">\uD83D\uDCCA Telemetry</a><a href="/profiles" class="link">\uD83D\uDC64 Profiles</a><a href="/health" class="link">\uD83E\uDE7A Health</a><a href="/telemetry/summary" class="link">\uD83D\uDCC8 Stats API</a><a href="https://github.com/rynfar/meridian" class="link">⚙️ GitHub</a></div>';
|
|
8433
|
+
o+='<div class="links"><a href="/telemetry" class="link">\uD83D\uDCCA Telemetry</a><a href="/settings" class="link">\uD83D\uDD27 Settings</a><a href="/profiles" class="link">\uD83D\uDC64 Profiles</a><a href="/health" class="link">\uD83E\uDE7A Health</a><a href="/telemetry/summary" class="link">\uD83D\uDCC8 Stats API</a><a href="https://github.com/rynfar/meridian" class="link">⚙️ GitHub</a></div>';
|
|
8045
8434
|
o+='<div class="footer">Meridian · Built on the <a href="https://github.com/anthropics/claude-code-sdk-js">Claude Code SDK</a></div>';
|
|
8046
8435
|
document.getElementById('content').innerHTML=o;
|
|
8047
8436
|
}
|
|
@@ -8232,7 +8621,8 @@ function isExpiredTokenError(errMsg) {
|
|
|
8232
8621
|
function isStaleSessionError(error) {
|
|
8233
8622
|
if (!(error instanceof Error))
|
|
8234
8623
|
return false;
|
|
8235
|
-
|
|
8624
|
+
const msg = error.message;
|
|
8625
|
+
return msg.includes("No message found with message.uuid") || msg.includes("No conversation found with session ID") || msg.includes("No conversation found to continue") || msg.includes("No conversations found to resume");
|
|
8236
8626
|
}
|
|
8237
8627
|
function isRateLimitError(errMsg) {
|
|
8238
8628
|
const lower = errMsg.toLowerCase();
|
|
@@ -8605,6 +8995,42 @@ function getLastUserMessage(messages) {
|
|
|
8605
8995
|
return messages.slice(-1);
|
|
8606
8996
|
}
|
|
8607
8997
|
|
|
8998
|
+
// src/proxy/auth.ts
|
|
8999
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
9000
|
+
function getConfiguredKey() {
|
|
9001
|
+
return process.env.MERIDIAN_API_KEY || undefined;
|
|
9002
|
+
}
|
|
9003
|
+
function safeCompare(a, b) {
|
|
9004
|
+
const hashA = createHmac("sha256", "meridian").update(a).digest();
|
|
9005
|
+
const hashB = createHmac("sha256", "meridian").update(b).digest();
|
|
9006
|
+
return timingSafeEqual(hashA, hashB);
|
|
9007
|
+
}
|
|
9008
|
+
function extractKey(c) {
|
|
9009
|
+
const apiKey = c.req.header("x-api-key");
|
|
9010
|
+
if (apiKey)
|
|
9011
|
+
return apiKey;
|
|
9012
|
+
const auth = c.req.header("authorization");
|
|
9013
|
+
if (auth?.startsWith("Bearer "))
|
|
9014
|
+
return auth.slice(7);
|
|
9015
|
+
return;
|
|
9016
|
+
}
|
|
9017
|
+
async function requireAuth(c, next) {
|
|
9018
|
+
const key = getConfiguredKey();
|
|
9019
|
+
if (!key)
|
|
9020
|
+
return next();
|
|
9021
|
+
const provided = extractKey(c);
|
|
9022
|
+
if (!provided || !safeCompare(provided, key)) {
|
|
9023
|
+
return c.json({
|
|
9024
|
+
type: "error",
|
|
9025
|
+
error: {
|
|
9026
|
+
type: "authentication_error",
|
|
9027
|
+
message: "Invalid or missing API key"
|
|
9028
|
+
}
|
|
9029
|
+
}, 401);
|
|
9030
|
+
}
|
|
9031
|
+
return next();
|
|
9032
|
+
}
|
|
9033
|
+
|
|
8608
9034
|
// src/proxy/fileChanges.ts
|
|
8609
9035
|
function extractFileChange(toolName, toolInput, mcpPrefix) {
|
|
8610
9036
|
if (!toolName.startsWith(mcpPrefix))
|
|
@@ -9091,6 +9517,9 @@ var crushAdapter = {
|
|
|
9091
9517
|
buildSystemContextAddendum(_body, _sdkAgents) {
|
|
9092
9518
|
return "";
|
|
9093
9519
|
},
|
|
9520
|
+
supportsThinking() {
|
|
9521
|
+
return true;
|
|
9522
|
+
},
|
|
9094
9523
|
extractFileChangesFromToolUse(toolName, toolInput) {
|
|
9095
9524
|
const input = toolInput;
|
|
9096
9525
|
const filePath = input?.file_path ?? input?.path;
|
|
@@ -9375,6 +9804,10 @@ function detectAdapter(c) {
|
|
|
9375
9804
|
return defaultAdapter;
|
|
9376
9805
|
}
|
|
9377
9806
|
|
|
9807
|
+
// src/proxy/query.ts
|
|
9808
|
+
import { join as join3 } from "node:path";
|
|
9809
|
+
import { homedir as homedir2 } from "node:os";
|
|
9810
|
+
|
|
9378
9811
|
// src/mcpTools.ts
|
|
9379
9812
|
import { createSdkMcpServer as createSdkMcpServer2, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
9380
9813
|
import * as fs from "node:fs/promises";
|
|
@@ -15067,6 +15500,18 @@ function createOpencodeMcpServer() {
|
|
|
15067
15500
|
}
|
|
15068
15501
|
|
|
15069
15502
|
// src/proxy/query.ts
|
|
15503
|
+
function resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt) {
|
|
15504
|
+
const hasSettings = settingSources != null && settingSources.length > 0;
|
|
15505
|
+
const usePreset = codeSystemPrompt ?? (hasSettings || !passthrough && !!systemContext);
|
|
15506
|
+
const includeClient = clientSystemPrompt ?? true;
|
|
15507
|
+
const clientContext = includeClient ? systemContext : undefined;
|
|
15508
|
+
if (usePreset) {
|
|
15509
|
+
return clientContext ? { systemPrompt: { type: "preset", preset: "claude_code", append: clientContext } } : { systemPrompt: { type: "preset", preset: "claude_code" } };
|
|
15510
|
+
}
|
|
15511
|
+
if (clientContext)
|
|
15512
|
+
return { systemPrompt: clientContext };
|
|
15513
|
+
return {};
|
|
15514
|
+
}
|
|
15070
15515
|
function buildQueryOptions(ctx) {
|
|
15071
15516
|
const {
|
|
15072
15517
|
prompt,
|
|
@@ -15089,7 +15534,17 @@ function buildQueryOptions(ctx) {
|
|
|
15089
15534
|
effort,
|
|
15090
15535
|
thinking,
|
|
15091
15536
|
taskBudget,
|
|
15092
|
-
betas
|
|
15537
|
+
betas,
|
|
15538
|
+
settingSources,
|
|
15539
|
+
codeSystemPrompt,
|
|
15540
|
+
clientSystemPrompt,
|
|
15541
|
+
memory,
|
|
15542
|
+
dreaming,
|
|
15543
|
+
sharedMemory,
|
|
15544
|
+
maxBudgetUsd,
|
|
15545
|
+
fallbackModel,
|
|
15546
|
+
sdkDebug,
|
|
15547
|
+
additionalDirectories
|
|
15093
15548
|
} = ctx;
|
|
15094
15549
|
const blockedTools = [...adapter.getBlockedBuiltinTools(), ...adapter.getAgentIncompatibleTools()];
|
|
15095
15550
|
const mcpServerName = adapter.getMcpServerName();
|
|
@@ -15105,9 +15560,7 @@ function buildQueryOptions(ctx) {
|
|
|
15105
15560
|
...stream2 ? { includePartialMessages: true } : {},
|
|
15106
15561
|
permissionMode: "bypassPermissions",
|
|
15107
15562
|
allowDangerouslySkipPermissions: true,
|
|
15108
|
-
...systemContext
|
|
15109
|
-
systemPrompt: passthrough ? systemContext : { type: "preset", preset: "claude_code", append: systemContext }
|
|
15110
|
-
} : {},
|
|
15563
|
+
...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt),
|
|
15111
15564
|
...passthrough ? {
|
|
15112
15565
|
disallowedTools: blockedTools,
|
|
15113
15566
|
...passthroughMcp ? {
|
|
@@ -15120,11 +15573,19 @@ function buildQueryOptions(ctx) {
|
|
|
15120
15573
|
mcpServers: { [mcpServerName]: createOpencodeMcpServer() }
|
|
15121
15574
|
},
|
|
15122
15575
|
plugins: [],
|
|
15576
|
+
...settingSources && settingSources.length > 0 ? {
|
|
15577
|
+
settingSources,
|
|
15578
|
+
settings: {
|
|
15579
|
+
autoMemoryEnabled: ctx.memory ?? true,
|
|
15580
|
+
autoDreamEnabled: ctx.dreaming ?? false
|
|
15581
|
+
}
|
|
15582
|
+
} : {},
|
|
15123
15583
|
...onStderr ? { stderr: onStderr } : {},
|
|
15124
15584
|
env: {
|
|
15125
15585
|
...cleanEnv,
|
|
15126
15586
|
ENABLE_TOOL_SEARCH: hasDeferredTools ? "true" : "false",
|
|
15127
15587
|
...passthrough ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {},
|
|
15588
|
+
...sharedMemory ? { CLAUDE_CONFIG_DIR: join3(homedir2(), ".claude") } : {},
|
|
15128
15589
|
...process.getuid?.() === 0 ? { IS_SANDBOX: "1" } : {}
|
|
15129
15590
|
},
|
|
15130
15591
|
...Object.keys(sdkAgents).length > 0 ? { agents: sdkAgents } : {},
|
|
@@ -15134,7 +15595,11 @@ function buildQueryOptions(ctx) {
|
|
|
15134
15595
|
...effort ? { effort } : {},
|
|
15135
15596
|
...thinking ? { thinking } : {},
|
|
15136
15597
|
...taskBudget ? { taskBudget } : {},
|
|
15137
|
-
...betas && betas.length > 0 ? { betas } : {}
|
|
15598
|
+
...betas && betas.length > 0 ? { betas } : {},
|
|
15599
|
+
...maxBudgetUsd && maxBudgetUsd > 0 ? { maxBudgetUsd } : {},
|
|
15600
|
+
...fallbackModel ? { fallbackModel } : {},
|
|
15601
|
+
...sdkDebug ? { debug: true } : {},
|
|
15602
|
+
...additionalDirectories && additionalDirectories.length > 0 ? { additionalDirectories } : {}
|
|
15138
15603
|
}
|
|
15139
15604
|
};
|
|
15140
15605
|
}
|
|
@@ -15505,8 +15970,8 @@ import {
|
|
|
15505
15970
|
unlinkSync,
|
|
15506
15971
|
writeFileSync
|
|
15507
15972
|
} from "node:fs";
|
|
15508
|
-
import { homedir as
|
|
15509
|
-
import { join as
|
|
15973
|
+
import { homedir as homedir3 } from "node:os";
|
|
15974
|
+
import { join as join4 } from "node:path";
|
|
15510
15975
|
var DEFAULT_MAX_STORED_SESSIONS = 1e4;
|
|
15511
15976
|
var STALE_LOCK_THRESHOLD_MS = 30000;
|
|
15512
15977
|
function getMaxStoredSessions() {
|
|
@@ -15557,11 +16022,11 @@ function getStorePath() {
|
|
|
15557
16022
|
if (!existsSync3(dir)) {
|
|
15558
16023
|
mkdirSync(dir, { recursive: true });
|
|
15559
16024
|
}
|
|
15560
|
-
return
|
|
16025
|
+
return join4(dir, "sessions.json");
|
|
15561
16026
|
}
|
|
15562
16027
|
function getDefaultCacheDir() {
|
|
15563
|
-
const newDir =
|
|
15564
|
-
const oldDir =
|
|
16028
|
+
const newDir = join4(homedir3(), ".cache", "meridian");
|
|
16029
|
+
const oldDir = join4(homedir3(), ".cache", "opencode-claude-max-proxy");
|
|
15565
16030
|
if (existsSync3(newDir))
|
|
15566
16031
|
return newDir;
|
|
15567
16032
|
if (existsSync3(oldDir)) {
|
|
@@ -16028,6 +16493,14 @@ function createProxyServer(config = {}) {
|
|
|
16028
16493
|
const sessionDiscoveredTools = new Map;
|
|
16029
16494
|
const app = new Hono2;
|
|
16030
16495
|
app.use("*", cors());
|
|
16496
|
+
app.use("/v1/*", requireAuth);
|
|
16497
|
+
app.use("/messages", requireAuth);
|
|
16498
|
+
app.use("/telemetry/*", requireAuth);
|
|
16499
|
+
app.use("/telemetry", requireAuth);
|
|
16500
|
+
app.use("/metrics", requireAuth);
|
|
16501
|
+
app.use("/profiles/*", requireAuth);
|
|
16502
|
+
app.use("/profiles", requireAuth);
|
|
16503
|
+
app.use("/auth/*", requireAuth);
|
|
16031
16504
|
app.get("/", (c) => {
|
|
16032
16505
|
const accept = c.req.header("accept") || "";
|
|
16033
16506
|
if (accept.includes("application/json") && !accept.includes("text/html")) {
|
|
@@ -16130,6 +16603,14 @@ function createProxyServer(config = {}) {
|
|
|
16130
16603
|
console.error(`[PROXY] ${requestMeta.requestId} ignoring malformed x-opencode-thinking header: ${e instanceof Error ? e.message : String(e)}`);
|
|
16131
16604
|
}
|
|
16132
16605
|
}
|
|
16606
|
+
const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
16607
|
+
const sdkFeatures = getFeaturesForAdapter2(adapter.name);
|
|
16608
|
+
if (!thinking) {
|
|
16609
|
+
if (sdkFeatures.thinking === "adaptive")
|
|
16610
|
+
thinking = { type: "adaptive" };
|
|
16611
|
+
else if (sdkFeatures.thinking === "enabled")
|
|
16612
|
+
thinking = { type: "enabled" };
|
|
16613
|
+
}
|
|
16133
16614
|
const thinkingBetaStripped = betaFilter.stripped.some((b) => b.startsWith("interleaved-thinking"));
|
|
16134
16615
|
if (thinkingBetaStripped) {
|
|
16135
16616
|
thinking = { type: "disabled" };
|
|
@@ -16282,6 +16763,7 @@ function createProxyServer(config = {}) {
|
|
|
16282
16763
|
}
|
|
16283
16764
|
const adapterPassthrough = adapter.usesPassthrough?.();
|
|
16284
16765
|
const passthrough = adapterPassthrough !== undefined ? adapterPassthrough : envBool("PASSTHROUGH");
|
|
16766
|
+
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : adapter.getSettingSources?.() ?? [];
|
|
16285
16767
|
const capturedToolUses = [];
|
|
16286
16768
|
const fileChanges = [];
|
|
16287
16769
|
let passthroughMcp;
|
|
@@ -16373,7 +16855,17 @@ function createProxyServer(config = {}) {
|
|
|
16373
16855
|
effort,
|
|
16374
16856
|
thinking,
|
|
16375
16857
|
taskBudget,
|
|
16376
|
-
betas
|
|
16858
|
+
betas,
|
|
16859
|
+
settingSources,
|
|
16860
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
16861
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
16862
|
+
memory: sdkFeatures.memory,
|
|
16863
|
+
dreaming: sdkFeatures.dreaming,
|
|
16864
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
16865
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
16866
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
16867
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
16868
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16377
16869
|
}))) {
|
|
16378
16870
|
if (event.type === "assistant" && !event.error) {
|
|
16379
16871
|
didYieldContent = true;
|
|
@@ -16417,7 +16909,17 @@ function createProxyServer(config = {}) {
|
|
|
16417
16909
|
effort,
|
|
16418
16910
|
thinking,
|
|
16419
16911
|
taskBudget,
|
|
16420
|
-
betas
|
|
16912
|
+
betas,
|
|
16913
|
+
settingSources,
|
|
16914
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
16915
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
16916
|
+
memory: sdkFeatures.memory,
|
|
16917
|
+
dreaming: sdkFeatures.dreaming,
|
|
16918
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
16919
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
16920
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
16921
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
16922
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16421
16923
|
}));
|
|
16422
16924
|
return;
|
|
16423
16925
|
}
|
|
@@ -16502,7 +17004,7 @@ function createProxyServer(config = {}) {
|
|
|
16502
17004
|
claudeLog("passthrough.toolsearch_filtered", { mode: "non_stream" });
|
|
16503
17005
|
continue;
|
|
16504
17006
|
}
|
|
16505
|
-
if (passthrough && !adapter.supportsThinking?.() && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
17007
|
+
if (passthrough && !adapter.supportsThinking?.() && !sdkFeatures.thinkingPassthrough && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
16506
17008
|
claudeLog("passthrough.thinking_stripped", { mode: "non_stream", type: b.type });
|
|
16507
17009
|
continue;
|
|
16508
17010
|
}
|
|
@@ -16641,7 +17143,12 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16641
17143
|
content: contentBlocks,
|
|
16642
17144
|
model: body.model,
|
|
16643
17145
|
stop_reason: stopReason,
|
|
16644
|
-
usage: {
|
|
17146
|
+
usage: {
|
|
17147
|
+
input_tokens: lastUsage?.input_tokens ?? 0,
|
|
17148
|
+
output_tokens: lastUsage?.output_tokens ?? 0,
|
|
17149
|
+
cache_read_input_tokens: lastUsage?.cache_read_input_tokens,
|
|
17150
|
+
cache_creation_input_tokens: lastUsage?.cache_creation_input_tokens
|
|
17151
|
+
}
|
|
16645
17152
|
}), {
|
|
16646
17153
|
headers: {
|
|
16647
17154
|
"Content-Type": "application/json",
|
|
@@ -16717,7 +17224,17 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16717
17224
|
effort,
|
|
16718
17225
|
thinking,
|
|
16719
17226
|
taskBudget,
|
|
16720
|
-
betas
|
|
17227
|
+
betas,
|
|
17228
|
+
settingSources,
|
|
17229
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
17230
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
17231
|
+
memory: sdkFeatures.memory,
|
|
17232
|
+
dreaming: sdkFeatures.dreaming,
|
|
17233
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
17234
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17235
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
17236
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
17237
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16721
17238
|
}))) {
|
|
16722
17239
|
if (event.type === "stream_event") {
|
|
16723
17240
|
didYieldClientEvent = true;
|
|
@@ -16761,7 +17278,17 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16761
17278
|
effort,
|
|
16762
17279
|
thinking,
|
|
16763
17280
|
taskBudget,
|
|
16764
|
-
betas
|
|
17281
|
+
betas,
|
|
17282
|
+
settingSources,
|
|
17283
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
17284
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
17285
|
+
memory: sdkFeatures.memory,
|
|
17286
|
+
dreaming: sdkFeatures.dreaming,
|
|
17287
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
17288
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17289
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
17290
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
17291
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16765
17292
|
}));
|
|
16766
17293
|
return;
|
|
16767
17294
|
}
|
|
@@ -16898,7 +17425,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
16898
17425
|
}
|
|
16899
17426
|
if (eventType === "content_block_start") {
|
|
16900
17427
|
const block = event.content_block;
|
|
16901
|
-
if (passthrough && !adapter.supportsThinking?.() && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
17428
|
+
if (passthrough && !adapter.supportsThinking?.() && !sdkFeatures.thinkingPassthrough && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
16902
17429
|
if (eventIndex !== undefined)
|
|
16903
17430
|
skipBlockIndices.add(eventIndex);
|
|
16904
17431
|
claudeLog("passthrough.thinking_stripped", { mode: "stream", type: block.type, index: eventIndex });
|
|
@@ -17259,6 +17786,33 @@ data: ${JSON.stringify({
|
|
|
17259
17786
|
app.post("/v1/messages", (c) => handleWithQueue(c, "/v1/messages"));
|
|
17260
17787
|
app.post("/messages", (c) => handleWithQueue(c, "/messages"));
|
|
17261
17788
|
app.route("/telemetry", createTelemetryRoutes());
|
|
17789
|
+
app.get("/settings", (c) => {
|
|
17790
|
+
const { settingsPageHtml: settingsPageHtml2 } = (init_settingsPage(), __toCommonJS(exports_settingsPage));
|
|
17791
|
+
return c.html(settingsPageHtml2);
|
|
17792
|
+
});
|
|
17793
|
+
app.get("/settings/api/features", (c) => {
|
|
17794
|
+
const { getAllFeatureConfigs: getAllFeatureConfigs2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17795
|
+
return c.json(getAllFeatureConfigs2());
|
|
17796
|
+
});
|
|
17797
|
+
app.patch("/settings/api/features/:adapter", async (c) => {
|
|
17798
|
+
const { validateFeatureUpdate: validateFeatureUpdate2, updateAdapterFeatures: updateAdapterFeatures2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17799
|
+
const adapter = c.req.param("adapter");
|
|
17800
|
+
const body = await c.req.json();
|
|
17801
|
+
let validated;
|
|
17802
|
+
try {
|
|
17803
|
+
validated = validateFeatureUpdate2(body);
|
|
17804
|
+
} catch (e) {
|
|
17805
|
+
return c.json({ error: e.message }, 400);
|
|
17806
|
+
}
|
|
17807
|
+
updateAdapterFeatures2(adapter, validated);
|
|
17808
|
+
return c.json({ ok: true });
|
|
17809
|
+
});
|
|
17810
|
+
app.delete("/settings/api/features/:adapter", (c) => {
|
|
17811
|
+
const { resetAdapterFeatures: resetAdapterFeatures2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17812
|
+
const adapter = c.req.param("adapter");
|
|
17813
|
+
resetAdapterFeatures2(adapter);
|
|
17814
|
+
return c.json({ ok: true });
|
|
17815
|
+
});
|
|
17262
17816
|
app.get("/metrics", (c) => {
|
|
17263
17817
|
const body = renderPrometheusMetrics(telemetryStore2);
|
|
17264
17818
|
return c.body(body, 200, {
|
|
@@ -17328,7 +17882,7 @@ data: ${JSON.stringify({
|
|
|
17328
17882
|
});
|
|
17329
17883
|
});
|
|
17330
17884
|
app.get("/profiles", async (c) => {
|
|
17331
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
17885
|
+
const { profilePageHtml } = await import("./profilePage-g5t5t6av.js");
|
|
17332
17886
|
return c.html(profilePageHtml);
|
|
17333
17887
|
});
|
|
17334
17888
|
app.post("/profiles/active", async (c) => {
|