@mariozechner/pi-ai 0.27.8 → 0.28.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.
Files changed (54) hide show
  1. package/README.md +39 -80
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +145 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/models.generated.d.ts +8 -8
  7. package/dist/models.generated.d.ts.map +1 -1
  8. package/dist/models.generated.js +46 -46
  9. package/dist/models.generated.js.map +1 -1
  10. package/dist/providers/anthropic.d.ts.map +1 -1
  11. package/dist/providers/anthropic.js +2 -2
  12. package/dist/providers/anthropic.js.map +1 -1
  13. package/dist/providers/google.d.ts.map +1 -1
  14. package/dist/providers/google.js +3 -7
  15. package/dist/providers/google.js.map +1 -1
  16. package/dist/providers/openai-completions.d.ts.map +1 -1
  17. package/dist/providers/openai-completions.js +3 -1
  18. package/dist/providers/openai-completions.js.map +1 -1
  19. package/dist/providers/openai-responses.d.ts.map +1 -1
  20. package/dist/providers/openai-responses.js +3 -1
  21. package/dist/providers/openai-responses.js.map +1 -1
  22. package/dist/stream.d.ts +4 -16
  23. package/dist/stream.d.ts.map +1 -1
  24. package/dist/stream.js +3 -27
  25. package/dist/stream.js.map +1 -1
  26. package/dist/utils/oauth/anthropic.d.ts +2 -2
  27. package/dist/utils/oauth/anthropic.d.ts.map +1 -1
  28. package/dist/utils/oauth/anthropic.js +1 -5
  29. package/dist/utils/oauth/anthropic.js.map +1 -1
  30. package/dist/utils/oauth/github-copilot.d.ts +1 -17
  31. package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  32. package/dist/utils/oauth/github-copilot.js +3 -7
  33. package/dist/utils/oauth/github-copilot.js.map +1 -1
  34. package/dist/utils/oauth/google-antigravity.d.ts +2 -6
  35. package/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  36. package/dist/utils/oauth/google-antigravity.js +0 -4
  37. package/dist/utils/oauth/google-antigravity.js.map +1 -1
  38. package/dist/utils/oauth/google-gemini-cli.d.ts +2 -6
  39. package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  40. package/dist/utils/oauth/google-gemini-cli.js +0 -4
  41. package/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  42. package/dist/utils/oauth/index.d.ts +11 -26
  43. package/dist/utils/oauth/index.d.ts.map +1 -1
  44. package/dist/utils/oauth/index.js +16 -48
  45. package/dist/utils/oauth/index.js.map +1 -1
  46. package/dist/utils/oauth/types.d.ts +24 -0
  47. package/dist/utils/oauth/types.d.ts.map +1 -0
  48. package/dist/utils/oauth/types.js +2 -0
  49. package/dist/utils/oauth/types.js.map +1 -0
  50. package/package.json +4 -2
  51. package/dist/utils/oauth/storage.d.ts +0 -81
  52. package/dist/utils/oauth/storage.d.ts.map +0 -1
  53. package/dist/utils/oauth/storage.js +0 -119
  54. package/dist/utils/oauth/storage.js.map +0 -1
package/README.md CHANGED
@@ -1100,59 +1100,51 @@ const response = await complete(model, context, {
1100
1100
  });
1101
1101
  ```
1102
1102
 
1103
- ### Programmatic API Key Management
1104
-
1105
- You can also set and get API keys programmatically:
1103
+ ### Checking Environment Variables
1106
1104
 
1107
1105
  ```typescript
1108
- import { setApiKey, getApiKey } from '@mariozechner/pi-ai';
1109
-
1110
- // Set API key for a provider
1111
- setApiKey('openai', 'sk-...');
1112
- setApiKey('anthropic', 'sk-ant-...');
1106
+ import { getEnvApiKey } from '@mariozechner/pi-ai';
1113
1107
 
1114
- // Get API key for a provider (checks both programmatic and env vars)
1115
- const key = getApiKey('openai');
1108
+ // Check if an API key is set in environment variables
1109
+ const key = getEnvApiKey('openai'); // checks OPENAI_API_KEY
1116
1110
  ```
1117
1111
 
1118
1112
  ## OAuth Providers
1119
1113
 
1120
- Several providers require OAuth authentication instead of static API keys. This library provides login flows, automatic token refresh, and credential storage for:
1114
+ Several providers require OAuth authentication instead of static API keys:
1121
1115
 
1122
1116
  - **Anthropic** (Claude Pro/Max subscription)
1123
1117
  - **GitHub Copilot** (Copilot subscription)
1124
1118
  - **Google Gemini CLI** (Free Gemini 2.0/2.5 via Google Cloud Code Assist)
1125
1119
  - **Antigravity** (Free Gemini 3, Claude, GPT-OSS via Google Cloud)
1126
1120
 
1127
- Credentials are stored in `~/.pi/agent/oauth.json` by default (with `chmod 600` permissions). Use `setOAuthStorage()` to configure a custom storage backend for different locations or environments (the coding-agent does this to respect its configurable config directory).
1121
+ ### CLI Login
1128
1122
 
1129
- ### Using with @mariozechner/pi-coding-agent
1123
+ The quickest way to authenticate:
1130
1124
 
1131
- Use `/login` and select a provider to authenticate. Tokens are automatically refreshed when expired.
1125
+ ```bash
1126
+ npx @mariozechner/pi-ai login # interactive provider selection
1127
+ npx @mariozechner/pi-ai login anthropic # login to specific provider
1128
+ npx @mariozechner/pi-ai list # list available providers
1129
+ ```
1130
+
1131
+ Credentials are saved to `auth.json` in the current directory.
1132
1132
 
1133
1133
  ### Programmatic OAuth
1134
1134
 
1135
- For standalone usage, the library exposes low-level OAuth functions:
1135
+ The library provides login and token refresh functions. Credential storage is the caller's responsibility.
1136
1136
 
1137
1137
  ```typescript
1138
1138
  import {
1139
- // Login functions (each implements provider-specific OAuth flow)
1139
+ // Login functions (return credentials, do not store)
1140
1140
  loginAnthropic,
1141
1141
  loginGitHubCopilot,
1142
1142
  loginGeminiCli,
1143
1143
  loginAntigravity,
1144
1144
 
1145
1145
  // Token management
1146
- refreshToken, // Refresh token for any provider
1147
- getOAuthApiKey, // Get API key (auto-refreshes if expired)
1148
-
1149
- // Credential storage
1150
- loadOAuthCredentials,
1151
- saveOAuthCredentials,
1152
- removeOAuthCredentials,
1153
- hasOAuthCredentials,
1154
- listOAuthProviders,
1155
- getOAuthPath,
1146
+ refreshOAuthToken, // (provider, credentials) => new credentials
1147
+ getOAuthApiKey, // (provider, credentialsMap) => { newCredentials, apiKey } | null
1156
1148
 
1157
1149
  // Types
1158
1150
  type OAuthProvider, // 'anthropic' | 'github-copilot' | 'google-gemini-cli' | 'google-antigravity'
@@ -1162,90 +1154,57 @@ import {
1162
1154
 
1163
1155
  ### Login Flow Example
1164
1156
 
1165
- Each provider has a different OAuth flow. Here's an example with GitHub Copilot:
1166
-
1167
1157
  ```typescript
1168
- import { loginGitHubCopilot, saveOAuthCredentials } from '@mariozechner/pi-ai';
1158
+ import { loginGitHubCopilot } from '@mariozechner/pi-ai';
1159
+ import { writeFileSync } from 'fs';
1169
1160
 
1170
1161
  const credentials = await loginGitHubCopilot({
1171
1162
  onAuth: (url, instructions) => {
1172
- // Display the URL and instructions to the user
1173
1163
  console.log(`Open: ${url}`);
1174
1164
  if (instructions) console.log(instructions);
1175
1165
  },
1176
1166
  onPrompt: async (prompt) => {
1177
- // Prompt user for input (e.g., device code confirmation)
1178
1167
  return await getUserInput(prompt.message);
1179
1168
  },
1180
- onProgress: (message) => {
1181
- // Optional: show progress updates
1182
- console.log(message);
1183
- }
1169
+ onProgress: (message) => console.log(message)
1184
1170
  });
1185
1171
 
1186
- // Save credentials for later use
1187
- saveOAuthCredentials('github-copilot', credentials);
1172
+ // Store credentials yourself
1173
+ const auth = { 'github-copilot': { type: 'oauth', ...credentials } };
1174
+ writeFileSync('auth.json', JSON.stringify(auth, null, 2));
1188
1175
  ```
1189
1176
 
1190
1177
  ### Using OAuth Tokens
1191
1178
 
1192
- Call `getOAuthApiKey()` before **every** `complete()` or `stream()` call. This function checks token expiry and refreshes automatically when needed:
1179
+ Use `getOAuthApiKey()` to get an API key, automatically refreshing if expired:
1193
1180
 
1194
1181
  ```typescript
1195
1182
  import { getModel, complete, getOAuthApiKey } from '@mariozechner/pi-ai';
1183
+ import { readFileSync, writeFileSync } from 'fs';
1196
1184
 
1197
- const model = getModel('github-copilot', 'gpt-4o');
1185
+ // Load your stored credentials
1186
+ const auth = JSON.parse(readFileSync('auth.json', 'utf-8'));
1198
1187
 
1199
- // Always call getOAuthApiKey() right before the API call
1200
- // Do NOT cache the result - tokens expire and need refresh
1201
- const apiKey = await getOAuthApiKey('github-copilot');
1202
- if (!apiKey) {
1203
- throw new Error('Not logged in to GitHub Copilot');
1204
- }
1188
+ // Get API key (refreshes if expired)
1189
+ const result = await getOAuthApiKey('github-copilot', auth);
1190
+ if (!result) throw new Error('Not logged in');
1205
1191
 
1192
+ // Save refreshed credentials
1193
+ auth['github-copilot'] = { type: 'oauth', ...result.newCredentials };
1194
+ writeFileSync('auth.json', JSON.stringify(auth, null, 2));
1195
+
1196
+ // Use the API key
1197
+ const model = getModel('github-copilot', 'gpt-4o');
1206
1198
  const response = await complete(model, {
1207
1199
  messages: [{ role: 'user', content: 'Hello!' }]
1208
- }, { apiKey });
1209
- ```
1210
-
1211
- ### Custom Storage Backend
1212
-
1213
- Override the default storage location with `setOAuthStorage()`:
1214
-
1215
- ```typescript
1216
- import { setOAuthStorage, resetOAuthStorage } from '@mariozechner/pi-ai';
1217
- import { readFileSync, writeFileSync } from 'fs';
1218
-
1219
- // Custom file path
1220
- setOAuthStorage({
1221
- load: () => {
1222
- try {
1223
- return JSON.parse(readFileSync('/custom/path/oauth.json', 'utf-8'));
1224
- } catch {
1225
- return {};
1226
- }
1227
- },
1228
- save: (storage) => {
1229
- writeFileSync('/custom/path/oauth.json', JSON.stringify(storage, null, 2));
1230
- }
1231
- });
1232
-
1233
- // In-memory storage (for testing or browser environments)
1234
- let memoryStorage = {};
1235
- setOAuthStorage({
1236
- load: () => memoryStorage,
1237
- save: (storage) => { memoryStorage = storage; }
1238
- });
1239
-
1240
- // Reset to default (~/.pi/agent/oauth.json)
1241
- resetOAuthStorage();
1200
+ }, { apiKey: result.apiKey });
1242
1201
  ```
1243
1202
 
1244
1203
  ### Provider Notes
1245
1204
 
1246
1205
  **GitHub Copilot**: If you get "The requested model is not supported" error, enable the model manually in VS Code: open Copilot Chat, click the model selector, select the model (warning icon), and click "Enable".
1247
1206
 
1248
- **Google Gemini CLI / Antigravity**: These use Google Cloud OAuth. The API key returned by `getOAuthApiKey()` is a JSON string containing both the token and project ID, which the library handles automatically.
1207
+ **Google Gemini CLI / Antigravity**: These use Google Cloud OAuth. The `apiKey` returned by `getOAuthApiKey()` is a JSON string containing both the token and project ID, which the library handles automatically.
1249
1208
 
1250
1209
  ## License
1251
1210
 
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"","sourcesContent":["#!/usr/bin/env node\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { loginAnthropic } from \"./utils/oauth/anthropic.js\";\nimport { loginGitHubCopilot } from \"./utils/oauth/github-copilot.js\";\nimport { loginAntigravity } from \"./utils/oauth/google-antigravity.js\";\nimport { loginGeminiCli } from \"./utils/oauth/google-gemini-cli.js\";\nimport { getOAuthProviders } from \"./utils/oauth/index.js\";\nimport type { OAuthCredentials, OAuthProvider } from \"./utils/oauth/types.js\";\n\nconst AUTH_FILE = \"auth.json\";\nconst PROVIDERS = getOAuthProviders();\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n\treturn new Promise((resolve) => rl.question(question, resolve));\n}\n\nfunction loadAuth(): Record<string, { type: \"oauth\" } & OAuthCredentials> {\n\tif (!existsSync(AUTH_FILE)) return {};\n\ttry {\n\t\treturn JSON.parse(readFileSync(AUTH_FILE, \"utf-8\"));\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction saveAuth(auth: Record<string, { type: \"oauth\" } & OAuthCredentials>): void {\n\twriteFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), \"utf-8\");\n}\n\nasync function login(provider: OAuthProvider): Promise<void> {\n\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\n\tconst promptFn = (msg: string) => prompt(rl, `${msg} `);\n\n\ttry {\n\t\tlet credentials: OAuthCredentials;\n\n\t\tswitch (provider) {\n\t\t\tcase \"anthropic\":\n\t\t\t\tcredentials = await loginAnthropic(\n\t\t\t\t\t(url) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${url}\\n`);\n\t\t\t\t\t},\n\t\t\t\t\tasync () => {\n\t\t\t\t\t\treturn await promptFn(\"Paste the authorization code:\");\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase \"github-copilot\":\n\t\t\t\tcredentials = await loginGitHubCopilot({\n\t\t\t\t\tonAuth: (url, instructions) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${url}`);\n\t\t\t\t\t\tif (instructions) console.log(instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\tonPrompt: async (p) => {\n\t\t\t\t\t\treturn await promptFn(`${p.message}${p.placeholder ? ` (${p.placeholder})` : \"\"}:`);\n\t\t\t\t\t},\n\t\t\t\t\tonProgress: (msg) => console.log(msg),\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase \"google-gemini-cli\":\n\t\t\t\tcredentials = await loginGeminiCli(\n\t\t\t\t\t(info) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${info.url}`);\n\t\t\t\t\t\tif (info.instructions) console.log(info.instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\t(msg) => console.log(msg),\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase \"google-antigravity\":\n\t\t\t\tcredentials = await loginAntigravity(\n\t\t\t\t\t(info) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${info.url}`);\n\t\t\t\t\t\tif (info.instructions) console.log(info.instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\t(msg) => console.log(msg),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst auth = loadAuth();\n\t\tauth[provider] = { type: \"oauth\", ...credentials };\n\t\tsaveAuth(auth);\n\n\t\tconsole.log(`\\nCredentials saved to ${AUTH_FILE}`);\n\t} finally {\n\t\trl.close();\n\t}\n}\n\nasync function main(): Promise<void> {\n\tconst args = process.argv.slice(2);\n\tconst command = args[0];\n\n\tif (!command || command === \"help\" || command === \"--help\" || command === \"-h\") {\n\t\tconsole.log(`Usage: npx @mariozechner/pi-ai <command> [provider]\n\nCommands:\n login [provider] Login to an OAuth provider\n list List available providers\n\nProviders:\n anthropic Anthropic (Claude Pro/Max)\n github-copilot GitHub Copilot\n google-gemini-cli Google Gemini CLI\n google-antigravity Antigravity (Gemini 3, Claude, GPT-OSS)\n\nExamples:\n npx @mariozechner/pi-ai login # interactive provider selection\n npx @mariozechner/pi-ai login anthropic # login to specific provider\n npx @mariozechner/pi-ai list # list providers\n`);\n\t\treturn;\n\t}\n\n\tif (command === \"list\") {\n\t\tconsole.log(\"Available OAuth providers:\\n\");\n\t\tfor (const p of PROVIDERS) {\n\t\t\tconsole.log(` ${p.id.padEnd(20)} ${p.name}`);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (command === \"login\") {\n\t\tlet provider = args[1] as OAuthProvider | undefined;\n\n\t\tif (!provider) {\n\t\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\t\tconsole.log(\"Select a provider:\\n\");\n\t\t\tfor (let i = 0; i < PROVIDERS.length; i++) {\n\t\t\t\tconsole.log(` ${i + 1}. ${PROVIDERS[i].name}`);\n\t\t\t}\n\t\t\tconsole.log();\n\n\t\t\tconst choice = await prompt(rl, \"Enter number (1-4): \");\n\t\t\trl.close();\n\n\t\t\tconst index = parseInt(choice, 10) - 1;\n\t\t\tif (index < 0 || index >= PROVIDERS.length) {\n\t\t\t\tconsole.error(\"Invalid selection\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tprovider = PROVIDERS[index].id;\n\t\t}\n\n\t\tif (!PROVIDERS.some((p) => p.id === provider)) {\n\t\t\tconsole.error(`Unknown provider: ${provider}`);\n\t\t\tconsole.error(`Use 'npx @mariozechner/pi-ai list' to see available providers`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconsole.log(`Logging in to ${provider}...`);\n\t\tawait login(provider);\n\t\treturn;\n\t}\n\n\tconsole.error(`Unknown command: ${command}`);\n\tconsole.error(`Use 'npx @mariozechner/pi-ai --help' for usage`);\n\tprocess.exit(1);\n}\n\nmain().catch((err) => {\n\tconsole.error(\"Error:\", err.message);\n\tprocess.exit(1);\n});\n"]}
package/dist/cli.js ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, writeFileSync } from "fs";
3
+ import { createInterface } from "readline";
4
+ import { loginAnthropic } from "./utils/oauth/anthropic.js";
5
+ import { loginGitHubCopilot } from "./utils/oauth/github-copilot.js";
6
+ import { loginAntigravity } from "./utils/oauth/google-antigravity.js";
7
+ import { loginGeminiCli } from "./utils/oauth/google-gemini-cli.js";
8
+ import { getOAuthProviders } from "./utils/oauth/index.js";
9
+ const AUTH_FILE = "auth.json";
10
+ const PROVIDERS = getOAuthProviders();
11
+ function prompt(rl, question) {
12
+ return new Promise((resolve) => rl.question(question, resolve));
13
+ }
14
+ function loadAuth() {
15
+ if (!existsSync(AUTH_FILE))
16
+ return {};
17
+ try {
18
+ return JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
24
+ function saveAuth(auth) {
25
+ writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), "utf-8");
26
+ }
27
+ async function login(provider) {
28
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
29
+ const promptFn = (msg) => prompt(rl, `${msg} `);
30
+ try {
31
+ let credentials;
32
+ switch (provider) {
33
+ case "anthropic":
34
+ credentials = await loginAnthropic((url) => {
35
+ console.log(`\nOpen this URL in your browser:\n${url}\n`);
36
+ }, async () => {
37
+ return await promptFn("Paste the authorization code:");
38
+ });
39
+ break;
40
+ case "github-copilot":
41
+ credentials = await loginGitHubCopilot({
42
+ onAuth: (url, instructions) => {
43
+ console.log(`\nOpen this URL in your browser:\n${url}`);
44
+ if (instructions)
45
+ console.log(instructions);
46
+ console.log();
47
+ },
48
+ onPrompt: async (p) => {
49
+ return await promptFn(`${p.message}${p.placeholder ? ` (${p.placeholder})` : ""}:`);
50
+ },
51
+ onProgress: (msg) => console.log(msg),
52
+ });
53
+ break;
54
+ case "google-gemini-cli":
55
+ credentials = await loginGeminiCli((info) => {
56
+ console.log(`\nOpen this URL in your browser:\n${info.url}`);
57
+ if (info.instructions)
58
+ console.log(info.instructions);
59
+ console.log();
60
+ }, (msg) => console.log(msg));
61
+ break;
62
+ case "google-antigravity":
63
+ credentials = await loginAntigravity((info) => {
64
+ console.log(`\nOpen this URL in your browser:\n${info.url}`);
65
+ if (info.instructions)
66
+ console.log(info.instructions);
67
+ console.log();
68
+ }, (msg) => console.log(msg));
69
+ break;
70
+ }
71
+ const auth = loadAuth();
72
+ auth[provider] = { type: "oauth", ...credentials };
73
+ saveAuth(auth);
74
+ console.log(`\nCredentials saved to ${AUTH_FILE}`);
75
+ }
76
+ finally {
77
+ rl.close();
78
+ }
79
+ }
80
+ async function main() {
81
+ const args = process.argv.slice(2);
82
+ const command = args[0];
83
+ if (!command || command === "help" || command === "--help" || command === "-h") {
84
+ console.log(`Usage: npx @mariozechner/pi-ai <command> [provider]
85
+
86
+ Commands:
87
+ login [provider] Login to an OAuth provider
88
+ list List available providers
89
+
90
+ Providers:
91
+ anthropic Anthropic (Claude Pro/Max)
92
+ github-copilot GitHub Copilot
93
+ google-gemini-cli Google Gemini CLI
94
+ google-antigravity Antigravity (Gemini 3, Claude, GPT-OSS)
95
+
96
+ Examples:
97
+ npx @mariozechner/pi-ai login # interactive provider selection
98
+ npx @mariozechner/pi-ai login anthropic # login to specific provider
99
+ npx @mariozechner/pi-ai list # list providers
100
+ `);
101
+ return;
102
+ }
103
+ if (command === "list") {
104
+ console.log("Available OAuth providers:\n");
105
+ for (const p of PROVIDERS) {
106
+ console.log(` ${p.id.padEnd(20)} ${p.name}`);
107
+ }
108
+ return;
109
+ }
110
+ if (command === "login") {
111
+ let provider = args[1];
112
+ if (!provider) {
113
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
114
+ console.log("Select a provider:\n");
115
+ for (let i = 0; i < PROVIDERS.length; i++) {
116
+ console.log(` ${i + 1}. ${PROVIDERS[i].name}`);
117
+ }
118
+ console.log();
119
+ const choice = await prompt(rl, "Enter number (1-4): ");
120
+ rl.close();
121
+ const index = parseInt(choice, 10) - 1;
122
+ if (index < 0 || index >= PROVIDERS.length) {
123
+ console.error("Invalid selection");
124
+ process.exit(1);
125
+ }
126
+ provider = PROVIDERS[index].id;
127
+ }
128
+ if (!PROVIDERS.some((p) => p.id === provider)) {
129
+ console.error(`Unknown provider: ${provider}`);
130
+ console.error(`Use 'npx @mariozechner/pi-ai list' to see available providers`);
131
+ process.exit(1);
132
+ }
133
+ console.log(`Logging in to ${provider}...`);
134
+ await login(provider);
135
+ return;
136
+ }
137
+ console.error(`Unknown command: ${command}`);
138
+ console.error(`Use 'npx @mariozechner/pi-ai --help' for usage`);
139
+ process.exit(1);
140
+ }
141
+ main().catch((err) => {
142
+ console.error("Error:", err.message);
143
+ process.exit(1);
144
+ });
145
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { loginAnthropic } from \"./utils/oauth/anthropic.js\";\nimport { loginGitHubCopilot } from \"./utils/oauth/github-copilot.js\";\nimport { loginAntigravity } from \"./utils/oauth/google-antigravity.js\";\nimport { loginGeminiCli } from \"./utils/oauth/google-gemini-cli.js\";\nimport { getOAuthProviders } from \"./utils/oauth/index.js\";\nimport type { OAuthCredentials, OAuthProvider } from \"./utils/oauth/types.js\";\n\nconst AUTH_FILE = \"auth.json\";\nconst PROVIDERS = getOAuthProviders();\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n\treturn new Promise((resolve) => rl.question(question, resolve));\n}\n\nfunction loadAuth(): Record<string, { type: \"oauth\" } & OAuthCredentials> {\n\tif (!existsSync(AUTH_FILE)) return {};\n\ttry {\n\t\treturn JSON.parse(readFileSync(AUTH_FILE, \"utf-8\"));\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction saveAuth(auth: Record<string, { type: \"oauth\" } & OAuthCredentials>): void {\n\twriteFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), \"utf-8\");\n}\n\nasync function login(provider: OAuthProvider): Promise<void> {\n\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\n\tconst promptFn = (msg: string) => prompt(rl, `${msg} `);\n\n\ttry {\n\t\tlet credentials: OAuthCredentials;\n\n\t\tswitch (provider) {\n\t\t\tcase \"anthropic\":\n\t\t\t\tcredentials = await loginAnthropic(\n\t\t\t\t\t(url) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${url}\\n`);\n\t\t\t\t\t},\n\t\t\t\t\tasync () => {\n\t\t\t\t\t\treturn await promptFn(\"Paste the authorization code:\");\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase \"github-copilot\":\n\t\t\t\tcredentials = await loginGitHubCopilot({\n\t\t\t\t\tonAuth: (url, instructions) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${url}`);\n\t\t\t\t\t\tif (instructions) console.log(instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\tonPrompt: async (p) => {\n\t\t\t\t\t\treturn await promptFn(`${p.message}${p.placeholder ? ` (${p.placeholder})` : \"\"}:`);\n\t\t\t\t\t},\n\t\t\t\t\tonProgress: (msg) => console.log(msg),\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase \"google-gemini-cli\":\n\t\t\t\tcredentials = await loginGeminiCli(\n\t\t\t\t\t(info) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${info.url}`);\n\t\t\t\t\t\tif (info.instructions) console.log(info.instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\t(msg) => console.log(msg),\n\t\t\t\t);\n\t\t\t\tbreak;\n\n\t\t\tcase \"google-antigravity\":\n\t\t\t\tcredentials = await loginAntigravity(\n\t\t\t\t\t(info) => {\n\t\t\t\t\t\tconsole.log(`\\nOpen this URL in your browser:\\n${info.url}`);\n\t\t\t\t\t\tif (info.instructions) console.log(info.instructions);\n\t\t\t\t\t\tconsole.log();\n\t\t\t\t\t},\n\t\t\t\t\t(msg) => console.log(msg),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst auth = loadAuth();\n\t\tauth[provider] = { type: \"oauth\", ...credentials };\n\t\tsaveAuth(auth);\n\n\t\tconsole.log(`\\nCredentials saved to ${AUTH_FILE}`);\n\t} finally {\n\t\trl.close();\n\t}\n}\n\nasync function main(): Promise<void> {\n\tconst args = process.argv.slice(2);\n\tconst command = args[0];\n\n\tif (!command || command === \"help\" || command === \"--help\" || command === \"-h\") {\n\t\tconsole.log(`Usage: npx @mariozechner/pi-ai <command> [provider]\n\nCommands:\n login [provider] Login to an OAuth provider\n list List available providers\n\nProviders:\n anthropic Anthropic (Claude Pro/Max)\n github-copilot GitHub Copilot\n google-gemini-cli Google Gemini CLI\n google-antigravity Antigravity (Gemini 3, Claude, GPT-OSS)\n\nExamples:\n npx @mariozechner/pi-ai login # interactive provider selection\n npx @mariozechner/pi-ai login anthropic # login to specific provider\n npx @mariozechner/pi-ai list # list providers\n`);\n\t\treturn;\n\t}\n\n\tif (command === \"list\") {\n\t\tconsole.log(\"Available OAuth providers:\\n\");\n\t\tfor (const p of PROVIDERS) {\n\t\t\tconsole.log(` ${p.id.padEnd(20)} ${p.name}`);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (command === \"login\") {\n\t\tlet provider = args[1] as OAuthProvider | undefined;\n\n\t\tif (!provider) {\n\t\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\t\tconsole.log(\"Select a provider:\\n\");\n\t\t\tfor (let i = 0; i < PROVIDERS.length; i++) {\n\t\t\t\tconsole.log(` ${i + 1}. ${PROVIDERS[i].name}`);\n\t\t\t}\n\t\t\tconsole.log();\n\n\t\t\tconst choice = await prompt(rl, \"Enter number (1-4): \");\n\t\t\trl.close();\n\n\t\t\tconst index = parseInt(choice, 10) - 1;\n\t\t\tif (index < 0 || index >= PROVIDERS.length) {\n\t\t\t\tconsole.error(\"Invalid selection\");\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tprovider = PROVIDERS[index].id;\n\t\t}\n\n\t\tif (!PROVIDERS.some((p) => p.id === provider)) {\n\t\t\tconsole.error(`Unknown provider: ${provider}`);\n\t\t\tconsole.error(`Use 'npx @mariozechner/pi-ai list' to see available providers`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconsole.log(`Logging in to ${provider}...`);\n\t\tawait login(provider);\n\t\treturn;\n\t}\n\n\tconsole.error(`Unknown command: ${command}`);\n\tconsole.error(`Use 'npx @mariozechner/pi-ai --help' for usage`);\n\tprocess.exit(1);\n}\n\nmain().catch((err) => {\n\tconsole.error(\"Error:\", err.message);\n\tprocess.exit(1);\n});\n"]}
@@ -6489,7 +6489,7 @@ export declare const MODELS: {
6489
6489
  contextWindow: number;
6490
6490
  maxTokens: number;
6491
6491
  };
6492
- readonly "meta-llama/llama-3.1-8b-instruct": {
6492
+ readonly "meta-llama/llama-3.1-70b-instruct": {
6493
6493
  id: string;
6494
6494
  name: string;
6495
6495
  api: "openai-completions";
@@ -6506,7 +6506,7 @@ export declare const MODELS: {
6506
6506
  contextWindow: number;
6507
6507
  maxTokens: number;
6508
6508
  };
6509
- readonly "meta-llama/llama-3.1-405b-instruct": {
6509
+ readonly "meta-llama/llama-3.1-8b-instruct": {
6510
6510
  id: string;
6511
6511
  name: string;
6512
6512
  api: "openai-completions";
@@ -6523,7 +6523,7 @@ export declare const MODELS: {
6523
6523
  contextWindow: number;
6524
6524
  maxTokens: number;
6525
6525
  };
6526
- readonly "meta-llama/llama-3.1-70b-instruct": {
6526
+ readonly "meta-llama/llama-3.1-405b-instruct": {
6527
6527
  id: string;
6528
6528
  name: string;
6529
6529
  api: "openai-completions";
@@ -6676,7 +6676,7 @@ export declare const MODELS: {
6676
6676
  contextWindow: number;
6677
6677
  maxTokens: number;
6678
6678
  };
6679
- readonly "openai/gpt-4o-2024-05-13": {
6679
+ readonly "openai/gpt-4o": {
6680
6680
  id: string;
6681
6681
  name: string;
6682
6682
  api: "openai-completions";
@@ -6693,7 +6693,7 @@ export declare const MODELS: {
6693
6693
  contextWindow: number;
6694
6694
  maxTokens: number;
6695
6695
  };
6696
- readonly "openai/gpt-4o": {
6696
+ readonly "openai/gpt-4o:extended": {
6697
6697
  id: string;
6698
6698
  name: string;
6699
6699
  api: "openai-completions";
@@ -6710,7 +6710,7 @@ export declare const MODELS: {
6710
6710
  contextWindow: number;
6711
6711
  maxTokens: number;
6712
6712
  };
6713
- readonly "openai/gpt-4o:extended": {
6713
+ readonly "openai/gpt-4o-2024-05-13": {
6714
6714
  id: string;
6715
6715
  name: string;
6716
6716
  api: "openai-completions";
@@ -6846,7 +6846,7 @@ export declare const MODELS: {
6846
6846
  contextWindow: number;
6847
6847
  maxTokens: number;
6848
6848
  };
6849
- readonly "openai/gpt-3.5-turbo-0613": {
6849
+ readonly "openai/gpt-4-turbo-preview": {
6850
6850
  id: string;
6851
6851
  name: string;
6852
6852
  api: "openai-completions";
@@ -6863,7 +6863,7 @@ export declare const MODELS: {
6863
6863
  contextWindow: number;
6864
6864
  maxTokens: number;
6865
6865
  };
6866
- readonly "openai/gpt-4-turbo-preview": {
6866
+ readonly "openai/gpt-3.5-turbo-0613": {
6867
6867
  id: string;
6868
6868
  name: string;
6869
6869
  api: "openai-completions";