@clawos-dev/clawd 0.2.102-beta.196.9ae3d02 → 0.2.102-beta.197.08025e2
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 +114 -137
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -32546,12 +32546,11 @@ var SessionManager = class {
|
|
|
32546
32546
|
// 新 client 通过 session:subscribe 接入时由 onSubscribe hook 取 getPtyReplay(sessionId)
|
|
32547
32547
|
// 把屏幕快照定向 emit,解决"刷新页面 / 第二个 tab 接入时 xterm 白屏"
|
|
32548
32548
|
ptyReplaysByToolSid = /* @__PURE__ */ new Map();
|
|
32549
|
-
// TUI 模式:toolSessionId → @xterm/headless
|
|
32550
|
-
//
|
|
32551
|
-
//
|
|
32552
|
-
// manager.resizePty 用此映射把 UI 的 session:pty:resize 同步到 surface 内部 buffer,
|
|
32549
|
+
// TUI 模式:toolSessionId → @xterm/headless PopupDetector。
|
|
32550
|
+
// ClaudeTuiAdapter spawn 时通过 onDetectorRegister callback 写入;exit 时 onDetectorUnregister 清理。
|
|
32551
|
+
// manager.resizePty 用此映射把 UI 的 session:pty:resize 同步到 detector 内部 buffer,
|
|
32553
32552
|
// 保证 snapshot serialize 时 cursor positioning 与 UI xterm 实际尺寸一致。
|
|
32554
|
-
|
|
32553
|
+
detectorsByToolSid = /* @__PURE__ */ new Map();
|
|
32555
32554
|
// 仅 mode='tui' 需要:index.ts 装配阶段在 observer 构造后注入。
|
|
32556
32555
|
// observer.onEvent 要回灌 manager.feedObserverEvents,所以 observer 必须晚于 manager
|
|
32557
32556
|
// 构造;反过来 manager 又要在 mode='tui' 下 spawn session 时 attach observer。setter 解循环
|
|
@@ -33825,18 +33824,18 @@ var SessionManager = class {
|
|
|
33825
33824
|
if (!tsid) return void 0;
|
|
33826
33825
|
return this.ptyTransports.get(tsid);
|
|
33827
33826
|
}
|
|
33828
|
-
/** ClaudeTuiAdapter spawn 时注册
|
|
33829
|
-
|
|
33830
|
-
this.
|
|
33827
|
+
/** ClaudeTuiAdapter spawn 时注册 detector ref;同一 tsid 重 spawn 会覆盖 */
|
|
33828
|
+
registerDetector(toolSessionId, detector) {
|
|
33829
|
+
this.detectorsByToolSid.set(toolSessionId, detector);
|
|
33831
33830
|
}
|
|
33832
33831
|
/** spawn 进程 exit 时清理 */
|
|
33833
|
-
|
|
33834
|
-
this.
|
|
33832
|
+
unregisterDetector(toolSessionId) {
|
|
33833
|
+
this.detectorsByToolSid.delete(toolSessionId);
|
|
33835
33834
|
}
|
|
33836
33835
|
/**
|
|
33837
|
-
* 同时 resize pty 子进程和
|
|
33838
|
-
* 顺序:pty.resize 在前,
|
|
33839
|
-
*
|
|
33836
|
+
* 同时 resize pty 子进程和 detector buffer:UI session:pty:resize 入口走这个。
|
|
33837
|
+
* 顺序:pty.resize 在前,detector.resize 在后 —— pty 是真正的 CC 子进程视图,必须先成功;
|
|
33838
|
+
* detector 只是 daemon 端镜像,任一步失败都返 false。
|
|
33840
33839
|
* 找不到 runner / toolSessionId / pty 任一缺失 → 返 false,handler 静默给 UI 报 ok=false 不抛错。
|
|
33841
33840
|
*/
|
|
33842
33841
|
resizePty(sessionId, cols, rows) {
|
|
@@ -33851,8 +33850,8 @@ var SessionManager = class {
|
|
|
33851
33850
|
} catch {
|
|
33852
33851
|
return false;
|
|
33853
33852
|
}
|
|
33854
|
-
const
|
|
33855
|
-
if (
|
|
33853
|
+
const detector = this.detectorsByToolSid.get(tsid);
|
|
33854
|
+
if (detector) detector.resize(cols, rows);
|
|
33856
33855
|
return true;
|
|
33857
33856
|
}
|
|
33858
33857
|
/**
|
|
@@ -35150,30 +35149,59 @@ var POPUP_FOOTER_PATTERNS = [
|
|
|
35150
35149
|
{ kind: "permission", regex: /Tab to amend|Do you want to proceed/i },
|
|
35151
35150
|
{ kind: "question", regex: /Enter to select|↑\/↓ to navigate/i }
|
|
35152
35151
|
];
|
|
35153
|
-
function
|
|
35152
|
+
function createPopupDetector(opts) {
|
|
35154
35153
|
const term = new Terminal({
|
|
35155
|
-
cols: opts
|
|
35156
|
-
rows: opts
|
|
35157
|
-
scrollback:
|
|
35154
|
+
cols: opts.cols ?? 120,
|
|
35155
|
+
rows: opts.rows ?? 40,
|
|
35156
|
+
scrollback: 1e3,
|
|
35158
35157
|
allowProposedApi: true
|
|
35159
35158
|
});
|
|
35160
35159
|
const serializeAddon = new D();
|
|
35161
35160
|
term.loadAddon(serializeAddon);
|
|
35161
|
+
let visible = null;
|
|
35162
|
+
let pendingClear = null;
|
|
35162
35163
|
let parseSeq = 0;
|
|
35163
35164
|
let pendingParse = 0;
|
|
35164
35165
|
let drainWaiters = [];
|
|
35165
35166
|
let disposed = false;
|
|
35166
|
-
const
|
|
35167
|
-
const collectLines = () => {
|
|
35167
|
+
const scanFooter = () => {
|
|
35168
35168
|
const buf = term.buffer.active;
|
|
35169
|
-
const lines = new Array(buf.length);
|
|
35170
35169
|
for (let i = 0; i < buf.length; i++) {
|
|
35171
35170
|
const line = buf.getLine(i);
|
|
35172
|
-
|
|
35171
|
+
if (!line) continue;
|
|
35172
|
+
const text = line.translateToString(true);
|
|
35173
|
+
if (!text) continue;
|
|
35174
|
+
for (const p2 of POPUP_FOOTER_PATTERNS) {
|
|
35175
|
+
if (p2.regex.test(text)) return p2.kind;
|
|
35176
|
+
}
|
|
35177
|
+
}
|
|
35178
|
+
return null;
|
|
35179
|
+
};
|
|
35180
|
+
const tick = () => {
|
|
35181
|
+
const matched = scanFooter();
|
|
35182
|
+
if (matched && visible === null) {
|
|
35183
|
+
visible = matched;
|
|
35184
|
+
opts.onTransition(matched, true);
|
|
35185
|
+
} else if (matched && visible !== null) {
|
|
35186
|
+
if (pendingClear) {
|
|
35187
|
+
clearTimeout(pendingClear);
|
|
35188
|
+
pendingClear = null;
|
|
35189
|
+
}
|
|
35190
|
+
} else if (!matched && visible !== null && !pendingClear) {
|
|
35191
|
+
const toClear = visible;
|
|
35192
|
+
pendingClear = setTimeout(() => {
|
|
35193
|
+
pendingClear = null;
|
|
35194
|
+
if (visible === toClear) {
|
|
35195
|
+
visible = null;
|
|
35196
|
+
opts.onTransition(toClear, false);
|
|
35197
|
+
}
|
|
35198
|
+
}, opts.clearQuietMs);
|
|
35173
35199
|
}
|
|
35174
|
-
return lines;
|
|
35175
35200
|
};
|
|
35176
35201
|
return {
|
|
35202
|
+
get visibleKind() {
|
|
35203
|
+
return visible;
|
|
35204
|
+
},
|
|
35177
35205
|
get parseSeq() {
|
|
35178
35206
|
return parseSeq;
|
|
35179
35207
|
},
|
|
@@ -35187,10 +35215,7 @@ function createTerminalSurface(opts) {
|
|
|
35187
35215
|
}
|
|
35188
35216
|
if (typeof seq === "number" && seq > parseSeq) parseSeq = seq;
|
|
35189
35217
|
pendingParse--;
|
|
35190
|
-
|
|
35191
|
-
const lines = collectLines();
|
|
35192
|
-
for (const cb of [...observers]) cb(lines);
|
|
35193
|
-
}
|
|
35218
|
+
tick();
|
|
35194
35219
|
if (pendingParse === 0 && drainWaiters.length > 0) {
|
|
35195
35220
|
const waiters = drainWaiters;
|
|
35196
35221
|
drainWaiters = [];
|
|
@@ -35212,93 +35237,42 @@ function createTerminalSurface(opts) {
|
|
|
35212
35237
|
} catch {
|
|
35213
35238
|
}
|
|
35214
35239
|
},
|
|
35215
|
-
serialize() {
|
|
35216
|
-
return serializeAddon.serialize({ scrollback: 1e3 });
|
|
35217
|
-
},
|
|
35218
35240
|
dispose() {
|
|
35219
35241
|
disposed = true;
|
|
35220
|
-
|
|
35242
|
+
if (pendingClear) {
|
|
35243
|
+
clearTimeout(pendingClear);
|
|
35244
|
+
pendingClear = null;
|
|
35245
|
+
}
|
|
35221
35246
|
const waiters = drainWaiters;
|
|
35222
35247
|
drainWaiters = [];
|
|
35223
35248
|
for (const w2 of waiters) w2();
|
|
35224
|
-
observers.length = 0;
|
|
35225
35249
|
serializeAddon.dispose();
|
|
35226
35250
|
term.dispose();
|
|
35227
35251
|
},
|
|
35228
|
-
|
|
35229
|
-
|
|
35230
|
-
return () => {
|
|
35231
|
-
const i = observers.indexOf(cb);
|
|
35232
|
-
if (i >= 0) observers.splice(i, 1);
|
|
35233
|
-
};
|
|
35252
|
+
serialize() {
|
|
35253
|
+
return serializeAddon.serialize({ scrollback: 1e3 });
|
|
35234
35254
|
}
|
|
35235
35255
|
};
|
|
35236
35256
|
}
|
|
35237
|
-
function
|
|
35238
|
-
|
|
35239
|
-
|
|
35240
|
-
|
|
35241
|
-
|
|
35242
|
-
|
|
35243
|
-
for (const p2 of POPUP_FOOTER_PATTERNS) {
|
|
35244
|
-
if (p2.regex.test(text)) return p2.kind;
|
|
35245
|
-
}
|
|
35246
|
-
}
|
|
35247
|
-
return null;
|
|
35248
|
-
};
|
|
35249
|
-
const unsubscribe = surface.onTick((lines) => {
|
|
35250
|
-
const matched = scanFooter(lines);
|
|
35251
|
-
const inputFrameVisible = opts.getInputFrameVisible();
|
|
35252
|
-
if (visible === null) {
|
|
35253
|
-
if (matched && !inputFrameVisible) {
|
|
35254
|
-
visible = matched;
|
|
35255
|
-
opts.onTransition(matched, true);
|
|
35256
|
-
}
|
|
35257
|
-
return;
|
|
35258
|
-
}
|
|
35259
|
-
if (!inputFrameVisible) {
|
|
35260
|
-
if (pendingClear) {
|
|
35261
|
-
clearTimeout(pendingClear);
|
|
35262
|
-
pendingClear = null;
|
|
35263
|
-
}
|
|
35264
|
-
return;
|
|
35265
|
-
}
|
|
35266
|
-
if (!pendingClear) {
|
|
35267
|
-
const toClear = visible;
|
|
35268
|
-
pendingClear = setTimeout(() => {
|
|
35269
|
-
pendingClear = null;
|
|
35270
|
-
if (visible === toClear) {
|
|
35271
|
-
visible = null;
|
|
35272
|
-
opts.onTransition(toClear, false);
|
|
35273
|
-
}
|
|
35274
|
-
}, opts.clearQuietMs);
|
|
35275
|
-
}
|
|
35257
|
+
function createReadyDetector(opts) {
|
|
35258
|
+
const term = new Terminal({
|
|
35259
|
+
cols: opts.cols ?? 120,
|
|
35260
|
+
rows: opts.rows ?? 40,
|
|
35261
|
+
scrollback: 200,
|
|
35262
|
+
allowProposedApi: true
|
|
35276
35263
|
});
|
|
35277
|
-
return {
|
|
35278
|
-
get visibleKind() {
|
|
35279
|
-
return visible;
|
|
35280
|
-
},
|
|
35281
|
-
dispose() {
|
|
35282
|
-
unsubscribe();
|
|
35283
|
-
if (pendingClear) {
|
|
35284
|
-
clearTimeout(pendingClear);
|
|
35285
|
-
pendingClear = null;
|
|
35286
|
-
}
|
|
35287
|
-
}
|
|
35288
|
-
};
|
|
35289
|
-
}
|
|
35290
|
-
function observeReady(surface, opts) {
|
|
35291
|
-
let prevReady = false;
|
|
35292
35264
|
let quietTimer = null;
|
|
35293
|
-
let
|
|
35294
|
-
|
|
35295
|
-
|
|
35265
|
+
let disposed = false;
|
|
35266
|
+
const scanReadyFrame = () => {
|
|
35267
|
+
const buf = term.buffer.active;
|
|
35296
35268
|
let prevHasDivider = false;
|
|
35297
|
-
for (
|
|
35298
|
-
|
|
35269
|
+
for (let i = 0; i < buf.length; i++) {
|
|
35270
|
+
const line = buf.getLine(i);
|
|
35271
|
+
if (!line) {
|
|
35299
35272
|
prevHasDivider = false;
|
|
35300
35273
|
continue;
|
|
35301
35274
|
}
|
|
35275
|
+
const text = line.translateToString(true);
|
|
35302
35276
|
const hasPrompt = /^❯/.test(text);
|
|
35303
35277
|
const hasDivider = /─{20,}/.test(text);
|
|
35304
35278
|
if (hasPrompt && prevHasDivider) return true;
|
|
@@ -35321,18 +35295,18 @@ function observeReady(surface, opts) {
|
|
|
35321
35295
|
};
|
|
35322
35296
|
const quietFire = () => {
|
|
35323
35297
|
quietTimer = null;
|
|
35324
|
-
if (
|
|
35325
|
-
if (!scanReadyFrame(
|
|
35298
|
+
if (disposed) return;
|
|
35299
|
+
if (!scanReadyFrame()) {
|
|
35326
35300
|
dbg({ event: "quiet-fire-but-not-ready-anymore" });
|
|
35327
35301
|
return;
|
|
35328
35302
|
}
|
|
35329
35303
|
dbg({ event: "quiet-fire \u2192 onReady" });
|
|
35330
35304
|
opts.onReady();
|
|
35331
35305
|
};
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
const ready = scanReadyFrame(
|
|
35306
|
+
let prevReady = false;
|
|
35307
|
+
const tick = () => {
|
|
35308
|
+
if (disposed) return;
|
|
35309
|
+
const ready = scanReadyFrame();
|
|
35336
35310
|
if (!ready) {
|
|
35337
35311
|
clearQuiet();
|
|
35338
35312
|
if (prevReady) {
|
|
@@ -35347,15 +35321,19 @@ function observeReady(surface, opts) {
|
|
|
35347
35321
|
}
|
|
35348
35322
|
clearQuiet();
|
|
35349
35323
|
quietTimer = setTimeout(quietFire, opts.quietMs);
|
|
35350
|
-
}
|
|
35324
|
+
};
|
|
35351
35325
|
return {
|
|
35352
|
-
|
|
35353
|
-
return
|
|
35326
|
+
writeBytes(data) {
|
|
35327
|
+
if (disposed) return;
|
|
35328
|
+
term.write(data, () => {
|
|
35329
|
+
if (disposed) return;
|
|
35330
|
+
tick();
|
|
35331
|
+
});
|
|
35354
35332
|
},
|
|
35355
35333
|
dispose() {
|
|
35356
|
-
|
|
35357
|
-
unsubscribe();
|
|
35334
|
+
disposed = true;
|
|
35358
35335
|
clearQuiet();
|
|
35336
|
+
term.dispose();
|
|
35359
35337
|
}
|
|
35360
35338
|
};
|
|
35361
35339
|
}
|
|
@@ -35437,18 +35415,7 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
35437
35415
|
tag: ctx.toolSessionId ?? "no-tsid"
|
|
35438
35416
|
});
|
|
35439
35417
|
const bootGate = createBootGate(pty, this.tuiLogger);
|
|
35440
|
-
const
|
|
35441
|
-
const readyObserver = observeReady(surface, {
|
|
35442
|
-
quietMs: 500,
|
|
35443
|
-
onReady: () => {
|
|
35444
|
-
if (!ctx.toolSessionId || !this.tuiOpts.onReady) return;
|
|
35445
|
-
this.tuiLogger?.debug("ready-detected", { toolSessionId: ctx.toolSessionId });
|
|
35446
|
-
this.tuiOpts.onReady(ctx.toolSessionId);
|
|
35447
|
-
},
|
|
35448
|
-
// [RG-DBG] 排查 ReadyGate 偶现卡输入用;定位完跟所有 [RG] 日志一起删
|
|
35449
|
-
logger: this.tuiLogger
|
|
35450
|
-
});
|
|
35451
|
-
const popupObserver = observePopup(surface, {
|
|
35418
|
+
const detector = createPopupDetector({
|
|
35452
35419
|
clearQuietMs: 200,
|
|
35453
35420
|
onTransition: (kind, visible) => {
|
|
35454
35421
|
if (!ctx.toolSessionId || !this.tuiOpts.onPopupTransition) return;
|
|
@@ -35458,21 +35425,29 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
35458
35425
|
visible
|
|
35459
35426
|
});
|
|
35460
35427
|
this.tuiOpts.onPopupTransition(ctx.toolSessionId, kind, visible);
|
|
35428
|
+
}
|
|
35429
|
+
});
|
|
35430
|
+
const readyDetector = createReadyDetector({
|
|
35431
|
+
quietMs: 500,
|
|
35432
|
+
onReady: () => {
|
|
35433
|
+
if (!ctx.toolSessionId || !this.tuiOpts.onReady) return;
|
|
35434
|
+
this.tuiLogger?.debug("ready-detected", { toolSessionId: ctx.toolSessionId });
|
|
35435
|
+
this.tuiOpts.onReady(ctx.toolSessionId);
|
|
35461
35436
|
},
|
|
35462
|
-
//
|
|
35463
|
-
|
|
35437
|
+
// [RG-DBG] 排查 ReadyGate 偶现卡输入用;定位完跟所有 [RG] 日志一起删
|
|
35438
|
+
logger: this.tuiLogger
|
|
35464
35439
|
});
|
|
35465
|
-
if (ctx.toolSessionId && this.tuiOpts.
|
|
35466
|
-
this.tuiOpts.
|
|
35440
|
+
if (ctx.toolSessionId && this.tuiOpts.onDetectorRegister) {
|
|
35441
|
+
this.tuiOpts.onDetectorRegister(ctx.toolSessionId, detector);
|
|
35467
35442
|
}
|
|
35468
35443
|
let chunkSeq = 0;
|
|
35469
35444
|
if (ctx.toolSessionId && this.tuiOpts.onPtyReplayRegister) {
|
|
35470
35445
|
this.tuiOpts.onPtyReplayRegister(ctx.toolSessionId, async () => {
|
|
35471
|
-
await
|
|
35446
|
+
await detector.drain();
|
|
35472
35447
|
return {
|
|
35473
|
-
data:
|
|
35474
|
-
popupKind:
|
|
35475
|
-
atSeq:
|
|
35448
|
+
data: detector.serialize(),
|
|
35449
|
+
popupKind: detector.visibleKind,
|
|
35450
|
+
atSeq: detector.parseSeq
|
|
35476
35451
|
};
|
|
35477
35452
|
});
|
|
35478
35453
|
}
|
|
@@ -35489,7 +35464,8 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
35489
35464
|
this.tuiOpts.onPtyData(ctx.toolSessionId, merged.toString("base64"), seq);
|
|
35490
35465
|
}
|
|
35491
35466
|
bootGate.feedBytes(merged);
|
|
35492
|
-
void
|
|
35467
|
+
void detector.writeBytes(merged.toString("utf8"), seq);
|
|
35468
|
+
readyDetector.writeBytes(merged.toString("utf8"));
|
|
35493
35469
|
if (ctx.toolSessionId) {
|
|
35494
35470
|
probePtyDataThrottled(ctx.toolSessionId, merged.length, merged);
|
|
35495
35471
|
}
|
|
@@ -35507,15 +35483,14 @@ var ClaudeTuiAdapter = class extends ClaudeAdapter {
|
|
|
35507
35483
|
flushCoalesced();
|
|
35508
35484
|
}
|
|
35509
35485
|
bootGate.dispose();
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
|
|
35513
|
-
this.tuiOpts.onSurfaceUnregister(ctx.toolSessionId);
|
|
35486
|
+
readyDetector.dispose();
|
|
35487
|
+
if (ctx.toolSessionId && this.tuiOpts.onDetectorUnregister) {
|
|
35488
|
+
this.tuiOpts.onDetectorUnregister(ctx.toolSessionId);
|
|
35514
35489
|
}
|
|
35515
35490
|
if (ctx.toolSessionId && this.tuiOpts.onPtyUnregister) {
|
|
35516
35491
|
this.tuiOpts.onPtyUnregister(ctx.toolSessionId);
|
|
35517
35492
|
}
|
|
35518
|
-
|
|
35493
|
+
detector.dispose();
|
|
35519
35494
|
});
|
|
35520
35495
|
return ptyChild;
|
|
35521
35496
|
}
|
|
@@ -40265,6 +40240,7 @@ function buildReadyFrame(deps, client) {
|
|
|
40265
40240
|
fileSharing.httpBaseUrl = httpBaseUrl;
|
|
40266
40241
|
if (deps.httpToken) fileSharing.httpToken = deps.httpToken;
|
|
40267
40242
|
}
|
|
40243
|
+
const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
|
|
40268
40244
|
return {
|
|
40269
40245
|
version,
|
|
40270
40246
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -40274,6 +40250,7 @@ function buildReadyFrame(deps, client) {
|
|
|
40274
40250
|
runningSessions: info.runningSessions,
|
|
40275
40251
|
tunnelUrl,
|
|
40276
40252
|
mode: deps.mode,
|
|
40253
|
+
daemonSource,
|
|
40277
40254
|
...fileSharing
|
|
40278
40255
|
};
|
|
40279
40256
|
}
|
|
@@ -41968,8 +41945,8 @@ async function startDaemon(config) {
|
|
|
41968
41945
|
onPtyData: (tsid, b64, seq) => manager.emitPtyChunk(tsid, b64, seq),
|
|
41969
41946
|
onPopupTransition: (tsid, kind, visible) => manager.emitPopupTransition(tsid, kind, visible),
|
|
41970
41947
|
onPtyReplayRegister: (tsid, replay) => manager.registerPtyReplay(tsid, replay),
|
|
41971
|
-
|
|
41972
|
-
|
|
41948
|
+
onDetectorRegister: (tsid, detector) => manager.registerDetector(tsid, detector),
|
|
41949
|
+
onDetectorUnregister: (tsid) => manager.unregisterDetector(tsid),
|
|
41973
41950
|
// ReadyGate v2:ReadyDetector emit ready 时投递 reducer 'ready-detected' input
|
|
41974
41951
|
onReady: (tsid) => manager.dispatchReadyDetected(tsid)
|
|
41975
41952
|
}) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
|
package/package.json
CHANGED