@rynfar/meridian 1.62.5 → 1.62.6
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 +31 -1
- package/dist/{cli-je60fevk.js → cli-pc0mtjjv.js} +83 -1
- package/dist/{cli-dya07jbg.js → cli-wxk8xvd3.js} +25 -68
- package/dist/cli.js +4 -4
- package/dist/proxy/adapters/opencode.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts +43 -0
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{setup-6c11e8d6.js → setup-0x573t61.js} +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,13 +104,43 @@ The Claude Agent SDK provides programmatic access to Claude. But your favorite c
|
|
|
104
104
|
| [Aider](https://github.com/paul-gauthier/aider) | ✅ Verified | Env vars — file editing, streaming; `--no-stream` broken (litellm bug) |
|
|
105
105
|
| [Open WebUI](https://github.com/open-webui/open-webui) | ✅ Verified | OpenAI-compatible endpoints — set base URL to `http://127.0.0.1:3456` |
|
|
106
106
|
| [Pi](https://github.com/mariozechner/pi-coding-agent) | ✅ Verified | models.json config (see [Agent Setup](docs/agents.md)) — full tool support via passthrough; detected via `x-meridian-agent: pi` header |
|
|
107
|
-
| [Prime Agent](https://www.npmjs.com/package/prime-agent) |
|
|
107
|
+
| [Prime Agent](https://www.npmjs.com/package/prime-agent) | ⚠️ Single-agent verified | Extension config (see [Agent Setup](docs/agents.md)) — reliable with one active agent. Concurrent RLM subagents receive distinct session keys, but are not yet production-safe; see [Prime Agent subagents](#prime-agent-subagents). The extension's `metadata.user_id` stamp is **required**, not optional. |
|
|
108
108
|
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | ✅ Verified | `ANTHROPIC_BASE_URL` — remote clients share a Max subscription over the network; client CWD preserved in system prompt |
|
|
109
109
|
| [Cherry Studio](https://github.com/CherryHQ/cherry-studio) | ✅ Verified | `cherry` adapter (see [Agent Setup](docs/agents.md)) — chat client with Claude's built-in web search via internal mode |
|
|
110
110
|
| Jcode | ✅ Verified | `/v1/chat/completions` + `x-jcode-session` header — dedicated `jcode` adapter keeps append-only history intact, so retained sessions resume on one SDK session (90.9% cache hit on turn 2 of a two-turn Opus session) |
|
|
111
111
|
| [Codex CLI](https://github.com/openai/codex) | ✅ Verified | `/v1/responses` (see [Agent Setup](docs/agents.md)) — Responses-API provider, passthrough tool execution; verified on 0.144 (plain + tool-driving turns) |
|
|
112
112
|
| [Continue](https://github.com/continuedev/continue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http://127.0.0.1:3456` |
|
|
113
113
|
|
|
114
|
+
### Prime Agent subagents
|
|
115
|
+
|
|
116
|
+
Prime Agent is reliable through Meridian with one active agent. RLM children have
|
|
117
|
+
separate session identities and can execute successfully, but concurrent subagent
|
|
118
|
+
orchestration is not yet production-safe. Observed failure modes include overload
|
|
119
|
+
amplification, expensive cache churn after fresh-session replay, loss of child-task
|
|
120
|
+
context during recovery, undelivered tool envelopes, and incomplete parent-to-child
|
|
121
|
+
cancellation. Use a single active Prime Agent for unattended or usage-sensitive work
|
|
122
|
+
until coordinated fixes land in Prime Agent and Meridian.
|
|
123
|
+
|
|
124
|
+
Prime Agent can keep Opus on the root session while selecting Sol for an individual
|
|
125
|
+
child. A child inherits its parent's model unless the `rlm` call supplies an exact
|
|
126
|
+
`provider/model` selector returned by `rlm.find_models()`:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
sol_models = await rlm.find_models("sol")
|
|
130
|
+
print(sol_models) # choose an available exact selector for your authenticated providers
|
|
131
|
+
|
|
132
|
+
child = await rlm(
|
|
133
|
+
"Review this change and report your findings to the parent.",
|
|
134
|
+
name="sol-reviewer",
|
|
135
|
+
model="openai-codex/gpt-5.6-sol",
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The selector above requires an authenticated OpenAI Codex provider in Prime Agent;
|
|
140
|
+
Prime Inference may expose a different Sol selector. Explicit child model selection
|
|
141
|
+
reduces Claude Max pressure, but does not by itself fix the orchestration and
|
|
142
|
+
cancellation limitations above.
|
|
143
|
+
|
|
114
144
|
Tested an agent or built a plugin? [Open an issue](https://github.com/rynfar/meridian/issues) and we'll add it.
|
|
115
145
|
|
|
116
146
|
## FAQ
|
|
@@ -5,6 +5,72 @@ import { dirname, join } from "path";
|
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser";
|
|
7
7
|
|
|
8
|
+
// src/utils/lruMap.ts
|
|
9
|
+
class LRUMap {
|
|
10
|
+
maxSize;
|
|
11
|
+
onEvict;
|
|
12
|
+
map = new Map;
|
|
13
|
+
constructor(maxSize, onEvict) {
|
|
14
|
+
this.maxSize = maxSize;
|
|
15
|
+
this.onEvict = onEvict;
|
|
16
|
+
}
|
|
17
|
+
get size() {
|
|
18
|
+
return this.map.size;
|
|
19
|
+
}
|
|
20
|
+
get(key) {
|
|
21
|
+
const value = this.map.get(key);
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return;
|
|
24
|
+
this.map.delete(key);
|
|
25
|
+
this.map.set(key, value);
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
set(key, value) {
|
|
29
|
+
if (this.map.has(key)) {
|
|
30
|
+
this.map.delete(key);
|
|
31
|
+
} else if (this.map.size >= this.maxSize) {
|
|
32
|
+
this.evictOldest();
|
|
33
|
+
}
|
|
34
|
+
this.map.set(key, value);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
has(key) {
|
|
38
|
+
return this.map.has(key);
|
|
39
|
+
}
|
|
40
|
+
delete(key) {
|
|
41
|
+
return this.map.delete(key);
|
|
42
|
+
}
|
|
43
|
+
clear() {
|
|
44
|
+
this.map.clear();
|
|
45
|
+
}
|
|
46
|
+
entries() {
|
|
47
|
+
return this.map.entries();
|
|
48
|
+
}
|
|
49
|
+
keys() {
|
|
50
|
+
return this.map.keys();
|
|
51
|
+
}
|
|
52
|
+
values() {
|
|
53
|
+
return this.map.values();
|
|
54
|
+
}
|
|
55
|
+
forEach(callbackfn) {
|
|
56
|
+
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
57
|
+
}
|
|
58
|
+
[Symbol.iterator]() {
|
|
59
|
+
return this.map[Symbol.iterator]();
|
|
60
|
+
}
|
|
61
|
+
evictOldest() {
|
|
62
|
+
const oldestKey = this.map.keys().next().value;
|
|
63
|
+
if (oldestKey === undefined)
|
|
64
|
+
return;
|
|
65
|
+
const oldestValue = this.map.get(oldestKey);
|
|
66
|
+
if (oldestValue === undefined)
|
|
67
|
+
return;
|
|
68
|
+
this.map.delete(oldestKey);
|
|
69
|
+
this.onEvict?.(oldestKey, oldestValue);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/proxy/setup.ts
|
|
8
74
|
class UnparseableConfigError extends Error {
|
|
9
75
|
configPath;
|
|
10
76
|
constructor(configPath) {
|
|
@@ -55,6 +121,22 @@ function checkPluginConfigured(configPath) {
|
|
|
55
121
|
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
56
122
|
return plugins.some((p) => typeof p === "string" && isMeridianEntry(p));
|
|
57
123
|
}
|
|
124
|
+
var pluginlessWarned = new LRUMap(256);
|
|
125
|
+
function clearPluginlessWarnings() {
|
|
126
|
+
pluginlessWarned.clear();
|
|
127
|
+
}
|
|
128
|
+
function notePluginlessOpenCodeRequest(input) {
|
|
129
|
+
if (!input.userAgent?.toLowerCase().startsWith("opencode/"))
|
|
130
|
+
return;
|
|
131
|
+
if (input.agentModeHeader)
|
|
132
|
+
return;
|
|
133
|
+
const key = input.sessionId || "(keyless)";
|
|
134
|
+
if (pluginlessWarned.get(key))
|
|
135
|
+
return;
|
|
136
|
+
pluginlessWarned.set(key, true);
|
|
137
|
+
const shortId = input.sessionId ? `${input.sessionId.slice(0, 12)}…` : "(no session header)";
|
|
138
|
+
return `OpenCode request without the Meridian plugin's agent headers (session ${shortId}). ` + `OpenCode runs its internal title/summary agents under your session id, so Meridian ` + `cannot tell them apart from your conversation: the first turn of each session can fail ` + `with a 400 or replay against a cold cache. Fix: meridian setup (or update the plugin).`;
|
|
139
|
+
}
|
|
58
140
|
function runSetup(pluginPath, configPath) {
|
|
59
141
|
const path = configPath ?? findOpencodeConfigPath();
|
|
60
142
|
const dir = dirname(path);
|
|
@@ -82,4 +164,4 @@ function runSetup(pluginPath, configPath) {
|
|
|
82
164
|
return { configPath: path, pluginPath, alreadyConfigured, removedStale, created: false };
|
|
83
165
|
}
|
|
84
166
|
|
|
85
|
-
export { UnparseableConfigError, findOpencodeConfigPath, findPluginPath, checkPluginConfigured, runSetup };
|
|
167
|
+
export { LRUMap, UnparseableConfigError, findOpencodeConfigPath, findPluginPath, checkPluginConfigured, clearPluginlessWarnings, notePluginlessOpenCodeRequest, runSetup };
|
|
@@ -56,8 +56,10 @@ import {
|
|
|
56
56
|
setSetting
|
|
57
57
|
} from "./cli-vj9cv18n.js";
|
|
58
58
|
import {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
LRUMap,
|
|
60
|
+
checkPluginConfigured,
|
|
61
|
+
notePluginlessOpenCodeRequest
|
|
62
|
+
} from "./cli-pc0mtjjv.js";
|
|
61
63
|
import {
|
|
62
64
|
claudeLog,
|
|
63
65
|
createPlatformCredentialStore,
|
|
@@ -2282,7 +2284,13 @@ var init_opencode2 = __esm(() => {
|
|
|
2282
2284
|
openCodeAdapter = {
|
|
2283
2285
|
name: "opencode",
|
|
2284
2286
|
getSessionId(c) {
|
|
2285
|
-
|
|
2287
|
+
const base = c.req.header("x-opencode-session") ?? c.req.header("x-session-affinity");
|
|
2288
|
+
if (!base)
|
|
2289
|
+
return;
|
|
2290
|
+
if (c.req.header("x-opencode-agent-mode") !== "subagent")
|
|
2291
|
+
return base;
|
|
2292
|
+
const agent = c.req.header("x-opencode-agent-name")?.trim();
|
|
2293
|
+
return agent ? `${base}#${agent}` : base;
|
|
2286
2294
|
},
|
|
2287
2295
|
getAgentMode(c) {
|
|
2288
2296
|
return c.req.header("x-opencode-agent-mode");
|
|
@@ -11309,71 +11317,6 @@ function shouldAttemptRecovery(input) {
|
|
|
11309
11317
|
// src/proxy/server.ts
|
|
11310
11318
|
init_agentMatch();
|
|
11311
11319
|
|
|
11312
|
-
// src/utils/lruMap.ts
|
|
11313
|
-
class LRUMap {
|
|
11314
|
-
maxSize;
|
|
11315
|
-
onEvict;
|
|
11316
|
-
map = new Map;
|
|
11317
|
-
constructor(maxSize, onEvict) {
|
|
11318
|
-
this.maxSize = maxSize;
|
|
11319
|
-
this.onEvict = onEvict;
|
|
11320
|
-
}
|
|
11321
|
-
get size() {
|
|
11322
|
-
return this.map.size;
|
|
11323
|
-
}
|
|
11324
|
-
get(key) {
|
|
11325
|
-
const value = this.map.get(key);
|
|
11326
|
-
if (value === undefined)
|
|
11327
|
-
return;
|
|
11328
|
-
this.map.delete(key);
|
|
11329
|
-
this.map.set(key, value);
|
|
11330
|
-
return value;
|
|
11331
|
-
}
|
|
11332
|
-
set(key, value) {
|
|
11333
|
-
if (this.map.has(key)) {
|
|
11334
|
-
this.map.delete(key);
|
|
11335
|
-
} else if (this.map.size >= this.maxSize) {
|
|
11336
|
-
this.evictOldest();
|
|
11337
|
-
}
|
|
11338
|
-
this.map.set(key, value);
|
|
11339
|
-
return this;
|
|
11340
|
-
}
|
|
11341
|
-
has(key) {
|
|
11342
|
-
return this.map.has(key);
|
|
11343
|
-
}
|
|
11344
|
-
delete(key) {
|
|
11345
|
-
return this.map.delete(key);
|
|
11346
|
-
}
|
|
11347
|
-
clear() {
|
|
11348
|
-
this.map.clear();
|
|
11349
|
-
}
|
|
11350
|
-
entries() {
|
|
11351
|
-
return this.map.entries();
|
|
11352
|
-
}
|
|
11353
|
-
keys() {
|
|
11354
|
-
return this.map.keys();
|
|
11355
|
-
}
|
|
11356
|
-
values() {
|
|
11357
|
-
return this.map.values();
|
|
11358
|
-
}
|
|
11359
|
-
forEach(callbackfn) {
|
|
11360
|
-
this.map.forEach((value, key) => callbackfn(value, key, this));
|
|
11361
|
-
}
|
|
11362
|
-
[Symbol.iterator]() {
|
|
11363
|
-
return this.map[Symbol.iterator]();
|
|
11364
|
-
}
|
|
11365
|
-
evictOldest() {
|
|
11366
|
-
const oldestKey = this.map.keys().next().value;
|
|
11367
|
-
if (oldestKey === undefined)
|
|
11368
|
-
return;
|
|
11369
|
-
const oldestValue = this.map.get(oldestKey);
|
|
11370
|
-
if (oldestValue === undefined)
|
|
11371
|
-
return;
|
|
11372
|
-
this.map.delete(oldestKey);
|
|
11373
|
-
this.onEvict?.(oldestKey, oldestValue);
|
|
11374
|
-
}
|
|
11375
|
-
}
|
|
11376
|
-
|
|
11377
11320
|
// src/telemetry/index.ts
|
|
11378
11321
|
init_env();
|
|
11379
11322
|
import { join as join2 } from "node:path";
|
|
@@ -21445,6 +21388,20 @@ data: ${JSON.stringify(lastError)}
|
|
|
21445
21388
|
const taskBudget = Number.isFinite(parsedBudget) ? { total: parsedBudget } : body.task_budget ? { total: body.task_budget.total ?? body.task_budget } : undefined;
|
|
21446
21389
|
const betas = betaFilter.forwarded;
|
|
21447
21390
|
const agentSessionId = adapter.getSessionId(c, body);
|
|
21391
|
+
const pluginlessWarning = notePluginlessOpenCodeRequest({
|
|
21392
|
+
userAgent: c.req.header("user-agent"),
|
|
21393
|
+
agentModeHeader: c.req.header("x-opencode-agent-mode"),
|
|
21394
|
+
sessionId: agentSessionId
|
|
21395
|
+
});
|
|
21396
|
+
if (pluginlessWarning) {
|
|
21397
|
+
plog(`[PROXY] ${requestMeta.requestId} ${pluginlessWarning}`);
|
|
21398
|
+
diagnosticLog2.log({
|
|
21399
|
+
level: "warn",
|
|
21400
|
+
category: "session",
|
|
21401
|
+
message: `${requestMeta.requestId} ${pluginlessWarning}`,
|
|
21402
|
+
requestId: requestMeta.requestId
|
|
21403
|
+
});
|
|
21404
|
+
}
|
|
21448
21405
|
const profileSessionId = profile.id !== "default" && agentSessionId ? `${profile.id}:${agentSessionId}` : agentSessionId;
|
|
21449
21406
|
const commitSessionTurn = () => {
|
|
21450
21407
|
if (profileSessionId)
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startProxyServer
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-wxk8xvd3.js";
|
|
5
5
|
import"./cli-m0p2bc8v.js";
|
|
6
6
|
import"./cli-sry5aqdj.js";
|
|
7
7
|
import"./cli-xmweegb1.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveClaudeExecutableAsync
|
|
10
10
|
} from "./cli-d45dq9gf.js";
|
|
11
11
|
import"./cli-vj9cv18n.js";
|
|
12
|
-
import"./cli-
|
|
12
|
+
import"./cli-pc0mtjjv.js";
|
|
13
13
|
import"./cli-khhjyk04.js";
|
|
14
14
|
import {
|
|
15
15
|
__require
|
|
@@ -80,7 +80,7 @@ if (args[0] === "profile") {
|
|
|
80
80
|
process.exit(0);
|
|
81
81
|
}
|
|
82
82
|
if (args[0] === "setup") {
|
|
83
|
-
const { findPluginPath, runSetup, UnparseableConfigError } = await import("./setup-
|
|
83
|
+
const { findPluginPath, runSetup, UnparseableConfigError } = await import("./setup-0x573t61.js");
|
|
84
84
|
const pluginPath = findPluginPath(import.meta.url);
|
|
85
85
|
let result;
|
|
86
86
|
try {
|
|
@@ -146,7 +146,7 @@ async function runCli(start = startProxyServer, runAuthCheck = async () => {
|
|
|
146
146
|
return execFile(claudePath, ["auth", "status"], { timeout: 5000 });
|
|
147
147
|
}) {
|
|
148
148
|
try {
|
|
149
|
-
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-
|
|
149
|
+
const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-0x573t61.js");
|
|
150
150
|
const configPath = findOpencodeConfigPath();
|
|
151
151
|
const { existsSync } = await import("fs");
|
|
152
152
|
if (existsSync(configPath) && !checkPluginConfigured(configPath)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/opencode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/proxy/adapters/opencode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS9C,eAAO,MAAM,eAAe,EAAE,YAoK7B,CAAA;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAGvD,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAA;AAKpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAoDnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAGpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAIzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AA0W7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/proxy/server.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACtE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAGvD,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,aAAa,CAAA;AAKpB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAoDnG,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EAGpB,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAA+B,iBAAiB,EAAE,mBAAmB,EAAsC,MAAM,iBAAiB,CAAA;AAIzI,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAChE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,CAAA;AA0W7B,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CA0+JhF;AAWD,wBAAgB,gCAAgC,IAAI,IAAI,CAavD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqHhG"}
|
package/dist/proxy/setup.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* - `meridian setup` — writes the plugin entry
|
|
7
7
|
* - `meridian` startup — warns if plugin is missing
|
|
8
8
|
* - `GET /health` — reports plugin status
|
|
9
|
+
* - every request — warns when an OpenCode client sends no plugin
|
|
10
|
+
* headers (see notePluginlessOpenCodeRequest)
|
|
9
11
|
*/
|
|
10
12
|
/**
|
|
11
13
|
* Thrown when an existing OpenCode config can't be parsed (even tolerantly).
|
|
@@ -32,6 +34,47 @@ export declare function findPluginPath(fromUrl: string): string;
|
|
|
32
34
|
* plugin is missing.
|
|
33
35
|
*/
|
|
34
36
|
export declare function checkPluginConfigured(configPath?: string): boolean;
|
|
37
|
+
/** Reset the warned-session memory. Used by tests. */
|
|
38
|
+
export declare function clearPluginlessWarnings(): void;
|
|
39
|
+
/**
|
|
40
|
+
* NOTE: OpenCode-specific. Warn when an OpenCode client reaches the proxy
|
|
41
|
+
* without the plugin's agent headers, once per session.
|
|
42
|
+
*
|
|
43
|
+
* This exists because the exposure it reports cannot be fixed from inside
|
|
44
|
+
* Meridian. OpenCode 1.18.11 sends `x-session-affinity` natively, so a
|
|
45
|
+
* plugin-less client is fully keyed and never reaches the fingerprint fallback
|
|
46
|
+
* — and its internal `title` / `summary` / `compaction` agents run under the
|
|
47
|
+
* SAME session id as the user's chat. One real key, two unrelated
|
|
48
|
+
* conversations. Live, both attempts of a plugin-less run returned HTTP 400
|
|
49
|
+
* `session_turn_conflict` on the user's first turn after an ~8s wait.
|
|
50
|
+
*
|
|
51
|
+
* The fix for that collision scopes the session key by agent, which it reads
|
|
52
|
+
* from the plugin's `x-opencode-agent-mode`. A client that sends none cannot be
|
|
53
|
+
* scoped, and inferring the agent from request shape was tried and reverted:
|
|
54
|
+
* "tool-less, one message" is equally the first turn of an ordinary tool-less
|
|
55
|
+
* chat, and keying that apart broke resume for it.
|
|
56
|
+
*
|
|
57
|
+
* So the remaining job is to stop the exposure being silent. The startup
|
|
58
|
+
* warning in `bin/cli.ts` does not cover it — that one is gated on an OpenCode
|
|
59
|
+
* config FILE existing, deliberately, so Meridian stays quiet for the many
|
|
60
|
+
* clients that are not OpenCode. Run the documented
|
|
61
|
+
* `ANTHROPIC_BASE_URL=… opencode` with no config file and nothing warns.
|
|
62
|
+
*
|
|
63
|
+
* Keyed on the `opencode/` User-Agent rather than the resolved adapter:
|
|
64
|
+
* `MERIDIAN_DEFAULT_AGENT` defaults to opencode, so unrelated clients land on
|
|
65
|
+
* that adapter, and telling a Pi user to configure an OpenCode plugin is worse
|
|
66
|
+
* than saying nothing. The User-Agent has no such ambiguity.
|
|
67
|
+
*
|
|
68
|
+
* Returns the message to log, or undefined when there is nothing to say.
|
|
69
|
+
* Stateful but I/O-free — the caller owns the logging.
|
|
70
|
+
*/
|
|
71
|
+
export declare function notePluginlessOpenCodeRequest(input: {
|
|
72
|
+
userAgent: string | undefined;
|
|
73
|
+
/** The plugin's `x-opencode-agent-mode` header, if it sent one. */
|
|
74
|
+
agentModeHeader: string | undefined;
|
|
75
|
+
/** Client session id — used only to warn once per conversation. */
|
|
76
|
+
sessionId: string | undefined;
|
|
77
|
+
}): string | undefined;
|
|
35
78
|
export interface SetupResult {
|
|
36
79
|
configPath: string;
|
|
37
80
|
pluginPath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/proxy/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM;CAI/C;AAoBD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAW/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAkBD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAOlE;AAaD,sDAAsD;AACtD,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,mEAAmE;IACnE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,MAAM,GAAG,SAAS,CAkBrB;AAMD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAsC7E"}
|
package/dist/server.js
CHANGED
|
@@ -11,13 +11,13 @@ import {
|
|
|
11
11
|
runObserveHook,
|
|
12
12
|
runTransformHook,
|
|
13
13
|
startProxyServer
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-wxk8xvd3.js";
|
|
15
15
|
import"./cli-m0p2bc8v.js";
|
|
16
16
|
import"./cli-sry5aqdj.js";
|
|
17
17
|
import"./cli-xmweegb1.js";
|
|
18
18
|
import"./cli-d45dq9gf.js";
|
|
19
19
|
import"./cli-vj9cv18n.js";
|
|
20
|
-
import"./cli-
|
|
20
|
+
import"./cli-pc0mtjjv.js";
|
|
21
21
|
import"./cli-khhjyk04.js";
|
|
22
22
|
import"./cli-p9swy5t3.js";
|
|
23
23
|
export {
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
UnparseableConfigError,
|
|
3
3
|
checkPluginConfigured,
|
|
4
|
+
clearPluginlessWarnings,
|
|
4
5
|
findOpencodeConfigPath,
|
|
5
6
|
findPluginPath,
|
|
7
|
+
notePluginlessOpenCodeRequest,
|
|
6
8
|
runSetup
|
|
7
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-pc0mtjjv.js";
|
|
8
10
|
import"./cli-p9swy5t3.js";
|
|
9
11
|
export {
|
|
10
12
|
runSetup,
|
|
13
|
+
notePluginlessOpenCodeRequest,
|
|
11
14
|
findPluginPath,
|
|
12
15
|
findOpencodeConfigPath,
|
|
16
|
+
clearPluginlessWarnings,
|
|
13
17
|
checkPluginConfigured,
|
|
14
18
|
UnparseableConfigError
|
|
15
19
|
};
|
package/package.json
CHANGED