cc-agy 1.0.0 → 1.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.
Files changed (46) hide show
  1. package/assets/kit/apple-touch-icon.png +0 -0
  2. package/assets/kit/cc-agy-app-icon-128.png +0 -0
  3. package/assets/kit/cc-agy-app-icon-32.png +0 -0
  4. package/assets/kit/cc-agy-app-icon-512.png +0 -0
  5. package/assets/kit/cc-agy-app-icon-64.png +0 -0
  6. package/assets/kit/cc-agy-app-icon.svg +45 -0
  7. package/assets/kit/cc-agy-black-128.png +0 -0
  8. package/assets/kit/cc-agy-black-32.png +0 -0
  9. package/assets/kit/cc-agy-black-512.png +0 -0
  10. package/assets/kit/cc-agy-black-64.png +0 -0
  11. package/assets/kit/cc-agy-black.svg +11 -0
  12. package/assets/kit/cc-agy-favicon-128.png +0 -0
  13. package/assets/kit/cc-agy-favicon-32.png +0 -0
  14. package/assets/kit/cc-agy-favicon-512.png +0 -0
  15. package/assets/kit/cc-agy-favicon-64.png +0 -0
  16. package/assets/kit/cc-agy-favicon.svg +45 -0
  17. package/assets/kit/cc-agy-mono-38bdf8-128.png +0 -0
  18. package/assets/kit/cc-agy-mono-38bdf8-32.png +0 -0
  19. package/assets/kit/cc-agy-mono-38bdf8-512.png +0 -0
  20. package/assets/kit/cc-agy-mono-38bdf8-64.png +0 -0
  21. package/assets/kit/cc-agy-mono-38bdf8.svg +11 -0
  22. package/assets/kit/cc-agy-square-128.png +0 -0
  23. package/assets/kit/cc-agy-square-32.png +0 -0
  24. package/assets/kit/cc-agy-square-512.png +0 -0
  25. package/assets/kit/cc-agy-square-64.png +0 -0
  26. package/assets/kit/cc-agy-square.svg +45 -0
  27. package/assets/kit/cc-agy-white-128.png +0 -0
  28. package/assets/kit/cc-agy-white-32.png +0 -0
  29. package/assets/kit/cc-agy-white-512.png +0 -0
  30. package/assets/kit/cc-agy-white-64.png +0 -0
  31. package/assets/kit/cc-agy-white.svg +11 -0
  32. package/assets/kit/favicon-16.png +0 -0
  33. package/assets/kit/favicon-32.png +0 -0
  34. package/assets/kit/favicon-48.png +0 -0
  35. package/assets/kit/favicon.ico +0 -0
  36. package/assets/kit/favicon.svg +45 -0
  37. package/assets/kit/head-snippet.html +5 -0
  38. package/assets/kit/icon-192.png +0 -0
  39. package/assets/kit/icon-512.png +0 -0
  40. package/assets/kit/maskable-512.png +0 -0
  41. package/assets/kit/site.webmanifest +24 -0
  42. package/assets/logo.png +0 -0
  43. package/assets/logo.svg +45 -0
  44. package/bin/cc-agy.js +273 -17
  45. package/package.json +2 -1
  46. package/scripts/patch-combo.py +83 -36
Binary file
@@ -0,0 +1,45 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Claude Code Amber / Terracotta Gradient -->
4
+ <linearGradient id="claudeAmber" x1="0%" y1="100%" x2="100%" y2="0%">
5
+ <stop offset="0%" stop-color="#D97706" />
6
+ <stop offset="100%" stop-color="#F59E0B" />
7
+ </linearGradient>
8
+
9
+ <!-- Antigravity TPU Cyan Gradient -->
10
+ <linearGradient id="agyCyan" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" stop-color="#00F0FF" />
12
+ <stop offset="100%" stop-color="#0284C7" />
13
+ </linearGradient>
14
+
15
+ <!-- Subtle Premium Glow -->
16
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
17
+ <feGaussianBlur stdDeviation="8" result="blur" />
18
+ <feMerge>
19
+ <feMergeNode in="blur" opacity="0.3" />
20
+ <feMergeNode in="SourceGraphic" />
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- PURE TRANSPARENT BACKGROUND -->
26
+
27
+ <!-- Perfectly Centered Scaled Encircled Mark -->
28
+ <g transform="translate(256, 256) scale(1.6) translate(-248, -256)" filter="url(#softGlow)">
29
+ <!-- Claude Code CLI Prompt Chevron -->
30
+ <path d="M 148 180
31
+ L 236 256
32
+ L 148 332
33
+ L 180 360
34
+ L 296 256
35
+ L 180 152 Z"
36
+ fill="url(#claudeAmber)" />
37
+
38
+ <!-- Antigravity Acceleration Node -->
39
+ <polygon points="268,256 348,188 348,324"
40
+ fill="url(#agyCyan)" />
41
+
42
+ <!-- Center Zero-Cost Nexus Flare -->
43
+ <circle cx="256" cy="256" r="10" fill="#FFFFFF" />
44
+ </g>
45
+ </svg>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ <svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="100%" height="100%"><title>cc-agy Logo</title>
2
+
3
+ <!-- Concept 3: Escape Velocity Delta (60 degree equilateral geometry) -->
4
+ <g fill="#000000" fill-rule="evenodd">
5
+ <!-- Outer Delta Frame with exact 60-degree angles -->
6
+ <path d="M 128 45.72 L 224 212 L 176 212 L 128 128.86 L 80 212 L 32 212 Z
7
+ M 128 85 L 152 126.57 L 104 126.57 Z" />
8
+ <!-- Dynamic Forward Agent Vector -->
9
+ <polygon points="108,180 156,180 172,164 156,148 108,148 124,164" />
10
+ </g>
11
+ </svg>
Binary file
Binary file
@@ -0,0 +1,45 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Claude Code Amber / Terracotta Gradient -->
4
+ <linearGradient id="claudeAmber" x1="0%" y1="100%" x2="100%" y2="0%">
5
+ <stop offset="0%" stop-color="#D97706" />
6
+ <stop offset="100%" stop-color="#F59E0B" />
7
+ </linearGradient>
8
+
9
+ <!-- Antigravity TPU Cyan Gradient -->
10
+ <linearGradient id="agyCyan" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" stop-color="#00F0FF" />
12
+ <stop offset="100%" stop-color="#0284C7" />
13
+ </linearGradient>
14
+
15
+ <!-- Subtle Premium Glow -->
16
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
17
+ <feGaussianBlur stdDeviation="8" result="blur" />
18
+ <feMerge>
19
+ <feMergeNode in="blur" opacity="0.3" />
20
+ <feMergeNode in="SourceGraphic" />
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- PURE TRANSPARENT BACKGROUND -->
26
+
27
+ <!-- Perfectly Centered Scaled Encircled Mark -->
28
+ <g transform="translate(256, 256) scale(1.6) translate(-248, -256)" filter="url(#softGlow)">
29
+ <!-- Claude Code CLI Prompt Chevron -->
30
+ <path d="M 148 180
31
+ L 236 256
32
+ L 148 332
33
+ L 180 360
34
+ L 296 256
35
+ L 180 152 Z"
36
+ fill="url(#claudeAmber)" />
37
+
38
+ <!-- Antigravity Acceleration Node -->
39
+ <polygon points="268,256 348,188 348,324"
40
+ fill="url(#agyCyan)" />
41
+
42
+ <!-- Center Zero-Cost Nexus Flare -->
43
+ <circle cx="256" cy="256" r="10" fill="#FFFFFF" />
44
+ </g>
45
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg fill="#38bdf8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="100%" height="100%"><title>cc-agy Logo</title>
2
+
3
+ <!-- Concept 3: Escape Velocity Delta (60 degree equilateral geometry) -->
4
+ <g fill="#38bdf8" fill-rule="evenodd">
5
+ <!-- Outer Delta Frame with exact 60-degree angles -->
6
+ <path d="M 128 45.72 L 224 212 L 176 212 L 128 128.86 L 80 212 L 32 212 Z
7
+ M 128 85 L 152 126.57 L 104 126.57 Z" />
8
+ <!-- Dynamic Forward Agent Vector -->
9
+ <polygon points="108,180 156,180 172,164 156,148 108,148 124,164" />
10
+ </g>
11
+ </svg>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,45 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Claude Code Amber / Terracotta Gradient -->
4
+ <linearGradient id="claudeAmber" x1="0%" y1="100%" x2="100%" y2="0%">
5
+ <stop offset="0%" stop-color="#D97706" />
6
+ <stop offset="100%" stop-color="#F59E0B" />
7
+ </linearGradient>
8
+
9
+ <!-- Antigravity TPU Cyan Gradient -->
10
+ <linearGradient id="agyCyan" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" stop-color="#00F0FF" />
12
+ <stop offset="100%" stop-color="#0284C7" />
13
+ </linearGradient>
14
+
15
+ <!-- Subtle Premium Glow -->
16
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
17
+ <feGaussianBlur stdDeviation="8" result="blur" />
18
+ <feMerge>
19
+ <feMergeNode in="blur" opacity="0.3" />
20
+ <feMergeNode in="SourceGraphic" />
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- PURE TRANSPARENT BACKGROUND -->
26
+
27
+ <!-- Perfectly Centered Scaled Encircled Mark -->
28
+ <g transform="translate(256, 256) scale(1.6) translate(-248, -256)" filter="url(#softGlow)">
29
+ <!-- Claude Code CLI Prompt Chevron -->
30
+ <path d="M 148 180
31
+ L 236 256
32
+ L 148 332
33
+ L 180 360
34
+ L 296 256
35
+ L 180 152 Z"
36
+ fill="url(#claudeAmber)" />
37
+
38
+ <!-- Antigravity Acceleration Node -->
39
+ <polygon points="268,256 348,188 348,324"
40
+ fill="url(#agyCyan)" />
41
+
42
+ <!-- Center Zero-Cost Nexus Flare -->
43
+ <circle cx="256" cy="256" r="10" fill="#FFFFFF" />
44
+ </g>
45
+ </svg>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ <svg fill="#ffffff" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="100%" height="100%"><title>cc-agy Logo</title>
2
+
3
+ <!-- Concept 3: Escape Velocity Delta (60 degree equilateral geometry) -->
4
+ <g fill="#ffffff" fill-rule="evenodd">
5
+ <!-- Outer Delta Frame with exact 60-degree angles -->
6
+ <path d="M 128 45.72 L 224 212 L 176 212 L 128 128.86 L 80 212 L 32 212 Z
7
+ M 128 85 L 152 126.57 L 104 126.57 Z" />
8
+ <!-- Dynamic Forward Agent Vector -->
9
+ <polygon points="108,180 156,180 172,164 156,148 108,148 124,164" />
10
+ </g>
11
+ </svg>
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,45 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Claude Code Amber / Terracotta Gradient -->
4
+ <linearGradient id="claudeAmber" x1="0%" y1="100%" x2="100%" y2="0%">
5
+ <stop offset="0%" stop-color="#D97706" />
6
+ <stop offset="100%" stop-color="#F59E0B" />
7
+ </linearGradient>
8
+
9
+ <!-- Antigravity TPU Cyan Gradient -->
10
+ <linearGradient id="agyCyan" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" stop-color="#00F0FF" />
12
+ <stop offset="100%" stop-color="#0284C7" />
13
+ </linearGradient>
14
+
15
+ <!-- Subtle Premium Glow -->
16
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
17
+ <feGaussianBlur stdDeviation="8" result="blur" />
18
+ <feMerge>
19
+ <feMergeNode in="blur" opacity="0.3" />
20
+ <feMergeNode in="SourceGraphic" />
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- PURE TRANSPARENT BACKGROUND -->
26
+
27
+ <!-- Perfectly Centered Scaled Encircled Mark -->
28
+ <g transform="translate(256, 256) scale(1.6) translate(-248, -256)" filter="url(#softGlow)">
29
+ <!-- Claude Code CLI Prompt Chevron -->
30
+ <path d="M 148 180
31
+ L 236 256
32
+ L 148 332
33
+ L 180 360
34
+ L 296 256
35
+ L 180 152 Z"
36
+ fill="url(#claudeAmber)" />
37
+
38
+ <!-- Antigravity Acceleration Node -->
39
+ <polygon points="268,256 348,188 348,324"
40
+ fill="url(#agyCyan)" />
41
+
42
+ <!-- Center Zero-Cost Nexus Flare -->
43
+ <circle cx="256" cy="256" r="10" fill="#FFFFFF" />
44
+ </g>
45
+ </svg>
@@ -0,0 +1,5 @@
1
+ <link rel="icon" href="/favicon.ico" sizes="48x48">
2
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml">
3
+ <link rel="apple-touch-icon" href="/apple-touch-icon.png">
4
+ <link rel="manifest" href="/site.webmanifest">
5
+ <meta name="theme-color" content="#090D16">
Binary file
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "cc-agy Logo",
3
+ "icons": [
4
+ {
5
+ "src": "/icon-192.png",
6
+ "sizes": "192x192",
7
+ "type": "image/png"
8
+ },
9
+ {
10
+ "src": "/icon-512.png",
11
+ "sizes": "512x512",
12
+ "type": "image/png"
13
+ },
14
+ {
15
+ "src": "/maskable-512.png",
16
+ "sizes": "512x512",
17
+ "type": "image/png",
18
+ "purpose": "maskable"
19
+ }
20
+ ],
21
+ "theme_color": "#090D16",
22
+ "background_color": "#090D16",
23
+ "display": "standalone"
24
+ }
Binary file
@@ -0,0 +1,45 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="100%" height="100%">
2
+ <defs>
3
+ <!-- Claude Code Amber / Terracotta Gradient -->
4
+ <linearGradient id="claudeAmber" x1="0%" y1="100%" x2="100%" y2="0%">
5
+ <stop offset="0%" stop-color="#D97706" />
6
+ <stop offset="100%" stop-color="#F59E0B" />
7
+ </linearGradient>
8
+
9
+ <!-- Antigravity TPU Cyan Gradient -->
10
+ <linearGradient id="agyCyan" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" stop-color="#00F0FF" />
12
+ <stop offset="100%" stop-color="#0284C7" />
13
+ </linearGradient>
14
+
15
+ <!-- Subtle Premium Glow -->
16
+ <filter id="softGlow" x="-20%" y="-20%" width="140%" height="140%">
17
+ <feGaussianBlur stdDeviation="8" result="blur" />
18
+ <feMerge>
19
+ <feMergeNode in="blur" opacity="0.3" />
20
+ <feMergeNode in="SourceGraphic" />
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- PURE TRANSPARENT BACKGROUND -->
26
+
27
+ <!-- Perfectly Centered Scaled Encircled Mark -->
28
+ <g transform="translate(256, 256) scale(1.6) translate(-248, -256)" filter="url(#softGlow)">
29
+ <!-- Claude Code CLI Prompt Chevron -->
30
+ <path d="M 148 180
31
+ L 236 256
32
+ L 148 332
33
+ L 180 360
34
+ L 296 256
35
+ L 180 152 Z"
36
+ fill="url(#claudeAmber)" />
37
+
38
+ <!-- Antigravity Acceleration Node -->
39
+ <polygon points="268,256 348,188 348,324"
40
+ fill="url(#agyCyan)" />
41
+
42
+ <!-- Center Zero-Cost Nexus Flare -->
43
+ <circle cx="256" cy="256" r="10" fill="#FFFFFF" />
44
+ </g>
45
+ </svg>
package/bin/cc-agy.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * cc-agy: Autonomous Self-Healing CLI Wrapper & Gateway Controller
4
- * Seamlessly connects Claude Code to Google Antigravity (Gemini 3.8 Flash High)
4
+ * Seamlessly connects Claude Code to Google Antigravity (Gemini 3.8 Flash High & Claude on TPU)
5
5
  * Author: Farhat Iqbal (@farhatkoka)
6
6
  */
7
7
 
@@ -10,6 +10,7 @@ const fs = require('fs');
10
10
  const path = require('path');
11
11
  const os = require('os');
12
12
  const http = require('http');
13
+ const readline = require('readline');
13
14
 
14
15
  const BOLD = '\x1b[1m';
15
16
  const GREEN = '\x1b[32m';
@@ -17,14 +18,90 @@ const BLUE = '\x1b[34m';
17
18
  const YELLOW = '\x1b[33m';
18
19
  const RED = '\x1b[31m';
19
20
  const CYAN = '\x1b[36m';
21
+ const DIM = '\x1b[2m';
20
22
  const NC = '\x1b[0m';
21
23
 
22
24
  const HOME = os.homedir();
23
25
  const AGY_TOKEN_PATH = path.join(HOME, '.gemini', 'antigravity-cli', 'antigravity-oauth-token');
24
26
  const CLAUDE_SETTINGS_PATH = path.join(HOME, '.claude', 'settings.json');
25
27
  const SYSTEMD_SERVICE_PATH = path.join(HOME, '.config', 'systemd', 'user', 'omniroute.service');
28
+ const CONFIG_DIR = path.join(HOME, '.config', 'cc-agy');
29
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json');
26
30
  const HEALTH_URL = 'http://127.0.0.1:20128/api/monitoring/health';
27
31
 
32
+ const AGY_MODELS = [
33
+ {
34
+ id: 'gemini-3.8-flash-high',
35
+ name: 'Gemini 3.8 Flash High',
36
+ description: 'Google Deep Thinking (TPU v5p Reasoning Engine)',
37
+ aliases: ['1', 'flash', 'high', 'flash-high', 'gemini']
38
+ },
39
+ {
40
+ id: 'gemini-3.8-flash-medium',
41
+ name: 'Gemini 3.8 Flash Medium',
42
+ description: 'Balanced latency & test-time reasoning',
43
+ aliases: ['2', 'medium', 'med', 'flash-medium']
44
+ },
45
+ {
46
+ id: 'gemini-3.8-flash-low',
47
+ name: 'Gemini 3.8 Flash Low',
48
+ description: 'Distilled sub-second speed',
49
+ aliases: ['3', 'low', 'flash-low']
50
+ },
51
+ {
52
+ id: 'claude-sonnet-4-6',
53
+ name: 'Claude Sonnet 4.6 (Thinking)',
54
+ description: 'Anthropic flagship agentic reasoning on TPU',
55
+ aliases: ['4', 'sonnet', 'sonnet-4-6']
56
+ },
57
+ {
58
+ id: 'claude-opus-4-6-thinking',
59
+ name: 'Claude Opus 4.6 (Thinking)',
60
+ description: 'Anthropic maximum depth reasoning',
61
+ aliases: ['5', 'opus', 'opus-4-6', 'opus-thinking']
62
+ },
63
+ {
64
+ id: 'gpt-oss-120b-medium',
65
+ name: 'GPT-OSS 120B (Medium)',
66
+ description: 'Open-weights high-density reasoning',
67
+ aliases: ['6', 'gpt', 'oss', '120b']
68
+ },
69
+ {
70
+ id: 'claude-auto',
71
+ name: 'Claude-Auto Priority Cascade',
72
+ description: 'Dynamic failover: Flash High -> Sonnet 4.6 -> Flash Lite',
73
+ aliases: ['7', 'auto', 'cascade', 'default']
74
+ }
75
+ ];
76
+
77
+ function loadConfig() {
78
+ try {
79
+ if (fs.existsSync(CONFIG_PATH)) {
80
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
81
+ }
82
+ } catch {}
83
+ return { defaultModel: 'gemini-3.8-flash-high' };
84
+ }
85
+
86
+ function saveConfig(cfg) {
87
+ try {
88
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
89
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(cfg, null, 2), 'utf8');
90
+ } catch (err) {
91
+ console.error(`${RED}[-] Failed to persist config:${NC}`, err.message);
92
+ }
93
+ }
94
+
95
+ function resolveModel(query) {
96
+ if (!query) return null;
97
+ const q = query.trim().toLowerCase();
98
+ for (const m of AGY_MODELS) {
99
+ if (m.id.toLowerCase() === q) return m;
100
+ if (m.aliases.includes(q)) return m;
101
+ }
102
+ return null;
103
+ }
104
+
28
105
  function checkHealth(timeoutMs = 1500) {
29
106
  return new Promise((resolve) => {
30
107
  const req = http.get(HEALTH_URL, { timeout: timeoutMs }, (res) => {
@@ -58,7 +135,12 @@ function healNativeBinary() {
58
135
 
59
136
  for (const scriptPath of possiblePaths) {
60
137
  if (fs.existsSync(scriptPath)) {
61
- process.stdout.write(`${YELLOW}⚡ [cc-agy] Re-linking platform native ELF binary...${NC} `);
138
+ // Purge any conflicting nested platform package to prevent 'Two copies installed' error
139
+ const nestedPkg = path.join(path.dirname(scriptPath), 'node_modules', '@anthropic-ai', 'claude-code-linux-x64');
140
+ if (fs.existsSync(nestedPkg)) {
141
+ try { fs.rmSync(nestedPkg, { recursive: true, force: true }); } catch {}
142
+ }
143
+ process.stdout.write(`${YELLOW}⚡ [cc-agy] Linking platform native ELF binary...${NC} `);
62
144
  const res = spawnSync('node', [scriptPath], { encoding: 'utf-8' });
63
145
  if (res.status === 0) {
64
146
  console.log(`${GREEN}✔ Done.${NC}`);
@@ -130,19 +212,15 @@ async function runDoctor() {
130
212
  console.log(`${BOLD}${CYAN} cc-agy: System Architecture & Diagnostic Telemetry ${NC}`);
131
213
  console.log(`${BOLD}${CYAN}====================================================================${NC}\n`);
132
214
 
133
- // 1. Antigravity OAuth Token
134
215
  const hasToken = fs.existsSync(AGY_TOKEN_PATH);
135
216
  console.log(`[1] Google Antigravity Token : ${hasToken ? `${GREEN}✔ Present (${AGY_TOKEN_PATH})${NC}` : `${RED}✖ Missing. Run 'agy' to sign in.${NC}`}`);
136
217
 
137
- // 2. Gateway Service
138
218
  const serviceActive = spawnSync('systemctl', ['--user', 'is-active', 'omniroute'], { encoding: 'utf-8' }).stdout?.trim() === 'active';
139
219
  console.log(`[2] OmniRoute User Daemon : ${serviceActive ? `${GREEN}✔ active (systemd --user)${NC}` : `${YELLOW}⚠ inactive / not running${NC}`}`);
140
220
 
141
- // 3. Local Endpoint Health
142
221
  const healthy = await checkHealth(2000);
143
222
  console.log(`[3] Gateway Health Endpoint : ${healthy ? `${GREEN}✔ http://127.0.0.1:20128 (healthy)${NC}` : `${RED}✖ Unreachable${NC}`}`);
144
223
 
145
- // 4. Claude Code CLI Version & Binary
146
224
  let claudeVersion = 'Unknown';
147
225
  let binaryStatus = `${RED}✖ Broken / Unlinked${NC}`;
148
226
  try {
@@ -156,15 +234,140 @@ async function runDoctor() {
156
234
  console.log(`[4] Claude Code CLI Version : ${CYAN}${claudeVersion}${NC}`);
157
235
  console.log(`[5] Platform Native Binary : ${binaryStatus}`);
158
236
 
159
- // 5. Model Routing
160
- console.log(`[6] Inference Architecture : ${BOLD}Tier 1: Gemini 3.8 Flash High (Reasoning)${NC}`);
161
- console.log(` ${BOLD}Tier 2: Claude Sonnet 4.6 (Fallback)${NC}`);
162
- console.log(` ${BOLD}Tier 3: Gemini 3.1 Flash Lite (Circuit Breaker)${NC}`);
237
+ const cfg = loadConfig();
238
+ const current = resolveModel(cfg.defaultModel) || AGY_MODELS[0];
239
+ console.log(`[6] Active Cognitive Model : ${BOLD}${CYAN}${current.name}${NC} (${current.id})`);
163
240
  console.log(`[7] Token Billing / Cost : ${GREEN}Asymmetric Zero Marginal Cost ($0 / token)${NC}\n`);
164
241
  }
165
242
 
243
+ async function handleModelCommand(targetArg) {
244
+ const cfg = loadConfig();
245
+ const currentId = cfg.defaultModel || 'gemini-3.8-flash-high';
246
+
247
+ if (targetArg) {
248
+ const matched = resolveModel(targetArg);
249
+ if (!matched) {
250
+ console.log(`\n${RED}[-] Unknown model alias: '${targetArg}'${NC}`);
251
+ console.log(` Available aliases: flash, medium, low, sonnet, opus, gpt, auto\n`);
252
+ process.exit(1);
253
+ }
254
+ cfg.defaultModel = matched.id;
255
+ saveConfig(cfg);
256
+ console.log(`\n${GREEN}✔ Active Antigravity Model switched to:${NC} ${BOLD}${matched.name}${NC} (${matched.id})\n`);
257
+ return;
258
+ }
259
+
260
+ // Interactive Model Selector Menu
261
+ console.log(`\n${BOLD}${CYAN}====================================================================${NC}`);
262
+ console.log(`${BOLD}${CYAN} cc-agy: Antigravity Model Switcher (TPU v5p Compute) ${NC}`);
263
+ console.log(`${BOLD}${CYAN}====================================================================${NC}\n`);
264
+
265
+ AGY_MODELS.forEach((m, idx) => {
266
+ const isActive = m.id === currentId;
267
+ const marker = isActive ? `${GREEN}● [ACTIVE]${NC}` : ` `;
268
+ const num = `${BOLD}[${idx + 1}]${NC}`;
269
+ console.log(` ${num} ${BOLD}${m.name.padEnd(28)}${NC} ${marker}`);
270
+ console.log(` ${DIM}${m.description}${NC}`);
271
+ console.log(` ${DIM}ID: ${m.id} | Aliases: ${m.aliases.join(', ')}${NC}\n`);
272
+ });
273
+
274
+ const rl = readline.createInterface({
275
+ input: process.stdin,
276
+ output: process.stdout,
277
+ });
278
+
279
+ rl.question(`${BOLD}Select model [1-7] (or press Enter to keep current): ${NC}`, (answer) => {
280
+ rl.close();
281
+ const trimmed = answer.trim();
282
+ if (!trimmed) {
283
+ console.log(`${CYAN}Retaining current active model: ${currentId}${NC}\n`);
284
+ return;
285
+ }
286
+ const matched = resolveModel(trimmed);
287
+ if (matched) {
288
+ cfg.defaultModel = matched.id;
289
+ saveConfig(cfg);
290
+ console.log(`\n${GREEN}✔ Active Antigravity Model set to:${NC} ${BOLD}${matched.name}${NC} (${matched.id})\n`);
291
+ } else {
292
+ console.log(`\n${RED}[-] Invalid selection. Keeping ${currentId}.${NC}\n`);
293
+ }
294
+ });
295
+ }
296
+
297
+ async function handleUpdateCommand() {
298
+ const pkgPath = path.join(__dirname, '..', 'package.json');
299
+ let pkg = { version: '1.1.0' };
300
+ try {
301
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
302
+ } catch (e) {}
303
+ const currentVersion = pkg.version;
304
+
305
+ console.log(`\n${BOLD}${CYAN}cc-agy Update Engine${NC}`);
306
+ console.log(`Current installed version: ${BOLD}v${currentVersion}${NC}`);
307
+
308
+ // Query registry for latest published version
309
+ let latestNpm = null;
310
+ try {
311
+ const res = spawnSync('npm', ['view', 'cc-agy', 'version'], { encoding: 'utf8' });
312
+ if (res.status === 0 && res.stdout) {
313
+ latestNpm = res.stdout.trim();
314
+ }
315
+ } catch (e) {}
316
+
317
+ if (latestNpm) {
318
+ console.log(`Latest registry version: ${BOLD}v${latestNpm}${NC}`);
319
+ }
320
+
321
+ const isGitRepo = fs.existsSync(path.join(__dirname, '..', '.git'));
322
+
323
+ if (isGitRepo) {
324
+ console.log(`\n${DIM}Repository checkout detected (${path.resolve(__dirname, '..')})${NC}`);
325
+ console.log(`Syncing latest commits from GitHub origin/main...`);
326
+ const pull = spawnSync('git', ['pull', '--rebase', 'origin', 'main'], {
327
+ cwd: path.join(__dirname, '..'),
328
+ stdio: 'inherit',
329
+ });
330
+ if (pull.status !== 0) {
331
+ console.log(`\n${RED}✖ Git pull failed. Please check local git working tree.${NC}\n`);
332
+ process.exit(1);
333
+ }
334
+ } else {
335
+ console.log(`\nUpdating global npm package: ${BOLD}npm install -g cc-agy@latest${NC}...`);
336
+ const npmUp = spawnSync('npm', ['install', '-g', 'cc-agy@latest'], {
337
+ stdio: 'inherit',
338
+ });
339
+ if (npmUp.status !== 0) {
340
+ console.log(`\n${RED}✖ npm update failed.${NC}\n`);
341
+ process.exit(1);
342
+ }
343
+ }
344
+
345
+ // Synchronize database combos if omniroute is installed
346
+ const patchScript = path.join(__dirname, '..', 'scripts', 'patch-combo.py');
347
+ if (fs.existsSync(patchScript)) {
348
+ console.log(`\nSynchronizing Antigravity model combos in SQLite...`);
349
+ spawnSync('python3', [patchScript], { stdio: 'inherit' });
350
+ }
351
+
352
+ // Ensure native binary link for claude-code
353
+ ensureNativeBinaryHealthy();
354
+
355
+ // Restart proxy daemon if running
356
+ console.log(`Verifying gateway daemon status...`);
357
+ spawnSync('systemctl', ['--user', 'restart', 'omniroute.service'], { stdio: 'ignore' });
358
+
359
+ let updatedVersion = currentVersion;
360
+ try {
361
+ const updatedPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
362
+ updatedVersion = updatedPkg.version;
363
+ } catch (e) {}
364
+
365
+ console.log(`\n${GREEN}✔ cc-agy is now at v${updatedVersion}!${NC}\n`);
366
+ process.exit(0);
367
+ }
368
+
166
369
  async function main() {
167
- const args = process.argv.slice(2);
370
+ const args = [...process.argv.slice(2)];
168
371
  const command = args[0];
169
372
 
170
373
  if (command === 'doctor' || command === 'status') {
@@ -185,21 +388,44 @@ async function main() {
185
388
  process.exit(ok ? 0 : 1);
186
389
  }
187
390
 
391
+ if (command === 'update' || command === 'upgrade') {
392
+ await handleUpdateCommand();
393
+ return;
394
+ }
395
+
396
+ if (command === 'model' || command === 'models' || command === 'switch') {
397
+ await handleModelCommand(args[1]);
398
+ return;
399
+ }
400
+
188
401
  if (command === '--help' || command === '-h' || command === 'help') {
189
402
  console.log(`
190
- ${BOLD}cc-agy${NC} - Claude Code + Google Antigravity (Gemini 3.8 Flash High) Gateway
403
+ ${BOLD}cc-agy${NC} - Claude Code + Google Antigravity (Gemini 3.8 Flash High & Claude on TPU)
191
404
 
192
405
  ${BOLD}USAGE:${NC}
193
406
  cc-agy [options] [claude-flags] Launch Claude Code connected to Antigravity
407
+ cc-agy model [alias] Switch default active model (or show interactive menu)
408
+ cc-agy update Self-update to the latest version & sync model combos
194
409
  cc-agy doctor Run full diagnostic telemetry & healthcheck
195
410
  cc-agy restart Restart local proxy daemon
196
411
  cc-agy setup Force re-run provisioning and database patches
197
412
 
413
+ ${BOLD}MODELS & ALIASES:${NC}
414
+ flash / high Gemini 3.8 Flash High (Deep Reasoning)
415
+ medium / med Gemini 3.8 Flash Medium
416
+ low Gemini 3.8 Flash Low (Sub-second)
417
+ sonnet Claude Sonnet 4.6 (Thinking on TPU)
418
+ opus Claude Opus 4.6 (Thinking on TPU)
419
+ gpt / oss GPT-OSS 120B (Medium)
420
+ auto Priority Cascade (High -> Sonnet -> Lite)
421
+
198
422
  ${BOLD}EXAMPLES:${NC}
199
- cc-agy
423
+ cc-agy Launch with active model
424
+ cc-agy --model sonnet Launch a session with Claude Sonnet 4.6
425
+ cc-agy --model opus Launch a session with Claude Opus 4.6
426
+ cc-agy model Open interactive model switcher
427
+ cc-agy model sonnet Set default model to Sonnet 4.6
200
428
  cc-agy --dangerously-skip-permissions
201
- cc-agy -p "Review this file"
202
- cc-agy doctor
203
429
  `);
204
430
  process.exit(0);
205
431
  }
@@ -223,18 +449,48 @@ ${BOLD}EXAMPLES:${NC}
223
449
  ensureNativeBinaryHealthy();
224
450
  await ensureDaemonRunning();
225
451
 
226
- // Inject gateway environment variables
452
+ // Model resolution: check command-line --model / -m override, otherwise use saved default
453
+ const cfg = loadConfig();
454
+ let selectedModelId = cfg.defaultModel || 'gemini-3.8-flash-high';
455
+ let modelIndex = -1;
456
+
457
+ for (let i = 0; i < args.length; i++) {
458
+ if (args[i] === '--model' || args[i] === '-m') {
459
+ if (args[i + 1]) {
460
+ const resolved = resolveModel(args[i + 1]);
461
+ if (resolved) {
462
+ selectedModelId = resolved.id;
463
+ } else {
464
+ selectedModelId = args[i + 1];
465
+ }
466
+ modelIndex = i;
467
+ }
468
+ break;
469
+ }
470
+ }
471
+
472
+ // Strip custom --model/-m from args to pass cleaned model id to claude
473
+ const forwardArgs = [...args];
474
+ if (modelIndex !== -1) {
475
+ forwardArgs.splice(modelIndex, 2);
476
+ }
477
+ forwardArgs.unshift('--model', selectedModelId);
478
+
479
+ // Inject gateway environment variables & disable broken background autoupdate
227
480
  const apiKey = getLocalApiKey();
228
481
  const env = {
229
482
  ...process.env,
230
483
  ANTHROPIC_BASE_URL: 'http://localhost:20128',
231
484
  ANTHROPIC_AUTH_TOKEN: apiKey,
232
485
  ANTHROPIC_API_KEY: '',
486
+ ANTHROPIC_MODEL: selectedModelId,
233
487
  CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1',
488
+ DISABLE_AUTOUPDATER: '1',
489
+ CLAUDE_CODE_AUTOUPDATER_DISABLED_BY_HOST: '1',
234
490
  };
235
491
 
236
492
  // Launch Claude Code transparently
237
- const child = spawn('claude', args, {
493
+ const child = spawn('claude', forwardArgs, {
238
494
  stdio: 'inherit',
239
495
  env,
240
496
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-agy",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Decoupled Asymmetric Compute Gateway: Claude Code CLI + Google Antigravity (Gemini 3.8 Flash High) TPU compute at zero marginal token cost.",
5
5
  "main": "bin/cc-agy.js",
6
6
  "bin": {
@@ -38,6 +38,7 @@
38
38
  "bin",
39
39
  "scripts",
40
40
  "systemd",
41
+ "assets",
41
42
  "install.sh",
42
43
  "uninstall.sh",
43
44
  "README.md",
@@ -2,9 +2,10 @@
2
2
  """
3
3
  patch-combo.py
4
4
  Configures OmniRoute SQLite database for Claude Code + Antigravity compatibility:
5
- 1. Enables compatFilterFailOpen on the 'claude-auto' combo to prevent fatal 400 capability errors.
6
- 2. Structures the priority cascade: Gemini 3.8 Flash High -> Claude Sonnet 4.6 -> Flash Lite (fallback).
7
- 3. Ensures local API keys have wildcard permissions for combo routing.
5
+ 1. Provisions exact Google Antigravity models and aliases (Gemini 3.8 Flash High/Med/Low, Claude Sonnet 4.6, Claude Opus 4.6, GPT-OSS 120B).
6
+ 2. Enables compatFilterFailOpen on combos to prevent fatal 400 capability errors.
7
+ 3. Sets up fallback 'claude-auto' priority cascade.
8
+ 4. Ensures local API keys have wildcard permissions for combo routing.
8
9
  """
9
10
 
10
11
  import sys
@@ -12,6 +13,45 @@ import json
12
13
  import sqlite3
13
14
  from pathlib import Path
14
15
 
16
+ MODELS_CONFIG = [
17
+ {
18
+ 'id': 'combo-gemini-3.8-high',
19
+ 'name': 'gemini-3.8-flash-high',
20
+ 'aliases': ['flash-high', 'flash', 'high', 'gemini'],
21
+ 'target': 'agy/gemini-3.8-flash-high'
22
+ },
23
+ {
24
+ 'id': 'combo-gemini-3.8-med',
25
+ 'name': 'gemini-3.8-flash-medium',
26
+ 'aliases': ['flash-medium', 'medium', 'med'],
27
+ 'target': 'agy/gemini-3.8-flash-medium'
28
+ },
29
+ {
30
+ 'id': 'combo-gemini-3.8-low',
31
+ 'name': 'gemini-3.8-flash-low',
32
+ 'aliases': ['flash-low', 'low'],
33
+ 'target': 'agy/gemini-3.8-flash-low'
34
+ },
35
+ {
36
+ 'id': 'combo-claude-sonnet-4-6',
37
+ 'name': 'claude-sonnet-4-6',
38
+ 'aliases': ['sonnet', 'sonnet-4-6'],
39
+ 'target': 'agy/claude-sonnet-4-6'
40
+ },
41
+ {
42
+ 'id': 'combo-claude-opus-4-6',
43
+ 'name': 'claude-opus-4-6-thinking',
44
+ 'aliases': ['opus', 'opus-4-6', 'opus-thinking'],
45
+ 'target': 'agy/claude-opus-4-6-thinking'
46
+ },
47
+ {
48
+ 'id': 'combo-gpt-oss-120b',
49
+ 'name': 'gpt-oss-120b-medium',
50
+ 'aliases': ['gpt', 'oss', 'gpt-oss'],
51
+ 'target': 'agy/gpt-oss-120b-medium'
52
+ }
53
+ ]
54
+
15
55
  def patch_omniroute_db():
16
56
  db_path = Path.home() / ".omniroute" / "storage.sqlite"
17
57
  if not db_path.exists():
@@ -22,11 +62,32 @@ def patch_omniroute_db():
22
62
  cur = conn.cursor()
23
63
 
24
64
  try:
25
- # 1. Patch claude-auto combo
65
+ # 1. Setup exact model combos and alias mappings
66
+ for m in MODELS_CONFIG:
67
+ combo_data = {
68
+ 'name': m['name'],
69
+ 'strategy': 'priority',
70
+ 'config': {'compatFilterFailOpen': True},
71
+ 'models': [{'id': m['id'] + '-m', 'kind': 'model', 'model': m['target'], 'providerId': 'agy', 'weight': 10}],
72
+ 'version': 2
73
+ }
74
+ cur.execute("""INSERT OR REPLACE INTO combos (id, name, data, updated_at, created_at)
75
+ VALUES (?, ?, ?, datetime('now'), datetime('now'))""",
76
+ (m['id'], m['name'], json.dumps(combo_data)))
77
+
78
+ cur.execute("""INSERT OR REPLACE INTO model_combo_mappings (id, pattern, combo_id, priority, enabled, description, created_at, updated_at)
79
+ VALUES (?, ?, ?, 20, 1, ?, datetime('now'), datetime('now'))""",
80
+ ('map-' + m['name'], m['name'], m['id'], 'Exact ' + m['name']))
81
+
82
+ for alias in m['aliases']:
83
+ cur.execute("""INSERT OR REPLACE INTO model_combo_mappings (id, pattern, combo_id, priority, enabled, description, created_at, updated_at)
84
+ VALUES (?, ?, ?, 15, 1, ?, datetime('now'), datetime('now'))""",
85
+ ('map-alias-' + alias, alias, m['id'], 'Alias ' + alias))
86
+
87
+ # 2. Patch claude-auto priority fallback combo
26
88
  row = cur.execute("SELECT id, data FROM combos WHERE name = 'claude-auto'").fetchone()
89
+ auto_id = "fc0a1ddb-af40-4c9d-b9ce-7e8166c3ddde"
27
90
  if not row:
28
- print("[-] Combo 'claude-auto' not found in database. Initializing default structure...")
29
- combo_id = "claude-auto-default"
30
91
  combo_data = {
31
92
  "name": "claude-auto",
32
93
  "strategy": "priority",
@@ -40,56 +101,42 @@ def patch_omniroute_db():
40
101
  }
41
102
  cur.execute(
42
103
  "INSERT INTO combos (id, name, data, sort_order, created_at, updated_at) VALUES (?, ?, ?, 1, datetime('now'), datetime('now'))",
43
- (combo_id, "claude-auto", json.dumps(combo_data))
104
+ (auto_id, "claude-auto", json.dumps(combo_data))
44
105
  )
45
106
  else:
46
- combo_id, raw_data = row
107
+ auto_id, raw_data = row
47
108
  data = json.loads(raw_data)
48
-
49
- # Ensure config has compatFilterFailOpen
50
109
  if "config" not in data or not isinstance(data["config"], dict):
51
110
  data["config"] = {}
52
111
  data["config"]["compatFilterFailOpen"] = True
53
-
54
- # Restructure priority tiering
55
112
  data["strategy"] = "priority"
56
113
  data["models"] = [
57
114
  {"id": "claude-auto-m1", "kind": "model", "model": "agy/gemini-3.8-flash-high", "providerId": "agy", "weight": 10},
58
115
  {"id": "claude-auto-m2", "kind": "model", "model": "agy/claude-sonnet-4-6", "providerId": "agy", "weight": 5},
59
116
  {"id": "claude-auto-m3", "kind": "model", "model": "agy/gemini-3.1-flash-lite", "providerId": "agy", "weight": 1}
60
117
  ]
61
-
62
118
  cur.execute("UPDATE combos SET data = ?, updated_at = datetime('now') WHERE name = 'claude-auto'", (json.dumps(data),))
63
119
 
64
- # 2. Grant wildcard combo permissions to all local API keys
65
- keys = cur.execute("SELECT key, allowed_combos FROM api_keys").fetchall()
66
- for key_val, allowed in keys:
67
- cur.execute(
68
- "UPDATE api_keys SET allowed_combos = ?, scopes = ? WHERE key = ?",
69
- (
70
- json.dumps(["*", "combo/*", "claude-auto", "auto/*"]),
71
- json.dumps(["admin", "manage", "read", "write"]),
72
- key_val
73
- )
74
- )
120
+ # Fallback mappings for generic legacy requests
121
+ cur.execute("""INSERT OR REPLACE INTO model_combo_mappings (id, pattern, combo_id, priority, enabled, description, created_at, updated_at)
122
+ VALUES ('map-claude-fallback-sonnet', 'claude-3-5-sonnet*', ?, 5, 1, 'Default Sonnet to Auto', datetime('now'), datetime('now'))""", (auto_id,))
123
+ cur.execute("""INSERT OR REPLACE INTO model_combo_mappings (id, pattern, combo_id, priority, enabled, description, created_at, updated_at)
124
+ VALUES ('map-claude-fallback-opus', 'claude-opus-5*', ?, 5, 1, 'Default Opus to Auto', datetime('now'), datetime('now'))""", (auto_id,))
75
125
 
76
- # 3. Ensure model combo mapping exists for claude-opus and claude-sonnet
77
- mappings = [
78
- ("map-claude-opus-5", "claude-opus-5", combo_id),
79
- ("map-claude-sonnet", "claude-sonnet*", combo_id),
80
- ("map-claude-opus", "claude-opus*", combo_id),
81
- ]
82
- for map_id, pattern, cid in mappings:
126
+ # 3. Grant wildcard combo permissions to all local API keys
127
+ all_combos = [m['name'] for m in MODELS_CONFIG] + [a for m in MODELS_CONFIG for a in m['aliases']] + ['claude-auto', '*', 'combo/*', 'auto/*']
128
+ keys = cur.execute("SELECT key FROM api_keys").fetchall()
129
+ for (key_val,) in keys:
83
130
  cur.execute(
84
- "INSERT OR REPLACE INTO model_combo_mappings (id, pattern, combo_id, priority, enabled, description, created_at, updated_at) "
85
- "VALUES (?, ?, ?, 10, 1, 'Auto route', datetime('now'), datetime('now'))",
86
- (map_id, pattern, cid)
131
+ "UPDATE api_keys SET allowed_combos = ?, scopes = ? WHERE key = ?",
132
+ (json.dumps(all_combos), json.dumps(["admin", "manage", "read", "write"]), key_val)
87
133
  )
88
134
 
89
135
  conn.commit()
90
136
  print("[+] OmniRoute SQLite database successfully patched:")
91
- print(" - 'claude-auto' combo set to priority: Gemini 3.8 Flash High -> Claude Sonnet 4.6 -> Flash Lite")
92
- print(" - 'compatFilterFailOpen' enabled (bypasses 400 schema mismatch)")
137
+ print(" - 6 exact Antigravity models and aliases mapped")
138
+ print(" - 'claude-auto' cascade configured (Gemini 3.8 Flash High -> Sonnet 4.6 -> Flash Lite)")
139
+ print(" - 'compatFilterFailOpen' enabled across all combos")
93
140
  print(" - Local API key permissions synchronized")
94
141
  return True
95
142