@clawos-dev/clawd 0.2.93-beta.175.b162fd0 → 0.2.94-beta.176.8dff088

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/cli.cjs +133 -154
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -222,11 +222,7 @@ var init_errors = __esm({
222
222
  PERMISSION_REQUEST_STALE: "PERMISSION_REQUEST_STALE",
223
223
  FILE_TOO_LARGE: "FILE_TOO_LARGE",
224
224
  INTERNAL: "INTERNAL",
225
- UNAUTHORIZED: "UNAUTHORIZED",
226
- // Ready gate:用户在 pendingSend 已存在时再次 send,daemon 拒绝(不覆盖暂存)。
227
- // UI ChatInput 应在 popup 态 disable,daemon 兜底;error 帧 broadcast 通知所有 tab。
228
- // Spec: clawd/superpowers/specs/2026-05-22-cc-ready-gate-design.md §错误处理
229
- SEND_PENDING: "SEND_PENDING"
225
+ UNAUTHORIZED: "UNAUTHORIZED"
230
226
  };
231
227
  ClawdError = class extends Error {
232
228
  constructor(code, message) {
@@ -10559,6 +10555,20 @@ function withCommonFields(msg, o) {
10559
10555
  if (typeof o.uuid === "string" && o.uuid.length > 0) msg.uuid = o.uuid;
10560
10556
  return msg;
10561
10557
  }
10558
+ function isRejectSentinelLine(obj) {
10559
+ if (!obj || typeof obj !== "object") return false;
10560
+ return typeof obj.toolUseResult === "string";
10561
+ }
10562
+ function isUserPlainTextLine(obj) {
10563
+ if (!obj || typeof obj !== "object") return false;
10564
+ const o = obj;
10565
+ if (o.type !== "user") return false;
10566
+ const message = o.message;
10567
+ const content = message?.content;
10568
+ if (!Array.isArray(content) || content.length !== 1) return false;
10569
+ const part = content[0];
10570
+ return part?.type === "text";
10571
+ }
10562
10572
  function messageFromJsonl(obj) {
10563
10573
  if (!obj || typeof obj !== "object") return null;
10564
10574
  const o = obj;
@@ -10566,6 +10576,7 @@ function messageFromJsonl(obj) {
10566
10576
  const ts = o.timestamp ?? o.ts;
10567
10577
  if (type === "user" || type === "assistant") {
10568
10578
  const message = o.message;
10579
+ if (type === "assistant" && message?.model === "<synthetic>") return null;
10569
10580
  const content = message?.content;
10570
10581
  const toolResultExtra = type === "user" ? extractToolResultExtraFromRaw(o.toolUseResult) : void 0;
10571
10582
  const sourceToolAssistantUUID = type === "user" && typeof o.sourceToolAssistantUUID === "string" ? o.sourceToolAssistantUUID : void 0;
@@ -10879,7 +10890,11 @@ var init_claude_history = __esm({
10879
10890
  );
10880
10891
  const lines = readJsonlLines(file);
10881
10892
  const messages = [];
10893
+ let prevIsRejectSentinel = false;
10882
10894
  for (const line of lines) {
10895
+ const skipInterruptedMarker = prevIsRejectSentinel && isUserPlainTextLine(line);
10896
+ prevIsRejectSentinel = isRejectSentinelLine(line);
10897
+ if (skipInterruptedMarker) continue;
10883
10898
  const msg = messageFromJsonl(line);
10884
10899
  if (msg) messages.push(msg);
10885
10900
  }
@@ -11305,6 +11320,7 @@ function parseClaudeObjectInner(obj) {
11305
11320
  }
11306
11321
  if (type === "assistant") {
11307
11322
  const message = obj.message;
11323
+ if (message?.model === "<synthetic>") return events;
11308
11324
  if (message) {
11309
11325
  const mModel = message.model;
11310
11326
  if (typeof mModel === "string" && mModel.length > 0) {
@@ -21273,9 +21289,7 @@ function cloneState(s) {
21273
21289
  freshSpawn: s.freshSpawn,
21274
21290
  procAlive: s.procAlive,
21275
21291
  seenUuids: s.seenUuids,
21276
- subSessionMeta: s.subSessionMeta,
21277
- readyForSend: s.readyForSend,
21278
- pendingSend: s.pendingSend
21292
+ subSessionMeta: s.subSessionMeta
21279
21293
  };
21280
21294
  }
21281
21295
  var IDLE_KILL_DELAY_MS = 6e4;
@@ -21510,23 +21524,6 @@ function applyCommand(state, command, deps) {
21510
21524
  effects.push({ kind: "cancel-idle-kill", sessionId });
21511
21525
  next.status = next.procAlive ? "running" : "idle";
21512
21526
  }
21513
- if (next.pendingSend) {
21514
- return {
21515
- state: next,
21516
- effects: [
21517
- ...effects,
21518
- {
21519
- kind: "emit-frame",
21520
- frame: {
21521
- type: "error",
21522
- sessionId,
21523
- code: ERROR_CODES.SEND_PENDING,
21524
- message: "a previous message is still pending; cc not yet ready"
21525
- }
21526
- }
21527
- ]
21528
- };
21529
- }
21530
21527
  if (!next.procAlive) {
21531
21528
  next.procAlive = true;
21532
21529
  next.freshSpawn = true;
@@ -21535,9 +21532,6 @@ function applyCommand(state, command, deps) {
21535
21532
  next.nextSeq = 0;
21536
21533
  next.turnOpen = false;
21537
21534
  next.status = "running";
21538
- if (deps.mode === "tui") {
21539
- next.readyForSend = false;
21540
- }
21541
21535
  effects.push({ kind: "spawn", ctx: buildSpawnContext(next, deps) });
21542
21536
  effects.push({
21543
21537
  kind: "emit-frame",
@@ -21554,15 +21548,10 @@ function applyCommand(state, command, deps) {
21554
21548
  uuid: deps.genUuid?.()
21555
21549
  };
21556
21550
  const pushed = pushEventToBuffer(next, userEvent, deps);
21557
- let nextState = pushed.state;
21558
21551
  effects.push(...pushed.effects);
21559
- if (nextState.readyForSend) {
21560
- const payload = deps.encodeStdin(command.text, { sessionId });
21561
- effects.push({ kind: "write-stdin", payload });
21562
- } else {
21563
- nextState = { ...nextState, pendingSend: { text: command.text } };
21564
- }
21565
- return { state: nextState, effects };
21552
+ const payload = deps.encodeStdin(command.text, { sessionId });
21553
+ effects.push({ kind: "write-stdin", payload });
21554
+ return { state: pushed.state, effects };
21566
21555
  }
21567
21556
  case "stop": {
21568
21557
  for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
@@ -21577,7 +21566,6 @@ function applyCommand(state, command, deps) {
21577
21566
  }
21578
21567
  next.pendingPermissions = {};
21579
21568
  next.pendingQuestions = {};
21580
- next.pendingSend = void 0;
21581
21569
  if (next.procAlive) {
21582
21570
  next.status = "stopping";
21583
21571
  effects.push({ kind: "kill", signal: "SIGKILL" });
@@ -21615,8 +21603,6 @@ function applyCommand(state, command, deps) {
21615
21603
  }
21616
21604
  next.pendingPermissions = {};
21617
21605
  next.pendingQuestions = {};
21618
- next.pendingSend = void 0;
21619
- next.readyForSend = false;
21620
21606
  if (next.procAlive) {
21621
21607
  effects.push({ kind: "kill", signal: "SIGKILL" });
21622
21608
  }
@@ -21660,7 +21646,6 @@ function applyCommand(state, command, deps) {
21660
21646
  next.pendingPermissions = {};
21661
21647
  next.freshSpawn = false;
21662
21648
  next.seenUuids = [];
21663
- next.pendingSend = void 0;
21664
21649
  effects.push({
21665
21650
  kind: "emit-frame",
21666
21651
  frame: { type: "session:cleared", sessionId }
@@ -21698,7 +21683,6 @@ function applyCommand(state, command, deps) {
21698
21683
  next.pendingPermissions = {};
21699
21684
  next.freshSpawn = false;
21700
21685
  next.seenUuids = [];
21701
- next.pendingSend = void 0;
21702
21686
  effects.push({ kind: "persist-file", file: nextFile });
21703
21687
  effects.push(sessionInfoFrame(nextFile));
21704
21688
  effects.push({
@@ -21733,8 +21717,6 @@ function reduceSession(state, input, deps) {
21733
21717
  const next = cloneState(state);
21734
21718
  next.procAlive = false;
21735
21719
  next.status = "stopped";
21736
- next.pendingSend = void 0;
21737
- next.readyForSend = false;
21738
21720
  const sessionId = next.file.sessionId;
21739
21721
  const clearedEffects = Object.keys(state.pendingQuestions ?? {}).map(
21740
21722
  (toolUseId) => ({
@@ -21766,8 +21748,6 @@ function reduceSession(state, input, deps) {
21766
21748
  case "proc-error": {
21767
21749
  const next = cloneState(state);
21768
21750
  next.status = "error";
21769
- next.pendingSend = void 0;
21770
- next.readyForSend = false;
21771
21751
  return {
21772
21752
  state: next,
21773
21753
  effects: [
@@ -21894,30 +21874,6 @@ function reduceSession(state, input, deps) {
21894
21874
  effects: [{ kind: "kill", signal: "SIGKILL" }]
21895
21875
  };
21896
21876
  }
21897
- case "ready-detected": {
21898
- if (!state.procAlive) {
21899
- return { state, effects: [] };
21900
- }
21901
- const next = cloneState(state);
21902
- next.readyForSend = true;
21903
- const flushEffects = [];
21904
- if (state.pendingSend) {
21905
- const payload = deps.encodeStdin(state.pendingSend.text, {
21906
- sessionId: next.file.sessionId
21907
- });
21908
- flushEffects.push({ kind: "write-stdin", payload });
21909
- next.pendingSend = void 0;
21910
- }
21911
- return { state: next, effects: flushEffects };
21912
- }
21913
- case "popup-detected": {
21914
- if (!state.procAlive) {
21915
- return { state, effects: [] };
21916
- }
21917
- const next = cloneState(state);
21918
- next.readyForSend = false;
21919
- return { state: next, effects: [] };
21920
- }
21921
21877
  case "inject-owner-text": {
21922
21878
  const ownerEvent = {
21923
21879
  kind: "meta-text",
@@ -22106,8 +22062,7 @@ var SessionRunner = class {
22106
22062
  resolveContextWindow: this.hooks.resolveContextWindow,
22107
22063
  genUuid: this.hooks.genUuid ?? v4_default,
22108
22064
  ownerDisplayName: this.hooks.ownerDisplayName,
22109
- personaRoot: this.hooks.personaRoot,
22110
- mode: this.hooks.mode ?? "sdk"
22065
+ personaRoot: this.hooks.personaRoot
22111
22066
  };
22112
22067
  const { state, effects } = reduceSession(this.state, inputMsg, deps);
22113
22068
  this.state = state;
@@ -22537,14 +22492,7 @@ function makeInitialState(file, subSessionMeta) {
22537
22492
  freshSpawn: false,
22538
22493
  procAlive: false,
22539
22494
  seenUuids: [],
22540
- subSessionMeta,
22541
- // Ready gate:保守起手 true,让 SDK 模式与 TUI 接线未完成时 send 仍走旧的"立即写 stdin"
22542
- // 路径不破坏 SDK 用户体验。TUI 模式 manager 集成(Task 6)会在 spawn 时显式 dispatch
22543
- // 'popup-detected' 把 flag 翻 false → 等 ReadyGate emit ready 再 dispatch 'ready-detected'
22544
- // 翻回 true 并 flush pendingSend。
22545
- // daemon-only 字段,不上 wire / 不写 SessionFile(compressFrameForWire 只处理
22546
- // session:status,SessionState 不直接序列化)。
22547
- readyForSend: true
22495
+ subSessionMeta
22548
22496
  };
22549
22497
  }
22550
22498
  var SessionManager = class {
@@ -22787,9 +22735,6 @@ var SessionManager = class {
22787
22735
  // Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
22788
22736
  // cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
22789
22737
  personaRoot: this.deps.personaRoot,
22790
- // 透传给 ReducerDeps.mode:reducer send !procAlive spawn 路径据此判断要不要把
22791
- // readyForSend 翻 false(TUI 翻 false 让 user_text 走 pendingSend 暂存;SDK 不动保持直写)
22792
- mode: this.deps.mode,
22793
22738
  // file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
22794
22739
  onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
22795
22740
  scope,
@@ -23925,9 +23870,6 @@ var SessionManager = class {
23925
23870
  },
23926
23871
  "broadcast"
23927
23872
  );
23928
- const runner = this.runners.get(sid);
23929
- if (!runner) return;
23930
- runner.input({ kind: visible ? "popup-detected" : "ready-detected" });
23931
23873
  }
23932
23874
  /** toolSessionId → sessionId 反查(遍历 runners);session 数典型 < 10,O(n) 可接受 */
23933
23875
  sessionIdByToolSid(toolSessionId) {
@@ -25212,29 +25154,6 @@ var POPUP_FOOTER_PATTERNS = [
25212
25154
  { kind: "permission", regex: /Tab to amend|Do you want to proceed/i },
25213
25155
  { kind: "question", regex: /Enter to select|↑\/↓ to navigate/i }
25214
25156
  ];
25215
- function matchPopupFooterKind(bufferText) {
25216
- for (const p2 of POPUP_FOOTER_PATTERNS) {
25217
- if (p2.regex.test(bufferText)) return p2.kind;
25218
- }
25219
- return null;
25220
- }
25221
- function hasInputFrame(bufferText) {
25222
- const lines = bufferText.split("\n");
25223
- for (let i = 1; i < lines.length; i++) {
25224
- const cur = lines[i];
25225
- if (!/^\s*❯\s/.test(cur)) continue;
25226
- const prev = lines[i - 1];
25227
- if (/─{20,}/.test(prev)) return true;
25228
- }
25229
- return false;
25230
- }
25231
- var READY_SIGNATURE_PATTERNS = [
25232
- { name: "input-frame", match: hasInputFrame }
25233
- ];
25234
- function isReadySignature(bufferText) {
25235
- if (matchPopupFooterKind(bufferText) !== null) return false;
25236
- return READY_SIGNATURE_PATTERNS.some((p2) => p2.match(bufferText));
25237
- }
25238
25157
  function createPopupDetector(opts) {
25239
25158
  const term = new Terminal({
25240
25159
  cols: opts.cols ?? 120,
@@ -25246,52 +25165,43 @@ function createPopupDetector(opts) {
25246
25165
  term.loadAddon(serializeAddon);
25247
25166
  let visible = null;
25248
25167
  let pendingClear = null;
25249
- let quietTimer = null;
25250
- const QUIET_MS = opts.quietMs ?? 300;
25251
25168
  let parseSeq = 0;
25252
25169
  let pendingParse = 0;
25253
25170
  let drainWaiters = [];
25254
25171
  let disposed = false;
25255
- const scanScreen = () => {
25172
+ const scanFooter = () => {
25256
25173
  const buf = term.buffer.active;
25257
- const lines = [];
25258
25174
  for (let i = 0; i < buf.length; i++) {
25259
25175
  const line = buf.getLine(i);
25260
25176
  if (!line) continue;
25261
- lines.push(line.translateToString(true));
25177
+ const text = line.translateToString(true);
25178
+ if (!text) continue;
25179
+ for (const p2 of POPUP_FOOTER_PATTERNS) {
25180
+ if (p2.regex.test(text)) return p2.kind;
25181
+ }
25262
25182
  }
25263
- const text = lines.join("\n");
25264
- return { ready: isReadySignature(text), footerKind: matchPopupFooterKind(text) };
25183
+ return null;
25265
25184
  };
25266
25185
  const tick = () => {
25267
- if (quietTimer) clearTimeout(quietTimer);
25268
- quietTimer = setTimeout(() => {
25269
- quietTimer = null;
25270
- const { ready, footerKind } = scanScreen();
25271
- const popupKind = footerKind ?? "unknown";
25272
- if (!ready && visible === null) {
25273
- visible = popupKind;
25274
- opts.onTransition(popupKind, true);
25275
- } else if (!ready && visible !== null) {
25276
- if (pendingClear) {
25277
- clearTimeout(pendingClear);
25278
- pendingClear = null;
25279
- }
25280
- } else if (ready && visible !== null) {
25281
- if (pendingClear) {
25282
- clearTimeout(pendingClear);
25283
- pendingClear = null;
25284
- }
25285
- const toClear = visible;
25286
- pendingClear = setTimeout(() => {
25287
- pendingClear = null;
25288
- if (visible === toClear) {
25289
- visible = null;
25290
- opts.onTransition(toClear, false);
25291
- }
25292
- }, opts.clearQuietMs);
25293
- }
25294
- }, QUIET_MS);
25186
+ const matched = scanFooter();
25187
+ if (matched && visible === null) {
25188
+ visible = matched;
25189
+ opts.onTransition(matched, true);
25190
+ } else if (matched && visible !== null) {
25191
+ if (pendingClear) {
25192
+ clearTimeout(pendingClear);
25193
+ pendingClear = null;
25194
+ }
25195
+ } else if (!matched && visible !== null && !pendingClear) {
25196
+ const toClear = visible;
25197
+ pendingClear = setTimeout(() => {
25198
+ pendingClear = null;
25199
+ if (visible === toClear) {
25200
+ visible = null;
25201
+ opts.onTransition(toClear, false);
25202
+ }
25203
+ }, opts.clearQuietMs);
25204
+ }
25295
25205
  };
25296
25206
  return {
25297
25207
  get visibleKind() {
@@ -25334,10 +25244,6 @@ function createPopupDetector(opts) {
25334
25244
  },
25335
25245
  dispose() {
25336
25246
  disposed = true;
25337
- if (quietTimer) {
25338
- clearTimeout(quietTimer);
25339
- quietTimer = null;
25340
- }
25341
25247
  if (pendingClear) {
25342
25248
  clearTimeout(pendingClear);
25343
25249
  pendingClear = null;
@@ -25353,6 +25259,64 @@ function createPopupDetector(opts) {
25353
25259
  }
25354
25260
  };
25355
25261
  }
25262
+ function createBootGate(pty, ptyChild, logger, toolSessionId) {
25263
+ const FALLBACK_MS = 4e3;
25264
+ const POST_POPUP_QUIET_MS = 800;
25265
+ const stripAnsi = (s) => s.replace(/\x1b\[[0-9;?]*C/g, " ").replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, "").replace(/\x1b\][^\x07]*\x07/g, "").replace(/\x1b[NOPM=>78]/g, "").replace(/[\x00-\x1f\x7f]/g, " ");
25266
+ const popups = {
25267
+ trust: { handled: false, regex: /trust this folder/i, accept: "\r", label: "trust-folder" },
25268
+ bypass: {
25269
+ handled: false,
25270
+ regex: /Bypass Permissions mode|By proceeding/i,
25271
+ accept: "2\r",
25272
+ label: "bypass-warning"
25273
+ }
25274
+ };
25275
+ let scanBuf = "";
25276
+ let opened = false;
25277
+ let postPopupQuiet = null;
25278
+ const openGate = (reason) => {
25279
+ if (opened) return;
25280
+ opened = true;
25281
+ logger?.debug("boot gate setReady", { toolSessionId, reason });
25282
+ clearTimeout(fallbackTimer);
25283
+ if (postPopupQuiet) clearTimeout(postPopupQuiet);
25284
+ scanBuf = "";
25285
+ ptyChild.setReady();
25286
+ };
25287
+ const fallbackTimer = setTimeout(() => openGate("timeout-4s"), FALLBACK_MS);
25288
+ return {
25289
+ get opened() {
25290
+ return opened;
25291
+ },
25292
+ feedBytes(data) {
25293
+ scanBuf += data.toString("utf8");
25294
+ const cleanBuf = stripAnsi(scanBuf).replace(/\s+/g, " ");
25295
+ for (const popup of Object.values(popups)) {
25296
+ if (popup.handled) continue;
25297
+ if (popup.regex.test(cleanBuf)) {
25298
+ popup.handled = true;
25299
+ logger?.debug(`${popup.label} popup auto-yes`, { toolSessionId });
25300
+ try {
25301
+ pty.write(popup.accept);
25302
+ } catch (err) {
25303
+ logger?.warn(`${popup.label} auto-yes write failed`, {
25304
+ error: err.message
25305
+ });
25306
+ }
25307
+ scanBuf = "";
25308
+ if (postPopupQuiet) clearTimeout(postPopupQuiet);
25309
+ postPopupQuiet = setTimeout(() => openGate("post-popup-quiet"), POST_POPUP_QUIET_MS);
25310
+ }
25311
+ }
25312
+ if (scanBuf.length > 8192) scanBuf = scanBuf.slice(-4096);
25313
+ },
25314
+ dispose() {
25315
+ clearTimeout(fallbackTimer);
25316
+ if (postPopupQuiet) clearTimeout(postPopupQuiet);
25317
+ }
25318
+ };
25319
+ }
25356
25320
  var ClaudeTuiAdapter = class extends ClaudeAdapter {
25357
25321
  // id 仍是 'claude'(继承)— UI / SessionFile.tool / capabilities:get RPC 字面量不变,
25358
25322
  // 完全兼容 SDK 模式 wiring。TUI 行为通过 daemon mode 流转,不通过 tool id 区分
@@ -25392,14 +25356,14 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25392
25356
  const ptyChild = new PtyChildProcess(pty, {
25393
25357
  logger: this.tuiLogger,
25394
25358
  tag: ctx.toolSessionId ?? "no-tsid",
25395
- // MVP 阶段:boot gate 自动应答 + 4s 硬超时已废弃(由 ReadyGate 反向判定接管),
25396
- // stdin buffer 关闸 —— 用户 query 直发 CC。
25397
- // boot gate 废弃;Task 5/6 在 reducer 层接 ReadyGate ready 信号做 pending-send 调度
25398
- bootGate: false
25359
+ // boot gate:CC TUI 启动 + popup 处理前 stdin.write 一律 buffer,防止用户 prompt 在
25360
+ // CC 加载 node runtime 时被吞。bootGate scanner popup 处理完成 / 4s 兜底任一条件
25361
+ // 触发后调 setReady() 开闸
25362
+ bootGate: true
25399
25363
  });
25364
+ const bootGate = createBootGate(pty, ptyChild, this.tuiLogger, ctx.toolSessionId);
25400
25365
  const detector = createPopupDetector({
25401
25366
  clearQuietMs: 200,
25402
- // quietMs 走默认 300ms — 屏幕静止判定时长,对 cc TUI 启动期重绘节奏足够
25403
25367
  onTransition: (kind, visible) => {
25404
25368
  if (!ctx.toolSessionId || !this.tuiOpts.onPopupTransition) return;
25405
25369
  this.tuiLogger?.debug("popup transition", {
@@ -25436,7 +25400,11 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25436
25400
  if (ctx.toolSessionId && this.tuiOpts.onPtyData) {
25437
25401
  this.tuiOpts.onPtyData(ctx.toolSessionId, merged.toString("base64"), seq);
25438
25402
  }
25439
- void detector.writeBytes(merged.toString("utf8"), seq);
25403
+ if (bootGate.opened) {
25404
+ void detector.writeBytes(merged.toString("utf8"), seq);
25405
+ } else {
25406
+ bootGate.feedBytes(merged);
25407
+ }
25440
25408
  if (ctx.toolSessionId) {
25441
25409
  probePtyDataThrottled(ctx.toolSessionId, merged.length, merged);
25442
25410
  }
@@ -25453,6 +25421,7 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
25453
25421
  if (coalesceBuf.length > 0) {
25454
25422
  flushCoalesced();
25455
25423
  }
25424
+ bootGate.dispose();
25456
25425
  if (ctx.toolSessionId && this.tuiOpts.onDetectorUnregister) {
25457
25426
  this.tuiOpts.onDetectorUnregister(ctx.toolSessionId);
25458
25427
  }
@@ -25970,7 +25939,8 @@ var SessionObserver = class {
25970
25939
  pollTimer: null,
25971
25940
  lastSize: size,
25972
25941
  buf: "",
25973
- adapter: args.adapter
25942
+ adapter: args.adapter,
25943
+ prevIsRejectSentinel: false
25974
25944
  };
25975
25945
  try {
25976
25946
  import_node_fs14.default.mkdirSync(import_node_path15.default.dirname(filePath), { recursive: true });
@@ -26043,6 +26013,15 @@ var SessionObserver = class {
26043
26013
  while ((newlineIndex = w2.buf.indexOf("\n")) >= 0) {
26044
26014
  const line = w2.buf.slice(0, newlineIndex);
26045
26015
  w2.buf = w2.buf.slice(newlineIndex + 1);
26016
+ let parsed = null;
26017
+ try {
26018
+ parsed = line.trim() ? JSON.parse(line) : null;
26019
+ } catch {
26020
+ parsed = null;
26021
+ }
26022
+ const skipAsMarker = w2.prevIsRejectSentinel && parsed !== null && isUserPlainTextLine(parsed);
26023
+ w2.prevIsRejectSentinel = parsed !== null ? isRejectSentinelLine(parsed) : false;
26024
+ if (skipAsMarker) continue;
26046
26025
  const events = w2.adapter.parseLine(line);
26047
26026
  this.maybeReportUserMessage(w2.sessionId, line);
26048
26027
  if (events.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.93-beta.175.b162fd0",
3
+ "version": "0.2.94-beta.176.8dff088",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",