@clawos-dev/clawd 0.2.93 → 0.2.94
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 +102 -153
- 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) {
|
|
@@ -21293,9 +21289,7 @@ function cloneState(s) {
|
|
|
21293
21289
|
freshSpawn: s.freshSpawn,
|
|
21294
21290
|
procAlive: s.procAlive,
|
|
21295
21291
|
seenUuids: s.seenUuids,
|
|
21296
|
-
subSessionMeta: s.subSessionMeta
|
|
21297
|
-
readyForSend: s.readyForSend,
|
|
21298
|
-
pendingSend: s.pendingSend
|
|
21292
|
+
subSessionMeta: s.subSessionMeta
|
|
21299
21293
|
};
|
|
21300
21294
|
}
|
|
21301
21295
|
var IDLE_KILL_DELAY_MS = 6e4;
|
|
@@ -21530,23 +21524,6 @@ function applyCommand(state, command, deps) {
|
|
|
21530
21524
|
effects.push({ kind: "cancel-idle-kill", sessionId });
|
|
21531
21525
|
next.status = next.procAlive ? "running" : "idle";
|
|
21532
21526
|
}
|
|
21533
|
-
if (next.pendingSend) {
|
|
21534
|
-
return {
|
|
21535
|
-
state: next,
|
|
21536
|
-
effects: [
|
|
21537
|
-
...effects,
|
|
21538
|
-
{
|
|
21539
|
-
kind: "emit-frame",
|
|
21540
|
-
frame: {
|
|
21541
|
-
type: "error",
|
|
21542
|
-
sessionId,
|
|
21543
|
-
code: ERROR_CODES.SEND_PENDING,
|
|
21544
|
-
message: "a previous message is still pending; cc not yet ready"
|
|
21545
|
-
}
|
|
21546
|
-
}
|
|
21547
|
-
]
|
|
21548
|
-
};
|
|
21549
|
-
}
|
|
21550
21527
|
if (!next.procAlive) {
|
|
21551
21528
|
next.procAlive = true;
|
|
21552
21529
|
next.freshSpawn = true;
|
|
@@ -21555,9 +21532,6 @@ function applyCommand(state, command, deps) {
|
|
|
21555
21532
|
next.nextSeq = 0;
|
|
21556
21533
|
next.turnOpen = false;
|
|
21557
21534
|
next.status = "running";
|
|
21558
|
-
if (deps.mode === "tui") {
|
|
21559
|
-
next.readyForSend = false;
|
|
21560
|
-
}
|
|
21561
21535
|
effects.push({ kind: "spawn", ctx: buildSpawnContext(next, deps) });
|
|
21562
21536
|
effects.push({
|
|
21563
21537
|
kind: "emit-frame",
|
|
@@ -21574,15 +21548,10 @@ function applyCommand(state, command, deps) {
|
|
|
21574
21548
|
uuid: deps.genUuid?.()
|
|
21575
21549
|
};
|
|
21576
21550
|
const pushed = pushEventToBuffer(next, userEvent, deps);
|
|
21577
|
-
let nextState = pushed.state;
|
|
21578
21551
|
effects.push(...pushed.effects);
|
|
21579
|
-
|
|
21580
|
-
|
|
21581
|
-
|
|
21582
|
-
} else {
|
|
21583
|
-
nextState = { ...nextState, pendingSend: { text: command.text } };
|
|
21584
|
-
}
|
|
21585
|
-
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 };
|
|
21586
21555
|
}
|
|
21587
21556
|
case "stop": {
|
|
21588
21557
|
for (const toolUseId of Object.keys(state.pendingQuestions ?? {})) {
|
|
@@ -21597,7 +21566,6 @@ function applyCommand(state, command, deps) {
|
|
|
21597
21566
|
}
|
|
21598
21567
|
next.pendingPermissions = {};
|
|
21599
21568
|
next.pendingQuestions = {};
|
|
21600
|
-
next.pendingSend = void 0;
|
|
21601
21569
|
if (next.procAlive) {
|
|
21602
21570
|
next.status = "stopping";
|
|
21603
21571
|
effects.push({ kind: "kill", signal: "SIGKILL" });
|
|
@@ -21635,8 +21603,6 @@ function applyCommand(state, command, deps) {
|
|
|
21635
21603
|
}
|
|
21636
21604
|
next.pendingPermissions = {};
|
|
21637
21605
|
next.pendingQuestions = {};
|
|
21638
|
-
next.pendingSend = void 0;
|
|
21639
|
-
next.readyForSend = false;
|
|
21640
21606
|
if (next.procAlive) {
|
|
21641
21607
|
effects.push({ kind: "kill", signal: "SIGKILL" });
|
|
21642
21608
|
}
|
|
@@ -21680,7 +21646,6 @@ function applyCommand(state, command, deps) {
|
|
|
21680
21646
|
next.pendingPermissions = {};
|
|
21681
21647
|
next.freshSpawn = false;
|
|
21682
21648
|
next.seenUuids = [];
|
|
21683
|
-
next.pendingSend = void 0;
|
|
21684
21649
|
effects.push({
|
|
21685
21650
|
kind: "emit-frame",
|
|
21686
21651
|
frame: { type: "session:cleared", sessionId }
|
|
@@ -21718,7 +21683,6 @@ function applyCommand(state, command, deps) {
|
|
|
21718
21683
|
next.pendingPermissions = {};
|
|
21719
21684
|
next.freshSpawn = false;
|
|
21720
21685
|
next.seenUuids = [];
|
|
21721
|
-
next.pendingSend = void 0;
|
|
21722
21686
|
effects.push({ kind: "persist-file", file: nextFile });
|
|
21723
21687
|
effects.push(sessionInfoFrame(nextFile));
|
|
21724
21688
|
effects.push({
|
|
@@ -21753,8 +21717,6 @@ function reduceSession(state, input, deps) {
|
|
|
21753
21717
|
const next = cloneState(state);
|
|
21754
21718
|
next.procAlive = false;
|
|
21755
21719
|
next.status = "stopped";
|
|
21756
|
-
next.pendingSend = void 0;
|
|
21757
|
-
next.readyForSend = false;
|
|
21758
21720
|
const sessionId = next.file.sessionId;
|
|
21759
21721
|
const clearedEffects = Object.keys(state.pendingQuestions ?? {}).map(
|
|
21760
21722
|
(toolUseId) => ({
|
|
@@ -21786,8 +21748,6 @@ function reduceSession(state, input, deps) {
|
|
|
21786
21748
|
case "proc-error": {
|
|
21787
21749
|
const next = cloneState(state);
|
|
21788
21750
|
next.status = "error";
|
|
21789
|
-
next.pendingSend = void 0;
|
|
21790
|
-
next.readyForSend = false;
|
|
21791
21751
|
return {
|
|
21792
21752
|
state: next,
|
|
21793
21753
|
effects: [
|
|
@@ -21914,30 +21874,6 @@ function reduceSession(state, input, deps) {
|
|
|
21914
21874
|
effects: [{ kind: "kill", signal: "SIGKILL" }]
|
|
21915
21875
|
};
|
|
21916
21876
|
}
|
|
21917
|
-
case "ready-detected": {
|
|
21918
|
-
if (!state.procAlive) {
|
|
21919
|
-
return { state, effects: [] };
|
|
21920
|
-
}
|
|
21921
|
-
const next = cloneState(state);
|
|
21922
|
-
next.readyForSend = true;
|
|
21923
|
-
const flushEffects = [];
|
|
21924
|
-
if (state.pendingSend) {
|
|
21925
|
-
const payload = deps.encodeStdin(state.pendingSend.text, {
|
|
21926
|
-
sessionId: next.file.sessionId
|
|
21927
|
-
});
|
|
21928
|
-
flushEffects.push({ kind: "write-stdin", payload });
|
|
21929
|
-
next.pendingSend = void 0;
|
|
21930
|
-
}
|
|
21931
|
-
return { state: next, effects: flushEffects };
|
|
21932
|
-
}
|
|
21933
|
-
case "popup-detected": {
|
|
21934
|
-
if (!state.procAlive) {
|
|
21935
|
-
return { state, effects: [] };
|
|
21936
|
-
}
|
|
21937
|
-
const next = cloneState(state);
|
|
21938
|
-
next.readyForSend = false;
|
|
21939
|
-
return { state: next, effects: [] };
|
|
21940
|
-
}
|
|
21941
21877
|
case "inject-owner-text": {
|
|
21942
21878
|
const ownerEvent = {
|
|
21943
21879
|
kind: "meta-text",
|
|
@@ -22126,8 +22062,7 @@ var SessionRunner = class {
|
|
|
22126
22062
|
resolveContextWindow: this.hooks.resolveContextWindow,
|
|
22127
22063
|
genUuid: this.hooks.genUuid ?? v4_default,
|
|
22128
22064
|
ownerDisplayName: this.hooks.ownerDisplayName,
|
|
22129
|
-
personaRoot: this.hooks.personaRoot
|
|
22130
|
-
mode: this.hooks.mode ?? "sdk"
|
|
22065
|
+
personaRoot: this.hooks.personaRoot
|
|
22131
22066
|
};
|
|
22132
22067
|
const { state, effects } = reduceSession(this.state, inputMsg, deps);
|
|
22133
22068
|
this.state = state;
|
|
@@ -22557,14 +22492,7 @@ function makeInitialState(file, subSessionMeta) {
|
|
|
22557
22492
|
freshSpawn: false,
|
|
22558
22493
|
procAlive: false,
|
|
22559
22494
|
seenUuids: [],
|
|
22560
|
-
subSessionMeta
|
|
22561
|
-
// Ready gate:保守起手 true,让 SDK 模式与 TUI 接线未完成时 send 仍走旧的"立即写 stdin"
|
|
22562
|
-
// 路径不破坏 SDK 用户体验。TUI 模式 manager 集成(Task 6)会在 spawn 时显式 dispatch
|
|
22563
|
-
// 'popup-detected' 把 flag 翻 false → 等 ReadyGate emit ready 再 dispatch 'ready-detected'
|
|
22564
|
-
// 翻回 true 并 flush pendingSend。
|
|
22565
|
-
// daemon-only 字段,不上 wire / 不写 SessionFile(compressFrameForWire 只处理
|
|
22566
|
-
// session:status,SessionState 不直接序列化)。
|
|
22567
|
-
readyForSend: true
|
|
22495
|
+
subSessionMeta
|
|
22568
22496
|
};
|
|
22569
22497
|
}
|
|
22570
22498
|
var SessionManager = class {
|
|
@@ -22807,9 +22735,6 @@ var SessionManager = class {
|
|
|
22807
22735
|
// Phase 2 capability platform (plan §3): 透传 personaRoot, buildSpawnArgs 据
|
|
22808
22736
|
// cwd 是否在 personaRoot 下自动决定是否注入 --settings sandbox-settings.json.
|
|
22809
22737
|
personaRoot: this.deps.personaRoot,
|
|
22810
|
-
// 透传给 ReducerDeps.mode:reducer send !procAlive spawn 路径据此判断要不要把
|
|
22811
|
-
// readyForSend 翻 false(TUI 翻 false 让 user_text 走 pendingSend 暂存;SDK 不动保持直写)
|
|
22812
|
-
mode: this.deps.mode,
|
|
22813
22738
|
// file-sharing (spec §6 PR 3):闭包 scope + sessionId,runner 只暴露 tool/relPath/cwd
|
|
22814
22739
|
onFileEdit: attachmentGroup ? (input) => attachmentGroup.onFileEdit({
|
|
22815
22740
|
scope,
|
|
@@ -23945,9 +23870,6 @@ var SessionManager = class {
|
|
|
23945
23870
|
},
|
|
23946
23871
|
"broadcast"
|
|
23947
23872
|
);
|
|
23948
|
-
const runner = this.runners.get(sid);
|
|
23949
|
-
if (!runner) return;
|
|
23950
|
-
runner.input({ kind: visible ? "popup-detected" : "ready-detected" });
|
|
23951
23873
|
}
|
|
23952
23874
|
/** toolSessionId → sessionId 反查(遍历 runners);session 数典型 < 10,O(n) 可接受 */
|
|
23953
23875
|
sessionIdByToolSid(toolSessionId) {
|
|
@@ -25232,29 +25154,6 @@ var POPUP_FOOTER_PATTERNS = [
|
|
|
25232
25154
|
{ kind: "permission", regex: /Tab to amend|Do you want to proceed/i },
|
|
25233
25155
|
{ kind: "question", regex: /Enter to select|↑\/↓ to navigate/i }
|
|
25234
25156
|
];
|
|
25235
|
-
function matchPopupFooterKind(bufferText) {
|
|
25236
|
-
for (const p2 of POPUP_FOOTER_PATTERNS) {
|
|
25237
|
-
if (p2.regex.test(bufferText)) return p2.kind;
|
|
25238
|
-
}
|
|
25239
|
-
return null;
|
|
25240
|
-
}
|
|
25241
|
-
function hasInputFrame(bufferText) {
|
|
25242
|
-
const lines = bufferText.split("\n");
|
|
25243
|
-
for (let i = 1; i < lines.length; i++) {
|
|
25244
|
-
const cur = lines[i];
|
|
25245
|
-
if (!/^\s*❯\s/.test(cur)) continue;
|
|
25246
|
-
const prev = lines[i - 1];
|
|
25247
|
-
if (/─{20,}/.test(prev)) return true;
|
|
25248
|
-
}
|
|
25249
|
-
return false;
|
|
25250
|
-
}
|
|
25251
|
-
var READY_SIGNATURE_PATTERNS = [
|
|
25252
|
-
{ name: "input-frame", match: hasInputFrame }
|
|
25253
|
-
];
|
|
25254
|
-
function isReadySignature(bufferText) {
|
|
25255
|
-
if (matchPopupFooterKind(bufferText) !== null) return false;
|
|
25256
|
-
return READY_SIGNATURE_PATTERNS.some((p2) => p2.match(bufferText));
|
|
25257
|
-
}
|
|
25258
25157
|
function createPopupDetector(opts) {
|
|
25259
25158
|
const term = new Terminal({
|
|
25260
25159
|
cols: opts.cols ?? 120,
|
|
@@ -25266,52 +25165,43 @@ function createPopupDetector(opts) {
|
|
|
25266
25165
|
term.loadAddon(serializeAddon);
|
|
25267
25166
|
let visible = null;
|
|
25268
25167
|
let pendingClear = null;
|
|
25269
|
-
let quietTimer = null;
|
|
25270
|
-
const QUIET_MS = opts.quietMs ?? 300;
|
|
25271
25168
|
let parseSeq = 0;
|
|
25272
25169
|
let pendingParse = 0;
|
|
25273
25170
|
let drainWaiters = [];
|
|
25274
25171
|
let disposed = false;
|
|
25275
|
-
const
|
|
25172
|
+
const scanFooter = () => {
|
|
25276
25173
|
const buf = term.buffer.active;
|
|
25277
|
-
const lines = [];
|
|
25278
25174
|
for (let i = 0; i < buf.length; i++) {
|
|
25279
25175
|
const line = buf.getLine(i);
|
|
25280
25176
|
if (!line) continue;
|
|
25281
|
-
|
|
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
|
+
}
|
|
25282
25182
|
}
|
|
25283
|
-
|
|
25284
|
-
return { ready: isReadySignature(text), footerKind: matchPopupFooterKind(text) };
|
|
25183
|
+
return null;
|
|
25285
25184
|
};
|
|
25286
25185
|
const tick = () => {
|
|
25287
|
-
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
25292
|
-
if (
|
|
25293
|
-
|
|
25294
|
-
|
|
25295
|
-
}
|
|
25296
|
-
|
|
25297
|
-
|
|
25298
|
-
|
|
25299
|
-
|
|
25300
|
-
|
|
25301
|
-
|
|
25302
|
-
|
|
25303
|
-
|
|
25304
|
-
|
|
25305
|
-
|
|
25306
|
-
pendingClear = setTimeout(() => {
|
|
25307
|
-
pendingClear = null;
|
|
25308
|
-
if (visible === toClear) {
|
|
25309
|
-
visible = null;
|
|
25310
|
-
opts.onTransition(toClear, false);
|
|
25311
|
-
}
|
|
25312
|
-
}, opts.clearQuietMs);
|
|
25313
|
-
}
|
|
25314
|
-
}, 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
|
+
}
|
|
25315
25205
|
};
|
|
25316
25206
|
return {
|
|
25317
25207
|
get visibleKind() {
|
|
@@ -25354,10 +25244,6 @@ function createPopupDetector(opts) {
|
|
|
25354
25244
|
},
|
|
25355
25245
|
dispose() {
|
|
25356
25246
|
disposed = true;
|
|
25357
|
-
if (quietTimer) {
|
|
25358
|
-
clearTimeout(quietTimer);
|
|
25359
|
-
quietTimer = null;
|
|
25360
|
-
}
|
|
25361
25247
|
if (pendingClear) {
|
|
25362
25248
|
clearTimeout(pendingClear);
|
|
25363
25249
|
pendingClear = null;
|
|
@@ -25373,6 +25259,64 @@ function createPopupDetector(opts) {
|
|
|
25373
25259
|
}
|
|
25374
25260
|
};
|
|
25375
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
|
+
}
|
|
25376
25320
|
var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
25377
25321
|
// id 仍是 'claude'(继承)— UI / SessionFile.tool / capabilities:get RPC 字面量不变,
|
|
25378
25322
|
// 完全兼容 SDK 模式 wiring。TUI 行为通过 daemon mode 流转,不通过 tool id 区分
|
|
@@ -25412,14 +25356,14 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
25412
25356
|
const ptyChild = new PtyChildProcess(pty, {
|
|
25413
25357
|
logger: this.tuiLogger,
|
|
25414
25358
|
tag: ctx.toolSessionId ?? "no-tsid",
|
|
25415
|
-
//
|
|
25416
|
-
//
|
|
25417
|
-
//
|
|
25418
|
-
bootGate:
|
|
25359
|
+
// boot gate:CC TUI 启动 + popup 处理前 stdin.write 一律 buffer,防止用户 prompt 在
|
|
25360
|
+
// CC 加载 node runtime 时被吞。bootGate scanner 在 popup 处理完成 / 4s 兜底任一条件
|
|
25361
|
+
// 触发后调 setReady() 开闸
|
|
25362
|
+
bootGate: true
|
|
25419
25363
|
});
|
|
25364
|
+
const bootGate = createBootGate(pty, ptyChild, this.tuiLogger, ctx.toolSessionId);
|
|
25420
25365
|
const detector = createPopupDetector({
|
|
25421
25366
|
clearQuietMs: 200,
|
|
25422
|
-
// quietMs 走默认 300ms — 屏幕静止判定时长,对 cc TUI 启动期重绘节奏足够
|
|
25423
25367
|
onTransition: (kind, visible) => {
|
|
25424
25368
|
if (!ctx.toolSessionId || !this.tuiOpts.onPopupTransition) return;
|
|
25425
25369
|
this.tuiLogger?.debug("popup transition", {
|
|
@@ -25456,7 +25400,11 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
25456
25400
|
if (ctx.toolSessionId && this.tuiOpts.onPtyData) {
|
|
25457
25401
|
this.tuiOpts.onPtyData(ctx.toolSessionId, merged.toString("base64"), seq);
|
|
25458
25402
|
}
|
|
25459
|
-
|
|
25403
|
+
if (bootGate.opened) {
|
|
25404
|
+
void detector.writeBytes(merged.toString("utf8"), seq);
|
|
25405
|
+
} else {
|
|
25406
|
+
bootGate.feedBytes(merged);
|
|
25407
|
+
}
|
|
25460
25408
|
if (ctx.toolSessionId) {
|
|
25461
25409
|
probePtyDataThrottled(ctx.toolSessionId, merged.length, merged);
|
|
25462
25410
|
}
|
|
@@ -25473,6 +25421,7 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
25473
25421
|
if (coalesceBuf.length > 0) {
|
|
25474
25422
|
flushCoalesced();
|
|
25475
25423
|
}
|
|
25424
|
+
bootGate.dispose();
|
|
25476
25425
|
if (ctx.toolSessionId && this.tuiOpts.onDetectorUnregister) {
|
|
25477
25426
|
this.tuiOpts.onDetectorUnregister(ctx.toolSessionId);
|
|
25478
25427
|
}
|