codex-claude-proxy 1.0.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.
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/docs/ACCOUNTS.md +202 -0
- package/docs/API.md +274 -0
- package/docs/ARCHITECTURE.md +133 -0
- package/docs/CLAUDE_INTEGRATION.md +163 -0
- package/docs/OAUTH.md +201 -0
- package/docs/OPENCLAW.md +338 -0
- package/images/f757093f-507b-4453-994e-f8275f8b07a9.png +0 -0
- package/package.json +44 -0
- package/public/css/style.css +791 -0
- package/public/index.html +783 -0
- package/public/js/app.js +511 -0
- package/src/account-manager.js +483 -0
- package/src/claude-config.js +143 -0
- package/src/cli/accounts.js +413 -0
- package/src/cli/index.js +66 -0
- package/src/direct-api.js +123 -0
- package/src/format-converter.js +331 -0
- package/src/index.js +41 -0
- package/src/kilo-api.js +68 -0
- package/src/kilo-format-converter.js +270 -0
- package/src/kilo-streamer.js +198 -0
- package/src/model-api.js +189 -0
- package/src/oauth.js +554 -0
- package/src/response-streamer.js +329 -0
- package/src/routes/api-routes.js +1035 -0
- package/src/server-settings.js +48 -0
- package/src/server.js +30 -0
- package/src/utils/logger.js +156 -0
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-theme="codex" class="dark">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Codex Claude Proxy</title>
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚀</text></svg>">
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
|
10
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
11
|
+
</head>
|
|
12
|
+
|
|
13
|
+
<body class="bg-space-950 text-gray-300 font-sans antialiased min-h-screen selection:bg-neon-purple selection:text-white"
|
|
14
|
+
x-data="app" x-init="init()">
|
|
15
|
+
|
|
16
|
+
<div class="fixed top-4 right-4 z-[100] flex flex-col gap-2 pointer-events-none">
|
|
17
|
+
<template x-if="toast">
|
|
18
|
+
<div x-transition:enter="transition ease-out duration-300"
|
|
19
|
+
x-transition:enter-start="opacity-0 translate-x-8 scale-95"
|
|
20
|
+
x-transition:enter-end="opacity-100 translate-x-0 scale-100"
|
|
21
|
+
x-transition:leave="transition ease-in duration-200"
|
|
22
|
+
x-transition:leave-start="opacity-100 translate-x-0 scale-100"
|
|
23
|
+
x-transition:leave-end="opacity-0 translate-x-4 scale-95"
|
|
24
|
+
class="alert shadow-lg border backdrop-blur-md pointer-events-auto min-w-[300px]"
|
|
25
|
+
:class="{
|
|
26
|
+
'alert-info border-neon-cyan/20 bg-space-900/90 text-neon-cyan': toast.type === 'info',
|
|
27
|
+
'alert-success border-neon-green/20 bg-space-900/90 text-neon-green': toast.type === 'success',
|
|
28
|
+
'alert-error border-red-500/20 bg-space-900/90 text-red-400': toast.type === 'error',
|
|
29
|
+
'alert-warning border-yellow-500/20 bg-space-900/90 text-yellow-400': toast.type === 'warning'
|
|
30
|
+
}">
|
|
31
|
+
<div class="flex items-center gap-3">
|
|
32
|
+
<template x-if="toast.type === 'info'">
|
|
33
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
34
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
35
|
+
</svg>
|
|
36
|
+
</template>
|
|
37
|
+
<template x-if="toast.type === 'success'">
|
|
38
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
39
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
40
|
+
</svg>
|
|
41
|
+
</template>
|
|
42
|
+
<template x-if="toast.type === 'error'">
|
|
43
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
44
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
45
|
+
</svg>
|
|
46
|
+
</template>
|
|
47
|
+
<template x-if="toast.type === 'warning'">
|
|
48
|
+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
49
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
50
|
+
</svg>
|
|
51
|
+
</template>
|
|
52
|
+
<span x-text="toast.message" class="font-mono text-sm"></span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="h-14 border-b border-space-border flex items-center px-4 lg:px-6 justify-between bg-space-900/50 backdrop-blur-md z-50 relative">
|
|
59
|
+
<div class="flex items-center gap-3">
|
|
60
|
+
<button @click="sidebarOpen = !sidebarOpen" class="text-gray-400 hover:text-white focus:outline-none p-1 transition-colors lg:hidden">
|
|
61
|
+
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
62
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
63
|
+
</svg>
|
|
64
|
+
</button>
|
|
65
|
+
|
|
66
|
+
<div class="w-8 h-8 rounded bg-gradient-to-br from-neon-purple to-blue-600 flex items-center justify-center text-white font-bold shadow-[0_0_15px_rgba(168,85,247,0.4)]">
|
|
67
|
+
CX
|
|
68
|
+
</div>
|
|
69
|
+
<div class="flex flex-col">
|
|
70
|
+
<span class="text-sm font-bold tracking-wide text-white">CODEX PROXY</span>
|
|
71
|
+
<div class="flex items-center gap-1.5">
|
|
72
|
+
<span class="text-[10px] text-gray-500 font-mono tracking-wider">CLAUDE PROXY SYSTEM</span>
|
|
73
|
+
<span class="text-[10px] text-gray-500 font-mono tracking-wider" x-text="'v' + version"></span>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="flex items-center gap-4">
|
|
79
|
+
<div class="flex items-center gap-2 px-3 py-1 rounded-full text-xs font-mono border transition-all duration-300"
|
|
80
|
+
:class="connectionStatus === 'connected'
|
|
81
|
+
? 'bg-neon-green/10 border-neon-green/20 text-neon-green'
|
|
82
|
+
: 'bg-red-500/10 border-red-500/20 text-red-500'">
|
|
83
|
+
<div class="w-1.5 h-1.5 rounded-full"
|
|
84
|
+
:class="connectionStatus === 'connected' ? 'bg-neon-green shadow-[0_0_8px_rgba(34,197,94,0.6)]' : 'bg-red-500'">
|
|
85
|
+
</div>
|
|
86
|
+
<span x-text="connectionStatus === 'connected' ? 'Online' : 'Offline'"></span>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="h-4 w-px bg-space-border"></div>
|
|
90
|
+
|
|
91
|
+
<button type="button" class="btn btn-ghost btn-xs btn-square text-gray-400 hover:text-white hover:bg-white/5"
|
|
92
|
+
@click="refreshAccounts()" :disabled="loading" title="Refresh data">
|
|
93
|
+
<svg class="w-4 h-4" :class="{'animate-spin': loading}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
94
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
95
|
+
</svg>
|
|
96
|
+
</button>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="flex h-[calc(100vh-56px)] relative">
|
|
101
|
+
<div x-show="sidebarOpen" x-transition:enter="transition-opacity ease-linear duration-300"
|
|
102
|
+
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
|
|
103
|
+
x-transition:leave="transition-opacity ease-linear duration-300"
|
|
104
|
+
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
|
|
105
|
+
@click="sidebarOpen = false" class="fixed inset-0 bg-black/50 z-40 lg:hidden" style="display: none;"></div>
|
|
106
|
+
|
|
107
|
+
<div class="fixed top-14 bottom-0 left-0 z-40 w-64 transform bg-space-900 border-r border-space-border transition-all duration-300 shadow-2xl overflow-hidden lg:static lg:h-auto lg:shadow-none lg:flex-shrink-0 lg:translate-x-0"
|
|
108
|
+
:class="{
|
|
109
|
+
'translate-x-0': sidebarOpen,
|
|
110
|
+
'-translate-x-full': !sidebarOpen
|
|
111
|
+
}">
|
|
112
|
+
<div class="w-64 flex flex-col h-full pt-6 pb-4 flex-shrink-0">
|
|
113
|
+
<div class="px-4 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest hidden lg:block">Main</div>
|
|
114
|
+
|
|
115
|
+
<nav class="flex flex-col gap-1">
|
|
116
|
+
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
117
|
+
:class="{'active': activeTab === 'dashboard'}" @click="setActiveTab('dashboard')">
|
|
118
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
119
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
|
|
120
|
+
</svg>
|
|
121
|
+
<span>Dashboard</span>
|
|
122
|
+
</button>
|
|
123
|
+
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
124
|
+
:class="{'active': activeTab === 'accounts'}" @click="setActiveTab('accounts')">
|
|
125
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
126
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
127
|
+
</svg>
|
|
128
|
+
<span>Accounts</span>
|
|
129
|
+
</button>
|
|
130
|
+
</nav>
|
|
131
|
+
|
|
132
|
+
<div class="px-4 mt-8 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest">System</div>
|
|
133
|
+
<nav class="flex flex-col gap-1">
|
|
134
|
+
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
135
|
+
:class="{'active': activeTab === 'logs'}" @click="setActiveTab('logs')">
|
|
136
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
137
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
138
|
+
</svg>
|
|
139
|
+
<span>Logs</span>
|
|
140
|
+
</button>
|
|
141
|
+
<button class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
|
|
142
|
+
:class="{'active': activeTab === 'settings'}" @click="setActiveTab('settings')">
|
|
143
|
+
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
144
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
145
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
146
|
+
</svg>
|
|
147
|
+
<span>Settings</span>
|
|
148
|
+
</button>
|
|
149
|
+
</nav>
|
|
150
|
+
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="flex-1 overflow-auto bg-space-950 relative custom-scrollbar">
|
|
155
|
+
<div x-show="activeTab === 'dashboard'" x-transition class="view-container">
|
|
156
|
+
<div class="flex items-center justify-between gap-4 mb-6">
|
|
157
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
158
|
+
<h1 class="text-2xl font-bold text-white tracking-tight">Dashboard</h1>
|
|
159
|
+
<div class="flex items-center h-6 px-3 rounded-full bg-space-800/80 border border-space-border/50 shadow-sm backdrop-blur-sm">
|
|
160
|
+
<span class="text-[10px] font-mono text-gray-400 uppercase tracking-wider">CHATGPT PROXY SYSTEM</span>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="flex items-center gap-2 px-2.5 py-1.5 rounded-lg bg-space-900/60 border border-space-border/40 whitespace-nowrap flex-shrink-0">
|
|
164
|
+
<div class="relative flex items-center justify-center">
|
|
165
|
+
<span class="absolute w-1.5 h-1.5 bg-neon-green rounded-full animate-ping opacity-75"></span>
|
|
166
|
+
<span class="relative w-1.5 h-1.5 bg-neon-green rounded-full"></span>
|
|
167
|
+
</div>
|
|
168
|
+
<span class="text-[10px] font-mono text-gray-500 uppercase tracking-wider">Live</span>
|
|
169
|
+
<span class="text-gray-700">•</span>
|
|
170
|
+
<span class="text-[10px] font-mono text-gray-400 tabular-nums" x-text="currentTime"></span>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2 lg:gap-3 mb-6">
|
|
175
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 hover:border-cyan-500/30 hover:bg-cyan-500/5 transition-all duration-300 group relative cursor-pointer min-w-0">
|
|
176
|
+
<div class="absolute top-3 right-3 text-gray-700/40 group-hover:text-cyan-400/70 transition-colors">
|
|
177
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-4 h-4 sm:w-5 sm:h-5 stroke-current">
|
|
178
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
|
179
|
+
</svg>
|
|
180
|
+
</div>
|
|
181
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="stats.total"></div>
|
|
182
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Total Accounts</div>
|
|
183
|
+
<div class="stat-desc text-cyan-400/60 text-[10px] truncate">Linked accounts</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 hover:border-green-500/30 hover:bg-green-500/5 transition-all duration-300 group relative cursor-pointer min-w-0">
|
|
187
|
+
<div class="absolute top-3 right-3 text-gray-700/40 group-hover:text-green-400/70 transition-colors">
|
|
188
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-4 h-4 sm:w-5 sm:h-5 stroke-current">
|
|
189
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
190
|
+
</svg>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="stats.active"></div>
|
|
193
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Active</div>
|
|
194
|
+
<div class="stat-desc text-green-400/60 text-[10px] truncate">Operational</div>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 hover:border-yellow-500/30 hover:bg-yellow-500/5 transition-all duration-300 group relative cursor-pointer min-w-0">
|
|
198
|
+
<div class="absolute top-3 right-3 text-gray-700/40 group-hover:text-yellow-400/70 transition-colors">
|
|
199
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-4 h-4 sm:w-5 sm:h-5 stroke-current">
|
|
200
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
201
|
+
</svg>
|
|
202
|
+
</div>
|
|
203
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="stats.expired"></div>
|
|
204
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Token Expired</div>
|
|
205
|
+
<div class="stat-desc text-yellow-400/60 text-[10px] truncate">Needs refresh</div>
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
<div class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-3 lg:p-4 hover:border-purple-500/30 hover:bg-purple-500/5 transition-all duration-300 group relative cursor-pointer min-w-0">
|
|
209
|
+
<div class="absolute top-3 right-3 text-gray-700/40 group-hover:text-purple-400/70 transition-colors">
|
|
210
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-4 h-4 sm:w-5 sm:h-5 stroke-current">
|
|
211
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"></path>
|
|
212
|
+
</svg>
|
|
213
|
+
</div>
|
|
214
|
+
<div class="stat-value text-white font-mono text-2xl lg:text-3xl font-bold mb-1 truncate" x-text="stats.planType"></div>
|
|
215
|
+
<div class="stat-title text-gray-500 font-mono text-[10px] uppercase tracking-wider truncate">Active Plan</div>
|
|
216
|
+
<div class="stat-desc text-purple-400/60 text-[10px] truncate">Current tier</div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div class="view-card">
|
|
221
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
222
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-purple">
|
|
223
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
|
224
|
+
</svg>
|
|
225
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Quick Test</h3>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="flex gap-3">
|
|
228
|
+
<input type="text" x-model="testPrompt" placeholder="Enter a test prompt..."
|
|
229
|
+
class="input flex-1 bg-space-800 border-space-border text-white font-mono text-sm">
|
|
230
|
+
<button class="btn bg-neon-purple hover:bg-purple-600 border-none text-white btn-sm gap-2"
|
|
231
|
+
@click="testChat()" :disabled="testing">
|
|
232
|
+
<svg class="w-4 h-4" :class="{'animate-spin': testing}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
233
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
|
234
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
235
|
+
</svg>
|
|
236
|
+
<span>Test</span>
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
239
|
+
<div x-show="testResponse" class="mt-4 p-3 rounded-lg bg-space-800/50 border border-space-border/30">
|
|
240
|
+
<pre class="text-xs font-mono text-gray-300 whitespace-pre-wrap" x-text="testResponse"></pre>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<div class="view-card mt-6">
|
|
245
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
246
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-cyan">
|
|
247
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
|
248
|
+
</svg>
|
|
249
|
+
<div class="flex items-center gap-2">
|
|
250
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Haiku (Kilo) Test</h3>
|
|
251
|
+
<span class="text-[10px] font-mono text-gray-500" x-text="haikuModelLabel()"></span>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
<div class="flex gap-3">
|
|
255
|
+
<input type="text" x-model="haikuTestPrompt" placeholder="Enter a Haiku prompt..."
|
|
256
|
+
class="input flex-1 bg-space-800 border-space-border text-white font-mono text-sm">
|
|
257
|
+
<button class="btn bg-neon-cyan hover:bg-cyan-600 border-none text-white btn-sm gap-2"
|
|
258
|
+
@click="testHaikuChat()" :disabled="haikuTesting">
|
|
259
|
+
<svg class="w-4 h-4" :class="{'animate-spin': haikuTesting}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
260
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
|
261
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
262
|
+
</svg>
|
|
263
|
+
<span>Test Haiku</span>
|
|
264
|
+
</button>
|
|
265
|
+
</div>
|
|
266
|
+
<div x-show="haikuTestResponse" class="mt-4 p-3 rounded-lg bg-space-800/50 border border-space-border/30">
|
|
267
|
+
<pre class="text-xs font-mono text-gray-300 whitespace-pre-wrap" x-text="haikuTestResponse"></pre>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div class="view-card mt-6">
|
|
272
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
273
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-cyan">
|
|
274
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
275
|
+
</svg>
|
|
276
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Usage with Claude Code</h3>
|
|
277
|
+
</div>
|
|
278
|
+
<div class="bg-space-800/50 border border-space-border/30 rounded-lg p-4 font-mono text-sm text-gray-300">
|
|
279
|
+
<div class="text-gray-500 mb-2"># Set environment variables</div>
|
|
280
|
+
<div class="text-neon-cyan">export ANTHROPIC_BASE_URL=http://localhost:8081</div>
|
|
281
|
+
<div class="text-neon-cyan">export ANTHROPIC_API_KEY=any-key</div>
|
|
282
|
+
<div class="text-gray-500 mt-2 mb-2"># Run Claude</div>
|
|
283
|
+
<div class="text-neon-green">claude</div>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<div x-show="activeTab === 'accounts'" x-transition class="view-container">
|
|
289
|
+
<div class="flex items-center justify-between gap-4 mb-6">
|
|
290
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
291
|
+
<h1 class="text-2xl font-bold text-white tracking-tight">Account Management</h1>
|
|
292
|
+
<div class="flex items-center h-6 px-3 rounded-full bg-space-800/80 border border-space-border/50 shadow-sm backdrop-blur-sm">
|
|
293
|
+
<span class="text-[10px] font-mono text-gray-400 uppercase tracking-wider">Manage ChatGPT accounts</span>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<div class="flex flex-wrap items-center justify-end gap-2 sm:flex-nowrap">
|
|
298
|
+
<div class="relative" x-show="accounts.length > 0">
|
|
299
|
+
<input type="text" x-model="searchQuery" placeholder="Search accounts..."
|
|
300
|
+
class="input-search-sm w-48 pl-9 h-8" @keydown.escape="searchQuery = ''">
|
|
301
|
+
<svg class="w-4 h-4 absolute left-3 top-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
302
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
303
|
+
</svg>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
<button class="btn btn-xs btn-outline border-space-border text-gray-400 hover:text-white transition-all gap-2 h-8"
|
|
307
|
+
@click="refreshAllTokens()" x-show="accounts.length > 0">
|
|
308
|
+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
309
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"></path>
|
|
310
|
+
</svg>
|
|
311
|
+
<span>Refresh All</span>
|
|
312
|
+
</button>
|
|
313
|
+
|
|
314
|
+
<div class="flex items-center h-6 px-2 rounded bg-space-800/80 border border-space-border/50 sm:ml-1">
|
|
315
|
+
<span class="text-[11px] font-mono text-gray-400" x-text="accounts.length + ' accounts'"></span>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<button class="btn bg-neon-purple hover:bg-purple-600 border-none text-white btn-xs gap-2 shadow-lg shadow-neon-purple/20 h-8"
|
|
319
|
+
@click="showAddModal = true">
|
|
320
|
+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
321
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
322
|
+
</svg>
|
|
323
|
+
<span>Add Account</span>
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<div class="view-card !p-0 overflow-x-auto">
|
|
329
|
+
<table class="w-full min-w-[860px]">
|
|
330
|
+
<thead x-show="filteredAccounts.length > 0">
|
|
331
|
+
<tr class="bg-space-900/50 border-b border-space-border/50">
|
|
332
|
+
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-20">Status</th>
|
|
333
|
+
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider flex-1 min-w-[200px]">Account (Email)</th>
|
|
334
|
+
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-20">Plan</th>
|
|
335
|
+
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-32">Token</th>
|
|
336
|
+
<th class="py-3 text-left text-[10px] font-bold text-gray-500 uppercase tracking-wider w-24">Quota</th>
|
|
337
|
+
<th class="py-3 pr-6 text-right text-[10px] font-bold text-gray-500 uppercase tracking-wider w-40">Operations</th>
|
|
338
|
+
</tr>
|
|
339
|
+
</thead>
|
|
340
|
+
<tbody>
|
|
341
|
+
<template x-if="filteredAccounts.length === 0 && accounts.length === 0">
|
|
342
|
+
<tr>
|
|
343
|
+
<td colspan="6" class="py-16 text-center">
|
|
344
|
+
<div class="flex flex-col items-center gap-4 max-w-lg mx-auto">
|
|
345
|
+
<svg class="w-20 h-20 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
346
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
|
347
|
+
</svg>
|
|
348
|
+
<h3 class="text-xl font-semibold text-gray-400">No Accounts Yet</h3>
|
|
349
|
+
<p class="text-sm text-gray-600 max-w-md leading-relaxed">Get started by adding a ChatGPT account via OAuth, or import from the Codex app.</p>
|
|
350
|
+
<div class="flex items-center gap-4 mt-2">
|
|
351
|
+
<button class="btn bg-neon-purple hover:bg-purple-600 border-none text-white btn-sm gap-2 shadow-lg shadow-neon-purple/20"
|
|
352
|
+
@click="showAddModal = true">
|
|
353
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
354
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
355
|
+
</svg>
|
|
356
|
+
<span>Add Your First Account</span>
|
|
357
|
+
</button>
|
|
358
|
+
<span class="text-xs text-gray-600">or</span>
|
|
359
|
+
<button class="btn btn-outline btn-sm text-gray-400" @click="importFromCodex()">
|
|
360
|
+
Import from Codex
|
|
361
|
+
</button>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
</td>
|
|
365
|
+
</tr>
|
|
366
|
+
</template>
|
|
367
|
+
|
|
368
|
+
<template x-for="acc in filteredAccounts" :key="acc.email">
|
|
369
|
+
<tr class="border-b border-space-border/30 last:border-0 hover:bg-white/5 transition-colors group">
|
|
370
|
+
<td class="py-4 pl-6">
|
|
371
|
+
<div class="flex items-center gap-2">
|
|
372
|
+
<div class="w-2 h-2 rounded-full flex-shrink-0"
|
|
373
|
+
:class="acc.isActive ? 'bg-neon-green shadow-[0_0_8px_rgba(34,197,94,0.6)] animate-pulse' : 'bg-gray-500'">
|
|
374
|
+
</div>
|
|
375
|
+
<span class="text-xs font-mono font-semibold"
|
|
376
|
+
:class="acc.isActive ? 'text-neon-green' : 'text-gray-500'"
|
|
377
|
+
x-text="acc.isActive ? 'ACTIVE' : 'IDLE'">
|
|
378
|
+
</span>
|
|
379
|
+
</div>
|
|
380
|
+
</td>
|
|
381
|
+
<td class="py-4">
|
|
382
|
+
<span class="font-mono text-sm text-gray-300 truncate max-w-[320px] inline-block group-hover:text-white transition-colors"
|
|
383
|
+
x-text="acc.email"></span>
|
|
384
|
+
</td>
|
|
385
|
+
<td class="py-4">
|
|
386
|
+
<span class="text-[10px] font-bold uppercase px-2 py-1 rounded"
|
|
387
|
+
:class="{
|
|
388
|
+
'bg-yellow-500/10 text-yellow-400 border border-yellow-500/30': acc.planType === 'plus',
|
|
389
|
+
'bg-blue-500/10 text-blue-400 border border-blue-500/30': acc.planType === 'pro',
|
|
390
|
+
'bg-gray-500/10 text-gray-400 border border-gray-500/30': acc.planType === 'free'
|
|
391
|
+
}"
|
|
392
|
+
x-text="(acc.planType || 'free').toUpperCase()"></span>
|
|
393
|
+
</td>
|
|
394
|
+
<td class="py-4">
|
|
395
|
+
<div class="flex items-center gap-2">
|
|
396
|
+
<span class="text-xs font-mono"
|
|
397
|
+
:class="acc.tokenExpired ? 'text-red-400' : 'text-neon-green'"
|
|
398
|
+
x-text="acc.tokenExpired ? 'Expired' : 'Valid'"></span>
|
|
399
|
+
</div>
|
|
400
|
+
</td>
|
|
401
|
+
<td class="py-4 cursor-pointer" @click="showQuotaModal(acc)">
|
|
402
|
+
<template x-if="getRemainingPercentage(acc) !== null">
|
|
403
|
+
<div class="flex flex-col gap-1">
|
|
404
|
+
<div class="flex items-center gap-2">
|
|
405
|
+
<div class="w-16 bg-gray-700 rounded-full h-2 overflow-hidden">
|
|
406
|
+
<div class="h-full rounded-full transition-all"
|
|
407
|
+
:class="quotaBarClass(acc)"
|
|
408
|
+
:style="`width: ${getRemainingPercentage(acc)}%`">
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
<template x-if="isQuotaExhausted(acc)">
|
|
412
|
+
<span class="text-[10px] font-bold uppercase text-red-400 bg-red-500/10 px-1.5 py-0.5 rounded border border-red-500/30">USED</span>
|
|
413
|
+
</template>
|
|
414
|
+
<template x-if="!isQuotaExhausted(acc)">
|
|
415
|
+
<span class="text-xs font-mono"
|
|
416
|
+
:class="quotaTextClass(acc)"
|
|
417
|
+
x-text="quotaLabel(acc)"></span>
|
|
418
|
+
</template>
|
|
419
|
+
</div>
|
|
420
|
+
<template x-if="quotaResetSummary(acc)">
|
|
421
|
+
<span class="text-[10px] font-mono text-gray-500" x-text="quotaResetSummary(acc)"></span>
|
|
422
|
+
</template>
|
|
423
|
+
</div>
|
|
424
|
+
</template>
|
|
425
|
+
<template x-if="getRemainingPercentage(acc) === null">
|
|
426
|
+
<span class="text-xs text-gray-600">-</span>
|
|
427
|
+
</template>
|
|
428
|
+
</td>
|
|
429
|
+
<td class="py-4 pr-6">
|
|
430
|
+
<div class="flex justify-end gap-2">
|
|
431
|
+
<button x-show="!acc.isActive"
|
|
432
|
+
class="px-3 py-1 text-[10px] font-bold font-mono uppercase tracking-wider rounded bg-neon-purple/10 text-neon-purple hover:bg-neon-purple/20 border border-neon-purple/30 hover:border-neon-purple/50 transition-all"
|
|
433
|
+
@click="switchAccount(acc.email)">
|
|
434
|
+
SWITCH
|
|
435
|
+
</button>
|
|
436
|
+
<button class="btn btn-xs btn-ghost p-2 rounded hover:bg-white/10 text-gray-500 hover:text-white transition-colors"
|
|
437
|
+
@click="refreshToken(acc.email)" title="Refresh token">
|
|
438
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
439
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
440
|
+
</svg>
|
|
441
|
+
</button>
|
|
442
|
+
<button class="btn btn-xs btn-ghost p-2 rounded hover:bg-red-500/10 text-gray-500 hover:text-red-400 transition-colors"
|
|
443
|
+
@click="confirmDelete(acc.email)" title="Delete account">
|
|
444
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
445
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
446
|
+
</svg>
|
|
447
|
+
</button>
|
|
448
|
+
</div>
|
|
449
|
+
</td>
|
|
450
|
+
</tr>
|
|
451
|
+
</template>
|
|
452
|
+
|
|
453
|
+
<template x-if="accounts.length > 0 && filteredAccounts.length === 0">
|
|
454
|
+
<tr>
|
|
455
|
+
<td colspan="6" class="py-12 text-center">
|
|
456
|
+
<div class="flex flex-col items-center gap-3">
|
|
457
|
+
<svg class="w-12 h-12 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
458
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
459
|
+
</svg>
|
|
460
|
+
<p class="text-sm text-gray-600">No accounts match your search</p>
|
|
461
|
+
<button class="text-xs text-neon-cyan hover:underline" @click="searchQuery = ''">Clear Search</button>
|
|
462
|
+
</div>
|
|
463
|
+
</td>
|
|
464
|
+
</tr>
|
|
465
|
+
</template>
|
|
466
|
+
</tbody>
|
|
467
|
+
</table>
|
|
468
|
+
</div>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<div x-show="activeTab === 'logs'" x-transition class="view-container h-full flex flex-col">
|
|
472
|
+
<div class="flex items-center justify-between gap-4 mb-6">
|
|
473
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
474
|
+
<h1 class="text-2xl font-bold text-white tracking-tight">Server Logs</h1>
|
|
475
|
+
<div class="flex items-center h-6 px-3 rounded-full bg-space-800/80 border border-space-border/50 shadow-sm backdrop-blur-sm">
|
|
476
|
+
<span class="text-[10px] font-mono text-gray-400 uppercase tracking-wider">Real-time log stream</span>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
<div class="flex items-center gap-3">
|
|
480
|
+
<div class="text-[10px] font-mono text-gray-600">
|
|
481
|
+
<span x-text="logs.length"></span> entries
|
|
482
|
+
</div>
|
|
483
|
+
<button class="btn btn-xs btn-ghost text-gray-400 hover:text-white" @click="clearLogs()" title="Clear logs">
|
|
484
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
485
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
486
|
+
</svg>
|
|
487
|
+
</button>
|
|
488
|
+
</div>
|
|
489
|
+
</div>
|
|
490
|
+
|
|
491
|
+
<div class="view-card !p-0 flex flex-col flex-1 min-h-0">
|
|
492
|
+
<div class="bg-space-900 flex items-center p-2 px-4 border-b border-space-border gap-4">
|
|
493
|
+
<div class="flex gap-2">
|
|
494
|
+
<div class="w-3 h-3 rounded-full bg-red-500/20 border border-red-500/50"></div>
|
|
495
|
+
<div class="w-3 h-3 rounded-full bg-yellow-500/20 border border-yellow-500/50"></div>
|
|
496
|
+
<div class="w-3 h-3 rounded-full bg-green-500/20 border border-green-500/50"></div>
|
|
497
|
+
</div>
|
|
498
|
+
<span class="text-xs font-mono text-gray-500 hidden sm:inline-block">~/logs</span>
|
|
499
|
+
|
|
500
|
+
<div class="flex-1 flex items-center justify-center gap-4">
|
|
501
|
+
<div class="relative w-full max-w-xs">
|
|
502
|
+
<input type="text" x-model="logSearchQuery" placeholder="Search logs..."
|
|
503
|
+
class="w-full h-7 bg-space-950 border border-space-border rounded text-xs font-mono pl-7 pr-2 focus:border-neon-purple focus:outline-none transition-colors placeholder-gray-700 text-gray-300">
|
|
504
|
+
<svg class="w-3 h-3 absolute left-2.5 top-2 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
505
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
506
|
+
</svg>
|
|
507
|
+
</div>
|
|
508
|
+
|
|
509
|
+
<div class="hidden md:flex gap-3 text-[10px] font-mono font-bold uppercase select-none">
|
|
510
|
+
<label class="flex items-center gap-1.5 cursor-pointer text-blue-400 opacity-50 hover:opacity-100 transition-opacity" :class="{'opacity-100': logFilters.INFO}">
|
|
511
|
+
<input type="checkbox" class="checkbox checkbox-xs rounded-[2px] w-3 h-3" x-model="logFilters.INFO"> INFO
|
|
512
|
+
</label>
|
|
513
|
+
<label class="flex items-center gap-1.5 cursor-pointer text-green-400 opacity-50 hover:opacity-100 transition-opacity" :class="{'opacity-100': logFilters.SUCCESS}">
|
|
514
|
+
<input type="checkbox" class="checkbox checkbox-xs rounded-[2px] w-3 h-3" x-model="logFilters.SUCCESS"> SUCCESS
|
|
515
|
+
</label>
|
|
516
|
+
<label class="flex items-center gap-1.5 cursor-pointer text-yellow-400 opacity-50 hover:opacity-100 transition-opacity" :class="{'opacity-100': logFilters.WARN}">
|
|
517
|
+
<input type="checkbox" class="checkbox checkbox-xs rounded-[2px] w-3 h-3" x-model="logFilters.WARN"> WARN
|
|
518
|
+
</label>
|
|
519
|
+
<label class="flex items-center gap-1.5 cursor-pointer text-red-500 opacity-50 hover:opacity-100 transition-opacity" :class="{'opacity-100': logFilters.ERROR}">
|
|
520
|
+
<input type="checkbox" class="checkbox checkbox-xs rounded-[2px] w-3 h-3" x-model="logFilters.ERROR"> ERROR
|
|
521
|
+
</label>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
<div id="logs-container" class="flex-1 overflow-auto p-4 font-mono text-[11px] leading-relaxed bg-space-950 custom-scrollbar">
|
|
527
|
+
<template x-for="(log, idx) in filteredLogs" :key="idx">
|
|
528
|
+
<div class="flex gap-3 px-2 py-1 -mx-2 hover:bg-white/[0.03] transition-colors group border-b border-space-border/10">
|
|
529
|
+
<span class="text-zinc-600 w-16 shrink-0 select-none group-hover:text-zinc-500 transition-colors"
|
|
530
|
+
x-text="new Date(log.timestamp).toLocaleTimeString([], {hour12:false})"></span>
|
|
531
|
+
<div class="w-16 shrink-0 flex items-center">
|
|
532
|
+
<span class="px-1.5 py-0.5 rounded-[2px] text-[10px] font-bold uppercase tracking-wider leading-none border"
|
|
533
|
+
:class="{
|
|
534
|
+
'bg-blue-500/10 text-blue-400 border-blue-500/20': log.level === 'INFO',
|
|
535
|
+
'bg-yellow-500/10 text-yellow-400 border-yellow-500/20': log.level === 'WARN',
|
|
536
|
+
'bg-red-500/10 text-red-500 border-red-500/20': log.level === 'ERROR',
|
|
537
|
+
'bg-emerald-500/10 text-emerald-400 border-emerald-500/20': log.level === 'SUCCESS',
|
|
538
|
+
'bg-purple-500/10 text-purple-400 border-purple-500/20': log.level === 'DEBUG'
|
|
539
|
+
}" x-text="log.level"></span>
|
|
540
|
+
</div>
|
|
541
|
+
<div class="flex-1 flex flex-col gap-0.5 min-w-0">
|
|
542
|
+
<span class="text-zinc-200 break-all group-hover:text-white transition-colors"
|
|
543
|
+
x-text="formatLogMessage(log.message)"></span>
|
|
544
|
+
<template x-if="getLogDetails(log.message)">
|
|
545
|
+
<div class="flex flex-wrap gap-2 text-[10px] text-zinc-500 mt-0.5">
|
|
546
|
+
<template x-for="(detail, key) in getLogDetails(log.message)" :key="key">
|
|
547
|
+
<span class="px-1.5 py-0.5 bg-space-800/50 rounded border border-space-border/30">
|
|
548
|
+
<span class="text-zinc-600" x-text="key"></span>=<span class="text-zinc-400" x-text="detail"></span>
|
|
549
|
+
</span>
|
|
550
|
+
</template>
|
|
551
|
+
</div>
|
|
552
|
+
</template>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
555
|
+
</template>
|
|
556
|
+
<div class="h-3 w-1.5 bg-zinc-600 animate-pulse mt-1 inline-block" x-show="filteredLogs.length === logs.length && !logSearchQuery"></div>
|
|
557
|
+
<div x-show="filteredLogs.length === 0 && logs.length > 0" class="text-zinc-700 italic mt-8 text-center">
|
|
558
|
+
No logs match filter
|
|
559
|
+
</div>
|
|
560
|
+
</div>
|
|
561
|
+
</div>
|
|
562
|
+
</div>
|
|
563
|
+
|
|
564
|
+
<div x-show="activeTab === 'settings'" x-transition class="view-container">
|
|
565
|
+
<div class="flex items-center justify-between gap-4 mb-6">
|
|
566
|
+
<div class="flex flex-wrap items-center gap-4">
|
|
567
|
+
<h1 class="text-2xl font-bold text-white tracking-tight">Settings</h1>
|
|
568
|
+
<div class="flex items-center h-6 px-3 rounded-full bg-space-800/80 border border-space-border/50 shadow-sm backdrop-blur-sm">
|
|
569
|
+
<span class="text-[10px] font-mono text-gray-400 uppercase tracking-wider">Server configuration</span>
|
|
570
|
+
</div>
|
|
571
|
+
</div>
|
|
572
|
+
</div>
|
|
573
|
+
|
|
574
|
+
<div class="view-card">
|
|
575
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
576
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-cyan">
|
|
577
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
|
578
|
+
</svg>
|
|
579
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Server Info</h3>
|
|
580
|
+
</div>
|
|
581
|
+
<div class="space-y-3">
|
|
582
|
+
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
583
|
+
<span class="text-sm text-gray-400">Server URL</span>
|
|
584
|
+
<span class="font-mono text-sm text-white">http://localhost:8081</span>
|
|
585
|
+
</div>
|
|
586
|
+
<div class="flex items-center justify-between py-2 border-b border-space-border/30">
|
|
587
|
+
<span class="text-sm text-gray-400">Config Path</span>
|
|
588
|
+
<span class="font-mono text-sm text-white" x-text="configPath"></span>
|
|
589
|
+
</div>
|
|
590
|
+
<div class="flex items-center justify-between py-2">
|
|
591
|
+
<span class="text-sm text-gray-400">Auto Token Refresh</span>
|
|
592
|
+
<span class="text-xs font-mono text-neon-green">Every 55 minutes</span>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
|
|
597
|
+
<div class="view-card mt-6">
|
|
598
|
+
<div class="flex items-center gap-2.5 mb-4">
|
|
599
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-4 h-4 text-neon-purple">
|
|
600
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
|
601
|
+
</svg>
|
|
602
|
+
<h3 class="text-xs font-mono text-gray-400 uppercase tracking-widest">Haiku Kilo Routing</h3>
|
|
603
|
+
</div>
|
|
604
|
+
<div class="flex flex-wrap items-center justify-between gap-4">
|
|
605
|
+
<div>
|
|
606
|
+
<div class="text-sm text-gray-300">Haiku Model Target</div>
|
|
607
|
+
<div class="text-xs text-gray-500 font-mono">Routes claude-haiku-4 to Kilo</div>
|
|
608
|
+
</div>
|
|
609
|
+
<div class="inline-flex items-center gap-2">
|
|
610
|
+
<button class="btn btn-xs" :class="haikuKiloModel === 'glm-5' ? 'bg-neon-purple text-white' : 'btn-outline text-gray-400'"
|
|
611
|
+
@click="setHaikuModel('glm-5')" :disabled="haikuModelSaving">GLM‑5</button>
|
|
612
|
+
<button class="btn btn-xs" :class="haikuKiloModel === 'minimax-2.5' ? 'bg-neon-purple text-white' : 'btn-outline text-gray-400'"
|
|
613
|
+
@click="setHaikuModel('minimax-2.5')" :disabled="haikuModelSaving">MiniMax M2.5</button>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
</div>
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
|
|
621
|
+
<div x-show="showAddModal" x-transition class="fixed inset-0 z-50 flex items-center justify-center p-4" style="display: none;">
|
|
622
|
+
<div class="absolute inset-0 bg-black/70 backdrop-blur-sm" @click="showAddModal = false"></div>
|
|
623
|
+
<div class="relative bg-space-900 border border-space-border rounded-xl shadow-2xl max-w-md w-full p-6">
|
|
624
|
+
<h3 class="font-bold text-lg text-white mb-4">Add New Account</h3>
|
|
625
|
+
|
|
626
|
+
<template x-if="!oauthManualMode">
|
|
627
|
+
<div>
|
|
628
|
+
<p class="text-sm text-gray-400 mb-6">Connect a ChatGPT account to use with the proxy. The account will be used for API calls.</p>
|
|
629
|
+
|
|
630
|
+
<div class="flex flex-col gap-3">
|
|
631
|
+
<button class="btn bg-neon-purple hover:bg-purple-600 border-none text-white btn-sm gap-3 h-11"
|
|
632
|
+
@click="startOAuth()">
|
|
633
|
+
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
|
634
|
+
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"></path>
|
|
635
|
+
<path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"></path>
|
|
636
|
+
<path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"></path>
|
|
637
|
+
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"></path>
|
|
638
|
+
</svg>
|
|
639
|
+
<span>Connect via OAuth</span>
|
|
640
|
+
</button>
|
|
641
|
+
|
|
642
|
+
<div class="text-center">
|
|
643
|
+
<span class="text-xs text-gray-500">or</span>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<button class="btn btn-outline btn-sm text-gray-400 hover:text-white gap-2"
|
|
647
|
+
@click="startManualOAuth()">
|
|
648
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
649
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
|
650
|
+
</svg>
|
|
651
|
+
<span>Manual Authorization (Headless)</span>
|
|
652
|
+
</button>
|
|
653
|
+
|
|
654
|
+
<div class="text-center">
|
|
655
|
+
<span class="text-xs text-gray-500">or</span>
|
|
656
|
+
</div>
|
|
657
|
+
|
|
658
|
+
<button class="btn btn-outline btn-sm text-gray-400 hover:text-white gap-2"
|
|
659
|
+
@click="importFromCodex()">
|
|
660
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
661
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
|
662
|
+
</svg>
|
|
663
|
+
<span>Import from Codex App</span>
|
|
664
|
+
</button>
|
|
665
|
+
</div>
|
|
666
|
+
|
|
667
|
+
<div class="mt-6 flex justify-end">
|
|
668
|
+
<button class="btn btn-outline btn-sm text-gray-400" @click="showAddModal = false">Cancel</button>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
</template>
|
|
672
|
+
|
|
673
|
+
<template x-if="oauthManualMode">
|
|
674
|
+
<div>
|
|
675
|
+
<p class="text-sm text-gray-400 mb-4">For headless servers without a browser:</p>
|
|
676
|
+
|
|
677
|
+
<div class="bg-space-800/50 border border-space-border/30 rounded-lg p-3 mb-4">
|
|
678
|
+
<p class="text-xs text-gray-500 mb-2">1. Open this URL on another device:</p>
|
|
679
|
+
<div class="flex items-center gap-2">
|
|
680
|
+
<input type="text" readonly :value="oauthManualUrl"
|
|
681
|
+
class="input flex-1 bg-space-700 border-space-border text-xs font-mono text-gray-300">
|
|
682
|
+
<button class="btn btn-xs btn-ghost text-gray-400" @click="copyToClipboard(oauthManualUrl)">
|
|
683
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
684
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
685
|
+
</svg>
|
|
686
|
+
</button>
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
|
|
690
|
+
<div class="mb-4">
|
|
691
|
+
<p class="text-xs text-gray-500 mb-2">2. After authorizing, paste the callback URL or code:</p>
|
|
692
|
+
<input type="text" x-model="oauthManualCode"
|
|
693
|
+
placeholder="http://localhost:1455/auth/callback?code=... or just the code"
|
|
694
|
+
class="input w-full bg-space-800 border-space-border text-white font-mono text-sm">
|
|
695
|
+
</div>
|
|
696
|
+
|
|
697
|
+
<div class="flex justify-end gap-2">
|
|
698
|
+
<button class="btn btn-outline btn-sm text-gray-400" @click="oauthManualMode = false">Back</button>
|
|
699
|
+
<button class="btn bg-neon-purple hover:bg-purple-600 border-none text-white btn-sm"
|
|
700
|
+
@click="submitManualOAuth()" :disabled="!oauthManualCode">
|
|
701
|
+
Add Account
|
|
702
|
+
</button>
|
|
703
|
+
</div>
|
|
704
|
+
</div>
|
|
705
|
+
</template>
|
|
706
|
+
</div>
|
|
707
|
+
</div>
|
|
708
|
+
|
|
709
|
+
<div x-show="showDeleteModal" x-transition class="fixed inset-0 z-50 flex items-center justify-center p-4" style="display: none;">
|
|
710
|
+
<div class="absolute inset-0 bg-black/70 backdrop-blur-sm" @click="showDeleteModal = false"></div>
|
|
711
|
+
<div class="relative bg-space-900 border-2 border-red-500/50 rounded-xl shadow-2xl max-w-md w-full p-6">
|
|
712
|
+
<h3 class="font-bold text-lg text-red-400 flex items-center gap-2 mb-4">
|
|
713
|
+
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
714
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
715
|
+
</svg>
|
|
716
|
+
<span>Delete Account</span>
|
|
717
|
+
</h3>
|
|
718
|
+
<p class="text-gray-300 mb-4">Are you sure you want to delete <strong class="text-white font-mono" x-text="deleteTarget"></strong>?</p>
|
|
719
|
+
<div class="bg-red-500/10 border border-red-500/30 rounded p-3 mb-4">
|
|
720
|
+
<p class="text-sm text-red-300">This action cannot be undone. All configuration will be permanently deleted.</p>
|
|
721
|
+
</div>
|
|
722
|
+
<div class="flex justify-end gap-2">
|
|
723
|
+
<button class="btn btn-outline btn-sm text-gray-400" @click="showDeleteModal = false">Cancel</button>
|
|
724
|
+
<button class="btn bg-red-500 hover:bg-red-600 border-none text-white btn-sm" @click="executeDelete()">
|
|
725
|
+
Delete
|
|
726
|
+
</button>
|
|
727
|
+
</div>
|
|
728
|
+
</div>
|
|
729
|
+
</div>
|
|
730
|
+
|
|
731
|
+
<div x-show="showQuotaModalView" x-transition class="fixed inset-0 z-50 flex items-center justify-center p-4" style="display: none;">
|
|
732
|
+
<div class="absolute inset-0 bg-black/70 backdrop-blur-sm" @click="showQuotaModalView = false"></div>
|
|
733
|
+
<div class="relative bg-space-900 border border-space-border rounded-xl shadow-2xl max-w-lg w-full p-6">
|
|
734
|
+
<h3 class="font-bold text-lg text-white mb-2 flex items-center gap-2">
|
|
735
|
+
<svg class="w-6 h-6 text-neon-cyan" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
736
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
737
|
+
</svg>
|
|
738
|
+
<span>Quota Distribution</span>
|
|
739
|
+
</h3>
|
|
740
|
+
<p class="text-sm text-gray-500 font-mono mb-4" x-text="selectedAccount?.email"></p>
|
|
741
|
+
|
|
742
|
+
<div class="space-y-3 max-h-[60vh] overflow-y-auto" x-show="getRemainingPercentage(selectedAccount) !== null">
|
|
743
|
+
<div class="p-3 bg-space-800/50 border border-space-border/30 rounded-lg">
|
|
744
|
+
<div class="flex justify-between items-center mb-2">
|
|
745
|
+
<span class="text-sm font-semibold text-gray-200">Usage</span>
|
|
746
|
+
<template x-if="!isQuotaExhausted(selectedAccount)">
|
|
747
|
+
<span class="text-xs font-mono"
|
|
748
|
+
:class="quotaTextClass(selectedAccount)"
|
|
749
|
+
x-text="quotaLabel(selectedAccount) + ' remaining'"></span>
|
|
750
|
+
</template>
|
|
751
|
+
<template x-if="isQuotaExhausted(selectedAccount)">
|
|
752
|
+
<span class="text-[10px] font-bold uppercase text-red-400 bg-red-500/10 px-2 py-0.5 rounded border border-red-500/30">QUOTA EXHAUSTED</span>
|
|
753
|
+
</template>
|
|
754
|
+
</div>
|
|
755
|
+
<div class="w-full bg-gray-700 rounded-full h-3 overflow-hidden">
|
|
756
|
+
<div class="h-full rounded-full transition-all"
|
|
757
|
+
:class="quotaBarClass(selectedAccount)"
|
|
758
|
+
:style="`width: ${getRemainingPercentage(selectedAccount)}%`"></div>
|
|
759
|
+
</div>
|
|
760
|
+
<div class="mt-3 pt-3 border-t border-space-border/30 space-y-1">
|
|
761
|
+
<div class="flex items-center justify-between text-xs">
|
|
762
|
+
<span class="text-gray-500">Reset window</span>
|
|
763
|
+
<span class="font-mono text-gray-300" x-text="quotaResetSummary(selectedAccount) || '-'"></span>
|
|
764
|
+
</div>
|
|
765
|
+
<template x-if="quotaResetAtLabel(selectedAccount)">
|
|
766
|
+
<div class="flex items-center justify-between text-xs">
|
|
767
|
+
<span class="text-gray-500">Resets at</span>
|
|
768
|
+
<span class="font-mono text-gray-300" x-text="quotaResetAtLabel(selectedAccount)"></span>
|
|
769
|
+
</div>
|
|
770
|
+
</template>
|
|
771
|
+
</div>
|
|
772
|
+
</div>
|
|
773
|
+
</div>
|
|
774
|
+
|
|
775
|
+
<div class="mt-6 flex justify-end">
|
|
776
|
+
<button class="btn btn-outline btn-sm text-gray-400" @click="showQuotaModalView = false">Close</button>
|
|
777
|
+
</div>
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
|
|
781
|
+
<script src="/js/app.js"></script>
|
|
782
|
+
</body>
|
|
783
|
+
</html>
|