oasis_test_v2 2.2.3 → 2.2.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 (2) hide show
  1. package/dist/index.js +194 -15
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -24008,6 +24008,13 @@ function applyModelOverrides(base, overrides) {
24008
24008
  }
24009
24009
  return kept;
24010
24010
  }
24011
+ function clearModelDiscoveryCache(runtime, executablePath) {
24012
+ if (!runtime) {
24013
+ modelCache.clear();
24014
+ return;
24015
+ }
24016
+ modelCache.delete(discoveryCacheKey(runtime, executablePath));
24017
+ }
24011
24018
  function discoveryCacheKey(runtime, executablePath) {
24012
24019
  return `${runtime}:${executablePath ?? ""}`;
24013
24020
  }
@@ -24032,8 +24039,11 @@ async function withFallback(runtime, executablePath, discover, fallback) {
24032
24039
  }
24033
24040
  function claudeStaticModels() {
24034
24041
  return [
24035
- { id: "claude-opus-4-7", label: "Claude Opus 4.7", provider: "Anthropic", default: true },
24042
+ { id: "claude-opus-5", label: "Claude Opus 5", provider: "Anthropic" },
24043
+ { id: "claude-fable-5-1", label: "Claude Fable 5.1", provider: "Anthropic" },
24044
+ { id: "claude-fable-5", label: "Claude Fable 5", provider: "Anthropic" },
24036
24045
  { id: "claude-opus-4-8", label: "Claude Opus 4.8", provider: "Anthropic" },
24046
+ { id: "claude-opus-4-7", label: "Claude Opus 4.7", provider: "Anthropic" },
24037
24047
  { id: "claude-opus-4-6", label: "Claude Opus 4.6", provider: "Anthropic" },
24038
24048
  { id: "claude-sonnet-5", label: "Claude Sonnet 5", provider: "Anthropic" },
24039
24049
  { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", provider: "Anthropic" },
@@ -24043,14 +24053,12 @@ function claudeStaticModels() {
24043
24053
  }
24044
24054
  function codexStaticModels() {
24045
24055
  return [
24046
- { id: "gpt-5.5", label: "GPT-5.5", provider: "OpenAI", default: true },
24047
- { id: "gpt-5.5-mini", label: "GPT-5.5 mini", provider: "OpenAI" },
24048
- { id: "gpt-5.4", label: "GPT-5.4", provider: "OpenAI" },
24049
- { id: "gpt-5.4-mini", label: "GPT-5.4 mini", provider: "OpenAI" },
24050
- { id: "gpt-5.3-codex", label: "GPT-5.3 Codex", provider: "OpenAI" },
24051
- { id: "gpt-5", label: "GPT-5", provider: "OpenAI" },
24052
- { id: "o3", label: "o3", provider: "OpenAI" },
24053
- { id: "o3-mini", label: "o3-mini", provider: "OpenAI" }
24056
+ { id: "gpt-6-astra", label: "GPT-6-Astra", provider: "OpenAI", default: true },
24057
+ { id: "gpt-5.6-sol", label: "GPT-5.6-Sol", provider: "OpenAI" },
24058
+ { id: "gpt-5.6-terra", label: "GPT-5.6-Terra", provider: "OpenAI" },
24059
+ { id: "gpt-5.6-luna", label: "GPT-5.6-Luna", provider: "OpenAI" },
24060
+ { id: "gpt-5.5", label: "GPT-5.5", provider: "OpenAI" },
24061
+ { id: "gpt-5.2", label: "GPT-5.2", provider: "OpenAI" }
24054
24062
  ];
24055
24063
  }
24056
24064
  function geminiStaticModels() {
@@ -218483,6 +218491,31 @@ ${input.description}
218483
218491
  listActorConnectorConnections(actorId) {
218484
218492
  return this.opts.store.listActorConnectorConnections(actorId);
218485
218493
  }
218494
+ /**
218495
+ * 移除某员工与某连接器的连接(组织页连接器详情的「移除连接」,2026-09-09 原型 1600:5765)。
218496
+ *
218497
+ * 删两样东西,缺一不可:
218498
+ * ① 这名员工**自己**那份连接器凭据(`scope=personal` 且 `connectorId` 命中的变量行)——
218499
+ * 不删的话,「移除」之后 `actorConnected` 里还有它,卡片照样在,读作「删不掉」;
218500
+ * ② 「员工×连接器」的连接记录——不删的话 `effective` 里还有它(enabled=false),
218501
+ * 卡片变成一张「已停用」的僵尸卡,而人要的是它消失。
218502
+ *
218503
+ * **不碰组织那条 connector 行**(决策 0080 修订五的同一条理由):组织级连接是别人配的资产,
218504
+ * 一名员工点「移除连接」不该把全组织的连接拆掉。组织级的断开在「管理 > 连接器」。
218505
+ * 于是:组织已连接时,移除个人连接后这名员工会**回落到组织默认**——卡片仍在,但身份那一行
218506
+ * 变回组织账号。这是对的,不是没删干净。
218507
+ *
218508
+ * 幂等:没有个人凭据、没有记录时照样返回成功(`variablesDeleted: 0`)——重复点、并发点都不该报错。
218509
+ */
218510
+ async removeActorConnector(actorId, connectorId) {
218511
+ const rows = await this.opts.store.listVariables(actorId);
218512
+ const mine = rows.filter(
218513
+ (v2) => v2.scope === "personal" && v2.actorId === actorId && v2.connectorId === connectorId
218514
+ );
218515
+ for (const v2 of mine) await this.opts.store.deleteVariable(v2.key, actorId);
218516
+ await this.opts.store.deleteActorConnectorConnection(actorId, connectorId);
218517
+ return { removed: true, variablesDeleted: mine.length };
218518
+ }
218486
218519
  /**
218487
218520
  * 员工连接器面板所需状态:连接记录 + 组织级已连接集合 + 该员工已授权(有个人 connector 变量)集合。
218488
218521
  * 前端据此算每个 connector 的 hasRecord / 有效 enabled / connected(actor 或 global)。
@@ -219282,15 +219315,28 @@ var init_model_pricing = __esm({
219282
219315
  "gpt-4.1-nano": usd(0.1, 0.4, 0.025),
219283
219316
  "gpt-4.1-nano-2025-04-14": usd(0.1, 0.4, 0.025),
219284
219317
  "o4-mini": usd(1.1, 4.4, 0.275),
219318
+ // o3 / o3-mini 在 codex 静态目录里可选,却一直不在价目快照里(费用记 0)。
219319
+ // 这两行按 OpenAI 公开价填,不是智增增快照里的行;供应商价目表同步到时以 DB 为准。
219320
+ "o3": usd(2, 8),
219321
+ "o3-mini": usd(1.1, 4.4),
219322
+ "claude-fable-5-1": usd(10, 50),
219285
219323
  "claude-fable-5": usd(10, 50),
219324
+ "claude-mythos-5-1": usd(10, 50),
219286
219325
  "claude-mythos-5": usd(10, 50),
219326
+ // claude-opus-5 是 Claude Code 当代默认款,却一直不在这张快照里:查不到价 → 费用记 0
219327
+ // (与 2026-09-04 那次 `claude-opus-5[1m]` 记 0 同一类坑)。按 Opus 档 $5/$25 补上。
219328
+ "claude-opus-5": usd(5, 25),
219287
219329
  "claude-opus-4-8": usd(5, 25),
219288
219330
  "claude-opus-4-7": usd(5, 25),
219289
219331
  "claude-sonnet-5": usd(2, 10),
219290
219332
  "claude-sonnet-4-6": usd(3, 15),
219291
219333
  "claude-opus-4-6": usd(5, 25),
219292
219334
  "claude-opus-4-5-20251101": usd(5, 25),
219335
+ "claude-opus-4-5": usd(5, 25),
219293
219336
  "claude-sonnet-4-5-20250929": usd(3, 15),
219337
+ // 短名同样要有:前缀比对是「表里的键是模型名的前缀」,带日期的那行匹配不上不带日期的短名。
219338
+ // claude-sonnet-4-5 从 2026-07-04 起就在目录里可选,却一直查不到价(费用记 0),本次一并补。
219339
+ "claude-sonnet-4-5": usd(3, 15),
219294
219340
  "claude-opus-4-1-20250805": usd(15, 75),
219295
219341
  "claude-opus-4-20250514": usd(15, 75),
219296
219342
  "claude-sonnet-4-20250514": usd(3, 15),
@@ -219299,6 +219345,14 @@ var init_model_pricing = __esm({
219299
219345
  "claude-3-5-sonnet-20240620": usd(3, 15),
219300
219346
  "claude-3-sonnet-20240229": usd(3, 15),
219301
219347
  "claude-haiku-4-5-20251001": usd(1, 5),
219348
+ // codebuddy 目录用点号写法(claude-sonnet-4.6),与上面的连字符写法是同一批模型,
219349
+ // 但字符串对不上就查不到价 → 记 0。同价另起别名行。
219350
+ "claude-sonnet-4.6": usd(3, 15),
219351
+ "claude-opus-4.7": usd(5, 25),
219352
+ "gemini-3.1-pro": usd(2, 12),
219353
+ "gemini-3-pro-preview": usd(2, 12),
219354
+ // Claude Code 回报的可能是不带日期的短名,短名匹配不上带日期的那行(前缀比对是「表里的键是模型名的前缀」)。
219355
+ "claude-haiku-4-5": usd(1, 5),
219302
219356
  "gemini-3.5-flash": usd(1.5, 9),
219303
219357
  "gemini-3.1-pro-preview": usd(2, 12),
219304
219358
  "gemini-3.1-pro-preview-customtools": usd(2, 12),
@@ -220432,6 +220486,11 @@ function actorsDomain(opts) {
220432
220486
  const conn = await service.setActorConnectorEnabled(req.params.id, req.params.connectorId, b2.enabled);
220433
220487
  return { status: 200, body: conn };
220434
220488
  });
220489
+ router.delete("/api/actors/:id/connectors/:connectorId", async (req) => {
220490
+ const { service } = await resolveCtx(req.auth.companyId);
220491
+ const r = await service.removeActorConnector(req.params.id, req.params.connectorId);
220492
+ return { status: 200, body: r };
220493
+ });
220435
220494
  const requireVariableManager = (req) => {
220436
220495
  if (!isHumanActor(req.auth.actor)) {
220437
220496
  throw new ApiError(
@@ -224723,11 +224782,13 @@ async function resolveRuntimeModels(deps, runtimeId) {
224723
224782
  const rt = (await deps.nodeStore.listRuntimes()).find((r) => r.id === runtimeId);
224724
224783
  if (!rt) return [];
224725
224784
  try {
224726
- const [base, overrides] = await Promise.all([
224727
- listModels(rt.kind, rt.binary),
224785
+ const reported = deps.nodeReportedModels?.(rt.nodeId, rt.kind);
224786
+ const [discovered, overrides] = await Promise.all([
224787
+ // 节点报过就不必再在控制面上白 spawn 一次(跨机时那次 spawn 注定 ENOENT)。
224788
+ reported && reported.length > 0 ? Promise.resolve(reported) : listModels(rt.kind, rt.binary),
224728
224789
  deps.registry.listRuntimeModelOverrides(runtimeId)
224729
224790
  ]);
224730
- return applyModelOverrides(base, overrides);
224791
+ return applyModelOverrides(discovered, overrides);
224731
224792
  } catch {
224732
224793
  const overrides = await deps.registry.listRuntimeModelOverrides(runtimeId).catch(() => []);
224733
224794
  return applyModelOverrides([], overrides);
@@ -225119,6 +225180,21 @@ function nodesDomain(deps) {
225119
225180
  if (!rt) return { status: 404, body: { error: "runtime not found" } };
225120
225181
  return { status: 200, body: { items: await resolveRuntimeModels(deps, runtimeId) } };
225121
225182
  });
225183
+ router.post("/api/runtimes/:runtimeId/models/refresh", async (req) => {
225184
+ const runtimeId = req.params["runtimeId"];
225185
+ if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
225186
+ const rt = (await deps.nodeStore.listRuntimes()).find((r) => r.id === runtimeId);
225187
+ if (!rt) return { status: 404, body: { error: "runtime not found" } };
225188
+ const outcome = deps.refreshNodeModels ? await deps.refreshNodeModels(rt.nodeId) : { ok: false, reason: "\u672C\u90E8\u7F72\u6CA1\u6709\u8282\u70B9\u7F51\u5173\uFF0C\u62FF\u4E0D\u5230\u8FD9\u53F0\u673A\u5668\u4E0A\u7684\u771F\u5B9E\u6E05\u5355" };
225189
+ return {
225190
+ status: 200,
225191
+ body: {
225192
+ items: await resolveRuntimeModels(deps, runtimeId),
225193
+ refreshed: outcome.ok,
225194
+ ...outcome.reason ? { reason: outcome.reason } : {}
225195
+ }
225196
+ };
225197
+ });
225122
225198
  router.get("/api/runtimes/:runtimeId/model-overrides", async (req) => {
225123
225199
  const runtimeId = req.params["runtimeId"];
225124
225200
  if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
@@ -256820,6 +256896,41 @@ async function startServe(opts) {
256820
256896
  let nodeTokens = createNodeTokenStore(path29.join(opts.dir, "node-tokens.json"));
256821
256897
  const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path29.join(opts.dir, "enroll-tokens.json"));
256822
256898
  let nodeStore = await FileNodeStore.open(path29.join(opts.dir, "nodes.json"));
256899
+ const nodeReportedModelsStore = /* @__PURE__ */ new Map();
256900
+ const modelRefreshWaiters = /* @__PURE__ */ new Map();
256901
+ const modelRefreshInFlight = /* @__PURE__ */ new Map();
256902
+ const modelRefreshLastAt = /* @__PURE__ */ new Map();
256903
+ const MODELS_STALE_MS = 5 * 6e4;
256904
+ const MODELS_BG_REFRESH_MIN_GAP_MS = 6e4;
256905
+ const MODELS_REFRESH_TIMEOUT_MS = 45e3;
256906
+ const refreshNodeModels = (nodeId) => {
256907
+ const running = modelRefreshInFlight.get(nodeId);
256908
+ if (running) return running;
256909
+ if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
256910
+ const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
256911
+ if (!online) return Promise.resolve({ ok: false, reason: "\u8282\u70B9\u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u7528\u7684\u662F\u5B83\u4E0A\u6B21\u62A5\u7684\u6E05\u5355" });
256912
+ const requestId = (0, import_node_crypto75.randomUUID)();
256913
+ const task = new Promise((resolve10) => {
256914
+ const timer = setTimeout(() => {
256915
+ modelRefreshWaiters.delete(requestId);
256916
+ resolve10({ ok: false, reason: "\u8282\u70B9\u6CA1\u5728 45 \u79D2\u5185\u56DE\u8BDD\uFF08\u53EF\u80FD\u662F\u65E7\u7248\u8282\u70B9\uFF0C\u6216\u8FD9\u53F0\u673A\u5668\u4E0A\u7684 CLI \u63A2\u6D4B\u8D85\u65F6\uFF09" });
256917
+ }, MODELS_REFRESH_TIMEOUT_MS);
256918
+ modelRefreshWaiters.set(requestId, { resolve: () => resolve10({ ok: true }), timer });
256919
+ hub.dispatch(nodeId, { type: "list_models", requestId });
256920
+ }).finally(() => {
256921
+ modelRefreshInFlight.delete(nodeId);
256922
+ modelRefreshLastAt.set(nodeId, Date.now());
256923
+ });
256924
+ modelRefreshInFlight.set(nodeId, task);
256925
+ return task;
256926
+ };
256927
+ const nodeReportedModels = (nodeId, runtimeKind) => {
256928
+ const entry = nodeReportedModelsStore.get(nodeId);
256929
+ const stale = !entry || Date.now() - entry.fetchedAt > MODELS_STALE_MS;
256930
+ const gapOk = Date.now() - (modelRefreshLastAt.get(nodeId) ?? 0) > MODELS_BG_REFRESH_MIN_GAP_MS;
256931
+ if (stale && gapOk) void refreshNodeModels(nodeId).catch(() => ({ ok: false }));
256932
+ return entry?.byKind.get(runtimeKind);
256933
+ };
256823
256934
  const registryAuditFile = path29.join(opts.dir, "registry-audit.ndjson");
256824
256935
  const registryListeners = /* @__PURE__ */ new Set();
256825
256936
  const registryAudit = (record8) => {
@@ -256949,7 +257060,7 @@ async function startServe(opts) {
256949
257060
  listBindingModelIds: async (nodeId, runtimeKind) => {
256950
257061
  const rt = (await nodeStore.listRuntimes(nodeId)).find((r) => r.kind === runtimeKind);
256951
257062
  if (!rt) return [];
256952
- return (await resolveRuntimeModels({ nodeStore, registry: registryStore }, rt.id)).map((m2) => m2.id);
257063
+ return (await resolveRuntimeModels({ nodeStore, registry: registryStore, nodeReportedModels }, rt.id)).map((m2) => m2.id);
256953
257064
  }
256954
257065
  });
256955
257066
  assistantsService = new AssistantsService({
@@ -258487,7 +258598,7 @@ async function startServe(opts) {
258487
258598
  registry: registryStore,
258488
258599
  // 会话级模型覆盖的候选清单:与 `GET /api/runtimes/:id/models` **同一份**实现
258489
258600
  // (resolveRuntimeModels = discovery + 管理员 override),避免「下拉选得到、发出去被拒」。
258490
- listRuntimeModelIds: async (runtimeId) => (await resolveRuntimeModels({ nodeStore, registry: registryStore }, runtimeId)).map((m2) => m2.id),
258601
+ listRuntimeModelIds: async (runtimeId) => (await resolveRuntimeModels({ nodeStore, registry: registryStore, nodeReportedModels }, runtimeId)).map((m2) => m2.id),
258491
258602
  // 诊断 ab94f202 Fix A:add-revision --role 写入口校验用「可分配岗位」集合(岗位目录 AND assignable)。
258492
258603
  // 与 GET /api/roles 的 assignable 派生同式(domains/roles/index.ts):system=true / 已弃用一律不可分配。
258493
258604
  resolveAssignableRoles: async () => new Set(
@@ -258624,6 +258735,8 @@ async function startServe(opts) {
258624
258735
  nodeHealth,
258625
258736
  activeRunCountOf,
258626
258737
  activeRunsOf,
258738
+ nodeReportedModels,
258739
+ refreshNodeModels,
258627
258740
  fetchLatestNpmDaemonVersion
258628
258741
  }),
258629
258742
  collabDomain({
@@ -259933,6 +260046,24 @@ async function startServe(opts) {
259933
260046
  });
259934
260047
  return chatLiveSessions.has(jobKey) ? "live" : "unknown";
259935
260048
  });
260049
+ hub.addMessageListener((daemonId, msg) => {
260050
+ if (msg.type !== "runtime_models") return;
260051
+ const prev = nodeReportedModelsStore.get(daemonId);
260052
+ const byKind = prev?.byKind ?? /* @__PURE__ */ new Map();
260053
+ for (const entry of msg.models) {
260054
+ if (entry.models.length > 0) byKind.set(entry.kind, entry.models);
260055
+ }
260056
+ nodeReportedModelsStore.set(daemonId, { byKind, fetchedAt: Date.now() });
260057
+ if (msg.requestId) {
260058
+ const waiter = modelRefreshWaiters.get(msg.requestId);
260059
+ if (waiter) {
260060
+ clearTimeout(waiter.timer);
260061
+ modelRefreshWaiters.delete(msg.requestId);
260062
+ waiter.resolve();
260063
+ }
260064
+ }
260065
+ console.log(`[models] \u8282\u70B9 ${daemonId} \u4E0A\u62A5\u5019\u9009\u6A21\u578B\uFF1A${msg.models.map((m2) => `${m2.kind}=${m2.models.length}`).join(" ") || "\uFF08\u4E00\u6761\u90FD\u6CA1\u63A2\u5230\uFF09"}`);
260066
+ });
259936
260067
  hub.addMessageListener((daemonId, msg) => {
259937
260068
  if (msg.type !== "gc_query_artifacts") return;
259938
260069
  void (async () => {
@@ -263036,6 +263167,7 @@ var OUTBOX_MAX = 500;
263036
263167
  var PENDING_STREAM_MAX = 2e3;
263037
263168
  var AUTH_REJECT_BACKOFF_MAX_MS = 15 * 6e4;
263038
263169
  var AUTH_REJECT_GIVE_UP_AFTER = 3;
263170
+ var MODEL_REPORT_COOLDOWN_MS = 10 * 6e4;
263039
263171
  var AUTH_REJECT_RE = /Unexpected server response:\s*(401|403)/;
263040
263172
  var DRAIN_TIMEOUT_MS = 15e3;
263041
263173
  var DRAIN_POLL_MS = 50;
@@ -263129,6 +263261,12 @@ var DaemonWsClient = class {
263129
263261
  authRejectStreak = 0;
263130
263262
  /** 本次连接尝试是否因握手 401/403 失败——error 事件里置、close 事件里消费。 */
263131
263263
  lastErrorWasAuthReject = false;
263264
+ /** 模型上报的轮次号:重连会再拉一轮,用它作废上一轮的迟到结果(否则旧结果可能盖住新结果)。 */
263265
+ modelReportGeneration = 0;
263266
+ /** 上一次**探测成功**的时刻;节点频繁掉线重连时靠它避免每分钟把十几个 CLI 重起一遍。 */
263267
+ lastModelReportAt = 0;
263268
+ /** 缓存上一轮结果:冷却期内重连直接重发这份,服务端重启后也能立刻拿到清单。 */
263269
+ lastModelReport = [];
263132
263270
  authRejectGiveUpAfter;
263133
263271
  /** 放弃时的动作;默认干净退出(exit 0),测试注入以免打死测试进程。 */
263134
263272
  onAuthGiveUp;
@@ -263237,6 +263375,7 @@ var DaemonWsClient = class {
263237
263375
  this.flushPendingStream();
263238
263376
  this.resendOutbox();
263239
263377
  this.reportRuntimes = false;
263378
+ void this.reportRuntimeModels();
263240
263379
  this.pingTimer = setInterval(() => {
263241
263380
  this.send({ type: "pong" });
263242
263381
  if (Date.now() - this.lastReceivedAt > this.silenceTimeoutMs) {
@@ -263403,6 +263542,10 @@ var DaemonWsClient = class {
263403
263542
  this.send({ type: "workdir_read_result", requestId: msg.requestId, result });
263404
263543
  break;
263405
263544
  }
263545
+ case "list_models": {
263546
+ void this.reportRuntimeModels({ force: true, requestId: msg.requestId });
263547
+ break;
263548
+ }
263406
263549
  case "update": {
263407
263550
  this.pendingUpdatePkg = msg.pkg;
263408
263551
  if (!this.onUpdate) {
@@ -263520,6 +263663,42 @@ var DaemonWsClient = class {
263520
263663
  this.onUpdate?.(this.pendingUpdatePkg);
263521
263664
  }
263522
263665
  }
263666
+ /**
263667
+ * 拉一遍本机各 runtime 的候选模型清单并上报(`runtime_models` 帧)。
263668
+ *
263669
+ * 串行而不是并发:ACP 家族每探一个都要真起一个 CLI 进程(hermes 40s、oasis-agent 30s 的超时),
263670
+ * 十几个一起起会把节点的内存和文件句柄按住。`listModels` 自带 60 秒缓存,重连时基本是空跑。
263671
+ * 任何一个 runtime 抛错都只丢它自己那一条,不影响其余。全空就不发帧——让服务端走老路,
263672
+ * 而不是用一份空清单把它原本能给出的静态目录盖掉。
263673
+ */
263674
+ async reportRuntimeModels(opts = {}) {
263675
+ const generation = ++this.modelReportGeneration;
263676
+ const reply = (models) => this.send({ type: "runtime_models", models, ...opts.requestId ? { requestId: opts.requestId } : {} });
263677
+ if (!opts.force && this.lastModelReport.length > 0 && Date.now() - this.lastModelReportAt < MODEL_REPORT_COOLDOWN_MS) {
263678
+ reply(this.lastModelReport);
263679
+ return;
263680
+ }
263681
+ const out = [];
263682
+ for (const rt of this.runtimes) {
263683
+ if (generation !== this.modelReportGeneration) return;
263684
+ try {
263685
+ const kind = rt.kind;
263686
+ if (opts.force) clearModelDiscoveryCache(kind, rt.binary);
263687
+ const models = await listModels(kind, rt.binary);
263688
+ if (models.length > 0) out.push({ kind: rt.kind, models });
263689
+ } catch {
263690
+ }
263691
+ }
263692
+ if (generation !== this.modelReportGeneration) return;
263693
+ if (out.length === 0) {
263694
+ if (opts.requestId) reply([]);
263695
+ return;
263696
+ }
263697
+ this.lastModelReport = out;
263698
+ this.lastModelReportAt = Date.now();
263699
+ reply(out);
263700
+ log2("[node-cli]", `\u5DF2\u4E0A\u62A5\u5019\u9009\u6A21\u578B\uFF1A${out.map((r) => `${r.kind}=${r.models.length}`).join(" ")}`);
263701
+ }
263523
263702
  buildMeta() {
263524
263703
  const activeSessions = this.sessions.activeSessions();
263525
263704
  return {
@@ -269401,7 +269580,7 @@ function shimScript() {
269401
269580
  }
269402
269581
 
269403
269582
  // src/index.ts
269404
- var PKG_VERSION = true ? "2.2.3" : "dev";
269583
+ var PKG_VERSION = true ? "2.2.4" : "dev";
269405
269584
  var LOCAL_BIN = localBin();
269406
269585
  var NPM_PREFIX = npmPrefix();
269407
269586
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "e56cbdcade7180b0ef7fe4e089c9dd74086b3b00"
29
+ "sourceHead": "1488999e5b4e5658ae63be219fd34f59ae74705e"
30
30
  }
31
31
  }