@rynfar/meridian 1.35.0 → 1.37.1
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-q712ymxw.js} +589 -24
- 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)) {
|
|
@@ -16026,8 +16491,17 @@ function createProxyServer(config = {}) {
|
|
|
16026
16491
|
const serverVersion = finalConfig.version ?? "unknown";
|
|
16027
16492
|
restoreActiveProfile(finalConfig.profiles);
|
|
16028
16493
|
const sessionDiscoveredTools = new Map;
|
|
16494
|
+
const sessionToolCache = new Map;
|
|
16029
16495
|
const app = new Hono2;
|
|
16030
16496
|
app.use("*", cors());
|
|
16497
|
+
app.use("/v1/*", requireAuth);
|
|
16498
|
+
app.use("/messages", requireAuth);
|
|
16499
|
+
app.use("/telemetry/*", requireAuth);
|
|
16500
|
+
app.use("/telemetry", requireAuth);
|
|
16501
|
+
app.use("/metrics", requireAuth);
|
|
16502
|
+
app.use("/profiles/*", requireAuth);
|
|
16503
|
+
app.use("/profiles", requireAuth);
|
|
16504
|
+
app.use("/auth/*", requireAuth);
|
|
16031
16505
|
app.get("/", (c) => {
|
|
16032
16506
|
const accept = c.req.header("accept") || "";
|
|
16033
16507
|
if (accept.includes("application/json") && !accept.includes("text/html")) {
|
|
@@ -16130,6 +16604,14 @@ function createProxyServer(config = {}) {
|
|
|
16130
16604
|
console.error(`[PROXY] ${requestMeta.requestId} ignoring malformed x-opencode-thinking header: ${e instanceof Error ? e.message : String(e)}`);
|
|
16131
16605
|
}
|
|
16132
16606
|
}
|
|
16607
|
+
const { getFeaturesForAdapter: getFeaturesForAdapter2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
16608
|
+
const sdkFeatures = getFeaturesForAdapter2(adapter.name);
|
|
16609
|
+
if (!thinking) {
|
|
16610
|
+
if (sdkFeatures.thinking === "adaptive")
|
|
16611
|
+
thinking = { type: "adaptive" };
|
|
16612
|
+
else if (sdkFeatures.thinking === "enabled")
|
|
16613
|
+
thinking = { type: "enabled" };
|
|
16614
|
+
}
|
|
16133
16615
|
const thinkingBetaStripped = betaFilter.stripped.some((b) => b.startsWith("interleaved-thinking"));
|
|
16134
16616
|
if (thinkingBetaStripped) {
|
|
16135
16617
|
thinking = { type: "disabled" };
|
|
@@ -16282,16 +16764,27 @@ function createProxyServer(config = {}) {
|
|
|
16282
16764
|
}
|
|
16283
16765
|
const adapterPassthrough = adapter.usesPassthrough?.();
|
|
16284
16766
|
const passthrough = adapterPassthrough !== undefined ? adapterPassthrough : envBool("PASSTHROUGH");
|
|
16767
|
+
const settingSources = envBool("LOAD_CONTEXT") || sdkFeatures.claudeMd === "full" ? ["user", "project"] : sdkFeatures.claudeMd === "project" ? ["project"] : adapter.getSettingSources?.() ?? [];
|
|
16285
16768
|
const capturedToolUses = [];
|
|
16286
16769
|
const fileChanges = [];
|
|
16287
16770
|
let passthroughMcp;
|
|
16288
|
-
|
|
16289
|
-
|
|
16771
|
+
let requestTools = Array.isArray(body.tools) ? body.tools : [];
|
|
16772
|
+
if (passthrough && requestTools.length === 0 && profileSessionId) {
|
|
16773
|
+
const cached = sessionToolCache.get(profileSessionId);
|
|
16774
|
+
if (cached && cached.length > 0) {
|
|
16775
|
+
requestTools = cached;
|
|
16776
|
+
console.error(`[PROXY] ${requestMeta.requestId} tools_restored: client sent 0 tools but session had ${cached.length} — reusing cached tools to preserve prompt cache`);
|
|
16777
|
+
}
|
|
16778
|
+
}
|
|
16779
|
+
if (passthrough && requestTools.length > 0) {
|
|
16780
|
+
passthroughMcp = createPassthroughMcpServer(requestTools, adapter.getCoreToolNames?.());
|
|
16781
|
+
if (profileSessionId)
|
|
16782
|
+
sessionToolCache.set(profileSessionId, requestTools);
|
|
16290
16783
|
}
|
|
16291
16784
|
const hasDeferredTools = passthroughMcp?.hasDeferredTools ?? false;
|
|
16292
16785
|
const coreNames = adapter.getCoreToolNames?.();
|
|
16293
16786
|
const coreSet = coreNames ? new Set(coreNames.map((n) => n.toLowerCase())) : undefined;
|
|
16294
|
-
const deferredToolCount = hasDeferredTools &&
|
|
16787
|
+
const deferredToolCount = hasDeferredTools && requestTools.length > 0 ? requestTools.filter((t) => t.defer_loading === true || coreSet && !coreSet.has(String(t.name).toLowerCase())).length : 0;
|
|
16295
16788
|
if (hasDeferredTools) {
|
|
16296
16789
|
console.error(`[PROXY] ${requestMeta.requestId} deferred=${deferredToolCount}/${toolCount} tools (core: ${coreNames?.join(",") ?? "none"})`);
|
|
16297
16790
|
}
|
|
@@ -16373,7 +16866,17 @@ function createProxyServer(config = {}) {
|
|
|
16373
16866
|
effort,
|
|
16374
16867
|
thinking,
|
|
16375
16868
|
taskBudget,
|
|
16376
|
-
betas
|
|
16869
|
+
betas,
|
|
16870
|
+
settingSources,
|
|
16871
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
16872
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
16873
|
+
memory: sdkFeatures.memory,
|
|
16874
|
+
dreaming: sdkFeatures.dreaming,
|
|
16875
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
16876
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
16877
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
16878
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
16879
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16377
16880
|
}))) {
|
|
16378
16881
|
if (event.type === "assistant" && !event.error) {
|
|
16379
16882
|
didYieldContent = true;
|
|
@@ -16417,7 +16920,17 @@ function createProxyServer(config = {}) {
|
|
|
16417
16920
|
effort,
|
|
16418
16921
|
thinking,
|
|
16419
16922
|
taskBudget,
|
|
16420
|
-
betas
|
|
16923
|
+
betas,
|
|
16924
|
+
settingSources,
|
|
16925
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
16926
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
16927
|
+
memory: sdkFeatures.memory,
|
|
16928
|
+
dreaming: sdkFeatures.dreaming,
|
|
16929
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
16930
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
16931
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
16932
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
16933
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16421
16934
|
}));
|
|
16422
16935
|
return;
|
|
16423
16936
|
}
|
|
@@ -16502,7 +17015,7 @@ function createProxyServer(config = {}) {
|
|
|
16502
17015
|
claudeLog("passthrough.toolsearch_filtered", { mode: "non_stream" });
|
|
16503
17016
|
continue;
|
|
16504
17017
|
}
|
|
16505
|
-
if (passthrough && !adapter.supportsThinking?.() && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
17018
|
+
if (passthrough && !adapter.supportsThinking?.() && !sdkFeatures.thinkingPassthrough && (b.type === "thinking" || b.type === "redacted_thinking")) {
|
|
16506
17019
|
claudeLog("passthrough.thinking_stripped", { mode: "non_stream", type: b.type });
|
|
16507
17020
|
continue;
|
|
16508
17021
|
}
|
|
@@ -16641,7 +17154,12 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16641
17154
|
content: contentBlocks,
|
|
16642
17155
|
model: body.model,
|
|
16643
17156
|
stop_reason: stopReason,
|
|
16644
|
-
usage: {
|
|
17157
|
+
usage: {
|
|
17158
|
+
input_tokens: lastUsage?.input_tokens ?? 0,
|
|
17159
|
+
output_tokens: lastUsage?.output_tokens ?? 0,
|
|
17160
|
+
cache_read_input_tokens: lastUsage?.cache_read_input_tokens,
|
|
17161
|
+
cache_creation_input_tokens: lastUsage?.cache_creation_input_tokens
|
|
17162
|
+
}
|
|
16645
17163
|
}), {
|
|
16646
17164
|
headers: {
|
|
16647
17165
|
"Content-Type": "application/json",
|
|
@@ -16717,7 +17235,17 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16717
17235
|
effort,
|
|
16718
17236
|
thinking,
|
|
16719
17237
|
taskBudget,
|
|
16720
|
-
betas
|
|
17238
|
+
betas,
|
|
17239
|
+
settingSources,
|
|
17240
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
17241
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
17242
|
+
memory: sdkFeatures.memory,
|
|
17243
|
+
dreaming: sdkFeatures.dreaming,
|
|
17244
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
17245
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17246
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
17247
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
17248
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16721
17249
|
}))) {
|
|
16722
17250
|
if (event.type === "stream_event") {
|
|
16723
17251
|
didYieldClientEvent = true;
|
|
@@ -16761,7 +17289,17 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
16761
17289
|
effort,
|
|
16762
17290
|
thinking,
|
|
16763
17291
|
taskBudget,
|
|
16764
|
-
betas
|
|
17292
|
+
betas,
|
|
17293
|
+
settingSources,
|
|
17294
|
+
codeSystemPrompt: sdkFeatures.codeSystemPrompt ? true : undefined,
|
|
17295
|
+
clientSystemPrompt: sdkFeatures.clientSystemPrompt === false ? false : undefined,
|
|
17296
|
+
memory: sdkFeatures.memory,
|
|
17297
|
+
dreaming: sdkFeatures.dreaming,
|
|
17298
|
+
sharedMemory: sdkFeatures.sharedMemory,
|
|
17299
|
+
maxBudgetUsd: sdkFeatures.maxBudgetUsd,
|
|
17300
|
+
fallbackModel: sdkFeatures.fallbackModel,
|
|
17301
|
+
sdkDebug: sdkFeatures.sdkDebug,
|
|
17302
|
+
additionalDirectories: sdkFeatures.additionalDirectories ? sdkFeatures.additionalDirectories.split(",").map((d) => d.trim()).filter(Boolean) : undefined
|
|
16765
17303
|
}));
|
|
16766
17304
|
return;
|
|
16767
17305
|
}
|
|
@@ -16898,7 +17436,7 @@ data: ${JSON.stringify({ type: "message_stop" })}
|
|
|
16898
17436
|
}
|
|
16899
17437
|
if (eventType === "content_block_start") {
|
|
16900
17438
|
const block = event.content_block;
|
|
16901
|
-
if (passthrough && !adapter.supportsThinking?.() && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
17439
|
+
if (passthrough && !adapter.supportsThinking?.() && !sdkFeatures.thinkingPassthrough && (block?.type === "thinking" || block?.type === "redacted_thinking")) {
|
|
16902
17440
|
if (eventIndex !== undefined)
|
|
16903
17441
|
skipBlockIndices.add(eventIndex);
|
|
16904
17442
|
claudeLog("passthrough.thinking_stripped", { mode: "stream", type: block.type, index: eventIndex });
|
|
@@ -17259,6 +17797,33 @@ data: ${JSON.stringify({
|
|
|
17259
17797
|
app.post("/v1/messages", (c) => handleWithQueue(c, "/v1/messages"));
|
|
17260
17798
|
app.post("/messages", (c) => handleWithQueue(c, "/messages"));
|
|
17261
17799
|
app.route("/telemetry", createTelemetryRoutes());
|
|
17800
|
+
app.get("/settings", (c) => {
|
|
17801
|
+
const { settingsPageHtml: settingsPageHtml2 } = (init_settingsPage(), __toCommonJS(exports_settingsPage));
|
|
17802
|
+
return c.html(settingsPageHtml2);
|
|
17803
|
+
});
|
|
17804
|
+
app.get("/settings/api/features", (c) => {
|
|
17805
|
+
const { getAllFeatureConfigs: getAllFeatureConfigs2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17806
|
+
return c.json(getAllFeatureConfigs2());
|
|
17807
|
+
});
|
|
17808
|
+
app.patch("/settings/api/features/:adapter", async (c) => {
|
|
17809
|
+
const { validateFeatureUpdate: validateFeatureUpdate2, updateAdapterFeatures: updateAdapterFeatures2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17810
|
+
const adapter = c.req.param("adapter");
|
|
17811
|
+
const body = await c.req.json();
|
|
17812
|
+
let validated;
|
|
17813
|
+
try {
|
|
17814
|
+
validated = validateFeatureUpdate2(body);
|
|
17815
|
+
} catch (e) {
|
|
17816
|
+
return c.json({ error: e.message }, 400);
|
|
17817
|
+
}
|
|
17818
|
+
updateAdapterFeatures2(adapter, validated);
|
|
17819
|
+
return c.json({ ok: true });
|
|
17820
|
+
});
|
|
17821
|
+
app.delete("/settings/api/features/:adapter", (c) => {
|
|
17822
|
+
const { resetAdapterFeatures: resetAdapterFeatures2 } = (init_sdkFeatures(), __toCommonJS(exports_sdkFeatures));
|
|
17823
|
+
const adapter = c.req.param("adapter");
|
|
17824
|
+
resetAdapterFeatures2(adapter);
|
|
17825
|
+
return c.json({ ok: true });
|
|
17826
|
+
});
|
|
17262
17827
|
app.get("/metrics", (c) => {
|
|
17263
17828
|
const body = renderPrometheusMetrics(telemetryStore2);
|
|
17264
17829
|
return c.body(body, 200, {
|
|
@@ -17328,7 +17893,7 @@ data: ${JSON.stringify({
|
|
|
17328
17893
|
});
|
|
17329
17894
|
});
|
|
17330
17895
|
app.get("/profiles", async (c) => {
|
|
17331
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
17896
|
+
const { profilePageHtml } = await import("./profilePage-g5t5t6av.js");
|
|
17332
17897
|
return c.html(profilePageHtml);
|
|
17333
17898
|
});
|
|
17334
17899
|
app.post("/profiles/active", async (c) => {
|