@oh-my-pi/pi-ai 0.1.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/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@oh-my-pi/pi-ai",
3
+ "version": "0.1.0",
4
+ "description": "Unified LLM API with automatic model discovery and provider configuration",
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "types": "./src/index.ts",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./utils/json-parse": "./src/utils/json-parse.ts"
11
+ },
12
+ "bin": {
13
+ "pi-ai": "./src/cli.ts"
14
+ },
15
+ "files": [
16
+ "src",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "generate-models": "bun scripts/generate-models.ts",
21
+ "test": "vitest --run",
22
+ "prepublishOnly": "bun run generate-models"
23
+ },
24
+ "dependencies": {
25
+ "@anthropic-ai/sdk": "0.71.2",
26
+ "@google/genai": "1.34.0",
27
+ "@mistralai/mistralai": "1.10.0",
28
+ "@sinclair/typebox": "^0.34.41",
29
+ "ajv": "^8.17.1",
30
+ "ajv-formats": "^3.0.1",
31
+ "chalk": "^5.6.2",
32
+ "openai": "6.10.0",
33
+ "partial-json": "^0.1.7",
34
+ "zod-to-json-schema": "^3.24.6"
35
+ },
36
+ "keywords": [
37
+ "ai",
38
+ "llm",
39
+ "openai",
40
+ "anthropic",
41
+ "gemini",
42
+ "unified",
43
+ "api"
44
+ ],
45
+ "author": "Mario Zechner",
46
+ "license": "MIT",
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/can1357/oh-my-pi.git",
50
+ "directory": "packages/ai"
51
+ },
52
+ "engines": {
53
+ "bun": ">=1.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^24.3.0",
57
+ "canvas": "^3.2.0",
58
+ "vitest": "^3.2.4"
59
+ }
60
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { logger } from "@oh-my-pi/pi-coding-agent";
4
+ import { loginAnthropic } from "./utils/oauth/anthropic";
5
+ import { loginGitHubCopilot } from "./utils/oauth/github-copilot";
6
+ import { loginAntigravity } from "./utils/oauth/google-antigravity";
7
+ import { loginGeminiCli } from "./utils/oauth/google-gemini-cli";
8
+ import { getOAuthProviders } from "./utils/oauth/index";
9
+ import type { OAuthCredentials, OAuthProvider } from "./utils/oauth/types";
10
+
11
+ const AUTH_FILE = "auth.json";
12
+ const PROVIDERS = getOAuthProviders();
13
+
14
+ function prompt(question: string): Promise<string> {
15
+ return new Promise((resolve) => {
16
+ process.stdout.write(question);
17
+ process.stdin.resume();
18
+ process.stdin.once("data", (data) => {
19
+ process.stdin.pause();
20
+ resolve(data.toString().trim());
21
+ });
22
+ });
23
+ }
24
+
25
+ async function loadAuth(): Promise<Record<string, { type: "oauth" } & OAuthCredentials>> {
26
+ const file = Bun.file(AUTH_FILE);
27
+ if (!(await file.exists())) return {};
28
+ try {
29
+ return await file.json();
30
+ } catch (err) {
31
+ logger.debug("Failed to parse config file", { error: String(err) });
32
+ return {};
33
+ }
34
+ }
35
+
36
+ async function saveAuth(auth: Record<string, { type: "oauth" } & OAuthCredentials>): Promise<void> {
37
+ await Bun.write(AUTH_FILE, JSON.stringify(auth, null, 2));
38
+ }
39
+
40
+ async function login(provider: OAuthProvider): Promise<void> {
41
+ const promptFn = (msg: string) => prompt(`${msg} `);
42
+
43
+ let credentials: OAuthCredentials;
44
+
45
+ switch (provider) {
46
+ case "anthropic":
47
+ credentials = await loginAnthropic(
48
+ (url) => {
49
+ console.log(`\nOpen this URL in your browser:\n${url}\n`);
50
+ },
51
+ async () => {
52
+ return await promptFn("Paste the authorization code:");
53
+ },
54
+ );
55
+ break;
56
+
57
+ case "github-copilot":
58
+ credentials = await loginGitHubCopilot({
59
+ onAuth: (url, instructions) => {
60
+ console.log(`\nOpen this URL in your browser:\n${url}`);
61
+ if (instructions) console.log(instructions);
62
+ console.log();
63
+ },
64
+ onPrompt: async (p) => {
65
+ return await promptFn(`${p.message}${p.placeholder ? ` (${p.placeholder})` : ""}:`);
66
+ },
67
+ onProgress: (msg) => console.log(msg),
68
+ });
69
+ break;
70
+
71
+ case "google-gemini-cli":
72
+ credentials = await loginGeminiCli(
73
+ (info) => {
74
+ console.log(`\nOpen this URL in your browser:\n${info.url}`);
75
+ if (info.instructions) console.log(info.instructions);
76
+ console.log();
77
+ },
78
+ (msg) => console.log(msg),
79
+ );
80
+ break;
81
+
82
+ case "google-antigravity":
83
+ credentials = await loginAntigravity(
84
+ (info) => {
85
+ console.log(`\nOpen this URL in your browser:\n${info.url}`);
86
+ if (info.instructions) console.log(info.instructions);
87
+ console.log();
88
+ },
89
+ (msg) => console.log(msg),
90
+ );
91
+ break;
92
+ }
93
+
94
+ const auth = await loadAuth();
95
+ auth[provider] = { type: "oauth", ...credentials };
96
+ await saveAuth(auth);
97
+
98
+ console.log(`\nCredentials saved to ${AUTH_FILE}`);
99
+ }
100
+
101
+ async function main(): Promise<void> {
102
+ const args = process.argv.slice(2);
103
+ const command = args[0];
104
+
105
+ if (!command || command === "help" || command === "--help" || command === "-h") {
106
+ console.log(`Usage: npx @oh-my-pi/pi-ai <command> [provider]
107
+
108
+ Commands:
109
+ login [provider] Login to an OAuth provider
110
+ list List available providers
111
+
112
+ Providers:
113
+ anthropic Anthropic (Claude Pro/Max)
114
+ github-copilot GitHub Copilot
115
+ google-gemini-cli Google Gemini CLI
116
+ google-antigravity Antigravity (Gemini 3, Claude, GPT-OSS)
117
+
118
+ Examples:
119
+ npx @oh-my-pi/pi-ai login # interactive provider selection
120
+ npx @oh-my-pi/pi-ai login anthropic # login to specific provider
121
+ npx @oh-my-pi/pi-ai list # list providers
122
+ `);
123
+ return;
124
+ }
125
+
126
+ if (command === "list") {
127
+ console.log("Available OAuth providers:\n");
128
+ for (const p of PROVIDERS) {
129
+ console.log(` ${p.id.padEnd(20)} ${p.name}`);
130
+ }
131
+ return;
132
+ }
133
+
134
+ if (command === "login") {
135
+ let provider = args[1] as OAuthProvider | undefined;
136
+
137
+ if (!provider) {
138
+ console.log("Select a provider:\n");
139
+ for (let i = 0; i < PROVIDERS.length; i++) {
140
+ console.log(` ${i + 1}. ${PROVIDERS[i].name}`);
141
+ }
142
+ console.log();
143
+
144
+ const choice = await prompt("Enter number (1-4): ");
145
+
146
+ const index = parseInt(choice, 10) - 1;
147
+ if (index < 0 || index >= PROVIDERS.length) {
148
+ console.error("Invalid selection");
149
+ process.exit(1);
150
+ }
151
+ provider = PROVIDERS[index].id;
152
+ }
153
+
154
+ if (!PROVIDERS.some((p) => p.id === provider)) {
155
+ console.error(`Unknown provider: ${provider}`);
156
+ console.error(`Use 'npx @oh-my-pi/pi-ai list' to see available providers`);
157
+ process.exit(1);
158
+ }
159
+
160
+ console.log(`Logging in to ${provider}...`);
161
+ await login(provider);
162
+ return;
163
+ }
164
+
165
+ console.error(`Unknown command: ${command}`);
166
+ console.error(`Use 'npx @oh-my-pi/pi-ai --help' for usage`);
167
+ process.exit(1);
168
+ }
169
+
170
+ main().catch((err) => {
171
+ console.error("Error:", err.message);
172
+ process.exit(1);
173
+ });
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export * from "./models";
2
+ export * from "./providers/anthropic";
3
+ export * from "./providers/google";
4
+ export * from "./providers/google-gemini-cli";
5
+ export * from "./providers/openai-completions";
6
+ export * from "./providers/openai-responses";
7
+ export * from "./stream";
8
+ export * from "./types";
9
+ export * from "./utils/event-stream";
10
+ export * from "./utils/oauth/index";
11
+ export * from "./utils/overflow";
12
+ export * from "./utils/typebox-helpers";
13
+ export * from "./utils/validation";