pi-anthropic-oauth 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-anthropic-oauth",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
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
 
@@ -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
  }