@rynfar/meridian 1.53.0 → 1.54.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.
@@ -23,6 +23,10 @@ import {
23
23
  } from "./cli-xmweegb1.js";
24
24
  import {
25
25
  CANONICAL_SONNET_MODEL,
26
+ OAUTH_CLIENT_ID,
27
+ OAUTH_REDIRECT_URI,
28
+ OAUTH_TOKEN_URL,
29
+ createManualOAuthSession,
26
30
  env,
27
31
  envBool,
28
32
  envInt,
@@ -34,12 +38,13 @@ import {
34
38
  init_env,
35
39
  isClosedControllerError,
36
40
  mapModelToClaudeModel,
41
+ parseAuthorizationCodeInput,
37
42
  recordExtendedContextUnavailable,
38
43
  resolveClaudeExecutableAsync,
39
44
  resolvePassthrough,
40
45
  resolveSdkModelDefaults,
41
46
  stripExtendedContext
42
- } from "./cli-vjeftz4z.js";
47
+ } from "./cli-jhm27q0x.js";
43
48
  import {
44
49
  getSetting
45
50
  } from "./cli-340h1chz.js";
@@ -1482,13 +1487,13 @@ __export(exports_sdkFeatures, {
1482
1487
  getAllFeatureConfigs: () => getAllFeatureConfigs
1483
1488
  });
1484
1489
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync3 } from "node:fs";
1485
- import { join as join6 } from "node:path";
1486
- import { homedir as homedir5 } from "node:os";
1490
+ import { join as join7 } from "node:path";
1491
+ import { homedir as homedir6 } from "node:os";
1487
1492
  function getConfigPath2() {
1488
- const dir = join6(homedir5(), ".config", "meridian");
1493
+ const dir = join7(homedir6(), ".config", "meridian");
1489
1494
  if (!existsSync7(dir))
1490
1495
  mkdirSync3(dir, { recursive: true });
1491
- return join6(dir, "sdk-features.json");
1496
+ return join7(dir, "sdk-features.json");
1492
1497
  }
1493
1498
  function readConfig() {
1494
1499
  const now = Date.now();
@@ -3641,6 +3646,112 @@ var cors = (options) => {
3641
3646
  };
3642
3647
  };
3643
3648
 
3649
+ // node_modules/hono/dist/utils/stream.js
3650
+ var StreamingApi = class {
3651
+ writer;
3652
+ encoder;
3653
+ writable;
3654
+ abortSubscribers = [];
3655
+ responseReadable;
3656
+ aborted = false;
3657
+ closed = false;
3658
+ constructor(writable, _readable) {
3659
+ this.writable = writable;
3660
+ this.writer = writable.getWriter();
3661
+ this.encoder = new TextEncoder;
3662
+ const reader = _readable.getReader();
3663
+ this.abortSubscribers.push(async () => {
3664
+ await reader.cancel();
3665
+ });
3666
+ this.responseReadable = new ReadableStream({
3667
+ async pull(controller) {
3668
+ const { done, value } = await reader.read();
3669
+ done ? controller.close() : controller.enqueue(value);
3670
+ },
3671
+ cancel: () => {
3672
+ this.abort();
3673
+ }
3674
+ });
3675
+ }
3676
+ async write(input) {
3677
+ try {
3678
+ if (typeof input === "string") {
3679
+ input = this.encoder.encode(input);
3680
+ }
3681
+ await this.writer.write(input);
3682
+ } catch {}
3683
+ return this;
3684
+ }
3685
+ async writeln(input) {
3686
+ await this.write(input + `
3687
+ `);
3688
+ return this;
3689
+ }
3690
+ sleep(ms) {
3691
+ return new Promise((res) => setTimeout(res, ms));
3692
+ }
3693
+ async close() {
3694
+ try {
3695
+ await this.writer.close();
3696
+ } catch {}
3697
+ this.closed = true;
3698
+ }
3699
+ async pipe(body) {
3700
+ this.writer.releaseLock();
3701
+ await body.pipeTo(this.writable, { preventClose: true });
3702
+ this.writer = this.writable.getWriter();
3703
+ }
3704
+ onAbort(listener) {
3705
+ this.abortSubscribers.push(listener);
3706
+ }
3707
+ abort() {
3708
+ if (!this.aborted) {
3709
+ this.aborted = true;
3710
+ this.abortSubscribers.forEach((subscriber) => subscriber());
3711
+ }
3712
+ }
3713
+ };
3714
+
3715
+ // node_modules/hono/dist/helper/streaming/utils.js
3716
+ var isOldBunVersion = () => {
3717
+ const version = typeof Bun !== "undefined" ? Bun.version : undefined;
3718
+ if (version === undefined) {
3719
+ return false;
3720
+ }
3721
+ const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
3722
+ isOldBunVersion = () => result;
3723
+ return result;
3724
+ };
3725
+
3726
+ // node_modules/hono/dist/helper/streaming/stream.js
3727
+ var contextStash = /* @__PURE__ */ new WeakMap;
3728
+ var stream = (c, cb, onError) => {
3729
+ const { readable, writable } = new TransformStream;
3730
+ const stream2 = new StreamingApi(writable, readable);
3731
+ if (isOldBunVersion()) {
3732
+ c.req.raw.signal.addEventListener("abort", () => {
3733
+ if (!stream2.closed) {
3734
+ stream2.abort();
3735
+ }
3736
+ });
3737
+ }
3738
+ contextStash.set(stream2.responseReadable, c);
3739
+ (async () => {
3740
+ try {
3741
+ await cb(stream2);
3742
+ } catch (e) {
3743
+ if (e === undefined) {} else if (e instanceof Error && onError) {
3744
+ await onError(e, stream2);
3745
+ } else {
3746
+ console.error(e);
3747
+ }
3748
+ } finally {
3749
+ stream2.close();
3750
+ }
3751
+ })();
3752
+ return c.newResponse(stream2.responseReadable);
3753
+ };
3754
+
3644
3755
  // node_modules/@hono/node-server/dist/index.mjs
3645
3756
  import { createServer as createServerHTTP } from "http";
3646
3757
  import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
@@ -3921,13 +4032,13 @@ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromi
3921
4032
  }
3922
4033
  }
3923
4034
  }
3924
- function writeFromReadableStream(stream, writable) {
3925
- if (stream.locked) {
4035
+ function writeFromReadableStream(stream2, writable) {
4036
+ if (stream2.locked) {
3926
4037
  throw new TypeError("ReadableStream is locked.");
3927
4038
  } else if (writable.destroyed) {
3928
4039
  return;
3929
4040
  }
3930
- return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
4041
+ return writeFromReadableStreamDefaultReader(stream2.getReader(), writable);
3931
4042
  }
3932
4043
  var buildOutgoingHttpHeaders = (headers) => {
3933
4044
  const res = {};
@@ -4192,8 +4303,8 @@ var serve = (options, listeningListener) => {
4192
4303
  };
4193
4304
 
4194
4305
  // src/proxy/server.ts
4195
- import { homedir as homedir6 } from "node:os";
4196
- import { join as join7 } from "node:path";
4306
+ import { homedir as homedir7 } from "node:os";
4307
+ import { join as join8 } from "node:path";
4197
4308
  import { query } from "@anthropic-ai/claude-agent-sdk";
4198
4309
 
4199
4310
  // src/proxy/rateLimitStore.ts
@@ -4542,7 +4653,7 @@ function createRequestContext(params) {
4542
4653
  }
4543
4654
  // src/proxy/server.ts
4544
4655
  import { exec as execCallback } from "child_process";
4545
- import { promisify as promisify2 } from "util";
4656
+ import { promisify as promisify3 } from "util";
4546
4657
  import { randomUUID } from "crypto";
4547
4658
 
4548
4659
  // src/proxy/passthroughTools.ts
@@ -10274,6 +10385,217 @@ function formatSdkTermination(t, ctx) {
10274
10385
  return `sdk_termination ${parts.join(" ")}`;
10275
10386
  }
10276
10387
 
10388
+ // src/proxy/design.ts
10389
+ import { homedir as homedir3 } from "node:os";
10390
+ import { join as join3, dirname as dirname3 } from "node:path";
10391
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
10392
+ var DESIGN_SCOPES = ["user:design:read", "user:design:write"];
10393
+ var DESIGN_UPSTREAM_ORIGIN = "https://api.anthropic.com";
10394
+ var EXPIRY_SKEW_MS = 60000;
10395
+ var LOGIN_SESSION_TTL_MS = 10 * 60 * 1000;
10396
+ function defaultDesignTokenPath() {
10397
+ return process.env.MERIDIAN_DESIGN_TOKEN_PATH || join3(homedir3(), ".config", "meridian", "design-token.json");
10398
+ }
10399
+ function createFileDesignTokenStore(path = defaultDesignTokenPath()) {
10400
+ return {
10401
+ async read() {
10402
+ try {
10403
+ const raw2 = await readFile(path, "utf-8");
10404
+ const data = JSON.parse(raw2);
10405
+ if (typeof data.accessToken === "string" && typeof data.expiresAt === "number") {
10406
+ return data;
10407
+ }
10408
+ return null;
10409
+ } catch {
10410
+ return null;
10411
+ }
10412
+ },
10413
+ async write(data) {
10414
+ await mkdir(dirname3(path), { recursive: true });
10415
+ await writeFile(path, JSON.stringify(data), { mode: 384 });
10416
+ }
10417
+ };
10418
+ }
10419
+ function isDesignTokenFresh(data, now = Date.now()) {
10420
+ return data.expiresAt > now + EXPIRY_SKEW_MS;
10421
+ }
10422
+ async function getDesignAccessToken(opts) {
10423
+ const now = opts.now ?? Date.now();
10424
+ const fetchFn = opts.fetchFn ?? fetch;
10425
+ const data = await opts.store.read();
10426
+ if (!data)
10427
+ return null;
10428
+ if (isDesignTokenFresh(data, now))
10429
+ return data.accessToken;
10430
+ if (!data.refreshToken)
10431
+ return null;
10432
+ let response;
10433
+ try {
10434
+ response = await fetchFn(OAUTH_TOKEN_URL, {
10435
+ method: "POST",
10436
+ headers: { "Content-Type": "application/json" },
10437
+ body: JSON.stringify({
10438
+ grant_type: "refresh_token",
10439
+ client_id: OAUTH_CLIENT_ID,
10440
+ refresh_token: data.refreshToken
10441
+ }),
10442
+ signal: AbortSignal.timeout(30000)
10443
+ });
10444
+ } catch {
10445
+ return null;
10446
+ }
10447
+ if (!response.ok)
10448
+ return null;
10449
+ let tokenData;
10450
+ try {
10451
+ tokenData = await response.json();
10452
+ } catch {
10453
+ return null;
10454
+ }
10455
+ if (!tokenData.access_token)
10456
+ return null;
10457
+ const refreshed = {
10458
+ accessToken: tokenData.access_token,
10459
+ refreshToken: tokenData.refresh_token ?? data.refreshToken,
10460
+ expiresAt: tokenData.expires_at ?? now + (tokenData.expires_in ?? 8 * 60 * 60) * 1000,
10461
+ scopes: tokenData.scope?.split(" ").filter(Boolean) ?? data.scopes
10462
+ };
10463
+ await opts.store.write(refreshed);
10464
+ return refreshed.accessToken;
10465
+ }
10466
+ async function resolveDesignAuthHeaders(opts) {
10467
+ if (opts.designToken)
10468
+ return { Authorization: `Bearer ${opts.designToken}` };
10469
+ const { profile } = opts;
10470
+ if (profile.type === "api" && profile.env.ANTHROPIC_API_KEY) {
10471
+ return { "x-api-key": profile.env.ANTHROPIC_API_KEY };
10472
+ }
10473
+ if (profile.type === "oauth-token" && profile.env.CLAUDE_CODE_OAUTH_TOKEN) {
10474
+ return { Authorization: `Bearer ${profile.env.CLAUDE_CODE_OAUTH_TOKEN}` };
10475
+ }
10476
+ if (opts.credentialStore) {
10477
+ if (opts.ensureFresh)
10478
+ await opts.ensureFresh(opts.credentialStore).catch(() => {});
10479
+ const creds = await opts.credentialStore.read();
10480
+ const token = creds?.claudeAiOauth?.accessToken;
10481
+ if (token)
10482
+ return { Authorization: `Bearer ${token}` };
10483
+ }
10484
+ return {};
10485
+ }
10486
+ function buildDesignForwardHeaders(getHeader, authHeaders) {
10487
+ const headers = {
10488
+ "anthropic-version": getHeader("anthropic-version") || "2023-06-01",
10489
+ "accept-encoding": "identity",
10490
+ ...authHeaders
10491
+ };
10492
+ for (const name of ["content-type", "anthropic-beta", "mcp-session-id"]) {
10493
+ const value = getHeader(name);
10494
+ if (value)
10495
+ headers[name] = value;
10496
+ }
10497
+ return headers;
10498
+ }
10499
+ var HOP_BY_HOP = new Set([
10500
+ "transfer-encoding",
10501
+ "connection",
10502
+ "keep-alive",
10503
+ "proxy-authenticate",
10504
+ "proxy-authorization",
10505
+ "te",
10506
+ "trailer",
10507
+ "upgrade"
10508
+ ]);
10509
+ function filterUpstreamResponseHeaders(headers) {
10510
+ const out = {};
10511
+ for (const [key, value] of headers) {
10512
+ if (!HOP_BY_HOP.has(key.toLowerCase()))
10513
+ out[key] = value;
10514
+ }
10515
+ return out;
10516
+ }
10517
+ function isDesignAuthFailure(status) {
10518
+ return status === 401 || status === 404;
10519
+ }
10520
+ function createDesignLogin(deps) {
10521
+ const createSession = deps.createSession ?? createManualOAuthSession;
10522
+ const fetchFn = deps.fetchFn ?? fetch;
10523
+ const now = deps.now ?? Date.now;
10524
+ const sessions = new Map;
10525
+ const startRaw = () => {
10526
+ for (const [state, session2] of sessions) {
10527
+ if (session2.expiresAt < now())
10528
+ sessions.delete(state);
10529
+ }
10530
+ const session = createSession(DESIGN_SCOPES);
10531
+ sessions.set(session.state, { codeVerifier: session.codeVerifier, expiresAt: now() + LOGIN_SESSION_TTL_MS });
10532
+ return { authorizeUrl: session.authorizeUrl, state: session.state };
10533
+ };
10534
+ return {
10535
+ startRaw,
10536
+ start() {
10537
+ const { authorizeUrl } = startRaw();
10538
+ return {
10539
+ authorizeUrl,
10540
+ instructions: 'Open the URL in your browser. After authorizing, POST the code to /design-login with body { "code": "<paste-code-here>" }'
10541
+ };
10542
+ },
10543
+ async exchange(rawBody) {
10544
+ const body = rawBody && typeof rawBody === "object" ? rawBody : {};
10545
+ const parsed = body.code ? parseAuthorizationCodeInput(body.code) : null;
10546
+ if (!parsed) {
10547
+ return { status: 400, body: { type: "error", error: { type: "invalid_request", message: "Missing or invalid 'code' field." } } };
10548
+ }
10549
+ const stateKey = parsed.state ?? body.state;
10550
+ const stored = stateKey ? sessions.get(stateKey) : undefined;
10551
+ if (!stateKey || !stored || stored.expiresAt < now()) {
10552
+ return {
10553
+ status: 400,
10554
+ body: { type: "error", error: { type: "session_expired", message: "OAuth session expired or not found. Call GET /design-login to start a new session." } }
10555
+ };
10556
+ }
10557
+ sessions.delete(stateKey);
10558
+ let response;
10559
+ try {
10560
+ response = await fetchFn(OAUTH_TOKEN_URL, {
10561
+ method: "POST",
10562
+ headers: { "Content-Type": "application/json" },
10563
+ body: JSON.stringify({
10564
+ grant_type: "authorization_code",
10565
+ client_id: OAUTH_CLIENT_ID,
10566
+ code: parsed.code,
10567
+ redirect_uri: OAUTH_REDIRECT_URI,
10568
+ code_verifier: stored.codeVerifier,
10569
+ state: stateKey
10570
+ }),
10571
+ signal: AbortSignal.timeout(30000)
10572
+ });
10573
+ } catch (err) {
10574
+ return { status: 502, body: { type: "error", error: { type: "upstream_error", message: err instanceof Error ? err.message : String(err) } } };
10575
+ }
10576
+ if (!response.ok) {
10577
+ const text = await response.text().catch(() => "");
10578
+ return {
10579
+ status: 502,
10580
+ body: { type: "error", error: { type: "token_exchange_failed", message: `Token exchange failed (${response.status}): ${text.slice(0, 200)}` } }
10581
+ };
10582
+ }
10583
+ const tokenData = await response.json();
10584
+ if (!tokenData.access_token) {
10585
+ return { status: 502, body: { type: "error", error: { type: "token_exchange_failed", message: "Token response missing access_token." } } };
10586
+ }
10587
+ const expiresAt = tokenData.expires_at ?? now() + (tokenData.expires_in ?? 8 * 60 * 60) * 1000;
10588
+ const scopes = tokenData.scope?.split(" ").filter(Boolean) ?? DESIGN_SCOPES;
10589
+ try {
10590
+ await deps.store.write({ accessToken: tokenData.access_token, refreshToken: tokenData.refresh_token, expiresAt, scopes });
10591
+ } catch (err) {
10592
+ return { status: 500, body: { type: "error", error: { type: "storage_error", message: `Failed to store design token: ${err instanceof Error ? err.message : String(err)}` } } };
10593
+ }
10594
+ return { status: 200, body: { success: true, scopes } };
10595
+ }
10596
+ };
10597
+ }
10598
+
10277
10599
  // src/proxy/openai.ts
10278
10600
  function extractOpenAiContent(content) {
10279
10601
  if (typeof content === "string")
@@ -12307,9 +12629,9 @@ var cherryAdapter = {
12307
12629
 
12308
12630
  // src/proxy/adapterInstances.ts
12309
12631
  import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
12310
- import { join as join3 } from "node:path";
12311
- import { homedir as homedir3 } from "node:os";
12312
- var CONFIG_FILE = join3(homedir3(), ".config", "meridian", "adapter-instances.json");
12632
+ import { join as join4 } from "node:path";
12633
+ import { homedir as homedir4 } from "node:os";
12634
+ var CONFIG_FILE = join4(homedir4(), ".config", "meridian", "adapter-instances.json");
12313
12635
  function parseAdapterInstances(raw2) {
12314
12636
  if (!raw2)
12315
12637
  return {};
@@ -12478,7 +12800,7 @@ import { createSdkMcpServer as createSdkMcpServer2, tool } from "@anthropic-ai/c
12478
12800
  import * as fs from "node:fs/promises";
12479
12801
  import * as path2 from "node:path";
12480
12802
  import { exec } from "node:child_process";
12481
- import { promisify } from "node:util";
12803
+ import { promisify as promisify2 } from "node:util";
12482
12804
 
12483
12805
  // node_modules/@isaacs/balanced-match/dist/esm/index.js
12484
12806
  var balanced = (a, b, str) => {
@@ -17999,7 +18321,7 @@ function globIterate(pattern, options = {}) {
17999
18321
  return new Glob(pattern, options).iterate();
18000
18322
  }
18001
18323
  var streamSync = globStreamSync;
18002
- var stream = Object.assign(globStream, { sync: globStreamSync });
18324
+ var stream2 = Object.assign(globStream, { sync: globStreamSync });
18003
18325
  var iterateSync = globIterateSync;
18004
18326
  var iterate = Object.assign(globIterate, {
18005
18327
  sync: globIterateSync
@@ -18013,7 +18335,7 @@ var glob = Object.assign(glob_, {
18013
18335
  globSync,
18014
18336
  sync,
18015
18337
  globStream,
18016
- stream,
18338
+ stream: stream2,
18017
18339
  globStreamSync,
18018
18340
  streamSync,
18019
18341
  globIterate,
@@ -18027,9 +18349,35 @@ var glob = Object.assign(glob_, {
18027
18349
  });
18028
18350
  glob.glob = glob;
18029
18351
 
18030
- // src/mcpTools.ts
18031
- var execAsync = promisify(exec);
18352
+ // src/grepTool.ts
18353
+ import { execFile } from "node:child_process";
18354
+ import { promisify } from "node:util";
18355
+ var execFileAsync = promisify(execFile);
18032
18356
  var getCwd = () => process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR ?? process.cwd();
18357
+ async function runGrepTool(args) {
18358
+ try {
18359
+ const searchPath = args.path || getCwd();
18360
+ const includePattern = args.include || "*";
18361
+ const grepArgs = ["-rn", `--include=${includePattern}`, args.pattern, searchPath];
18362
+ const { stdout } = await execFileAsync("grep", grepArgs, { maxBuffer: 10 * 1024 * 1024 });
18363
+ return {
18364
+ content: [{ type: "text", text: stdout || "(no matches)" }]
18365
+ };
18366
+ } catch (error) {
18367
+ const grepError = error;
18368
+ if (grepError.code === 1) {
18369
+ return { content: [{ type: "text", text: grepError.stdout || "(no matches)" }] };
18370
+ }
18371
+ return {
18372
+ content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
18373
+ isError: true
18374
+ };
18375
+ }
18376
+ }
18377
+
18378
+ // src/mcpTools.ts
18379
+ var execAsync = promisify2(exec);
18380
+ var getCwd2 = () => process.env.MERIDIAN_WORKDIR ?? process.env.CLAUDE_PROXY_WORKDIR ?? process.cwd();
18033
18381
  function createOpencodeMcpServer() {
18034
18382
  return createSdkMcpServer2({
18035
18383
  name: "opencode",
@@ -18040,7 +18388,7 @@ function createOpencodeMcpServer() {
18040
18388
  encoding: exports_external.string().optional().describe("File encoding, defaults to utf-8")
18041
18389
  }, async (args) => {
18042
18390
  try {
18043
- const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd(), args.path);
18391
+ const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd2(), args.path);
18044
18392
  const content = await fs.readFile(filePath, args.encoding || "utf-8");
18045
18393
  return {
18046
18394
  content: [{ type: "text", text: content }]
@@ -18057,7 +18405,7 @@ function createOpencodeMcpServer() {
18057
18405
  content: exports_external.string().describe("Content to write")
18058
18406
  }, async (args) => {
18059
18407
  try {
18060
- const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd(), args.path);
18408
+ const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd2(), args.path);
18061
18409
  await fs.mkdir(path2.dirname(filePath), { recursive: true });
18062
18410
  await fs.writeFile(filePath, args.content, "utf-8");
18063
18411
  return {
@@ -18076,7 +18424,7 @@ function createOpencodeMcpServer() {
18076
18424
  newString: exports_external.string().describe("The replacement text")
18077
18425
  }, async (args) => {
18078
18426
  try {
18079
- const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd(), args.path);
18427
+ const filePath = path2.isAbsolute(args.path) ? args.path : path2.resolve(getCwd2(), args.path);
18080
18428
  const content = await fs.readFile(filePath, "utf-8");
18081
18429
  if (!content.includes(args.oldString)) {
18082
18430
  return {
@@ -18102,7 +18450,7 @@ function createOpencodeMcpServer() {
18102
18450
  }, async (args) => {
18103
18451
  try {
18104
18452
  const options = {
18105
- cwd: args.cwd || getCwd(),
18453
+ cwd: args.cwd || getCwd2(),
18106
18454
  timeout: 120000
18107
18455
  };
18108
18456
  const { stdout, stderr } = await execAsync(args.command, options);
@@ -18125,7 +18473,7 @@ function createOpencodeMcpServer() {
18125
18473
  }, async (args) => {
18126
18474
  try {
18127
18475
  const files = await glob(args.pattern, {
18128
- cwd: args.cwd || getCwd(),
18476
+ cwd: args.cwd || getCwd2(),
18129
18477
  nodir: true,
18130
18478
  ignore: ["**/node_modules/**", "**/.git/**"]
18131
18479
  });
@@ -18144,22 +18492,7 @@ function createOpencodeMcpServer() {
18144
18492
  pattern: exports_external.string().describe("Regex pattern to search for"),
18145
18493
  path: exports_external.string().optional().describe("Directory or file to search in"),
18146
18494
  include: exports_external.string().optional().describe("File pattern to include, e.g., *.ts")
18147
- }, async (args) => {
18148
- try {
18149
- const searchPath = args.path || getCwd();
18150
- const includePattern = args.include || "*";
18151
- let cmd = `grep -rn --include="${includePattern}" "${args.pattern}" "${searchPath}" 2>/dev/null || true`;
18152
- const { stdout } = await execAsync(cmd, { maxBuffer: 10 * 1024 * 1024 });
18153
- return {
18154
- content: [{ type: "text", text: stdout || "(no matches)" }]
18155
- };
18156
- } catch (error) {
18157
- return {
18158
- content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
18159
- isError: true
18160
- };
18161
- }
18162
- })
18495
+ }, runGrepTool)
18163
18496
  ]
18164
18497
  });
18165
18498
  }
@@ -18219,7 +18552,7 @@ function buildQueryOptions(ctx, abortController) {
18219
18552
  systemContext,
18220
18553
  claudeExecutable,
18221
18554
  passthrough,
18222
- stream: stream2,
18555
+ stream: stream3,
18223
18556
  sdkAgents,
18224
18557
  passthroughMcp,
18225
18558
  cleanEnv,
@@ -18261,7 +18594,7 @@ function buildQueryOptions(ctx, abortController) {
18261
18594
  model,
18262
18595
  pathToClaudeCodeExecutable: claudeExecutable,
18263
18596
  ...abortController ? { abortController } : {},
18264
- ...stream2 ? { includePartialMessages: true } : {},
18597
+ ...stream3 ? { includePartialMessages: true } : {},
18265
18598
  permissionMode: "bypassPermissions",
18266
18599
  allowDangerouslySkipPermissions: true,
18267
18600
  ...resolveSystemPrompt(systemContext, passthrough, settingSources, codeSystemPrompt, clientSystemPrompt, cwdNote),
@@ -18401,7 +18734,7 @@ function getAdapterTransforms(adapterName) {
18401
18734
 
18402
18735
  // src/proxy/plugins/loader.ts
18403
18736
  import { readdirSync as readdirSync2, readFileSync as readFileSync4, existsSync as existsSync5 } from "fs";
18404
- import { join as join4, isAbsolute as isAbsolute2, extname } from "path";
18737
+ import { join as join5, isAbsolute as isAbsolute2, extname } from "path";
18405
18738
  import { pathToFileURL } from "url";
18406
18739
 
18407
18740
  // src/proxy/plugins/validation.ts
@@ -18486,7 +18819,7 @@ async function loadPlugins(pluginDir, configPath) {
18486
18819
  const loaded = [];
18487
18820
  const seenNames = new Set;
18488
18821
  for (const { filename, entry } of ordered) {
18489
- const filePath = isAbsolute2(filename) ? filename : join4(pluginDir, filename);
18822
+ const filePath = isAbsolute2(filename) ? filename : join5(pluginDir, filename);
18490
18823
  if (entry && !entry.enabled) {
18491
18824
  loaded.push({
18492
18825
  name: filename,
@@ -18868,8 +19201,8 @@ import {
18868
19201
  unlinkSync,
18869
19202
  writeFileSync as writeFileSync2
18870
19203
  } from "node:fs";
18871
- import { homedir as homedir4 } from "node:os";
18872
- import { join as join5 } from "node:path";
19204
+ import { homedir as homedir5 } from "node:os";
19205
+ import { join as join6 } from "node:path";
18873
19206
  var DEFAULT_MAX_STORED_SESSIONS = 1e4;
18874
19207
  var STALE_LOCK_THRESHOLD_MS = 30000;
18875
19208
  function getMaxStoredSessions() {
@@ -18920,11 +19253,11 @@ function getStorePath() {
18920
19253
  if (!existsSync6(dir)) {
18921
19254
  mkdirSync2(dir, { recursive: true });
18922
19255
  }
18923
- return join5(dir, "sessions.json");
19256
+ return join6(dir, "sessions.json");
18924
19257
  }
18925
19258
  function getDefaultCacheDir() {
18926
- const newDir = join5(homedir4(), ".cache", "meridian");
18927
- const oldDir = join5(homedir4(), ".cache", "opencode-claude-max-proxy");
19259
+ const newDir = join6(homedir5(), ".cache", "meridian");
19260
+ const oldDir = join6(homedir5(), ".cache", "opencode-claude-max-proxy");
18928
19261
  if (existsSync6(newDir))
18929
19262
  return newDir;
18930
19263
  if (existsSync6(oldDir)) {
@@ -19264,7 +19597,7 @@ function storeSession(sessionId, messages, claudeSessionId, workingDirectory, sd
19264
19597
  }
19265
19598
 
19266
19599
  // src/proxy/server.ts
19267
- var exec2 = promisify2(execCallback);
19600
+ var exec2 = promisify3(execCallback);
19268
19601
  var claudeExecutable = "";
19269
19602
  var UPSTREAM_IDLE_MS = 90000;
19270
19603
  function credentialStoreForProfile(profile) {
@@ -19494,8 +19827,8 @@ function createProxyServer(config = {}) {
19494
19827
  pendingSessionStores.delete(key);
19495
19828
  };
19496
19829
  };
19497
- const pluginDir = finalConfig.pluginDir ?? join7(homedir6(), ".config", "meridian", "plugins");
19498
- const pluginConfigPath = finalConfig.pluginConfigPath ?? join7(homedir6(), ".config", "meridian", "plugins.json");
19830
+ const pluginDir = finalConfig.pluginDir ?? join8(homedir7(), ".config", "meridian", "plugins");
19831
+ const pluginConfigPath = finalConfig.pluginConfigPath ?? join8(homedir7(), ".config", "meridian", "plugins.json");
19499
19832
  let loadedPlugins = [];
19500
19833
  let pluginTransforms = [];
19501
19834
  const app = new Hono2;
@@ -19511,6 +19844,7 @@ function createProxyServer(config = {}) {
19511
19844
  app.use("/plugins", requireAuth);
19512
19845
  app.use("/settings/*", requireAuth);
19513
19846
  app.use("/settings", requireAuth);
19847
+ app.use("/design-login", requireAuth);
19514
19848
  app.use("/auth/*", requireAuth);
19515
19849
  app.get("/", (c) => {
19516
19850
  const accept = c.req.header("accept") || "";
@@ -19519,7 +19853,7 @@ function createProxyServer(config = {}) {
19519
19853
  status: "ok",
19520
19854
  service: "meridian",
19521
19855
  format: "anthropic",
19522
- endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/responses", "/v1/models", "/telemetry", "/metrics", "/health"]
19856
+ endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/responses", "/v1/models", "/v1/design/*", "/design-login", "/telemetry", "/metrics", "/health"]
19523
19857
  });
19524
19858
  }
19525
19859
  return c.html(landingHtml);
@@ -19632,7 +19966,7 @@ function createProxyServer(config = {}) {
19632
19966
  stream: body.stream ?? false,
19633
19967
  workingDirectory
19634
19968
  }), adapterBase);
19635
- const stream2 = pipelineCtx.prefersStreaming !== undefined ? pipelineCtx.prefersStreaming : body.stream ?? false;
19969
+ const stream3 = pipelineCtx.prefersStreaming !== undefined ? pipelineCtx.prefersStreaming : body.stream ?? false;
19636
19970
  const effortHeader = c.req.header("x-opencode-effort");
19637
19971
  const thinkingHeader = c.req.header("x-opencode-thinking");
19638
19972
  const taskBudgetHeader = c.req.header("x-opencode-task-budget");
@@ -19707,7 +20041,7 @@ function createProxyServer(config = {}) {
19707
20041
  const lineageType = lineageResult.type === "diverged" && !cachedSession ? "new" : lineageResult.type;
19708
20042
  const msgCount = Array.isArray(body.messages) ? body.messages.length : 0;
19709
20043
  const toolCount = body.tools?.length ?? 0;
19710
- const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name}${requestSource ? ` source=${requestSource}` : ""}${profile.id !== "default" ? ` profile=${profile.id}${routingMode === "sticky" ? "(sticky)" : ""}` : ""} model=${model} stream=${stream2} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
20044
+ const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name}${requestSource ? ` source=${requestSource}` : ""}${profile.id !== "default" ? ` profile=${profile.id}${routingMode === "sticky" ? "(sticky)" : ""}` : ""} model=${model} stream=${stream3} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
19711
20045
  plog(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
19712
20046
  diagnosticLog2.session(`${requestLogLine}`, requestMeta.requestId);
19713
20047
  if (lineageResult.type === "diverged" && profileSessionId && !isIndependentSession) {
@@ -19721,7 +20055,7 @@ function createProxyServer(config = {}) {
19721
20055
  }
19722
20056
  claudeLog("request.received", {
19723
20057
  model,
19724
- stream: stream2,
20058
+ stream: stream3,
19725
20059
  queueWaitMs: requestMeta.queueStartedAt - requestMeta.queueEnteredAt,
19726
20060
  messageCount: Array.isArray(body.messages) ? body.messages.length : 0,
19727
20061
  hasSystemPrompt: Boolean(body.system)
@@ -19960,7 +20294,7 @@ function createProxyServer(config = {}) {
19960
20294
  stderrLines.push(data.trimEnd());
19961
20295
  claudeLog("subprocess.stderr", { line: data.trimEnd() });
19962
20296
  };
19963
- if (!stream2) {
20297
+ if (!stream3) {
19964
20298
  const contentBlocks = [];
19965
20299
  let assistantMessages = 0;
19966
20300
  let hasStructuredOutput = false;
@@ -22147,6 +22481,65 @@ data: ${JSON.stringify({ response: { id: responseId, status: "failed", error: {
22147
22481
  } : {}
22148
22482
  });
22149
22483
  });
22484
+ const designTokenStore = createFileDesignTokenStore();
22485
+ const designLogin = createDesignLogin({ store: designTokenStore });
22486
+ app.get("/design-login", (c) => c.json(designLogin.start()));
22487
+ app.post("/design-login", async (c) => {
22488
+ let body;
22489
+ try {
22490
+ body = await c.req.json();
22491
+ } catch {
22492
+ return c.json({ type: "error", error: { type: "invalid_request", message: "Request body must be JSON with a 'code' field." } }, 400);
22493
+ }
22494
+ const result = await designLogin.exchange(body);
22495
+ if (result.status === 200)
22496
+ plog(`[PROXY] Design token stored via /design-login`);
22497
+ return new Response(JSON.stringify(result.body), {
22498
+ status: result.status,
22499
+ headers: { "content-type": "application/json" }
22500
+ });
22501
+ });
22502
+ app.get("/v1/design/*", (c) => {
22503
+ c.status(200);
22504
+ c.header("content-type", "text/event-stream");
22505
+ c.header("cache-control", "no-cache");
22506
+ return stream(c, async (s) => {
22507
+ while (!s.aborted) {
22508
+ await s.write(`: keepalive
22509
+
22510
+ `);
22511
+ await s.sleep(15000);
22512
+ }
22513
+ });
22514
+ });
22515
+ app.post("/v1/design/*", async (c) => {
22516
+ const profile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile, c.req.header("x-meridian-profile") || undefined);
22517
+ const url = new URL(c.req.url);
22518
+ const upstreamUrl = `${DESIGN_UPSTREAM_ORIGIN}${url.pathname}${url.search}`;
22519
+ const designToken = await getDesignAccessToken({ store: designTokenStore });
22520
+ const authHeaders = await resolveDesignAuthHeaders({
22521
+ designToken,
22522
+ profile,
22523
+ credentialStore: credentialStoreForProfile(profile),
22524
+ ensureFresh: ensureFreshToken
22525
+ });
22526
+ const body = await c.req.arrayBuffer();
22527
+ const forwardHeaders = buildDesignForwardHeaders((name) => c.req.header(name), authHeaders);
22528
+ let upstreamRes;
22529
+ try {
22530
+ upstreamRes = await fetch(upstreamUrl, { method: "POST", headers: forwardHeaders, body });
22531
+ } catch (err) {
22532
+ return c.json({ type: "error", error: { type: "upstream_error", message: err instanceof Error ? err.message : String(err) } }, 502);
22533
+ }
22534
+ if (isDesignAuthFailure(upstreamRes.status)) {
22535
+ return c.json({ type: "error", error: { type: "auth_error", message: "Unauthorized. Run /design-login to authorize Claude Design (adds user:design:read/write scopes)." } }, 401);
22536
+ }
22537
+ plog(`[PROXY] DESIGN upstream=${upstreamRes.status}`);
22538
+ return new Response(upstreamRes.body, {
22539
+ status: upstreamRes.status,
22540
+ headers: filterUpstreamResponseHeaders(upstreamRes.headers.entries())
22541
+ });
22542
+ });
22150
22543
  app.all("*", (c) => {
22151
22544
  plog(`[PROXY] UNHANDLED ${c.req.method} ${c.req.url}`);
22152
22545
  return c.json({ error: { type: "not_found", message: `Endpoint not supported: ${c.req.method} ${new URL(c.req.url).pathname}` } }, 404);