@rikcodes/teamclaude 1.1.13-rik.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +122 -0
- package/package.json +43 -0
- package/src/account-manager.js +1459 -0
- package/src/account-uuid-rewrite.js +115 -0
- package/src/alias.js +125 -0
- package/src/claude-env.js +65 -0
- package/src/config.js +146 -0
- package/src/crash-log.js +27 -0
- package/src/egress-guard.js +132 -0
- package/src/identity.js +96 -0
- package/src/index.js +1873 -0
- package/src/json-format-stream.js +63 -0
- package/src/mitm.js +336 -0
- package/src/model.js +276 -0
- package/src/oauth.js +459 -0
- package/src/prober.js +158 -0
- package/src/request-log.js +32 -0
- package/src/resolve-accounts.js +43 -0
- package/src/server.js +1319 -0
- package/src/service.js +241 -0
- package/src/session-tracker.js +133 -0
- package/src/status-renderer.js +316 -0
- package/src/sx.js +218 -0
- package/src/terminal-title.js +31 -0
- package/src/tool-pair-sanitize.js +193 -0
- package/src/tui-remote.js +274 -0
- package/src/tui.js +1634 -0
- package/src/updater.js +177 -0
- package/src/upstream-fetch.js +267 -0
- package/src/upstream-proxy.js +214 -0
- package/src/warmer.js +237 -0
- package/src/x509.js +166 -0
package/src/identity.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Account identity helpers.
|
|
2
|
+
//
|
|
3
|
+
// An OAuth account is identified by its Anthropic account UUID (the *person*)
|
|
4
|
+
// plus the organization it is scoped to. The same email/person can belong to
|
|
5
|
+
// multiple organizations — e.g. a corporate Pro org and a personal Max org —
|
|
6
|
+
// each with its own OAuth token and quota. The org must therefore be part of
|
|
7
|
+
// the identity; otherwise multi-org logins overwrite each other, removals match
|
|
8
|
+
// the wrong entry, and token rotation persists onto the wrong account.
|
|
9
|
+
//
|
|
10
|
+
// The org discriminator prefers the org UUID but falls back to the org name
|
|
11
|
+
// (the profile endpoint has always returned a name), so identity still works on
|
|
12
|
+
// entries created before org UUIDs were stored.
|
|
13
|
+
|
|
14
|
+
/** Stable org discriminator for an account record: org UUID, else org name, else null. */
|
|
15
|
+
export function orgKey(acct) {
|
|
16
|
+
return acct?.orgUuid || acct?.orgName || null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Whether two account records refer to the same account+org.
|
|
21
|
+
*
|
|
22
|
+
* - Both have an accountUuid: it must match. If both org keys are known they
|
|
23
|
+
* must also match; but if either side's org is still unknown we treat them as
|
|
24
|
+
* the same. This lets a freshly-profiled login backfill a legacy entry (which
|
|
25
|
+
* has no stored org) instead of creating a duplicate. Once both sides carry an
|
|
26
|
+
* org key, a *different* org is correctly seen as a distinct account.
|
|
27
|
+
* - Otherwise (API-key accounts, or no UUID yet): fall back to matching by name.
|
|
28
|
+
*/
|
|
29
|
+
export function sameIdentity(a, b) {
|
|
30
|
+
if (a?.accountUuid && b?.accountUuid) {
|
|
31
|
+
if (a.accountUuid !== b.accountUuid) return false;
|
|
32
|
+
const ka = orgKey(a);
|
|
33
|
+
const kb = orgKey(b);
|
|
34
|
+
if (ka && kb) return ka === kb;
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return a?.name === b?.name;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Are these two records definitely NOT the same account? True only when both
|
|
42
|
+
* sides are fully identified and point at different account+org pairs — an
|
|
43
|
+
* unknown UUID or org on either side means "cannot tell", never "different".
|
|
44
|
+
*/
|
|
45
|
+
export function distinctAccounts(a, b) {
|
|
46
|
+
if (!a?.accountUuid || !b?.accountUuid) return false;
|
|
47
|
+
if (a.accountUuid !== b.accountUuid) return true;
|
|
48
|
+
const ka = orgKey(a);
|
|
49
|
+
const kb = orgKey(b);
|
|
50
|
+
return !!(ka && kb && ka !== kb);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Index of the config entry an incoming login should UPDATE, or -1 to add it as
|
|
55
|
+
* a new one.
|
|
56
|
+
*
|
|
57
|
+
* Identity decides first: the same account+org is the same entry. A bare display
|
|
58
|
+
* name match is accepted only when nothing contradicts it — one person's two
|
|
59
|
+
* organizations share an email, and the display name is derived from that email,
|
|
60
|
+
* so treating equal names as one account overwrites the other org's entry and
|
|
61
|
+
* silently drops an account from the config. The account keeps working until the
|
|
62
|
+
* process that still holds it in memory restarts, which is what makes the loss
|
|
63
|
+
* hard to trace back to the login that caused it.
|
|
64
|
+
*/
|
|
65
|
+
export function findUpsertTarget(accounts, incoming) {
|
|
66
|
+
const byIdentity = accounts.findIndex(a => sameIdentity(a, incoming));
|
|
67
|
+
if (byIdentity >= 0) return byIdentity;
|
|
68
|
+
return accounts.findIndex(a => a.name === incoming.name && !distinctAccounts(a, incoming));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The email portion of a display name, stripping any " (org)" suffix. */
|
|
72
|
+
export function emailOf(acct) {
|
|
73
|
+
return (acct?.name || '').replace(/ \(.*\)$/, '');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Find accounts matching a name-or-email query, optionally narrowed by org.
|
|
78
|
+
*
|
|
79
|
+
* An exact display-name match wins outright. Otherwise match by email (so
|
|
80
|
+
* `remove user@x.com` finds `user@x.com (Acme)`). `orgFilter` narrows by org
|
|
81
|
+
* name or org UUID (prefix allowed). Returns the array of matches; the caller
|
|
82
|
+
* decides what to do with 0, 1, or many.
|
|
83
|
+
*/
|
|
84
|
+
export function matchAccounts(accounts, query, orgFilter) {
|
|
85
|
+
let matches = accounts.filter(a => a.name === query);
|
|
86
|
+
if (matches.length === 0) {
|
|
87
|
+
matches = accounts.filter(a => emailOf(a) === query);
|
|
88
|
+
}
|
|
89
|
+
if (orgFilter) {
|
|
90
|
+
matches = matches.filter(a =>
|
|
91
|
+
(a.orgName && a.orgName === orgFilter) ||
|
|
92
|
+
(a.orgUuid && (a.orgUuid === orgFilter || a.orgUuid.startsWith(orgFilter)))
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return matches;
|
|
96
|
+
}
|