@rynfar/meridian 1.37.8 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -3
- package/dist/{cli-pr79d7nw.js → cli-4rqtm83g.js} +33 -2
- package/dist/{cli-z5r7ptsm.js → cli-jbdchsr4.js} +1109 -231
- package/dist/cli-sry5aqdj.js +54 -0
- package/dist/cli.js +5 -4
- package/dist/pluginPage-85s6t6k8.js +405 -0
- package/dist/{profilePage-g5t5t6av.js → profilePage-77z05e0r.js} +4 -8
- package/dist/proxy/adapter.d.ts +45 -12
- package/dist/proxy/adapter.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts +21 -0
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -0
- package/dist/proxy/adapters/crush.d.ts +2 -0
- package/dist/proxy/adapters/crush.d.ts.map +1 -1
- package/dist/proxy/adapters/detect.d.ts +3 -2
- package/dist/proxy/adapters/detect.d.ts.map +1 -1
- package/dist/proxy/adapters/droid.d.ts +2 -0
- package/dist/proxy/adapters/droid.d.ts.map +1 -1
- package/dist/proxy/adapters/forgecode.d.ts +2 -0
- package/dist/proxy/adapters/forgecode.d.ts.map +1 -1
- package/dist/proxy/adapters/opencode.d.ts +2 -0
- package/dist/proxy/adapters/opencode.d.ts.map +1 -1
- package/dist/proxy/adapters/passthrough.d.ts +2 -0
- package/dist/proxy/adapters/passthrough.d.ts.map +1 -1
- package/dist/proxy/adapters/pi.d.ts +2 -0
- package/dist/proxy/adapters/pi.d.ts.map +1 -1
- package/dist/proxy/agentDefs.d.ts +2 -0
- package/dist/proxy/agentDefs.d.ts.map +1 -1
- package/dist/proxy/agentMatch.d.ts +11 -1
- package/dist/proxy/agentMatch.d.ts.map +1 -1
- package/dist/proxy/messages.d.ts +11 -0
- package/dist/proxy/messages.d.ts.map +1 -1
- package/dist/proxy/models.d.ts +25 -0
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/passthroughTools.d.ts +18 -0
- package/dist/proxy/passthroughTools.d.ts.map +1 -1
- package/dist/proxy/plugins/loader.d.ts +6 -0
- package/dist/proxy/plugins/loader.d.ts.map +1 -0
- package/dist/proxy/plugins/pluginPage.d.ts +7 -0
- package/dist/proxy/plugins/pluginPage.d.ts.map +1 -0
- package/dist/proxy/plugins/stats.d.ts +61 -0
- package/dist/proxy/plugins/stats.d.ts.map +1 -0
- package/dist/proxy/plugins/types.d.ts +21 -0
- package/dist/proxy/plugins/types.d.ts.map +1 -0
- package/dist/proxy/plugins/validation.d.ts +8 -0
- package/dist/proxy/plugins/validation.d.ts.map +1 -0
- package/dist/proxy/query.d.ts +27 -4
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/server.d.ts +2 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts +10 -1
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/transform.d.ts +137 -0
- package/dist/proxy/transform.d.ts.map +1 -0
- package/dist/proxy/transforms/crush.d.ts +3 -0
- package/dist/proxy/transforms/crush.d.ts.map +1 -0
- package/dist/proxy/transforms/droid.d.ts +3 -0
- package/dist/proxy/transforms/droid.d.ts.map +1 -0
- package/dist/proxy/transforms/forgecode.d.ts +3 -0
- package/dist/proxy/transforms/forgecode.d.ts.map +1 -0
- package/dist/proxy/transforms/opencode.d.ts +3 -0
- package/dist/proxy/transforms/opencode.d.ts.map +1 -0
- package/dist/proxy/transforms/passthrough.d.ts +3 -0
- package/dist/proxy/transforms/passthrough.d.ts.map +1 -0
- package/dist/proxy/transforms/pi.d.ts +3 -0
- package/dist/proxy/transforms/pi.d.ts.map +1 -0
- package/dist/proxy/transforms/registry.d.ts +3 -0
- package/dist/proxy/transforms/registry.d.ts.map +1 -0
- package/dist/proxy/types.d.ts +6 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/server.js +14 -5
- package/dist/stats-4c4ewmdh.js +17 -0
- package/dist/telemetry/dashboard.d.ts.map +1 -1
- package/dist/telemetry/landing.d.ts.map +1 -1
- package/dist/telemetry/profileBar.d.ts +13 -1
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +1 -1
- package/dist/telemetry/settingsPage.d.ts.map +1 -1
- package/dist/telemetry/sqlite.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +4 -0
- package/dist/telemetry/types.d.ts.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/proxy/plugins/stats.ts
|
|
2
|
+
var stats = new Map;
|
|
3
|
+
function emptyStats() {
|
|
4
|
+
return { hooks: {} };
|
|
5
|
+
}
|
|
6
|
+
function emptyHook() {
|
|
7
|
+
return { invocations: 0, errors: 0, totalMs: 0 };
|
|
8
|
+
}
|
|
9
|
+
function registerPluginStats(name) {
|
|
10
|
+
stats.set(name, emptyStats());
|
|
11
|
+
}
|
|
12
|
+
function resetAllPluginStats() {
|
|
13
|
+
stats.clear();
|
|
14
|
+
}
|
|
15
|
+
function isTrackedPlugin(name) {
|
|
16
|
+
return stats.has(name);
|
|
17
|
+
}
|
|
18
|
+
function recordInvocation(name, hook, durationMs) {
|
|
19
|
+
const entry = stats.get(name);
|
|
20
|
+
if (!entry)
|
|
21
|
+
return;
|
|
22
|
+
const h = entry.hooks[hook] ?? emptyHook();
|
|
23
|
+
h.invocations += 1;
|
|
24
|
+
h.totalMs += durationMs;
|
|
25
|
+
entry.hooks[hook] = h;
|
|
26
|
+
entry.lastInvokedAt = Date.now();
|
|
27
|
+
}
|
|
28
|
+
function recordError(name, hook, err) {
|
|
29
|
+
const entry = stats.get(name);
|
|
30
|
+
if (!entry)
|
|
31
|
+
return;
|
|
32
|
+
const h = entry.hooks[hook] ?? emptyHook();
|
|
33
|
+
h.errors += 1;
|
|
34
|
+
entry.hooks[hook] = h;
|
|
35
|
+
const at = Date.now();
|
|
36
|
+
entry.lastInvokedAt = at;
|
|
37
|
+
entry.lastError = {
|
|
38
|
+
hook,
|
|
39
|
+
message: err instanceof Error ? err.message : String(err),
|
|
40
|
+
at
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function getPluginStats(name) {
|
|
44
|
+
const entry = stats.get(name);
|
|
45
|
+
if (!entry)
|
|
46
|
+
return;
|
|
47
|
+
return {
|
|
48
|
+
hooks: Object.fromEntries(Object.entries(entry.hooks).map(([k, v]) => [k, { ...v }])),
|
|
49
|
+
lastInvokedAt: entry.lastInvokedAt,
|
|
50
|
+
...entry.lastError ? { lastError: { ...entry.lastError } } : {}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { registerPluginStats, resetAllPluginStats, isTrackedPlugin, recordInvocation, recordError, getPluginStats };
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startProxyServer
|
|
4
|
-
} from "./cli-
|
|
5
|
-
import"./cli-pr79d7nw.js";
|
|
6
|
-
import"./cli-rtab0qa6.js";
|
|
7
|
-
import"./cli-m9pfb7h9.js";
|
|
4
|
+
} from "./cli-jbdchsr4.js";
|
|
8
5
|
import"./cli-vdp9s10c.js";
|
|
6
|
+
import"./cli-sry5aqdj.js";
|
|
7
|
+
import"./cli-4rqtm83g.js";
|
|
9
8
|
import"./cli-340h1chz.js";
|
|
9
|
+
import"./cli-rtab0qa6.js";
|
|
10
|
+
import"./cli-m9pfb7h9.js";
|
|
10
11
|
import {
|
|
11
12
|
__require
|
|
12
13
|
} from "./cli-p9swy5t3.js";
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_profileBar,
|
|
3
|
+
profileBarCss,
|
|
4
|
+
profileBarHtml,
|
|
5
|
+
profileBarJs,
|
|
6
|
+
themeCss
|
|
7
|
+
} from "./cli-4rqtm83g.js";
|
|
8
|
+
import"./cli-p9swy5t3.js";
|
|
9
|
+
|
|
10
|
+
// src/proxy/plugins/pluginPage.ts
|
|
11
|
+
init_profileBar();
|
|
12
|
+
var pluginPageHtml = `<!DOCTYPE html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="utf-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
17
|
+
<title>Meridian — Plugins</title>
|
|
18
|
+
<style>
|
|
19
|
+
${themeCss}
|
|
20
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
21
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
22
|
+
background: var(--bg); color: var(--text); line-height: 1.6; min-height: 100vh; }
|
|
23
|
+
.container { max-width: 960px; margin: 0 auto; padding: 32px 24px; }
|
|
24
|
+
|
|
25
|
+
.back-link { display: inline-flex; align-items: center; gap: 6px; color: var(--muted);
|
|
26
|
+
text-decoration: none; font-size: 13px; margin-bottom: 24px; transition: color 0.15s; }
|
|
27
|
+
.back-link:hover { color: var(--text); }
|
|
28
|
+
|
|
29
|
+
.page-header { display: flex; align-items: flex-start; justify-content: space-between;
|
|
30
|
+
gap: 16px; margin-bottom: 6px; flex-wrap: wrap; }
|
|
31
|
+
.page-header h1 { font-size: 24px; font-weight: 700; letter-spacing: 0.5px; }
|
|
32
|
+
.tagline { color: var(--muted); font-size: 14px; margin-bottom: 28px; }
|
|
33
|
+
|
|
34
|
+
.reload-btn { padding: 8px 18px; font-size: 13px; font-weight: 500;
|
|
35
|
+
background: var(--surface2); color: var(--accent); border: 1px solid var(--accent);
|
|
36
|
+
border-radius: 8px; cursor: pointer; transition: all 0.15s; white-space: nowrap; }
|
|
37
|
+
.reload-btn:hover { background: rgba(139,92,246,0.15); }
|
|
38
|
+
.reload-btn:disabled { opacity: 0.5; cursor: default; }
|
|
39
|
+
.reload-btn.loading { opacity: 0.7; }
|
|
40
|
+
|
|
41
|
+
.reload-status { font-size: 12px; color: var(--green); opacity: 0; transition: opacity 0.3s;
|
|
42
|
+
margin-left: 8px; }
|
|
43
|
+
.reload-status.show { opacity: 1; }
|
|
44
|
+
.reload-status.error { color: var(--red); }
|
|
45
|
+
|
|
46
|
+
.header-actions { display: flex; align-items: center; gap: 0; }
|
|
47
|
+
|
|
48
|
+
.plugin-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
|
|
49
|
+
padding: 20px; margin-bottom: 12px; transition: border-color 0.2s; }
|
|
50
|
+
.plugin-card.status-error { border-color: rgba(248,81,73,0.4); }
|
|
51
|
+
|
|
52
|
+
.plugin-card-header { display: flex; align-items: center; gap: 10px; margin-bottom: 10px;
|
|
53
|
+
flex-wrap: wrap; }
|
|
54
|
+
.plugin-name { font-size: 16px; font-weight: 600; }
|
|
55
|
+
.plugin-version { font-size: 11px; color: var(--muted);
|
|
56
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; }
|
|
57
|
+
|
|
58
|
+
.status-badge { font-size: 10px; padding: 2px 9px; border-radius: 4px;
|
|
59
|
+
text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; }
|
|
60
|
+
.badge-active { background: rgba(63,185,80,0.15); color: var(--green);
|
|
61
|
+
border: 1px solid rgba(63,185,80,0.3); }
|
|
62
|
+
.badge-disabled { background: var(--surface2); color: var(--muted);
|
|
63
|
+
border: 1px solid var(--border); }
|
|
64
|
+
.badge-error { background: rgba(248,81,73,0.12); color: var(--red);
|
|
65
|
+
border: 1px solid rgba(248,81,73,0.3); }
|
|
66
|
+
|
|
67
|
+
.plugin-description { font-size: 13px; color: var(--muted); margin-bottom: 12px; }
|
|
68
|
+
|
|
69
|
+
.plugin-meta { display: flex; gap: 20px; flex-wrap: wrap; font-size: 12px; }
|
|
70
|
+
.meta-item { display: flex; align-items: center; gap: 6px; }
|
|
71
|
+
.meta-label { color: var(--muted); text-transform: uppercase; font-size: 10px;
|
|
72
|
+
letter-spacing: 0.5px; font-weight: 500; }
|
|
73
|
+
.meta-value { color: var(--text);
|
|
74
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 11px; }
|
|
75
|
+
|
|
76
|
+
.plugin-error-box { margin-top: 12px; padding: 10px 14px;
|
|
77
|
+
background: rgba(248,81,73,0.08); border: 1px solid rgba(248,81,73,0.3);
|
|
78
|
+
border-radius: 8px; font-size: 12px; color: var(--red);
|
|
79
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; word-break: break-word; }
|
|
80
|
+
|
|
81
|
+
.empty-state { text-align: center; padding: 56px 24px; color: var(--muted);
|
|
82
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px; }
|
|
83
|
+
.empty-state h2 { font-size: 16px; font-weight: 600; margin-bottom: 10px; color: var(--text); }
|
|
84
|
+
.empty-state p { font-size: 13px; line-height: 1.7; }
|
|
85
|
+
.empty-state code { font-family: 'SF Mono', SFMono-Regular, Consolas, monospace;
|
|
86
|
+
font-size: 12px; background: var(--surface2); padding: 2px 7px;
|
|
87
|
+
border-radius: 4px; color: #a78bfa; }
|
|
88
|
+
|
|
89
|
+
/* ── Hero panel: aggregate stats at a glance ── */
|
|
90
|
+
.hero-panel { background: linear-gradient(135deg, var(--surface) 0%, var(--surface2) 100%);
|
|
91
|
+
border: 1px solid var(--border); border-radius: 14px;
|
|
92
|
+
padding: 20px 24px; margin-bottom: 24px; }
|
|
93
|
+
.hero-row { display: flex; align-items: center; }
|
|
94
|
+
.hero-row-top { gap: 28px; flex-wrap: wrap; padding-bottom: 16px;
|
|
95
|
+
border-bottom: 1px solid var(--border); margin-bottom: 14px; }
|
|
96
|
+
.hero-metric { flex: 1 1 0; min-width: 110px; }
|
|
97
|
+
.hero-num { font-family: 'SF Mono', SFMono-Regular, Consolas, monospace;
|
|
98
|
+
font-size: 28px; font-weight: 600; color: var(--text);
|
|
99
|
+
line-height: 1.1; font-variant-numeric: tabular-nums; }
|
|
100
|
+
.hero-num.hero-err { color: var(--red); }
|
|
101
|
+
.hero-sub { font-size: 15px; font-weight: 400; color: var(--muted); margin-left: 4px; }
|
|
102
|
+
.hero-unit { font-size: 13px; font-weight: 400; color: var(--muted); margin-left: 3px; }
|
|
103
|
+
.hero-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 0.6px;
|
|
104
|
+
color: var(--muted); margin-top: 6px; font-weight: 500; }
|
|
105
|
+
.hero-row-bottom { gap: 18px; justify-content: space-between; flex-wrap: wrap;
|
|
106
|
+
font-size: 12px; color: var(--muted); }
|
|
107
|
+
.hero-status { display: flex; align-items: center; gap: 6px; }
|
|
108
|
+
.hero-status strong { color: var(--text); font-weight: 600; }
|
|
109
|
+
.chip-sep { width: 1px; height: 14px; background: var(--border); margin: 0 6px; }
|
|
110
|
+
.status-chip { font-size: 10px; line-height: 1; }
|
|
111
|
+
.status-chip-active { color: var(--green); }
|
|
112
|
+
.status-chip-disabled { color: var(--muted); }
|
|
113
|
+
.status-chip-error { color: var(--red); }
|
|
114
|
+
.hero-busiest { color: var(--muted); font-size: 12px; }
|
|
115
|
+
.hero-busiest strong { color: var(--accent); font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; }
|
|
116
|
+
.hero-busiest-count { color: var(--muted); font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 11px; }
|
|
117
|
+
|
|
118
|
+
.plugin-stats { margin-top: 14px; padding-top: 14px;
|
|
119
|
+
border-top: 1px solid var(--border); }
|
|
120
|
+
.plugin-stats-empty { margin-top: 14px; padding: 10px 14px;
|
|
121
|
+
background: var(--surface2); border-radius: 6px; font-size: 12px;
|
|
122
|
+
color: var(--muted); font-style: italic; }
|
|
123
|
+
.stats-header { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;
|
|
124
|
+
color: var(--muted); font-weight: 500; margin-bottom: 8px; }
|
|
125
|
+
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
|
|
126
|
+
margin-bottom: 12px; }
|
|
127
|
+
.stat-cell { background: var(--surface2); border: 1px solid var(--border);
|
|
128
|
+
border-radius: 8px; padding: 10px 12px; }
|
|
129
|
+
.stat-num { font-size: 18px; font-weight: 600; color: var(--text);
|
|
130
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace;
|
|
131
|
+
font-variant-numeric: tabular-nums; line-height: 1.2; }
|
|
132
|
+
.stat-num.stat-err { color: var(--red); }
|
|
133
|
+
.stat-unit { font-size: 11px; color: var(--muted); font-weight: 400; margin-left: 2px; }
|
|
134
|
+
.stat-lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px;
|
|
135
|
+
color: var(--muted); margin-top: 4px; }
|
|
136
|
+
.stats-breakdown { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
137
|
+
.hook-pill { font-size: 11px; padding: 3px 8px; border-radius: 4px;
|
|
138
|
+
background: var(--surface2); color: var(--muted);
|
|
139
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; }
|
|
140
|
+
.hook-pill strong { color: var(--text); font-weight: 600; }
|
|
141
|
+
.hook-err { color: var(--red); font-weight: 500; }
|
|
142
|
+
` + profileBarCss + `
|
|
143
|
+
</style>
|
|
144
|
+
</head>
|
|
145
|
+
<body>
|
|
146
|
+
` + profileBarHtml + `
|
|
147
|
+
<div class="container">
|
|
148
|
+
<a href="/" class="back-link">← Back to Meridian</a>
|
|
149
|
+
|
|
150
|
+
<div class="page-header">
|
|
151
|
+
<div>
|
|
152
|
+
<h1>Plugins</h1>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="header-actions">
|
|
155
|
+
<button class="reload-btn" id="reloadBtn" onclick="reloadPlugins()">Reload Plugins</button>
|
|
156
|
+
<span class="reload-status" id="reloadStatus"></span>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="tagline">Transform request and response behavior with composable plugins</div>
|
|
160
|
+
|
|
161
|
+
<div id="content"><div style="color:var(--muted);padding:40px;text-align:center">Loading…</div></div>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<script>
|
|
165
|
+
function esc(s) {
|
|
166
|
+
if (s == null) return '';
|
|
167
|
+
var d = document.createElement('div');
|
|
168
|
+
d.textContent = String(s);
|
|
169
|
+
return d.innerHTML;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function loadPlugins() {
|
|
173
|
+
try {
|
|
174
|
+
var res = await fetch('/plugins/list');
|
|
175
|
+
var data = await res.json();
|
|
176
|
+
render(data.plugins || []);
|
|
177
|
+
} catch {
|
|
178
|
+
document.getElementById('content').innerHTML =
|
|
179
|
+
'<div class="empty-state"><h2>Could not load plugins</h2><p>Is Meridian running?</p></div>';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function reloadPlugins() {
|
|
184
|
+
var btn = document.getElementById('reloadBtn');
|
|
185
|
+
var status = document.getElementById('reloadStatus');
|
|
186
|
+
btn.disabled = true;
|
|
187
|
+
btn.classList.add('loading');
|
|
188
|
+
btn.textContent = 'Reloading…';
|
|
189
|
+
status.className = 'reload-status';
|
|
190
|
+
status.textContent = '';
|
|
191
|
+
try {
|
|
192
|
+
var res = await fetch('/plugins/reload', { method: 'POST' });
|
|
193
|
+
var data = await res.json();
|
|
194
|
+
if (data.success) {
|
|
195
|
+
status.textContent = '✓ Reloaded';
|
|
196
|
+
status.className = 'reload-status show';
|
|
197
|
+
} else {
|
|
198
|
+
status.textContent = data.error || 'Reload failed';
|
|
199
|
+
status.className = 'reload-status show error';
|
|
200
|
+
}
|
|
201
|
+
await loadPlugins();
|
|
202
|
+
} catch {
|
|
203
|
+
status.textContent = 'Reload failed';
|
|
204
|
+
status.className = 'reload-status show error';
|
|
205
|
+
} finally {
|
|
206
|
+
btn.disabled = false;
|
|
207
|
+
btn.classList.remove('loading');
|
|
208
|
+
btn.textContent = 'Reload Plugins';
|
|
209
|
+
setTimeout(function() { status.className = 'reload-status'; }, 3000);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function render(plugins) {
|
|
214
|
+
if (!plugins.length) {
|
|
215
|
+
document.getElementById('content').innerHTML =
|
|
216
|
+
'<div class="empty-state">'
|
|
217
|
+
+ '<h2>No plugins found</h2>'
|
|
218
|
+
+ '<p>Drop <code>.ts</code> or <code>.js</code> files in <code>~/.config/meridian/plugins/</code> and reload.</p>'
|
|
219
|
+
+ '</div>';
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
var active = plugins.filter(function(p) { return p.status === 'active'; }).length;
|
|
224
|
+
var disabled = plugins.filter(function(p) { return p.status === 'disabled'; }).length;
|
|
225
|
+
var errors = plugins.filter(function(p) { return p.status === 'error'; }).length;
|
|
226
|
+
|
|
227
|
+
// ── Aggregate stats across all active plugins ──
|
|
228
|
+
var totalCalls = 0, totalErrors = 0, totalMs = 0, lastSeen = 0;
|
|
229
|
+
var busiestName = null, busiestCount = 0;
|
|
230
|
+
for (var i = 0; i < plugins.length; i++) {
|
|
231
|
+
var p = plugins[i];
|
|
232
|
+
if (p.status !== 'active' || !p.stats) continue;
|
|
233
|
+
var pluginCalls = 0, pluginErrors = 0, pluginMs = 0;
|
|
234
|
+
var hookNames = Object.keys(p.stats.hooks || {});
|
|
235
|
+
for (var j = 0; j < hookNames.length; j++) {
|
|
236
|
+
var h = p.stats.hooks[hookNames[j]];
|
|
237
|
+
pluginCalls += h.invocations || 0;
|
|
238
|
+
pluginErrors += h.errors || 0;
|
|
239
|
+
pluginMs += h.totalMs || 0;
|
|
240
|
+
}
|
|
241
|
+
totalCalls += pluginCalls;
|
|
242
|
+
totalErrors += pluginErrors;
|
|
243
|
+
totalMs += pluginMs;
|
|
244
|
+
if (p.stats.lastInvokedAt && p.stats.lastInvokedAt > lastSeen) {
|
|
245
|
+
lastSeen = p.stats.lastInvokedAt;
|
|
246
|
+
}
|
|
247
|
+
if (pluginCalls > busiestCount) {
|
|
248
|
+
busiestCount = pluginCalls;
|
|
249
|
+
busiestName = p.name;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
var aggAvg = totalCalls > 0 ? (totalMs / totalCalls).toFixed(2) : '0.00';
|
|
253
|
+
|
|
254
|
+
var html = '<div class="hero-panel">';
|
|
255
|
+
html += '<div class="hero-row hero-row-top">';
|
|
256
|
+
html += '<div class="hero-metric">'
|
|
257
|
+
+ '<div class="hero-num">' + active + '<span class="hero-sub">/ ' + plugins.length + '</span></div>'
|
|
258
|
+
+ '<div class="hero-lbl">Active plugins</div>'
|
|
259
|
+
+ '</div>';
|
|
260
|
+
html += '<div class="hero-metric">'
|
|
261
|
+
+ '<div class="hero-num">' + totalCalls.toLocaleString() + '</div>'
|
|
262
|
+
+ '<div class="hero-lbl">Total invocations</div>'
|
|
263
|
+
+ '</div>';
|
|
264
|
+
html += '<div class="hero-metric">'
|
|
265
|
+
+ '<div class="hero-num ' + (totalErrors > 0 ? 'hero-err' : '') + '">' + totalErrors.toLocaleString() + '</div>'
|
|
266
|
+
+ '<div class="hero-lbl">Errors</div>'
|
|
267
|
+
+ '</div>';
|
|
268
|
+
html += '<div class="hero-metric">'
|
|
269
|
+
+ '<div class="hero-num">' + aggAvg + '<span class="hero-unit">ms</span></div>'
|
|
270
|
+
+ '<div class="hero-lbl">Avg latency</div>'
|
|
271
|
+
+ '</div>';
|
|
272
|
+
html += '<div class="hero-metric">'
|
|
273
|
+
+ '<div class="hero-num">' + (lastSeen ? formatRelative(lastSeen) : '—') + '</div>'
|
|
274
|
+
+ '<div class="hero-lbl">Last request</div>'
|
|
275
|
+
+ '</div>';
|
|
276
|
+
html += '</div>';
|
|
277
|
+
|
|
278
|
+
// Status breakdown + busiest plugin row
|
|
279
|
+
html += '<div class="hero-row hero-row-bottom">';
|
|
280
|
+
html += '<div class="hero-status">';
|
|
281
|
+
html += '<span class="status-chip status-chip-active">●</span> <strong>' + active + '</strong> active';
|
|
282
|
+
if (disabled) html += '<span class="chip-sep"></span><span class="status-chip status-chip-disabled">●</span> <strong>' + disabled + '</strong> disabled';
|
|
283
|
+
if (errors) html += '<span class="chip-sep"></span><span class="status-chip status-chip-error">●</span> <strong>' + errors + '</strong> error' + (errors !== 1 ? 's' : '');
|
|
284
|
+
html += '</div>';
|
|
285
|
+
if (busiestName) {
|
|
286
|
+
html += '<div class="hero-busiest">Busiest: <strong>' + esc(busiestName) + '</strong> <span class="hero-busiest-count">(' + busiestCount.toLocaleString() + ' calls)</span></div>';
|
|
287
|
+
}
|
|
288
|
+
html += '</div>';
|
|
289
|
+
html += '</div>';
|
|
290
|
+
|
|
291
|
+
for (var i = 0; i < plugins.length; i++) {
|
|
292
|
+
var p = plugins[i];
|
|
293
|
+
var statusClass = p.status === 'active' ? 'badge-active' : p.status === 'error' ? 'badge-error' : 'badge-disabled';
|
|
294
|
+
html += '<div class="plugin-card' + (p.status === 'error' ? ' status-error' : '') + '">';
|
|
295
|
+
|
|
296
|
+
html += '<div class="plugin-card-header">';
|
|
297
|
+
html += '<span class="plugin-name">' + esc(p.name) + '</span>';
|
|
298
|
+
if (p.version) html += '<span class="plugin-version">v' + esc(p.version) + '</span>';
|
|
299
|
+
html += '<span class="status-badge ' + statusClass + '">' + esc(p.status) + '</span>';
|
|
300
|
+
html += '</div>';
|
|
301
|
+
|
|
302
|
+
if (p.description) {
|
|
303
|
+
html += '<div class="plugin-description">' + esc(p.description) + '</div>';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
html += '<div class="plugin-meta">';
|
|
307
|
+
var hooks = (p.hooks && p.hooks.length) ? p.hooks.join(', ') : '—';
|
|
308
|
+
html += '<div class="meta-item"><span class="meta-label">Hooks</span><span class="meta-value">' + esc(hooks) + '</span></div>';
|
|
309
|
+
var adapters = (p.adapters && p.adapters.length) ? p.adapters.join(', ') : 'All adapters';
|
|
310
|
+
html += '<div class="meta-item"><span class="meta-label">Adapters</span><span class="meta-value">' + esc(adapters) + '</span></div>';
|
|
311
|
+
html += '</div>';
|
|
312
|
+
|
|
313
|
+
if (p.status === 'active' && p.stats) {
|
|
314
|
+
html += renderStats(p.stats);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (p.status === 'error' && p.error) {
|
|
318
|
+
html += '<div class="plugin-error-box">' + esc(p.error) + '</div>';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
html += '</div>';
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
document.getElementById('content').innerHTML = html;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function renderStats(s) {
|
|
328
|
+
var hooks = s.hooks || {};
|
|
329
|
+
var hookNames = Object.keys(hooks);
|
|
330
|
+
if (hookNames.length === 0 && !s.lastInvokedAt && !s.lastError) {
|
|
331
|
+
return '<div class="plugin-stats-empty">No invocations yet — send a request to see counters.</div>';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
var totalInvocations = 0, totalErrors = 0, totalMs = 0;
|
|
335
|
+
for (var i = 0; i < hookNames.length; i++) {
|
|
336
|
+
var h = hooks[hookNames[i]];
|
|
337
|
+
totalInvocations += h.invocations || 0;
|
|
338
|
+
totalErrors += h.errors || 0;
|
|
339
|
+
totalMs += h.totalMs || 0;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
var html = '<div class="plugin-stats">';
|
|
343
|
+
html += '<div class="stats-header">Invocations</div>';
|
|
344
|
+
html += '<div class="stats-grid">';
|
|
345
|
+
html += '<div class="stat-cell"><div class="stat-num">' + totalInvocations + '</div><div class="stat-lbl">calls</div></div>';
|
|
346
|
+
html += '<div class="stat-cell"><div class="stat-num ' + (totalErrors > 0 ? 'stat-err' : '') + '">' + totalErrors + '</div><div class="stat-lbl">errors</div></div>';
|
|
347
|
+
var avgMs = totalInvocations > 0 ? (totalMs / totalInvocations).toFixed(2) : '0.00';
|
|
348
|
+
html += '<div class="stat-cell"><div class="stat-num">' + avgMs + '<span class="stat-unit">ms</span></div><div class="stat-lbl">avg</div></div>';
|
|
349
|
+
if (s.lastInvokedAt) {
|
|
350
|
+
html += '<div class="stat-cell"><div class="stat-num">' + formatRelative(s.lastInvokedAt) + '</div><div class="stat-lbl">last seen</div></div>';
|
|
351
|
+
}
|
|
352
|
+
html += '</div>';
|
|
353
|
+
|
|
354
|
+
if (hookNames.length > 0) {
|
|
355
|
+
html += '<div class="stats-breakdown">';
|
|
356
|
+
for (var j = 0; j < hookNames.length; j++) {
|
|
357
|
+
var name = hookNames[j];
|
|
358
|
+
var hd = hooks[name];
|
|
359
|
+
html += '<span class="hook-pill">'
|
|
360
|
+
+ esc(name) + ': <strong>' + (hd.invocations || 0) + '</strong>'
|
|
361
|
+
+ (hd.errors > 0 ? ' <span class="hook-err">(' + hd.errors + ' err)</span>' : '')
|
|
362
|
+
+ '</span>';
|
|
363
|
+
}
|
|
364
|
+
html += '</div>';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (s.lastError) {
|
|
368
|
+
html += '<div class="plugin-error-box">'
|
|
369
|
+
+ 'Last error in <strong>' + esc(s.lastError.hook) + '</strong> '
|
|
370
|
+
+ formatRelative(s.lastError.at)
|
|
371
|
+
+ ': ' + esc(s.lastError.message)
|
|
372
|
+
+ '</div>';
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
html += '</div>';
|
|
376
|
+
return html;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function formatRelative(ts) {
|
|
380
|
+
var diffMs = Date.now() - ts;
|
|
381
|
+
if (diffMs < 0) return 'just now';
|
|
382
|
+
var s = Math.floor(diffMs / 1000);
|
|
383
|
+
if (s < 5) return 'just now';
|
|
384
|
+
if (s < 60) return s + 's ago';
|
|
385
|
+
var m = Math.floor(s / 60);
|
|
386
|
+
if (m < 60) return m + 'm ago';
|
|
387
|
+
var h = Math.floor(m / 60);
|
|
388
|
+
if (h < 24) return h + 'h ago';
|
|
389
|
+
return Math.floor(h / 24) + 'd ago';
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Periodic refresh so you can watch invocation counters climb while
|
|
393
|
+
// you drive traffic through the proxy. Stops when the tab is hidden.
|
|
394
|
+
setInterval(function() {
|
|
395
|
+
if (document.visibilityState === 'visible') loadPlugins();
|
|
396
|
+
}, 3000);
|
|
397
|
+
|
|
398
|
+
loadPlugins();
|
|
399
|
+
` + profileBarJs + `
|
|
400
|
+
</script>
|
|
401
|
+
</body>
|
|
402
|
+
</html>`;
|
|
403
|
+
export {
|
|
404
|
+
pluginPageHtml
|
|
405
|
+
};
|
|
@@ -2,8 +2,9 @@ import {
|
|
|
2
2
|
init_profileBar,
|
|
3
3
|
profileBarCss,
|
|
4
4
|
profileBarHtml,
|
|
5
|
-
profileBarJs
|
|
6
|
-
|
|
5
|
+
profileBarJs,
|
|
6
|
+
themeCss
|
|
7
|
+
} from "./cli-4rqtm83g.js";
|
|
7
8
|
import"./cli-p9swy5t3.js";
|
|
8
9
|
|
|
9
10
|
// src/telemetry/profilePage.ts
|
|
@@ -15,12 +16,7 @@ var profilePageHtml = `<!DOCTYPE html>
|
|
|
15
16
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
16
17
|
<title>Meridian — Profiles</title>
|
|
17
18
|
<style>
|
|
18
|
-
|
|
19
|
-
--bg: #0d1117; --surface: #161b22; --border: #30363d;
|
|
20
|
-
--text: #e6edf3; --muted: #8b949e; --accent: #58a6ff;
|
|
21
|
-
--green: #3fb950; --yellow: #d29922; --red: #f85149;
|
|
22
|
-
--purple: #bc8cff;
|
|
23
|
-
}
|
|
19
|
+
${themeCss}
|
|
24
20
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
25
21
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
26
22
|
background: var(--bg); color: var(--text); padding: 0; line-height: 1.5; }
|
package/dist/proxy/adapter.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
import type { Context } from "hono";
|
|
8
8
|
import type { SettingSource } from "@anthropic-ai/claude-agent-sdk";
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Core identity of an agent — detection, session tracking, CWD extraction.
|
|
11
|
+
* This is the minimal interface for agent recognition. Behavioral customization
|
|
12
|
+
* (tool filtering, system prompt modifications, hooks) lives in Transform objects.
|
|
13
13
|
*/
|
|
14
|
-
export interface
|
|
15
|
-
/** Human-readable name for logging */
|
|
14
|
+
export interface AgentIdentity {
|
|
15
|
+
/** Human-readable name for logging and transform scoping */
|
|
16
16
|
readonly name: string;
|
|
17
17
|
/**
|
|
18
18
|
* Extract a session ID from the request.
|
|
@@ -20,15 +20,53 @@ export interface AgentAdapter {
|
|
|
20
20
|
*/
|
|
21
21
|
getSessionId(c: Context): string | undefined;
|
|
22
22
|
/**
|
|
23
|
-
* Extract the
|
|
24
|
-
*
|
|
23
|
+
* Extract the SDK subprocess working directory from the request body.
|
|
24
|
+
*
|
|
25
|
+
* This path must exist on the proxy host because it becomes the SDK
|
|
26
|
+
* child_process cwd (passed through as the `cwd` option to the Claude
|
|
27
|
+
* Agent SDK's query() call). If it doesn't exist, the subprocess spawn
|
|
28
|
+
* fails or chdirs misbehave.
|
|
29
|
+
*
|
|
30
|
+
* Adapters that assume the client runs on the same host as the proxy
|
|
31
|
+
* (OpenCode, Crush) can return the client-local path here.
|
|
32
|
+
* Adapters for remote clients pointing at a network-exposed proxy
|
|
33
|
+
* (Claude Code) should return undefined and override
|
|
34
|
+
* extractClientWorkingDirectory instead.
|
|
35
|
+
*
|
|
36
|
+
* Returns undefined to fall back to MERIDIAN_WORKDIR / CLAUDE_PROXY_WORKDIR
|
|
37
|
+
* env vars, then process.cwd().
|
|
25
38
|
*/
|
|
26
39
|
extractWorkingDirectory(body: any): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Optional: extract the client-local working directory (which may not
|
|
42
|
+
* exist on the proxy host). This is used for:
|
|
43
|
+
* - Conversation fingerprinting (per-client-project bucketing so two
|
|
44
|
+
* unrelated projects don't collide on identical first-message hashes).
|
|
45
|
+
* - A system prompt addendum so the model reports the correct path
|
|
46
|
+
* when asked and uses it for file path references.
|
|
47
|
+
*
|
|
48
|
+
* Return undefined to default to the SDK working directory (same machine
|
|
49
|
+
* assumption). Adapters for remote clients should implement this to parse
|
|
50
|
+
* the client's own "working directory" hint from the request body.
|
|
51
|
+
*/
|
|
52
|
+
extractClientWorkingDirectory?(body: any): string | undefined;
|
|
27
53
|
/**
|
|
28
54
|
* Content normalization — convert message content to a stable string
|
|
29
55
|
* for hashing. Agents may send content in different formats.
|
|
30
56
|
*/
|
|
31
57
|
normalizeContent(content: any): string;
|
|
58
|
+
/**
|
|
59
|
+
* The MCP server name used by this agent.
|
|
60
|
+
* Tools are registered as `mcp__{name}__{tool}`.
|
|
61
|
+
*/
|
|
62
|
+
getMcpServerName(): string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* An agent adapter provides agent-specific configuration to the proxy.
|
|
66
|
+
* The proxy calls these methods during request handling to determine
|
|
67
|
+
* how to interact with the calling agent.
|
|
68
|
+
*/
|
|
69
|
+
export interface AgentAdapter extends AgentIdentity {
|
|
32
70
|
/**
|
|
33
71
|
* SDK built-in tools to block (replaced by MCP equivalents).
|
|
34
72
|
* These are tools where the agent provides its own implementation.
|
|
@@ -40,11 +78,6 @@ export interface AgentAdapter {
|
|
|
40
78
|
* can't handle.
|
|
41
79
|
*/
|
|
42
80
|
getAgentIncompatibleTools(): readonly string[];
|
|
43
|
-
/**
|
|
44
|
-
* The MCP server name used by this agent.
|
|
45
|
-
* Tools are registered as `mcp__{name}__{tool}`.
|
|
46
|
-
*/
|
|
47
|
-
getMcpServerName(): string;
|
|
48
81
|
/**
|
|
49
82
|
* MCP tools that are allowed through the proxy's tool filter.
|
|
50
83
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/proxy/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAE5C;;;;;;;;;;;;;;;;OAgBG;IACH,uBAAuB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAEtD;;;;;;;;;;;OAWG;IACH,6BAA6B,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAA;IAE7D;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAA;IAEtC;;;OAGG;IACH,gBAAgB,IAAI,MAAM,CAAA;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD;;;OAGG;IACH,sBAAsB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE3C;;;;OAIG;IACH,yBAAyB,IAAI,SAAS,MAAM,EAAE,CAAA;IAE9C;;OAEG;IACH,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAA;IAEvC;;;;OAIG;IACH,cAAc,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEhF;;;OAGG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAA;IAE9D;;;OAGG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAA;IAE9E;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAA;IAErC;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,SAAS,MAAM,EAAE,CAAA;IAEtC;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,IAAI,aAAa,EAAE,CAAA;IAErC;;;;;;;OAOG;IACH,gBAAgB,CAAC,IAAI,OAAO,CAAA;IAE5B;;;;;;OAMG;IACH,sBAAsB,CAAC,IAAI,OAAO,CAAA;IAElC;;;;;;;;OAQG;IACH,yBAAyB,CAAC,IAAI,OAAO,CAAA;IAErC;;;;;;;;;;;;;;;OAeG;IACH,6BAA6B,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,eAAe,EAAE,UAAU,EAAE,CAAA;CAC3G"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code agent adapter.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code (claude-cli) is unusual among meridian clients in two ways:
|
|
5
|
+
* 1. It typically runs on a different machine than the proxy (pointing at
|
|
6
|
+
* ANTHROPIC_BASE_URL over the network), so its CWD doesn't exist on the
|
|
7
|
+
* proxy host.
|
|
8
|
+
* 2. Its system prompt embeds working-directory info using the
|
|
9
|
+
* `Primary working directory: <path>` format inside a `# Environment`
|
|
10
|
+
* block — different from OpenCode's `<env>Working directory: <path></env>`.
|
|
11
|
+
*
|
|
12
|
+
* Consequently this adapter:
|
|
13
|
+
* - Returns `undefined` from extractWorkingDirectory so the SDK subprocess
|
|
14
|
+
* chdirs into `process.cwd()` (a valid server path) rather than the
|
|
15
|
+
* client's local filesystem layout.
|
|
16
|
+
* - Parses the client's local CWD via extractClientWorkingDirectory for
|
|
17
|
+
* fingerprinting and a system-prompt hint (see server.ts + query.ts).
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentAdapter } from "../adapter";
|
|
20
|
+
export declare const claudeCodeAdapter: AgentAdapter;
|
|
21
|
+
//# sourceMappingURL=claudecode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudecode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/claudecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgC9C,eAAO,MAAM,iBAAiB,EAAE,YA8F/B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crush.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/crush.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgB9C,eAAO,MAAM,YAAY,EAAE,YAyF1B,CAAA"}
|
|
1
|
+
{"version":3,"file":"crush.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/crush.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgB9C,eAAO,MAAM,YAAY,EAAE,YAyF1B,CAAA;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -15,8 +15,9 @@ import type { AgentAdapter } from "../adapter";
|
|
|
15
15
|
* 3. User-Agent starts with "opencode/" → OpenCode adapter
|
|
16
16
|
* 4. User-Agent starts with "factory-cli/" → Droid adapter
|
|
17
17
|
* 5. User-Agent starts with "Charm-Crush/" → Crush adapter
|
|
18
|
-
* 6.
|
|
19
|
-
* 7.
|
|
18
|
+
* 6. User-Agent starts with "claude-cli/" → Claude Code adapter
|
|
19
|
+
* 7. litellm/* UA or x-litellm-* headers → LiteLLM passthrough adapter
|
|
20
|
+
* 8. Default → MERIDIAN_DEFAULT_AGENT env var, or OpenCode
|
|
20
21
|
*/
|
|
21
22
|
export declare function detectAdapter(c: Context): AgentAdapter;
|
|
22
23
|
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/detect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/detect.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AA0C9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,YAAY,CAsCtD"}
|