@rynfar/meridian 1.72.0 → 1.73.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 (114) hide show
  1. package/dist/cli-1jstkdj9.js +30 -0
  2. package/dist/{cli-9e5cxp89.js → cli-2h3w5n6g.js} +163 -65
  3. package/dist/cli-3zwfvexc.js +56 -0
  4. package/dist/{cli-hxxy0m1z.js → cli-82e2m44k.js} +2 -1
  5. package/dist/cli-8sw5wr9j.js +136 -0
  6. package/dist/{cli-khhjyk04.js → cli-chsp880k.js} +214 -21
  7. package/dist/cli-dh0a1bw4.js +619 -0
  8. package/dist/cli-eehk3052.js +57 -0
  9. package/dist/cli-grfp0s1j.js +330 -0
  10. package/dist/{cli-ab7zkp1a.js → cli-p5zbk952.js} +2027 -315
  11. package/dist/{cli-hj61zpt7.js → cli-p9ca4p13.js} +17 -2
  12. package/dist/cli-qpfky8wy.js +133 -0
  13. package/dist/cli.js +47 -12
  14. package/dist/cliDashboard-c0dvkj4y.js +325 -0
  15. package/dist/configDir.d.ts +30 -0
  16. package/dist/configDir.d.ts.map +1 -0
  17. package/dist/organizationName-90f0atkn.js +29 -0
  18. package/dist/{pluginPage-f5gdmbxc.js → pluginPage-3kxsrdpj.js} +1 -1
  19. package/dist/{profileCli-1eecbmgk.js → profileCli-1bfgc05h.js} +13 -3
  20. package/dist/{profilePage-mamej7kp.js → profilePage-etxqg3vn.js} +252 -60
  21. package/dist/profileRename-4a4km6g8.js +22 -0
  22. package/dist/{profiles-wch9h234.js → profiles-0mp32ek9.js} +16 -3
  23. package/dist/proxy/adapterInstances.d.ts +1 -1
  24. package/dist/proxy/adapterInstances.d.ts.map +1 -1
  25. package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
  26. package/dist/proxy/adapters/droid.d.ts.map +1 -1
  27. package/dist/proxy/authDiscovery.d.ts +52 -0
  28. package/dist/proxy/authDiscovery.d.ts.map +1 -0
  29. package/dist/proxy/credentialsMode.d.ts +77 -0
  30. package/dist/proxy/credentialsMode.d.ts.map +1 -0
  31. package/dist/proxy/design.d.ts.map +1 -1
  32. package/dist/proxy/followActive.d.ts +262 -0
  33. package/dist/proxy/followActive.d.ts.map +1 -0
  34. package/dist/proxy/limitDetection.d.ts +110 -0
  35. package/dist/proxy/limitDetection.d.ts.map +1 -0
  36. package/dist/proxy/models.d.ts.map +1 -1
  37. package/dist/proxy/oauthPlan.d.ts +63 -0
  38. package/dist/proxy/oauthPlan.d.ts.map +1 -0
  39. package/dist/proxy/oauthUsage.d.ts +65 -2
  40. package/dist/proxy/oauthUsage.d.ts.map +1 -1
  41. package/dist/proxy/openai.d.ts +4 -2
  42. package/dist/proxy/openai.d.ts.map +1 -1
  43. package/dist/proxy/organizationName.d.ts +71 -0
  44. package/dist/proxy/organizationName.d.ts.map +1 -0
  45. package/dist/proxy/passthroughEarlyStop.d.ts +10 -0
  46. package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
  47. package/dist/proxy/planAllowance.d.ts +75 -0
  48. package/dist/proxy/planAllowance.d.ts.map +1 -0
  49. package/dist/proxy/probes.d.ts +85 -0
  50. package/dist/proxy/probes.d.ts.map +1 -0
  51. package/dist/proxy/profileCli.d.ts +53 -1
  52. package/dist/proxy/profileCli.d.ts.map +1 -1
  53. package/dist/proxy/profileHealth.d.ts +127 -0
  54. package/dist/proxy/profileHealth.d.ts.map +1 -0
  55. package/dist/proxy/profileRename.d.ts +83 -0
  56. package/dist/proxy/profileRename.d.ts.map +1 -0
  57. package/dist/proxy/profiles.d.ts +72 -6
  58. package/dist/proxy/profiles.d.ts.map +1 -1
  59. package/dist/proxy/query.d.ts +7 -0
  60. package/dist/proxy/query.d.ts.map +1 -1
  61. package/dist/proxy/routing.d.ts +59 -1
  62. package/dist/proxy/routing.d.ts.map +1 -1
  63. package/dist/proxy/sdkFeatures.d.ts +1 -1
  64. package/dist/proxy/sdkFeatures.d.ts.map +1 -1
  65. package/dist/proxy/server.d.ts.map +1 -1
  66. package/dist/proxy/session/fingerprint.d.ts +5 -0
  67. package/dist/proxy/session/fingerprint.d.ts.map +1 -1
  68. package/dist/proxy/session/lineage.d.ts.map +1 -1
  69. package/dist/proxy/setup.d.ts.map +1 -1
  70. package/dist/proxy/supervision.d.ts +41 -0
  71. package/dist/proxy/supervision.d.ts.map +1 -0
  72. package/dist/proxy/tokenRefresh.d.ts +38 -4
  73. package/dist/proxy/tokenRefresh.d.ts.map +1 -1
  74. package/dist/server.js +11 -7
  75. package/dist/settings.d.ts +83 -0
  76. package/dist/settings.d.ts.map +1 -0
  77. package/dist/{setup-ndmjpy23.js → setup-7fr49z92.js} +1 -1
  78. package/dist/statusProbe-9x9q261e.js +151 -0
  79. package/dist/telemetry/dashboard.d.ts.map +1 -1
  80. package/dist/telemetry/index.d.ts +20 -2
  81. package/dist/telemetry/index.d.ts.map +1 -1
  82. package/dist/telemetry/landing.d.ts +1 -1
  83. package/dist/telemetry/landing.d.ts.map +1 -1
  84. package/dist/telemetry/logStore.d.ts +11 -0
  85. package/dist/telemetry/logStore.d.ts.map +1 -1
  86. package/dist/telemetry/pricingStore.d.ts +2 -2
  87. package/dist/telemetry/pricingStore.d.ts.map +1 -1
  88. package/dist/telemetry/profileBar.d.ts +2 -2
  89. package/dist/telemetry/profileBar.d.ts.map +1 -1
  90. package/dist/telemetry/profileFacts.d.ts +17 -0
  91. package/dist/telemetry/profileFacts.d.ts.map +1 -0
  92. package/dist/telemetry/profileOrder.d.ts +68 -0
  93. package/dist/telemetry/profileOrder.d.ts.map +1 -0
  94. package/dist/telemetry/profilePage.d.ts.map +1 -1
  95. package/dist/telemetry/profileSort.d.ts +35 -0
  96. package/dist/telemetry/profileSort.d.ts.map +1 -0
  97. package/dist/telemetry/profileSpent.d.ts +68 -0
  98. package/dist/telemetry/profileSpent.d.ts.map +1 -0
  99. package/dist/telemetry/routeChain.d.ts +32 -0
  100. package/dist/telemetry/routeChain.d.ts.map +1 -0
  101. package/dist/telemetry/routes.d.ts.map +1 -1
  102. package/dist/telemetry/settingsPage.d.ts +1 -1
  103. package/dist/telemetry/settingsPage.d.ts.map +1 -1
  104. package/dist/telemetry/sqlite.d.ts.map +1 -1
  105. package/dist/telemetry/store.d.ts +6 -1
  106. package/dist/telemetry/store.d.ts.map +1 -1
  107. package/dist/telemetry/types.d.ts +132 -2
  108. package/dist/telemetry/types.d.ts.map +1 -1
  109. package/dist/{tokenRefresh-kzz08kea.js → tokenRefresh-eg9h83wd.js} +6 -1
  110. package/package.json +1 -1
  111. package/dist/cli-5jxyma6z.js +0 -277
  112. package/dist/cli-vj9cv18n.js +0 -38
  113. package/dist/proxy/settings.d.ts +0 -30
  114. package/dist/proxy/settings.d.ts.map +0 -1
@@ -0,0 +1,52 @@
1
+ /**
2
+ * What Anthropic told us during authentication, rendered safe to log.
3
+ *
4
+ * Three payloads decide what Meridian knows about an account — the token
5
+ * endpoint's response, `GET /api/oauth/profile`, and `claude auth status` —
6
+ * and none of them is currently observable. When a field is absent, or renamed,
7
+ * or Anthropic starts returning a plan tier nobody has seen before, the only
8
+ * symptom downstream is a profile that reads `unknown`, with nothing in any log
9
+ * to say whether the field was missing from the response or dropped on the way
10
+ * to disk. That distinction is the whole of the diagnosis.
11
+ *
12
+ * The obstacle is that two of those payloads carry credentials, so they cannot
13
+ * simply be logged. `logger.ts`'s `sanitize()` redacts by key name, which is
14
+ * the wrong polarity here: it protects the names somebody already thought of,
15
+ * and a field discovered tomorrow is by definition not one of them.
16
+ *
17
+ * So this inverts it. Every string is redacted to its length unless its key is
18
+ * on an allow-list of values known to carry no secret. A new field is therefore
19
+ * reported by NAME and TYPE — enough to see it arrived and to decide what it is
20
+ * — while its contents stay out of the log until somebody deliberately adds it
21
+ * to the list.
22
+ *
23
+ * This is a leaf module — pure, no imports.
24
+ */
25
+ /**
26
+ * String-valued keys whose contents are safe to print.
27
+ *
28
+ * Every one is either a duration, a timestamp, an enum Anthropic publishes, or
29
+ * the scope list that already appears in plaintext in the authorize URL. A key
30
+ * that identifies a person or an organization is deliberately absent: `email`,
31
+ * `email_address`, `name`, `display_name` and `uuid` are all reported by length
32
+ * only, because a debug log is routinely pasted into an issue.
33
+ */
34
+ export declare const SAFE_AUTH_STRING_KEYS: ReadonlySet<string>;
35
+ /**
36
+ * Render a parsed auth response as a loggable field map.
37
+ *
38
+ * The shape mirrors the payload rather than flattening it, so a nested
39
+ * `organization.rate_limit_tier` reads the same way in the log as it does in
40
+ * Anthropic's documentation and in the code that consumes it.
41
+ */
42
+ export declare function describeAuthFields(payload: unknown): unknown;
43
+ /**
44
+ * The keys a payload actually carried, nested ones included, as dotted paths.
45
+ *
46
+ * Logged alongside the described payload because it is the line worth grepping:
47
+ * comparing two logins reduces to comparing two key lists, which answers "did
48
+ * this account's response even contain the field" without reading the values at
49
+ * all.
50
+ */
51
+ export declare function authFieldPaths(payload: unknown, prefix?: string): string[];
52
+ //# sourceMappingURL=authDiscovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authDiscovery.d.ts","sourceRoot":"","sources":["../../src/proxy/authDiscovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAepD,CAAA;AA0BF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE5D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE,CAStE"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Read-only credential mode — `MERIDIAN_CREDENTIALS_READONLY`.
3
+ *
4
+ * Lets a second Meridian instance run beside a production one against the
5
+ * SAME credential files without being able to corrupt them. When set, the
6
+ * instance never initiates a token refresh and never writes a credential; it
7
+ * re-reads credentials from disk so refreshes performed by the OTHER instance
8
+ * are picked up.
9
+ *
10
+ * The hazard this exists for: two instances holding the same OAuth refresh
11
+ * token. Meridian refreshes proactively on boot and on a 45s cadence. If
12
+ * Anthropic rotates the refresh token on use, whichever instance refreshes
13
+ * first invalidates the other's copy, and recovery is an interactive
14
+ * `claude login` per account.
15
+ *
16
+ * Sharing is not a choice the operator makes, which is why this is the only
17
+ * defence rather than one layer of several. `MERIDIAN_CONFIG_DIR` relocates
18
+ * `settings.json` and nothing else: `profiles.json` is a module-level constant
19
+ * in `profiles.ts`, so every instance on a machine reads the same profile
20
+ * list, pointing at the same `claudeConfigDir` credential directories. There
21
+ * is no supported way to give a second instance a different profile set, so
22
+ * any second instance holds the first one's real accounts from the moment it
23
+ * boots. This flag is what stops it writing to them.
24
+ *
25
+ * Env var rather than a settings key on purpose: settings are editable from
26
+ * the web UI, and switching this on for the production instance by accident
27
+ * would silently stop it refreshing its own tokens. The systemd unit is
28
+ * already where the two instances differ.
29
+ *
30
+ * Leaf module — no imports from server.ts or session/.
31
+ */
32
+ /**
33
+ * Whether this instance is forbidden from refreshing or writing credentials.
34
+ *
35
+ * Resolved per call rather than frozen at import time, matching
36
+ * `settings.ts`'s treatment of MERIDIAN_CONFIG_DIR: module-level credential
37
+ * stores are constructed at import, so a value captured then would be fixed
38
+ * before any test (or embedding host) could set it.
39
+ */
40
+ export declare function isCredentialsReadOnly(): boolean;
41
+ /**
42
+ * Report a refused credential write, loudly, and return false so the caller
43
+ * takes its existing write-failed path.
44
+ *
45
+ * Deliberately `console.error` and not `claudeLog`: the latter is gated behind
46
+ * OPENCODE_CLAUDE_PROVIDER_DEBUG, so in a normal deployment it prints nothing.
47
+ *
48
+ * Why failing LOUDLY beats failing safe here: this refusal is the backstop for
49
+ * a write path nobody thought of. Silently swallowing it would leave an
50
+ * operator believing the guarantee held while some future call site quietly
51
+ * did nothing — and the failure it is protecting against (a corrupted token
52
+ * file that a production instance depends on, costing an interactive
53
+ * `claude login` across every account, including borrowed ones) is expensive
54
+ * and manual to recover from. A noisy log that turns out to be benign costs a
55
+ * grep; a silent one costs the fleet. If this line ever appears, the correct
56
+ * response is to find the call site and gate it upstream of the store.
57
+ *
58
+ * @param operation short label for the call site (e.g. "oauth-refresh")
59
+ * @param target store identity — a path or keychain service, NEVER a value
60
+ */
61
+ export declare function refuseCredentialWrite(operation: string, target: string): false;
62
+ /**
63
+ * Announce the mode once at startup, unmistakably.
64
+ *
65
+ * An instance silently in read-only mode when you thought it was normal is a
66
+ * confusing bug — tokens quietly stop being refreshed. An instance loudly in
67
+ * it is self-documenting.
68
+ *
69
+ * Not gated on `silent`, unlike the rest of the startup output: MERIDIAN_SILENT
70
+ * suppresses routine chatter, and this is not routine — it is a non-default
71
+ * operating mode that changes what the process is allowed to do. One line,
72
+ * once, and only when the flag is actually set.
73
+ */
74
+ export declare function logCredentialsModeBanner(): void;
75
+ /** Reset the once-per-process banner — for testing only. */
76
+ export declare function resetCredentialsModeBanner(): void;
77
+ //# sourceMappingURL=credentialsMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentialsMode.d.ts","sourceRoot":"","sources":["../../src/proxy/credentialsMode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,CAO9E;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAQ/C;AAED,4DAA4D;AAC5D,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/proxy/design.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/proxy/design.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Follow-the-active-profile mode — `MERIDIAN_FOLLOW_ACTIVE`.
3
+ *
4
+ * Makes a development instance take its active profile from ANOTHER Meridian
5
+ * instance instead of from its own `settings.json`, so the two serve from the
6
+ * same account and a side-by-side comparison is like-for-like.
7
+ *
8
+ * The problem it solves: `MERIDIAN_CONFIG_DIR` relocates `settings.json` and
9
+ * nothing else, so a second instance keeps its own `activeProfile`. Whatever
10
+ * moves the primary's active profile — a UI click, the CLI, an external fleet
11
+ * scheduler — has no effect on the second instance, which quietly serves from
12
+ * a different account. Measured on one box: the primary was on one profile
13
+ * while the dev instance served the same instant from another.
14
+ *
15
+ * What this changes: exactly ONE input to `resolveProfile` — the active
16
+ * profile. The precedence chain around it is untouched, so an explicit
17
+ * `x-meridian-profile` header still wins, and sticky/priority routing behave
18
+ * as they always did (priority mode does not consult the active profile at
19
+ * all for unpinned requests, so follow mode is a no-op there).
20
+ *
21
+ * Degradation is the design constraint, not an afterthought. The followed
22
+ * instance is polled in the background and the last good value is cached; the
23
+ * request path never waits on the network. If the followed instance is down,
24
+ * slow, or answers rubbish, the last known value keeps being served — and if
25
+ * there has never been a good value, the local active profile is used. A dev
26
+ * convenience must not be able to take an instance offline.
27
+ *
28
+ * Leaf module — no imports from server.ts, session/ or profiles.ts.
29
+ */
30
+ /**
31
+ * Poll cadence. The followed value changes on the order of minutes (a human
32
+ * clicking, or a scheduler rotating accounts), so a fetch per request would be
33
+ * absurd; 10s bounds the divergence window without making the followed
34
+ * instance do meaningful work — `/profiles/list` serves its auth status from a
35
+ * 60s cache that the instance's own 45s keepalive already keeps warm.
36
+ */
37
+ export declare const FOLLOW_POLL_INTERVAL_MS = 10000;
38
+ /** Per-poll timeout. Short: a slow followed instance must not accumulate polls. */
39
+ export declare const FOLLOW_FETCH_TIMEOUT_MS = 2000;
40
+ /**
41
+ * How long a value may go unconfirmed before it is REPORTED stale.
42
+ *
43
+ * Staleness deliberately does not change routing. Falling back to the local
44
+ * value after a timeout would silently split the comparison exactly when you
45
+ * are least likely to notice, and the local value is not more correct — it is
46
+ * just different. A stale-but-known followed value remains the best available
47
+ * answer to "what is the primary on?"; the dev instance's own `activeProfile`
48
+ * is arbitrary. So a stale value is still followed, and is flagged as stale
49
+ * everywhere the mode is surfaced.
50
+ */
51
+ export declare const FOLLOW_STALE_AFTER_MS = 120000;
52
+ export type FollowTarget = {
53
+ kind: "off";
54
+ } | {
55
+ kind: "on";
56
+ url: string;
57
+ } | {
58
+ kind: "invalid";
59
+ raw: string;
60
+ message: string;
61
+ };
62
+ /**
63
+ * Parse the env var value into a normalized base URL.
64
+ *
65
+ * A bare `host:port` is accepted and assumed to be http, because that is what
66
+ * anyone types first and `new URL()` would otherwise read `127.0.0.1` as a
67
+ * scheme. Trailing slashes are stripped so callers can concatenate paths.
68
+ *
69
+ * A malformed value yields "invalid" rather than throwing: the caller warns
70
+ * and runs without follow mode. Refusing to start on a typo would take an
71
+ * instance offline, which is the one outcome this feature must never cause.
72
+ */
73
+ export declare function parseFollowTarget(raw: string | undefined): FollowTarget;
74
+ /**
75
+ * Whether a follow target addresses the instance doing the following.
76
+ *
77
+ * Self-follow is a deadlock, not a harmless no-op: the instance would follow
78
+ * its own active profile (so the value never changes) while refusing local
79
+ * writes (so nothing can change it), leaving the profile frozen forever. It is
80
+ * also the realistic typo — copying the wrong port out of a unit file.
81
+ */
82
+ export declare function isSelfTarget(url: string, selfHost: string, selfPort: number): boolean;
83
+ /**
84
+ * Extract `activeProfile` from a `/profiles/list` body.
85
+ *
86
+ * Deliberately paranoid about the shape. The followed instance may be a
87
+ * different version, a different program listening on a recycled port, or an
88
+ * error page — "answers rubbish" is one of the failure modes this must
89
+ * survive, and a non-string or absurdly long value must be treated as no
90
+ * value at all rather than routed to.
91
+ */
92
+ export declare function readActiveProfile(body: unknown): string | undefined;
93
+ /** A profile the followed instance has, and where its credentials live. */
94
+ export interface FollowedProfile {
95
+ id: string;
96
+ /** Absolute CLAUDE_CONFIG_DIR, on a filesystem both instances can read. */
97
+ credentialDir: string;
98
+ }
99
+ export interface FollowedRoster {
100
+ /** Profiles this instance can serve by pointing at the same directory. */
101
+ adoptable: FollowedProfile[];
102
+ /** Profiles it cannot, because their credentials are an inline secret. */
103
+ unadoptable: string[];
104
+ }
105
+ /**
106
+ * Extract the profile roster from a `/profiles/list` body.
107
+ *
108
+ * Following one scalar is not enough. `MERIDIAN_CONFIG_DIR` gives a second
109
+ * instance its own `profiles.json` — that is the whole point of it — so the
110
+ * two rosters diverge the moment an account is added to either. The followed
111
+ * value then names a profile this instance does not have, `decideFollowedProfile`
112
+ * returns "unknown-profile", and the dev instance serves from an unrelated
113
+ * account: exactly the divergence follow mode exists to prevent. Measured on
114
+ * one box, a profile added to the primary was still absent from the follower
115
+ * minutes later, and its traffic 429'd against the wrong account.
116
+ *
117
+ * Adoptability is decided by the SENDER, which is the only side that can. A
118
+ * profile authenticated by a file both instances can read crosses as a path; a
119
+ * profile authenticated by an inline API key or OAuth token cannot cross at
120
+ * all, because the secret must not leave the process that holds it. The sender
121
+ * reports the second kind by id alone so this instance can say why an account
122
+ * it can see is one it cannot serve.
123
+ *
124
+ * Returns undefined — distinct from an empty roster — when the body carries no
125
+ * roster information at all. `credentialDir` is emitted for EVERY profile, null
126
+ * included, so its total absence means the followed instance predates this and
127
+ * cannot answer the question. Guessing "nothing is adoptable" there would warn
128
+ * about accounts that are merely unreported.
129
+ */
130
+ export declare function readFollowedRoster(body: unknown): FollowedRoster | undefined;
131
+ export interface FollowState {
132
+ /** Last value successfully read, and when it was last CONFIRMED by a poll. */
133
+ lastGood?: {
134
+ profileId: string;
135
+ at: number;
136
+ };
137
+ /**
138
+ * Last roster successfully read. Kept across a failed poll for the same
139
+ * reason `lastGood` is: a followed instance that has gone quiet has not
140
+ * withdrawn its accounts, and dropping them would strand every session
141
+ * pinned to one.
142
+ */
143
+ lastRoster?: {
144
+ roster: FollowedRoster;
145
+ at: number;
146
+ };
147
+ /** When the most recent poll completed, successful or not. */
148
+ lastPollAt?: number;
149
+ /** Most recent poll failure. Cleared on the next success. */
150
+ lastError?: {
151
+ message: string;
152
+ at: number;
153
+ };
154
+ }
155
+ export type FollowOutcome = {
156
+ follow: true;
157
+ profileId: string;
158
+ stale: boolean;
159
+ } | {
160
+ follow: false;
161
+ reason: "no-value" | "unknown-profile";
162
+ followedValue?: string;
163
+ };
164
+ /**
165
+ * Decide whether the followed value should be used, given what this instance
166
+ * actually has. Pure — the whole point is that every branch is testable
167
+ * without a second instance running.
168
+ *
169
+ * `unknown-profile` is a fallback, not a resolution: routing to a profile this
170
+ * instance does not have would resolve to "first configured profile" deeper in
171
+ * `resolveProfile` and silently serve from an unrelated account. Using the
172
+ * local choice and saying so is the smaller surprise.
173
+ */
174
+ export declare function decideFollowedProfile(state: FollowState, availableIds: readonly string[], now: number, staleAfterMs?: number): FollowOutcome;
175
+ /**
176
+ * The followed instance's base URL, or undefined when not following.
177
+ *
178
+ * Resolved per call rather than frozen at import time, matching `settings.ts`'s
179
+ * treatment of MERIDIAN_CONFIG_DIR — a value captured at import would be fixed
180
+ * before any test (or embedding host) could set it. Parsing is memoized on the
181
+ * raw string so the request path does not build a URL object per call.
182
+ */
183
+ export declare function followTarget(): {
184
+ url: string;
185
+ } | undefined;
186
+ /** Whether this instance takes its active profile from another one. */
187
+ export declare function isFollowEnabled(): boolean;
188
+ /**
189
+ * The follow decision for a given profile list, or undefined when not
190
+ * following. Called on the request path — synchronous, cache-only, no I/O.
191
+ */
192
+ export declare function followedActiveProfile(availableIds: readonly string[]): FollowOutcome | undefined;
193
+ /**
194
+ * Profiles contributed by the followed instance. Called on the request path
195
+ * through `getEffectiveProfiles` — synchronous, cache-only, no I/O.
196
+ *
197
+ * Empty until the first successful poll, so an instance whose followed peer is
198
+ * down starts with its own profiles rather than none.
199
+ */
200
+ export declare function adoptedProfiles(): readonly FollowedProfile[];
201
+ /** Follow state as surfaced by `/profiles/list`. Undefined when not following. */
202
+ export interface FollowStatus {
203
+ /** Base URL of the followed instance. */
204
+ url: string;
205
+ /** Value actually in effect, or null when falling back to the local one. */
206
+ activeProfile: string | null;
207
+ /** Last value read from the followed instance, even if unusable here. */
208
+ followedValue: string | null;
209
+ /** Why the followed value is not in effect, when it isn't. */
210
+ reason: "no-value" | "unknown-profile" | null;
211
+ /** Followed value has not been confirmed recently — still in effect. */
212
+ stale: boolean;
213
+ /** When the followed value was last confirmed. */
214
+ lastSyncedAt: number | null;
215
+ /** Most recent poll failure, if the last poll failed. */
216
+ lastError: string | null;
217
+ /** Profile ids taken from the followed instance and served here. */
218
+ adoptedProfiles: string[];
219
+ /** Profile ids it has that cannot be adopted, so a UI can say why. */
220
+ unadoptableProfiles: string[];
221
+ /** When the roster was last confirmed, or null if never read. */
222
+ rosterSyncedAt: number | null;
223
+ }
224
+ export declare function followStatus(availableIds: readonly string[]): FollowStatus | undefined;
225
+ /**
226
+ * Read the followed instance's active profile once and update the cache.
227
+ *
228
+ * Never throws and never clears a good value on failure: a failed poll leaves
229
+ * the last known value in place, which is what "degrade, never fail" means
230
+ * here. Exported so tests can drive it without a timer.
231
+ */
232
+ export declare function pollFollowedActiveProfile(): Promise<void>;
233
+ /**
234
+ * Arm the background poll. Idempotent.
235
+ *
236
+ * `self` is the address this instance actually bound (the configured port may
237
+ * be 0), used only for the self-follow guard.
238
+ */
239
+ export declare function startFollowPolling(self?: {
240
+ host: string;
241
+ port: number;
242
+ }): void;
243
+ /** Stop the background poll. Idempotent. */
244
+ export declare function stopFollowPolling(): void;
245
+ /**
246
+ * Announce the mode once at startup.
247
+ *
248
+ * Not gated on `silent`, matching the treatment of other non-default operating
249
+ * modes: MERIDIAN_SILENT suppresses routine chatter, and this is not routine —
250
+ * it changes where a core piece of this instance's state comes from. An
251
+ * instance silently following another is exactly the hour-long confusion this
252
+ * line exists to prevent.
253
+ *
254
+ * @param routingMode current routing mode, so the one combination where follow
255
+ * mode does nothing useful says so instead of being discovered the hard way.
256
+ */
257
+ export declare function logFollowBanner(routingMode?: string): void;
258
+ /** Reset all module state — for testing only. */
259
+ export declare function resetFollowActive(): void;
260
+ /** Seed the cache directly — for testing only. */
261
+ export declare function setFollowStateForTesting(next: FollowState): void;
262
+ //# sourceMappingURL=followActive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"followActive.d.ts","sourceRoot":"","sources":["../../src/proxy/followActive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Which allowance did Anthropic just refuse?
3
+ *
4
+ * An account that has run out keeps reporting healthy percentages: measured on
5
+ * the live fleet, `corp4` rendered `5h 67% / 7d 7%` on /profiles at the same
6
+ * minute its requests were being refused. The cached numbers are a snapshot of
7
+ * the last successful read; a refusal is news that arrives later and never
8
+ * overwrites them. So the refusal has to be recorded and reported on its own
9
+ * terms, next to the cached numbers rather than instead of them.
10
+ *
11
+ * This module answers only the "which bucket, and when does it reset" part.
12
+ * It is a leaf module and every function here is pure - the stores that hold
13
+ * the answers live in profileHealth.ts.
14
+ *
15
+ * Evidence ladder, best source first. The distinction that matters to a reader
16
+ * of the UI is `reported` (Anthropic said so) versus inferred (we worked it
17
+ * out from stale numbers), so every diagnosis carries it explicitly:
18
+ *
19
+ * 1. `sdk_event` - the SDK's own `rate_limit_event` said `rejected` and
20
+ * named `rateLimitType`. Unambiguous.
21
+ * 2. `error_message` - the CLI's prose names the window. Measured live:
22
+ * "You've hit your session limit · resets 12:30am
23
+ * (America/Chicago)" - that is both the bucket (Claude
24
+ * Code calls the 5-hour window a "session") and a real
25
+ * reset clock, so it is worth parsing rather than
26
+ * discarding.
27
+ * 3. `cached_usage` - nothing said which, so deduce from the last-read
28
+ * windows: whichever is nearest its limit, or, when the
29
+ * weekly windows are nowhere near theirs, the 5-hour one
30
+ * by elimination.
31
+ * 4. `unknown` - say so rather than guessing a bucket.
32
+ *
33
+ * There are no `anthropic-ratelimit-*` response headers to read here: Meridian
34
+ * reaches Anthropic through the Claude Agent SDK subprocess, never over HTTP it
35
+ * can see, so `rate_limit_event` IS this proxy's structured form of those
36
+ * headers and tier 1 above is the header check.
37
+ */
38
+ /** How the bucket was determined. See the ladder in the module doc. */
39
+ export type LimitSource = "sdk_event" | "error_message" | "cached_usage" | "unknown";
40
+ export interface LimitDiagnosis {
41
+ /** Anthropic's window key ("five_hour", "seven_day", "seven_day_opus", …),
42
+ * or null when nothing identified it. */
43
+ bucket: string | null;
44
+ /** True when Anthropic named the bucket; false when we deduced it. Drives
45
+ * the "(guess)" marking in the UI. */
46
+ reported: boolean;
47
+ source: LimitSource;
48
+ /** Epoch ms the window reopens, when known. */
49
+ resetsAt: number | null;
50
+ /** One line explaining the verdict, rendered as the badge's tooltip. */
51
+ rationale: string;
52
+ }
53
+ export interface ParsedLimitWording {
54
+ bucket: string | null;
55
+ /** The qualifier as written, kept for the rationale so an unrecognized one
56
+ * ("daily", "monthly") still tells the reader what the CLI said. */
57
+ qualifier: string | null;
58
+ clock: string | null;
59
+ zone: string | null;
60
+ }
61
+ /**
62
+ * Pull the bucket and reset clock out of an SDK error message. Returns nulls
63
+ * for anything it cannot read - this never throws on unfamiliar prose, because
64
+ * the CLI's wording has changed three times already (#764, #787).
65
+ */
66
+ export declare function parseLimitWording(errMsg: string): ParsedLimitWording;
67
+ /**
68
+ * Resolve "resets 12:30am (America/Chicago)" to an instant: the next time that
69
+ * wall clock occurs in that zone.
70
+ *
71
+ * The offset is read twice - once at `now`, then again at the candidate - so a
72
+ * reset that lands on the far side of a DST boundary resolves to the right
73
+ * instant rather than being an hour out.
74
+ *
75
+ * Returns null for an unparseable clock or unknown zone. Only ever looks one
76
+ * day ahead, so the result is bounded to ~24h from `now`: the CLI prints a
77
+ * clock time with no date, and a value further out than that would be a
78
+ * misreading, not information.
79
+ */
80
+ export declare function resolveResetClock(clock: string, zone: string | null | undefined, now: number): number | null;
81
+ export interface SdkLimitEvidence {
82
+ rateLimitType?: string;
83
+ status?: string;
84
+ utilization?: number | null;
85
+ resetsAt?: number | null;
86
+ observedAt: number;
87
+ }
88
+ export interface CachedWindow {
89
+ type: string;
90
+ utilization: number | null;
91
+ resetsAt: number | null;
92
+ }
93
+ export interface DiagnoseLimitInput {
94
+ /** Raw SDK error text, before `classifyError` replaces it with proxy prose. */
95
+ message: string;
96
+ now: number;
97
+ /** This profile's SDK rate-limit entries (rateLimitStore.getAll). */
98
+ sdkEntries?: readonly SdkLimitEvidence[];
99
+ /** This profile's last-read OAuth usage windows. */
100
+ windows?: readonly CachedWindow[];
101
+ }
102
+ /**
103
+ * Decide which allowance was refused, and say how confident that is.
104
+ *
105
+ * Never throws and always returns a diagnosis - an "unknown" verdict is a
106
+ * useful thing to render ("refusing, cause unknown") and far better than
107
+ * silently attributing the refusal to whichever window happened to look busiest.
108
+ */
109
+ export declare function diagnoseLimit(input: DiagnoseLimitInput): LimitDiagnosis;
110
+ //# sourceMappingURL=limitDetection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limitDetection.d.ts","sourceRoot":"","sources":["../../src/proxy/limitDetection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,uEAAuE;AACvE,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,eAAe,GAAG,cAAc,GAAG,SAAS,CAAA;AAEpF,MAAM,WAAW,cAAc;IAC7B;8CAC0C;IAC1C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;2CACuC;IACvC,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAA;CAClB;AAiCD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;yEACqE;IACrE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAiBpE;AAsDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB5G;AASD,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,qEAAqE;IACrE,UAAU,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACxC,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;CAClC;AAQD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,cAAc,CAgEvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/proxy/models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The account's plan, as Anthropic reports it for a given access token.
3
+ *
4
+ * Shared by the two moments a plan can be learned: an interactive login, which
5
+ * has just minted a token, and a token refresh, which has just minted another.
6
+ * It lives in its own module rather than in profileCli.ts because profileCli
7
+ * already imports tokenRefresh for the credential store, so the refresh path
8
+ * importing back would close a cycle.
9
+ *
10
+ * This is a leaf module — one authenticated GET, no imports.
11
+ */
12
+ interface OAuthProfileResponse {
13
+ organization?: {
14
+ organization_type?: string | null;
15
+ rate_limit_tier?: string | null;
16
+ seat_tier?: string | null;
17
+ } | null;
18
+ }
19
+ export interface OAuthPlanFields {
20
+ subscriptionType?: string;
21
+ rateLimitTier?: string;
22
+ /**
23
+ * Which seat a Team member holds, and the ONLY field that separates a
24
+ * Premium seat from a Standard one. Measured across twelve live accounts:
25
+ * every Premium seat reports `rate_limit_tier: "default_claude_max_5x"` —
26
+ * byte-identical to what a personal Max 5x reports — and a Standard seat
27
+ * reports `default_raven`, a codename naming no published allotment. So the
28
+ * rate-limit tier can size neither kind of Team seat: one because it lies
29
+ * and one because it says nothing. Null on every personal account.
30
+ */
31
+ seatTier?: string;
32
+ }
33
+ /**
34
+ * Translate Anthropic's wire `organization_type` into the vocabulary the Claude
35
+ * CLI writes on disk — the wire value is prefixed (`claude_max`), the stored one
36
+ * is not (`max`). Mirroring the CLI's own mapping is what keeps a credential
37
+ * file Meridian writes indistinguishable from one `claude login` wrote, which
38
+ * matters because `claude auth status` reads it back and is what ultimately
39
+ * feeds `/profiles/list`, `/health` and the `max`-only branch of `/v1/models`.
40
+ *
41
+ * An unrecognized or absent type yields undefined so the caller omits the key,
42
+ * rather than inventing a plan for an account it could not identify.
43
+ */
44
+ export declare function subscriptionTypeFromOrganizationType(organizationType: string | null | undefined): string | undefined;
45
+ export declare function extractPlanFields(profile: OAuthProfileResponse | null | undefined): OAuthPlanFields;
46
+ /**
47
+ * Whether a stored credential is still missing plan information.
48
+ *
49
+ * Either field being absent counts, because they answer different questions
50
+ * and arrive from different writers: `claude login` records `subscriptionType`
51
+ * but not always `rateLimitTier`, and only `rateLimitTier` distinguishes Max 5x
52
+ * from Max 20x. Requiring both means a file half-filled by the CLI still gets
53
+ * completed.
54
+ */
55
+ export declare function planFieldsMissing(fields: OAuthPlanFields | null | undefined): boolean;
56
+ /**
57
+ * Best-effort plan lookup for a valid access token. Never throws and never
58
+ * fails its caller: a profile whose plan is unknown is strictly better than no
59
+ * profile at all, and every consumer already treats it as optional.
60
+ */
61
+ export declare function fetchOAuthPlanFields(accessToken: string): Promise<OAuthPlanFields>;
62
+ export {};
63
+ //# sourceMappingURL=oauthPlan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthPlan.d.ts","sourceRoot":"","sources":["../../src/proxy/oauthPlan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkBH,UAAU,oBAAoB;IAC5B,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAC1B,GAAG,IAAI,CAAA;CACT;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oCAAoC,CAClD,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe,CASnG;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAErF;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAuCxF"}