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 CHANGED
@@ -1,11 +1,12 @@
1
1
  # Pi Anthropic OAuth
2
2
 
3
- [![npm](https://img.shields.io/npm/v/pi-anthropic-oauth?style=flat-square&logo=npm&logoColor=white&label=npm&color=7c3aed)](https://www.npmjs.com/package/pi-anthropic-oauth) [![node](https://img.shields.io/badge/node-%3E%3D18-7c3aed?style=flat-square&logo=nodedotjs&logoColor=white)](https://nodejs.org)
3
+ [![npm](https://img.shields.io/npm/v/pi-anthropic-oauth?style=flat-square&logo=npm&logoColor=white&label=npm&color=7c3aed)](https://www.npmjs.com/package/pi-anthropic-oauth) [![downloads](https://img.shields.io/npm/dm/pi-anthropic-oauth?style=flat-square&logo=npm&logoColor=white&label=downloads&color=7c3aed)](https://www.npmjs.com/package/pi-anthropic-oauth) [![node](https://img.shields.io/badge/node-%3E%3D18-7c3aed?style=flat-square&logo=nodedotjs&logoColor=white)](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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-anthropic-oauth",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "Claude Pro/Max OAuth extension for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
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 authorization in the browser. Pi will try to capture the callback automatically.",
55
+ "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.",
53
56
  });
54
57
 
55
- authInput = await localAuthorization.waitForCallback();
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(0, "127.0.0.1", () => {
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:${address.port}/callback`,
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: 200000,
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: 200000,
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 ? undefined : apiKey,
109
- authToken: isOAuth ? apiKey : undefined,
108
+ apiKey: isOAuth ? null : apiKey,
109
+ authToken: isOAuth ? apiKey : null,
110
110
  defaultHeaders,
111
111
  dangerouslyAllowBrowser: true,
112
112
  });