@co0ontty/wand 4.20.0 → 4.21.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/dist/server.js CHANGED
@@ -14,7 +14,7 @@ import { AuthService, BROWSER_ADMIN_PRINCIPAL, CONNECTED_APP_PRINCIPAL, principa
14
14
  import { ensureCertificates } from "./cert.js";
15
15
  import { listClaudeSkills } from "./claude-skills.js";
16
16
  import { getDefaultModelForProvider, getProviderDefaultModels, isExecutionMode, resolveConfigDir, } from "./config.js";
17
- import { refreshModels } from "./models.js";
17
+ import { ModelCatalogService } from "./models.js";
18
18
  import { ProcessManager } from "./process-manager.js";
19
19
  import { SessionLogger } from "./session-logger.js";
20
20
  import { SessionRegistry } from "./session-registry.js";
@@ -54,6 +54,7 @@ const PKG_NODE_REQ = PKG_JSON.engines?.node ?? ">=22.5.0";
54
54
  const PKG_REPO_URL = "https://github.com/co0ontty/wand";
55
55
  // ── Update check cache ──
56
56
  const CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes
57
+ const MODEL_CATALOG_AUTO_REFRESH_INTERVAL_MS = 30 * 60 * 1000;
57
58
  /** Cached update result broadcast to new clients on connect. */
58
59
  let cachedUpdateInfo = null;
59
60
  const packageUpdateCache = new Map();
@@ -485,6 +486,9 @@ export async function startServer(config, configPath, options = {}) {
485
486
  ],
486
487
  };
487
488
  };
489
+ // This service is the only owner of CLI model discovery for this server.
490
+ // Clients receive its persisted snapshot via GET /api/models.
491
+ const modelCatalog = new ModelCatalogService(getModelRefreshOptions);
488
492
  const configDir = resolveConfigDir(configPath);
489
493
  const distributionManager = new DistributionManager({
490
494
  configDir,
@@ -886,7 +890,7 @@ export async function startServer(config, configPath, options = {}) {
886
890
  getCachedUpdateInfo: () => cachedUpdateInfo,
887
891
  getUpdateChannel,
888
892
  getDistributionSettings,
889
- getModelRefreshOptions,
893
+ modelCatalog,
890
894
  resolveAppConnectCode: (req) => {
891
895
  const effectivePassword = getEffectivePassword(storage, config);
892
896
  const requestProtocol = getPublicRequestProtocol(req, useHttps ? "https" : "http");
@@ -904,7 +908,7 @@ export async function startServer(config, configPath, options = {}) {
904
908
  requireAdmin,
905
909
  state: updateState,
906
910
  getDistributionSettings,
907
- getModelRefreshOptions,
911
+ modelCatalog,
908
912
  getUpdateChannel,
909
913
  checkLatestPackageVersion,
910
914
  buildInfo: BUILD_INFO,
@@ -1178,9 +1182,16 @@ export async function startServer(config, configPath, options = {}) {
1178
1182
  if (!testMode) {
1179
1183
  processes.runStartupCommands();
1180
1184
  }
1181
- // Pre-warm model cache (probes claude --version + codex debug models).
1185
+ // Model discovery runs exclusively in the server. Its first result is
1186
+ // persisted; later checks only write when catalog content changes.
1187
+ let modelCatalogRefreshTimer = null;
1182
1188
  if (!testMode) {
1183
- refreshModels(getModelRefreshOptions()).catch(() => { });
1189
+ void modelCatalog.refresh().catch(() => { });
1190
+ modelCatalogRefreshTimer = setInterval(() => {
1191
+ if (!shuttingDown)
1192
+ void modelCatalog.refresh().catch(() => { });
1193
+ }, MODEL_CATALOG_AUTO_REFRESH_INTERVAL_MS);
1194
+ modelCatalogRefreshTimer.unref();
1184
1195
  }
1185
1196
  // ── Auto-update endpoints ──
1186
1197
  app.get("/api/auto-update", requireAdmin, (_req, res) => {
@@ -1340,7 +1351,7 @@ export async function startServer(config, configPath, options = {}) {
1340
1351
  for (const result of results) {
1341
1352
  process.stdout.write(`[wand] CLI 自动更新 ${result.ok ? "完成" : "失败"}: ${result.message}\n`);
1342
1353
  }
1343
- refreshModels(getModelRefreshOptions()).catch(() => { });
1354
+ void modelCatalog.refresh().catch(() => { });
1344
1355
  }
1345
1356
  catch (error) {
1346
1357
  process.stdout.write(`[wand] CLI 自动更新失败: ${getErrorMessage(error)}\n`);
@@ -1383,6 +1394,10 @@ export async function startServer(config, configPath, options = {}) {
1383
1394
  clearTimeout(providerCliUpdateTimer);
1384
1395
  providerCliUpdateTimer = null;
1385
1396
  }
1397
+ if (modelCatalogRefreshTimer) {
1398
+ clearInterval(modelCatalogRefreshTimer);
1399
+ modelCatalogRefreshTimer = null;
1400
+ }
1386
1401
  // Stop accepting requests first. Existing requests get a short grace
1387
1402
  // period while managers flush and active runners are cancelled.
1388
1403
  const serverClosed = new Promise((resolve) => {