oasis_test_v2 2.2.97 → 2.2.99

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 -45
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -5838,7 +5838,7 @@ var init_binary = __esm({
5838
5838
  async function listModels(runtime, executablePath) {
5839
5839
  switch (runtime) {
5840
5840
  case "claude-code":
5841
- return discoverClaudeCatalog(executablePath);
5841
+ return withFallback(runtime, executablePath, () => discoverClaudeModels(executablePath), claudeStaticModels);
5842
5842
  case "codex":
5843
5843
  return discoverCodexCatalog(executablePath);
5844
5844
  case "gemini":
@@ -5924,13 +5924,6 @@ async function cachedDiscovery(key2, fn) {
5924
5924
  if (models.length > 0) modelCache.set(key2, { models, expiresAt: now + CACHE_TTL_MS });
5925
5925
  return models;
5926
5926
  }
5927
- async function discoverClaudeCatalog(bin) {
5928
- const models = await cachedDiscovery(discoveryCacheKey("claude-code", bin), () => discoverClaudeModels(bin));
5929
- if (models.length === 0) return claudeStaticModels();
5930
- if (models.some((m2) => m2.provider === "custom")) return models;
5931
- const present = new Set(models.map((m2) => m2.id));
5932
- return [...models, ...claudeStaticModels().filter((m2) => !present.has(m2.id))];
5933
- }
5934
5927
  async function withFallback(runtime, executablePath, discover, fallback) {
5935
5928
  const models = await cachedDiscovery(discoveryCacheKey(runtime, executablePath), discover);
5936
5929
  return models.length > 0 ? models : fallback();
@@ -13681,12 +13674,13 @@ async function recordChatTurnInterruption(deps) {
13681
13674
  let version2 = await items.sessionVersionCursor(sessionId).catch(() => 0);
13682
13675
  const touched = [];
13683
13676
  const at2 = now();
13684
- for (const row of rows) {
13677
+ for (const row of deps.cause === "user-stop" ? [] : rows) {
13685
13678
  if (row.status !== "streaming") continue;
13686
13679
  const updated = await items.applyOp(row.id, { op: "set_status", status: "interrupted" }, { at: at2, version: ++version2, sessionId });
13687
13680
  if (updated) touched.push(updated);
13688
13681
  }
13689
- const payload2 = deps.cause === "sweep-orphan" ? {
13682
+ if (existing && isUserStopPayload(existing.payload)) return touched;
13683
+ const payload2 = deps.cause === "user-stop" ? { code: "error", note: CHAT_INTERRUPT_NOTICE["user-stop"], reason: "cancelled", closedBy: deps.reason, cancelledBy: "user" } : deps.cause === "sweep-orphan" ? {
13690
13684
  code: "error",
13691
13685
  note: deps.cancelledBy ? chatCancelNote(deps.cancelledBy) : CHAT_INTERRUPT_NOTICE[deps.cause],
13692
13686
  reason: "cancelled",
@@ -13720,6 +13714,9 @@ async function recordChatTurnInterruption(deps) {
13720
13714
  return [];
13721
13715
  }
13722
13716
  }
13717
+ function isUserStopPayload(payload2) {
13718
+ return !!payload2 && typeof payload2 === "object" && !Array.isArray(payload2) && payload2.cancelledBy === "user";
13719
+ }
13723
13720
  var chatInterruptItemId, CHAT_INTERRUPT_NOTICE;
13724
13721
  var init_chat_interrupt_notice = __esm({
13725
13722
  "../server/src/chat-interrupt-notice.ts"() {
@@ -13731,7 +13728,10 @@ var init_chat_interrupt_notice = __esm({
13731
13728
  CHAT_INTERRUPT_NOTICE = {
13732
13729
  "sweep-orphan": CHAT_CANCELLED_NOTE,
13733
13730
  "sweep-absolute-cap": "\u8FD9\u4E00\u8F6E\u8FD0\u884C\u65F6\u95F4\u8D85\u8FC7\u4E86\u4E0A\u9650\uFF0C\u5DF2\u88AB\u7CFB\u7EDF\u7EC8\u6B62\u3002\u4E0A\u9762\u662F\u7EC8\u6B62\u524D\u5DF2\u7ECF\u751F\u6210\u7684\u5185\u5BB9\uFF0C\u53EF\u4EE5\u628A\u4EFB\u52A1\u62C6\u5C0F\u4E00\u4E9B\u518D\u53D1\u4E00\u6B21\u3002",
13734
- "run-failed": "\u8FD9\u4E00\u8F6E\u6CA1\u6709\u6B63\u5E38\u7ED3\u675F\uFF08\u8FD0\u884C\u88AB\u4E2D\u65AD\uFF09\uFF0C\u6CA1\u80FD\u8DD1\u5B8C\u3002\u4E0A\u9762\u662F\u4E2D\u65AD\u524D\u5DF2\u7ECF\u751F\u6210\u7684\u5185\u5BB9\uFF0C\u4F60\u53EF\u4EE5\u518D\u53D1\u4E00\u6B21\u3002"
13731
+ "run-failed": "\u8FD9\u4E00\u8F6E\u6CA1\u6709\u6B63\u5E38\u7ED3\u675F\uFF08\u8FD0\u884C\u88AB\u4E2D\u65AD\uFF09\uFF0C\u6CA1\u80FD\u8DD1\u5B8C\u3002\u4E0A\u9762\u662F\u4E2D\u65AD\u524D\u5DF2\u7ECF\u751F\u6210\u7684\u5185\u5BB9\uFF0C\u4F60\u53EF\u4EE5\u518D\u53D1\u4E00\u6B21\u3002",
13732
+ // Bug 0228:serve 重启窗口里点停止,注册表里没有这一轮、只能在台账上收(`chat-turn-stop.ts`)。
13733
+ // 与在飞路径用户停止同一句、同一格归因;不借 `sweep-orphan` 那一支,免得日志里「用户停的」长成孤儿清扫。
13734
+ "user-stop": CHAT_CANCEL_NOTE.user
13735
13735
  };
13736
13736
  }
13737
13737
  });
@@ -131270,7 +131270,7 @@ async function renewInjectedCredentials(injected, fetchCredentials) {
131270
131270
  log("[node-connectors]", `\u7EED\u671F\uFF1A${slug6} \u6362\u5230\u65B0\u4EE4\u724C`);
131271
131271
  } else {
131272
131272
  outcome.unchanged.push(slug6);
131273
- log("[node-connectors]", `\u7EED\u671F\uFF1A${slug6} server \u8FD4\u56DE\u7684\u4ECD\u662F\u65E7\u4EE4\u724C\uFF08\u672A\u5230\u6362\u65B0\u95E8\u69DB\uFF09`);
131273
+ log("[node-connectors]", `\u7EED\u671F\uFF1A${slug6} server \u8FD4\u56DE\u7684\u4ECD\u662F\u65E7\u4EE4\u724C\uFF08\u539F\u56E0\u89C1 server \u65E5\u5FD7 [credential-refresh]\uFF09`);
131274
131274
  }
131275
131275
  } catch (err) {
131276
131276
  outcome.failed.push({ slug: slug6, error: String(err) });
@@ -176546,6 +176546,58 @@ var init_chat_workorder_files = __esm({
176546
176546
  }
176547
176547
  });
176548
176548
 
176549
+ // ../server/src/chat-turn-stop.ts
176550
+ async function stopLedgerTurn(deps) {
176551
+ const now = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
176552
+ const log3 = deps.log ?? (() => {
176553
+ });
176554
+ let turn = deps.turn ?? await deps.turns.activeTurn(deps.sessionId);
176555
+ for (let attempt = 0; attempt < MAX_CAS_ATTEMPTS; attempt += 1) {
176556
+ if (!turn || turn.status !== "reserved" && turn.status !== "running") return { stopped: false, reason: "no-live-turn" };
176557
+ if (deps.expectedRunId && turn.assistantRunId && turn.assistantRunId !== deps.expectedRunId) {
176558
+ return { stopped: false, reason: "turn-changed" };
176559
+ }
176560
+ const completedAt = now();
176561
+ const ok3 = await deps.turns.transitionTurn(
176562
+ turn.id,
176563
+ { status: turn.status, dispatchId: turn.dispatchId },
176564
+ { status: "cancelled", completedAt, lastError: `\u7528\u6237\u505C\u6B62\uFF08\u672C\u8FDB\u7A0B\u6CE8\u518C\u8868\u91CC\u6CA1\u6709\u8FD9\u4E00\u8F6E\uFF0C\u6309\u53F0\u8D26\u6536\uFF1B\u539F\u72B6\u6001 ${turn.status}\uFF09` }
176565
+ );
176566
+ if (ok3) {
176567
+ log3(`[chat-stop] \u4F1A\u8BDD ${deps.sessionId} \u8F6E ${turn.id} \u6309\u53F0\u8D26\u505C\u6B62\uFF08${turn.status} \u2192 cancelled\uFF09`);
176568
+ await recordUserStopNotice(deps, turn, completedAt);
176569
+ return { stopped: true, ledger: true };
176570
+ }
176571
+ turn = await deps.turns.getTurn(turn.id);
176572
+ }
176573
+ return { stopped: false, reason: "turn-changed" };
176574
+ }
176575
+ async function recordUserStopNotice(deps, turn, completedAt) {
176576
+ if (!deps.items) return;
176577
+ const messageId = turn.assistantRunId && deps.findAssistantMessageId ? await deps.findAssistantMessageId(turn.assistantRunId).catch(() => void 0) : void 0;
176578
+ const turnId = messageId ? await resolveChatItemsTurnId(deps.items, messageId, turn.id) : turn.id;
176579
+ await recordChatTurnInterruption({
176580
+ items: deps.items,
176581
+ sessionId: deps.sessionId,
176582
+ turnId,
176583
+ runId: turn.assistantRunId,
176584
+ messageId,
176585
+ cause: "user-stop",
176586
+ reason: "user-stop",
176587
+ now: () => completedAt,
176588
+ ...deps.log ? { log: deps.log } : {}
176589
+ });
176590
+ }
176591
+ var MAX_CAS_ATTEMPTS;
176592
+ var init_chat_turn_stop = __esm({
176593
+ "../server/src/chat-turn-stop.ts"() {
176594
+ "use strict";
176595
+ init_chat_interrupt_notice();
176596
+ init_chat_item_ledger();
176597
+ MAX_CAS_ATTEMPTS = 3;
176598
+ }
176599
+ });
176600
+
176549
176601
  // ../server/src/chat-broadcast.ts
176550
176602
  function isFreshTerminal(terminalAt, nowMs, maxAgeMs) {
176551
176603
  if (!terminalAt) return true;
@@ -211154,6 +211206,10 @@ function writeApiError(res, err) {
211154
211206
  error: { code: err.code, message: err.message, ...err.details ?? {} }
211155
211207
  }));
211156
211208
  }
211209
+ async function findAssistantMessageIdByRun(store, sessionId, runId) {
211210
+ const rows = await (await store())?.listMessages(sessionId, 20).catch(() => []) ?? [];
211211
+ return rows.find((m2) => m2.role === "assistant" && m2.runId === runId)?.id;
211212
+ }
211157
211213
  function toApiError(err) {
211158
211214
  if (err instanceof ApiError) return err;
211159
211215
  const message = err instanceof Error ? err.message : String(err);
@@ -212737,6 +212793,7 @@ async function startOasisServer(opts) {
212737
212793
  }) : void 0;
212738
212794
  knowledgeDomain?.register(domainRouter);
212739
212795
  const liveChat = opts.liveChat ?? new LiveChatRegistry();
212796
+ const serveBootedAtMs = Date.now();
212740
212797
  const resolveChatSessionsForDelegation = opts.chatSessionFor ?? (opts.chatSession ? async () => opts.chatSession : void 0);
212741
212798
  let delegationService = null;
212742
212799
  if (opts.delegationStoreFor && resolveChatSessionsForDelegation && opts.actors && opts.dispatchChat) {
@@ -215173,12 +215230,15 @@ async function startOasisServer(opts) {
215173
215230
  liveChat.reopenForRecovery(sid, {
215174
215231
  runtimeSessionId: cs.runtimeSessionId ?? active.dispatchId ?? "",
215175
215232
  ...active.assistantRunId ? { runId: active.assistantRunId } : {},
215233
+ // 占位轮被 `/stop` 停掉:与注册表落空时同一个收法(条件迁移 + 用户停止结局项,Bug 0228)。
215176
215234
  onStop: () => {
215177
- void turns.settleTurn(active.id, {
215178
- status: "cancelled",
215179
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
215180
- lastError: `\u7528\u6237\u5728 serve \u91CD\u542F\u6062\u590D\u7A97\u53E3\u5185\u505C\u6B62\uFF08\u8F6E ${active.id}\uFF09`
215181
- }).catch(() => void 0);
215235
+ void (async () => stopLedgerTurn({
215236
+ turns,
215237
+ sessionId: sid,
215238
+ turn: active,
215239
+ items: opts.resolveChatItems ? await opts.resolveChatItems(currentCompanyId).catch(() => void 0) : opts.chatItems,
215240
+ findAssistantMessageId: (runId) => findAssistantMessageIdByRun(chatStoreNowOrNull, sid, runId)
215241
+ }))().catch(() => void 0);
215182
215242
  }
215183
215243
  });
215184
215244
  };
@@ -215342,7 +215402,32 @@ async function startOasisServer(opts) {
215342
215402
  if (typeof b2.expectedRunId === "string" && b2.expectedRunId) expectedRunId = b2.expectedRunId;
215343
215403
  } catch {
215344
215404
  }
215345
- const outcome = liveChat.stop(sid, expectedRunId);
215405
+ let outcome = liveChat.stop(sid, expectedRunId);
215406
+ if (!outcome.stopped && outcome.reason === "no-live-turn") {
215407
+ const turns = opts.resolveChatTurns ? await opts.resolveChatTurns(currentCompanyId).catch(() => void 0) : opts.chatTurns;
215408
+ const active = turns ? await turns.activeTurn(sid).catch(() => null) : null;
215409
+ if (turns && active) {
215410
+ const openedByThisProcess = Date.parse(active.reservedAt) >= serveBootedAtMs;
215411
+ if (openedByThisProcess) {
215412
+ await waitForAdmittedTurnStart(sid, { liveChat, ledgerTurnRunning: async () => true, timeoutMs: STOP_TURN_START_WAIT_MS });
215413
+ outcome = liveChat.stop(sid, expectedRunId);
215414
+ }
215415
+ if (!outcome.stopped && outcome.reason === "no-live-turn") {
215416
+ outcome = await stopLedgerTurn({
215417
+ turns,
215418
+ sessionId: sid,
215419
+ expectedRunId,
215420
+ ...openedByThisProcess ? {} : { turn: active },
215421
+ items: opts.resolveChatItems ? await opts.resolveChatItems(currentCompanyId).catch(() => void 0) : opts.chatItems,
215422
+ findAssistantMessageId: (runId) => findAssistantMessageIdByRun(chatStoreNowOrNull, sid, runId),
215423
+ log: (m2) => console.log(m2)
215424
+ }).catch((err) => {
215425
+ console.warn(`[chat-stop] \u4F1A\u8BDD ${sid} \u6309\u53F0\u8D26\u505C\u6B62\u5931\u8D25: ${String(err)}`);
215426
+ return { stopped: false, reason: "turn-changed" };
215427
+ });
215428
+ }
215429
+ }
215430
+ }
215346
215431
  res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(outcome));
215347
215432
  return;
215348
215433
  }
@@ -217439,7 +217524,7 @@ async function markDeliveredWithRetry(store, messageId, attempts = 3) {
217439
217524
  }
217440
217525
  return false;
217441
217526
  }
217442
- var http, import_node_crypto44, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, COMPANY_FROM_PENDING_CALLBACKS, defaultResolveActor, enc, APPEND_TURN_START_WAIT_MS, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
217527
+ var http, import_node_crypto44, CONNECTOR_AUTH_SNAPSHOT_TTL_MS, COMPANY_FROM_PENDING_CALLBACKS, defaultResolveActor, enc, APPEND_TURN_START_WAIT_MS, STOP_TURN_START_WAIT_MS, STREAMING_PATHS, PLANNER_BLOCKING_CODES, WILL_VERBS, GOVERNANCE_COMMANDS, READ_ONLY_COMMANDS, isAgent, isHuman;
217443
217528
  var init_server3 = __esm({
217444
217529
  "../server/src/server.ts"() {
217445
217530
  "use strict";
@@ -217505,6 +217590,7 @@ var init_server3 = __esm({
217505
217590
  init_chat_workorder_files();
217506
217591
  init_chat_item_ledger();
217507
217592
  init_chat_cancel_attribution();
217593
+ init_chat_turn_stop();
217508
217594
  init_chat_assistant_turn();
217509
217595
  init_src2();
217510
217596
  init_chat_broadcast();
@@ -217526,6 +217612,7 @@ var init_server3 = __esm({
217526
217612
  defaultResolveActor = (token2) => token2.startsWith("token:") ? token2.slice("token:".length) : null;
217527
217613
  enc = (s2) => new TextEncoder().encode(s2);
217528
217614
  APPEND_TURN_START_WAIT_MS = 1e4;
217615
+ STOP_TURN_START_WAIT_MS = 5e3;
217529
217616
  STREAMING_PATHS = ["/api/events", "/api/chat", "/api/trajectory/events", "/api/intervention/wait"];
217530
217617
  PLANNER_BLOCKING_CODES = /* @__PURE__ */ new Set([
217531
217618
  "title_collision",
@@ -230730,6 +230817,8 @@ var init_daemon_hub = __esm({
230730
230817
  frameWatermark = /* @__PURE__ */ new Map();
230731
230818
  /** 每 dispatch 上次回 ackSeq 的时刻——把流式期间的回执节流到 ~250ms 一次。 */
230732
230819
  lastAckSeqAt = /* @__PURE__ */ new Map();
230820
+ /** 收尾后那 60 秒延迟清理的定时器(换机器重派时要撤掉,否则会在新会话跑到一半时把它的帧号状态清掉)。 */
230821
+ frameCleanupTimers = /* @__PURE__ */ new Map();
230733
230822
  /**
230734
230823
  * 「这次派发归谁管、现在什么状态」的认领口。**必须由 hub 汇总,不能各 adapter 自己判**——
230735
230824
  * serve 里同时有两个 DaemonHubAdapter(chat 一个、dispatch 一个),一次派发只属于其中一个。
@@ -231084,14 +231173,36 @@ var init_daemon_hub = __esm({
231084
231173
  this.lastAckSeqAt.set(dispatchId, now);
231085
231174
  ws.send(JSON.stringify({ type: "ack", dispatchId, ackSeq: this.frameWatermark.get(dispatchId) ?? 0 }));
231086
231175
  }
231176
+ /**
231177
+ * 同一把派发键**换了一台机器重派**(Bug 0279 的换候选重试)时,清掉这把键的帧号状态。
231178
+ *
231179
+ * 帧号是按会话进程编的:新机器上的新进程从 1 重新编。不清的话,上一个进程留下的水位(收尾后还要
231180
+ * 保留 60 秒)会把新进程的帧**全部当成重复帧丢掉**,连收尾帧都到不了,这一轮就一直挂着
231181
+ * (2026-09-29 v2 run chat-run:d27ff875:第二台 1.3 秒就退出了,服务端一帧都没收到)。
231182
+ * 旧进程这时已经退出或被判死;它若还有迟到的帧,由认领那一步按机器对不上直接驱逐。
231183
+ */
231184
+ resetSessionFrameState(dispatchId) {
231185
+ const pending = this.frameCleanupTimers.get(dispatchId);
231186
+ if (pending) {
231187
+ clearTimeout(pending);
231188
+ this.frameCleanupTimers.delete(dispatchId);
231189
+ }
231190
+ this.frameSeqSupported.delete(dispatchId);
231191
+ this.frameWatermark.delete(dispatchId);
231192
+ this.lastAckSeqAt.delete(dispatchId);
231193
+ }
231087
231194
  /** `session_exited` 后延迟清帧号状态:给重连重放的收尾帧留一个去重窗口,之后回收避免无界增长。 */
231088
231195
  scheduleFrameStateCleanup(dispatchId) {
231196
+ const prior = this.frameCleanupTimers.get(dispatchId);
231197
+ if (prior) clearTimeout(prior);
231089
231198
  const t = setTimeout(() => {
231199
+ this.frameCleanupTimers.delete(dispatchId);
231090
231200
  this.frameSeqSupported.delete(dispatchId);
231091
231201
  this.frameWatermark.delete(dispatchId);
231092
231202
  this.lastAckSeqAt.delete(dispatchId);
231093
231203
  }, 6e4);
231094
231204
  t.unref?.();
231205
+ this.frameCleanupTimers.set(dispatchId, t);
231095
231206
  }
231096
231207
  /**
231097
231208
  * 注册一个认领判断。返回:
@@ -238077,10 +238188,10 @@ function stepRef(nodeId, title) {
238077
238188
  return token("s", nodeId ?? "", title);
238078
238189
  }
238079
238190
  function actorRef2(actorId, name) {
238080
- return actorId ? token("a", actorId, name) : clean(name);
238191
+ return actorId ? token("a", actorId, name) : withAt(clean(name));
238081
238192
  }
238082
238193
  function mentionRef(actorId, name) {
238083
- return actorId ? token("m", actorId, name) : `@${clean(name)}`;
238194
+ return actorId ? token("m", actorId, name) : withAt(clean(name));
238084
238195
  }
238085
238196
  function tokenize(s2) {
238086
238197
  const out = [];
@@ -238124,9 +238235,9 @@ function sentenceSegments(s2) {
238124
238235
  return out;
238125
238236
  }
238126
238237
  function plainSentence(s2) {
238127
- return tokenize(s2).map((t) => typeof t === "string" ? t : t.kind === "s" ? `\u300C${t.name}\u300D` : t.kind === "m" ? `@${t.name}` : t.name).join("");
238238
+ return tokenize(s2).map((t) => typeof t === "string" ? t : t.kind === "s" ? `\u300C${t.name}\u300D` : withAt(t.name)).join("");
238128
238239
  }
238129
- var OPEN2, SEP, CLOSE2, MARKS, clean, token;
238240
+ var OPEN2, SEP, CLOSE2, MARKS, clean, withAt, token, plainActor;
238130
238241
  var init_activity_text = __esm({
238131
238242
  "../server/src/domains/collab/activity-text.ts"() {
238132
238243
  "use strict";
@@ -238135,7 +238246,9 @@ var init_activity_text = __esm({
238135
238246
  CLOSE2 = "\uE002";
238136
238247
  MARKS = /[-]/g;
238137
238248
  clean = (s2) => s2.replace(MARKS, "");
238249
+ withAt = (name) => name.startsWith("@") ? name : `@${name}`;
238138
238250
  token = (kind, id, name) => `${OPEN2}${kind}${SEP}${clean(id)}${SEP}${clean(name)}${CLOSE2}`;
238251
+ plainActor = (name) => withAt(clean(name));
238139
238252
  }
238140
238253
  });
238141
238254
 
@@ -238608,7 +238721,7 @@ function buildWorkorderActivity(input) {
238608
238721
  const managerId = resolveWorkorderManager(snap);
238609
238722
  const ownerId = snap.workorder.ownerActorId;
238610
238723
  const nameOf2 = (id) => id ? ref2(id).name ?? id : "\u2014";
238611
- const personOf = (id) => actorRef2(id ?? void 0, nameOf2(id));
238724
+ const personOf = (id) => id ? actorRef2(id, nameOf2(id)) : nameOf2(id);
238612
238725
  const mentionOf = (id) => mentionRef(id ?? void 0, nameOf2(id));
238613
238726
  const managerName = () => personOf(managerId);
238614
238727
  const nodeTitleOf = (nodeId) => {
@@ -240874,7 +240987,10 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
240874
240987
  ...extra?.avatar ? { avatar: extra.avatar } : {}
240875
240988
  };
240876
240989
  };
240877
- const actorName = (id) => resolveActor?.(id)?.name ?? "";
240990
+ const atName = (id) => {
240991
+ const name = resolveActor?.(id)?.name;
240992
+ return name ? plainActor(name) : "";
240993
+ };
240878
240994
  const nowMs = nowIso ? Date.parse(nowIso) : Number.NaN;
240879
240995
  const overdueSince = (sinceIso) => {
240880
240996
  if (slaMs === void 0 || !Number.isFinite(nowMs) || !sinceIso) return void 0;
@@ -241011,7 +241127,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241011
241127
  // 续跑申请的入口在任务动态那张续跑申请卡上(卡 id = 申请 id,见 activity.ts `continuationCards`)。
241012
241128
  ...r.continuation ? { activityCardId: r.continuation.requestId } : {},
241013
241129
  ...anchorArt ? { title: nodeLabel(anchorArt) } : {},
241014
- detail: `${actorName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command ? commandCardLine(r.command) : firstSentence3(r.plan.reason)}`,
241130
+ detail: `${atName(r.proposedBy) || "\u7BA1\u7406\u8005"}\uFF1A${r.command ? commandCardLine(r.command) : firstSentence3(r.plan.reason)}`,
241015
241131
  ...r.kind !== "command" && opCount > 0 ? { impact: `\u6D89\u53CA ${opCount} \u5904\u6539\u52A8${r.nonMonotonicOps.length > 0 ? " \xB7 \u542B\u9500\u6BC1\u6027" : ""}` } : {},
241016
241132
  actor: actorRef3(r.proposedBy),
241017
241133
  ...overdueField(r.at)
@@ -241052,7 +241168,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241052
241168
  actionRequired: true,
241053
241169
  summary: `\u6709\u4EBA\u5728\u300C${label2}\u300D\u7684\u4FE1\u91CC @ \u4E86\u4F60\uFF0C\u7B49\u4F60\u56DE\u8BDD\uFF1A${(lastPost?.body ?? an.body).slice(0, 100)}`,
241054
241170
  title: label2,
241055
- detail: `${(lastPost ? actorName(lastPost.author) : "") || "\u6709\u4EBA"} @ \u4E86\u4F60\uFF1A${firstSentence3(lastPost?.body ?? an.body)}`,
241171
+ detail: `${(lastPost ? atName(lastPost.author) : "") || "\u6709\u4EBA"} @ \u4E86\u4F60\uFF1A${firstSentence3(lastPost?.body ?? an.body)}`,
241056
241172
  ...lastPost ? { actor: actorRef3(lastPost.author) } : {},
241057
241173
  ...overdueField(an.createdAt)
241058
241174
  });
@@ -241077,7 +241193,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241077
241193
  actionRequired: false,
241078
241194
  summary: `\u4F60\u7684\u4FE1\u6709\u65B0\u52A8\u9759\uFF08${phrase}\uFF09\u300C${nodeLabel(a)}\u300D\uFF1A${lastNote.slice(0, 100)}\u2014\u2014\u4E0D\u8BA4\u53EF\u53EF\u5728\u4FE1\u4E2D\u56DE\u5E16`,
241079
241195
  title: nodeLabel(a),
241080
- detail: `${actorName(activity.by) || "\u5BF9\u65B9"} \u56DE\u5E94\u4E86\u4F60\u7684\u4FE1\uFF1A${firstSentence3(lastNote)}`,
241196
+ detail: `${atName(activity.by) || "\u5BF9\u65B9"} \u56DE\u5E94\u4E86\u4F60\u7684\u4FE1\uFF1A${firstSentence3(lastNote)}`,
241081
241197
  actor: actorRef3(activity.by)
241082
241198
  // 通知型不判 overdue(诊断明说),不设 overdue 字段。
241083
241199
  });
@@ -241097,7 +241213,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241097
241213
  actionRequired: true,
241098
241214
  summary: `\u5F85\u4F60\u9A8C\u6536\uFF1A${label2}\uFF08${pendingHead.id}\uFF09\u2014\u2014\u8BE5\u7248\u7B54\u590D\u4E86\u4F60\u7684\u4FE1`,
241099
241215
  title: label2,
241100
- detail: `${actorName(pendingHead.author) || "agent"} \u4EA4\u4E86\u65B0\u7248\u7B54\u590D\u4F60\u7684\u4FE1\uFF1A${firstSentence3(pendingHead.reason)}`,
241216
+ detail: `${atName(pendingHead.author) || "agent"} \u4EA4\u4E86\u65B0\u7248\u7B54\u590D\u4F60\u7684\u4FE1\uFF1A${firstSentence3(pendingHead.reason)}`,
241101
241217
  actor: actorRef3(pendingHead.author),
241102
241218
  ...overdueField(pendingHead.createdAt)
241103
241219
  });
@@ -241124,7 +241240,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241124
241240
  actionRequired: true,
241125
241241
  summary: `\u5F85\u4F60\u5BA1\u6279\uFF1A${label2}`,
241126
241242
  title: label2,
241127
- ...gp ? { detail: `${actorName(gp.headAuthor) || "\u4F5C\u8005"} \u4EA4\u4E86\u65B0\u7248\uFF1A${firstSentence3(headReason)}`, actor: actorRef3(gp.headAuthor) } : {},
241243
+ ...gp ? { detail: `${atName(gp.headAuthor) || "\u4F5C\u8005"} \u4EA4\u4E86\u65B0\u7248\uFF1A${firstSentence3(headReason)}`, actor: actorRef3(gp.headAuthor) } : {},
241128
241244
  ...impactParts.length > 0 ? { impact: impactParts.join(" \xB7 ") } : {},
241129
241245
  ...overdueField(gate.at)
241130
241246
  });
@@ -241147,7 +241263,7 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
241147
241263
  actionRequired: true,
241148
241264
  summary: `\u4EA7\u51FA\u88AB\u6253\u56DE\uFF0C\u9700\u8FD4\u5DE5\uFF1A${label2}`,
241149
241265
  title: label2,
241150
- ...rejectVote ? { detail: `${actorName(rejectVote.author) || "\u8BC4\u5BA1"} \u6253\u56DE\uFF1A${firstSentence3(rejectVote.note ?? "\u89C1\u8BC4\u5BA1\u610F\u89C1")}`, actor: actorRef3(rejectVote.author) } : {},
241266
+ ...rejectVote ? { detail: `${atName(rejectVote.author) || "\u8BC4\u5BA1"} \u6253\u56DE\uFF1A${firstSentence3(rejectVote.note ?? "\u89C1\u8BC4\u5BA1\u610F\u89C1")}`, actor: actorRef3(rejectVote.author) } : {},
241151
241267
  ...reworkDs > 0 ? { impact: `\u6321\u7740\u4E0B\u6E38 ${reworkDs} \u4E2A\u8282\u70B9` } : {},
241152
241268
  ...overdueField(latest.createdAt)
241153
241269
  });
@@ -241267,6 +241383,7 @@ var init_inbox = __esm({
241267
241383
  init_src8();
241268
241384
  init_src();
241269
241385
  init_node_state();
241386
+ init_activity_text();
241270
241387
  C_ACTION_LABEL = {
241271
241388
  unlink: "\u65AD\u5F00\u4F9D\u8D56\u8FB9",
241272
241389
  pin: "\u6539\u9489\u7248\u672C",
@@ -247579,11 +247696,12 @@ function nodesDomain(deps) {
247579
247696
  ...typeof r.presentOnMachine === "boolean" ? { presentOnMachine: r.presentOnMachine } : {}
247580
247697
  };
247581
247698
  }
247582
- function revokeNodeAccess(nodeId) {
247699
+ function revokeNodeAccess(nodeId, opts = {}) {
247700
+ const tellMachine = opts.tellMachine ?? true;
247583
247701
  const daemon = deps.getHub()?.connectedDaemons().find((d) => d.daemonId === nodeId);
247584
- daemon?.send({ type: "node_deleted", nodeId });
247702
+ if (tellMachine) daemon?.send({ type: "node_deleted", nodeId });
247585
247703
  for (const { token: token2, nodeId: nid } of deps.nodeTokens.list()) {
247586
- if (nid === nodeId) deps.nodeTokens.revoke(token2, "node-deleted");
247704
+ if (nid === nodeId) deps.nodeTokens.revoke(token2, tellMachine ? "node-deleted" : "unspecified");
247587
247705
  }
247588
247706
  daemon?.close();
247589
247707
  }
@@ -247591,9 +247709,9 @@ function nodesDomain(deps) {
247591
247709
  const restartEmptyClock = (nodeId) => {
247592
247710
  emptySince.set(nodeId, Date.now());
247593
247711
  };
247594
- async function removeNode(nodeId, releaseAs) {
247712
+ async function removeNode(nodeId, releaseAs, opts = {}) {
247595
247713
  const kinds = [...new Set((await deps.nodeStore.listRuntimes(nodeId)).map((r) => r.kind))];
247596
- revokeNodeAccess(nodeId);
247714
+ revokeNodeAccess(nodeId, opts);
247597
247715
  await deps.nodeStore.deleteNode(nodeId);
247598
247716
  emptySince.delete(nodeId);
247599
247717
  const released = [];
@@ -247630,13 +247748,25 @@ function nodesDomain(deps) {
247630
247748
  if (removed.length > 0) deps.onStatusChange?.();
247631
247749
  return removed;
247632
247750
  }
247751
+ async function purgeUnownedNodes() {
247752
+ const removed = [];
247753
+ for (const n of await deps.nodeStore.listUnownedNodes()) {
247754
+ const current = await deps.nodeStore.getNode(n.id);
247755
+ if (!current || current.companyId) continue;
247756
+ await removeNode(n.id, void 0, { tellMachine: false });
247757
+ removed.push(n.id);
247758
+ console.log(`[nodes] \u4F5C\u5E9F\u6CA1\u6709\u5F52\u5C5E\u516C\u53F8\u7684\u8282\u70B9\uFF1A${n.id}\uFF08\u4E3B\u673A\u540D ${n.hostname}${n.name ? `\uFF0C\u540D\u79F0 ${n.name}` : ""}\uFF0C\u72B6\u6001 ${n.status}\uFF09\u2014\u2014\u5DF2\u64A4\u51ED\u8BC1\u3001\u65AD\u5F00\u8FDE\u63A5\u3001\u5220\u9664\u8BB0\u5F55\uFF0C\u673A\u5668\u672C\u5730\u4E0D\u52A8\uFF1B\u91CD\u65B0\u8FD0\u884C\u63A5\u5165\u547D\u4EE4\u5373\u6309\u65B0\u673A\u5668\u63A5\u5165`);
247759
+ }
247760
+ if (removed.length > 0) deps.onStatusChange?.();
247761
+ return removed;
247762
+ }
247633
247763
  if (deps.emptyNodeSweep) {
247634
247764
  const { graceMs, intervalMs } = deps.emptyNodeSweep;
247635
247765
  let sweeping = false;
247636
247766
  const timer = setInterval(() => {
247637
247767
  if (sweeping) return;
247638
247768
  sweeping = true;
247639
- void sweepEmptyNodes(graceMs).catch((err) => console.warn(`[nodes] \u7A7A\u8282\u70B9\u6E05\u626B\u5931\u8D25\uFF08\u4E0B\u4E00\u62CD\u518D\u8BD5\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}`)).finally(() => {
247769
+ void purgeUnownedNodes().then(() => sweepEmptyNodes(graceMs)).catch((err) => console.warn(`[nodes] \u7A7A\u8282\u70B9\u6E05\u626B\u5931\u8D25\uFF08\u4E0B\u4E00\u62CD\u518D\u8BD5\uFF09\uFF1A${err instanceof Error ? err.message : String(err)}`)).finally(() => {
247640
247770
  sweeping = false;
247641
247771
  });
247642
247772
  }, intervalMs);
@@ -248143,6 +248273,12 @@ function nodesDomain(deps) {
248143
248273
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
248144
248274
  }
248145
248275
  const existingNode = await deps.nodeStore.getNode(nodeId);
248276
+ if (existingNode && !existingNode.companyId && entry.companyId) {
248277
+ return {
248278
+ status: 409,
248279
+ body: { error: "NODE_UNOWNED", message: "\u8FD9\u53F0\u673A\u5668\u5728\u7CFB\u7EDF\u91CC\u7684\u65E7\u8BB0\u5F55\u6CA1\u6709\u5F52\u5C5E\u516C\u53F8\uFF0C\u4E0D\u80FD\u88AB\u63A5\u5165\uFF1B\u7CFB\u7EDF\u4F1A\u5728\u7EA6\u4E00\u5206\u949F\u5185\u6E05\u6389\u8FD9\u6761\u65E7\u8BB0\u5F55\uFF0C\u4E4B\u540E\u91CD\u65B0\u8FD0\u884C\u63A5\u5165\u547D\u4EE4\u5373\u53EF\u6309\u65B0\u673A\u5668\u63A5\u5165" }
248280
+ };
248281
+ }
248146
248282
  if (existingNode?.companyId && entry.companyId && existingNode.companyId !== entry.companyId) {
248147
248283
  return { status: 409, body: { error: "\u8BE5\u8282\u70B9\u65E0\u6CD5\u7528\u5F53\u524D\u5165\u7F51\u4EE4\u724C\u63A5\u7BA1" } };
248148
248284
  }
@@ -249152,6 +249288,9 @@ var init_node_store = __esm({
249152
249288
  const live = [...this.nodes.values()].filter((n) => n.status !== "deleted");
249153
249289
  return filter?.companyId === void 0 ? live : live.filter((n) => n.companyId === filter.companyId);
249154
249290
  }
249291
+ async listUnownedNodes() {
249292
+ return [...this.nodes.values()].filter((n) => !n.companyId);
249293
+ }
249155
249294
  async listRuntimes(nodeId, filter) {
249156
249295
  let all2 = [...this.runtimes.values()];
249157
249296
  if (nodeId) all2 = all2.filter((r) => r.nodeId === nodeId);
@@ -253324,11 +253463,12 @@ function missingNodeFacts(body2) {
253324
253463
  }
253325
253464
  function renderEscalationOpeningBody(facts) {
253326
253465
  const body2 = facts.body.trim();
253466
+ const who = facts.actorName ? plainActor(facts.actorName) : void 0;
253327
253467
  if (facts.kind === "reviewer_unavailable") {
253328
253468
  const { reviewerId, role } = reviewerUnavailableFacts(body2);
253329
253469
  if (!reviewerId) return body2;
253330
253470
  return [
253331
- `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D\u9501\u5B9A\u7684\u5BA1\u6838\u4EBA${facts.actorName ? ` ${facts.actorName}` : ""}\uFF08${role} \u89D2\u8272\uFF09\u73B0\u5728\u4E0D\u53EF\u7528\u2014\u2014\u7194\u65AD\u3001\u79BB\u5C97\uFF0C\u6216\u8005\u5DF2\u88AB\u79FB\u51FA\u8FD9\u4E2A\u89D2\u8272\u2014\u2014\u8FD9\u4E00\u6B65\u7684\u8BC4\u5BA1\u6D3E\u4E0D\u51FA\u53BB\u3002`,
253471
+ `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D\u9501\u5B9A\u7684\u5BA1\u6838\u4EBA${who ? ` ${who}` : ""}\uFF08${role} \u89D2\u8272\uFF09\u73B0\u5728\u4E0D\u53EF\u7528\u2014\u2014\u7194\u65AD\u3001\u79BB\u5C97\uFF0C\u6216\u8005\u5DF2\u88AB\u79FB\u51FA\u8FD9\u4E2A\u89D2\u8272\u2014\u2014\u8FD9\u4E00\u6B65\u7684\u8BC4\u5BA1\u6D3E\u4E0D\u51FA\u53BB\u3002`,
253332
253472
  "\u9700\u8981\u4F60\u5B9A\u4E00\u4E0B\uFF1A\u6362\u4E00\u4E2A\u5BA1\u6838\u4EBA\uFF0C\u8FD8\u662F\u7B49\u539F\u5BA1\u6838\u4EBA\u6062\u590D\u3002"
253333
253473
  ].join("\n\n");
253334
253474
  }
@@ -253336,7 +253476,7 @@ function renderEscalationOpeningBody(facts) {
253336
253476
  const { gone, runtimeNode } = missingNodeFacts(body2);
253337
253477
  if (!runtimeNode) return body2;
253338
253478
  return [
253339
- `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D\u8FD8\u6CA1\u6709\u542F\u52A8\uFF1A${facts.actorName ?? "\u6267\u884C\u4EBA"}\u7ED1\u5B9A\u7684\u8FD0\u884C\u8282\u70B9 ${runtimeNode} ${gone === "\u672A\u6CE8\u518C" ? "\u6CA1\u6709\u6CE8\u518C\u8FC7" : "\u5DF2\u7ECF\u88AB\u5220\u9664"}\uFF0C\u6D3E\u4E0D\u51FA\u53BB\u3002\u8FD9\u6B21\u68C0\u67E5\u6CA1\u6709\u7EC8\u6B62\u4EFB\u4F55\u4F1A\u8BDD\uFF0C\u4E5F\u6CA1\u6709\u6D88\u8017\u91CD\u8BD5\u6B21\u6570\u3002`,
253479
+ `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D\u8FD8\u6CA1\u6709\u542F\u52A8\uFF1A${who ?? "\u6267\u884C\u4EBA"}\u7ED1\u5B9A\u7684\u8FD0\u884C\u8282\u70B9 ${runtimeNode} ${gone === "\u672A\u6CE8\u518C" ? "\u6CA1\u6709\u6CE8\u518C\u8FC7" : "\u5DF2\u7ECF\u88AB\u5220\u9664"}\uFF0C\u6D3E\u4E0D\u51FA\u53BB\u3002\u8FD9\u6B21\u68C0\u67E5\u6CA1\u6709\u7EC8\u6B62\u4EFB\u4F55\u4F1A\u8BDD\uFF0C\u4E5F\u6CA1\u6709\u6D88\u8017\u91CD\u8BD5\u6B21\u6570\u3002`,
253340
253480
  "\u9700\u8981\u4F60\u6062\u590D\u90A3\u53F0\u8282\u70B9\uFF0C\u6216\u8005\u7ED9\u6267\u884C\u4EBA\u6539\u7ED1\u4E00\u53F0\u5728\u7EBF\u7684\u8282\u70B9\uFF1B\u4FEE\u597D\u4E4B\u540E\u544A\u8BC9\u6211\uFF0C\u6211\u6765\u628A\u8FD9\u4E00\u6B65\u653E\u51FA\u53BB\u3002"
253341
253481
  ].join("\n\n");
253342
253482
  }
@@ -253345,7 +253485,7 @@ function renderEscalationOpeningBody(facts) {
253345
253485
  const { count: count3, lastReason } = retryFacts(body2);
253346
253486
  if (!count3) return body2;
253347
253487
  return [
253348
- `${facts.actorName ?? "\u8FD9\u4E00\u6B65\u7684\u6267\u884C\u4EBA"}${at(facts.nodeLabel)}\u8FDE\u7EED ${count3.n} \u8F6E\u90FD\u6CA1\u8DD1\u6210\uFF0C\u81EA\u52A8\u91CD\u8BD5\u5DF2\u7ECF\u7528\u5B8C\u2014\u2014\u8FD9\u4E00\u6B65\u4E0D\u4F1A\u518D\u81EA\u52A8\u91CD\u6765\u4E86\u3002`,
253488
+ `${who ?? "\u8FD9\u4E00\u6B65\u7684\u6267\u884C\u4EBA"}${at(facts.nodeLabel)}\u8FDE\u7EED ${count3.n} \u8F6E\u90FD\u6CA1\u8DD1\u6210\uFF0C\u81EA\u52A8\u91CD\u8BD5\u5DF2\u7ECF\u7528\u5B8C\u2014\u2014\u8FD9\u4E00\u6B65\u4E0D\u4F1A\u518D\u81EA\u52A8\u91CD\u6765\u4E86\u3002`,
253349
253489
  ...lastReason ? [`\u6700\u540E\u4E00\u6B21\u5931\u8D25\u8BB0\u4E0B\u7684\u539F\u56E0\uFF1A${lastReason}`] : [],
253350
253490
  "\u9700\u8981\u4F60\u5B9A\u4E00\u4E0B\u63A5\u4E0B\u6765\u600E\u4E48\u529E\uFF1A\u6309\u539F\u65B9\u6848\u518D\u8BD5\u4E00\u6B21\u3001\u6539\u4E86\u4EFB\u52A1\u8BF4\u660E\u518D\u8DD1\uFF0C\u8FD8\u662F\u6362\u4E2A\u4EBA\u505A\u3002"
253351
253491
  ].join("\n\n");
@@ -253360,7 +253500,7 @@ function renderEscalationOpeningBody(facts) {
253360
253500
  }
253361
253501
  const { count: count2, minutes, cost, remark, stalled } = stallFacts(body2);
253362
253502
  if (!count2) return body2;
253363
- const subject = stalled ? `${facts.actorName ?? (stalled === "review" ? "\u8FD9\u4E00\u6B65\u7684\u8BC4\u5BA1\u5458" : "\u8FD9\u4E00\u6B65\u7684\u6267\u884C\u4EBA")}${at(facts.nodeLabel)}` : `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D`;
253503
+ const subject = stalled ? `${who ?? (stalled === "review" ? "\u8FD9\u4E00\u6B65\u7684\u8BC4\u5BA1\u5458" : "\u8FD9\u4E00\u6B65\u7684\u6267\u884C\u4EBA")}${at(facts.nodeLabel)}` : `\u300C${facts.nodeLabel ?? "\u8FD9\u4E00\u6B65"}\u300D`;
253364
253504
  const window3 = minutes !== void 0 ? `\u6700\u8FD1 ${minutes} \u5206\u949F\u91CC` : "\u6700\u8FD1\u4E00\u6BB5\u65F6\u95F4\u91CC";
253365
253505
  const spent = cost ? `\uFF08\u8FD9\u4E9B\u7A7A\u8DD1\u5408\u8BA1\u5DF2\u7ECF\u82B1\u6389\u7EA6 ${cost}\uFF09` : "";
253366
253506
  const each = count2.unit === "\u8F6E" ? "\u6BCF\u4E00\u8F6E" : "\u6BCF\u4E00\u6B21";
@@ -253376,6 +253516,7 @@ var num3, at;
253376
253516
  var init_escalation_opening_body = __esm({
253377
253517
  "../server/src/domains/collab/escalation-opening-body.ts"() {
253378
253518
  "use strict";
253519
+ init_activity_text();
253379
253520
  num3 = (v2) => {
253380
253521
  if (v2 === void 0) return void 0;
253381
253522
  const n = Number(v2);
@@ -259448,7 +259589,7 @@ var init_daemon_adapter = __esm({
259448
259589
  appendWaiters: []
259449
259590
  };
259450
259591
  this.pending.set(dispatchId, entry);
259451
- this.settledDispatchIds.delete(dispatchId);
259592
+ if (this.settledDispatchIds.delete(dispatchId)) this.hub.resetSessionFrameState?.(dispatchId);
259452
259593
  const sessionAuth = this.sessionAuth ? { ...this.sessionAuth.issue({ nodeId, dispatchId }), gatewayUrl: this.sessionAuth.gatewayUrl } : void 0;
259453
259594
  let sent;
259454
259595
  try {
@@ -272034,6 +272175,10 @@ var init_postgres_nodes = __esm({
272034
272175
  const r = filter?.companyId !== void 0 ? await this.pool.query(`SELECT * FROM ${this.s}.nodes WHERE status <> 'deleted' AND company_id = $1 ORDER BY enrolled_at ASC`, [filter.companyId]) : await this.pool.query(`SELECT * FROM ${this.s}.nodes WHERE status <> 'deleted' ORDER BY enrolled_at ASC`);
272035
272176
  return r.rows.map(rowToNode);
272036
272177
  }
272178
+ async listUnownedNodes() {
272179
+ const r = await this.pool.query(`SELECT * FROM ${this.s}.nodes WHERE company_id IS NULL ORDER BY enrolled_at ASC`);
272180
+ return r.rows.map(rowToNode);
272181
+ }
272037
272182
  async listRuntimes(nodeId, filter) {
272038
272183
  const where = [];
272039
272184
  const params = [];
@@ -289503,7 +289648,7 @@ async function startServe(opts) {
289503
289648
  if (isDeletedActor(dispatchTarget)) {
289504
289649
  throw new ApiError(409, ACTOR_DELETED_ERROR_CODE, ACTOR_DELETED_CHAT_MESSAGE);
289505
289650
  }
289506
- const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(`chat-runtime:${requestDispatchId}`) : (0, import_node_crypto92.randomUUID)());
289651
+ const runtimeSessionId = sessionId ?? (requestDispatchId ? deterministicUuid(retargetClaimedDispatch ? `chat-runtime:${requestDispatchId}:retry:${(0, import_node_crypto92.randomUUID)()}` : `chat-runtime:${requestDispatchId}`) : (0, import_node_crypto92.randomUUID)());
289507
289652
  const resumeRuntimeSession = Boolean(sessionId);
289508
289653
  const traceRunId = requestDispatchId ? stableChatTraceRunId(requestDispatchId) : `chat-run:${(0, import_node_crypto92.randomUUID)()}`;
289509
289654
  const artifactId = requestDispatchId ? `artifact:chat:${deterministicUuid(`chat-artifact:${requestDispatchId}`)}` : `artifact:chat:${(0, import_node_crypto92.randomUUID)()}`;
@@ -289722,8 +289867,12 @@ async function startServe(opts) {
289722
289867
  旧机器那次失败的原文仍留在事件流里,也记进了故障标记与失败链。 */
289723
289868
  exitReason: null,
289724
289869
  errorMessage: null,
289870
+ // 这一次是新的一场 runtime 会话(见上面 runtimeSessionId),账本里的会话号跟着换。
289871
+ triggerRef: runtimeSessionId,
289872
+ jobKey: runtimeSessionId,
289725
289873
  metadata: {
289726
289874
  ...prior.metadata ?? {},
289875
+ runtimeSessionId,
289727
289876
  nodeId: binding.nodeId,
289728
289877
  runtimeKind: binding.runtimeKind,
289729
289878
  runtimeTargetSource: "session_override"
@@ -298211,7 +298360,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
298211
298360
  }
298212
298361
  }
298213
298362
  }
298214
- var CLI_VERSION = "2.2.97" ? "2.2.97" : "dev";
298363
+ var CLI_VERSION = "2.2.99" ? "2.2.99" : "dev";
298215
298364
  function apiHeaders(token2, company) {
298216
298365
  const headers = {
298217
298366
  authorization: `Bearer ${token2}`,
@@ -302182,7 +302331,7 @@ function shimScript() {
302182
302331
  }
302183
302332
 
302184
302333
  // src/index.ts
302185
- var PKG_VERSION = true ? "2.2.97" : "dev";
302334
+ var PKG_VERSION = true ? "2.2.99" : "dev";
302186
302335
  var LOCAL_BIN = localBin();
302187
302336
  var NPM_PREFIX = npmPrefix();
302188
302337
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.97",
3
+ "version": "2.2.99",
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": "b58602b3836acf502fd5bfc644949eb355440ae0"
29
+ "sourceHead": "705a5a2b945e6e24cd1ddefef8d0e6e148574808"
30
30
  }
31
31
  }