botmux 2.74.0 → 2.75.1
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/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +23 -19
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +6 -0
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/adapters/hook-installer.d.ts +4 -0
- package/dist/adapters/hook-installer.d.ts.map +1 -1
- package/dist/adapters/hook-installer.js +32 -2
- package/dist/adapters/hook-installer.js.map +1 -1
- package/dist/bot-registry.d.ts +10 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +22 -5
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/pm2-command.d.ts +6 -0
- package/dist/cli/pm2-command.d.ts.map +1 -0
- package/dist/cli/pm2-command.js +7 -0
- package/dist/cli/pm2-command.js.map +1 -0
- package/dist/cli/stdin-encoding.d.ts +3 -0
- package/dist/cli/stdin-encoding.d.ts.map +1 -0
- package/dist/cli/stdin-encoding.js +19 -0
- package/dist/cli/stdin-encoding.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +48 -13
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +3 -1
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/maintenance.d.ts +18 -0
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +56 -4
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +1 -0
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +2 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-onboarding.d.ts +2 -0
- package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/bot-onboarding.js +2 -0
- package/dist/dashboard/bot-onboarding.js.map +1 -1
- package/dist/dashboard/hd2d-assets.d.ts +20 -0
- package/dist/dashboard/hd2d-assets.d.ts.map +1 -0
- package/dist/dashboard/hd2d-assets.js +216 -0
- package/dist/dashboard/hd2d-assets.js.map +1 -0
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +3 -0
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/office.d.ts +2 -0
- package/dist/dashboard/web/office.d.ts.map +1 -0
- package/dist/dashboard/web/office.js +140 -0
- package/dist/dashboard/web/office.js.map +1 -0
- package/dist/dashboard-web/app.js +327 -299
- package/dist/dashboard-web/game/index.apple-touch-icon.png +0 -0
- package/dist/dashboard-web/game/index.audio.position.worklet.js +66 -0
- package/dist/dashboard-web/game/index.audio.worklet.js +213 -0
- package/dist/dashboard-web/game/index.html +224 -0
- package/dist/dashboard-web/game/index.icon.png +0 -0
- package/dist/dashboard-web/game/index.js +909 -0
- package/dist/dashboard-web/game/index.png +0 -0
- package/dist/dashboard-web/index.html +1 -0
- package/dist/dashboard.js +87 -13
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +5 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +2 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.js +2 -2
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.js +2 -2
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +3 -1
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +66 -6
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/reply-mode-command.d.ts.map +1 -1
- package/dist/im/lark/reply-mode-command.js +4 -1
- package/dist/im/lark/reply-mode-command.js.map +1 -1
- package/dist/services/bridge-rotation-policy.d.ts +40 -0
- package/dist/services/bridge-rotation-policy.d.ts.map +1 -1
- package/dist/services/bridge-rotation-policy.js +38 -0
- package/dist/services/bridge-rotation-policy.js.map +1 -1
- package/dist/services/chat-reply-mode-store.d.ts +1 -1
- package/dist/services/chat-reply-mode-store.d.ts.map +1 -1
- package/dist/services/chat-reply-mode-store.js +8 -9
- package/dist/services/chat-reply-mode-store.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts +9 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +11 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/cli-selection.d.ts +65 -0
- package/dist/setup/cli-selection.d.ts.map +1 -0
- package/dist/setup/cli-selection.js +112 -0
- package/dist/setup/cli-selection.js.map +1 -0
- package/dist/setup/interactive-select.d.ts +30 -0
- package/dist/setup/interactive-select.d.ts.map +1 -0
- package/dist/setup/interactive-select.js +177 -0
- package/dist/setup/interactive-select.js.map +1 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +17 -3
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/ready-gate.d.ts +6 -0
- package/dist/utils/ready-gate.d.ts.map +1 -1
- package/dist/utils/ready-gate.js +6 -0
- package/dist/utils/ready-gate.js.map +1 -1
- package/dist/worker.js +105 -7
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
package/dist/worker.js
CHANGED
|
@@ -22,7 +22,7 @@ import { shouldSuppressBridgeEmit } from './services/bridge-fallback-gate.js';
|
|
|
22
22
|
import { shouldWriteNow } from './utils/input-gate.js';
|
|
23
23
|
import { ReadyGate, shouldArmReadyGate } from './utils/ready-gate.js';
|
|
24
24
|
import { InflightInputTracker } from './core/inflight-input-tracker.js';
|
|
25
|
-
import { shouldRunQuietRotation, evaluatePidResolverPullback, decideFingerprintSwitch, sessionIdFromJsonlPath, SESSION_ID_FILENAME_RE, } from './services/bridge-rotation-policy.js';
|
|
25
|
+
import { shouldRunQuietRotation, evaluatePidResolverPullback, decideFingerprintSwitch, shouldHealAbsentBaseline, sessionIdFromJsonlPath, SESSION_ID_FILENAME_RE, } from './services/bridge-rotation-policy.js';
|
|
26
26
|
import { CodexBridgeQueue } from './services/codex-bridge-queue.js';
|
|
27
27
|
import { drainCodexRollout, findCodexRolloutBySessionId, findCodexRolloutByPid, splitCodexEventsByCutoff, extractLastCodexTurn } from './services/codex-transcript.js';
|
|
28
28
|
import { findTraexRolloutBySessionId, findTraexRolloutByPid } from './services/traex-transcript.js';
|
|
@@ -39,6 +39,7 @@ import { t, setDefaultLocale } from './i18n/index.js';
|
|
|
39
39
|
import { TerminalRenderer } from './utils/terminal-renderer.js';
|
|
40
40
|
import { DEFAULT_RENDER_COLS, DEFAULT_RENDER_ROWS, MAX_RENDER_COLS, MAX_RENDER_ROWS, MIN_RENDER_COLS, MIN_RENDER_ROWS, clamp, resolveRenderDimensions, } from './utils/render-dimensions.js';
|
|
41
41
|
import { createCliAdapterSync, locateOnPath } from './adapters/cli/registry.js';
|
|
42
|
+
import { buildWrappedLaunch } from './setup/cli-selection.js';
|
|
42
43
|
import { claudeJsonlPathForSession, resolveJsonlFromPid, findOpenClaudeSessionIds, DEFAULT_CLAUDE_DATA_DIR } from './adapters/cli/claude-code.js';
|
|
43
44
|
import { mtrSessionIdForBotmuxSession } from './adapters/cli/mtr.js';
|
|
44
45
|
import { HerdrBackend } from './adapters/backend/herdr-backend.js';
|
|
@@ -147,6 +148,41 @@ let readySignalTimer = null;
|
|
|
147
148
|
* back. The real signal lands within ~ms of the input box rendering, so this is
|
|
148
149
|
* pure insurance against a missing/failed hook — generous but bounded. */
|
|
149
150
|
const READY_SIGNAL_TIMEOUT_MS = 45_000;
|
|
151
|
+
/** Epoch ms of the most recent PTY output — used to settle for quiescence
|
|
152
|
+
* before the first flush (see settleThenFlush). */
|
|
153
|
+
let lastPtyOutputAtMs = 0;
|
|
154
|
+
/** After the SessionStart signal fires, the input box has appeared but Ink's
|
|
155
|
+
* startup render isn't fully drained yet — typing immediately trips Claude's
|
|
156
|
+
* paste-burst heuristic and the `\` soft-newline markers (claude-code
|
|
157
|
+
* writeInput) get kept literally. This is pronounced under wrapperCli launchers
|
|
158
|
+
* (e.g. `aiden x claude`) whose Claude renders more at startup. So we wait for
|
|
159
|
+
* the PTY to fall quiet for SETTLE_MS before the first flush — the signal still
|
|
160
|
+
* gates readiness (anti-selector), the settle just lets the render drain. */
|
|
161
|
+
const READY_FLUSH_SETTLE_MS = 1_000;
|
|
162
|
+
/** Upper bound on the settle so a chatty startup (spinners, periodic redraw)
|
|
163
|
+
* can't stall the first prompt indefinitely. */
|
|
164
|
+
const READY_FLUSH_SETTLE_CAP_MS = 6_000;
|
|
165
|
+
let readyFlushSettleTimer = null;
|
|
166
|
+
/** True while the post-signal quiescence settle is in progress — flushPending
|
|
167
|
+
* holds (just like the gate) so a message arriving mid-settle can't type-ahead
|
|
168
|
+
* past the settle and re-trigger paste-burst. */
|
|
169
|
+
let isSettlingFirstFlush = false;
|
|
170
|
+
/** Wait until the PTY has been quiet for READY_FLUSH_SETTLE_MS (Ink render
|
|
171
|
+
* drained), capped at READY_FLUSH_SETTLE_CAP_MS, then flush the held prompt. */
|
|
172
|
+
function settleThenFlush(startedAtMs) {
|
|
173
|
+
readyFlushSettleTimer = null;
|
|
174
|
+
const now = Date.now();
|
|
175
|
+
const quietForMs = now - lastPtyOutputAtMs;
|
|
176
|
+
if (quietForMs >= READY_FLUSH_SETTLE_MS || now - startedAtMs >= READY_FLUSH_SETTLE_CAP_MS) {
|
|
177
|
+
isSettlingFirstFlush = false;
|
|
178
|
+
log(`Ready-gate settle done (quiet ${quietForMs}ms); delivering held first prompt`);
|
|
179
|
+
void flushPending();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const wait = Math.min(READY_FLUSH_SETTLE_MS - quietForMs, READY_FLUSH_SETTLE_CAP_MS - (now - startedAtMs));
|
|
183
|
+
readyFlushSettleTimer = setTimeout(() => settleThenFlush(startedAtMs), Math.max(50, wait));
|
|
184
|
+
readyFlushSettleTimer.unref?.();
|
|
185
|
+
}
|
|
150
186
|
/** Release the ready-gate and flush anything it held. No-op when the gate was
|
|
151
187
|
* never armed (other CLIs / adopt) or already released (idempotent). */
|
|
152
188
|
function releaseReadyGate(reason) {
|
|
@@ -155,8 +191,13 @@ function releaseReadyGate(reason) {
|
|
|
155
191
|
readySignalTimer = null;
|
|
156
192
|
}
|
|
157
193
|
if (readyGate.receive()) {
|
|
158
|
-
log(`Ready gate released (${reason});
|
|
159
|
-
|
|
194
|
+
log(`Ready gate released (${reason}); settling for PTY quiescence before first flush`);
|
|
195
|
+
if (readyFlushSettleTimer) {
|
|
196
|
+
clearTimeout(readyFlushSettleTimer);
|
|
197
|
+
readyFlushSettleTimer = null;
|
|
198
|
+
}
|
|
199
|
+
isSettlingFirstFlush = true;
|
|
200
|
+
settleThenFlush(Date.now());
|
|
160
201
|
}
|
|
161
202
|
}
|
|
162
203
|
const pendingMessages = [];
|
|
@@ -1375,8 +1416,28 @@ function bridgeMarkPendingTurn(messageText, preferredTurnId) {
|
|
|
1375
1416
|
if (!bridgeJsonlPath)
|
|
1376
1417
|
return undefined;
|
|
1377
1418
|
if (!bridgeBaselineDone) {
|
|
1378
|
-
|
|
1379
|
-
|
|
1419
|
+
// Self-heal a stuck baseline: the guessed transcript path never
|
|
1420
|
+
// materialised (Claude wrote under a different sessionId, a stale resume
|
|
1421
|
+
// id, or an /adopt sid persisted as the botmux sid). An absent file has
|
|
1422
|
+
// no history to absorb, so arm fresh-empty readiness so THIS turn gets
|
|
1423
|
+
// marked — the mark arms the per-tick exact-content fingerprint recovery,
|
|
1424
|
+
// which finds the jsonl Claude actually wrote this message to and switches
|
|
1425
|
+
// the bridge onto it (no dependence on Claude-internal pid files, so
|
|
1426
|
+
// version-robust). See shouldHealAbsentBaseline for the full rationale.
|
|
1427
|
+
if (shouldHealAbsentBaseline({
|
|
1428
|
+
baselineDone: bridgeBaselineDone,
|
|
1429
|
+
hasJsonlPath: !!bridgeJsonlPath,
|
|
1430
|
+
jsonlFileExists: existsSyncSafe(bridgeJsonlPath),
|
|
1431
|
+
})) {
|
|
1432
|
+
bridgeOffset = 0;
|
|
1433
|
+
bridgePendingTail = '';
|
|
1434
|
+
bridgeBaselineDone = true;
|
|
1435
|
+
log(`Bridge baseline self-healed: guessed transcript ${bridgeJsonlPath} absent; fresh-empty readiness armed for fingerprint recovery`);
|
|
1436
|
+
}
|
|
1437
|
+
else {
|
|
1438
|
+
log('Bridge baseline not ready — this turn will not have transcript-driven final_output');
|
|
1439
|
+
return undefined;
|
|
1440
|
+
}
|
|
1380
1441
|
}
|
|
1381
1442
|
const fingerprint = makeFingerprint(messageText);
|
|
1382
1443
|
// Full normalised content powers the unknown-sid recovery path. When a
|
|
@@ -2785,7 +2846,9 @@ function onPtyData(data) {
|
|
|
2785
2846
|
return;
|
|
2786
2847
|
}
|
|
2787
2848
|
}
|
|
2788
|
-
//
|
|
2849
|
+
// Track last PTY output time for the ready-gate quiescence settle (see
|
|
2850
|
+
// settleThenFlush) and delegate idle detection to IdleDetector.
|
|
2851
|
+
lastPtyOutputAtMs = Date.now();
|
|
2789
2852
|
idleDetector?.feed(data);
|
|
2790
2853
|
}
|
|
2791
2854
|
function markPromptReady() {
|
|
@@ -2970,6 +3033,12 @@ async function flushPending() {
|
|
|
2970
3033
|
log(`Holding ${pendingMessages.length} pending message(s) until SessionStart ready signal`);
|
|
2971
3034
|
return;
|
|
2972
3035
|
}
|
|
3036
|
+
// Post-signal quiescence settle in progress — hold so the first write lands
|
|
3037
|
+
// after Ink's startup render has drained (else paste-burst keeps `\` literal).
|
|
3038
|
+
if (isSettlingFirstFlush) {
|
|
3039
|
+
log(`Holding ${pendingMessages.length} pending message(s) until ready-gate settle completes`);
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
2973
3042
|
// Type-ahead adapters flush even while the CLI is busy; others wait for
|
|
2974
3043
|
// idle. Claude bridge fallback used to also disable type-ahead because
|
|
2975
3044
|
// BridgeTurnQueue.ingest didn't recognise the `attachment(queued_command)`
|
|
@@ -3838,6 +3907,23 @@ function spawnCli(cfg) {
|
|
|
3838
3907
|
throw err;
|
|
3839
3908
|
}
|
|
3840
3909
|
}
|
|
3910
|
+
// 通用启动前缀(wrapperCli):把启动命令重写成 `<wrapperCli> <CLI 参数>`(首 token 当
|
|
3911
|
+
// bin 走 PATH 解析),无需 wrapper 脚本、跨系统。aiden x claude 形态会剥掉 aiden 拒收的
|
|
3912
|
+
// --settings(见 buildWrappedLaunch)。与文件沙盒互斥:沙盒已把命令重写成 bwrap,叠加
|
|
3913
|
+
// 前缀会破坏隔离,故 sandboxOn 时跳过并告警(网关 + oncall 沙盒本就不是合理组合)。
|
|
3914
|
+
if (cfg.wrapperCli && cfg.wrapperCli.trim()) {
|
|
3915
|
+
if (sandboxOn) {
|
|
3916
|
+
log(`wrapperCli="${cfg.wrapperCli}" ignored: file sandbox enabled and takes precedence (cannot combine launch prefix with bwrap)`);
|
|
3917
|
+
}
|
|
3918
|
+
else {
|
|
3919
|
+
const launch = buildWrappedLaunch(cfg.wrapperCli, spawnArgs, (b) => locateOnPath(b) ?? b);
|
|
3920
|
+
if (launch.bin) {
|
|
3921
|
+
spawnBin = launch.bin;
|
|
3922
|
+
spawnArgs = launch.args;
|
|
3923
|
+
log(`Launch prefix: spawning ${spawnBin} ${spawnArgs.slice(0, 2).join(' ')} … (cliId=${cfg.cliId})`);
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3841
3927
|
backend.spawn(spawnBin, spawnArgs, {
|
|
3842
3928
|
cwd: spawnCwd,
|
|
3843
3929
|
cols: PTY_COLS,
|
|
@@ -4010,6 +4096,13 @@ function spawnCli(cfg) {
|
|
|
4010
4096
|
clearTimeout(readySignalTimer);
|
|
4011
4097
|
readySignalTimer = null;
|
|
4012
4098
|
}
|
|
4099
|
+
if (readyFlushSettleTimer) {
|
|
4100
|
+
clearTimeout(readyFlushSettleTimer);
|
|
4101
|
+
readyFlushSettleTimer = null;
|
|
4102
|
+
}
|
|
4103
|
+
isSettlingFirstFlush = false;
|
|
4104
|
+
// Reset quiescence baseline so the settle measures silence from THIS spawn.
|
|
4105
|
+
lastPtyOutputAtMs = Date.now();
|
|
4013
4106
|
if (shouldArmReadyGate({
|
|
4014
4107
|
injectsReadyHook: cliAdapter.injectsReadyHook === true,
|
|
4015
4108
|
adoptMode: cfg.adoptMode === true,
|
|
@@ -4092,11 +4185,16 @@ function spawnCli(cfg) {
|
|
|
4092
4185
|
function killCli() {
|
|
4093
4186
|
idleDetector?.dispose();
|
|
4094
4187
|
idleDetector = null;
|
|
4095
|
-
// Cancel any pending ready-gate fallback
|
|
4188
|
+
// Cancel any pending ready-gate fallback / settle timers; spawnCli re-arms on respawn.
|
|
4096
4189
|
if (readySignalTimer) {
|
|
4097
4190
|
clearTimeout(readySignalTimer);
|
|
4098
4191
|
readySignalTimer = null;
|
|
4099
4192
|
}
|
|
4193
|
+
if (readyFlushSettleTimer) {
|
|
4194
|
+
clearTimeout(readyFlushSettleTimer);
|
|
4195
|
+
readyFlushSettleTimer = null;
|
|
4196
|
+
}
|
|
4197
|
+
isSettlingFirstFlush = false;
|
|
4100
4198
|
stopScreenAnalyzer();
|
|
4101
4199
|
stopScreenUpdates();
|
|
4102
4200
|
backend?.kill();
|