pi-anthropic-oauth 0.1.3 → 0.1.6
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/README.md +2 -1
- package/package.json +1 -1
- package/src/auth.ts +40 -11
- package/src/index.ts +7 -5
- package/src/stream.ts +2 -2
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Pi Anthropic OAuth
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/pi-anthropic-oauth) [](https://nodejs.org)
|
|
3
|
+
[](https://www.npmjs.com/package/pi-anthropic-oauth) [](https://www.npmjs.com/package/pi-anthropic-oauth) [](https://nodejs.org)
|
|
4
4
|
|
|
5
5
|
Claude Pro/Max OAuth extension for Pi.
|
|
6
6
|
|
|
7
7
|
> [!WARNING]
|
|
8
8
|
> Use this at your own risk. This may go against Anthropic's terms.
|
|
9
|
+
> I do not recommend using this with gsd2 or any extensions that will cause heavy token usage.
|
|
9
10
|
|
|
10
11
|
## Install
|
|
11
12
|
|
package/package.json
CHANGED
package/src/auth.ts
CHANGED
|
@@ -17,6 +17,8 @@ const SCOPES = [
|
|
|
17
17
|
"user:file_upload",
|
|
18
18
|
].join(" ");
|
|
19
19
|
const USER_AGENT = "claude-code/2.1.97";
|
|
20
|
+
const CALLBACK_PORT = 53692;
|
|
21
|
+
const CALLBACK_HOST = "127.0.0.1";
|
|
20
22
|
const LOCAL_CALLBACK_TIMEOUT = 5 * 60 * 1000;
|
|
21
23
|
const MAX_TOKEN_RETRIES = 2;
|
|
22
24
|
const INITIAL_RETRY_DELAY_MS = 5000;
|
|
@@ -27,6 +29,7 @@ type ParsedAuthInput = { code: string; state: string };
|
|
|
27
29
|
type LocalAuthorization = {
|
|
28
30
|
redirectUri: string;
|
|
29
31
|
waitForCallback: () => Promise<string | null>;
|
|
32
|
+
cancel: () => void;
|
|
30
33
|
};
|
|
31
34
|
|
|
32
35
|
export function isClaudeOAuthAccessToken(apiKey: string): boolean {
|
|
@@ -49,12 +52,43 @@ export async function loginAnthropic(
|
|
|
49
52
|
callbacks.onAuth({
|
|
50
53
|
url: makeAuthorizeUrl(challenge, state, redirectUri),
|
|
51
54
|
instructions:
|
|
52
|
-
"Complete
|
|
55
|
+
"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.",
|
|
53
56
|
});
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
if (callbacks.onManualCodeInput) {
|
|
59
|
+
let manualInput: string | undefined;
|
|
60
|
+
let manualError: Error | undefined;
|
|
61
|
+
const manualPromise = callbacks
|
|
62
|
+
.onManualCodeInput()
|
|
63
|
+
.then((input) => {
|
|
64
|
+
manualInput = input;
|
|
65
|
+
localAuthorization.cancel();
|
|
66
|
+
})
|
|
67
|
+
.catch((err) => {
|
|
68
|
+
manualError =
|
|
69
|
+
err instanceof Error ? err : new Error(String(err));
|
|
70
|
+
localAuthorization.cancel();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const callbackResult = await localAuthorization.waitForCallback();
|
|
74
|
+
|
|
75
|
+
if (manualError) throw manualError;
|
|
76
|
+
|
|
77
|
+
if (callbackResult) {
|
|
78
|
+
authInput = callbackResult;
|
|
79
|
+
} else if (manualInput) {
|
|
80
|
+
authInput = manualInput;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!authInput) {
|
|
84
|
+
await manualPromise;
|
|
85
|
+
if (manualError) throw manualError;
|
|
86
|
+
if (manualInput) authInput = manualInput;
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
authInput = await localAuthorization.waitForCallback();
|
|
90
|
+
}
|
|
56
91
|
} catch {
|
|
57
|
-
// Fall back to manual code entry when localhost callback setup fails.
|
|
58
92
|
}
|
|
59
93
|
|
|
60
94
|
if (!authInput) {
|
|
@@ -270,17 +304,12 @@ async function createLocalAuthorization(
|
|
|
270
304
|
|
|
271
305
|
server.once("error", reject);
|
|
272
306
|
|
|
273
|
-
server.listen(
|
|
274
|
-
const address = server.address();
|
|
275
|
-
if (!address || typeof address === "string") {
|
|
276
|
-
reject(new Error("Failed to allocate localhost callback port"));
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
|
|
307
|
+
server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
|
|
280
308
|
timer = setTimeout(() => finish(null), LOCAL_CALLBACK_TIMEOUT);
|
|
281
309
|
resolve({
|
|
282
|
-
redirectUri: `http://localhost:${
|
|
310
|
+
redirectUri: `http://localhost:${CALLBACK_PORT}/callback`,
|
|
283
311
|
waitForCallback: () => wait,
|
|
312
|
+
cancel: () => finish(null),
|
|
284
313
|
});
|
|
285
314
|
});
|
|
286
315
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, symlinkSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
|
+
import type { ExtensionAPI, ProviderConfig } from "@mariozechner/pi-coding-agent";
|
|
5
|
+
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
|
5
6
|
import { loginAnthropic, refreshAnthropicToken } from "./auth.js";
|
|
6
7
|
import { streamAnthropicOAuth } from "./stream.js";
|
|
7
8
|
|
|
@@ -12,7 +13,7 @@ const MODELS = [
|
|
|
12
13
|
reasoning: true,
|
|
13
14
|
input: ["text", "image"] as ("text" | "image")[],
|
|
14
15
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
15
|
-
contextWindow:
|
|
16
|
+
contextWindow: 1000000,
|
|
16
17
|
maxTokens: 128000,
|
|
17
18
|
},
|
|
18
19
|
{
|
|
@@ -21,7 +22,7 @@ const MODELS = [
|
|
|
21
22
|
reasoning: true,
|
|
22
23
|
input: ["text", "image"] as ("text" | "image")[],
|
|
23
24
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
24
|
-
contextWindow:
|
|
25
|
+
contextWindow: 1000000,
|
|
25
26
|
maxTokens: 64000,
|
|
26
27
|
},
|
|
27
28
|
{
|
|
@@ -54,10 +55,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
54
55
|
models: [...MODELS],
|
|
55
56
|
oauth: {
|
|
56
57
|
name: "Claude Pro/Max",
|
|
58
|
+
usesCallbackServer: true,
|
|
57
59
|
login: loginAnthropic,
|
|
58
60
|
refreshToken: refreshAnthropicToken,
|
|
59
|
-
getApiKey: (credentials) => credentials.access,
|
|
60
|
-
},
|
|
61
|
+
getApiKey: (credentials: OAuthCredentials) => credentials.access,
|
|
62
|
+
} as unknown as ProviderConfig["oauth"],
|
|
61
63
|
streamSimple: streamAnthropicOAuth,
|
|
62
64
|
});
|
|
63
65
|
}
|
package/src/stream.ts
CHANGED
|
@@ -105,8 +105,8 @@ export function streamAnthropicOAuth(
|
|
|
105
105
|
|
|
106
106
|
const client = new Anthropic({
|
|
107
107
|
baseURL: model.baseUrl,
|
|
108
|
-
apiKey: isOAuth ?
|
|
109
|
-
authToken: isOAuth ? apiKey :
|
|
108
|
+
apiKey: isOAuth ? null : apiKey,
|
|
109
|
+
authToken: isOAuth ? apiKey : null,
|
|
110
110
|
defaultHeaders,
|
|
111
111
|
dangerouslyAllowBrowser: true,
|
|
112
112
|
});
|