ai-zero-token 2.0.2 → 2.0.4

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 (35) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +31 -6
  3. package/README.zh-CN.md +31 -6
  4. package/admin-ui/dist/assets/accounts-CTjk9c4F.js +4 -0
  5. package/admin-ui/dist/assets/{docs-CihX3Xsm.js → docs-oNIugCIL.js} +3 -3
  6. package/admin-ui/dist/assets/{image-bed-BGjlDLks.js → image-bed-CQtIhjg_.js} +1 -1
  7. package/admin-ui/dist/assets/index-By4r-wy3.css +1 -0
  8. package/admin-ui/dist/assets/index-rgcJgVAu.js +10 -0
  9. package/admin-ui/dist/assets/{launch-BWw7Odq7.js → launch-B-2Zdz9m.js} +1 -1
  10. package/admin-ui/dist/assets/logs-JFuSf56b.js +1 -0
  11. package/admin-ui/dist/assets/{network-detect-cUdjg4zk.js → network-detect-SfvK6uhx.js} +1 -1
  12. package/admin-ui/dist/assets/{overview-CsjVVcvi.js → overview-X_WodIqE.js} +1 -1
  13. package/admin-ui/dist/assets/settings-0eXUAvcm.js +1 -0
  14. package/admin-ui/dist/assets/{tester-BIvH_8DY.js → tester-ocpF053C.js} +1 -1
  15. package/admin-ui/dist/index.html +2 -2
  16. package/build/mac-install-guide.txt +25 -0
  17. package/build/tray-icon-template.png +0 -0
  18. package/dist/core/providers/openai-codex/chat.js +77 -0
  19. package/dist/core/services/auth-service.js +88 -12
  20. package/dist/core/services/chat-service.js +1 -0
  21. package/dist/core/services/config-service.js +87 -23
  22. package/dist/core/services/version-service.js +1 -1
  23. package/dist/core/store/profile-store.js +73 -32
  24. package/dist/core/store/settings-store.js +14 -0
  25. package/dist/desktop/main.js +616 -15
  26. package/dist/server/app.js +512 -58
  27. package/dist/server/index.js +2 -1
  28. package/docs/API_USAGE.md +65 -1
  29. package/docs/DESKTOP_RELEASE.md +48 -3
  30. package/package.json +33 -2
  31. package/admin-ui/dist/assets/accounts-Ddq82u6R.js +0 -1
  32. package/admin-ui/dist/assets/index-CX8e0-BB.js +0 -10
  33. package/admin-ui/dist/assets/index-ywn2Jwpu.css +0 -1
  34. package/admin-ui/dist/assets/logs-DDdgDVwo.js +0 -1
  35. package/admin-ui/dist/assets/settings-Be99HpDD.js +0 -1
@@ -3,8 +3,34 @@ import { getPreferredCodexModel, hasCodexModel } from "../models/openai-codex-mo
3
3
  import {
4
4
  createDefaultSettings,
5
5
  loadSettings,
6
+ normalizeQuotaSyncConcurrency,
6
7
  saveSettings
7
8
  } from "../store/settings-store.js";
9
+ function normalizeNetworkProxy(settings, params) {
10
+ const requestedUrl = params.url?.trim() ?? "";
11
+ const url = requestedUrl || (!params.enabled ? settings.networkProxy.url : "");
12
+ const noProxy = params.noProxy?.trim() || settings.networkProxy.noProxy || "localhost,127.0.0.1,::1";
13
+ if (params.enabled) {
14
+ if (!url) {
15
+ throw new Error("\u542F\u7528\u4EE3\u7406\u65F6\u5FC5\u987B\u586B\u5199\u4EE3\u7406\u5730\u5740\u3002");
16
+ }
17
+ let parsed;
18
+ try {
19
+ parsed = new URL(url);
20
+ } catch {
21
+ throw new Error("\u4EE3\u7406\u5730\u5740\u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u586B\u5199\u5B8C\u6574\u7684\u4EE3\u7406 URL\u3002");
22
+ }
23
+ const supportedProtocols = /* @__PURE__ */ new Set(["http:", "https:", "socks4:", "socks4a:", "socks5:", "socks5h:"]);
24
+ if (!supportedProtocols.has(parsed.protocol)) {
25
+ throw new Error("\u4EE3\u7406\u5730\u5740\u4EC5\u652F\u6301 http\u3001https\u3001socks4\u3001socks4a\u3001socks5 \u6216 socks5h\u3002");
26
+ }
27
+ }
28
+ return {
29
+ enabled: params.enabled,
30
+ url,
31
+ noProxy
32
+ };
33
+ }
8
34
  class ConfigService {
9
35
  async getSettings() {
10
36
  return this.ensureSettings();
@@ -43,31 +69,9 @@ class ConfigService {
43
69
  }
44
70
  async setNetworkProxy(params) {
45
71
  const settings = await this.getSettings();
46
- const requestedUrl = params.url?.trim() ?? "";
47
- const url = requestedUrl || (!params.enabled ? settings.networkProxy.url : "");
48
- const noProxy = params.noProxy?.trim() || settings.networkProxy.noProxy || "localhost,127.0.0.1,::1";
49
- if (params.enabled) {
50
- if (!url) {
51
- throw new Error("\u542F\u7528\u4EE3\u7406\u65F6\u5FC5\u987B\u586B\u5199\u4EE3\u7406\u5730\u5740\u3002");
52
- }
53
- let parsed;
54
- try {
55
- parsed = new URL(url);
56
- } catch {
57
- throw new Error("\u4EE3\u7406\u5730\u5740\u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u586B\u5199\u5B8C\u6574\u7684\u4EE3\u7406 URL\u3002");
58
- }
59
- const supportedProtocols = /* @__PURE__ */ new Set(["http:", "https:", "socks4:", "socks4a:", "socks5:", "socks5h:"]);
60
- if (!supportedProtocols.has(parsed.protocol)) {
61
- throw new Error("\u4EE3\u7406\u5730\u5740\u4EC5\u652F\u6301 http\u3001https\u3001socks4\u3001socks4a\u3001socks5 \u6216 socks5h\u3002");
62
- }
63
- }
64
72
  const next = {
65
73
  ...settings,
66
- networkProxy: {
67
- enabled: params.enabled,
68
- url,
69
- noProxy
70
- }
74
+ networkProxy: normalizeNetworkProxy(settings, params)
71
75
  };
72
76
  await saveSettings(next);
73
77
  return next;
@@ -83,6 +87,18 @@ class ConfigService {
83
87
  await saveSettings(next);
84
88
  return next;
85
89
  }
90
+ async setRuntimeConfig(params) {
91
+ const settings = await this.getSettings();
92
+ const next = {
93
+ ...settings,
94
+ runtime: {
95
+ ...settings.runtime,
96
+ quotaSyncConcurrency: normalizeQuotaSyncConcurrency(params.quotaSyncConcurrency, settings.runtime.quotaSyncConcurrency)
97
+ }
98
+ };
99
+ await saveSettings(next);
100
+ return next;
101
+ }
86
102
  async getServerConfig() {
87
103
  const settings = await this.getSettings();
88
104
  return settings.server;
@@ -99,6 +115,54 @@ class ConfigService {
99
115
  await saveSettings(next);
100
116
  return next;
101
117
  }
118
+ async updateSettings(params) {
119
+ const settings = await this.getSettings();
120
+ let next = { ...settings };
121
+ if (params.defaultModel) {
122
+ if (!await hasCodexModel(params.defaultModel)) {
123
+ throw new Error(`\u5F53\u524D\u7F51\u5173\u672A\u627E\u5230\u53EF\u7528\u6A21\u578B: ${params.defaultModel}`);
124
+ }
125
+ next = {
126
+ ...next,
127
+ defaultProvider: "openai-codex",
128
+ defaultModel: params.defaultModel
129
+ };
130
+ }
131
+ if (params.networkProxy) {
132
+ next = {
133
+ ...next,
134
+ networkProxy: normalizeNetworkProxy(next, params.networkProxy)
135
+ };
136
+ }
137
+ if (params.autoSwitch) {
138
+ next = {
139
+ ...next,
140
+ autoSwitch: {
141
+ enabled: params.autoSwitch.enabled
142
+ }
143
+ };
144
+ }
145
+ if (params.runtime) {
146
+ next = {
147
+ ...next,
148
+ runtime: {
149
+ ...next.runtime,
150
+ quotaSyncConcurrency: normalizeQuotaSyncConcurrency(params.runtime.quotaSyncConcurrency, next.runtime.quotaSyncConcurrency)
151
+ }
152
+ };
153
+ }
154
+ if (params.server) {
155
+ next = {
156
+ ...next,
157
+ server: {
158
+ ...next.server,
159
+ port: params.server.port
160
+ }
161
+ };
162
+ }
163
+ await saveSettings(next);
164
+ return next;
165
+ }
102
166
  async resetSettings() {
103
167
  const defaults = createDefaultSettings();
104
168
  await saveSettings(defaults);
@@ -56,7 +56,7 @@ class VersionService {
56
56
  const manifest = await readPackageManifest();
57
57
  const registryUrl = `https://registry.npmjs.org/${encodeURIComponent(manifest.name)}/latest`;
58
58
  try {
59
- const latestVersion = await this.fetchNpmLatestVersion(registryUrl);
59
+ const latestVersion = process.env.AZT_FORCE_LATEST_VERSION || await this.fetchNpmLatestVersion(registryUrl);
60
60
  const needsUpdate = compareSemver(manifest.version, latestVersion) < 0;
61
61
  return {
62
62
  packageName: manifest.name,
@@ -6,6 +6,7 @@ import {
6
6
  getStorePath
7
7
  } from "./state-paths.js";
8
8
  const PROFILE_CLAIM_PATH = "https://api.openai.com/profile";
9
+ let storeMutationQueue = Promise.resolve();
9
10
  function createEmptyStore() {
10
11
  return {
11
12
  version: 1,
@@ -73,36 +74,50 @@ async function saveStore(store) {
73
74
  await fs.writeFile(getStorePath(), `${JSON.stringify(store, null, 2)}
74
75
  `, "utf8");
75
76
  }
77
+ async function withStoreMutation(operation) {
78
+ const run = storeMutationQueue.then(operation, operation);
79
+ storeMutationQueue = run.then(
80
+ () => void 0,
81
+ () => void 0
82
+ );
83
+ return run;
84
+ }
76
85
  async function saveProfile(profile) {
77
- const store = await loadStore();
78
- store.profiles[profile.profileId] = profile;
79
- store.activeProfileId = profile.profileId;
80
- await saveStore(store);
86
+ await withStoreMutation(async () => {
87
+ const store = await loadStore();
88
+ store.profiles[profile.profileId] = profile;
89
+ store.activeProfileId = profile.profileId;
90
+ await saveStore(store);
91
+ });
81
92
  }
82
93
  async function updateProfile(profileId, updater) {
83
- const store = await loadStore();
84
- const profile = store.profiles[profileId];
85
- if (!profile) {
86
- return null;
87
- }
88
- const updated = updater(profile);
89
- store.profiles[profileId] = updated;
90
- await saveStore(store);
91
- return updated;
94
+ return withStoreMutation(async () => {
95
+ const store = await loadStore();
96
+ const profile = store.profiles[profileId];
97
+ if (!profile) {
98
+ return null;
99
+ }
100
+ const updated = updater(profile);
101
+ store.profiles[profileId] = updated;
102
+ await saveStore(store);
103
+ return updated;
104
+ });
92
105
  }
93
106
  async function listProfiles() {
94
107
  const store = await loadStore();
95
108
  return Object.values(store.profiles);
96
109
  }
97
110
  async function setActiveProfile(profileId) {
98
- const store = await loadStore();
99
- const profile = store.profiles[profileId];
100
- if (!profile) {
101
- return null;
102
- }
103
- store.activeProfileId = profileId;
104
- await saveStore(store);
105
- return profile;
111
+ return withStoreMutation(async () => {
112
+ const store = await loadStore();
113
+ const profile = store.profiles[profileId];
114
+ if (!profile) {
115
+ return null;
116
+ }
117
+ store.activeProfileId = profileId;
118
+ await saveStore(store);
119
+ return profile;
120
+ });
106
121
  }
107
122
  async function getActiveProfile() {
108
123
  const store = await loadStore();
@@ -114,19 +129,44 @@ async function getActiveProfile() {
114
129
  return first ?? null;
115
130
  }
116
131
  async function removeProfile(profileId) {
117
- const store = await loadStore();
118
- if (!store.profiles[profileId]) {
119
- return null;
120
- }
121
- delete store.profiles[profileId];
122
- if (store.activeProfileId === profileId) {
123
- store.activeProfileId = Object.keys(store.profiles)[0];
124
- }
125
- await saveStore(store);
126
- return store.activeProfileId ? store.profiles[store.activeProfileId] ?? null : null;
132
+ return withStoreMutation(async () => {
133
+ const store = await loadStore();
134
+ if (!store.profiles[profileId]) {
135
+ return null;
136
+ }
137
+ delete store.profiles[profileId];
138
+ if (store.activeProfileId === profileId) {
139
+ store.activeProfileId = Object.keys(store.profiles)[0];
140
+ }
141
+ await saveStore(store);
142
+ return store.activeProfileId ? store.profiles[store.activeProfileId] ?? null : null;
143
+ });
144
+ }
145
+ async function removeProfiles(profileIds) {
146
+ return withStoreMutation(async () => {
147
+ const idSet = new Set(profileIds.map((id) => id.trim()).filter(Boolean));
148
+ if (idSet.size === 0) {
149
+ return 0;
150
+ }
151
+ const store = await loadStore();
152
+ let removed = 0;
153
+ for (const profileId of idSet) {
154
+ if (store.profiles[profileId]) {
155
+ delete store.profiles[profileId];
156
+ removed += 1;
157
+ }
158
+ }
159
+ if (store.activeProfileId && !store.profiles[store.activeProfileId]) {
160
+ store.activeProfileId = Object.keys(store.profiles)[0];
161
+ }
162
+ await saveStore(store);
163
+ return removed;
164
+ });
127
165
  }
128
166
  async function clearStore() {
129
- await fs.rm(getStateDir(), { recursive: true, force: true });
167
+ await withStoreMutation(async () => {
168
+ await fs.rm(getStateDir(), { recursive: true, force: true });
169
+ });
130
170
  }
131
171
  export {
132
172
  clearStore,
@@ -136,6 +176,7 @@ export {
136
176
  listProfiles,
137
177
  loadStore,
138
178
  removeProfile,
179
+ removeProfiles,
139
180
  saveProfile,
140
181
  saveStore,
141
182
  setActiveProfile,
@@ -18,6 +18,9 @@ function createDefaultSettings() {
18
18
  autoSwitch: {
19
19
  enabled: false
20
20
  },
21
+ runtime: {
22
+ quotaSyncConcurrency: 16
23
+ },
21
24
  server: {
22
25
  host: "0.0.0.0",
23
26
  port: 8787
@@ -42,6 +45,9 @@ async function loadSettings() {
42
45
  autoSwitch: {
43
46
  enabled: parsed.autoSwitch?.enabled ?? defaults.autoSwitch.enabled
44
47
  },
48
+ runtime: {
49
+ quotaSyncConcurrency: normalizeQuotaSyncConcurrency(parsed.runtime?.quotaSyncConcurrency, defaults.runtime.quotaSyncConcurrency)
50
+ },
45
51
  server: {
46
52
  host: parsed.server?.host ?? defaults.server.host,
47
53
  port: parsed.server?.port ?? defaults.server.port
@@ -51,6 +57,13 @@ async function loadSettings() {
51
57
  return createDefaultSettings();
52
58
  }
53
59
  }
60
+ function normalizeQuotaSyncConcurrency(value, fallback = 16) {
61
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : fallback;
62
+ if (!Number.isFinite(parsed)) {
63
+ return fallback;
64
+ }
65
+ return Math.min(32, Math.max(1, Math.trunc(parsed)));
66
+ }
54
67
  async function saveSettings(settings) {
55
68
  await ensureStateMigrated();
56
69
  await fs.mkdir(getStateDir(), { recursive: true });
@@ -61,5 +74,6 @@ export {
61
74
  createDefaultSettings,
62
75
  getSettingsPath,
63
76
  loadSettings,
77
+ normalizeQuotaSyncConcurrency,
64
78
  saveSettings
65
79
  };