codex-endpoint-switcher 1.1.0 → 1.3.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/package.json +3 -3
- package/src/main/cloud-sync-client.js +12 -7
- package/src/renderer/index.html +182 -158
- package/src/renderer/renderer.js +223 -85
- package/src/renderer/styles.css +526 -130
- package/src/web/server.js +26 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-endpoint-switcher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "用于切换 Codex URL 和 Key 的本地网页控制台与 npm CLI",
|
|
5
5
|
"main": "src/main/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -58,13 +58,13 @@
|
|
|
58
58
|
"x64"
|
|
59
59
|
]
|
|
60
60
|
}
|
|
61
|
-
]
|
|
62
|
-
"artifactName": "CodexProfileDesktop-${version}-portable.${ext}"
|
|
61
|
+
]
|
|
63
62
|
},
|
|
64
63
|
"portable": {
|
|
65
64
|
"artifactName": "CodexProfileDesktop-${version}-portable.${ext}"
|
|
66
65
|
},
|
|
67
66
|
"nsis": {
|
|
67
|
+
"artifactName": "CodexProfileDesktop-${version}-installer.${ext}",
|
|
68
68
|
"oneClick": false,
|
|
69
69
|
"allowToChangeInstallationDirectory": true
|
|
70
70
|
}
|
|
@@ -29,6 +29,14 @@ function normalizeServerUrl(value) {
|
|
|
29
29
|
return parsedUrl.toString().replace(/\/+$/, "");
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function getDefaultServerUrl() {
|
|
33
|
+
return normalizeServerUrl(
|
|
34
|
+
process.env.CODEX_SYNC_SERVER_URL ||
|
|
35
|
+
process.env.SYNC_SERVER_PUBLIC_URL ||
|
|
36
|
+
"https://codexqh.zhang-fy.top",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
function normalizeUsername(value) {
|
|
33
41
|
const username = String(value || "").trim();
|
|
34
42
|
if (!username) {
|
|
@@ -69,7 +77,7 @@ async function ensureStorage() {
|
|
|
69
77
|
cloudSyncConfigPath,
|
|
70
78
|
`${JSON.stringify(
|
|
71
79
|
{
|
|
72
|
-
serverUrl:
|
|
80
|
+
serverUrl: getDefaultServerUrl(),
|
|
73
81
|
username: "",
|
|
74
82
|
authToken: "",
|
|
75
83
|
tokenExpiresAt: "",
|
|
@@ -90,7 +98,7 @@ async function readConfig() {
|
|
|
90
98
|
const config = JSON.parse(content);
|
|
91
99
|
|
|
92
100
|
return {
|
|
93
|
-
serverUrl: String(config.serverUrl ||
|
|
101
|
+
serverUrl: String(config.serverUrl || getDefaultServerUrl()).trim(),
|
|
94
102
|
username: String(config.username || "").trim(),
|
|
95
103
|
authToken: String(config.authToken || "").trim(),
|
|
96
104
|
tokenExpiresAt: String(config.tokenExpiresAt || "").trim(),
|
|
@@ -180,7 +188,7 @@ async function getCloudSyncStatus() {
|
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
async function authenticate(mode, payload) {
|
|
183
|
-
const serverUrl = normalizeServerUrl(payload.serverUrl);
|
|
191
|
+
const serverUrl = normalizeServerUrl(payload.serverUrl || getDefaultServerUrl());
|
|
184
192
|
const username = normalizeUsername(payload.username);
|
|
185
193
|
const password = normalizePassword(payload.password);
|
|
186
194
|
const endpointPath = mode === "register" ? "/api/auth/register" : "/api/auth/login";
|
|
@@ -244,10 +252,6 @@ async function logoutAccount() {
|
|
|
244
252
|
|
|
245
253
|
async function requireLoggedInConfig() {
|
|
246
254
|
const config = await readConfig();
|
|
247
|
-
if (!config.serverUrl) {
|
|
248
|
-
throw new Error("请先填写并登录同步服务器。");
|
|
249
|
-
}
|
|
250
|
-
|
|
251
255
|
if (!config.authToken) {
|
|
252
256
|
throw new Error("当前还没有登录同步账号。");
|
|
253
257
|
}
|
|
@@ -319,6 +323,7 @@ async function pullRemoteConfig(mode = "merge") {
|
|
|
319
323
|
|
|
320
324
|
module.exports = {
|
|
321
325
|
cloudSyncConfigPath,
|
|
326
|
+
getDefaultServerUrl,
|
|
322
327
|
getCloudSyncStatus,
|
|
323
328
|
loginAccount,
|
|
324
329
|
logoutAccount,
|
package/src/renderer/index.html
CHANGED
|
@@ -12,82 +12,198 @@
|
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div class="page-shell">
|
|
15
|
-
<
|
|
16
|
-
<div class="
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<button id="openCodexRootButton" class="ghost-button">打开 Codex 目录</button>
|
|
27
|
-
<button id="openEndpointStoreButton" class="ghost-button">打开连接数据文件</button>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
<div class="hero-side">
|
|
31
|
-
<div class="orb orb-a"></div>
|
|
32
|
-
<div class="orb orb-b"></div>
|
|
33
|
-
<div class="hero-badge" id="heroBadge">读取中</div>
|
|
34
|
-
</div>
|
|
35
|
-
</header>
|
|
15
|
+
<section id="authGate" class="auth-gate">
|
|
16
|
+
<div class="auth-card panel">
|
|
17
|
+
<div class="auth-form-card">
|
|
18
|
+
<div class="panel-header auth-panel-header">
|
|
19
|
+
<div>
|
|
20
|
+
<p class="eyebrow">CODEX ENDPOINT SWITCHER</p>
|
|
21
|
+
<p class="panel-kicker">Account Access</p>
|
|
22
|
+
<h2>账号登录</h2>
|
|
23
|
+
</div>
|
|
24
|
+
<span class="panel-tag" id="authAccessTag">未登录</span>
|
|
25
|
+
</div>
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
27
|
+
<form id="authForm" class="stack-form auth-form">
|
|
28
|
+
<label class="field">
|
|
29
|
+
<span>账号</span>
|
|
30
|
+
<input
|
|
31
|
+
id="authUsername"
|
|
32
|
+
type="text"
|
|
33
|
+
placeholder="输入你的账号"
|
|
34
|
+
autocomplete="username"
|
|
35
|
+
/>
|
|
36
|
+
</label>
|
|
37
|
+
<label class="field">
|
|
38
|
+
<span>密码</span>
|
|
39
|
+
<input
|
|
40
|
+
id="authPassword"
|
|
41
|
+
type="password"
|
|
42
|
+
placeholder="输入你的密码"
|
|
43
|
+
autocomplete="current-password"
|
|
44
|
+
/>
|
|
45
|
+
</label>
|
|
46
|
+
<p class="field-hint">
|
|
47
|
+
系统会自动连接同步服务。第一次使用先注册账号,之后直接登录。
|
|
48
|
+
</p>
|
|
49
|
+
<div class="action-row">
|
|
50
|
+
<button id="authLoginButton" type="submit" class="primary-button">登录进入</button>
|
|
51
|
+
<button id="authRegisterButton" type="button" class="secondary-button">
|
|
52
|
+
注册账号
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</form>
|
|
56
|
+
|
|
57
|
+
<div id="authStatusBox" class="status-box info auth-status">
|
|
58
|
+
正在检查登录状态。
|
|
43
59
|
</div>
|
|
44
|
-
<span class="panel-tag" id="activeEndpointTag">未识别</span>
|
|
45
60
|
</div>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
64
|
+
<div id="appShell" class="app-shell" hidden>
|
|
65
|
+
<main class="content-grid">
|
|
66
|
+
<div class="left-column">
|
|
67
|
+
<section class="panel current-panel">
|
|
68
|
+
<div class="panel-header">
|
|
69
|
+
<div>
|
|
70
|
+
<p class="panel-kicker">当前状态</p>
|
|
71
|
+
<h2>当前生效连接</h2>
|
|
72
|
+
</div>
|
|
73
|
+
<span class="panel-tag" id="activeEndpointTag">未识别</span>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="current-summary">
|
|
76
|
+
<p class="current-copy">
|
|
77
|
+
这里只管理 <code>备注</code>、<code>URL</code>、<code>Key</code>。切换时只更新
|
|
78
|
+
Codex 当前使用的 <code>base_url</code> 和 <code>OPENAI_API_KEY</code>。
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="current-tools">
|
|
82
|
+
<button id="refreshButton" class="ghost-button">刷新状态</button>
|
|
83
|
+
<button id="openCodexRootButton" class="ghost-button">打开 Codex 目录</button>
|
|
84
|
+
<button id="openEndpointStoreButton" class="ghost-button">打开连接数据文件</button>
|
|
85
|
+
</div>
|
|
86
|
+
<div class="current-grid">
|
|
87
|
+
<article class="metric-card">
|
|
88
|
+
<span class="metric-label">当前备注</span>
|
|
89
|
+
<strong id="currentNote">-</strong>
|
|
90
|
+
</article>
|
|
91
|
+
<article class="metric-card">
|
|
92
|
+
<span class="metric-label">提供商</span>
|
|
93
|
+
<strong id="currentProvider">-</strong>
|
|
94
|
+
</article>
|
|
95
|
+
<article class="metric-card">
|
|
96
|
+
<span class="metric-label">当前 Key</span>
|
|
97
|
+
<strong id="currentKeyMasked">-</strong>
|
|
98
|
+
</article>
|
|
99
|
+
<article class="metric-card">
|
|
100
|
+
<span class="metric-label">模型</span>
|
|
101
|
+
<strong id="currentModel">-</strong>
|
|
102
|
+
</article>
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
106
|
+
<section class="panel account-panel">
|
|
107
|
+
<div class="panel-header">
|
|
108
|
+
<div>
|
|
109
|
+
<p class="panel-kicker">Account Center</p>
|
|
110
|
+
<h2>账号与同步</h2>
|
|
111
|
+
</div>
|
|
112
|
+
<span class="panel-tag" id="cloudAccessTag">未登录</span>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<p class="field-hint account-hint">
|
|
116
|
+
账号空间保存连接配置,支持推送上传和拉取同步。
|
|
72
117
|
</p>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
118
|
+
|
|
119
|
+
<div class="account-primary-grid">
|
|
120
|
+
<article class="account-primary-card">
|
|
121
|
+
<span class="metric-label">当前账号</span>
|
|
122
|
+
<strong id="cloudAccountName">-</strong>
|
|
123
|
+
</article>
|
|
124
|
+
<article class="account-primary-card">
|
|
125
|
+
<span class="metric-label">会话状态</span>
|
|
126
|
+
<strong id="cloudSessionStatus">未登录</strong>
|
|
127
|
+
</article>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div class="account-inline-grid">
|
|
131
|
+
<article class="account-inline-card">
|
|
132
|
+
<span class="metric-label">同步服务</span>
|
|
133
|
+
<strong id="cloudServerStatus">自动连接</strong>
|
|
134
|
+
</article>
|
|
135
|
+
<article class="account-inline-card">
|
|
136
|
+
<span class="metric-label">同步记录</span>
|
|
137
|
+
<strong id="cloudLastSyncStatus">还没有推送或拉取记录</strong>
|
|
138
|
+
</article>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="account-actions-grid account-actions-grid-compact">
|
|
142
|
+
<button id="openSwitchAccountButton" type="button" class="ghost-button">
|
|
143
|
+
切换账号
|
|
144
|
+
</button>
|
|
145
|
+
<button id="cloudLogoutButton" type="button" class="danger-button">退出登录</button>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div class="account-actions-grid account-actions-grid-sync">
|
|
149
|
+
<button id="cloudPushButton" type="button" class="secondary-button">
|
|
150
|
+
推送当前连接
|
|
151
|
+
</button>
|
|
152
|
+
<button id="cloudPullMergeButton" type="button" class="primary-button">
|
|
153
|
+
合并拉取
|
|
154
|
+
</button>
|
|
155
|
+
<button id="cloudPullReplaceButton" type="button" class="danger-button">
|
|
156
|
+
覆盖拉取
|
|
76
157
|
</button>
|
|
77
158
|
</div>
|
|
78
|
-
</
|
|
159
|
+
</section>
|
|
79
160
|
</div>
|
|
80
|
-
</section>
|
|
81
161
|
|
|
82
|
-
|
|
83
|
-
|
|
162
|
+
<section class="panel profiles-panel">
|
|
163
|
+
<div class="panel-header">
|
|
164
|
+
<div>
|
|
165
|
+
<p class="panel-kicker">Endpoints</p>
|
|
166
|
+
<h2>连接列表</h2>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="panel-header-actions">
|
|
169
|
+
<span class="profile-count" id="endpointCount">0 条</span>
|
|
170
|
+
<button id="openCreateEndpointButton" type="button" class="primary-button">
|
|
171
|
+
新增连接
|
|
172
|
+
</button>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
<div id="endpointsList" class="profiles-list"></div>
|
|
176
|
+
</section>
|
|
177
|
+
</main>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div id="endpointModal" class="modal-shell" hidden>
|
|
181
|
+
<div class="modal-backdrop" data-modal-close="true"></div>
|
|
182
|
+
<section
|
|
183
|
+
class="modal-card"
|
|
184
|
+
role="dialog"
|
|
185
|
+
aria-modal="true"
|
|
186
|
+
aria-labelledby="endpointModalTitle"
|
|
187
|
+
>
|
|
188
|
+
<div class="modal-header">
|
|
84
189
|
<div>
|
|
85
|
-
<p class="panel-kicker"
|
|
86
|
-
<h2
|
|
190
|
+
<p class="panel-kicker">Endpoint Editor</p>
|
|
191
|
+
<h2 id="endpointModalTitle">新增连接</h2>
|
|
192
|
+
<p id="endpointModalText" class="modal-text">
|
|
193
|
+
填写备注、URL、Key,保存后就能直接加入切换列表。
|
|
194
|
+
</p>
|
|
87
195
|
</div>
|
|
196
|
+
<button
|
|
197
|
+
id="closeEndpointModalButton"
|
|
198
|
+
type="button"
|
|
199
|
+
class="icon-button"
|
|
200
|
+
aria-label="关闭弹窗"
|
|
201
|
+
>
|
|
202
|
+
×
|
|
203
|
+
</button>
|
|
88
204
|
</div>
|
|
89
205
|
|
|
90
|
-
<form id="endpointForm" class="stack-form">
|
|
206
|
+
<form id="endpointForm" class="stack-form endpoint-form">
|
|
91
207
|
<input id="endpointId" type="hidden" />
|
|
92
208
|
<label class="field">
|
|
93
209
|
<span>备注</span>
|
|
@@ -119,103 +235,11 @@
|
|
|
119
235
|
<p class="field-hint">连接数据仅保存在本机 `~/.codex/endpoint-presets.json`。</p>
|
|
120
236
|
<div class="action-row">
|
|
121
237
|
<button id="saveEndpointButton" type="submit" class="primary-button">新增连接</button>
|
|
122
|
-
<button id="clearFormButton" type="button" class="ghost-button"
|
|
238
|
+
<button id="clearFormButton" type="button" class="ghost-button">重置表单</button>
|
|
123
239
|
</div>
|
|
124
240
|
</form>
|
|
125
|
-
|
|
126
|
-
<div class="stack-form stack-form-alt">
|
|
127
|
-
<div>
|
|
128
|
-
<p class="panel-kicker">Cloud Sync</p>
|
|
129
|
-
<h3>账号配置同步</h3>
|
|
130
|
-
</div>
|
|
131
|
-
<label class="field">
|
|
132
|
-
<span>同步服务器</span>
|
|
133
|
-
<input
|
|
134
|
-
id="cloudServerUrl"
|
|
135
|
-
type="text"
|
|
136
|
-
placeholder="例如:http://127.0.0.1:3190"
|
|
137
|
-
autocomplete="off"
|
|
138
|
-
/>
|
|
139
|
-
</label>
|
|
140
|
-
<label class="field">
|
|
141
|
-
<span>账号</span>
|
|
142
|
-
<input
|
|
143
|
-
id="cloudUsername"
|
|
144
|
-
type="text"
|
|
145
|
-
placeholder="例如:yourname"
|
|
146
|
-
autocomplete="off"
|
|
147
|
-
/>
|
|
148
|
-
</label>
|
|
149
|
-
<label class="field">
|
|
150
|
-
<span>密码</span>
|
|
151
|
-
<input
|
|
152
|
-
id="cloudPassword"
|
|
153
|
-
type="password"
|
|
154
|
-
placeholder="输入同步账号密码"
|
|
155
|
-
autocomplete="off"
|
|
156
|
-
/>
|
|
157
|
-
</label>
|
|
158
|
-
<p class="field-hint">
|
|
159
|
-
账号空间里保存的是你的连接配置。推送是把本机连接上传到账号,拉取是把账号里的连接同步回本机。
|
|
160
|
-
</p>
|
|
161
|
-
<div class="sync-status-grid">
|
|
162
|
-
<article class="sync-status-card">
|
|
163
|
-
<span class="metric-label">登录状态</span>
|
|
164
|
-
<strong id="cloudAuthStatus">未登录</strong>
|
|
165
|
-
</article>
|
|
166
|
-
<article class="sync-status-card">
|
|
167
|
-
<span class="metric-label">服务器</span>
|
|
168
|
-
<strong id="cloudRemoteStatus">未设置</strong>
|
|
169
|
-
</article>
|
|
170
|
-
<article class="sync-status-card sync-status-card-wide">
|
|
171
|
-
<span class="metric-label">同步记录</span>
|
|
172
|
-
<strong id="cloudLastSyncStatus">还没有推送或拉取记录</strong>
|
|
173
|
-
</article>
|
|
174
|
-
</div>
|
|
175
|
-
<div class="action-row">
|
|
176
|
-
<button id="cloudRegisterButton" type="button" class="secondary-button">
|
|
177
|
-
注册账号
|
|
178
|
-
</button>
|
|
179
|
-
<button id="cloudLoginButton" type="button" class="primary-button">
|
|
180
|
-
登录账号
|
|
181
|
-
</button>
|
|
182
|
-
<button id="cloudLogoutButton" type="button" class="ghost-button">退出登录</button>
|
|
183
|
-
</div>
|
|
184
|
-
<div class="action-row">
|
|
185
|
-
<button id="cloudPushButton" type="button" class="secondary-button">
|
|
186
|
-
推送当前连接
|
|
187
|
-
</button>
|
|
188
|
-
<button id="cloudPullMergeButton" type="button" class="primary-button">
|
|
189
|
-
合并拉取
|
|
190
|
-
</button>
|
|
191
|
-
<button id="cloudPullReplaceButton" type="button" class="danger-button">
|
|
192
|
-
覆盖拉取
|
|
193
|
-
</button>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
</section>
|
|
197
|
-
|
|
198
|
-
<section class="panel profiles-panel">
|
|
199
|
-
<div class="panel-header">
|
|
200
|
-
<div>
|
|
201
|
-
<p class="panel-kicker">Endpoints</p>
|
|
202
|
-
<h2>连接列表</h2>
|
|
203
|
-
</div>
|
|
204
|
-
<span class="profile-count" id="endpointCount">0 条</span>
|
|
205
|
-
</div>
|
|
206
|
-
<div id="endpointsList" class="profiles-list"></div>
|
|
207
|
-
</section>
|
|
208
|
-
|
|
209
|
-
<section class="panel footer-panel">
|
|
210
|
-
<div class="panel-header">
|
|
211
|
-
<div>
|
|
212
|
-
<p class="panel-kicker">输出</p>
|
|
213
|
-
<h2>执行结果</h2>
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
<div id="statusBox" class="status-box info">应用已启动,正在读取当前连接。</div>
|
|
217
241
|
</section>
|
|
218
|
-
</
|
|
242
|
+
</div>
|
|
219
243
|
</div>
|
|
220
244
|
|
|
221
245
|
<script src="./renderer.js"></script>
|