@namzu/cli 8.1.0 → 8.3.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.
- package/dist/doctor/checks/credentials.d.ts.map +1 -1
- package/dist/doctor/checks/credentials.js +2 -0
- package/dist/doctor/checks/credentials.js.map +1 -1
- package/dist/integrations/providers/credential-store.d.ts +118 -0
- package/dist/integrations/providers/credential-store.d.ts.map +1 -0
- package/dist/integrations/providers/credential-store.js +322 -0
- package/dist/integrations/providers/credential-store.js.map +1 -0
- package/dist/integrations/providers/discover.d.ts +37 -10
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js +43 -13
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/integrations/providers/identity.d.ts +75 -0
- package/dist/integrations/providers/identity.d.ts.map +1 -0
- package/dist/integrations/providers/identity.js +75 -0
- package/dist/integrations/providers/identity.js.map +1 -0
- package/dist/integrations/providers/index.d.ts +5 -2
- package/dist/integrations/providers/index.d.ts.map +1 -1
- package/dist/integrations/providers/index.js +5 -2
- package/dist/integrations/providers/index.js.map +1 -1
- package/dist/integrations/providers/oauth.d.ts +37 -7
- package/dist/integrations/providers/oauth.d.ts.map +1 -1
- package/dist/integrations/providers/oauth.js +62 -17
- package/dist/integrations/providers/oauth.js.map +1 -1
- package/dist/integrations/providers/registry.d.ts +16 -0
- package/dist/integrations/providers/registry.d.ts.map +1 -1
- package/dist/integrations/providers/registry.js +19 -0
- package/dist/integrations/providers/registry.js.map +1 -1
- package/dist/integrations/providers/subscription-login.d.ts +123 -0
- package/dist/integrations/providers/subscription-login.d.ts.map +1 -0
- package/dist/integrations/providers/subscription-login.js +348 -0
- package/dist/integrations/providers/subscription-login.js.map +1 -0
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +166 -7
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Picker.d.ts +28 -1
- package/dist/tui/Picker.d.ts.map +1 -1
- package/dist/tui/Picker.js +71 -20
- package/dist/tui/Picker.js.map +1 -1
- package/dist/tui/agent.d.ts +24 -0
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +68 -11
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/credential-entry.d.ts +54 -18
- package/dist/tui/credential-entry.d.ts.map +1 -1
- package/dist/tui/credential-entry.js +67 -24
- package/dist/tui/credential-entry.js.map +1 -1
- package/dist/tui/login-prompt.d.ts +41 -0
- package/dist/tui/login-prompt.d.ts.map +1 -0
- package/dist/tui/login-prompt.js +69 -0
- package/dist/tui/login-prompt.js.map +1 -0
- package/dist/tui/open-browser.d.ts +24 -0
- package/dist/tui/open-browser.d.ts.map +1 -0
- package/dist/tui/open-browser.js +57 -0
- package/dist/tui/open-browser.js.map +1 -0
- package/dist/tui/slashCommands.d.ts +16 -0
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +13 -0
- package/dist/tui/slashCommands.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Credential discoverer for LLM provider clients.
|
|
3
3
|
*
|
|
4
|
-
* For each entry in `PROVIDER_REGISTRY`, ask
|
|
4
|
+
* For each entry in `PROVIDER_REGISTRY`, ask four questions in order:
|
|
5
5
|
* 1. Is one of its env vars set in `process.env`?
|
|
6
|
-
* 2. Is there
|
|
6
|
+
* 2. Is there a subscription credential in namzu's own store — the one the
|
|
7
|
+
* login flow writes? (every platform, and only `anthropic` consumes it.)
|
|
8
|
+
* 3. Is there an OAuth credential in the login Keychain? (macOS only, and
|
|
7
9
|
* only `anthropic` consumes it.)
|
|
8
|
-
*
|
|
10
|
+
* 4. Is the probe URL (if any) reachable right now?
|
|
9
11
|
*
|
|
10
12
|
* The header used to say "three" and list two, and the one it omitted was the
|
|
11
13
|
* Keychain — the question that reads a secret off the machine, so the one a
|
|
@@ -13,11 +15,18 @@
|
|
|
13
15
|
* tell that the list stopped being maintained; in a file about credentials that
|
|
14
16
|
* is worth more than a typo.
|
|
15
17
|
*
|
|
16
|
-
* **The Keychain path is macOS-only and that is
|
|
17
|
-
* `readAgentKeychainCredential` returns `null` on any other platform
|
|
18
|
-
* looks at anything
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* **The Keychain path is macOS-only, and question 2 is why that is no longer a
|
|
19
|
+
* hole.** `readAgentKeychainCredential` returns `null` on any other platform
|
|
20
|
+
* before it looks at anything; it reads a credential belonging to a
|
|
21
|
+
* co-installed tool, so it can only ever help someone who has that tool, on
|
|
22
|
+
* that operating system. namzu's own store is asked first among the credential
|
|
23
|
+
* sources and works everywhere, which is what makes signing in from inside
|
|
24
|
+
* namzu useful on a machine that has neither.
|
|
25
|
+
*
|
|
26
|
+
* Order between the two matters when both answer. namzu's own store wins,
|
|
27
|
+
* because it is the one namzu wrote and refreshes; preferring a borrowed
|
|
28
|
+
* credential over the operator's own sign-in would make the login look
|
|
29
|
+
* ineffective on precisely the machine where they bothered to run it.
|
|
21
30
|
*
|
|
22
31
|
* The first positive answer per provider wins; subsequent sources are
|
|
23
32
|
* recorded as "also available from" so the picker can show alternatives
|
|
@@ -51,15 +60,20 @@
|
|
|
51
60
|
* Discovery is non-throwing. Network probes have short timeouts. The
|
|
52
61
|
* picker can render immediately and refine if discovery completes later.
|
|
53
62
|
*/
|
|
63
|
+
import { credentialsPath, readStoredSubscriptionCredential } from './credential-store.js';
|
|
54
64
|
import { KEYCHAIN_SERVICE, readAgentKeychainCredential } from './keychain.js';
|
|
55
65
|
import { PROVIDER_REGISTRY } from './registry.js';
|
|
56
66
|
const DEFAULT_PROBE_TIMEOUT_MS = 500;
|
|
57
67
|
export async function discoverProviders(opts = {}) {
|
|
58
68
|
const env = opts.env ?? process.env;
|
|
59
69
|
const detected = [];
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
|
|
70
|
+
// Read both credential sources once, up front, so the loop body stays
|
|
71
|
+
// uniform. Only anthropic consumes either.
|
|
72
|
+
const storedCredential = opts.skipStored
|
|
73
|
+
? null
|
|
74
|
+
: readStoredSubscriptionCredential(...(opts.home === undefined ? [] : [opts.home]));
|
|
75
|
+
// macOS-only: the OAuth credential a co-installed tool keeps in the login
|
|
76
|
+
// Keychain.
|
|
63
77
|
const keychainCredential = opts.skipKeychain ? null : readAgentKeychainCredential();
|
|
64
78
|
for (const id of Object.keys(PROVIDER_REGISTRY)) {
|
|
65
79
|
const entry = PROVIDER_REGISTRY[id];
|
|
@@ -74,16 +88,32 @@ export async function discoverProviders(opts = {}) {
|
|
|
74
88
|
sources.push({ kind: 'env', envName });
|
|
75
89
|
}
|
|
76
90
|
}
|
|
91
|
+
if (id === 'anthropic' && storedCredential) {
|
|
92
|
+
if (apiKey === undefined)
|
|
93
|
+
apiKey = storedCredential.accessToken;
|
|
94
|
+
sources.push({
|
|
95
|
+
kind: 'stored',
|
|
96
|
+
path: credentialsPath(...(opts.home === undefined ? [] : [opts.home])),
|
|
97
|
+
});
|
|
98
|
+
// Only carry refresh metadata when this token is the one we'll
|
|
99
|
+
// actually use (an env/secrets token has no refresh path).
|
|
100
|
+
if (apiKey === storedCredential.accessToken) {
|
|
101
|
+
oauth = {
|
|
102
|
+
refreshToken: storedCredential.refreshToken,
|
|
103
|
+
expiresAt: storedCredential.expiresAt,
|
|
104
|
+
origin: 'stored',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
77
108
|
if (id === 'anthropic' && keychainCredential) {
|
|
78
109
|
if (apiKey === undefined)
|
|
79
110
|
apiKey = keychainCredential.accessToken;
|
|
80
111
|
sources.push({ kind: 'keychain', service: KEYCHAIN_SERVICE });
|
|
81
|
-
// Only carry refresh metadata when the Keychain token is the one we'll
|
|
82
|
-
// actually use (an env/secrets token has no refresh path).
|
|
83
112
|
if (apiKey === keychainCredential.accessToken) {
|
|
84
113
|
oauth = {
|
|
85
114
|
refreshToken: keychainCredential.refreshToken,
|
|
86
115
|
expiresAt: keychainCredential.expiresAt,
|
|
116
|
+
origin: 'keychain',
|
|
87
117
|
};
|
|
88
118
|
}
|
|
89
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/integrations/providers/discover.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/integrations/providers/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,OAAO,EAAE,eAAe,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAA;AAE7E,OAAO,EAAE,iBAAiB,EAA+C,MAAM,eAAe,CAAA;AAkE9F,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,OAAwB,EAAE;IAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;IACnC,MAAM,QAAQ,GAAuB,EAAE,CAAA;IAEvC,sEAAsE;IACtE,2CAA2C;IAC3C,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU;QACvC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,gCAAgC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACpF,0EAA0E;IAC1E,YAAY;IACZ,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAAA;IAEnF,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAA0B,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAA;QACnC,MAAM,OAAO,GAAsB,EAAE,CAAA;QACrC,IAAI,MAA0B,CAAA;QAC9B,IAAI,KAAgC,CAAA;QACpC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;YACtB,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,IAAI,MAAM,KAAK,SAAS;oBAAE,MAAM,GAAG,CAAC,CAAA;gBACpC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;YACvC,CAAC;QACF,CAAC;QACD,IAAI,EAAE,KAAK,WAAW,IAAI,gBAAgB,EAAE,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAA;YAC/D,OAAO,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;aACtE,CAAC,CAAA;YACF,+DAA+D;YAC/D,2DAA2D;YAC3D,IAAI,MAAM,KAAK,gBAAgB,CAAC,WAAW,EAAE,CAAC;gBAC7C,KAAK,GAAG;oBACP,YAAY,EAAE,gBAAgB,CAAC,YAAY;oBAC3C,SAAS,EAAE,gBAAgB,CAAC,SAAS;oBACrC,MAAM,EAAE,QAAQ;iBAChB,CAAA;YACF,CAAC;QACF,CAAC;QACD,IAAI,EAAE,KAAK,WAAW,IAAI,kBAAkB,EAAE,CAAC;YAC9C,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM,GAAG,kBAAkB,CAAC,WAAW,CAAA;YACjE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAA;YAC7D,IAAI,MAAM,KAAK,kBAAkB,CAAC,WAAW,EAAE,CAAC;gBAC/C,KAAK,GAAG;oBACP,YAAY,EAAE,kBAAkB,CAAC,YAAY;oBAC7C,SAAS,EAAE,kBAAkB,CAAC,SAAS;oBACvC,MAAM,EAAE,UAAU;iBAClB,CAAA;YACF,CAAC;QACF,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChE,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;YACnD,IAAI,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;YACrD,CAAC;QACF,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC;gBACb,KAAK;gBACL,MAAM,EAAE,OAAO,CAAC,CAAC,CAAoB;gBACrC,MAAM;gBACN,OAAO,EAAE,KAAK,CAAC,cAAc;gBAC7B,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;aAC9B,CAAC,CAAA;QACH,CAAC;IACF,CAAC;IACD,OAAO,QAAQ,CAAA;AAChB,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,GAAW,EAAE,IAAqB;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;IAC9C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,MAAM,KAAK,GAAG,UAAU,CACvB,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EACxB,IAAI,CAAC,cAAc,IAAI,wBAAwB,CAC/C,CAAA;IACD,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5E,OAAO,GAAG,CAAC,EAAE,CAAA;IACd,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAA;IACb,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC;AACF,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAC3B,IAAiC,EACjC,EAAc;IAEd,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OAuth client namzu presents when it signs an operator in, and the
|
|
3
|
+
* addresses that identity is valid against.
|
|
4
|
+
*
|
|
5
|
+
* ## Whose identity this is — the decision, written where the value is
|
|
6
|
+
*
|
|
7
|
+
* `OAUTH_CLIENT_ID` was **not registered by namzu**. It is the public client
|
|
8
|
+
* identifier that the vendor's own command-line tool is registered under, and
|
|
9
|
+
* it is the only one the subscription authorization server will issue
|
|
10
|
+
* plan-scoped inference tokens to. This project has no client of its own
|
|
11
|
+
* there because that vendor operates no open client registration for this
|
|
12
|
+
* grant: there is no form to fill in, no application to make. The choice was
|
|
13
|
+
* therefore between presenting this identity, and not offering the capability
|
|
14
|
+
* at all.
|
|
15
|
+
*
|
|
16
|
+
* The owner decided the capability should exist, so this is the identity used,
|
|
17
|
+
* and the consequences are stated rather than discovered later:
|
|
18
|
+
*
|
|
19
|
+
* - **The authorization server cannot tell namzu apart from that tool.** A
|
|
20
|
+
* credential obtained here is, at the server, a credential obtained there.
|
|
21
|
+
* - **The operator's own plan governs it.** namzu mediates a sign-in the
|
|
22
|
+
* person completes themselves, on the vendor's own page, against the
|
|
23
|
+
* vendor's own account. No namzu service sees the credential, and nothing
|
|
24
|
+
* is proxied — the token goes from the vendor to this machine.
|
|
25
|
+
* - **This identity can be revoked by its owner at any time,** and if it is,
|
|
26
|
+
* every sign-in below stops working at once. That is a dependency namzu
|
|
27
|
+
* accepted knowingly; it is not a bug to be worked around when it happens.
|
|
28
|
+
* - **It is not a secret and is not treated as one.** A public OAuth client
|
|
29
|
+
* identifier is public by definition — that is why PKCE exists. Nearby
|
|
30
|
+
* implementations obscure this value behind a base64 decode at runtime,
|
|
31
|
+
* which hides nothing from anyone reading the request and hides the one
|
|
32
|
+
* fact a reviewer of THIS file most needs. It stays legible.
|
|
33
|
+
*
|
|
34
|
+
* Anyone uncomfortable with the above has the other door: set the credential
|
|
35
|
+
* in the environment and namzu never runs this flow at all.
|
|
36
|
+
*
|
|
37
|
+
* ## The addresses
|
|
38
|
+
*
|
|
39
|
+
* Verified 2026-08-09 rather than assumed. Two hosts serve this token
|
|
40
|
+
* endpoint — the one below and `platform.claude.com` on the same path — and
|
|
41
|
+
* both answer an `authorization_code` grant identically (`400 invalid_grant`
|
|
42
|
+
* for a bogus code, from the same handler). namzu keeps the address its
|
|
43
|
+
* existing refresh path has always used, because there was no behaviour to
|
|
44
|
+
* gain by moving and a live refresh to lose by guessing.
|
|
45
|
+
*
|
|
46
|
+
* The redirect port is fixed and NOT free to change: it is part of what the
|
|
47
|
+
* client identity above is registered with, so a different port is simply not
|
|
48
|
+
* an accepted redirect. That is why a busy port degrades to the paste flow
|
|
49
|
+
* rather than picking another one.
|
|
50
|
+
*/
|
|
51
|
+
export declare const OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
52
|
+
export declare const OAUTH_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
53
|
+
export declare const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
54
|
+
/** Registered with the client identity above; not ours to choose. */
|
|
55
|
+
export declare const SUBSCRIPTION_REDIRECT_PORT = 53692;
|
|
56
|
+
export declare const REDIRECT_URI = "http://localhost:53692/callback";
|
|
57
|
+
/**
|
|
58
|
+
* Asked for at sign-in.
|
|
59
|
+
*
|
|
60
|
+
* This is WIDER than namzu needs, and that is a knowing compromise rather
|
|
61
|
+
* than an oversight. Least privilege would ask for an identity and the right
|
|
62
|
+
* to run inference, and stop; this set also admits key creation and file
|
|
63
|
+
* upload. It is the set the client identity above is exercised with by the
|
|
64
|
+
* implementations that are known to work, and a narrower request cannot be
|
|
65
|
+
* tested from here — nobody on this side of the flow holds a plan-backed
|
|
66
|
+
* account to try it against. Guessing narrow fails in the worst place: the
|
|
67
|
+
* sign-in succeeds, and inference is refused afterwards with an error about
|
|
68
|
+
* scope that the operator cannot act on.
|
|
69
|
+
*
|
|
70
|
+
* So it is recorded as debt with the measurement that would settle it: sign
|
|
71
|
+
* in with `user:profile user:inference` alone and send one message. If that
|
|
72
|
+
* works, this shrinks to those two.
|
|
73
|
+
*/
|
|
74
|
+
export declare const OAUTH_SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
|
|
75
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,eAAO,MAAM,eAAe,yCAAyC,CAAA;AACrE,eAAO,MAAM,eAAe,iDAAiD,CAAA;AAC7E,eAAO,MAAM,aAAa,sCAAsC,CAAA;AAEhE,qEAAqE;AACrE,eAAO,MAAM,0BAA0B,QAAQ,CAAA;AAC/C,eAAO,MAAM,YAAY,oCAA4D,CAAA;AAErF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY,+GACoF,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OAuth client namzu presents when it signs an operator in, and the
|
|
3
|
+
* addresses that identity is valid against.
|
|
4
|
+
*
|
|
5
|
+
* ## Whose identity this is — the decision, written where the value is
|
|
6
|
+
*
|
|
7
|
+
* `OAUTH_CLIENT_ID` was **not registered by namzu**. It is the public client
|
|
8
|
+
* identifier that the vendor's own command-line tool is registered under, and
|
|
9
|
+
* it is the only one the subscription authorization server will issue
|
|
10
|
+
* plan-scoped inference tokens to. This project has no client of its own
|
|
11
|
+
* there because that vendor operates no open client registration for this
|
|
12
|
+
* grant: there is no form to fill in, no application to make. The choice was
|
|
13
|
+
* therefore between presenting this identity, and not offering the capability
|
|
14
|
+
* at all.
|
|
15
|
+
*
|
|
16
|
+
* The owner decided the capability should exist, so this is the identity used,
|
|
17
|
+
* and the consequences are stated rather than discovered later:
|
|
18
|
+
*
|
|
19
|
+
* - **The authorization server cannot tell namzu apart from that tool.** A
|
|
20
|
+
* credential obtained here is, at the server, a credential obtained there.
|
|
21
|
+
* - **The operator's own plan governs it.** namzu mediates a sign-in the
|
|
22
|
+
* person completes themselves, on the vendor's own page, against the
|
|
23
|
+
* vendor's own account. No namzu service sees the credential, and nothing
|
|
24
|
+
* is proxied — the token goes from the vendor to this machine.
|
|
25
|
+
* - **This identity can be revoked by its owner at any time,** and if it is,
|
|
26
|
+
* every sign-in below stops working at once. That is a dependency namzu
|
|
27
|
+
* accepted knowingly; it is not a bug to be worked around when it happens.
|
|
28
|
+
* - **It is not a secret and is not treated as one.** A public OAuth client
|
|
29
|
+
* identifier is public by definition — that is why PKCE exists. Nearby
|
|
30
|
+
* implementations obscure this value behind a base64 decode at runtime,
|
|
31
|
+
* which hides nothing from anyone reading the request and hides the one
|
|
32
|
+
* fact a reviewer of THIS file most needs. It stays legible.
|
|
33
|
+
*
|
|
34
|
+
* Anyone uncomfortable with the above has the other door: set the credential
|
|
35
|
+
* in the environment and namzu never runs this flow at all.
|
|
36
|
+
*
|
|
37
|
+
* ## The addresses
|
|
38
|
+
*
|
|
39
|
+
* Verified 2026-08-09 rather than assumed. Two hosts serve this token
|
|
40
|
+
* endpoint — the one below and `platform.claude.com` on the same path — and
|
|
41
|
+
* both answer an `authorization_code` grant identically (`400 invalid_grant`
|
|
42
|
+
* for a bogus code, from the same handler). namzu keeps the address its
|
|
43
|
+
* existing refresh path has always used, because there was no behaviour to
|
|
44
|
+
* gain by moving and a live refresh to lose by guessing.
|
|
45
|
+
*
|
|
46
|
+
* The redirect port is fixed and NOT free to change: it is part of what the
|
|
47
|
+
* client identity above is registered with, so a different port is simply not
|
|
48
|
+
* an accepted redirect. That is why a busy port degrades to the paste flow
|
|
49
|
+
* rather than picking another one.
|
|
50
|
+
*/
|
|
51
|
+
export const OAUTH_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
|
|
52
|
+
export const OAUTH_TOKEN_URL = 'https://console.anthropic.com/v1/oauth/token';
|
|
53
|
+
export const AUTHORIZE_URL = 'https://claude.ai/oauth/authorize';
|
|
54
|
+
/** Registered with the client identity above; not ours to choose. */
|
|
55
|
+
export const SUBSCRIPTION_REDIRECT_PORT = 53692;
|
|
56
|
+
export const REDIRECT_URI = `http://localhost:${SUBSCRIPTION_REDIRECT_PORT}/callback`;
|
|
57
|
+
/**
|
|
58
|
+
* Asked for at sign-in.
|
|
59
|
+
*
|
|
60
|
+
* This is WIDER than namzu needs, and that is a knowing compromise rather
|
|
61
|
+
* than an oversight. Least privilege would ask for an identity and the right
|
|
62
|
+
* to run inference, and stop; this set also admits key creation and file
|
|
63
|
+
* upload. It is the set the client identity above is exercised with by the
|
|
64
|
+
* implementations that are known to work, and a narrower request cannot be
|
|
65
|
+
* tested from here — nobody on this side of the flow holds a plan-backed
|
|
66
|
+
* account to try it against. Guessing narrow fails in the worst place: the
|
|
67
|
+
* sign-in succeeds, and inference is refused afterwards with an error about
|
|
68
|
+
* scope that the operator cannot act on.
|
|
69
|
+
*
|
|
70
|
+
* So it is recorded as debt with the measurement that would settle it: sign
|
|
71
|
+
* in with `user:profile user:inference` alone and send one message. If that
|
|
72
|
+
* works, this shrinks to those two.
|
|
73
|
+
*/
|
|
74
|
+
export const OAUTH_SCOPES = 'org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload';
|
|
75
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/integrations/providers/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,sCAAsC,CAAA;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,8CAA8C,CAAA;AAC7E,MAAM,CAAC,MAAM,aAAa,GAAG,mCAAmC,CAAA;AAEhE,qEAAqE;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,CAAA;AAC/C,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,0BAA0B,WAAW,CAAA;AAErF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,YAAY,GACxB,4GAA4G,CAAA"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export { type DetectedProvider, type DetectionSource, type DiscoverOptions, discoverProviders, findDetected, } from './discover.js';
|
|
2
2
|
export { type AgentOAuthCredential, isAnthropicOAuthToken, readAgentKeychainCredential, } from './keychain.js';
|
|
3
|
-
export {
|
|
3
|
+
export { clearStoredSubscriptionCredential, CREDENTIALS_FILE_VERSION, CredentialStoreError, credentialsPath, readStoredSubscriptionCredential, writeStoredSubscriptionCredential, } from './credential-store.js';
|
|
4
|
+
export { OAUTH_SCOPES, REDIRECT_URI } from './identity.js';
|
|
5
|
+
export { type CredentialOrigin, ensureFreshAnthropicToken, type OAuthMetadata, readSubscriptionCredential, refreshAgentOAuthToken, } from './oauth.js';
|
|
6
|
+
export { beginSubscriptionLogin, type LoginOutcome, parsePastedInput, type SubscriptionLogin, type SubscriptionLoginOptions, subscriptionDetectedProvider, } from './subscription-login.js';
|
|
4
7
|
export { type CapabilityDisagreement, chainCapabilityDisagreements, describeAcceptedMismatch, describeCapabilityRefusal, type MemberCapabilities, unresolvedMembers, } from './chain-capabilities.js';
|
|
5
8
|
export { chainPositionName, type Preferences, PREFERENCES_FILE_VERSION, PreferencesError, preferencesPath, primaryProvider, type ProviderChoice, type ReadResult, readPreferences, writePreferences, } from './preferences.js';
|
|
6
|
-
export { ALL_PROVIDER_IDS, PROVIDER_REGISTRY, type ProviderId, type ProviderRegistryEntry, type SdkProviderType, unsupportedProviderMessage, } from './registry.js';
|
|
9
|
+
export { ALL_PROVIDER_IDS, missingCredentialMessage, PROVIDER_REGISTRY, type ProviderId, type ProviderRegistryEntry, type SdkProviderType, unsupportedProviderMessage, } from './registry.js';
|
|
7
10
|
export { ensureRegistered, isRegistered, resolveChainCapabilities } from './register.js';
|
|
8
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EACzB,KAAK,aAAa,EAClB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACN,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EACjB,KAAK,WAAW,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,0BAA0B,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,iCAAiC,EACjC,wBAAwB,EACxB,oBAAoB,EACpB,eAAe,EACf,gCAAgC,EAChC,iCAAiC,GACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EACN,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,KAAK,aAAa,EAClB,0BAA0B,EAC1B,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACN,sBAAsB,EACtB,KAAK,YAAY,EACjB,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,4BAA4B,GAC5B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EACjB,KAAK,WAAW,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,0BAA0B,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export { discoverProviders, findDetected, } from './discover.js';
|
|
2
2
|
export { isAnthropicOAuthToken, readAgentKeychainCredential, } from './keychain.js';
|
|
3
|
-
export {
|
|
3
|
+
export { clearStoredSubscriptionCredential, CREDENTIALS_FILE_VERSION, CredentialStoreError, credentialsPath, readStoredSubscriptionCredential, writeStoredSubscriptionCredential, } from './credential-store.js';
|
|
4
|
+
export { OAUTH_SCOPES, REDIRECT_URI } from './identity.js';
|
|
5
|
+
export { ensureFreshAnthropicToken, readSubscriptionCredential, refreshAgentOAuthToken, } from './oauth.js';
|
|
6
|
+
export { beginSubscriptionLogin, parsePastedInput, subscriptionDetectedProvider, } from './subscription-login.js';
|
|
4
7
|
export { chainCapabilityDisagreements, describeAcceptedMismatch, describeCapabilityRefusal, unresolvedMembers, } from './chain-capabilities.js';
|
|
5
8
|
export { chainPositionName, PREFERENCES_FILE_VERSION, PreferencesError, preferencesPath, primaryProvider, readPreferences, writePreferences, } from './preferences.js';
|
|
6
|
-
export { ALL_PROVIDER_IDS, PROVIDER_REGISTRY, unsupportedProviderMessage, } from './registry.js';
|
|
9
|
+
export { ALL_PROVIDER_IDS, missingCredentialMessage, PROVIDER_REGISTRY, unsupportedProviderMessage, } from './registry.js';
|
|
7
10
|
export { ensureRegistered, isRegistered, resolveChainCapabilities } from './register.js';
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAEN,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,yBAAyB,EAEzB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EAEN,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EAEzB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EAEjB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAGf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EAIjB,0BAA0B,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,iBAAiB,EACjB,YAAY,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAEN,qBAAqB,EACrB,2BAA2B,GAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EACN,iCAAiC,EACjC,wBAAwB,EACxB,oBAAoB,EACpB,eAAe,EACf,gCAAgC,EAChC,iCAAiC,GACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EAEN,yBAAyB,EAEzB,0BAA0B,EAC1B,sBAAsB,GACtB,MAAM,YAAY,CAAA;AACnB,OAAO,EACN,sBAAsB,EAEtB,gBAAgB,EAGhB,4BAA4B,GAC5B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAEN,4BAA4B,EAC5B,wBAAwB,EACxB,yBAAyB,EAEzB,iBAAiB,GACjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACN,iBAAiB,EAEjB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAGf,eAAe,EACf,gBAAgB,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EAIjB,0BAA0B,GAC1B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -1,25 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth token refresh for a
|
|
2
|
+
* OAuth token refresh for a subscription credential.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* A subscription access token is short-lived (~8h). When it lapses the
|
|
5
|
+
* provider answers 401 and the agent stream dies. Refreshing proactively
|
|
6
|
+
* against the token endpoint, using the long-lived refresh token, renews a
|
|
7
|
+
* stale token before the session starts instead of surfacing it as an
|
|
8
|
+
* authentication error.
|
|
9
9
|
*
|
|
10
10
|
* Non-throwing: any failure (no refresh token, network down, endpoint error)
|
|
11
11
|
* returns the existing token unchanged — at worst the caller hits the same
|
|
12
12
|
* 401 it would have hit anyway, never a crash.
|
|
13
|
+
*
|
|
14
|
+
* ## Where a refreshed token is written back
|
|
15
|
+
*
|
|
16
|
+
* There are two places a subscription credential can live and they are not
|
|
17
|
+
* interchangeable, so `origin` says which one this credential came from and
|
|
18
|
+
* the refreshed value goes back to the same place:
|
|
19
|
+
*
|
|
20
|
+
* - `'stored'` — namzu's own store, written by the login flow, present on
|
|
21
|
+
* every platform.
|
|
22
|
+
* - `'keychain'` — a co-installed tool's macOS entry, which namzu reads but
|
|
23
|
+
* does not own.
|
|
24
|
+
*
|
|
25
|
+
* `origin` is optional and defaults to `'keychain'` because that is the only
|
|
26
|
+
* source that existed when this file was written, and a caller compiled
|
|
27
|
+
* against the old shape must keep behaving as it did. Every namzu-owned
|
|
28
|
+
* caller passes it explicitly; a credential that came from the login flow and
|
|
29
|
+
* was written back to the Keychain would be a no-op off macOS, leaving the
|
|
30
|
+
* real store holding a token that is refreshed again on every launch.
|
|
13
31
|
*/
|
|
14
32
|
import { type AgentOAuthCredential } from './keychain.js';
|
|
33
|
+
/**
|
|
34
|
+
* Re-read the current credential from the store it lives in.
|
|
35
|
+
*
|
|
36
|
+
* The session layer calls this between turns because another process may
|
|
37
|
+
* have rotated the token since launch. Pairing it with `origin` is what stops
|
|
38
|
+
* a long-running session reading one store and writing the other.
|
|
39
|
+
*/
|
|
40
|
+
export declare function readSubscriptionCredential(origin: CredentialOrigin): AgentOAuthCredential | null;
|
|
41
|
+
/** Which store a subscription credential came from, and goes back to. */
|
|
42
|
+
export type CredentialOrigin = 'stored' | 'keychain';
|
|
15
43
|
export interface OAuthMetadata {
|
|
16
44
|
readonly refreshToken?: string;
|
|
17
45
|
readonly expiresAt?: number;
|
|
46
|
+
/** Defaults to `'keychain'` — see the note at the top of this file. */
|
|
47
|
+
readonly origin?: CredentialOrigin;
|
|
18
48
|
}
|
|
19
49
|
/**
|
|
20
50
|
* Return a non-expired access token, refreshing first if the current one is
|
|
21
51
|
* lapsed/about-to-lapse and a refresh token is available. On a successful
|
|
22
|
-
* refresh the new credential is persisted back to
|
|
52
|
+
* refresh the new credential is persisted back to its own store (best-effort).
|
|
23
53
|
*/
|
|
24
54
|
export declare function ensureFreshAnthropicToken(accessToken: string, oauth: OAuthMetadata): Promise<string>;
|
|
25
55
|
/** Exchange a refresh token for a new credential, or `null` on any failure. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/oauth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAOH,OAAO,EACN,KAAK,oBAAoB,EAGzB,MAAM,eAAe,CAAA;AAKtB;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,IAAI,CAEhG;AAED,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,CAAA;AAEpD,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAClC;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC9C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,GAClB,OAAO,CAAC,MAAM,CAAC,CASjB;AAuBD,+EAA+E;AAC/E,wBAAsB,sBAAsB,CAC3C,YAAY,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA2BtC"}
|
|
@@ -1,29 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OAuth token refresh for a
|
|
2
|
+
* OAuth token refresh for a subscription credential.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* A subscription access token is short-lived (~8h). When it lapses the
|
|
5
|
+
* provider answers 401 and the agent stream dies. Refreshing proactively
|
|
6
|
+
* against the token endpoint, using the long-lived refresh token, renews a
|
|
7
|
+
* stale token before the session starts instead of surfacing it as an
|
|
8
|
+
* authentication error.
|
|
9
9
|
*
|
|
10
10
|
* Non-throwing: any failure (no refresh token, network down, endpoint error)
|
|
11
11
|
* returns the existing token unchanged — at worst the caller hits the same
|
|
12
12
|
* 401 it would have hit anyway, never a crash.
|
|
13
|
+
*
|
|
14
|
+
* ## Where a refreshed token is written back
|
|
15
|
+
*
|
|
16
|
+
* There are two places a subscription credential can live and they are not
|
|
17
|
+
* interchangeable, so `origin` says which one this credential came from and
|
|
18
|
+
* the refreshed value goes back to the same place:
|
|
19
|
+
*
|
|
20
|
+
* - `'stored'` — namzu's own store, written by the login flow, present on
|
|
21
|
+
* every platform.
|
|
22
|
+
* - `'keychain'` — a co-installed tool's macOS entry, which namzu reads but
|
|
23
|
+
* does not own.
|
|
24
|
+
*
|
|
25
|
+
* `origin` is optional and defaults to `'keychain'` because that is the only
|
|
26
|
+
* source that existed when this file was written, and a caller compiled
|
|
27
|
+
* against the old shape must keep behaving as it did. Every namzu-owned
|
|
28
|
+
* caller passes it explicitly; a credential that came from the login flow and
|
|
29
|
+
* was written back to the Keychain would be a no-op off macOS, leaving the
|
|
30
|
+
* real store holding a token that is refreshed again on every launch.
|
|
13
31
|
*/
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* against. Addresses, verbatim — the refresh only succeeds against these.
|
|
18
|
-
*/
|
|
19
|
-
const CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
|
|
20
|
-
const TOKEN_URL = 'https://console.anthropic.com/v1/oauth/token';
|
|
32
|
+
import { readStoredSubscriptionCredential, writeStoredSubscriptionCredential, } from './credential-store.js';
|
|
33
|
+
import { OAUTH_CLIENT_ID, OAUTH_TOKEN_URL } from './identity.js';
|
|
34
|
+
import { readAgentKeychainCredential, writeAgentKeychainCredential, } from './keychain.js';
|
|
21
35
|
/** Refresh a few seconds early so an about-to-expire token isn't used. */
|
|
22
36
|
const EXPIRY_SKEW_MS = 60_000;
|
|
37
|
+
/**
|
|
38
|
+
* Re-read the current credential from the store it lives in.
|
|
39
|
+
*
|
|
40
|
+
* The session layer calls this between turns because another process may
|
|
41
|
+
* have rotated the token since launch. Pairing it with `origin` is what stops
|
|
42
|
+
* a long-running session reading one store and writing the other.
|
|
43
|
+
*/
|
|
44
|
+
export function readSubscriptionCredential(origin) {
|
|
45
|
+
return origin === 'stored' ? readStoredSubscriptionCredential() : readAgentKeychainCredential();
|
|
46
|
+
}
|
|
23
47
|
/**
|
|
24
48
|
* Return a non-expired access token, refreshing first if the current one is
|
|
25
49
|
* lapsed/about-to-lapse and a refresh token is available. On a successful
|
|
26
|
-
* refresh the new credential is persisted back to
|
|
50
|
+
* refresh the new credential is persisted back to its own store (best-effort).
|
|
27
51
|
*/
|
|
28
52
|
export async function ensureFreshAnthropicToken(accessToken, oauth) {
|
|
29
53
|
const fresh = oauth.expiresAt === undefined || oauth.expiresAt - Date.now() > EXPIRY_SKEW_MS;
|
|
@@ -34,19 +58,40 @@ export async function ensureFreshAnthropicToken(accessToken, oauth) {
|
|
|
34
58
|
const refreshed = await refreshAgentOAuthToken(oauth.refreshToken);
|
|
35
59
|
if (!refreshed)
|
|
36
60
|
return accessToken;
|
|
37
|
-
|
|
61
|
+
persistRefreshed(refreshed, oauth.origin ?? 'keychain');
|
|
38
62
|
return refreshed.accessToken;
|
|
39
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Write a refreshed credential back to the store it came from.
|
|
66
|
+
*
|
|
67
|
+
* Best-effort in both arms, and for the same reason the refresh itself is:
|
|
68
|
+
* the token is already in hand and usable for this session, so a store that
|
|
69
|
+
* will not take it costs a re-refresh next launch, not the session.
|
|
70
|
+
*/
|
|
71
|
+
function persistRefreshed(cred, origin) {
|
|
72
|
+
if (origin === 'keychain') {
|
|
73
|
+
writeAgentKeychainCredential(cred);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
writeStoredSubscriptionCredential(cred);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// The store refused to prove the file private and therefore wrote
|
|
81
|
+
// nothing. Deliberately silent: the message would be about a file, on
|
|
82
|
+
// a path the operator did not ask about, in the middle of a turn.
|
|
83
|
+
}
|
|
84
|
+
}
|
|
40
85
|
/** Exchange a refresh token for a new credential, or `null` on any failure. */
|
|
41
86
|
export async function refreshAgentOAuthToken(refreshToken) {
|
|
42
87
|
try {
|
|
43
|
-
const res = await fetch(
|
|
88
|
+
const res = await fetch(OAUTH_TOKEN_URL, {
|
|
44
89
|
method: 'POST',
|
|
45
90
|
headers: { 'content-type': 'application/json' },
|
|
46
91
|
body: JSON.stringify({
|
|
47
92
|
grant_type: 'refresh_token',
|
|
48
93
|
refresh_token: refreshToken,
|
|
49
|
-
client_id:
|
|
94
|
+
client_id: OAUTH_CLIENT_ID,
|
|
50
95
|
}),
|
|
51
96
|
});
|
|
52
97
|
if (!res.ok)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/integrations/providers/oauth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/integrations/providers/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -75,4 +75,20 @@ export declare const ALL_PROVIDER_IDS: readonly ProviderId[];
|
|
|
75
75
|
* depend on it yet sends them to the wrong place with the wrong bug report.
|
|
76
76
|
*/
|
|
77
77
|
export declare function unsupportedProviderMessage(id: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* The sentence an operator reads when their SAVED provider needs a credential
|
|
80
|
+
* and this machine has none.
|
|
81
|
+
*
|
|
82
|
+
* Deliberately different from the one `createAgentSession` prints for the same
|
|
83
|
+
* fact, and the difference is the whole point. That one is read by a headless
|
|
84
|
+
* run, where the answers are an environment variable or `--provider`. This one
|
|
85
|
+
* is printed directly above the picker, so it names what the picker offers:
|
|
86
|
+
* enter one now, or choose something else. Advice that matches the screen it is
|
|
87
|
+
* printed on is the property the unbuildable-primary refusal already has and
|
|
88
|
+
* this case did not — see `docs/conventions/read-the-neighbour.md`.
|
|
89
|
+
*
|
|
90
|
+
* The environment variables are still named. They are how the credential
|
|
91
|
+
* becomes durable, and the entry screen holds one only for the session.
|
|
92
|
+
*/
|
|
93
|
+
export declare function missingCredentialMessage(entry: ProviderRegistryEntry): string;
|
|
78
94
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GACnB,WAAW,GACX,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,SAAS,GACT,MAAM,CAAA;AAET,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG,UAAU,CAAA;AAExC,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,mEAAmE;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,CAAC,CA8EjF,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,UAAU,EAQvC,CAAA;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAO7D"}
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GACnB,WAAW,GACX,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,SAAS,GACT,MAAM,CAAA;AAET,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG,UAAU,CAAA;AAExC,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,mEAAmE;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,CAAC,CA8EjF,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,UAAU,EAQvC,CAAA;AAEX;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAI7E"}
|
|
@@ -109,4 +109,23 @@ export function unsupportedProviderMessage(id) {
|
|
|
109
109
|
const usable = ALL_PROVIDER_IDS.filter((other) => PROVIDER_REGISTRY[other].constructible).join(', ');
|
|
110
110
|
return `${label} ("${id}") is not available in this build of namzu — it has no driver bundled, so no session can use it. Pick one of: ${usable}. Following it is tracked in cogitave/namzu#257.`;
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* The sentence an operator reads when their SAVED provider needs a credential
|
|
114
|
+
* and this machine has none.
|
|
115
|
+
*
|
|
116
|
+
* Deliberately different from the one `createAgentSession` prints for the same
|
|
117
|
+
* fact, and the difference is the whole point. That one is read by a headless
|
|
118
|
+
* run, where the answers are an environment variable or `--provider`. This one
|
|
119
|
+
* is printed directly above the picker, so it names what the picker offers:
|
|
120
|
+
* enter one now, or choose something else. Advice that matches the screen it is
|
|
121
|
+
* printed on is the property the unbuildable-primary refusal already has and
|
|
122
|
+
* this case did not — see `docs/conventions/read-the-neighbour.md`.
|
|
123
|
+
*
|
|
124
|
+
* The environment variables are still named. They are how the credential
|
|
125
|
+
* becomes durable, and the entry screen holds one only for the session.
|
|
126
|
+
*/
|
|
127
|
+
export function missingCredentialMessage(entry) {
|
|
128
|
+
const looked = entry.envVars.length > 0 ? ` namzu looked for ${entry.envVars.join(', ')} and found none.` : '';
|
|
129
|
+
return `No credential found for ${entry.label}, your saved provider.${looked} Enter one below with "k", or choose a different provider.`;
|
|
130
|
+
}
|
|
112
131
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmEH,MAAM,CAAC,MAAM,iBAAiB,GAAwD,MAAM,CAAC,MAAM,CAClG;IACC,SAAS,EAAE;QACV,EAAE,EAAE,WAAW;QACf,KAAK,EAAE,oBAAoB;QAC3B,sDAAsD;QACtD,qEAAqE;QACrE,8BAA8B;QAC9B,OAAO,EAAE,CAAC,mBAAmB,EAAE,iBAAiB,EAAE,yBAAyB,CAAC;QAC5E,YAAY,EAAE,eAAe;QAC7B,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACnB;IACD,MAAM,EAAE;QACP,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,CAAC,gBAAgB,CAAC;QAC3B,YAAY,EAAE,QAAQ;QACtB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACnB;IACD,UAAU,EAAE;QACX,EAAE,EAAE,YAAY;QAChB,KAAK,EAAE,YAAY;QACnB,OAAO,EAAE,CAAC,oBAAoB,CAAC;QAC/B,cAAc,EAAE,8BAA8B;QAC9C,YAAY,EAAE,yBAAyB;QACvC,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACnB;IACD,MAAM,EAAE;QACP,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,gBAAgB;QACvB,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,wBAAwB;QACxC,QAAQ,EAAE,iCAAiC;QAC3C,YAAY,EAAE,UAAU;QACxB,cAAc,EAAE,KAAK;QACrB,aAAa,EAAE,IAAI;KACnB;IACD,QAAQ,EAAE;QACT,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,mBAAmB;QAC1B,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,0BAA0B;QAC1C,QAAQ,EAAE,iCAAiC;QAC3C,YAAY,EAAE,MAAM;QACpB,cAAc,EAAE,KAAK;QACrB,aAAa,EAAE,KAAK;KACpB;IACD,OAAO,EAAE;QACR,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,CAAC,mBAAmB,CAAC,EAAE,wCAAwC;QACxE,oEAAoE;QACpE,gEAAgE;QAChE,iEAAiE;QACjE,kEAAkE;QAClE,mEAAmE;QACnE,mEAAmE;QACnE,8DAA8D;QAC9D,oEAAoE;QACpE,uDAAuD;QACvD,YAAY,EAAE,gCAAgC;QAC9C,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACpB;IACD,IAAI,EAAE;QACL,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,iCAAiC;QACxC,oEAAoE;QACpE,kDAAkD;QAClD,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,QAAQ;QACtB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACpB;CACD,CACD,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACpE,WAAW;IACX,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,UAAU;IACV,SAAS;IACT,MAAM;CACG,CAAC,CAAA;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,EAAU;IACpD,MAAM,KAAK,GAAI,iBAAuE,CAAC,EAAE,CAAC,CAAA;IAC1F,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,EAAE,CAAA;IAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAC7F,IAAI,CACJ,CAAA;IACD,OAAO,GAAG,KAAK,MAAM,EAAE,iHAAiH,MAAM,kDAAkD,CAAA;AACjM,CAAC"}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"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"}
|