@clawos-dev/clawd 0.2.197-beta.396.cf8bb30 → 0.2.198-beta.397.035eade

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/cli.cjs CHANGED
@@ -42956,9 +42956,6 @@ var SessionManager = class {
42956
42956
  // 由 observer 监听 jsonl user 行后调 recordRealUserUuid 建立映射;rewind 系列 RPC 在
42957
42957
  // 入参 / 出参做转译,保证 UI 看到的 uuid 始终是 events 流里的 synth uuid
42958
42958
  realUuidBySynth = /* @__PURE__ */ new Map();
42959
- // observeScreenIdle 复合条件闸用:sessionId → observer 上次喂出业务事件的时刻(deps.now())。
42960
- // observerIdleWaitMs 据此判 observer 是否也静止 ≥ idleMs(屏幕静止 AND observer 静止才补 turn_end)。
42961
- lastObserverEventAt = /* @__PURE__ */ new Map();
42962
42959
  // SessionStore 按 scope 派生(root = <dataDir>/sessions/<scopeSubPath>/)。
42963
42960
  // default scope 直接复用 deps.store;persona scope(owner / listener)第一次访问时按需创建并缓存。
42964
42961
  // 取代旧的 storesByAgent —— agentId 概念由 SessionScope 取代,路径即身份,
@@ -43579,7 +43576,6 @@ var SessionManager = class {
43579
43576
  this.runners.delete(args.sessionId);
43580
43577
  this.realUuidBySynth.delete(args.sessionId);
43581
43578
  this.lastUiSizeBySessionId.delete(args.sessionId);
43582
- this.lastObserverEventAt.delete(args.sessionId);
43583
43579
  return { response: { sessionId: args.sessionId }, broadcast };
43584
43580
  }
43585
43581
  this.deleteOwned(args.sessionId);
@@ -44058,7 +44054,6 @@ var SessionManager = class {
44058
44054
  this.runners.delete(args.sessionId);
44059
44055
  this.realUuidBySynth.delete(args.sessionId);
44060
44056
  this.lastUiSizeBySessionId.delete(args.sessionId);
44061
- this.lastObserverEventAt.delete(args.sessionId);
44062
44057
  return { response: { sessionId: args.sessionId }, broadcast };
44063
44058
  }
44064
44059
  this.storeFor(args.scope).delete(args.sessionId);
@@ -44304,7 +44299,6 @@ var SessionManager = class {
44304
44299
  return;
44305
44300
  }
44306
44301
  }
44307
- this.lastObserverEventAt.set(sessionId, (this.deps.now ?? Date.now)());
44308
44302
  let feedEvents = outEvents;
44309
44303
  if (outEvents.some((e) => e.kind === "turn_end")) {
44310
44304
  const runnerState = runner.getState();
@@ -44331,27 +44325,10 @@ var SessionManager = class {
44331
44325
  });
44332
44326
  feedEvents = outEvents.filter((e) => e.kind !== "turn_end");
44333
44327
  } else {
44334
- const ev = this.peekTurnEvidence(runner);
44335
- if (!ev.turnHasContent) {
44336
- this.deps.logger?.info("drop turn_end (empty turn, observer replay)", {
44337
- sessionId,
44338
- ...ev,
44339
- batchKinds: outEvents.map((e) => e.kind)
44340
- });
44341
- this.deps.screenIdleProbeLogger?.info("drop turn_end: empty turn (Fix B)", {
44342
- sessionId,
44343
- toolSessionId,
44344
- ...ev,
44345
- batchKinds: outEvents.map((e) => e.kind)
44346
- });
44347
- feedEvents = outEvents.filter((e) => e.kind !== "turn_end");
44348
- } else {
44349
- this.deps.screenIdleProbeLogger?.info("turn_end passed all filters \u2192 fed to reducer", {
44350
- sessionId,
44351
- toolSessionId,
44352
- ...ev
44353
- });
44354
- }
44328
+ this.deps.screenIdleProbeLogger?.info("turn_end passed gate \u2192 fed to reducer", {
44329
+ sessionId,
44330
+ toolSessionId
44331
+ });
44355
44332
  }
44356
44333
  }
44357
44334
  if (feedEvents.length === 0) return;
@@ -44615,87 +44592,6 @@ var SessionManager = class {
44615
44592
  if (!runner) return;
44616
44593
  runner.input({ kind: "ready-detected" });
44617
44594
  }
44618
- /**
44619
- * ClaudeTuiAdapter onTurnIdle callback:屏幕内容静止时**复发**本轮已出现过的权威 turn_end。
44620
- * 本意:turn_duration 写盘早于尾段正文 → observer 把尾随 text 推进 buffer 盖掉 lastEventKind →
44621
- * spinner 不熄;屏幕静止时再补一条 turn_end 排到尾随 text 之后。
44622
- *
44623
- * Fix A(修 bug1 "UI 还在变却显示结束" / bug2 "发消息后无 spinner"):补偿**只复发不 originate**——
44624
- * 仅当本轮已出现过 turn_end(turnEndSeenThisTurn,即真有过尾随 text 覆盖场景)才补。turnEndSeenThisTurn
44625
- * ===false 说明本轮 CC 从未结束过(仍在工作 / 刚发消息没产出 / 漏检弹框等用户),屏幕静止 ≠ turn 结束,
44626
- * 凭空 inject turn_end 会误灭 spinner——故跳过,让真正的 turn_duration 来时再正常收。
44627
- * 仅 tui 模式;runner 缺失 noop。turn_end 无 uuid 不参与 dedup。
44628
- */
44629
- dispatchTurnIdle(toolSessionId) {
44630
- if (this.deps.mode !== "tui") return;
44631
- const sid = this.sessionIdByToolSid(toolSessionId);
44632
- const runner = sid ? this.runners.get(sid) : void 0;
44633
- if (!runner) {
44634
- this.deps.screenIdleProbeLogger?.warn("dispatchTurnIdle: no runner for toolSessionId", {
44635
- toolSessionId
44636
- });
44637
- return;
44638
- }
44639
- const ev = this.peekTurnEvidence(runner);
44640
- if (!ev.turnEndSeenThisTurn) {
44641
- this.deps.logger?.debug("screen-idle compensation skipped (no prior turn_end this turn)", {
44642
- sessionId: sid,
44643
- ...ev
44644
- });
44645
- this.deps.screenIdleProbeLogger?.info("dispatchTurnIdle skip: no prior turn_end this turn", {
44646
- sessionId: sid,
44647
- toolSessionId,
44648
- ...ev
44649
- });
44650
- return;
44651
- }
44652
- this.deps.screenIdleProbeLogger?.info("dispatchTurnIdle inject turn_end (screen-idle compensation)", {
44653
- sessionId: sid,
44654
- toolSessionId,
44655
- ...ev
44656
- });
44657
- runner.input({ kind: "inject-events", events: [{ kind: "turn_end" }] });
44658
- }
44659
- /**
44660
- * 读 runner 当前 turn 态快照,供 turn_end 判定使用:
44661
- * `turnEndSeenThisTurn`:从 buffer 末尾回扫到最近 user_text 期间是否已出现过 turn_end
44662
- * (已出现=本轮真结束过、合法尾随;未出现=本轮还没结束过)→ 屏幕静止补偿的复发闸
44663
- * (`dispatchTurnIdle`)。
44664
- * `turnHasContent`:末条是否 assistant 产出(非 user_text/turn_end/空)→ observer 回灌
44665
- * turn_end 的空 turn 守卫闸(`feedObserverEvents`)。
44666
- * 权威 gate(TUI 屏幕是否 idle + 弹框态)在 `adapter.canAcceptTurnEnd` 里,这两条只覆盖
44667
- * "buffer 完整性"独立维度。
44668
- */
44669
- peekTurnEvidence(runner) {
44670
- const st = runner.getState();
44671
- const buf = st.buffer;
44672
- const lastEventKindBefore = buf.length > 0 ? buf[buf.length - 1].event.kind : null;
44673
- let turnEndSeenThisTurn = false;
44674
- for (let i = buf.length - 1; i >= 0; i--) {
44675
- const k2 = buf[i].event.kind;
44676
- if (k2 === "user_text") break;
44677
- if (k2 === "turn_end") {
44678
- turnEndSeenThisTurn = true;
44679
- break;
44680
- }
44681
- }
44682
- const turnHasContent = lastEventKindBefore !== null && lastEventKindBefore !== "user_text" && lastEventKindBefore !== "turn_end";
44683
- return { turnOpenBefore: st.turnOpen, lastEventKindBefore, turnEndSeenThisTurn, turnHasContent };
44684
- }
44685
- /**
44686
- * observer 还需静止多久(ms)才满 idleMs,0 = 已满。observeScreenIdle 复合条件闸:屏幕静止后
44687
- * 精确等这段剩余再补 turn_end —— turn_duration 写盘早于尾段正文,observer 把尾随 text poll 落盘
44688
- * 期间屏幕可能已静止,仅看屏幕会早 fire(补的 turn_end 盖不到尾随 text 之后)。
44689
- * 找不到 runner / 从无事件 → 0(不阻塞 fire)。idleMs 由装配处传 SCREEN_IDLE_MS。
44690
- */
44691
- observerIdleWaitMs(toolSessionId, idleMs) {
44692
- const sid = this.sessionIdByToolSid(toolSessionId);
44693
- if (!sid) return 0;
44694
- const last = this.lastObserverEventAt.get(sid);
44695
- if (last === void 0) return 0;
44696
- const elapsed = (this.deps.now ?? Date.now)() - last;
44697
- return Math.max(0, idleMs - elapsed);
44698
- }
44699
44595
  /** toolSessionId → sessionId 反查(遍历 runners);session 数典型 < 10,O(n) 可接受 */
44700
44596
  sessionIdByToolSid(toolSessionId) {
44701
44597
  for (const [sid, runner] of this.runners) {
@@ -47312,15 +47208,13 @@ function observeScreenIdle(surface, opts) {
47312
47208
  },
47313
47209
  isIdle() {
47314
47210
  const popupVisible = opts.getPopupVisible();
47315
- const obsWait = opts.getObserverWaitMs?.() ?? 0;
47316
- const idle = armed && !popupVisible && obsWait <= 0;
47211
+ const idle = armed && !popupVisible;
47317
47212
  if (opts.probeLogger) {
47318
47213
  opts.probeLogger.info("screen-idle isIdle check", {
47319
47214
  label: opts.probeLabel,
47320
47215
  idle,
47321
47216
  armed,
47322
- popupVisible,
47323
- obsWait
47217
+ popupVisible
47324
47218
  });
47325
47219
  }
47326
47220
  return idle;
@@ -47510,14 +47404,8 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
47510
47404
  const screenIdleObserver = observeScreenIdle(surface, {
47511
47405
  idleMs: SCREEN_IDLE_MS,
47512
47406
  onIdle: () => {
47513
- if (!ctx.toolSessionId || !this.tuiOpts.onTurnIdle) return;
47514
- this.tuiLogger?.debug("screen-idle \u2192 turn_end", { toolSessionId: ctx.toolSessionId });
47515
- this.tuiOpts.onTurnIdle(ctx.toolSessionId);
47516
47407
  },
47517
47408
  getPopupVisible: () => popupObserver.visibleKind !== null,
47518
- // observer 还需静止多久才满 SCREEN_IDLE_MS(复合条件 AND):屏幕静止后精确等这段剩余再补
47519
- // turn_end,确保它排在尾段 text + turn_duration 全部 poll 落盘之后 = buffer 末条。
47520
- getObserverWaitMs: () => ctx.toolSessionId ? this.tuiOpts.getObserverWaitMs?.(ctx.toolSessionId, SCREEN_IDLE_MS) ?? 0 : 0,
47521
47409
  // 取证 probe(可选,装配处传独立 file-only logger,跟主 daemon.log 解耦)
47522
47410
  ...this.tuiOpts.screenIdleProbeLogger ? {
47523
47411
  probeLogger: this.tuiOpts.screenIdleProbeLogger,
@@ -58008,12 +57896,8 @@ async function startDaemon(config) {
58008
57896
  onSurfaceUnregister: (tsid) => manager.unregisterSurface(tsid),
58009
57897
  // ReadyGate v2:ReadyDetector emit ready 时投递 reducer 'ready-detected' input
58010
57898
  onReady: (tsid) => manager.dispatchReadyDetected(tsid),
58011
- // 屏幕静止 补权威 turn_end(修 turn_duration 尾随 text 覆盖 lastEventKind
58012
- onTurnIdle: (tsid) => manager.dispatchTurnIdle(tsid),
58013
- // 复合条件闸:observer 还需静止多久才满 idleMs(屏幕静止后精确等这段剩余再补 turn_end)
58014
- getObserverWaitMs: (tsid, idleMs) => manager.observerIdleWaitMs(tsid, idleMs),
58015
- // 取证 probe(可选,CLAWD_SCREEN_IDLE_PROBE=1 时启用;生产默认 undefined 不打)
58016
- ...screenIdleProbeLogger ? { screenIdleProbeLogger } : {}
57899
+ // 取证 probe(默认无条件启用;见 createFileOnlyLogger
57900
+ screenIdleProbeLogger
58017
57901
  }) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
58018
57902
  registerAdapter("claude", claudeAdapter);
58019
57903
  registerAdapter("codex", new CodexAdapter({ logger, historyReader: new CodexHistoryReader() }));