@kenkaiiii/ggcoder 4.3.223 → 4.3.225

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 (93) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/auth.d.ts +4 -0
  3. package/dist/cli/auth.d.ts.map +1 -0
  4. package/dist/cli/auth.js +344 -0
  5. package/dist/cli/auth.js.map +1 -0
  6. package/dist/cli/pixel.d.ts +27 -0
  7. package/dist/cli/pixel.d.ts.map +1 -0
  8. package/dist/cli/pixel.js +103 -0
  9. package/dist/cli/pixel.js.map +1 -0
  10. package/dist/cli/shared.d.ts +13 -0
  11. package/dist/cli/shared.d.ts.map +1 -0
  12. package/dist/cli/shared.js +82 -0
  13. package/dist/cli/shared.js.map +1 -0
  14. package/dist/cli.d.ts.map +1 -1
  15. package/dist/cli.js +15 -544
  16. package/dist/cli.js.map +1 -1
  17. package/dist/config.js +1 -1
  18. package/dist/config.js.map +1 -1
  19. package/dist/core/compaction/compactor.test.js +2 -2
  20. package/dist/core/compaction/token-estimator.test.js +1 -1
  21. package/dist/core/model-registry.d.ts +2 -2
  22. package/dist/core/model-registry.js +4 -4
  23. package/dist/core/model-registry.js.map +1 -1
  24. package/dist/core/model-registry.test.js +1 -1
  25. package/dist/core/model-registry.test.js.map +1 -1
  26. package/dist/core/runtime-mode.js +1 -1
  27. package/dist/core/runtime-mode.js.map +1 -1
  28. package/dist/core/settings-manager.d.ts +3 -2
  29. package/dist/core/settings-manager.d.ts.map +1 -1
  30. package/dist/core/settings-manager.js +1 -6
  31. package/dist/core/settings-manager.js.map +1 -1
  32. package/dist/system-prompt.js +2 -2
  33. package/dist/system-prompt.js.map +1 -1
  34. package/dist/tools/bash.d.ts.map +1 -1
  35. package/dist/tools/bash.js +2 -1
  36. package/dist/tools/bash.js.map +1 -1
  37. package/dist/tools/plan-mode.test.js +13 -1
  38. package/dist/tools/plan-mode.test.js.map +1 -1
  39. package/dist/tools/read-only-bash.d.ts +13 -0
  40. package/dist/tools/read-only-bash.d.ts.map +1 -0
  41. package/dist/tools/read-only-bash.js +155 -0
  42. package/dist/tools/read-only-bash.js.map +1 -0
  43. package/dist/tools/read-only-bash.test.d.ts +2 -0
  44. package/dist/tools/read-only-bash.test.d.ts.map +1 -0
  45. package/dist/tools/read-only-bash.test.js +47 -0
  46. package/dist/tools/read-only-bash.test.js.map +1 -0
  47. package/dist/ui/App.d.ts.map +1 -1
  48. package/dist/ui/App.js +105 -1034
  49. package/dist/ui/App.js.map +1 -1
  50. package/dist/ui/components/Footer.d.ts +2 -2
  51. package/dist/ui/components/Footer.js +8 -8
  52. package/dist/ui/components/Footer.js.map +1 -1
  53. package/dist/ui/components/index.d.ts +3 -0
  54. package/dist/ui/components/index.d.ts.map +1 -1
  55. package/dist/ui/components/index.js +3 -0
  56. package/dist/ui/components/index.js.map +1 -1
  57. package/dist/ui/hooks/useContextCompaction.d.ts +41 -0
  58. package/dist/ui/hooks/useContextCompaction.d.ts.map +1 -0
  59. package/dist/ui/hooks/useContextCompaction.js +149 -0
  60. package/dist/ui/hooks/useContextCompaction.js.map +1 -0
  61. package/dist/ui/hooks/useGoalOrchestration.d.ts +81 -0
  62. package/dist/ui/hooks/useGoalOrchestration.d.ts.map +1 -0
  63. package/dist/ui/hooks/useGoalOrchestration.js +745 -0
  64. package/dist/ui/hooks/useGoalOrchestration.js.map +1 -0
  65. package/dist/ui/hooks/useModeState.d.ts +61 -0
  66. package/dist/ui/hooks/useModeState.d.ts.map +1 -0
  67. package/dist/ui/hooks/useModeState.js +86 -0
  68. package/dist/ui/hooks/useModeState.js.map +1 -0
  69. package/dist/ui/hooks/usePixelFixFlow.d.ts +57 -0
  70. package/dist/ui/hooks/usePixelFixFlow.d.ts.map +1 -0
  71. package/dist/ui/hooks/usePixelFixFlow.js +102 -0
  72. package/dist/ui/hooks/usePixelFixFlow.js.map +1 -0
  73. package/dist/ui/hooks/useSessionPersistence.d.ts +34 -0
  74. package/dist/ui/hooks/useSessionPersistence.d.ts.map +1 -0
  75. package/dist/ui/hooks/useSessionPersistence.js +67 -0
  76. package/dist/ui/hooks/useSessionPersistence.js.map +1 -0
  77. package/dist/ui/hooks/useTranscriptHistory.d.ts +30 -16
  78. package/dist/ui/hooks/useTranscriptHistory.d.ts.map +1 -1
  79. package/dist/ui/hooks/useTranscriptHistory.js +13 -15
  80. package/dist/ui/hooks/useTranscriptHistory.js.map +1 -1
  81. package/dist/ui/login.js +1 -1
  82. package/dist/ui/terminal-history.test.js +60 -0
  83. package/dist/ui/terminal-history.test.js.map +1 -1
  84. package/dist/ui/thinking-level-cycle.test.js +23 -3
  85. package/dist/ui/thinking-level-cycle.test.js.map +1 -1
  86. package/dist/ui/thinking-level.d.ts.map +1 -1
  87. package/dist/ui/thinking-level.js +30 -1
  88. package/dist/ui/thinking-level.js.map +1 -1
  89. package/dist/ui/transcript/spacing.d.ts +31 -19
  90. package/dist/ui/transcript/spacing.d.ts.map +1 -1
  91. package/dist/ui/transcript/spacing.js +16 -3
  92. package/dist/ui/transcript/spacing.js.map +1 -1
  93. package/package.json +24 -4
package/dist/cli.js CHANGED
@@ -45,14 +45,11 @@ import { fileURLToPath } from "node:url";
45
45
  import { parseArgs } from "node:util";
46
46
  import fs from "node:fs";
47
47
  import readline from "node:readline/promises";
48
- import { execFile } from "node:child_process";
49
- import { createRequire } from "node:module";
50
48
  import { renderApp } from "./ui/render.js";
51
49
  import { runJsonMode } from "./modes/json-mode.js";
52
50
  import { runRpcMode } from "./modes/rpc-mode.js";
53
51
  import { runServeMode } from "./modes/serve-mode.js";
54
52
  import { runAgentHomeMode } from "./modes/agent-home-mode.js";
55
- import { renderLoginSelector } from "./ui/login.js";
56
53
  import { renderSessionSelector } from "./ui/sessions.js";
57
54
  import { segmentDisplayText, stripDoneMarkers } from "./utils/plan-steps.js";
58
55
  import { formatUserError } from "./utils/error-handler.js";
@@ -70,62 +67,23 @@ import { createCompactedSessionCheckpoint, formatRestoreInfoText, getRestoredMes
70
67
  import { setEstimatorModel } from "./core/compaction/token-estimator.js";
71
68
  import { getContextWindow, getDefaultModel, getMaxThinkingLevel, getModel, } from "./core/model-registry.js";
72
69
  import { MCPClientManager, getMCPServers } from "./core/mcp/index.js";
70
+ import { runPixel } from "./cli/pixel.js";
71
+ import { runLogin, runLogout, runDoctor } from "./cli/auth.js";
72
+ import { CLI_VERSION, LOGO_LINES, clearVisibleScreen, displayName, gradientLine, requireInteractiveTTY, } from "./cli/shared.js";
73
73
  import { discoverAgents } from "./core/agents.js";
74
74
  import { discoverSkills } from "./core/skills.js";
75
75
  import path from "node:path";
76
- import { loginAnthropic } from "./core/oauth/anthropic.js";
77
- import { loginOpenAI } from "./core/oauth/openai.js";
78
- import { loginGemini } from "./core/oauth/gemini.js";
79
76
  import chalk from "chalk";
80
77
  import { checkAndAutoUpdate } from "./core/auto-update.js";
81
78
  import { parseGoalSyntheticEvent } from "./ui/goal-events.js";
82
79
  import { routeCliCommandInput } from "./cli/command-routing.js";
83
- const _require = createRequire(import.meta.url);
84
- const CLI_VERSION = _require("../package.json").version;
85
- const THINKING_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
80
+ const THINKING_LEVELS = new Set(["low", "medium", "high", "xhigh", "max"]);
86
81
  export function parseThinkingLevel(value) {
87
82
  if (value === undefined)
88
83
  return undefined;
89
84
  if (THINKING_LEVELS.has(value))
90
85
  return value;
91
- throw new Error(`Invalid --thinking value "${value}". Expected low, medium, high, or xhigh.`);
92
- }
93
- // ── Logo + gradient (mirrors Banner.tsx) ────────────────────────────
94
- const LOGO_LINES = [
95
- " \u2584\u2580\u2580\u2580 \u2584\u2580\u2580\u2580",
96
- " \u2588 \u2580\u2588 \u2588 \u2580\u2588",
97
- " \u2580\u2584\u2584\u2580 \u2580\u2584\u2584\u2580",
98
- ];
99
- const GRADIENT = [
100
- "#60a5fa",
101
- "#6da1f9",
102
- "#7a9df7",
103
- "#8799f5",
104
- "#9495f3",
105
- "#a18ff1",
106
- "#a78bfa",
107
- "#a18ff1",
108
- "#9495f3",
109
- "#8799f5",
110
- "#7a9df7",
111
- "#6da1f9",
112
- ];
113
- function gradientLine(text) {
114
- let result = "";
115
- let colorIdx = 0;
116
- for (const ch of text) {
117
- if (ch === " ") {
118
- result += ch;
119
- }
120
- else {
121
- result += chalk.hex(GRADIENT[colorIdx % GRADIENT.length])(ch);
122
- colorIdx++;
123
- }
124
- }
125
- return result;
126
- }
127
- function clearVisibleScreen() {
128
- process.stdout.write("\x1b[2J\x1b[H");
86
+ throw new Error(`Invalid --thinking value "${value}". Expected low, medium, high, xhigh, or max.`);
129
87
  }
130
88
  function printHelp() {
131
89
  // Clear the visible viewport for a clean look without erasing scrollback.
@@ -178,7 +136,7 @@ function printHelp() {
178
136
  ["--model <name>", "Model to use (e.g. claude-sonnet-4-6, gpt-5.5)"],
179
137
  ["--max-turns <n>", "Maximum agent turns per prompt"],
180
138
  ["--system-prompt <text>", "Override the system prompt"],
181
- ["--thinking <level>", "Enable thinking level (low, medium, high, xhigh)"],
139
+ ["--thinking <level>", "Enable thinking level (low, medium, high, xhigh, max)"],
182
140
  ["--resume <id>", "Resume a session by id"],
183
141
  ["--json", "JSON output mode (for sub-agents)"],
184
142
  ["--rpc", "JSON-RPC mode (for IDE integrations)"],
@@ -227,7 +185,7 @@ function createCliSubcommandHandlers() {
227
185
  });
228
186
  };
229
187
  return {
230
- pixel: () => runWithStandardErrorHandling(runPixel, true),
188
+ pixel: () => runWithStandardErrorHandling(() => runPixel({ runInkTUI }), true),
231
189
  login: () => runWithStandardErrorHandling(runLogin),
232
190
  logout: () => runWithStandardErrorHandling(runLogout),
233
191
  sessions: () => runWithStandardErrorHandling(runSessions),
@@ -288,7 +246,7 @@ function main() {
288
246
  if (values.json) {
289
247
  const message = positionals[0] ?? "";
290
248
  const jsonProvider = (values.provider ?? "anthropic");
291
- const jsonModel = values.model ?? "claude-opus-4-7";
249
+ const jsonModel = values.model ?? "claude-opus-4-8";
292
250
  const maxTurns = values["max-turns"] ? parseInt(values["max-turns"], 10) : undefined;
293
251
  const systemPrompt = values["system-prompt"];
294
252
  const promptCacheKey = values["prompt-cache-key"];
@@ -312,7 +270,7 @@ function main() {
312
270
  // RPC mode — headless JSON-over-stdio for IDE integrations
313
271
  if (values.rpc) {
314
272
  const rpcProvider = (values.provider ?? "anthropic");
315
- const rpcModel = values.model ?? "claude-opus-4-7";
273
+ const rpcModel = values.model ?? "claude-opus-4-8";
316
274
  const systemPrompt = values["system-prompt"];
317
275
  const cwd = process.cwd();
318
276
  runRpcMode({
@@ -345,7 +303,7 @@ function main() {
345
303
  return "deepseek-v4-pro";
346
304
  if (p === "openrouter")
347
305
  return "qwen/qwen3.6-plus";
348
- return "claude-opus-4-7";
306
+ return "claude-opus-4-8";
349
307
  }
350
308
  const model = saved.model ?? getHardcodedDefault(provider);
351
309
  const thinkingLevel = saved.thinkingEnabled
@@ -370,18 +328,6 @@ function main() {
370
328
  });
371
329
  }
372
330
  // ── Ink TUI ───────────────────────────────────────────────
373
- /**
374
- * Bail with a friendly message if stdin isn't a TTY. Ink's raw-mode crash is
375
- * cryptic; this catches the common case (piped stdin, API shells, CI).
376
- */
377
- function requireInteractiveTTY() {
378
- if (process.stdin.isTTY)
379
- return;
380
- process.stderr.write(chalk.red("ggcoder needs an interactive terminal — your stdin isn't a TTY.\n") +
381
- chalk.hex("#6b7280")("Run ggcoder directly in your terminal (not piped or through an API shell). " +
382
- 'For headless use try "ggcoder --json \'<prompt>\'" or "ggcoder --rpc".\n'));
383
- process.exit(1);
384
- }
385
331
  async function runInkTUI(opts) {
386
332
  requireInteractiveTTY();
387
333
  const { cwd } = opts;
@@ -652,341 +598,6 @@ async function runInkTUI(opts) {
652
598
  });
653
599
  closeLogger();
654
600
  }
655
- // ── Login ──────────────────────────────────────────────────
656
- async function runLogin() {
657
- requireInteractiveTTY();
658
- clearVisibleScreen();
659
- const paths = await ensureAppDirs();
660
- initLogger(paths.logFile, { version: CLI_VERSION });
661
- log("INFO", "auth", "Login flow started");
662
- const authStorage = new AuthStorage();
663
- await authStorage.load();
664
- // Phase 1: Ink-based provider selector
665
- const provider = await renderLoginSelector(CLI_VERSION);
666
- if (!provider) {
667
- console.log(chalk.hex("#6b7280")("Login cancelled."));
668
- return;
669
- }
670
- console.log(chalk.hex("#60a5fa").bold("\nLogging in to ") +
671
- chalk.hex("#a78bfa")(displayName(provider)) +
672
- chalk.hex("#60a5fa").bold("...\n"));
673
- // Phase 2: OAuth flow (readline needed for Anthropic code paste)
674
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
675
- try {
676
- const callbacks = {
677
- onOpenUrl: (url) => {
678
- console.log(chalk.hex("#60a5fa").bold("Opening browser..."));
679
- openBrowser(url);
680
- console.log(chalk.hex("#6b7280")("\nIf the browser didn't open, visit:\n") +
681
- chalk.hex("#6b7280")(url) +
682
- "\n");
683
- },
684
- onPromptCode: async (message) => {
685
- return rl.question(message + " ");
686
- },
687
- onStatus: (message) => {
688
- console.log(chalk.hex("#6b7280")(message));
689
- },
690
- };
691
- let creds;
692
- if (provider === "glm" ||
693
- provider === "moonshot" ||
694
- provider === "xiaomi" ||
695
- provider === "minimax" ||
696
- provider === "deepseek" ||
697
- provider === "openrouter") {
698
- const keyLabel = provider === "glm"
699
- ? "Z.AI"
700
- : provider === "xiaomi"
701
- ? "Xiaomi MiMo"
702
- : provider === "minimax"
703
- ? "MiniMax"
704
- : provider === "deepseek"
705
- ? "DeepSeek"
706
- : provider === "openrouter"
707
- ? "OpenRouter"
708
- : "Moonshot";
709
- const apiKey = await rl.question(chalk.hex("#60a5fa")(`Paste your ${keyLabel} API key: `));
710
- if (!apiKey.trim()) {
711
- console.log(chalk.hex("#ef4444")("No API key provided. Login cancelled."));
712
- return;
713
- }
714
- creds = {
715
- accessToken: apiKey.trim(),
716
- refreshToken: "",
717
- expiresAt: Date.now() + 365 * 24 * 60 * 60 * 1000 * 100, // ~100 years
718
- ...(provider === "xiaomi" ? { baseUrl: "https://token-plan-sgp.xiaomimimo.com/v1" } : {}),
719
- };
720
- }
721
- else {
722
- creds =
723
- provider === "anthropic"
724
- ? await loginAnthropic(callbacks)
725
- : provider === "gemini"
726
- ? await loginGemini(callbacks)
727
- : await loginOpenAI(callbacks);
728
- }
729
- await authStorage.setCredentials(provider, creds);
730
- log("INFO", "auth", `Login succeeded for ${displayName(provider)}`);
731
- console.log(chalk.hex("#4ade80")(`\n✓ Logged in to ${displayName(provider)} successfully!`));
732
- }
733
- finally {
734
- rl.close();
735
- closeLogger();
736
- }
737
- }
738
- // ── Doctor ─────────────────────────────────────────────────
739
- async function runDoctor() {
740
- clearVisibleScreen();
741
- const os = await import("node:os");
742
- const fsP = await import("node:fs/promises");
743
- const dim = chalk.hex("#6b7280");
744
- const primary = chalk.hex("#60a5fa");
745
- const accent = chalk.hex("#a78bfa");
746
- const good = chalk.hex("#4ade80");
747
- const warn = chalk.hex("#fbbf24");
748
- const bad = chalk.hex("#ef4444");
749
- // ── Banner ──────────────────────────────────────────────────
750
- const LOGO = LOGO_LINES;
751
- const GAP = " ";
752
- console.log();
753
- console.log(` ${gradientLine(LOGO[0])}${GAP}` +
754
- primary.bold("GG Coder") +
755
- dim(` v${CLI_VERSION}`) +
756
- dim(" · By ") +
757
- chalk.white.bold("Ken Kai"));
758
- console.log(` ${gradientLine(LOGO[1])}${GAP}` + accent("Doctor"));
759
- console.log(` ${gradientLine(LOGO[2])}${GAP}` + dim("Diagnose & Fix"));
760
- console.log();
761
- const home = os.homedir();
762
- const ggDir = path.join(home, ".gg");
763
- const authFile = path.join(ggDir, "auth.json");
764
- const lockFile = authFile + ".lock";
765
- const myUid = process.getuid();
766
- let fixed = 0;
767
- // ── Environment ─────────────────────────────────────────────
768
- console.log(accent(" Environment\n"));
769
- console.log(dim(` Home: ${home}`));
770
- console.log(dim(` $HOME: ${process.env.HOME ?? "(not set)"}`));
771
- console.log(dim(` Node.js: ${process.version}`));
772
- console.log(dim(` Platform: ${process.platform} ${process.arch}`));
773
- console.log(dim(` UID: ${myUid} EUID: ${process.geteuid()}`));
774
- if (process.env.HOME && process.env.HOME !== home) {
775
- console.log(warn("\n ⚠ $HOME differs from os.homedir() — this can cause auth mismatches"));
776
- }
777
- if (myUid !== process.geteuid()) {
778
- console.log(warn(" ⚠ uid ≠ euid — running with elevated privileges (sudo?)"));
779
- console.log(dim(" Running ggcoder with sudo can cause ownership issues."));
780
- console.log(dim(" Use without sudo, or fix after: sudo chown -R $(whoami) ~/.gg"));
781
- }
782
- console.log();
783
- // ── Config Directory ────────────────────────────────────────
784
- console.log(accent(" Config Directory\n"));
785
- try {
786
- const stat = await fsP.stat(ggDir);
787
- const mode = stat.mode & 0o777;
788
- console.log(dim(` Path: ${ggDir}`));
789
- console.log(dim(` Mode: 0o${mode.toString(8)} UID: ${stat.uid}`));
790
- // Fix ownership
791
- if (stat.uid !== myUid) {
792
- console.log(warn(` ⚠ Owned by uid ${stat.uid}, expected ${myUid}`));
793
- try {
794
- await fsP.chown(ggDir, myUid, process.getgid());
795
- console.log(good(" ✓ Fixed directory ownership"));
796
- fixed++;
797
- }
798
- catch {
799
- console.log(bad(` ✗ Cannot fix — try: sudo chown -R $(whoami) ${ggDir}`));
800
- }
801
- }
802
- // Fix permissions (should be 0o700)
803
- if (mode !== 0o700) {
804
- try {
805
- await fsP.chmod(ggDir, 0o700);
806
- console.log(good(" ✓ Fixed directory permissions → 0o700"));
807
- fixed++;
808
- }
809
- catch {
810
- console.log(bad(` ✗ Cannot fix — try: chmod 700 ${ggDir}`));
811
- }
812
- }
813
- }
814
- catch {
815
- console.log(warn(` ${ggDir} missing — creating...`));
816
- try {
817
- await fsP.mkdir(ggDir, { recursive: true, mode: 0o700 });
818
- console.log(good(` ✓ Created ${ggDir}`));
819
- fixed++;
820
- }
821
- catch (mkErr) {
822
- console.log(bad(` ✗ Cannot create: ${mkErr instanceof Error ? mkErr.message : String(mkErr)}`));
823
- console.log();
824
- return;
825
- }
826
- }
827
- console.log();
828
- // ── Lock File ───────────────────────────────────────────────
829
- try {
830
- const lockStat = await fsP.stat(lockFile);
831
- const ageMs = Date.now() - lockStat.mtimeMs;
832
- console.log(accent(" Lock File\n"));
833
- console.log(warn(` ⚠ Stale lock found (age: ${Math.round(ageMs / 1000)}s)`));
834
- await fsP.unlink(lockFile);
835
- console.log(good(" ✓ Removed"));
836
- fixed++;
837
- console.log();
838
- }
839
- catch {
840
- // No lock file — good, skip section entirely
841
- }
842
- // ── Auth File ───────────────────────────────────────────────
843
- console.log(accent(" Auth File\n"));
844
- let authData = null;
845
- let authNeedsRewrite = false;
846
- try {
847
- const stat = await fsP.stat(authFile);
848
- const mode = stat.mode & 0o777;
849
- console.log(dim(` Path: ${authFile}`));
850
- console.log(dim(` Size: ${stat.size} bytes Mode: 0o${mode.toString(8)} UID: ${stat.uid}`));
851
- // Fix ownership
852
- if (stat.uid !== myUid) {
853
- console.log(warn(` ⚠ Owned by uid ${stat.uid}, expected ${myUid}`));
854
- try {
855
- await fsP.chown(authFile, myUid, process.getgid());
856
- console.log(good(" ✓ Fixed file ownership"));
857
- fixed++;
858
- }
859
- catch {
860
- console.log(bad(` ✗ Cannot fix — try: sudo chown $(whoami) ${authFile}`));
861
- }
862
- }
863
- // Fix permissions (should be 0o600)
864
- if (mode !== 0o600) {
865
- try {
866
- await fsP.chmod(authFile, 0o600);
867
- console.log(good(" ✓ Fixed file permissions → 0o600"));
868
- fixed++;
869
- }
870
- catch {
871
- console.log(bad(` ✗ Cannot fix — try: chmod 600 ${authFile}`));
872
- }
873
- }
874
- // Try to read and parse
875
- try {
876
- const content = await fsP.readFile(authFile, "utf-8");
877
- try {
878
- authData = JSON.parse(content);
879
- }
880
- catch {
881
- console.log(bad(" ✗ Invalid JSON — backing up and resetting"));
882
- const backupName = `auth.json.corrupt.${Date.now()}`;
883
- await fsP.copyFile(authFile, path.join(ggDir, backupName));
884
- await fsP.writeFile(authFile, "{}", { encoding: "utf-8", mode: 0o600 });
885
- console.log(good(` ✓ Corrupt file backed up as ${backupName}`));
886
- console.log(dim(' Run "ggcoder login" to re-authenticate'));
887
- authData = {};
888
- fixed++;
889
- }
890
- }
891
- catch (readErr) {
892
- const code = readErr.code;
893
- if (code === "EACCES") {
894
- console.log(bad(" ✗ Permission denied reading auth.json"));
895
- console.log(dim(` Try: sudo chown $(whoami) ${authFile} && chmod 600 ${authFile}`));
896
- }
897
- else {
898
- console.log(bad(` ✗ Read error: ${readErr instanceof Error ? readErr.message : String(readErr)}`));
899
- }
900
- }
901
- }
902
- catch {
903
- console.log(dim(` Path: ${authFile}`));
904
- console.log(warn(' Not found — run "ggcoder login" to authenticate'));
905
- }
906
- console.log();
907
- // ── Credentials ─────────────────────────────────────────────
908
- if (authData && Object.keys(authData).length > 0) {
909
- console.log(accent(" Credentials\n"));
910
- for (const p of Object.keys(authData)) {
911
- const cred = authData[p];
912
- if (!cred || typeof cred !== "object") {
913
- console.log(bad(` ✗ ${p}: invalid entry — removing`));
914
- delete authData[p];
915
- authNeedsRewrite = true;
916
- fixed++;
917
- continue;
918
- }
919
- if (!cred.accessToken || typeof cred.accessToken !== "string") {
920
- console.log(bad(` ✗ ${p}: missing accessToken — removing`));
921
- delete authData[p];
922
- authNeedsRewrite = true;
923
- fixed++;
924
- continue;
925
- }
926
- const token = String(cred.accessToken);
927
- const masked = token.slice(0, 8) + "..." + token.slice(-4);
928
- const expires = typeof cred.expiresAt === "number" ? new Date(cred.expiresAt).toISOString() : "unknown";
929
- const expired = typeof cred.expiresAt === "number" && Date.now() > cred.expiresAt;
930
- if (expired) {
931
- console.log(warn(` ⚠ ${p}: ${masked} expired ${expires}`));
932
- }
933
- else {
934
- console.log(good(` ✓ ${p}: ${masked} expires ${expires}`));
935
- }
936
- }
937
- if (authNeedsRewrite) {
938
- try {
939
- await fsP.writeFile(authFile, JSON.stringify(authData, null, 2), {
940
- encoding: "utf-8",
941
- mode: 0o600,
942
- });
943
- console.log(good(" ✓ Cleaned up auth.json"));
944
- }
945
- catch {
946
- console.log(bad(" ✗ Failed to write cleaned auth.json"));
947
- }
948
- }
949
- console.log();
950
- }
951
- // ── Temp Files ──────────────────────────────────────────────
952
- try {
953
- const entries = await fsP.readdir(ggDir);
954
- const tmpFiles = entries.filter((e) => e.startsWith("auth.json.") && e.endsWith(".tmp"));
955
- if (tmpFiles.length > 0) {
956
- console.log(accent(" Temp Files\n"));
957
- console.log(warn(` ⚠ ${tmpFiles.length} orphaned temp file(s) from interrupted writes`));
958
- for (const tmp of tmpFiles) {
959
- await fsP.unlink(path.join(ggDir, tmp)).catch(() => { });
960
- }
961
- console.log(good(` ✓ Removed ${tmpFiles.length} file(s)`));
962
- fixed++;
963
- console.log();
964
- }
965
- }
966
- catch {
967
- // Can't read directory — already flagged above
968
- }
969
- // ── Summary ─────────────────────────────────────────────────
970
- if (fixed > 0) {
971
- console.log(good(` ✓ Fixed ${fixed} issue${fixed > 1 ? "s" : ""}.`));
972
- }
973
- else {
974
- console.log(good(" ✓ Everything looks good."));
975
- }
976
- console.log();
977
- }
978
- // ── Logout ─────────────────────────────────────────────────
979
- async function runLogout() {
980
- const paths = await ensureAppDirs();
981
- initLogger(paths.logFile, { version: CLI_VERSION });
982
- log("INFO", "auth", "Logout requested");
983
- const authStorage = new AuthStorage();
984
- await authStorage.load();
985
- await authStorage.clearAll();
986
- log("INFO", "auth", "Logout succeeded");
987
- closeLogger();
988
- console.log(chalk.green("Logged out successfully."));
989
- }
990
601
  // ── Sessions ──────────────────────────────────────────────
991
602
  async function runSessions() {
992
603
  requireInteractiveTTY();
@@ -1016,7 +627,7 @@ async function runSessions() {
1016
627
  return "MiniMax-M2.7";
1017
628
  if (p === "deepseek")
1018
629
  return "deepseek-v4-pro";
1019
- return "claude-opus-4-7";
630
+ return "claude-opus-4-8";
1020
631
  }
1021
632
  const model = saved2.model ?? getDefault(provider);
1022
633
  const thinkingLevel = saved2.thinkingEnabled
@@ -1248,32 +859,16 @@ async function runAgentHomeLogin() {
1248
859
  log("INFO", "agent-home", "Agent Home login started");
1249
860
  const existing = await loadAgentHomeConfig();
1250
861
  // Banner
1251
- const LOGO = [
1252
- " \u2584\u2580\u2580\u2580 \u2584\u2580\u2580\u2580",
1253
- " \u2588 \u2580\u2588 \u2588 \u2580\u2588",
1254
- " \u2580\u2584\u2584\u2580 \u2580\u2584\u2584\u2580",
1255
- ];
1256
- function gradientTextLocal(text) {
1257
- let colorIdx = 0;
1258
- return text
1259
- .split("")
1260
- .map((ch) => {
1261
- if (ch === " ")
1262
- return ch;
1263
- const color = GRADIENT[colorIdx++ % GRADIENT.length];
1264
- return chalk.hex(color)(ch);
1265
- })
1266
- .join("");
1267
- }
862
+ const LOGO = LOGO_LINES;
1268
863
  const GAP = " ";
1269
864
  console.log();
1270
- console.log(` ${gradientTextLocal(LOGO[0])}${GAP}` +
865
+ console.log(` ${gradientLine(LOGO[0])}${GAP}` +
1271
866
  chalk.hex("#60a5fa").bold("GG Coder") +
1272
867
  chalk.hex("#6b7280")(` v${CLI_VERSION}`) +
1273
868
  chalk.hex("#6b7280")(" \u00b7 By ") +
1274
869
  chalk.white.bold("Ken Kai"));
1275
- console.log(` ${gradientTextLocal(LOGO[1])}${GAP}` + chalk.hex("#a78bfa")("Agent Home Setup"));
1276
- console.log(` ${gradientTextLocal(LOGO[2])}${GAP}` + chalk.hex("#6b7280")("Remote Control via iOS"));
870
+ console.log(` ${gradientLine(LOGO[1])}${GAP}` + chalk.hex("#a78bfa")("Agent Home Setup"));
871
+ console.log(` ${gradientLine(LOGO[2])}${GAP}` + chalk.hex("#6b7280")("Remote Control via iOS"));
1277
872
  console.log();
1278
873
  if (existing) {
1279
874
  console.log(chalk.hex("#6b7280")(" Current config:\n") +
@@ -1355,105 +950,6 @@ async function runAgentHome() {
1355
950
  });
1356
951
  }
1357
952
  // ── Pixel ──────────────────────────────────────────────────
1358
- async function runPixel() {
1359
- const sub = process.argv[3];
1360
- const rest = process.argv.slice(4);
1361
- if (sub === "install") {
1362
- const { runPixelInstall } = await import("./core/pixel.js");
1363
- const opts = parsePixelInstallArgs(rest);
1364
- await runPixelInstall(opts);
1365
- return;
1366
- }
1367
- if (sub === "fix") {
1368
- const errorId = rest[0];
1369
- if (!errorId) {
1370
- process.stderr.write("Usage: ggcoder pixel fix <error_id>\n");
1371
- process.exit(1);
1372
- }
1373
- const { fixError } = await import("./core/pixel-fix.js");
1374
- const result = await fixError(errorId);
1375
- if (result.outcome === "awaiting_review") {
1376
- console.log(chalk.hex("#4ade80")(`✓ ${result.reason}`));
1377
- }
1378
- else {
1379
- console.log(chalk.hex("#ef4444")(`✗ ${result.reason}`));
1380
- process.exit(1);
1381
- }
1382
- return;
1383
- }
1384
- if (sub === "run") {
1385
- const { runQueue } = await import("./core/pixel-fix.js");
1386
- const result = await runQueue();
1387
- console.log(chalk.bold(`${result.fixed} fixed · ${result.failed} failed · ${result.total} total`));
1388
- if (result.failed > 0)
1389
- process.exit(1);
1390
- return;
1391
- }
1392
- if (sub === "--help" || sub === "-h") {
1393
- printPixelHelp();
1394
- return;
1395
- }
1396
- if (sub === "list") {
1397
- const { listAllErrors } = await import("./core/pixel.js");
1398
- await listAllErrors();
1399
- return;
1400
- }
1401
- if (sub) {
1402
- process.stderr.write(`Unknown pixel subcommand: ${sub}\n`);
1403
- printPixelHelp();
1404
- process.exit(1);
1405
- }
1406
- // No subcommand → launch the Ink TUI with the pixel overlay open. The fix
1407
- // flow runs through the same agent loop, streaming live in the chat instead
1408
- // of spawning a subprocess.
1409
- // Non-TTY (CI, piped) → fall back to text list.
1410
- if (!process.stdin.isTTY) {
1411
- const { listAllErrors } = await import("./core/pixel.js");
1412
- await listAllErrors();
1413
- return;
1414
- }
1415
- const saved = loadSavedSettings();
1416
- const provider = saved.provider ?? "anthropic";
1417
- const model = saved.model ?? defaultModelFor(provider);
1418
- await runInkTUI({
1419
- provider,
1420
- model,
1421
- cwd: process.cwd(),
1422
- thinkingLevel: saved.thinkingEnabled ? (saved.thinkingLevel ?? "medium") : undefined,
1423
- theme: saved.theme,
1424
- initialOverlay: "pixel",
1425
- });
1426
- }
1427
- function defaultModelFor(p) {
1428
- return getDefaultModel(p).id;
1429
- }
1430
- function parsePixelInstallArgs(args) {
1431
- const out = { skipPackageInstall: false };
1432
- for (let i = 0; i < args.length; i++) {
1433
- const a = args[i];
1434
- if (a === "--ingest-url")
1435
- out.ingestUrl = args[++i];
1436
- else if (a === "--name")
1437
- out.name = args[++i];
1438
- else if (a === "--skip-install")
1439
- out.skipPackageInstall = true;
1440
- }
1441
- return out;
1442
- }
1443
- function printPixelHelp() {
1444
- console.log(`ggcoder pixel — error tracking + auto-fix queue
1445
-
1446
- Usage:
1447
- ggcoder pixel List open errors across every registered project
1448
- ggcoder pixel install Register the current project and wire up the SDK
1449
- ggcoder pixel fix <error_id> Fix one specific error end-to-end
1450
- ggcoder pixel run Auto-fix every open error across all projects
1451
-
1452
- ggcoder pixel install --name <name> Override the project name
1453
- ggcoder pixel install --ingest-url <url> Use a custom backend URL
1454
- ggcoder pixel install --skip-install Don't run the package manager
1455
- `);
1456
- }
1457
953
  // ── Helpers ────────────────────────────────────────────────
1458
954
  /**
1459
955
  * Pick the provider/model to start with. If the preferred provider isn't
@@ -1497,25 +993,6 @@ async function resolveActiveProvider(authStorage, preferred, savedModel) {
1497
993
  const provider = loggedInProviders[0];
1498
994
  return { provider, model: getDefaultModel(provider).id, loggedInProviders };
1499
995
  }
1500
- function displayName(provider) {
1501
- if (provider === "anthropic")
1502
- return "Anthropic";
1503
- if (provider === "xiaomi")
1504
- return "Xiaomi (MiMo)";
1505
- if (provider === "gemini")
1506
- return "Gemini";
1507
- if (provider === "glm")
1508
- return "Z.AI (GLM)";
1509
- if (provider === "moonshot")
1510
- return "Moonshot";
1511
- if (provider === "minimax")
1512
- return "MiniMax";
1513
- if (provider === "deepseek")
1514
- return "DeepSeek";
1515
- if (provider === "openrouter")
1516
- return "OpenRouter";
1517
- return "OpenAI";
1518
- }
1519
996
  function extractText(content) {
1520
997
  if (typeof content === "string")
1521
998
  return content;
@@ -1743,12 +1220,6 @@ export function messagesToHistoryItems(msgs) {
1743
1220
  });
1744
1221
  return items;
1745
1222
  }
1746
- function openBrowser(url) {
1747
- const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1748
- execFile(cmd, [url], () => {
1749
- // Ignore errors — user can copy URL manually
1750
- });
1751
- }
1752
1223
  if (process.argv[1] &&
1753
1224
  fileURLToPath(import.meta.url) === fs.realpathSync(path.resolve(process.argv[1]))) {
1754
1225
  main();