codemaxxing 0.1.2 → 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.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * codemaxxing auth CLI
4
+ *
5
+ * Commands:
6
+ * codemaxxing login — Interactive auth setup
7
+ * codemaxxing auth list — List saved credentials
8
+ * codemaxxing auth remove <name> — Remove a credential
9
+ * codemaxxing auth openrouter — Start OpenRouter OAuth
10
+ * codemaxxing auth anthropic — Get Anthropic via Claude Code
11
+ * codemaxxing auth openai — Import Codex CLI credentials
12
+ * codemaxxing auth qwen — Import Qwen CLI credentials
13
+ * codemaxxing auth copilot — GitHub Copilot device flow
14
+ * codemaxxing auth api-key <name> <key> — Save API key directly
15
+ */
16
+ export {};
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * codemaxxing auth CLI
4
+ *
5
+ * Commands:
6
+ * codemaxxing login — Interactive auth setup
7
+ * codemaxxing auth list — List saved credentials
8
+ * codemaxxing auth remove <name> — Remove a credential
9
+ * codemaxxing auth openrouter — Start OpenRouter OAuth
10
+ * codemaxxing auth anthropic — Get Anthropic via Claude Code
11
+ * codemaxxing auth openai — Import Codex CLI credentials
12
+ * codemaxxing auth qwen — Import Qwen CLI credentials
13
+ * codemaxxing auth copilot — GitHub Copilot device flow
14
+ * codemaxxing auth api-key <name> <key> — Save API key directly
15
+ */
16
+ import { PROVIDERS, getCredentials, removeCredential, openRouterOAuth, anthropicSetupToken, importCodexToken, importQwenToken, copilotDeviceFlow, saveApiKey, detectAvailableAuth, } from "./utils/auth.js";
17
+ const command = process.argv[2] ?? "login";
18
+ async function main() {
19
+ switch (command) {
20
+ case "login": {
21
+ console.log("\n💪 Codemaxxing Authentication\n");
22
+ console.log("Available providers:\n");
23
+ PROVIDERS.forEach((p, i) => {
24
+ const methods = p.methods.filter((m) => m !== "none").join(", ");
25
+ console.log(` ${i + 1}. ${p.name}`);
26
+ console.log(` ${p.description}`);
27
+ console.log(` Methods: ${methods}\n`);
28
+ });
29
+ console.log("Detected on this machine:");
30
+ const detected = detectAvailableAuth();
31
+ if (detected.length === 0) {
32
+ console.log(" — No existing CLI credentials found\n");
33
+ }
34
+ else {
35
+ detected.forEach((d) => {
36
+ console.log(` ⚡ ${d.provider} — ${d.description}`);
37
+ });
38
+ console.log("");
39
+ }
40
+ const readline = await import("readline");
41
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
42
+ const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
43
+ const choice = await ask("Select a provider (1-" + PROVIDERS.length + ") or name: ");
44
+ const providerId = PROVIDERS[parseInt(choice) - 1]?.id ?? choice.toLowerCase();
45
+ const provider = PROVIDERS.find((p) => p.id === providerId);
46
+ if (!provider) {
47
+ console.log(`Unknown provider: ${providerId}`);
48
+ process.exit(1);
49
+ }
50
+ console.log(`\nSetting up ${provider.name}...\n`);
51
+ try {
52
+ if (providerId === "openrouter") {
53
+ const cred = await openRouterOAuth((msg) => console.log(` ${msg}`));
54
+ console.log(`\n✅ OpenRouter authenticated! (${cred.label})`);
55
+ }
56
+ else if (providerId === "anthropic") {
57
+ if (provider.methods.includes("setup-token")) {
58
+ const cred = await anthropicSetupToken((msg) => console.log(` ${msg}`));
59
+ console.log(`\n✅ Anthropic authenticated! (${cred.label})`);
60
+ }
61
+ else {
62
+ const apiKey = await ask("Enter your Anthropic API key: ");
63
+ const cred = saveApiKey(providerId, apiKey);
64
+ console.log(`\n✅ Saved API key for ${provider.name}`);
65
+ }
66
+ }
67
+ else if (providerId === "openai") {
68
+ const imported = importCodexToken((msg) => console.log(` ${msg}`));
69
+ if (imported) {
70
+ console.log(`\n✅ Imported Codex credentials! (${imported.label})`);
71
+ }
72
+ else {
73
+ const apiKey = await ask("Enter your OpenAI API key: ");
74
+ const cred = saveApiKey(providerId, apiKey);
75
+ console.log(`\n✅ Saved API key for ${provider.name}`);
76
+ }
77
+ }
78
+ else if (providerId === "qwen") {
79
+ const imported = importQwenToken((msg) => console.log(` ${msg}`));
80
+ if (imported) {
81
+ console.log(`\n✅ Imported Qwen credentials! (${imported.label})`);
82
+ }
83
+ else {
84
+ const apiKey = await ask("Enter your Qwen/DashScope API key: ");
85
+ const cred = saveApiKey(providerId, apiKey);
86
+ console.log(`\n✅ Saved API key for ${provider.name}`);
87
+ }
88
+ }
89
+ else if (providerId === "copilot") {
90
+ const cred = await copilotDeviceFlow((msg) => console.log(` ${msg}`));
91
+ console.log(`\n✅ GitHub Copilot authenticated!`);
92
+ }
93
+ else if (providerId === "custom") {
94
+ const baseUrl = await ask("Enter the base URL: ");
95
+ const apiKey = await ask("Enter your API key: ");
96
+ const cred = saveApiKey(providerId, apiKey, baseUrl, "Custom provider");
97
+ console.log(`\n✅ Saved custom provider`);
98
+ }
99
+ else {
100
+ const apiKey = await ask(`Enter your ${provider.name} API key (${provider.consoleUrl}): `);
101
+ const cred = saveApiKey(providerId, apiKey);
102
+ console.log(`\n✅ Saved API key for ${provider.name}`);
103
+ }
104
+ console.log("\nRun 'codemaxxing' to start coding!");
105
+ }
106
+ catch (err) {
107
+ console.error(`\n❌ Error: ${err.message}`);
108
+ process.exit(1);
109
+ }
110
+ finally {
111
+ rl.close();
112
+ }
113
+ break;
114
+ }
115
+ case "list":
116
+ case "ls": {
117
+ const creds = getCredentials();
118
+ console.log("\n💪 Saved Credentials\n");
119
+ if (creds.length === 0) {
120
+ console.log(" No credentials saved.\n");
121
+ console.log(" Run 'codemaxxing login' to set up authentication.\n");
122
+ break;
123
+ }
124
+ creds.forEach((c) => {
125
+ console.log(` ${c.provider}`);
126
+ console.log(` Method: ${c.method}`);
127
+ console.log(` Label: ${c.label ?? "—"}`);
128
+ const maskedKey = c.apiKey.length > 12
129
+ ? c.apiKey.slice(0, 4) + "•".repeat(8) + c.apiKey.slice(-4)
130
+ : "••••••••";
131
+ console.log(` Key: ${maskedKey}`);
132
+ console.log(` Base: ${c.baseUrl}`);
133
+ console.log("");
134
+ });
135
+ break;
136
+ }
137
+ case "remove":
138
+ case "rm":
139
+ case "delete": {
140
+ const target = process.argv[3];
141
+ if (!target) {
142
+ console.log("Usage: codemaxxing auth remove <provider-name>");
143
+ console.log("\nSaved providers:");
144
+ getCredentials().forEach((c) => console.log(` ${c.provider}`));
145
+ process.exit(1);
146
+ }
147
+ const removed = removeCredential(target);
148
+ if (removed) {
149
+ console.log(`✅ Removed ${target}`);
150
+ }
151
+ else {
152
+ console.log(`❌ No credential found for: ${target}`);
153
+ console.log("\nSaved providers:");
154
+ getCredentials().forEach((c) => console.log(` ${c.provider}`));
155
+ process.exit(1);
156
+ }
157
+ break;
158
+ }
159
+ case "openrouter": {
160
+ console.log("Starting OpenRouter OAuth flow...\n");
161
+ try {
162
+ const cred = await openRouterOAuth((msg) => console.log(` ${msg}`));
163
+ console.log(`\n✅ OpenRouter authenticated!`);
164
+ }
165
+ catch (err) {
166
+ console.error(`\n❌ ${err.message}`);
167
+ process.exit(1);
168
+ }
169
+ break;
170
+ }
171
+ case "anthropic": {
172
+ console.log("Starting Anthropic setup-token flow...\n");
173
+ try {
174
+ const cred = await anthropicSetupToken((msg) => console.log(` ${msg}`));
175
+ console.log(`\n✅ Anthropic authenticated!`);
176
+ }
177
+ catch (err) {
178
+ console.error(`\n❌ ${err.message}`);
179
+ process.exit(1);
180
+ }
181
+ break;
182
+ }
183
+ case "openai": {
184
+ console.log("Checking for Codex CLI credentials...\n");
185
+ const imported = importCodexToken((msg) => console.log(` ${msg}`));
186
+ if (imported) {
187
+ console.log(`\n✅ Imported Codex credentials!`);
188
+ }
189
+ else {
190
+ console.log("\n❌ No Codex CLI credentials found.");
191
+ console.log("Make sure Codex CLI is installed and you've logged in.");
192
+ }
193
+ break;
194
+ }
195
+ case "qwen": {
196
+ console.log("Checking for Qwen CLI credentials...\n");
197
+ const imported = importQwenToken((msg) => console.log(` ${msg}`));
198
+ if (imported) {
199
+ console.log(`\n✅ Imported Qwen credentials!`);
200
+ }
201
+ else {
202
+ console.log("\n❌ No Qwen CLI credentials found.");
203
+ console.log("Make sure Qwen CLI is installed and you've logged in.");
204
+ }
205
+ break;
206
+ }
207
+ case "copilot": {
208
+ console.log("Starting GitHub Copilot device flow...\n");
209
+ try {
210
+ const cred = await copilotDeviceFlow((msg) => console.log(` ${msg}`));
211
+ console.log(`\n✅ GitHub Copilot authenticated!`);
212
+ }
213
+ catch (err) {
214
+ console.error(`\n❌ ${err.message}`);
215
+ process.exit(1);
216
+ }
217
+ break;
218
+ }
219
+ case "api-key": {
220
+ const providerId = process.argv[3];
221
+ const apiKey = process.argv[4];
222
+ if (!providerId || !apiKey) {
223
+ console.log("Usage: codemaxxing auth api-key <provider-id> <api-key>");
224
+ process.exit(1);
225
+ }
226
+ const cred = saveApiKey(providerId, apiKey);
227
+ console.log(`\n✅ Saved API key for ${cred.provider}`);
228
+ break;
229
+ }
230
+ case "help":
231
+ case "--help":
232
+ case "-h": {
233
+ console.log(`
234
+ 💪 Codemaxxing Auth
235
+
236
+ Commands:
237
+ codemaxxing login Interactive authentication setup
238
+ codemaxxing auth list List saved credentials
239
+ codemaxxing auth remove <name> Remove a credential
240
+ codemaxxing auth openrouter Start OpenRouter OAuth flow
241
+ codemaxxing auth anthropic Get Anthropic via Claude Code CLI
242
+ codemaxxing auth openai Import Codex CLI credentials
243
+ codemaxxing auth qwen Import Qwen CLI credentials
244
+ codemaxxing auth copilot GitHub Copilot device flow
245
+ codemaxxing auth api-key <id> <key> Save API key directly
246
+ codemaxxing auth help Show this help
247
+
248
+ Examples:
249
+ codemaxxing login # Interactive provider picker
250
+ codemaxxing auth openrouter # One browser login, access to 200+ models
251
+ codemaxxing auth anthropic # Use your Claude subscription via Claude Code
252
+ codemaxxing auth list # See what's saved
253
+ `);
254
+ break;
255
+ }
256
+ default:
257
+ console.log(`Unknown command: ${command}`);
258
+ console.log("Run 'codemaxxing auth help' for available commands.");
259
+ process.exit(1);
260
+ }
261
+ }
262
+ main().catch((err) => {
263
+ console.error(`Error: ${err.message}`);
264
+ process.exit(1);
265
+ });
package/dist/config.d.ts CHANGED
@@ -39,3 +39,12 @@ export declare function detectLocalProvider(): Promise<ProviderConfig | null>;
39
39
  * List available models from a provider endpoint
40
40
  */
41
41
  export declare function listModels(baseUrl: string, apiKey: string): Promise<string[]>;
42
+ /**
43
+ * Resolve provider configuration from auth store or config file
44
+ * Priority: CLI args > auth store > config file > auto-detect
45
+ */
46
+ export declare function resolveProvider(providerId: string, cliArgs: CLIArgs): {
47
+ baseUrl: string;
48
+ apiKey: string;
49
+ model: string;
50
+ } | null;
package/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
+ import { getCredential } from "./utils/auth.js";
4
5
  const CONFIG_DIR = join(homedir(), ".codemaxxing");
5
6
  const CONFIG_FILE = join(CONFIG_DIR, "settings.json");
6
7
  const DEFAULT_CONFIG = {
@@ -172,3 +173,29 @@ export async function listModels(baseUrl, apiKey) {
172
173
  catch { /* ignore */ }
173
174
  return [];
174
175
  }
176
+ /**
177
+ * Resolve provider configuration from auth store or config file
178
+ * Priority: CLI args > auth store > config file > auto-detect
179
+ */
180
+ export function resolveProvider(providerId, cliArgs) {
181
+ // Check auth store first
182
+ const authCred = getCredential(providerId);
183
+ if (authCred) {
184
+ return {
185
+ baseUrl: authCred.baseUrl,
186
+ apiKey: authCred.apiKey,
187
+ model: cliArgs.model || "auto",
188
+ };
189
+ }
190
+ // Fall back to config file
191
+ const config = loadConfig();
192
+ const provider = config.providers?.[providerId];
193
+ if (provider) {
194
+ return {
195
+ baseUrl: provider.baseUrl,
196
+ apiKey: cliArgs.apiKey || provider.apiKey,
197
+ model: cliArgs.model || provider.model,
198
+ };
199
+ }
200
+ return null;
201
+ }
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ function formatTimeAgo(date) {
28
28
  // ── Slash Commands ──
29
29
  const SLASH_COMMANDS = [
30
30
  { cmd: "/help", desc: "show commands" },
31
+ { cmd: "/login", desc: "set up authentication" },
31
32
  { cmd: "/map", desc: "show repository map" },
32
33
  { cmd: "/reset", desc: "clear conversation" },
33
34
  { cmd: "/context", desc: "show message count" },
@@ -275,10 +276,33 @@ function App() {
275
276
  exit();
276
277
  return;
277
278
  }
279
+ if (trimmed === "/login" || trimmed === "/auth") {
280
+ addMsg("info", [
281
+ "💪 Authentication Setup",
282
+ "",
283
+ "Run 'codemaxxing login' in a new terminal to set up:",
284
+ " • OpenRouter OAuth (browser login, 200+ models)",
285
+ " • Anthropic via Claude Code (your Pro/Max subscription)",
286
+ " • ChatGPT via Codex CLI (your Plus/Pro subscription)",
287
+ " • Qwen CLI (your Qwen access)",
288
+ " • GitHub Copilot (device flow)",
289
+ " • Manual API keys for any provider",
290
+ "",
291
+ "Commands:",
292
+ " codemaxxing login — interactive setup",
293
+ " codemaxxing auth list — see saved credentials",
294
+ " codemaxxing auth openrouter — OpenRouter OAuth",
295
+ " codemaxxing auth anthropic — Anthropic subscription",
296
+ " codemaxxing auth openai — ChatGPT subscription",
297
+ " codemaxxing auth copilot — GitHub Copilot",
298
+ ].join("\n"));
299
+ return;
300
+ }
278
301
  if (trimmed === "/help") {
279
302
  addMsg("info", [
280
303
  "Commands:",
281
304
  " /help — show this",
305
+ " /login — authentication setup (run codemaxxing login in terminal)",
282
306
  " /model — switch model mid-session",
283
307
  " /models — list available models",
284
308
  " /map — show repository map",
package/dist/themes.d.ts CHANGED
@@ -19,6 +19,6 @@ export interface Theme {
19
19
  };
20
20
  }
21
21
  export declare const THEMES: Record<string, Theme>;
22
- export declare const DEFAULT_THEME = "neon";
22
+ export declare const DEFAULT_THEME = "nord";
23
23
  export declare function getTheme(name: string): Theme;
24
24
  export declare function listThemes(): string[];
package/dist/themes.js CHANGED
@@ -140,7 +140,7 @@ export const THEMES = {
140
140
  },
141
141
  },
142
142
  };
143
- export const DEFAULT_THEME = "neon";
143
+ export const DEFAULT_THEME = "nord";
144
144
  export function getTheme(name) {
145
145
  return THEMES[name] ?? THEMES[DEFAULT_THEME];
146
146
  }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Auth management for Codemaxxing
3
+ *
4
+ * Supports:
5
+ * - OpenRouter OAuth PKCE (browser login, no API key needed)
6
+ * - Anthropic setup-token (via Claude Code CLI)
7
+ * - OpenAI/ChatGPT (via Codex CLI cached token)
8
+ * - Qwen (via Qwen CLI cached credentials)
9
+ * - GitHub Copilot (device flow)
10
+ * - Manual API key entry (any provider)
11
+ *
12
+ * Credentials stored in ~/.codemaxxing/auth.json with 0o600 permissions.
13
+ */
14
+ export interface AuthCredential {
15
+ provider: string;
16
+ method: "api-key" | "oauth" | "setup-token" | "cached-token";
17
+ apiKey: string;
18
+ baseUrl: string;
19
+ label?: string;
20
+ expiresAt?: string;
21
+ createdAt: string;
22
+ }
23
+ export interface ProviderDef {
24
+ id: string;
25
+ name: string;
26
+ methods: string[];
27
+ baseUrl: string;
28
+ consoleUrl?: string;
29
+ description: string;
30
+ }
31
+ export declare const PROVIDERS: ProviderDef[];
32
+ export declare function getCredentials(): AuthCredential[];
33
+ export declare function getCredential(providerId: string): AuthCredential | undefined;
34
+ export declare function saveCredential(cred: AuthCredential): void;
35
+ export declare function removeCredential(providerId: string): boolean;
36
+ export declare function openRouterOAuth(onStatus?: (msg: string) => void): Promise<AuthCredential>;
37
+ export declare function detectClaudeCLI(): boolean;
38
+ export declare function anthropicSetupToken(onStatus?: (msg: string) => void): Promise<AuthCredential>;
39
+ export declare function detectCodexToken(): string | null;
40
+ export declare function importCodexToken(onStatus?: (msg: string) => void): AuthCredential | null;
41
+ export declare function detectQwenToken(): string | null;
42
+ export declare function importQwenToken(onStatus?: (msg: string) => void): AuthCredential | null;
43
+ export declare function copilotDeviceFlow(onStatus?: (msg: string) => void): Promise<AuthCredential>;
44
+ export declare function saveApiKey(providerId: string, apiKey: string, baseUrl?: string, label?: string): AuthCredential;
45
+ /**
46
+ * Check which provider CLIs / cached tokens are available on this machine
47
+ */
48
+ export declare function detectAvailableAuth(): Array<{
49
+ provider: string;
50
+ method: string;
51
+ description: string;
52
+ }>;
53
+ /**
54
+ * Resolve provider config: check auth store first, then fall back to config
55
+ */
56
+ export declare function resolveProviderAuth(providerId: string): {
57
+ apiKey: string;
58
+ baseUrl: string;
59
+ } | null;