codemaxxing 0.1.4 → 0.1.7

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.
@@ -13,4 +13,4 @@
13
13
  * codemaxxing auth copilot — GitHub Copilot device flow
14
14
  * codemaxxing auth api-key <name> <key> — Save API key directly
15
15
  */
16
- export {};
16
+ export declare function main(): Promise<void>;
package/dist/auth-cli.js CHANGED
@@ -14,8 +14,8 @@
14
14
  * codemaxxing auth api-key <name> <key> — Save API key directly
15
15
  */
16
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() {
17
+ export async function main() {
18
+ const command = process.argv[2] ?? "login";
19
19
  switch (command) {
20
20
  case "login": {
21
21
  console.log("\n💪 Codemaxxing Authentication\n");
@@ -259,6 +259,7 @@ Examples:
259
259
  process.exit(1);
260
260
  }
261
261
  }
262
+ // Always run main — this module is either imported and main() called, or run directly
262
263
  main().catch((err) => {
263
264
  console.error(`Error: ${err.message}`);
264
265
  process.exit(1);
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Codemaxxing CLI entry point
4
+ * Routes subcommands (login, auth) to auth-cli, everything else to the TUI
5
+ */
6
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Codemaxxing CLI entry point
4
+ * Routes subcommands (login, auth) to auth-cli, everything else to the TUI
5
+ */
6
+ import { spawn } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
+ import { dirname, join } from "node:path";
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ const subcmd = process.argv[2];
12
+ if (subcmd === "login" || subcmd === "auth") {
13
+ // Route to auth CLI (spawn is fine here — no TUI/raw mode needed)
14
+ const authScript = join(__dirname, "auth-cli.js");
15
+ const args = subcmd === "login"
16
+ ? [authScript, "login", ...process.argv.slice(3)]
17
+ : [authScript, ...process.argv.slice(3)];
18
+ const child = spawn(process.execPath, args, {
19
+ stdio: "inherit",
20
+ cwd: process.cwd(),
21
+ });
22
+ child.on("exit", (code) => process.exit(code ?? 0));
23
+ }
24
+ else {
25
+ // TUI mode — import directly (not spawn) to preserve raw stdin
26
+ await import("./index.js");
27
+ }
package/dist/index.js CHANGED
@@ -10,7 +10,8 @@ import { listSessions, getSession, loadMessages } from "./utils/sessions.js";
10
10
  import { execSync } from "child_process";
11
11
  import { isGitRepo, getBranch, getStatus, getDiff, undoLastCommit } from "./utils/git.js";
12
12
  import { getTheme, listThemes, THEMES, DEFAULT_THEME } from "./themes.js";
13
- const VERSION = "0.1.0";
13
+ import { PROVIDERS, openRouterOAuth, anthropicSetupToken, importCodexToken, importQwenToken, copilotDeviceFlow } from "./utils/auth.js";
14
+ const VERSION = "0.1.5";
14
15
  // ── Helpers ──
15
16
  function formatTimeAgo(date) {
16
17
  const secs = Math.floor((Date.now() - date.getTime()) / 1000);
@@ -105,6 +106,8 @@ function App() {
105
106
  const [sessionPickerIndex, setSessionPickerIndex] = useState(0);
106
107
  const [themePicker, setThemePicker] = useState(false);
107
108
  const [themePickerIndex, setThemePickerIndex] = useState(0);
109
+ const [loginPicker, setLoginPicker] = useState(false);
110
+ const [loginPickerIndex, setLoginPickerIndex] = useState(0);
108
111
  const [approval, setApproval] = useState(null);
109
112
  // Listen for paste events from stdin interceptor
110
113
  useEffect(() => {
@@ -277,25 +280,8 @@ function App() {
277
280
  return;
278
281
  }
279
282
  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"));
283
+ setLoginPicker(true);
284
+ setLoginPickerIndex(0);
299
285
  return;
300
286
  }
301
287
  if (trimmed === "/help") {
@@ -511,6 +497,92 @@ function App() {
511
497
  return;
512
498
  }
513
499
  }
500
+ // Login picker navigation
501
+ if (loginPicker) {
502
+ const loginProviders = PROVIDERS.filter((p) => p.id !== "local");
503
+ if (key.upArrow) {
504
+ setLoginPickerIndex((prev) => (prev - 1 + loginProviders.length) % loginProviders.length);
505
+ return;
506
+ }
507
+ if (key.downArrow) {
508
+ setLoginPickerIndex((prev) => (prev + 1) % loginProviders.length);
509
+ return;
510
+ }
511
+ if (key.return) {
512
+ const selected = loginProviders[loginPickerIndex];
513
+ setLoginPicker(false);
514
+ if (selected.id === "openrouter") {
515
+ addMsg("info", "Starting OpenRouter OAuth — opening browser...");
516
+ setLoading(true);
517
+ setSpinnerMsg("Waiting for authorization...");
518
+ openRouterOAuth((msg) => addMsg("info", msg))
519
+ .then((cred) => {
520
+ addMsg("info", `✅ OpenRouter authenticated! You now have access to 200+ models.`);
521
+ addMsg("info", `Switch with: /model anthropic/claude-sonnet-4`);
522
+ setLoading(false);
523
+ })
524
+ .catch((err) => {
525
+ addMsg("error", `OAuth failed: ${err.message}`);
526
+ setLoading(false);
527
+ });
528
+ }
529
+ else if (selected.id === "anthropic") {
530
+ addMsg("info", "Starting Anthropic setup-token flow...");
531
+ setLoading(true);
532
+ setSpinnerMsg("Waiting for Claude Code auth...");
533
+ anthropicSetupToken((msg) => addMsg("info", msg))
534
+ .then((cred) => {
535
+ addMsg("info", `✅ Anthropic authenticated! (${cred.label})`);
536
+ setLoading(false);
537
+ })
538
+ .catch((err) => {
539
+ addMsg("error", `Anthropic auth failed: ${err.message}`);
540
+ setLoading(false);
541
+ });
542
+ }
543
+ else if (selected.id === "openai") {
544
+ const imported = importCodexToken((msg) => addMsg("info", msg));
545
+ if (imported) {
546
+ addMsg("info", `✅ Imported Codex credentials! (${imported.label})`);
547
+ }
548
+ else {
549
+ addMsg("info", "No Codex CLI found. Run: codemaxxing auth api-key openai <your-key>");
550
+ }
551
+ }
552
+ else if (selected.id === "qwen") {
553
+ const imported = importQwenToken((msg) => addMsg("info", msg));
554
+ if (imported) {
555
+ addMsg("info", `✅ Imported Qwen credentials! (${imported.label})`);
556
+ }
557
+ else {
558
+ addMsg("info", "No Qwen CLI found. Run: codemaxxing auth api-key qwen <your-key>");
559
+ }
560
+ }
561
+ else if (selected.id === "copilot") {
562
+ addMsg("info", "Starting GitHub Copilot device flow...");
563
+ setLoading(true);
564
+ setSpinnerMsg("Waiting for GitHub authorization...");
565
+ copilotDeviceFlow((msg) => addMsg("info", msg))
566
+ .then(() => {
567
+ addMsg("info", `✅ GitHub Copilot authenticated!`);
568
+ setLoading(false);
569
+ })
570
+ .catch((err) => {
571
+ addMsg("error", `Copilot auth failed: ${err.message}`);
572
+ setLoading(false);
573
+ });
574
+ }
575
+ else {
576
+ addMsg("info", `Run: codemaxxing auth api-key ${selected.id} <your-key>\n Get key at: ${selected.consoleUrl ?? selected.baseUrl}`);
577
+ }
578
+ return;
579
+ }
580
+ if (key.escape) {
581
+ setLoginPicker(false);
582
+ return;
583
+ }
584
+ return;
585
+ }
514
586
  // Theme picker navigation
515
587
  if (themePicker) {
516
588
  const themeKeys = listThemes();
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "codemaxxing",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "Open-source terminal coding agent. Connect any LLM. Max your code.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "codemaxxing": "./dist/index.js",
8
- "codemaxxing-auth": "./dist/auth-cli.js"
7
+ "codemaxxing": "dist/cli.js",
8
+ "codemaxxing-auth": "dist/auth-cli.js"
9
9
  },
10
10
  "type": "module",
11
11
  "scripts": {
package/src/auth-cli.ts CHANGED
@@ -28,9 +28,9 @@ import {
28
28
  detectAvailableAuth,
29
29
  } from "./utils/auth.js";
30
30
 
31
- const command = process.argv[2] ?? "login";
31
+ export async function main() {
32
+ const command = process.argv[2] ?? "login";
32
33
 
33
- async function main() {
34
34
  switch (command) {
35
35
  case "login": {
36
36
  console.log("\n💪 Codemaxxing Authentication\n");
@@ -280,6 +280,7 @@ Examples:
280
280
  }
281
281
  }
282
282
 
283
+ // Always run main — this module is either imported and main() called, or run directly
283
284
  main().catch((err) => {
284
285
  console.error(`Error: ${err.message}`);
285
286
  process.exit(1);
package/src/cli.ts ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Codemaxxing CLI entry point
5
+ * Routes subcommands (login, auth) to auth-cli, everything else to the TUI
6
+ */
7
+
8
+ import { spawn } from "node:child_process";
9
+ import { fileURLToPath } from "node:url";
10
+ import { dirname, join } from "node:path";
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = dirname(__filename);
14
+
15
+ const subcmd = process.argv[2];
16
+
17
+ if (subcmd === "login" || subcmd === "auth") {
18
+ // Route to auth CLI (spawn is fine here — no TUI/raw mode needed)
19
+ const authScript = join(__dirname, "auth-cli.js");
20
+ const args = subcmd === "login"
21
+ ? [authScript, "login", ...process.argv.slice(3)]
22
+ : [authScript, ...process.argv.slice(3)];
23
+
24
+ const child = spawn(process.execPath, args, {
25
+ stdio: "inherit",
26
+ cwd: process.cwd(),
27
+ });
28
+
29
+ child.on("exit", (code) => process.exit(code ?? 0));
30
+ } else {
31
+ // TUI mode — import directly (not spawn) to preserve raw stdin
32
+ await import("./index.js");
33
+ }
package/src/index.tsx CHANGED
@@ -10,8 +10,9 @@ import { listSessions, getSession, loadMessages } from "./utils/sessions.js";
10
10
  import { execSync } from "child_process";
11
11
  import { isGitRepo, getBranch, getStatus, getDiff, undoLastCommit } from "./utils/git.js";
12
12
  import { getTheme, listThemes, THEMES, DEFAULT_THEME, type Theme } from "./themes.js";
13
+ import { PROVIDERS, getCredentials, openRouterOAuth, anthropicSetupToken, importCodexToken, importQwenToken, copilotDeviceFlow, saveApiKey } from "./utils/auth.js";
13
14
 
14
- const VERSION = "0.1.0";
15
+ const VERSION = "0.1.5";
15
16
 
16
17
  // ── Helpers ──
17
18
  function formatTimeAgo(date: Date): string {
@@ -134,6 +135,8 @@ function App() {
134
135
  const [sessionPickerIndex, setSessionPickerIndex] = useState(0);
135
136
  const [themePicker, setThemePicker] = useState(false);
136
137
  const [themePickerIndex, setThemePickerIndex] = useState(0);
138
+ const [loginPicker, setLoginPicker] = useState(false);
139
+ const [loginPickerIndex, setLoginPickerIndex] = useState(0);
137
140
  const [approval, setApproval] = useState<{
138
141
  tool: string;
139
142
  args: Record<string, unknown>;
@@ -325,25 +328,8 @@ function App() {
325
328
  return;
326
329
  }
327
330
  if (trimmed === "/login" || trimmed === "/auth") {
328
- addMsg("info", [
329
- "💪 Authentication Setup",
330
- "",
331
- "Run 'codemaxxing login' in a new terminal to set up:",
332
- " • OpenRouter OAuth (browser login, 200+ models)",
333
- " • Anthropic via Claude Code (your Pro/Max subscription)",
334
- " • ChatGPT via Codex CLI (your Plus/Pro subscription)",
335
- " • Qwen CLI (your Qwen access)",
336
- " • GitHub Copilot (device flow)",
337
- " • Manual API keys for any provider",
338
- "",
339
- "Commands:",
340
- " codemaxxing login — interactive setup",
341
- " codemaxxing auth list — see saved credentials",
342
- " codemaxxing auth openrouter — OpenRouter OAuth",
343
- " codemaxxing auth anthropic — Anthropic subscription",
344
- " codemaxxing auth openai — ChatGPT subscription",
345
- " codemaxxing auth copilot — GitHub Copilot",
346
- ].join("\n"));
331
+ setLoginPicker(true);
332
+ setLoginPickerIndex(0);
347
333
  return;
348
334
  }
349
335
  if (trimmed === "/help") {
@@ -557,6 +543,87 @@ function App() {
557
543
  }
558
544
  }
559
545
 
546
+ // Login picker navigation
547
+ if (loginPicker) {
548
+ const loginProviders = PROVIDERS.filter((p) => p.id !== "local");
549
+ if (key.upArrow) {
550
+ setLoginPickerIndex((prev: number) => (prev - 1 + loginProviders.length) % loginProviders.length);
551
+ return;
552
+ }
553
+ if (key.downArrow) {
554
+ setLoginPickerIndex((prev: number) => (prev + 1) % loginProviders.length);
555
+ return;
556
+ }
557
+ if (key.return) {
558
+ const selected = loginProviders[loginPickerIndex];
559
+ setLoginPicker(false);
560
+
561
+ if (selected.id === "openrouter") {
562
+ addMsg("info", "Starting OpenRouter OAuth — opening browser...");
563
+ setLoading(true);
564
+ setSpinnerMsg("Waiting for authorization...");
565
+ openRouterOAuth((msg: string) => addMsg("info", msg))
566
+ .then((cred) => {
567
+ addMsg("info", `✅ OpenRouter authenticated! You now have access to 200+ models.`);
568
+ addMsg("info", `Switch with: /model anthropic/claude-sonnet-4`);
569
+ setLoading(false);
570
+ })
571
+ .catch((err: any) => {
572
+ addMsg("error", `OAuth failed: ${err.message}`);
573
+ setLoading(false);
574
+ });
575
+ } else if (selected.id === "anthropic") {
576
+ addMsg("info", "Starting Anthropic setup-token flow...");
577
+ setLoading(true);
578
+ setSpinnerMsg("Waiting for Claude Code auth...");
579
+ anthropicSetupToken((msg: string) => addMsg("info", msg))
580
+ .then((cred) => {
581
+ addMsg("info", `✅ Anthropic authenticated! (${cred.label})`);
582
+ setLoading(false);
583
+ })
584
+ .catch((err: any) => {
585
+ addMsg("error", `Anthropic auth failed: ${err.message}`);
586
+ setLoading(false);
587
+ });
588
+ } else if (selected.id === "openai") {
589
+ const imported = importCodexToken((msg: string) => addMsg("info", msg));
590
+ if (imported) {
591
+ addMsg("info", `✅ Imported Codex credentials! (${imported.label})`);
592
+ } else {
593
+ addMsg("info", "No Codex CLI found. Run: codemaxxing auth api-key openai <your-key>");
594
+ }
595
+ } else if (selected.id === "qwen") {
596
+ const imported = importQwenToken((msg: string) => addMsg("info", msg));
597
+ if (imported) {
598
+ addMsg("info", `✅ Imported Qwen credentials! (${imported.label})`);
599
+ } else {
600
+ addMsg("info", "No Qwen CLI found. Run: codemaxxing auth api-key qwen <your-key>");
601
+ }
602
+ } else if (selected.id === "copilot") {
603
+ addMsg("info", "Starting GitHub Copilot device flow...");
604
+ setLoading(true);
605
+ setSpinnerMsg("Waiting for GitHub authorization...");
606
+ copilotDeviceFlow((msg: string) => addMsg("info", msg))
607
+ .then(() => {
608
+ addMsg("info", `✅ GitHub Copilot authenticated!`);
609
+ setLoading(false);
610
+ })
611
+ .catch((err: any) => {
612
+ addMsg("error", `Copilot auth failed: ${err.message}`);
613
+ setLoading(false);
614
+ });
615
+ } else {
616
+ addMsg("info", `Run: codemaxxing auth api-key ${selected.id} <your-key>\n Get key at: ${selected.consoleUrl ?? selected.baseUrl}`);
617
+ }
618
+ return;
619
+ }
620
+ if (key.escape) {
621
+ setLoginPicker(false);
622
+ return;
623
+ }
624
+ return;
625
+ }
626
+
560
627
  // Theme picker navigation
561
628
  if (themePicker) {
562
629
  const themeKeys = listThemes();