claudmax 2.0.0 → 2.0.1

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 (124) hide show
  1. package/claudmax-1.0.16.tgz +0 -0
  2. package/{packages/cli/index.js → index.js} +2 -0
  3. package/package.json +27 -55
  4. package/.claude/settings.local.json +0 -7
  5. package/.env.example +0 -24
  6. package/.github/workflows/publish.yml +0 -31
  7. package/README.md +0 -178
  8. package/claudmax-mcp-1.0.2.tgz +0 -0
  9. package/help +0 -0
  10. package/help-wal +0 -0
  11. package/next-env.d.ts +0 -6
  12. package/next.config.mjs +0 -43
  13. package/packages/cli/claudmax-1.0.16.tgz +0 -0
  14. package/packages/cli/package.json +0 -33
  15. package/packages/mcp/claudmax-mcp-1.0.0.tgz +0 -0
  16. package/packages/mcp/claudmax-mcp-1.0.1.tgz +0 -0
  17. package/packages/mcp/claudmax-mcp-1.0.2.tgz +0 -0
  18. package/packages/mcp/claudmax-mcp-1.0.3.tgz +0 -0
  19. package/packages/mcp/index.js +0 -129
  20. package/packages/mcp/package-lock.json +0 -1146
  21. package/packages/mcp/package.json +0 -32
  22. package/postcss.config.mjs +0 -6
  23. package/prisma/schema.prisma +0 -130
  24. package/prisma/seed.ts +0 -27
  25. package/public/favicon.svg +0 -10
  26. package/public/robots.txt +0 -10
  27. package/run_build.sh +0 -4
  28. package/scripts/migrate-plans.js +0 -98
  29. package/scripts/seed-blog.ts +0 -1014
  30. package/src/app/admin/dashboard/AdminDashboardClient.tsx +0 -1546
  31. package/src/app/admin/dashboard/page.tsx +0 -13
  32. package/src/app/admin/page.tsx +0 -132
  33. package/src/app/api/admin/auth/me/route.ts +0 -34
  34. package/src/app/api/admin/health/route.ts +0 -110
  35. package/src/app/api/admin/keys/[id]/route.ts +0 -116
  36. package/src/app/api/admin/keys/route.ts +0 -192
  37. package/src/app/api/admin/keys-list/route.ts +0 -81
  38. package/src/app/api/admin/login/route.ts +0 -72
  39. package/src/app/api/admin/logout/route.ts +0 -8
  40. package/src/app/api/admin/migrate/route.ts +0 -133
  41. package/src/app/api/admin/plans/[id]/route.ts +0 -65
  42. package/src/app/api/admin/plans/route.ts +0 -66
  43. package/src/app/api/admin/posts/[id]/route.ts +0 -81
  44. package/src/app/api/admin/posts/route.ts +0 -83
  45. package/src/app/api/admin/seed/route.ts +0 -145
  46. package/src/app/api/admin/settings/route.ts +0 -44
  47. package/src/app/api/admin/stats/route.ts +0 -74
  48. package/src/app/api/admin/users/[id]/route.ts +0 -166
  49. package/src/app/api/admin/users/plans/route.ts +0 -45
  50. package/src/app/api/admin/users/route.ts +0 -202
  51. package/src/app/api/blog/[slug]/route.ts +0 -22
  52. package/src/app/api/blog/route.ts +0 -40
  53. package/src/app/api/cron/daily-status/route.ts +0 -208
  54. package/src/app/api/support/chat/route.ts +0 -55
  55. package/src/app/api/support/chat/session/route.ts +0 -62
  56. package/src/app/api/support/chat/stream/route.ts +0 -44
  57. package/src/app/api/support/email/route.ts +0 -63
  58. package/src/app/api/tools/understand_image/route.ts +0 -113
  59. package/src/app/api/tools/upload/route.ts +0 -179
  60. package/src/app/api/tools/web_search/route.ts +0 -99
  61. package/src/app/api/v1/audio/route.ts +0 -67
  62. package/src/app/api/v1/audio/speech/route.ts +0 -73
  63. package/src/app/api/v1/chat/completions/route.ts +0 -3
  64. package/src/app/api/v1/chat/route.ts +0 -1079
  65. package/src/app/api/v1/images/generations/route.ts +0 -93
  66. package/src/app/api/v1/info/route.ts +0 -30
  67. package/src/app/api/v1/key-status/route.ts +0 -109
  68. package/src/app/api/v1/key-status/stream/route.ts +0 -135
  69. package/src/app/api/v1/messages/count_tokens/route.ts +0 -22
  70. package/src/app/api/v1/messages/route.ts +0 -807
  71. package/src/app/api/v1/models/route.ts +0 -14
  72. package/src/app/api/v1/route.ts +0 -18
  73. package/src/app/blog/BlogClient.tsx +0 -193
  74. package/src/app/blog/[slug]/page.tsx +0 -117
  75. package/src/app/blog/page.tsx +0 -20
  76. package/src/app/check-usage/CheckUsageClient.tsx +0 -186
  77. package/src/app/check-usage/layout.tsx +0 -11
  78. package/src/app/check-usage/page.tsx +0 -15
  79. package/src/app/docs/layout.tsx +0 -16
  80. package/src/app/docs/page.tsx +0 -1055
  81. package/src/app/faq/FAQClient.tsx +0 -227
  82. package/src/app/faq/page.tsx +0 -21
  83. package/src/app/globals.css +0 -75
  84. package/src/app/layout.tsx +0 -80
  85. package/src/app/page.tsx +0 -256
  86. package/src/app/reseller/ResellerClient.tsx +0 -435
  87. package/src/app/reseller/page.tsx +0 -15
  88. package/src/app/setup.ps1/route.ts +0 -79
  89. package/src/app/setup.sh/route.ts +0 -113
  90. package/src/app/sitemap.ts +0 -50
  91. package/src/app/status/StatusClient.tsx +0 -103
  92. package/src/app/status/layout.tsx +0 -11
  93. package/src/app/status/page.tsx +0 -15
  94. package/src/app/support/SupportClient.tsx +0 -411
  95. package/src/app/support/page.tsx +0 -25
  96. package/src/app/v1/chat/completions/route.ts +0 -3
  97. package/src/app/v1/chat/route.ts +0 -4
  98. package/src/app/v1/messages/route.ts +0 -3
  99. package/src/components/Footer.tsx +0 -120
  100. package/src/components/Header.tsx +0 -131
  101. package/src/components/landing/features.tsx +0 -99
  102. package/src/components/ui/badge.tsx +0 -32
  103. package/src/components/ui/button.tsx +0 -46
  104. package/src/components/ui/card.tsx +0 -50
  105. package/src/components/ui/dialog.tsx +0 -97
  106. package/src/components/ui/dropdown-menu.tsx +0 -156
  107. package/src/components/ui/input.tsx +0 -21
  108. package/src/components/ui/label.tsx +0 -15
  109. package/src/components/ui/separator.tsx +0 -22
  110. package/src/components/ui/switch.tsx +0 -27
  111. package/src/components/ui/tabs.tsx +0 -51
  112. package/src/components/ui/toast.tsx +0 -103
  113. package/src/lib/auth.ts +0 -45
  114. package/src/lib/prisma.ts +0 -20
  115. package/src/lib/providers.ts +0 -158
  116. package/src/lib/security.ts +0 -165
  117. package/src/lib/utils.ts +0 -14
  118. package/src/middleware.ts +0 -30
  119. package/tailwind.config.ts +0 -53
  120. package/tsconfig.json +0 -41
  121. package/tsconfig.tsbuildinfo +0 -1
  122. package/vercel.json +0 -8
  123. /package/{packages/cli/bin → bin}/claudmax.js +0 -0
  124. /package/{packages/cli/claudmax-1.0.17.tgz → claudmax-1.0.17.tgz} +0 -0
@@ -1,1055 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useEffect, useRef } from 'react';
4
- import Link from 'next/link';
5
- import {
6
- Zap, Shield, Search, ChevronRight, BookOpen,
7
- Key, MessageSquare, Box, Hash,
8
- Activity, Puzzle, Gauge, Wrench, Menu, X,
9
- Terminal as TerminalIcon
10
- } from 'lucide-react';
11
- import Header from '@/components/Header';
12
- import Footer from '@/components/Footer';
13
-
14
- // NOTE: Metadata is exported from layout.tsx (server component).
15
-
16
- const API_BASE = (process.env.NEXT_PUBLIC_API_BASE || process.env.NEXT_PUBLIC_API_URL) || 'https://api.claudmax.pro';
17
- const SETUP_DOMAIN = 'claudmax.pro';
18
-
19
- // ─── Icon Map ───────────────────────────────────────────────────────────────
20
- const navIcons: Record<string, React.ReactNode> = {
21
- overview: <BookOpen className="w-4 h-4" />,
22
- claude_code: <TerminalIcon className="w-4 h-4" />,
23
- vscode: <Box className="w-4 h-4" />,
24
- cursor: <Box className="w-4 h-4" />,
25
- windsurf: <Box className="w-4 h-4" />,
26
- cline: <Box className="w-4 h-4" />,
27
- roo_code: <Box className="w-4 h-4" />,
28
- auth: <Key className="w-4 h-4" />,
29
- messages: <MessageSquare className="w-4 h-4" />,
30
- models: <Box className="w-4 h-4" />,
31
- token_count: <Hash className="w-4 h-4" />,
32
- key_status: <Activity className="w-4 h-4" />,
33
- mcp: <Puzzle className="w-4 h-4" />,
34
- limits: <Gauge className="w-4 h-4" />,
35
- troubleshooting: <Wrench className="w-4 h-4" />,
36
- };
37
-
38
- // ─── Components ───────────────────────────────────────────────────────────────
39
- function Terminal({ title, code, lang = 'bash', filename }: { title?: string; code: string; lang?: 'bash' | 'powershell' | 'python' | 'javascript'; filename?: string }) {
40
- const [copied, setCopied] = useState(false);
41
- const colors: Record<string, string> = { bash: 'text-orange-300', powershell: 'text-blue-300', python: 'text-purple-300', javascript: 'text-yellow-300' };
42
- return (
43
- <div className="rounded-xl border border-gray-200 bg-[#0d0d0d] overflow-hidden my-4">
44
- <div className="flex items-center justify-between px-4 py-2.5 border-b border-white/[0.06] bg-[#161616]">
45
- <div className="flex items-center gap-2">
46
- <div className="flex gap-1.5"><div className="w-2.5 h-2.5 rounded-full bg-red-500/60" /><div className="w-2.5 h-2.5 rounded-full bg-yellow-500/60" /><div className="w-2.5 h-2.5 rounded-full bg-green-500/60" /></div>
47
- <span className="text-white/25 text-xs font-mono ml-2">{filename || title || 'terminal'}</span>
48
- </div>
49
- <button onClick={() => { navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); }}
50
- className="text-xs text-white/30 hover:text-white/60 px-2 py-0.5 rounded border border-white/10 font-medium transition-colors">
51
- {copied ? 'Copied!' : 'Copy'}
52
- </button>
53
- </div>
54
- <div className="p-4 font-mono text-sm overflow-x-auto"><pre className={colors[lang] || colors.bash}><code>{code}</code></pre></div>
55
- </div>
56
- );
57
- }
58
-
59
- function Callout({ type, children }: { type?: 'info' | 'warning' | 'success'; children: React.ReactNode }) {
60
- const styles: Record<string, string> = {
61
- info: 'border-blue-200 bg-blue-50 text-blue-800',
62
- warning: 'border-amber-200 bg-amber-50 text-amber-800',
63
- success: 'border-emerald-200 bg-emerald-50 text-emerald-800',
64
- };
65
- const icons: Record<string, React.ReactNode> = {
66
- info: <BookOpen className="w-4 h-4 shrink-0 mt-0.5" />,
67
- warning: <Shield className="w-4 h-4 shrink-0 mt-0.5" />,
68
- success: <Zap className="w-4 h-4 shrink-0 mt-0.5" />,
69
- };
70
- return (
71
- <div className={`rounded-lg border p-3 my-4 text-sm flex gap-2.5 ${styles[type ?? 'info']}`}>
72
- {icons[type ?? 'info']}
73
- <span>{children}</span>
74
- </div>
75
- );
76
- }
77
-
78
- function CodeInline({ children }: { children: string }) {
79
- return <code className="bg-gray-100 text-purple-600 px-1.5 py-0.5 rounded text-xs font-mono font-semibold">{children}</code>;
80
- }
81
-
82
- function CodeBlock({ label, children }: { label?: string; children: React.ReactNode }) {
83
- return (
84
- <div className="bg-gray-50 border border-gray-200 rounded-xl p-4 my-4">
85
- {label && <p className="text-xs font-bold text-gray-400 uppercase tracking-wider mb-2">{label}</p>}
86
- {children}
87
- </div>
88
- );
89
- }
90
-
91
- function SectionTitle({ children }: { children: React.ReactNode }) {
92
- return <h2 className="text-xl font-bold text-[#111827] mt-10 mb-3 pb-2 border-b border-gray-100">{children}</h2>;
93
- }
94
-
95
- function SubTitle({ children }: { children: React.ReactNode }) {
96
- return <h3 className="text-base font-bold text-[#374151] mt-8 mb-2">{children}</h3>;
97
- }
98
-
99
- function Para({ children }: { children: React.ReactNode }) {
100
- return <p className="text-sm text-[#6B7280] leading-relaxed mb-3">{children}</p>;
101
- }
102
-
103
- function SidebarItem({ label, active, onClick, icon }: { label: string; active?: boolean; onClick?: () => void; icon?: React.ReactNode }) {
104
- return (
105
- <button
106
- onClick={onClick}
107
- className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm font-medium transition-all text-left ${
108
- active
109
- ? 'bg-purple-100 text-purple-700 font-semibold'
110
- : 'text-[#6B7280] hover:text-[#111827] hover:bg-gray-100'
111
- }`}
112
- >
113
- {icon && <span className={active ? 'text-purple-600' : 'text-[#9CA3AF]'}>{icon}</span>}
114
- {label}
115
- {active && <ChevronRight className="w-3 h-3 ml-auto shrink-0" />}
116
- </button>
117
- );
118
- }
119
-
120
- // ─── Content Sections ─────────────────────────────────────────────────────────
121
- function OverviewSection() {
122
- const features = [
123
- { icon: <Zap className="w-5 h-5 text-amber-500" />, title: 'Drop-in Compatible', desc: 'Works with Claude Code CLI, Python SDK, OpenAI SDK, and any HTTP client — just change the base URL.' },
124
- { icon: <Shield className="w-5 h-5 text-emerald-500" />, title: 'Per-Key Budgets', desc: '5-hour rolling window token limits per API key. Automatic resets on every request.' },
125
- { icon: <Search className="w-5 h-5 text-blue-500" />, title: 'MCP Tools Built-in', desc: 'Web search and image analysis available as native Claude tools via the MCP server.' },
126
- { icon: <Gauge className="w-5 h-5 text-purple-500" />, title: '200K Context', desc: 'All models support up to 200,000 token context windows. Process entire documents in one call.' },
127
- ];
128
-
129
- const models = [
130
- { id: 'claude-opus-4-6', name: 'Opus 4.6', input: '$5', output: '$25', ctx: '200K', best: 'Research, complex reasoning, highest quality' },
131
- { id: 'claude-sonnet-4-6', name: 'Sonnet 4.6', input: '$3', output: '$15', ctx: '200K', best: 'Coding, writing, general assistance' },
132
- { id: 'claude-haiku-4-5-20251001', name: 'Haiku 4.5', input: '$1', output: '$5', ctx: '200K', best: 'High-volume, low-cost tasks' },
133
- { id: 'claude-sonnet-4-vision', name: 'Sonnet 4 Vision', input: '$3', output: '$15', ctx: '200K', best: 'Image analysis, screenshots, documents' },
134
- ];
135
-
136
- const plans = [
137
- { tier: '5x Max', requests: '500 / 5h', tokens: '5M / 5h', price: 'Affordable', color: 'bg-blue-50 border-blue-100' },
138
- { tier: '20x Max', requests: '2,000 / 5h', tokens: '20M / 5h', price: 'Best Value', color: 'bg-purple-50 border-purple-100' },
139
- { tier: 'Unlimited', requests: 'Unlimited', tokens: 'Unlimited', price: 'Enterprise', color: 'bg-amber-50 border-amber-100' },
140
- ];
141
-
142
- return (
143
- <div id="overview" className="space-y-0">
144
- <h1 className="text-3xl font-black text-[#111827] mb-2">Getting Started with ClaudMax</h1>
145
- <p className="text-[#6B7280] mb-6">ClaudMax is a high-performance Claude API gateway powered by OpenRouter. Access Claude Opus 4.6, Sonnet 4.6, and Haiku 4.5 through a single unified endpoint.</p>
146
-
147
- {/* Key Features */}
148
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-8">
149
- {features.map(f => (
150
- <div key={f.title} className="bg-white rounded-xl border border-gray-200 p-4">
151
- <div className="mb-2">{f.icon}</div>
152
- <h3 className="font-bold text-sm text-[#111827] mb-1">{f.title}</h3>
153
- <p className="text-xs text-[#9CA3AF] leading-relaxed">{f.desc}</p>
154
- </div>
155
- ))}
156
- </div>
157
-
158
- {/* Models Table */}
159
- <SectionTitle>Available Models</SectionTitle>
160
- <Para>All Claude models are accessible with up to 200K token context windows.</Para>
161
- <CodeBlock label="Model Pricing (per 1M tokens)">
162
- <div className="overflow-x-auto">
163
- <table className="w-full text-sm">
164
- <thead>
165
- <tr className="border-b border-gray-100 bg-gray-50">
166
- {['Model', 'Name', 'Input', 'Output', 'Context', 'Best For'].map(h => (
167
- <th key={h} className="text-left px-3 py-2 text-xs font-bold text-gray-400 uppercase">{h}</th>
168
- ))}
169
- </tr>
170
- </thead>
171
- <tbody>
172
- {models.map(m => (
173
- <tr key={m.id} className="border-b border-gray-100 last:border-0 hover:bg-gray-50">
174
- <td className="px-3 py-2.5"><code className="text-purple-600 font-mono text-xs">{m.id}</code></td>
175
- <td className="px-3 py-2.5 text-gray-700 text-xs font-semibold">{m.name}</td>
176
- <td className="px-3 py-2.5 text-gray-500 text-xs font-mono">{m.input}</td>
177
- <td className="px-3 py-2.5 text-gray-500 text-xs font-mono">{m.output}</td>
178
- <td className="px-3 py-2.5 text-gray-400 text-xs font-mono">{m.ctx}</td>
179
- <td className="px-3 py-2.5 text-gray-500 text-xs">{m.best}</td>
180
- </tr>
181
- ))}
182
- </tbody>
183
- </table>
184
- </div>
185
- </CodeBlock>
186
-
187
- {/* Plan Tiers */}
188
- <SectionTitle>Plan Tiers</SectionTitle>
189
- <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-6">
190
- {plans.map(p => (
191
- <div key={p.tier} className={`rounded-xl border p-4 ${p.color}`}>
192
- <h3 className="font-bold text-sm text-[#111827] mb-2">{p.tier}</h3>
193
- <div className="space-y-1 text-xs text-[#6B7280]">
194
- <div className="flex justify-between"><span>Requests</span><span className="font-semibold text-[#111827]">{p.requests}</span></div>
195
- <div className="flex justify-between"><span>Tokens</span><span className="font-semibold text-[#111827]">{p.tokens}</span></div>
196
- <div className="flex justify-between"><span>Tier</span><span className="font-semibold text-[#111827]">{p.price}</span></div>
197
- </div>
198
- </div>
199
- ))}
200
- </div>
201
-
202
- <Callout type="info">All plans use a rolling 5-hour window that resets on every API request, ensuring you always have fresh capacity when you need it.</Callout>
203
-
204
- {/* Quick Start */}
205
- <SectionTitle>Quick Install (30 Seconds)</SectionTitle>
206
- <Para>Run the interactive setup wizard — it detects your IDE and configures everything automatically:</Para>
207
- <Terminal filename="terminal" code={`npx claudmax`} />
208
- <Para>The wizard will:</Para>
209
- <ul className="list-disc list-inside text-sm text-[#6B7280] space-y-1.5 ml-2 mb-4">
210
- <li>Prompt for your API key (format: <CodeInline>sk-cmx_...</CodeInline>)</li>
211
- <li>Auto-detect and configure your IDE</li>
212
- <li>Install ClaudMax MCP tools automatically</li>
213
- <li>Verify your connection</li>
214
- </ul>
215
-
216
- {/* Manual Setup */}
217
- <SectionTitle>Manual Setup</SectionTitle>
218
- <SubTitle>Windows (PowerShell)</SubTitle>
219
- <Terminal lang="powershell" filename="PowerShell (Administrator)" code={`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
220
- irm https://${SETUP_DOMAIN}/setup.ps1 | iex`} />
221
-
222
- <SubTitle>macOS / Linux</SubTitle>
223
- <Terminal filename="terminal" code={`curl -fsSL https://${SETUP_DOMAIN}/setup.sh | bash`} />
224
-
225
- <SubTitle>First API Call</SubTitle>
226
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages \\
227
- -H "x-api-key: YOUR_API_KEY" \\
228
- -H "Content-Type: application/json" \\
229
- -d '{
230
- "model": "claude-sonnet-4-6",
231
- "max_tokens": 512,
232
- "messages": [{"role": "user", "content": "Hello, Claude!"}]
233
- }'`} />
234
-
235
- <Callout type="success">That is all you need to get started. Scroll down or use the sidebar to explore each section in detail.</Callout>
236
- </div>
237
- );
238
- }
239
-
240
- function ClaudeCodeSection() {
241
- return (
242
- <div id="claude_code">
243
- <h1 className="text-3xl font-black text-[#111827] mb-2">Claude Code CLI</h1>
244
- <p className="text-[#9CA3AF] mb-6">Configure Claude Code CLI to use ClaudMax as your API gateway.</p>
245
-
246
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
247
- <Para>Run the setup wizard and select Claude Code CLI:</Para>
248
- <Terminal filename="terminal" code={`npx claudmax`} />
249
- <Callout type="info">The wizard automatically configures both <CodeInline>settings.json</CodeInline> and <CodeInline>.claude.json</CodeInline>.</Callout>
250
-
251
- <SectionTitle>Manual Configuration</SectionTitle>
252
- <SubTitle>Step 1: Configure settings.json</SubTitle>
253
- <Terminal filename="~/.claude/settings.json" code={`{
254
- "env": {
255
- "ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY",
256
- "ANTHROPIC_BASE_URL": "${API_BASE}/v1/messages",
257
- "ANTHROPIC_MODEL": "claude-opus-4-6",
258
- "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5-20251001",
259
- "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6",
260
- "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-6",
261
- "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-4-5-20251001",
262
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
263
- },
264
- "hasCompletedOnboarding": true
265
- }`} />
266
- <Callout type="warning">Replace <CodeInline>YOUR_API_KEY</CodeInline> with your actual ClaudMax API key.</Callout>
267
-
268
- <SubTitle>Step 2: Configure MCP server</SubTitle>
269
- <Terminal filename="~/.claude.json" code={`{
270
- "mcpServers": {
271
- "ClaudMax": {
272
- "command": "npx",
273
- "args": ["-y", "claudmax-mcp"],
274
- "env": {
275
- "CLAUDMAX_API_KEY": "YOUR_API_KEY",
276
- "CLAUDMAX_URL": "${API_BASE}"
277
- }
278
- }
279
- }
280
- }`} />
281
-
282
- <SubTitle>Step 3: Reload your shell</SubTitle>
283
- <Terminal filename="terminal" code={`source ~/.zshrc # or source ~/.bashrc`} />
284
-
285
- <SubTitle>Step 4: Verify installation</SubTitle>
286
- <Terminal filename="terminal" code={`claude --version
287
- # Should show Claude Code version without errors`} />
288
-
289
- <Callout type="success">Claude Code is now configured to route all requests through ClaudMax.</Callout>
290
- </div>
291
- );
292
- }
293
-
294
- function VSSection() {
295
- return (
296
- <div id="vscode">
297
- <h1 className="text-3xl font-black text-[#111827] mb-2">VS Code</h1>
298
- <p className="text-[#9CA3AF] mb-6">The VS Code Claude extension uses the same configuration as Claude Code CLI.</p>
299
-
300
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
301
- <Para>Run the setup wizard and select VS Code:</Para>
302
- <Terminal filename="terminal" code={`npx claudmax`} />
303
-
304
- <SectionTitle>Manual Configuration</SectionTitle>
305
- <Para>Same files as Claude Code CLI. Create or edit:</Para>
306
- <ul className="list-disc list-inside text-sm text-[#6B7280] space-y-1.5 mb-4 ml-2">
307
- <li><CodeInline>~/.claude/settings.json</CodeInline></li>
308
- <li><CodeInline>~/.claude.json</CodeInline></li>
309
- </ul>
310
- <Callout type="warning">Restart VS Code after configuring the files.</Callout>
311
- </div>
312
- );
313
- }
314
-
315
- function CursorSection() {
316
- return (
317
- <div id="cursor">
318
- <h1 className="text-3xl font-black text-[#111827] mb-2">Cursor</h1>
319
- <p className="text-[#9CA3AF] mb-6">Configure Cursor IDE to use ClaudMax for AI assistance.</p>
320
-
321
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
322
- <Terminal filename="terminal" code={`npx claudmax`} />
323
-
324
- <SectionTitle>Manual MCP Configuration</SectionTitle>
325
- <SubTitle>Step 1: Configure MCP server</SubTitle>
326
- <Terminal filename="~/.cursor/mcp.json" code={`{
327
- "mcpServers": {
328
- "ClaudMax": {
329
- "command": "npx",
330
- "args": ["-y", "claudmax-mcp"],
331
- "env": {
332
- "CLAUDMAX_API_KEY": "YOUR_API_KEY",
333
- "CLAUDMAX_URL": "${API_BASE}"
334
- }
335
- }
336
- }
337
- }`} />
338
-
339
- <SubTitle>Step 2: Add API model in Cursor</SubTitle>
340
- <Para>Open Cursor Settings, navigate to Models, and add a custom OpenAI-compatible model:</Para>
341
- <CodeBlock label="Settings — Models — Add Custom Model">
342
- <div className="space-y-2 text-sm">
343
- <div className="flex justify-between"><span className="text-gray-500 font-medium">Base URL</span><code className="text-purple-600 font-mono text-xs">{API_BASE}</code></div>
344
- <div className="flex justify-between"><span className="text-gray-500 font-medium">API Key</span><code className="text-purple-600 font-mono text-xs">YOUR_API_KEY</code></div>
345
- <div className="flex justify-between"><span className="text-gray-500 font-medium">Model ID</span><code className="text-purple-600 font-mono text-xs">claude-sonnet-4-6</code></div>
346
- </div>
347
- </CodeBlock>
348
- <Callout type="success">Cursor will now route Claude requests through ClaudMax.</Callout>
349
- </div>
350
- );
351
- }
352
-
353
- function WindsurfSection() {
354
- return (
355
- <div id="windsurf">
356
- <h1 className="text-3xl font-black text-[#111827] mb-2">Windsurf</h1>
357
- <p className="text-[#9CA3AF] mb-6">Configure Windsurf IDE to use ClaudMax for AI assistance.</p>
358
-
359
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
360
- <Terminal filename="terminal" code={`npx claudmax`} />
361
-
362
- <SectionTitle>Manual MCP Configuration</SectionTitle>
363
- <SubTitle>Step 1: Configure MCP server</SubTitle>
364
- <Terminal filename="~/.windsurf/mcp.json" code={`{
365
- "mcpServers": {
366
- "ClaudMax": {
367
- "command": "npx",
368
- "args": ["-y", "claudmax-mcp"],
369
- "env": {
370
- "CLAUDMAX_API_KEY": "YOUR_API_KEY",
371
- "CLAUDMAX_URL": "${API_BASE}"
372
- }
373
- }
374
- }
375
- }`} />
376
-
377
- <SubTitle>Step 2: Set base URL in Windsurf</SubTitle>
378
- <Para>Open Windsurf Settings, navigate to AI Provider, and set the base URL:</Para>
379
- <CodeBlock label="Settings — AI Provider">
380
- <div className="space-y-2 text-sm">
381
- <div className="flex justify-between"><span className="text-gray-500 font-medium">Base URL</span><code className="text-purple-600 font-mono text-xs">{API_BASE}</code></div>
382
- <div className="flex justify-between"><span className="text-gray-500 font-medium">API Key</span><code className="text-purple-600 font-mono text-xs">YOUR_API_KEY</code></div>
383
- </div>
384
- </CodeBlock>
385
- </div>
386
- );
387
- }
388
-
389
- function ClineSection() {
390
- return (
391
- <div id="cline">
392
- <h1 className="text-3xl font-black text-[#111827] mb-2">Cline</h1>
393
- <p className="text-[#9CA3AF] mb-6">Configure Cline (VS Code extension) to use ClaudMax.</p>
394
-
395
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
396
- <Terminal filename="terminal" code={`npx claudmax`} />
397
-
398
- <SectionTitle>Manual Configuration</SectionTitle>
399
- <SubTitle>Edit VS Code Settings</SubTitle>
400
- <Para>Open VS Code, navigate to Extensions, then Cline Settings, and edit in settings.json:</Para>
401
- <Terminal filename="settings.json" code={`{
402
- "cline.apiProvider": "anthropic",
403
- "cline.anthropicBaseUrl": "${API_BASE}",
404
- "cline.apiKey": "YOUR_API_KEY"
405
- }`} />
406
- <Callout type="info">Cline also supports the MCP server configuration. See the Windsurf section for MCP setup.</Callout>
407
- </div>
408
- );
409
- }
410
-
411
- function RooCodeSection() {
412
- return (
413
- <div id="roo_code">
414
- <h1 className="text-3xl font-black text-[#111827] mb-2">Roo Code</h1>
415
- <p className="text-[#9CA3AF] mb-6">Configure Roo Code (VS Code extension) to use ClaudMax.</p>
416
-
417
- <SectionTitle>Automatic Setup (Recommended)</SectionTitle>
418
- <Terminal filename="terminal" code={`npx claudmax`} />
419
-
420
- <SectionTitle>Manual Configuration</SectionTitle>
421
- <SubTitle>Edit VS Code Settings</SubTitle>
422
- <Terminal filename="settings.json" code={`{
423
- "roo-cline.apiProvider": "anthropic",
424
- "roo-cline.anthropicBaseUrl": "${API_BASE}",
425
- "roo-cline.apiKey": "YOUR_API_KEY"
426
- }`} />
427
- </div>
428
- );
429
- }
430
-
431
- function AuthSection() {
432
- return (
433
- <div id="auth">
434
- <h1 className="text-3xl font-black text-[#111827] mb-2">Authentication</h1>
435
- <p className="text-[#9CA3AF] mb-6">All API requests require your ClaudMax API key passed via HTTP headers.</p>
436
-
437
- <SectionTitle>Passing Your API Key</SectionTitle>
438
- <Para>Include your API key in the <CodeInline>x-api-key</CodeInline> header or <CodeInline>Authorization: Bearer</CodeInline> header.</Para>
439
-
440
- <SubTitle>x-api-key Header</SubTitle>
441
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages \\
442
- -H "x-api-key: YOUR_API_KEY" \\
443
- -H "Content-Type: application/json" \\
444
- -d '{
445
- "model": "claude-sonnet-4-6",
446
- "max_tokens": 512,
447
- "messages": [{"role": "user", "content": "Hello!"}]
448
- }'`} />
449
-
450
- <SubTitle>Authorization Header</SubTitle>
451
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages \\
452
- -H "Authorization: Bearer YOUR_API_KEY" \\
453
- -H "Content-Type: application/json" \\
454
- -d '{
455
- "model": "claude-sonnet-4-6",
456
- "max_tokens": 512,
457
- "messages": [{"role": "user", "content": "Hello!"}]
458
- }'`} />
459
-
460
- <Callout type="warning">Never expose your API key in client-side code. Use server-side proxies or environment variables.</Callout>
461
- </div>
462
- );
463
- }
464
-
465
- function MessagesSection() {
466
- return (
467
- <div id="messages">
468
- <h1 className="text-3xl font-black text-[#111827] mb-2">Messages</h1>
469
- <p className="text-[#9CA3AF] mb-6">POST <CodeInline>{`${API_BASE}/v1/messages`}</CodeInline> — Send a conversation and receive a structured response.</p>
470
-
471
- <SectionTitle>Request Body</SectionTitle>
472
- <CodeBlock label="Fields">
473
- <div className="space-y-2 text-sm">
474
- {[
475
- { field: 'model', type: 'string', desc: 'Claude model ID (see Models)' },
476
- { field: 'messages', type: 'array', desc: 'Array of {role, content} message objects' },
477
- { field: 'system', type: 'string', desc: 'Optional system prompt (shorthand)' },
478
- { field: 'max_tokens', type: 'integer', desc: 'Maximum tokens in the response (min 1, max 8192)' },
479
- { field: 'temperature', type: 'number', desc: 'Sampling temperature (0.0–2.0, default: 1.0)' },
480
- { field: 'stream', type: 'boolean', desc: 'Enable server-sent events streaming (default: false)' },
481
- { field: 'tools', type: 'array', desc: 'MCP tools array for function calling' },
482
- ].map(f => (
483
- <div key={f.field} className="flex sm:justify-between sm:flex-row flex-col gap-1 border-b border-gray-100 last:border-0 py-2">
484
- <code className="text-purple-600 font-mono text-xs">{f.field}</code>
485
- <span className="text-blue-500 text-xs font-mono">{f.type}</span>
486
- <span className="text-gray-400 text-xs">{f.desc}</span>
487
- </div>
488
- ))}
489
- </div>
490
- </CodeBlock>
491
-
492
- <SubTitle>Standard Request</SubTitle>
493
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages \\
494
- -H "x-api-key: YOUR_API_KEY" \\
495
- -H "Content-Type: application/json" \\
496
- -d '{
497
- "model": "claude-sonnet-4-6",
498
- "max_tokens": 1024,
499
- "messages": [
500
- {"role": "user", "content": "What is 2 + 2?"}
501
- ]
502
- }'`} />
503
-
504
- <SubTitle>Streaming Response</SubTitle>
505
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages \\
506
- -H "x-api-key: YOUR_API_KEY" \\
507
- -H "Content-Type: application/json" \\
508
- -d '{
509
- "model": "claude-sonnet-4-6",
510
- "max_tokens": 1024,
511
- "stream": true,
512
- "messages": [
513
- {"role": "user", "content": "Write a haiku about the sea."}
514
- ]
515
- }'`} />
516
-
517
- <SectionTitle>Chat Completions (OpenAI-compatible)</SectionTitle>
518
- <Para>The <CodeInline>/v1/chat/completions</CodeInline> endpoint accepts the OpenAI chat completions format:</Para>
519
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/chat/completions \\
520
- -H "x-api-key: YOUR_API_KEY" \\
521
- -H "Content-Type: "application/json" \\
522
- -d '{
523
- "model": "claude-sonnet-4-6",
524
- "max_tokens": 1024,
525
- "messages": [
526
- {"role": "system", "content": "You are a helpful assistant."},
527
- {"role": "user", "content": "Hello!"}
528
- ]
529
- }'`} />
530
- <Callout type="info">Both <CodeInline>/v1/messages</CodeInline> (native Anthropic) and <CodeInline>/v1/chat/completions</CodeInline> (OpenAI-compatible) are supported.</Callout>
531
- </div>
532
- );
533
- }
534
-
535
- function ModelsSection() {
536
- return (
537
- <div id="models">
538
- <h1 className="text-3xl font-black text-[#111827] mb-2">Models</h1>
539
- <p className="text-[#9CA3AF] mb-6">All Claude models are accessible through ClaudMax with up to 200K context windows.</p>
540
-
541
- <SectionTitle>Available Models</SectionTitle>
542
- <CodeBlock label="Model Reference">
543
- <div className="overflow-x-auto">
544
- <table className="w-full text-sm">
545
- <thead>
546
- <tr className="border-b border-gray-100 bg-gray-50">
547
- {['Model ID', 'Name', 'Input', 'Output', 'Context', 'Best For'].map(h => (
548
- <th key={h} className="text-left px-3 py-2 text-xs font-bold text-gray-400 uppercase">{h}</th>
549
- ))}
550
- </tr>
551
- </thead>
552
- <tbody>
553
- {[
554
- { id: 'claude-opus-4-6', name: 'Opus 4.6', input: 'Text', output: 'Text', ctx: '200K', best: 'Complex analysis, research, long-form writing' },
555
- { id: 'claude-sonnet-4-6', name: 'Sonnet 4.6', input: 'Text', output: 'Text', ctx: '200K', best: 'General coding, reasoning, and assistance' },
556
- { id: 'claude-haiku-4-5-20251001', name: 'Haiku 4.5', input: 'Text', output: 'Text', ctx: '200K', best: 'High-volume tasks, quick completions' },
557
- { id: 'claude-sonnet-4-vision', name: 'Sonnet 4 Vision', input: 'Text+Img',output: 'Text', ctx: '200K', best: 'Image analysis, screenshots, document understanding' },
558
- { id: 'claude-image-4', name: 'Image 4', input: 'Text', output: 'Image', ctx: '200K', best: 'High-quality image generation from text prompts' },
559
- { id: 'claude-audio-4', name: 'Audio 4', input: 'Text', output: 'Audio', ctx: '200K', best: 'Natural text-to-speech, voice synthesis' },
560
- ].map(m => (
561
- <tr key={m.id} className="border-b border-gray-100 last:border-0 hover:bg-gray-50">
562
- <td className="px-3 py-2.5"><code className="text-purple-600 font-mono text-xs">{m.id}</code></td>
563
- <td className="px-3 py-2.5 text-gray-700 text-xs font-semibold">{m.name}</td>
564
- <td className="px-3 py-2.5 text-gray-500 text-xs">{m.input}</td>
565
- <td className="px-3 py-2.5 text-gray-500 text-xs">{m.output}</td>
566
- <td className="px-3 py-2.5 text-gray-400 text-xs font-mono">{m.ctx}</td>
567
- <td className="px-3 py-2.5 text-gray-500 text-xs">{m.best}</td>
568
- </tr>
569
- ))}
570
- </tbody>
571
- </table>
572
- </div>
573
- </CodeBlock>
574
- <Callout type="info">Model IDs are case-insensitive aliases: <CodeInline>opus</CodeInline>, <CodeInline>sonnet</CodeInline>, <CodeInline>haiku</CodeInline> all map to their respective Claude models.</Callout>
575
- </div>
576
- );
577
- }
578
-
579
- function TokenCountSection() {
580
- return (
581
- <div id="token_count">
582
- <h1 className="text-3xl font-black text-[#111827] mb-2">Token Counting</h1>
583
- <p className="text-[#9CA3AF] mb-6">Estimate token usage for a given input before sending to the API.</p>
584
-
585
- <SectionTitle>Endpoint</SectionTitle>
586
- <Para>POST <CodeInline>{`${API_BASE}/v1/messages/count_tokens`}</CodeInline></Para>
587
-
588
- <SubTitle>Request</SubTitle>
589
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/messages/count_tokens \\
590
- -H "x-api-key: YOUR_API_KEY" \\
591
- -H "Content-Type: application/json" \\
592
- -d '{
593
- "model": "claude-sonnet-4-6",
594
- "messages": [
595
- {"role": "user", "content": "Explain quantum entanglement."}
596
- ]
597
- }'`} />
598
-
599
- <SubTitle>Response</SubTitle>
600
- <Terminal filename="JSON Response" code={`{
601
- "input_tokens": 14,
602
- "output_tokens": 0,
603
- "total_tokens": 14
604
- }`} />
605
- <Callout type="info">Use this endpoint to check how many tokens a request will consume before making the actual API call.</Callout>
606
- </div>
607
- );
608
- }
609
-
610
- function KeyStatusSection() {
611
- return (
612
- <div id="key_status">
613
- <h1 className="text-3xl font-black text-[#111827] mb-2">Key Status</h1>
614
- <p className="text-[#9CA3AF] mb-6">Check your API key usage, limits, and validity in real time.</p>
615
-
616
- <SectionTitle>Endpoint</SectionTitle>
617
- <Para>POST <CodeInline>{`${API_BASE}/v1/key-status`}</CodeInline></Para>
618
-
619
- <SubTitle>Request</SubTitle>
620
- <Terminal filename="terminal" code={`curl -X POST ${API_BASE}/v1/key-status \\
621
- -H "Content-Type: application/json" \\
622
- -d '{
623
- "apiKey": "YOUR_API_KEY"
624
- }'`} />
625
-
626
- <SubTitle>Response Fields</SubTitle>
627
- <CodeBlock label="Fields">
628
- <div className="space-y-2 text-sm">
629
- {[
630
- { field: 'key', type: 'string', desc: 'Internal key ID' },
631
- { field: 'name', type: 'string', desc: 'Human-readable key name' },
632
- { field: 'tier', type: 'string', desc: 'Plan tier: free, 5x, 20x, unlimited' },
633
- { field: 'isActive', type: 'boolean', desc: 'Whether the key is active' },
634
- { field: 'requestsUsed', type: 'integer', desc: 'Requests used in the current 5h window' },
635
- { field: 'requestsLimit', type: 'integer', desc: 'Max requests per 5h window' },
636
- { field: 'tokensUsed', type: 'integer', desc: 'Tokens used (displayed, with multiplier)' },
637
- { field: 'tokensLimit', type: 'integer', desc: 'Max tokens per 5h window (displayed)' },
638
- { field: 'windowResetAt', type: 'string', desc: 'ISO 8601 timestamp when limits reset' },
639
- { field: 'tokensUsedActual', type: 'integer', desc: 'Actual backend token usage' },
640
- { field: 'tokensLeft', type: 'integer', desc: 'Tokens remaining in the window' },
641
- ].map(f => (
642
- <div key={f.field} className="flex sm:justify-between sm:flex-row flex-col gap-1 border-b border-gray-100 last:border-0 py-2">
643
- <code className="text-purple-600 font-mono text-xs">{f.field}</code>
644
- <span className="text-blue-500 text-xs font-mono">{f.type}</span>
645
- <span className="text-gray-400 text-xs">{f.desc}</span>
646
- </div>
647
- ))}
648
- </div>
649
- </CodeBlock>
650
-
651
- <SubTitle>Example Response</SubTitle>
652
- <Terminal filename="JSON Response" code={`{
653
- "key": "cmnhqfpx90000lpx5urf3rb31",
654
- "name": "ClaudMax Key",
655
- "tier": "20x",
656
- "isActive": true,
657
- "requestsUsed": 142,
658
- "requestsLimit": 2000,
659
- "tokensUsed": 3600000,
660
- "tokensLimit": 60000000,
661
- "tokensUsedActual": 1200000,
662
- "tokensLeft": 56400000,
663
- "windowResetAt": "2026-04-03T22:12:12.286Z",
664
- "createdAt": "2026-04-03T17:12:12.286Z",
665
- "lastUsedAt": "2026-04-03T19:15:00.000Z"
666
- }`} />
667
-
668
- <Callout type="info">Check usage visually at <Link href="/check-usage" className="underline font-semibold">claudmax.pro/check-usage</Link>.</Callout>
669
- </div>
670
- );
671
- }
672
-
673
- function MCPSection() {
674
- const tools = [
675
- { icon: <Search className="w-5 h-5 text-blue-500" />, name: 'Web Search', desc: 'Search the web for current information. Ideal for factual queries, news, and research.' },
676
- { icon: <Box className="w-5 h-5 text-purple-500" />, name: 'Image Analysis', desc: 'Analyze images using AI vision. Upload screenshots, diagrams, or photos for detailed descriptions.' },
677
- ];
678
-
679
- return (
680
- <div id="mcp">
681
- <h1 className="text-3xl font-black text-[#111827] mb-2">MCP Tools</h1>
682
- <p className="text-[#9CA3AF] mb-6">ClaudMax supports the Model Context Protocol (MCP) for tool use with Claude models.</p>
683
-
684
- <SectionTitle>Available Tools</SectionTitle>
685
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6">
686
- {tools.map(t => (
687
- <div key={t.name} className="bg-white rounded-xl border border-gray-200 p-4">
688
- <div className="mb-2">{t.icon}</div>
689
- <h3 className="font-bold text-sm text-[#111827] mb-1">{t.name}</h3>
690
- <p className="text-xs text-[#9CA3AF] leading-relaxed">{t.desc}</p>
691
- </div>
692
- ))}
693
- </div>
694
-
695
- <SectionTitle>Enabling MCP Tools</SectionTitle>
696
- <Para>MCP tools are supported on all Claude text models. Web search and image analysis are available via dedicated endpoints.</Para>
697
-
698
- <SubTitle>Python Example</SubTitle>
699
- <Terminal lang="python" filename="mcp_example.py" code={`from anthropic import Anthropic
700
-
701
- client = Anthropic(
702
- base_url="${API_BASE}",
703
- api_key="YOUR_API_KEY"
704
- )
705
-
706
- message = client.messages.create(
707
- model="claude-sonnet-4-6",
708
- max_tokens=1024,
709
- tools=[
710
- {
711
- "name": "get_weather",
712
- "description": "Get current weather for a city",
713
- "input_schema": {
714
- "type": "object",
715
- "properties": {
716
- "city": {"type": "string", "description": "City name"}
717
- },
718
- "required": ["city"]
719
- }
720
- }
721
- ],
722
- messages=[
723
- {"role": "user", "content": "What is the weather in Tokyo?"}
724
- ]
725
- )
726
-
727
- for content in message.content:
728
- if content.type == "tool_use":
729
- print(f"Tool: {content.name}, Input: {content.input}")
730
- elif content.type == "text":
731
- print(f"Response: {content.text}")`} />
732
-
733
- <SectionTitle>MCP Server Setup</SectionTitle>
734
- <Para>Install the ClaudMax MCP server globally:</Para>
735
- <Terminal filename="terminal" code={`npm install -g claudmax-mcp`} />
736
- <Para>Then add it to your IDE MCP configuration (see Claude Code CLI, Cursor, Windsurf sections above).</Para>
737
-
738
- <Callout type="info">The MCP server enables web search and image analysis as native Claude tools, accessible through the standard tools API.</Callout>
739
- </div>
740
- );
741
- }
742
-
743
- function LimitsSection() {
744
- return (
745
- <div id="limits">
746
- <h1 className="text-3xl font-black text-[#111827] mb-2">Rate Limits</h1>
747
- <p className="text-[#9CA3AF] mb-6">Rate limits are enforced per API key on a 5-hour rolling window. Limits reset automatically when the window expires.</p>
748
-
749
- <SectionTitle>Limits by Tier</SectionTitle>
750
- <CodeBlock label="Rate Limit Table">
751
- <div className="overflow-x-auto">
752
- <table className="w-full text-sm">
753
- <thead>
754
- <tr className="border-b border-gray-100 bg-gray-50">
755
- {['Tier', 'Requests / 5h', 'Tokens / 5h', 'Use Case'].map(h => (
756
- <th key={h} className="text-left px-3 py-2 text-xs font-bold text-gray-400 uppercase">{h}</th>
757
- ))}
758
- </tr>
759
- </thead>
760
- <tbody>
761
- {[
762
- { tier: 'Free', req: '100', tok: '500K', use: 'Learning, experimentation' },
763
- { tier: '5x Max', req: '500', tok: '5M', use: 'Individual developers, light workloads' },
764
- { tier: '20x Max', req: '2,000', tok: '20M', use: 'Power users, moderate production' },
765
- { tier: 'Unlimited', req: 'Infinite', tok: 'Infinite', use: 'Heavy production, unlimited scale' },
766
- ].map((t, i) => (
767
- <tr key={t.tier} className={`border-b border-gray-100 last:border-0 ${i === 0 ? 'bg-gray-50/50' : ''}`}>
768
- <td className="px-3 py-2.5"><span className="text-gray-700 text-xs font-semibold">{t.tier}</span></td>
769
- <td className="px-3 py-2.5 text-gray-500 text-xs font-mono">{t.req}</td>
770
- <td className="px-3 py-2.5 text-gray-500 text-xs font-mono">{t.tok}</td>
771
- <td className="px-3 py-2.5 text-gray-400 text-xs">{t.use}</td>
772
- </tr>
773
- ))}
774
- </tbody>
775
- </table>
776
- </div>
777
- </CodeBlock>
778
-
779
- <SectionTitle>Rate Limit Headers</SectionTitle>
780
- <CodeBlock label="Response Headers">
781
- <div className="space-y-2 text-sm">
782
- {[
783
- { h: 'x-ratelimit-limit', d: 'Total requests allowed in the window' },
784
- { h: 'x-ratelimit-remaining', d: 'Requests remaining in the current window' },
785
- { h: 'x-ratelimit-reset', d: 'ISO 8601 timestamp when the window resets' },
786
- ].map(r => (
787
- <div key={r.h} className="flex sm:justify-between sm:flex-row flex-col gap-1 border-b border-gray-100 last:border-0 py-2">
788
- <code className="text-purple-600 font-mono text-xs">{r.h}</code>
789
- <span className="text-gray-400 text-xs">{r.d}</span>
790
- </div>
791
- ))}
792
- </div>
793
- </CodeBlock>
794
-
795
- <Callout type="warning">When a rate limit is hit, the API returns <CodeInline>429 Too Many Requests</CodeInline>. Check the <CodeInline>x-ratelimit-reset</CodeInline> header for the reset timestamp.</Callout>
796
-
797
- <SectionTitle>Checking Your Usage</SectionTitle>
798
- <Para>Monitor your current usage:</Para>
799
- <Terminal filename="terminal" code={`npx claudmax status`} />
800
- </div>
801
- );
802
- }
803
-
804
- function TroubleshootingSection() {
805
- const issues = [
806
- { q: 'Invalid API key error (401)', a: 'Ensure your API key starts with sk-cmx_. Obtain a valid key from your administrator.', type: 'warning' },
807
- { q: 'Rate limit exceeded (429)', a: 'You have hit your per-5-hour window limit. Wait for the window to reset, or upgrade your tier.', type: 'warning' },
808
- { q: 'Model not found', a: "Ensure you are using a valid Claude model ID: claude-opus-4-6, claude-sonnet-4-6, or claude-haiku-4-5-20251001.", type: 'warning' },
809
- { q: 'Streaming not working', a: 'Set "stream": true in your request body. Ensure your client handles text/event-stream content type.', type: 'info' },
810
- { q: '403 / 500 server errors', a: 'The API gateway may be experiencing temporary issues. Check the status page and try again shortly.', type: 'warning' },
811
- { q: 'Cursor/Windsurf not connecting', a: 'Double-check the base URL is set to ' + API_BASE + ' (not /v1/chat or /v1/messages). Some providers require the base URL without the path suffix.', type: 'info' },
812
- { q: 'Token usage higher than expected', a: 'Token counts include both input (prompt) and output (response) tokens. Use /v1/key-status for accurate tracking.', type: 'info' },
813
- { q: 'CLI not found after installation', a: 'Ensure ~/.local/bin is in your PATH. Run: export PATH="$HOME/.local/bin:$PATH" && claudmax status.', type: 'warning' },
814
- ];
815
-
816
- return (
817
- <div id="troubleshooting">
818
- <h1 className="text-3xl font-black text-[#111827] mb-2">Troubleshooting</h1>
819
- <p className="text-[#9CA3AF] mb-6">Common issues and how to resolve them.</p>
820
-
821
- <div className="space-y-3">
822
- {issues.map(item => (
823
- <div key={item.q} className="bg-white rounded-xl border border-gray-200 p-4">
824
- <h3 className="font-bold text-sm text-[#111827] mb-1">{item.q}</h3>
825
- <p className="text-[#6B7280] text-sm leading-relaxed">{item.a}</p>
826
- </div>
827
- ))}
828
- </div>
829
-
830
- <div className="mt-6">
831
- <SectionTitle>Contact Support</SectionTitle>
832
- <Para>Still experiencing issues? Check the <Link href="/status" className="text-purple-600 underline">status page</Link> for live service updates.</Para>
833
- </div>
834
- </div>
835
- );
836
- }
837
-
838
- // ─── Page ─────────────────────────────────────────────────────────────────────
839
- export default function DocsPage() {
840
- const [activeSection, setActiveSection] = useState('overview');
841
- const [sidebarOpen, setSidebarOpen] = useState(false);
842
- const contentRef = useRef<HTMLDivElement>(null);
843
-
844
- const sectionIds = ['overview', 'claude_code', 'vscode', 'cursor', 'windsurf', 'cline', 'roo_code', 'auth', 'messages', 'models', 'token_count', 'key_status', 'mcp', 'limits', 'troubleshooting'];
845
-
846
- // IntersectionObserver to track the currently visible section
847
- useEffect(() => {
848
- const observer = new IntersectionObserver(
849
- (entries) => {
850
- entries.forEach((entry) => {
851
- if (entry.isIntersecting) {
852
- setActiveSection(entry.target.id);
853
- }
854
- });
855
- },
856
- {
857
- rootMargin: '-35% 0px -35% 0px',
858
- threshold: 0,
859
- }
860
- );
861
-
862
- sectionIds.forEach((id) => {
863
- const el = document.getElementById(id);
864
- if (el) observer.observe(el);
865
- });
866
-
867
- return () => observer.disconnect();
868
- }, [sectionIds]);
869
-
870
- // Auto-scroll: when active section scrolls above 20% of viewport, advance to next
871
- useEffect(() => {
872
- let isScrolling = false;
873
- let lockTimeout: ReturnType<typeof setTimeout>;
874
-
875
- const handleScroll = () => {
876
- if (isScrolling) return;
877
- const currentIndex = sectionIds.indexOf(activeSection);
878
- if (currentIndex === -1 || currentIndex >= sectionIds.length - 1) return;
879
-
880
- const el = document.getElementById(activeSection);
881
- if (!el) return;
882
-
883
- // When the section's bottom edge passes the top of the viewport
884
- const rect = el.getBoundingClientRect();
885
- const contentEl = contentRef.current;
886
- const viewportH = contentEl ? contentEl.clientHeight : window.innerHeight;
887
-
888
- if (rect.bottom < viewportH * 0.25) {
889
- const nextId = sectionIds[currentIndex + 1];
890
- const nextEl = document.getElementById(nextId);
891
- if (nextEl) {
892
- isScrolling = true;
893
- nextEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
894
- setActiveSection(nextId);
895
- clearTimeout(lockTimeout);
896
- lockTimeout = setTimeout(() => {
897
- isScrolling = false;
898
- }, 1200);
899
- }
900
- }
901
- };
902
-
903
- const contentEl = contentRef.current;
904
- if (contentEl) {
905
- contentEl.addEventListener('scroll', handleScroll, { passive: true });
906
- } else {
907
- window.addEventListener('scroll', handleScroll, { passive: true });
908
- }
909
-
910
- return () => {
911
- if (contentEl) {
912
- contentEl.removeEventListener('scroll', handleScroll);
913
- } else {
914
- window.removeEventListener('scroll', handleScroll);
915
- }
916
- clearTimeout(lockTimeout);
917
- };
918
- }, [activeSection, sectionIds]);
919
-
920
- const handleNavClick = (key: string) => {
921
- setActiveSection(key);
922
- setSidebarOpen(false);
923
- const el = document.getElementById(key);
924
- if (el) {
925
- el.scrollIntoView({ behavior: 'smooth', block: 'start' });
926
- // Sync scroll position for auto-scroll detection
927
- if (contentRef.current) contentRef.current.scrollTop = el.offsetTop - 20;
928
- }
929
- };
930
-
931
- const navGroups = [
932
- { label: 'Getting Started', items: [{ key: 'overview', label: 'Overview' }] },
933
- { label: 'IDE Setup', items: [
934
- { key: 'claude_code', label: 'Claude Code CLI' },
935
- { key: 'vscode', label: 'VS Code' },
936
- { key: 'cursor', label: 'Cursor' },
937
- { key: 'windsurf', label: 'Windsurf' },
938
- { key: 'cline', label: 'Cline' },
939
- { key: 'roo_code', label: 'Roo Code' },
940
- ]},
941
- { label: 'API Reference', items: [
942
- { key: 'auth', label: 'Authentication' },
943
- { key: 'messages', label: 'Messages' },
944
- { key: 'models', label: 'Models' },
945
- { key: 'token_count', label: 'Token Counting' },
946
- { key: 'key_status', label: 'Key Status' },
947
- ]},
948
- { label: 'Advanced', items: [
949
- { key: 'mcp', label: 'MCP Tools' },
950
- { key: 'limits', label: 'Rate Limits' },
951
- { key: 'troubleshooting', label: 'Troubleshooting' },
952
- ]},
953
- ];
954
-
955
- return (
956
- <div className="min-h-screen bg-[#F9FAFB] flex flex-col">
957
-
958
- {/* Header */}
959
- <header className="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-gray-200 shrink-0">
960
- <div className="flex items-center justify-between h-14 px-4 lg:px-6">
961
- <div className="flex items-center gap-4">
962
- <Link href="/" className="flex items-center gap-2">
963
- <div className="w-7 h-7 rounded-lg bg-gradient-to-br from-purple-600 to-purple-500 flex items-center justify-center">
964
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" className="text-white">
965
- <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="currentColor"/>
966
- </svg>
967
- </div>
968
- <span className="text-[#111827] font-bold text-base">ClaudMax</span>
969
- </Link>
970
- <span className="hidden sm:inline text-[#D1D5DB] text-xs">/</span>
971
- <span className="hidden sm:inline text-[#6B7280] text-sm font-medium">Documentation</span>
972
- </div>
973
-
974
- {/* Desktop nav */}
975
- <nav className="hidden md:flex items-center gap-4">
976
- <Link href="/" className="text-sm text-[#6B7280] hover:text-[#111827] transition-colors">Home</Link>
977
- <Link href="/docs" className="text-sm text-purple-600 font-medium transition-colors">Docs</Link>
978
- <Link href="/status" className="text-sm text-[#6B7280] hover:text-[#111827] transition-colors">Status</Link>
979
- <Link href="/check-usage" className="text-sm text-[#6B7280] hover:text-[#111827] transition-colors">Usage</Link>
980
- </nav>
981
-
982
- {/* Mobile hamburger */}
983
- <button
984
- onClick={() => setSidebarOpen(!sidebarOpen)}
985
- className="md:hidden w-8 h-8 flex items-center justify-center rounded-lg hover:bg-gray-100 transition-colors"
986
- aria-label="Toggle sidebar"
987
- >
988
- {sidebarOpen ? <X className="w-5 h-5 text-[#374151]" /> : <Menu className="w-5 h-5 text-[#374151]" />}
989
- </button>
990
- </div>
991
- </header>
992
-
993
- {/* Body: sidebar + content */}
994
- <div className="flex flex-col md:flex-row flex-1">
995
-
996
- {/* Sidebar overlay (mobile) */}
997
- {sidebarOpen && (
998
- <div
999
- className="fixed inset-0 z-40 bg-black/30 backdrop-blur-sm md:hidden"
1000
- onClick={() => setSidebarOpen(false)}
1001
- />
1002
- )}
1003
-
1004
- {/* Sidebar */}
1005
- <aside className={`
1006
- fixed md:sticky top-14 left-0 z-50 md:z-0 shrink-0
1007
- w-64 md:w-56 lg:w-64 md:h-fit md:max-h-[calc(100vh-3.5rem)] md:overflow-y-auto
1008
- bg-white md:bg-transparent border-r border-gray-200 md:border-0
1009
- pb-8 md:pb-0
1010
- transition-transform duration-200 ease-in-out
1011
- ${sidebarOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'}
1012
- `}>
1013
- <div className="p-4 md:pt-4">
1014
- {navGroups.map((group) => (
1015
- <div key={group.label} className="mb-5">
1016
- <p className="text-[#9CA3AF] text-xs font-bold uppercase tracking-widest mb-1.5 px-3">{group.label}</p>
1017
- {group.items.map((item) => (
1018
- <SidebarItem
1019
- key={item.key}
1020
- label={item.label}
1021
- icon={navIcons[item.key]}
1022
- active={activeSection === item.key}
1023
- onClick={() => handleNavClick(item.key)}
1024
- />
1025
- ))}
1026
- </div>
1027
- ))}
1028
- </div>
1029
- </aside>
1030
-
1031
- {/* Main content — render ALL sections for continuous scroll */}
1032
- <main ref={contentRef} className="flex-1 min-w-0 px-4 sm:px-6 lg:px-8 py-8 pb-20 overflow-y-auto" style={{ maxHeight: 'calc(100vh - 3.5rem)' }}>
1033
- <div className="max-w-3xl mx-auto space-y-4">
1034
- <OverviewSection />
1035
- <ClaudeCodeSection />
1036
- <VSSection />
1037
- <CursorSection />
1038
- <WindsurfSection />
1039
- <ClineSection />
1040
- <RooCodeSection />
1041
- <AuthSection />
1042
- <MessagesSection />
1043
- <ModelsSection />
1044
- <TokenCountSection />
1045
- <KeyStatusSection />
1046
- <MCPSection />
1047
- <LimitsSection />
1048
- <TroubleshootingSection />
1049
- </div>
1050
- </main>
1051
- </div>
1052
-
1053
- </div>
1054
- );
1055
- }