@rynfar/meridian 1.72.0 → 1.74.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.
Files changed (177) hide show
  1. package/README.md +119 -107
  2. package/assets/banner.svg +18 -43
  3. package/assets/how-it-works.svg +40 -86
  4. package/assets/providers/README.md +10 -0
  5. package/assets/providers/antigravity.png +0 -0
  6. package/assets/providers/claude.png +0 -0
  7. package/dist/antigravity-clients/opencode.js +173 -0
  8. package/dist/antigravity-clients/pi.js +21 -0
  9. package/dist/antigravitySetup-35pd5xqn.js +191 -0
  10. package/dist/cli-1jstkdj9.js +30 -0
  11. package/dist/{cli-9e5cxp89.js → cli-2h3w5n6g.js} +163 -65
  12. package/dist/cli-3zwfvexc.js +56 -0
  13. package/dist/{cli-hxxy0m1z.js → cli-82e2m44k.js} +2 -1
  14. package/dist/cli-8sw5wr9j.js +136 -0
  15. package/dist/{cli-khhjyk04.js → cli-chsp880k.js} +214 -21
  16. package/dist/cli-dh0a1bw4.js +619 -0
  17. package/dist/cli-eehk3052.js +57 -0
  18. package/dist/{cli-ab7zkp1a.js → cli-fveyj34s.js} +32261 -18952
  19. package/dist/cli-grfp0s1j.js +330 -0
  20. package/dist/cli-qpfky8wy.js +133 -0
  21. package/dist/{cli-hj61zpt7.js → cli-wbsmhxcx.js} +26 -2
  22. package/dist/cli.js +111 -38
  23. package/dist/cliDashboard-c0dvkj4y.js +325 -0
  24. package/dist/configDir.d.ts +30 -0
  25. package/dist/configDir.d.ts.map +1 -0
  26. package/dist/organizationName-90f0atkn.js +29 -0
  27. package/dist/{pluginPage-f5gdmbxc.js → pluginPage-pp72d2j8.js} +1 -1
  28. package/dist/{profileCli-1eecbmgk.js → profileCli-1bfgc05h.js} +13 -3
  29. package/dist/{profilePage-mamej7kp.js → profilePage-vs319rvf.js} +252 -60
  30. package/dist/profileRename-4a4km6g8.js +22 -0
  31. package/dist/{profiles-wch9h234.js → profiles-0mp32ek9.js} +16 -3
  32. package/dist/proxy/adapterInstances.d.ts +1 -1
  33. package/dist/proxy/adapterInstances.d.ts.map +1 -1
  34. package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
  35. package/dist/proxy/adapters/droid.d.ts.map +1 -1
  36. package/dist/proxy/auth.d.ts +2 -0
  37. package/dist/proxy/auth.d.ts.map +1 -1
  38. package/dist/proxy/authDiscovery.d.ts +52 -0
  39. package/dist/proxy/authDiscovery.d.ts.map +1 -0
  40. package/dist/proxy/backends/antigravity.d.ts +8 -0
  41. package/dist/proxy/backends/antigravity.d.ts.map +1 -0
  42. package/dist/proxy/backends/antigravityAttachments.d.ts +16 -0
  43. package/dist/proxy/backends/antigravityAttachments.d.ts.map +1 -0
  44. package/dist/proxy/backends/antigravityGrammar.d.ts +12 -0
  45. package/dist/proxy/backends/antigravityGrammar.d.ts.map +1 -0
  46. package/dist/proxy/backends/antigravityJobs.d.ts +19 -0
  47. package/dist/proxy/backends/antigravityJobs.d.ts.map +1 -0
  48. package/dist/proxy/backends/antigravityMedia.d.ts +9 -0
  49. package/dist/proxy/backends/antigravityMedia.d.ts.map +1 -0
  50. package/dist/proxy/backends/antigravityNative.d.ts +8 -0
  51. package/dist/proxy/backends/antigravityNative.d.ts.map +1 -0
  52. package/dist/proxy/backends/antigravityOpenai.d.ts +9 -0
  53. package/dist/proxy/backends/antigravityOpenai.d.ts.map +1 -0
  54. package/dist/proxy/backends/antigravityOpenaiMedia.d.ts +9 -0
  55. package/dist/proxy/backends/antigravityOpenaiMedia.d.ts.map +1 -0
  56. package/dist/proxy/backends/antigravityPlugins.d.ts +41 -0
  57. package/dist/proxy/backends/antigravityPlugins.d.ts.map +1 -0
  58. package/dist/proxy/backends/antigravityProbe.d.ts +16 -0
  59. package/dist/proxy/backends/antigravityProbe.d.ts.map +1 -0
  60. package/dist/proxy/backends/antigravityProcess.d.ts +4 -0
  61. package/dist/proxy/backends/antigravityProcess.d.ts.map +1 -0
  62. package/dist/proxy/backends/antigravityProtocol.d.ts +582 -0
  63. package/dist/proxy/backends/antigravityProtocol.d.ts.map +1 -0
  64. package/dist/proxy/backends/antigravityReplay.d.ts +41 -0
  65. package/dist/proxy/backends/antigravityReplay.d.ts.map +1 -0
  66. package/dist/proxy/backends/antigravityResponses.d.ts +35 -0
  67. package/dist/proxy/backends/antigravityResponses.d.ts.map +1 -0
  68. package/dist/proxy/backends/antigravityRuntime.d.ts +189 -0
  69. package/dist/proxy/backends/antigravityRuntime.d.ts.map +1 -0
  70. package/dist/proxy/backends/antigravitySchema.d.ts +10 -0
  71. package/dist/proxy/backends/antigravitySchema.d.ts.map +1 -0
  72. package/dist/proxy/backends/antigravitySessions.d.ts +28 -0
  73. package/dist/proxy/backends/antigravitySessions.d.ts.map +1 -0
  74. package/dist/proxy/backends/antigravityState.d.ts +22 -0
  75. package/dist/proxy/backends/antigravityState.d.ts.map +1 -0
  76. package/dist/proxy/backends/antigravityStops.d.ts +10 -0
  77. package/dist/proxy/backends/antigravityStops.d.ts.map +1 -0
  78. package/dist/proxy/backends/antigravityTokens.d.ts +14 -0
  79. package/dist/proxy/backends/antigravityTokens.d.ts.map +1 -0
  80. package/dist/proxy/backends/antigravityUrl.d.ts +7 -0
  81. package/dist/proxy/backends/antigravityUrl.d.ts.map +1 -0
  82. package/dist/proxy/backends/providerStatus.d.ts +15 -0
  83. package/dist/proxy/backends/providerStatus.d.ts.map +1 -0
  84. package/dist/proxy/credentialsMode.d.ts +77 -0
  85. package/dist/proxy/credentialsMode.d.ts.map +1 -0
  86. package/dist/proxy/design.d.ts.map +1 -1
  87. package/dist/proxy/followActive.d.ts +262 -0
  88. package/dist/proxy/followActive.d.ts.map +1 -0
  89. package/dist/proxy/limitDetection.d.ts +110 -0
  90. package/dist/proxy/limitDetection.d.ts.map +1 -0
  91. package/dist/proxy/models.d.ts.map +1 -1
  92. package/dist/proxy/oauthPlan.d.ts +63 -0
  93. package/dist/proxy/oauthPlan.d.ts.map +1 -0
  94. package/dist/proxy/oauthUsage.d.ts +65 -2
  95. package/dist/proxy/oauthUsage.d.ts.map +1 -1
  96. package/dist/proxy/openai.d.ts +6 -2
  97. package/dist/proxy/openai.d.ts.map +1 -1
  98. package/dist/proxy/organizationName.d.ts +71 -0
  99. package/dist/proxy/organizationName.d.ts.map +1 -0
  100. package/dist/proxy/passthroughEarlyStop.d.ts +10 -0
  101. package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
  102. package/dist/proxy/planAllowance.d.ts +75 -0
  103. package/dist/proxy/planAllowance.d.ts.map +1 -0
  104. package/dist/proxy/probes.d.ts +85 -0
  105. package/dist/proxy/probes.d.ts.map +1 -0
  106. package/dist/proxy/profileCli.d.ts +53 -1
  107. package/dist/proxy/profileCli.d.ts.map +1 -1
  108. package/dist/proxy/profileHealth.d.ts +127 -0
  109. package/dist/proxy/profileHealth.d.ts.map +1 -0
  110. package/dist/proxy/profileRename.d.ts +83 -0
  111. package/dist/proxy/profileRename.d.ts.map +1 -0
  112. package/dist/proxy/profiles.d.ts +72 -6
  113. package/dist/proxy/profiles.d.ts.map +1 -1
  114. package/dist/proxy/query.d.ts +7 -0
  115. package/dist/proxy/query.d.ts.map +1 -1
  116. package/dist/proxy/routing.d.ts +59 -1
  117. package/dist/proxy/routing.d.ts.map +1 -1
  118. package/dist/proxy/sdkFeatures.d.ts +1 -1
  119. package/dist/proxy/sdkFeatures.d.ts.map +1 -1
  120. package/dist/proxy/server.d.ts.map +1 -1
  121. package/dist/proxy/session/fingerprint.d.ts +5 -0
  122. package/dist/proxy/session/fingerprint.d.ts.map +1 -1
  123. package/dist/proxy/session/lineage.d.ts.map +1 -1
  124. package/dist/proxy/setup.d.ts.map +1 -1
  125. package/dist/proxy/supervision.d.ts +41 -0
  126. package/dist/proxy/supervision.d.ts.map +1 -0
  127. package/dist/proxy/tokenRefresh.d.ts +38 -4
  128. package/dist/proxy/tokenRefresh.d.ts.map +1 -1
  129. package/dist/proxy/types.d.ts +32 -0
  130. package/dist/proxy/types.d.ts.map +1 -1
  131. package/dist/server.js +11 -7
  132. package/dist/settings.d.ts +83 -0
  133. package/dist/settings.d.ts.map +1 -0
  134. package/dist/{setup-ndmjpy23.js → setup-7fr49z92.js} +1 -1
  135. package/dist/statusProbe-9x9q261e.js +151 -0
  136. package/dist/telemetry/dashboard.d.ts.map +1 -1
  137. package/dist/telemetry/index.d.ts +20 -2
  138. package/dist/telemetry/index.d.ts.map +1 -1
  139. package/dist/telemetry/landing.d.ts +1 -1
  140. package/dist/telemetry/landing.d.ts.map +1 -1
  141. package/dist/telemetry/logStore.d.ts +11 -0
  142. package/dist/telemetry/logStore.d.ts.map +1 -1
  143. package/dist/telemetry/pricingStore.d.ts +2 -2
  144. package/dist/telemetry/pricingStore.d.ts.map +1 -1
  145. package/dist/telemetry/profileBar.d.ts +3 -3
  146. package/dist/telemetry/profileBar.d.ts.map +1 -1
  147. package/dist/telemetry/profileFacts.d.ts +17 -0
  148. package/dist/telemetry/profileFacts.d.ts.map +1 -0
  149. package/dist/telemetry/profileOrder.d.ts +68 -0
  150. package/dist/telemetry/profileOrder.d.ts.map +1 -0
  151. package/dist/telemetry/profilePage.d.ts.map +1 -1
  152. package/dist/telemetry/profileSort.d.ts +35 -0
  153. package/dist/telemetry/profileSort.d.ts.map +1 -0
  154. package/dist/telemetry/profileSpent.d.ts +68 -0
  155. package/dist/telemetry/profileSpent.d.ts.map +1 -0
  156. package/dist/telemetry/providerPage.d.ts +2 -0
  157. package/dist/telemetry/providerPage.d.ts.map +1 -0
  158. package/dist/telemetry/providerSetup.d.ts +5 -0
  159. package/dist/telemetry/providerSetup.d.ts.map +1 -0
  160. package/dist/telemetry/providerView.d.ts +45 -0
  161. package/dist/telemetry/providerView.d.ts.map +1 -0
  162. package/dist/telemetry/routeChain.d.ts +32 -0
  163. package/dist/telemetry/routeChain.d.ts.map +1 -0
  164. package/dist/telemetry/routes.d.ts.map +1 -1
  165. package/dist/telemetry/settingsPage.d.ts +1 -1
  166. package/dist/telemetry/settingsPage.d.ts.map +1 -1
  167. package/dist/telemetry/sqlite.d.ts.map +1 -1
  168. package/dist/telemetry/store.d.ts +6 -1
  169. package/dist/telemetry/store.d.ts.map +1 -1
  170. package/dist/telemetry/types.d.ts +132 -2
  171. package/dist/telemetry/types.d.ts.map +1 -1
  172. package/dist/{tokenRefresh-kzz08kea.js → tokenRefresh-eg9h83wd.js} +6 -1
  173. package/package.json +11 -4
  174. package/dist/cli-5jxyma6z.js +0 -277
  175. package/dist/cli-vj9cv18n.js +0 -38
  176. package/dist/proxy/settings.d.ts +0 -30
  177. package/dist/proxy/settings.d.ts.map +0 -1
package/dist/cli.js CHANGED
@@ -1,16 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startProxyServer
4
- } from "./cli-ab7zkp1a.js";
5
- import"./cli-5jxyma6z.js";
4
+ } from "./cli-fveyj34s.js";
5
+ import"./cli-82e2m44k.js";
6
+ import"./cli-dh0a1bw4.js";
7
+ import"./cli-8sw5wr9j.js";
8
+ import"./cli-grfp0s1j.js";
6
9
  import"./cli-sry5aqdj.js";
7
- import"./cli-hj61zpt7.js";
10
+ import"./cli-wbsmhxcx.js";
8
11
  import {
9
12
  resolveClaudeExecutableAsync
10
- } from "./cli-9e5cxp89.js";
11
- import"./cli-khhjyk04.js";
12
- import"./cli-vj9cv18n.js";
13
- import"./cli-hxxy0m1z.js";
13
+ } from "./cli-2h3w5n6g.js";
14
+ import"./cli-chsp880k.js";
15
+ import"./cli-1jstkdj9.js";
16
+ import"./cli-qpfky8wy.js";
17
+ import"./cli-eehk3052.js";
14
18
  import {
15
19
  __require
16
20
  } from "./cli-p9swy5t3.js";
@@ -29,17 +33,25 @@ if (args.includes("--version") || args.includes("-v")) {
29
33
  if (args.includes("--help") || args.includes("-h")) {
30
34
  console.log(`meridian v${version}
31
35
 
32
- Local Anthropic API powered by your Claude Max subscription.
36
+ Local API bridge for Claude and Antigravity subscriptions.
33
37
 
34
38
  Usage: meridian [command] [options]
35
39
 
36
40
  Commands:
37
41
  (default) Start the proxy server
38
- setup Configure the OpenCode plugin (run once after install)
42
+ status Show what a running instance is doing (the / page, in the terminal)
43
+ setup Configure client integrations (run once after install)
39
44
  profile Manage Claude account profiles (add, list, switch, remove)
40
45
  refresh-token Refresh the Claude Code OAuth token
41
46
 
42
47
  Setup options:
48
+ --antigravity Configure Pi or OpenCode V1 for Antigravity
49
+ --client <pi|opencode> Client to configure with --antigravity
50
+ --url <base URL> Antigravity URL (include /antigravity in combined mode)
51
+ --model <account slug> Account model to add
52
+ --config-dir <directory> Optional client configuration directory
53
+ --api-key-env <variable> Reference a local Meridian API key from the environment
54
+ --set-default Also select Antigravity for the client
43
55
  --v1 Install the OpenCode V1 plugin
44
56
  --v2 Install the pinned OpenCode V2 beta plugin
45
57
  --opencode-bin <executable> Probe this OpenCode executable
@@ -51,6 +63,19 @@ Options:
51
63
  Environment variables:
52
64
  MERIDIAN_PORT Port to listen on (default: 3456)
53
65
  MERIDIAN_HOST Host to bind to (default: 127.0.0.1)
66
+ MERIDIAN_BACKEND claude (default), antigravity, or combined
67
+ MERIDIAN_AGY_STATE_PATH Optional bounded persistent state file
68
+ MERIDIAN_AGY_TURN_TIMEOUT_MS Active CLI turn deadline (default: 300000)
69
+ MERIDIAN_AGY_TOOL_TIMEOUT_MS Idle client-tool wait (default: 60000)
70
+ MERIDIAN_AGY_MAX_CONCURRENT Maximum CLI processes (default: 4)
71
+ MERIDIAN_AGY_PLUGIN_PATHS JSON array of Antigravity plugin modules
72
+ MERIDIAN_AGY_GRAMMAR_PYTHON Local Python with Lark for custom grammars
73
+ MERIDIAN_AGY_PATH Official agy executable (default: agy)
74
+ MERIDIAN_AGY_ALLOW_TOOL_BRIDGE Opt into Antigravity client-owned tools (1)
75
+ MERIDIAN_AGY_ADAPT_THINKING_BUDGETS Map numeric budgets to Gemini effort (1)
76
+ MERIDIAN_AGY_ALLOW_NATIVE_BROWSER Opt into native browser actions (1)
77
+ MERIDIAN_AGY_BROWSER_MCP_PATH Installed chrome-devtools-mcp 1.9.0 executable
78
+ MERIDIAN_AGY_ALLOW_NATIVE_SUBAGENTS Opt into native subagents (1)
54
79
  MERIDIAN_PASSTHROUGH Enable passthrough mode (tools forwarded to client)
55
80
  MERIDIAN_IDLE_TIMEOUT_SECONDS Idle timeout in seconds (default: 120)
56
81
  MERIDIAN_PLUGIN_DIR Plugin auto-discovery directory (default: ~/.config/meridian/plugins)
@@ -60,7 +85,7 @@ See https://github.com/rynfar/meridian for full documentation.`);
60
85
  process.exit(0);
61
86
  }
62
87
  if (args[0] === "profile") {
63
- const { profileAdd, profileAddOauthToken, profileList, profileRemove, profileSwitch, profileLogin, profileHelp } = await import("./profileCli-1eecbmgk.js");
88
+ const { profileAdd, profileAddOauthToken, profileList, profileRemove, profileRename, profileSwitch, profileLogin, profileHelp } = await import("./profileCli-1bfgc05h.js");
64
89
  const subcommand = args[1];
65
90
  const profileId = args[2];
66
91
  const headless = args.includes("--headless");
@@ -76,6 +101,8 @@ if (args[0] === "profile") {
76
101
  profileList();
77
102
  else if (subcommand === "remove" && profileId)
78
103
  profileRemove(profileId);
104
+ else if (subcommand === "rename" && profileId && args[3])
105
+ profileRename(profileId, args[3]);
79
106
  else if (subcommand === "switch" && profileId)
80
107
  await profileSwitch(profileId);
81
108
  else if (subcommand === "login" && profileId)
@@ -84,6 +111,22 @@ if (args[0] === "profile") {
84
111
  profileHelp();
85
112
  process.exit(0);
86
113
  }
114
+ if (args[0] === "setup" && args.includes("--antigravity")) {
115
+ const { parseAntigravitySetupArgs, setupAntigravityClient } = await import("./antigravitySetup-35pd5xqn.js");
116
+ try {
117
+ const result = setupAntigravityClient(parseAntigravitySetupArgs(args.slice(1)), import.meta.url);
118
+ console.log(`${result.changed.length ? "Configured" : "Already configured"} ${result.client} for Antigravity`);
119
+ console.log(` Config: ${result.configPath}`);
120
+ console.log(` Integration: ${result.integrationPath}`);
121
+ for (const backup of result.backups)
122
+ console.log(` Backup: ${backup}`);
123
+ console.log(`Restart ${result.client}, then select meridian-agy/${result.model}. Tool permissions remain in the client.`);
124
+ process.exit(0);
125
+ } catch (error) {
126
+ console.error(error instanceof Error ? error.message : String(error));
127
+ process.exit(1);
128
+ }
129
+ }
87
130
  if (args[0] === "setup") {
88
131
  const {
89
132
  detectOpenCodeGeneration,
@@ -93,7 +136,7 @@ if (args[0] === "setup") {
93
136
  runSetup,
94
137
  SUPPORTED_OPENCODE_V2_VERSIONS,
95
138
  UnparseableConfigError
96
- } = await import("./setup-ndmjpy23.js");
139
+ } = await import("./setup-7fr49z92.js");
97
140
  const forceV1 = args.includes("--v1");
98
141
  const forceV2 = args.includes("--v2");
99
142
  if (forceV1 && forceV2) {
@@ -172,7 +215,7 @@ Restart OpenCode for the plugin to take effect.`);
172
215
  process.exit(0);
173
216
  }
174
217
  if (args[0] === "refresh-token") {
175
- const { refreshOAuthToken } = await import("./tokenRefresh-kzz08kea.js");
218
+ const { refreshOAuthToken } = await import("./tokenRefresh-eg9h83wd.js");
176
219
  const success = await refreshOAuthToken();
177
220
  if (success) {
178
221
  console.log("Token refreshed successfully");
@@ -189,6 +232,23 @@ var host = process.env.MERIDIAN_HOST ?? process.env.CLAUDE_PROXY_HOST ?? "127.0.
189
232
  var idleTimeoutSeconds = parseInt(process.env.MERIDIAN_IDLE_TIMEOUT_SECONDS ?? process.env.CLAUDE_PROXY_IDLE_TIMEOUT_SECONDS ?? "120", 10);
190
233
  var pluginDir = process.env.MERIDIAN_PLUGIN_DIR;
191
234
  var pluginConfigPath = process.env.MERIDIAN_PLUGIN_CONFIG;
235
+ async function printRunningInstance() {
236
+ const { probeMeridian } = await import("./statusProbe-9x9q261e.js");
237
+ const result = await probeMeridian(host, port, { apiKey: process.env.MERIDIAN_API_KEY });
238
+ if (result.kind === "meridian") {
239
+ const { renderCliDashboard } = await import("./cliDashboard-c0dvkj4y.js");
240
+ process.stdout.write(renderCliDashboard({ host, port, ...result.snapshot }, { color: process.stdout.isTTY === true }));
241
+ }
242
+ return result;
243
+ }
244
+ if (args[0] === "status") {
245
+ const result = await printRunningInstance();
246
+ if (result.kind === "meridian")
247
+ process.exit(0);
248
+ const { formatStatusMessage } = await import("./statusProbe-9x9q261e.js");
249
+ console.error(formatStatusMessage(result, host, port));
250
+ process.exit(1);
251
+ }
192
252
  var profiles;
193
253
  var defaultProfile;
194
254
  try {
@@ -204,35 +264,39 @@ async function runCli(start = startProxyServer, runAuthCheck = async () => {
204
264
  const claudePath = await resolveClaudeExecutableAsync();
205
265
  return execFile(claudePath, ["auth", "status"], { timeout: 5000 });
206
266
  }) {
207
- try {
208
- const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-ndmjpy23.js");
209
- const configPath = findOpencodeConfigPath();
210
- const { existsSync } = await import("fs");
211
- if (existsSync(configPath) && !checkPluginConfigured(configPath)) {
212
- const pluginPath = findPluginPath(import.meta.url);
213
- console.error("\x1B[33m⚠ Meridian plugin not found in OpenCode config.\x1B[0m");
214
- console.error(" Session tracking and subagent model selection won't work.");
215
- console.error(` Fix: meridian setup`);
216
- console.error("");
217
- }
218
- } catch {}
219
- try {
220
- const { stdout } = await runAuthCheck();
221
- const auth = JSON.parse(stdout);
222
- if (!auth.loggedIn) {
223
- console.error("\x1B[31m✗ Not logged in to Claude.\x1B[0m Run: claude login");
224
- process.exit(1);
267
+ if (process.env.MERIDIAN_BACKEND !== "antigravity") {
268
+ try {
269
+ const { findOpencodeConfigPath, checkPluginConfigured, findPluginPath } = await import("./setup-7fr49z92.js");
270
+ const configPath = findOpencodeConfigPath();
271
+ const { existsSync } = await import("fs");
272
+ if (existsSync(configPath) && !checkPluginConfigured(configPath)) {
273
+ const pluginPath = findPluginPath(import.meta.url);
274
+ console.error("\x1B[33m⚠ Meridian plugin not found in OpenCode config.\x1B[0m");
275
+ console.error(" Session tracking and subagent model selection won't work.");
276
+ console.error(` Fix: meridian setup`);
277
+ console.error("");
278
+ }
279
+ } catch {}
280
+ try {
281
+ const { stdout } = await runAuthCheck();
282
+ const auth = JSON.parse(stdout);
283
+ if (!auth.loggedIn) {
284
+ console.error("\x1B[31m✗ Not logged in to Claude.\x1B[0m Run: claude login");
285
+ process.exit(1);
286
+ }
287
+ if (auth.subscriptionType !== "max") {
288
+ console.error(`\x1B[33m⚠ Claude subscription: ${auth.subscriptionType || "unknown"} (Max recommended)\x1B[0m`);
289
+ }
290
+ } catch {
291
+ console.error("\x1B[33m⚠ Could not verify Claude auth status. If requests fail, run: claude login\x1B[0m");
225
292
  }
226
- if (auth.subscriptionType !== "max") {
227
- console.error(`\x1B[33m⚠ Claude subscription: ${auth.subscriptionType || "unknown"} (Max recommended)\x1B[0m`);
293
+ if (!profiles) {
294
+ const { enableDiskProfileDiscovery } = await import("./profiles-0mp32ek9.js");
295
+ enableDiskProfileDiscovery();
228
296
  }
229
- } catch {
230
- console.error("\x1B[33m⚠ Could not verify Claude auth status. If requests fail, run: claude login\x1B[0m");
231
- }
232
- if (!profiles) {
233
- const { enableDiskProfileDiscovery } = await import("./profiles-wch9h234.js");
234
- enableDiskProfileDiscovery();
235
297
  }
298
+ const { enableOrganizationLookup } = await import("./organizationName-90f0atkn.js");
299
+ enableOrganizationLookup();
236
300
  const proxy = await start({ port, host, idleTimeoutSeconds, pluginDir, pluginConfigPath, profiles, defaultProfile, version, installProcessErrorHandlers: true });
237
301
  proxy.server.on("error", (error) => {
238
302
  if (error.code === "EADDRINUSE") {
@@ -258,6 +322,15 @@ async function runCli(start = startProxyServer, runAuthCheck = async () => {
258
322
  process.on("SIGINT", handleShutdownSignal);
259
323
  }
260
324
  if (__require.main == __require.module) {
325
+ const { isPortAvailable } = await import("./statusProbe-9x9q261e.js");
326
+ if (!await isPortAvailable(host, port)) {
327
+ const result = await printRunningInstance();
328
+ if (result.kind === "meridian")
329
+ process.exit(0);
330
+ const { formatConflictMessage } = await import("./statusProbe-9x9q261e.js");
331
+ console.error(formatConflictMessage(result, host, port));
332
+ process.exit(1);
333
+ }
261
334
  await runCli();
262
335
  }
263
336
  export {
@@ -0,0 +1,325 @@
1
+ import {
2
+ WINDOW_LABELS,
3
+ classifyUtilization,
4
+ computeWeeklyPace,
5
+ formatResetCountdown
6
+ } from "./cli-3zwfvexc.js";
7
+ import"./cli-p9swy5t3.js";
8
+
9
+ // src/telemetry/cliDashboard.ts
10
+ var PALETTE = {
11
+ green: 71,
12
+ yellow: 178,
13
+ red: 203,
14
+ muted: 246,
15
+ accent: 75
16
+ };
17
+ var colorPaint = (text, color) => `\x1B[38;5;${PALETTE[color]}m${text}\x1B[0m`;
18
+ var plainPaint = (text) => text;
19
+ var UNKNOWN = "—";
20
+ function isNum(v) {
21
+ return typeof v === "number" && Number.isFinite(v);
22
+ }
23
+ function usd(v) {
24
+ if (!isNum(v))
25
+ return UNKNOWN;
26
+ if (v > 0 && v < 0.01)
27
+ return `$${v.toFixed(4)}`;
28
+ if (v < 100)
29
+ return `$${v.toFixed(2)}`;
30
+ return `$${Math.round(v).toLocaleString("en-US")}`;
31
+ }
32
+ function tokens(v) {
33
+ if (!isNum(v))
34
+ return UNKNOWN;
35
+ if (v >= 1e6)
36
+ return `${(v / 1e6).toFixed(1)}M`;
37
+ if (v >= 1000)
38
+ return `${(v / 1000).toFixed(1)}k`;
39
+ return String(v);
40
+ }
41
+ function millis(v) {
42
+ if (!isNum(v) || v === 0)
43
+ return UNKNOWN;
44
+ return v < 1000 ? `${v}ms` : `${(v / 1000).toFixed(1)}s`;
45
+ }
46
+ function windowLabel(type) {
47
+ const known = WINDOW_LABELS[type];
48
+ if (known)
49
+ return known;
50
+ return type.replace(/^seven_day_/, "7d ").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
51
+ }
52
+ function utilizationColor(utilization) {
53
+ const status = classifyUtilization(utilization);
54
+ return status === "high" ? "red" : status === "warn" ? "yellow" : "green";
55
+ }
56
+ function paceStatus(pace) {
57
+ return pace.projectedPct != null && pace.projectedPct >= 100 ? "over" : pace.status;
58
+ }
59
+ function paceColor(status) {
60
+ return status === "over" ? "red" : status === "ahead" ? "yellow" : "green";
61
+ }
62
+ var BAR_WIDTH = 28;
63
+ var BAR_FILL = "█";
64
+ var BAR_TRACK = "░";
65
+ var BAR_MARKER = "┃";
66
+ function clampPct(pct) {
67
+ return Math.max(0, Math.min(100, pct));
68
+ }
69
+ function renderBar(pct, color, paint, markerPct) {
70
+ const filled = Math.round(clampPct(pct) / 100 * BAR_WIDTH);
71
+ const marker = markerPct == null ? -1 : Math.min(Math.round(clampPct(markerPct) / 100 * BAR_WIDTH), BAR_WIDTH - 1);
72
+ const cells = [];
73
+ for (let i2 = 0;i2 < BAR_WIDTH; i2++) {
74
+ if (i2 === marker)
75
+ cells.push({ ch: BAR_MARKER, role: "marker" });
76
+ else if (i2 < filled)
77
+ cells.push({ ch: BAR_FILL, role: "fill" });
78
+ else
79
+ cells.push({ ch: BAR_TRACK, role: "track" });
80
+ }
81
+ let out = "";
82
+ let i = 0;
83
+ while (i < cells.length) {
84
+ const role = cells[i].role;
85
+ let run = "";
86
+ while (i < cells.length && cells[i].role === role) {
87
+ run += cells[i].ch;
88
+ i++;
89
+ }
90
+ out += role === "fill" ? paint(run, color) : role === "track" ? paint(run, "muted") : run;
91
+ }
92
+ return out;
93
+ }
94
+ function buildAccounts(input, now) {
95
+ const byProfile = input.summary?.costEstimate?.byProfile ?? {};
96
+ const quotaByProfile = {};
97
+ for (const entry of input.quota?.profiles ?? []) {
98
+ quotaByProfile[entry.id || entry.profile || "default"] = entry.windows ?? [];
99
+ }
100
+ const configured = input.profileList?.profiles ?? [];
101
+ const candidates = [];
102
+ if (configured.length > 0) {
103
+ for (const p of configured) {
104
+ const id = p.id ?? "default";
105
+ candidates.push({ id, label: id, isActive: p.isActive === true, configured: true });
106
+ }
107
+ } else {
108
+ const auth = input.health?.auth;
109
+ const email = auth?.loggedIn && auth.email || "";
110
+ const seen = new Set;
111
+ for (const key of [...Object.keys(quotaByProfile), ...Object.keys(byProfile)]) {
112
+ if (seen.has(key))
113
+ continue;
114
+ seen.add(key);
115
+ candidates.push({
116
+ id: key,
117
+ label: key === "default" ? email || "account" : key,
118
+ isActive: false,
119
+ configured: false
120
+ });
121
+ }
122
+ }
123
+ const isPriority = input.profileList?.routing === "priority";
124
+ const blocks = [];
125
+ for (const candidate of candidates) {
126
+ const cost = byProfile[candidate.id];
127
+ const windows = (quotaByProfile[candidate.id] ?? []).filter((w) => w.utilization != null);
128
+ if (!candidate.configured && windows.length === 0 && !cost)
129
+ continue;
130
+ const rows = [];
131
+ for (const w of windows) {
132
+ const utilization = w.utilization;
133
+ if (!isNum(utilization))
134
+ continue;
135
+ rows.push({
136
+ label: windowLabel(w.type ?? ""),
137
+ pct: Math.round(utilization * 100),
138
+ figure: `${Math.round(utilization * 100)}%`,
139
+ color: utilizationColor(utilization),
140
+ note: formatResetCountdown(w.resetsAt, now)
141
+ });
142
+ }
143
+ let weekly;
144
+ for (const w of windows)
145
+ if (w.type === "seven_day")
146
+ weekly = w;
147
+ const pace = weekly ? computeWeeklyPace(weekly.utilization, weekly.resetsAt, now) : null;
148
+ if (pace) {
149
+ const status = paceStatus(pace);
150
+ const projected = pace.projectedPct;
151
+ const figure = status === "over" ? projected != null ? `${projected}%` : "100%" : `${pace.deltaPct >= 0 ? "+" : "-"}${Math.abs(pace.deltaPct)}%`;
152
+ rows.push({
153
+ label: "pace",
154
+ pct: pace.actualPct,
155
+ markerPct: pace.expectedPct,
156
+ figure,
157
+ color: paceColor(status),
158
+ note: status === "over" ? "runs out before reset" : projected != null ? `~${projected}% by reset` : ""
159
+ });
160
+ }
161
+ const badges = [];
162
+ if (isPriority) {
163
+ const order = input.profileList?.profileOrder ?? [];
164
+ const idx = order.indexOf(candidate.id);
165
+ if (idx >= 0)
166
+ badges.push({ text: `#${idx + 1} in pool`, color: "muted" });
167
+ const exhausted = (input.profileList?.exhausted ?? []).find((e) => e.id === candidate.id);
168
+ if (exhausted) {
169
+ badges.push({
170
+ text: `exhausted · resets ${formatResetCountdown(exhausted.until, now)}`,
171
+ color: "red"
172
+ });
173
+ }
174
+ } else if (candidate.isActive) {
175
+ badges.push({ text: "ACTIVE", color: "accent" });
176
+ }
177
+ const requests = cost?.requests;
178
+ blocks.push({
179
+ label: candidate.label,
180
+ isActive: candidate.isActive,
181
+ badges,
182
+ cost: usd(cost ? cost.estimatedUsd : 0),
183
+ sub: isNum(requests) ? `${requests} request${requests === 1 ? "" : "s"} · est. API value · 24h` : "no traffic · 24h",
184
+ rows
185
+ });
186
+ }
187
+ return blocks;
188
+ }
189
+ function buildStrip(summary) {
190
+ const tu = summary.tokenUsage ?? {};
191
+ const hitRate = tu.avgCacheHitRate;
192
+ const errors = summary.errorCount;
193
+ const items = [
194
+ {
195
+ label: "Requests",
196
+ value: isNum(summary.totalRequests) ? String(summary.totalRequests) : UNKNOWN,
197
+ detail: !isNum(errors) ? UNKNOWN : errors > 0 ? `${errors} error${errors === 1 ? "" : "s"}` : "no errors",
198
+ detailColor: isNum(errors) && errors > 0 ? "red" : undefined
199
+ },
200
+ {
201
+ label: "Tokens Out",
202
+ value: tokens(tu.totalOutputTokens),
203
+ detail: `${tokens(tu.totalInputTokens)} in`
204
+ },
205
+ {
206
+ label: "Cache Hit",
207
+ value: isNum(hitRate) ? `${Math.round(hitRate * 100)}%` : UNKNOWN,
208
+ valueColor: isNum(hitRate) && hitRate >= 0.5 ? "green" : undefined,
209
+ detail: "prompt cache"
210
+ },
211
+ {
212
+ label: "Est. API Value",
213
+ value: usd(summary.costEstimate?.totalUsd),
214
+ detail: "list prices"
215
+ },
216
+ {
217
+ label: "Median Response",
218
+ value: millis(summary.totalDuration?.p50),
219
+ detail: `p95 ${millis(summary.totalDuration?.p95)}`
220
+ }
221
+ ];
222
+ const violations = summary.envelopeViolationCount;
223
+ if (isNum(violations) && violations > 0) {
224
+ items.push({
225
+ label: "Envelope",
226
+ value: String(violations),
227
+ valueColor: "red",
228
+ detail: "wire-contract violations",
229
+ detailColor: "red"
230
+ });
231
+ }
232
+ return items;
233
+ }
234
+ function healthPill(health) {
235
+ const status = health?.status;
236
+ if (status === "healthy")
237
+ return { label: "Operational", color: "green" };
238
+ if (status === "degraded")
239
+ return { label: "Degraded", color: "yellow" };
240
+ return { label: "Offline", color: "red" };
241
+ }
242
+ function activeProfileChip(profileList) {
243
+ const active = (profileList?.profiles ?? []).find((p) => p.isActive === true);
244
+ if (!active?.id)
245
+ return null;
246
+ return active.type ? `${active.id} ${active.type}` : active.id;
247
+ }
248
+ var INDENT = " ";
249
+ function renderCliDashboard(input, options = {}) {
250
+ const paint = options.color ? colorPaint : plainPaint;
251
+ const bold = options.color ? (t) => `\x1B[1m${t}\x1B[22m` : (t) => t;
252
+ const now = input.now ?? Date.now();
253
+ const out = [];
254
+ const pill = healthPill(input.health);
255
+ const chip = activeProfileChip(input.profileList);
256
+ out.push(`${bold("MERIDIAN")} ${paint("●", pill.color)} ${pill.label}` + (chip ? ` ${paint("·", "muted")} ${chip}` : ""));
257
+ out.push("");
258
+ out.push(`${INDENT}ANTHROPIC_BASE_URL=http://${input.host}:${input.port}`);
259
+ const meta = [];
260
+ const auth = input.health?.auth;
261
+ if (auth?.loggedIn) {
262
+ meta.push(`${auth.email ?? ""}${auth.subscriptionType ? ` (${auth.subscriptionType})` : ""}`);
263
+ }
264
+ meta.push(input.health?.mode ?? "internal");
265
+ meta.push(`port ${input.port}`);
266
+ out.push(`${INDENT}${paint(meta.join(" · "), "muted")}`);
267
+ out.push("");
268
+ const accounts = buildAccounts(input, now);
269
+ const accountsNote = input.unavailable?.accounts;
270
+ if (accounts.length > 0 || accountsNote) {
271
+ out.push(paint(accounts.length === 1 ? "ACCOUNT" : "ACCOUNTS", "muted"));
272
+ out.push("");
273
+ if (accountsNote) {
274
+ out.push(`${INDENT}${paint(accountsNote, "yellow")}`);
275
+ out.push("");
276
+ }
277
+ const allRows = accounts.flatMap((a) => a.rows);
278
+ const labelWidth = Math.max(0, ...allRows.map((r) => r.label.length));
279
+ const figureWidth = Math.max(0, ...allRows.map((r) => r.figure.length));
280
+ const costColumn = INDENT.length + 2 + labelWidth + 2 + BAR_WIDTH + 2 + figureWidth;
281
+ for (const account of accounts) {
282
+ const dot = paint("●", account.isActive ? "accent" : "muted");
283
+ const badges = account.badges.map((b) => b.color ? paint(b.text, b.color) : b.text).join(" ");
284
+ const headLeft = `${account.label}${badges ? ` ${badges}` : ""}`;
285
+ const headLeftPlain = account.label + (account.badges.length > 0 ? ` ${account.badges.map((b) => b.text).join(" ")}` : "");
286
+ const gap = Math.max(1, costColumn - INDENT.length - 2 - headLeftPlain.length - account.cost.length);
287
+ out.push(`${INDENT}${dot} ${headLeft}${" ".repeat(gap)}${bold(account.cost)}`);
288
+ out.push(`${INDENT} ${paint(account.sub, "muted")}`);
289
+ if (account.rows.length === 0) {
290
+ out.push(`${INDENT} ${paint("no usage data yet", "muted")}`);
291
+ }
292
+ for (const row of account.rows) {
293
+ const label = row.label.padEnd(labelWidth);
294
+ const bar = renderBar(row.pct, row.color, paint, row.markerPct);
295
+ const figure = row.figure.padStart(figureWidth);
296
+ const note = row.note ? ` ${paint(row.note, "muted")}` : "";
297
+ out.push(`${INDENT} ${paint(label, "muted")} ${bar} ${paint(figure, row.color)}${note}`);
298
+ }
299
+ out.push("");
300
+ }
301
+ }
302
+ const trafficNote = input.unavailable?.traffic;
303
+ out.push(paint("LAST 24 HOURS", "muted"));
304
+ out.push("");
305
+ if (trafficNote) {
306
+ out.push(`${INDENT}${paint(trafficNote, "yellow")}`);
307
+ } else {
308
+ const items = buildStrip(input.summary ?? {});
309
+ const labelWidth = Math.max(...items.map((i) => i.label.length));
310
+ const valueWidth = Math.max(...items.map((i) => i.value.length));
311
+ for (const item of items) {
312
+ const label = paint(item.label.padEnd(labelWidth), "muted");
313
+ const valuePlain = item.value.padStart(valueWidth);
314
+ const value = item.valueColor ? paint(valuePlain, item.valueColor) : valuePlain;
315
+ const detail = item.detailColor ? paint(item.detail, item.detailColor) : paint(item.detail, "muted");
316
+ out.push(`${INDENT}${label} ${value} ${detail}`);
317
+ }
318
+ }
319
+ return `${out.join(`
320
+ `)}
321
+ `;
322
+ }
323
+ export {
324
+ renderCliDashboard
325
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Where Meridian keeps its own configuration.
3
+ *
4
+ * One directory holds everything Meridian persists for itself — settings.json,
5
+ * profiles.json, the per-profile CLAUDE_CONFIG_DIRs under profiles/,
6
+ * adapter-instances.json, sdk-features.json, model-pricing.json, telemetry.db.
7
+ * `MERIDIAN_CONFIG_DIR` moves that directory, so a second instance pointed at
8
+ * an empty one gets its own everything rather than inheriting the first
9
+ * instance's accounts.
10
+ *
11
+ * Resolved per call, never frozen at import time. A module-level constant is
12
+ * computed before the CLI has parsed argv or a test has set the variable, and
13
+ * can then be changed by neither.
14
+ *
15
+ * NOTE: deliberately does NOT honour XDG_CONFIG_HOME — anyone who has that set
16
+ * would silently relocate to a different config directory and appear to lose
17
+ * everything in it.
18
+ *
19
+ * NOTE: read straight from process.env rather than through env.ts, which would
20
+ * also accept a CLAUDE_PROXY_CONFIG_DIR alias. This variable postdates that
21
+ * prefix, so there is no legacy deployment to stay compatible with and no
22
+ * reason to start accepting a second name for it.
23
+ */
24
+ /** The directory used when MERIDIAN_CONFIG_DIR is unset. */
25
+ export declare function defaultConfigDir(): string;
26
+ /** The directory Meridian's configuration lives in. */
27
+ export declare function configDir(): string;
28
+ /** A path inside the config directory, e.g. `configPath("profiles.json")`. */
29
+ export declare function configPath(...segments: string[]): string;
30
+ //# sourceMappingURL=configDir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configDir.d.ts","sourceRoot":"","sources":["../src/configDir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,4DAA4D;AAC5D,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,uDAAuD;AACvD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAExD"}
@@ -0,0 +1,29 @@
1
+ import {
2
+ ORGANIZATION_REFRESH_AFTER_MS,
3
+ ORGANIZATION_RETRY_AFTER_MS,
4
+ enableOrganizationLookup,
5
+ extractOrganizationName,
6
+ fetchOrganizationName,
7
+ organizationNames,
8
+ organizationNeedsRefresh,
9
+ readOrganizations,
10
+ refreshOrganizationNameSoon,
11
+ rememberOrganizationName,
12
+ resetOrganizationLookupForTesting
13
+ } from "./cli-8sw5wr9j.js";
14
+ import"./cli-chsp880k.js";
15
+ import"./cli-1jstkdj9.js";
16
+ import"./cli-p9swy5t3.js";
17
+ export {
18
+ resetOrganizationLookupForTesting,
19
+ rememberOrganizationName,
20
+ refreshOrganizationNameSoon,
21
+ readOrganizations,
22
+ organizationNeedsRefresh,
23
+ organizationNames,
24
+ fetchOrganizationName,
25
+ extractOrganizationName,
26
+ enableOrganizationLookup,
27
+ ORGANIZATION_RETRY_AFTER_MS,
28
+ ORGANIZATION_REFRESH_AFTER_MS
29
+ };
@@ -4,7 +4,7 @@ import {
4
4
  profileBarHtml,
5
5
  profileBarJs,
6
6
  themeCss
7
- } from "./cli-hj61zpt7.js";
7
+ } from "./cli-wbsmhxcx.js";
8
8
  import"./cli-p9swy5t3.js";
9
9
 
10
10
  // src/proxy/plugins/pluginPage.ts
@@ -3,31 +3,41 @@ import {
3
3
  OAUTH_REDIRECT_URI,
4
4
  OAUTH_TOKEN_URL,
5
5
  buildAuthLoginEnv,
6
+ buildLoginCredentials,
6
7
  createManualOAuthSession,
7
8
  dirsToRemoveOnProfileRemove,
9
+ isValidProfileId,
8
10
  parseAuthorizationCodeInput,
11
+ planProfileLogin,
9
12
  profileAdd,
10
13
  profileAddOauthToken,
11
14
  profileHelp,
12
15
  profileList,
13
16
  profileLogin,
14
17
  profileRemove,
18
+ profileRename,
15
19
  profileSwitch
16
- } from "./cli-9e5cxp89.js";
17
- import"./cli-khhjyk04.js";
18
- import"./cli-vj9cv18n.js";
20
+ } from "./cli-2h3w5n6g.js";
21
+ import"./cli-chsp880k.js";
22
+ import"./cli-1jstkdj9.js";
23
+ import"./cli-qpfky8wy.js";
24
+ import"./cli-eehk3052.js";
19
25
  import"./cli-p9swy5t3.js";
20
26
  export {
21
27
  profileSwitch,
28
+ profileRename,
22
29
  profileRemove,
23
30
  profileLogin,
24
31
  profileList,
25
32
  profileHelp,
26
33
  profileAddOauthToken,
27
34
  profileAdd,
35
+ planProfileLogin,
28
36
  parseAuthorizationCodeInput,
37
+ isValidProfileId,
29
38
  dirsToRemoveOnProfileRemove,
30
39
  createManualOAuthSession,
40
+ buildLoginCredentials,
31
41
  buildAuthLoginEnv,
32
42
  OAUTH_TOKEN_URL,
33
43
  OAUTH_REDIRECT_URI,