From 3cd944bc3221df3130ee48d2c301fefe539357c2 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Fri, 1 May 2026 00:01:02 -0400 Subject: [PATCH] Remove mobile-fit debug logging, add debug skill doc Strip all mfLog file logging and console.log('[mobile-fit]') calls from production code. The skill doc at skills/mobile-fit-debug/SKILL.md documents how to temporarily re-add logging when needed. Co-authored-by: Orca --- .../app/h/[hostId]/session/[worktreeId].tsx | 6 +- skills/mobile-fit-debug/SKILL.md | 182 ++++++++++++++++++ src/main/ipc/pty.ts | 13 -- src/main/runtime/orca-runtime.ts | 73 ------- src/main/runtime/rpc/methods/terminal.ts | 45 +---- .../components/terminal-pane/TerminalPane.tsx | 3 - src/renderer/src/hooks/useIpcEvents.ts | 3 - 7 files changed, 185 insertions(+), 140 deletions(-) create mode 100644 skills/mobile-fit-debug/SKILL.md diff --git a/mobile/app/h/[hostId]/session/[worktreeId].tsx b/mobile/app/h/[hostId]/session/[worktreeId].tsx index 2b3f3a8d951..320dcfadf2e 100644 --- a/mobile/app/h/[hostId]/session/[worktreeId].tsx +++ b/mobile/app/h/[hostId]/session/[worktreeId].tsx @@ -210,7 +210,6 @@ export default function SessionScreen() { if (terminalUnsubsRef.current.has(handle)) return if (subscribingHandlesRef.current.has(handle)) return if (!getTerminalRef(handle)) { - console.log(`[mobile-fit] subscribeToTerminal SKIP handle=${handle} reason=no-ref`) return } @@ -319,12 +318,11 @@ export default function SessionScreen() { if (toggleInFlightRef.current.has(handle)) return const current = terminalModes.get(handle) ?? 'auto' const next: MobileDisplayMode = current === 'auto' || current === 'phone' ? 'desktop' : 'auto' - console.log(`[mobile-fit] toggleDisplayMode handle=${handle} current=${current} next=${next}`) toggleInFlightRef.current.add(handle) try { await client.sendRequest('terminal.setDisplayMode', { terminal: handle, mode: next }) - } catch (err) { - console.log(`[mobile-fit] toggleDisplayMode FAILED handle=${handle}`, err) + } catch { + // Mode change failed — server state unchanged, UI stays in sync. } finally { toggleInFlightRef.current.delete(handle) } diff --git a/skills/mobile-fit-debug/SKILL.md b/skills/mobile-fit-debug/SKILL.md new file mode 100644 index 00000000000..63535e24172 --- /dev/null +++ b/skills/mobile-fit-debug/SKILL.md @@ -0,0 +1,182 @@ +--- +name: mobile-fit-debug +description: Debug mobile terminal display-mode toggle and PTY resize issues. Use when investigating why a terminal restores to the wrong width after toggling between phone and desktop mode on mobile, or when PTY sizes are corrupted across tab switches. +--- + +# Mobile Fit Debug + +Use this skill when debugging mobile terminal display-mode toggle issues — wrong restore width, corrupted previousCols, stale PTY sizes, or collateral safeFit cascades. + +## Architecture Overview + +The mobile display-mode toggle involves **3 processes** communicating asynchronously: + +``` +Mobile App (React Native) Server (Electron main) Desktop Renderer (Electron renderer) +───────────────────────── ────────────────────── ──────────────────────────────────── +terminal.setDisplayMode ──RPC──► applyMobileDisplayMode + ├─ resize PTY (authoritative) + ├─ suppressResizesForMs(500) + ├─ terminalFitOverrideChanged ──IPC──► setOverrideTick (React re-render) + │ ├─ safeFit on ALL panes + │ └─ pty:resize IPC ──────► SUPPRESSED + └─ notifyTerminalResize ──stream──► mobile client updates +``` + +## Key Files + +| File | Role | +|------|------| +| `src/main/runtime/orca-runtime.ts` | Server-side state: `mobileSubscribers`, `mobileDisplayModes`, `lastRendererSizes`, suppress window. Core handlers: `handleMobileSubscribe`, `handleMobileUnsubscribe`, `applyMobileDisplayMode`, `onExternalPtyResize` | +| `src/main/ipc/pty.ts` | `pty:resize` IPC handler. Checks `isResizeSuppressed()` before processing. Calls `onExternalPtyResize` to update server state | +| `src/main/runtime/rpc/methods/terminal.ts` | RPC methods: `terminal.subscribe` (mobile subscription lifecycle), `terminal.setDisplayMode`, `terminal.getDisplayMode` | +| `src/renderer/src/lib/pane-manager/mobile-fit-overrides.ts` | Desktop renderer's override cache. `setFitOverride('desktop-fit')` clears the override. `notifyChange` fires `onOverrideChange` listeners | +| `src/renderer/src/lib/pane-manager/pane-tree-ops.ts` | `safeFit()` — measures pane DOM and resizes xterm. When a mobile-fit override exists, uses override dims instead of measuring | +| `src/renderer/src/components/terminal-pane/TerminalPane.tsx` | `onOverrideChange` handler triggers `setOverrideTick` re-render cascade. This is what causes safeFit to run on ALL panes | +| `mobile/app/h/[hostId]/session/[worktreeId].tsx` | Mobile session screen — tab switching, `toggleDisplayMode`, terminal subscription management | +| `src/main/runtime/mobile-subscribe-integration.test.ts` | Integration tests for the full subscribe/unsubscribe/toggle lifecycle | + +## Adding Debug Logging + +Production code has no debug logging. To investigate issues, temporarily add file-based logging to the key files. Here's a pattern that works well: + +### 1. Add mfLog helper to each file you want to instrument + +```typescript +// In orca-runtime.ts (no prefix): +import { appendFileSync } from 'fs' +function mfLog(msg: string): void { + try { appendFileSync('/tmp/mobile-fit-debug.log', `[${new Date().toISOString()}] ${msg}\n`) } catch {} +} + +// In pty.ts (prefix [pty-ipc]): +function mfLog(msg: string): void { + try { appendFileSync('/tmp/mobile-fit-debug.log', `[${new Date().toISOString()}] [pty-ipc] ${msg}\n`) } catch {} +} + +// In terminal.ts RPC methods (prefix [rpc]): +function mfLog(msg: string): void { + try { appendFileSync('/tmp/mobile-fit-debug.log', `[${new Date().toISOString()}] [rpc] ${msg}\n`) } catch {} +} +``` + +### 2. Useful log points + +**orca-runtime.ts — `handleMobileSubscribe`:** +```typescript +mfLog(`handleMobileSubscribe ptyId=${ptyId} mode=${mode} viewport=${viewport?.cols}x${viewport?.rows}`) +mfLog(` existing.prev=${existing?.previousCols}x${existing?.previousRows} currentSize=${currentSize?.cols}x${currentSize?.rows} rendererSize=${rendererSize?.cols}x${rendererSize?.rows}`) +mfLog(` → previousCols=${previousCols}`) +``` + +**orca-runtime.ts — `applyMobileDisplayMode`:** +```typescript +mfLog(`applyMobileDisplayMode ptyId=${ptyId} mode=${mode} sub.prev=${subscriber?.previousCols}x${subscriber?.previousRows}`) +mfLog(` DESKTOP RESTORE: previousCols=${previousCols}`) +``` + +**orca-runtime.ts — `onExternalPtyResize`:** +```typescript +mfLog(`onExternalPtyResize ptyId=${ptyId} cols=${cols} rows=${rows}`) +``` + +**pty.ts — `pty:resize` handler:** +```typescript +if (runtime?.isResizeSuppressed()) { + mfLog(`pty:resize SUPPRESSED id=${args.id} cols=${args.cols} rows=${args.rows}`) + return +} +mfLog(`pty:resize id=${args.id} cols=${args.cols} rows=${args.rows}`) +``` + +**terminal.ts — `terminal.subscribe`:** +```typescript +mfLog(`\n========== MOBILE SUBSCRIBE ==========`) +mfLog(`terminal.subscribe handle=${params.terminal} ptyId=${leaf?.ptyId} client=${params.client?.type}`) +``` + +### 3. Reading the log + +```bash +> /tmp/mobile-fit-debug.log # clear +# ... reproduce issue on mobile ... +cat /tmp/mobile-fit-debug.log # read +``` + +### 4. Remember to remove logging before committing + +Remove all `mfLog` functions, calls, and `appendFileSync` imports. + +## What to Look For in Logs + +**Wrong previousCols captured:** +``` +handleMobileSubscribe ptyId=...@@abc123 ... + existing.prev=null currentSize=105x72 rendererSize=214x72 <-- rendererSize is WRONG + → previousCols=214 <-- captured wrong value +``` +This means `lastRendererSizes` was polluted by a collateral safeFit cascade. + +**Suppress window too short:** +``` +[pty-ipc] pty:resize id=...@@abc123 cols=105 rows=72 <-- NOT suppressed, arrived after window +``` +If you see unsuppressed `pty:resize` events for terminals that weren't the one being toggled, the 500ms suppress window may be too short. Check the timestamp gap between `applyMobileDisplayMode` and the stale resize. + +**Suppress working correctly:** +``` +[pty-ipc] pty:resize SUPPRESSED id=...@@abc123 cols=214 rows=72 +``` + +**Collateral cascade pattern** (the root cause of most bugs): +``` +applyMobileDisplayMode ptyId=...@@split mode=desktop + DESKTOP RESTORE: previousCols=105 +[pty-ipc] pty:resize SUPPRESSED id=...@@split cols=105 <-- redundant, suppressed OK +[pty-ipc] pty:resize SUPPRESSED id=...@@other cols=214 <-- collateral, suppressed OK +``` +If the collateral line says `pty:resize id=` instead of `SUPPRESSED`, the cascade leaked through. + +## Known Gotchas + +### 1. The Collateral safeFit Cascade +When `terminalFitOverrideChanged` fires for ONE pane, the desktop renderer's `setOverrideTick` React state change triggers a re-render that runs `safeFit` on ALL panes across ALL tabs. Background-tab panes get measured at wrong widths because they may not be visible or may be in different split configurations than the active tab. + +### 2. Cascade Timing is ~360ms +The full cascade path: server sends IPC -> desktop renderer receives -> React re-render -> requestAnimationFrame -> DOM measurement -> `pty:resize` IPC back to server. This takes ~360ms, which is why the suppress window must be >360ms (currently 500ms). + +### 3. lastRendererSizes Persistence +`lastRendererSizes` stores every `pty:resize` from the desktop renderer. Stale values persist across mobile subscribe/unsubscribe cycles. The `lastRendererSizes.delete(ptyId)` in desktop restore is critical — without it, a stale 214 from a previous cascade gets used as `previousCols` on the next subscribe. + +### 4. Daemon Doesn't Hot-Reload +The daemon process (`out/main/daemon-entry.js`) loads compiled code once at startup. Changes to `orca-runtime.ts` or `pty.ts` require: +1. `npx electron-vite build --outDir out` (or wait for watcher) +2. **Restart the dev server** (`pnpm dev`) — the daemon subprocess won't pick up new builds + +Verify your code is live: `grep "your_unique_string" out/main/index.js` + +### 5. previousCols Priority Chain +```typescript +previousCols = existing?.previousCols ?? rendererSize?.cols ?? currentSize?.cols +``` +- `existing?.previousCols` — re-subscribe case (tab switch back), most trusted +- `rendererSize?.cols` — from `lastRendererSizes`, the desktop renderer's last `pty:resize` +- `currentSize?.cols` — from `getTerminalSize()`, the server-side PTY size + +If `rendererSize` is polluted (e.g. 214 for a split pane), it takes priority over the correct `currentSize`. That's why clearing `lastRendererSizes` on restore is essential. + +### 6. agent-device for Automated Testing +Use `/opt/homebrew/bin/agent-device` to automate mobile UI testing: +```bash +agent-device snapshot # accessibility tree +agent-device click @e45 # click element by ref +agent-device screenshot --out /tmp/s.png # capture screenshot +agent-device wait 2 # wait 2 seconds +``` +Typical test flow: click tab -> click "Switch to desktop mode" -> wait 3s -> click "Switch to phone mode" -> switch tabs -> repeat -> read `/tmp/mobile-fit-debug.log`. + +## Running Tests + +```bash +npx vitest run src/main/runtime/mobile-subscribe-integration.test.ts +``` diff --git a/src/main/ipc/pty.ts b/src/main/ipc/pty.ts index 9e3931c9d8b..d9f4565f6af 100644 --- a/src/main/ipc/pty.ts +++ b/src/main/ipc/pty.ts @@ -5,15 +5,6 @@ boundary. Splitting it by line count would scatter tightly coupled terminal process behavior across files without a cleaner ownership seam. */ import { join, delimiter } from 'path' import { randomUUID } from 'crypto' -import { appendFileSync } from 'fs' - -function mfLog(msg: string): void { - try { - appendFileSync('/tmp/mobile-fit-debug.log', `[${new Date().toISOString()}] [pty-ipc] ${msg}\n`) - } catch { - /* ignore */ - } -} import { type BrowserWindow, ipcMain, app } from 'electron' export { getBashShellReadyRcfileContent } from '../providers/local-pty-shell-ready' import type { OrcaRuntimeService } from '../runtime/orca-runtime' @@ -840,12 +831,8 @@ export function registerPtyHandlers( // of their correct split width. Suppressing ALL pty:resize during // this window prevents the cascade from corrupting PTY dimensions. if (runtime?.isResizeSuppressed()) { - mfLog( - `pty:resize SUPPRESSED (global window) id=${args.id} cols=${args.cols} rows=${args.rows}` - ) return } - mfLog(`pty:resize id=${args.id} cols=${args.cols} rows=${args.rows}`) ptySizes.set(args.id, { cols: args.cols, rows: args.rows }) getProviderForPty(args.id).resize(args.id, args.cols, args.rows) runtime?.onExternalPtyResize(args.id, args.cols, args.rows) diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index eb444697cdf..a88070803db 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -11,18 +11,6 @@ import { gitExecFileAsync, gitExecFileSync } from '../git/runner' import { isWslPath, parseWslPath, getWslHome } from '../wsl' import { randomUUID } from 'crypto' import { join } from 'path' -import { appendFileSync } from 'fs' - -const MOBILE_FIT_LOG = '/tmp/mobile-fit-debug.log' -function mfLog(msg: string): void { - const ts = new Date().toISOString() - const line = `[${ts}] ${msg}\n` - try { - appendFileSync(MOBILE_FIT_LOG, line) - } catch { - /* ignore */ - } -} import { rm } from 'fs/promises' import { OrchestrationDb } from './orchestration/db' import { formatMessagesForInjection } from './orchestration/formatter' @@ -1106,14 +1094,7 @@ export class OrcaRuntimeService { viewport?: { cols: number; rows: number } ): boolean { const mode = this.mobileDisplayModes.get(ptyId) ?? 'auto' - mfLog( - `handleMobileSubscribe ptyId=${ptyId} mode=${mode} viewport=${viewport ? `${viewport.cols}x${viewport.rows}` : 'none'}` - ) - console.log( - `[mobile-fit] handleMobileSubscribe ptyId=${ptyId} mode=${mode} viewport=${viewport ? `${viewport.cols}x${viewport.rows}` : 'none'}` - ) if (!viewport) { - console.log('[mobile-fit] → skipped (no viewport)') return false } @@ -1136,24 +1117,11 @@ export class OrcaRuntimeService { const previousCols = existing?.previousCols ?? rendererSize?.cols ?? currentSize?.cols ?? null const previousRows = existing?.previousRows ?? rendererSize?.rows ?? currentSize?.rows ?? null - mfLog( - ` existing.previousCols=${existing?.previousCols ?? 'null'} existing.previousRows=${existing?.previousRows ?? 'null'} existing.wasResized=${existing?.wasResizedToPhone ?? 'N/A'}` - ) - mfLog( - ` currentSize=${currentSize ? `${currentSize.cols}x${currentSize.rows}` : 'null'} rendererSize=${rendererSize ? `${rendererSize.cols}x${rendererSize.rows}` : 'null'}` - ) - mfLog(` → previousCols=${previousCols} previousRows=${previousRows}`) - mfLog( - ` allRendererSizes: ${JSON.stringify([...this.lastRendererSizes.entries()].map(([k, v]) => [k.slice(-12), `${v.cols}x${v.rows}`]))}` - ) - // Why: always register the subscriber so applyMobileDisplayMode can find // the viewport when the user later toggles from desktop to auto/phone. // Without this, toggling to auto after subscribing in desktop mode sees // hasSubscriber=false and can't perform the phone resize. if (mode === 'desktop') { - mfLog(` → SKIP (desktop mode), registering with null prev`) - console.log('[mobile-fit] → registered subscriber but skipped resize (desktop mode)') // Why: set previousCols/Rows to null so we don't capture a stale PTY // size that may not match the actual pane geometry (e.g. 214 when the // pane is in a split at 105). When the user later toggles to auto/phone, @@ -1184,14 +1152,6 @@ export class OrcaRuntimeService { // to a terminal that was left at phone dims (no restore on tab switch) // should not trigger another SIGWINCH → shell prompt redraw. const alreadyAtTarget = currentSize?.cols === clampedCols && currentSize?.rows === clampedRows - const prevSource = - existing?.previousCols != null ? 'existing' : rendererSize ? 'renderer' : 'pty' - mfLog( - ` → ${alreadyAtTarget ? 'ALREADY AT' : 'RESIZE TO'} ${clampedCols}x${clampedRows} src=${prevSource}` - ) - console.log( - `[mobile-fit] → ${alreadyAtTarget ? 'already at' : 'resizing PTY to'} ${clampedCols}x${clampedRows} (prev=${previousCols}x${previousRows} src=${prevSource}) notifier=${!!this.notifier}` - ) if (!alreadyAtTarget) { this.ptyController?.resize?.(ptyId, clampedCols, clampedRows) this.resizeHeadlessTerminal(ptyId, clampedCols, clampedRows) @@ -1217,20 +1177,12 @@ export class OrcaRuntimeService { // intermediate terminals keep their current dims harmlessly. handleMobileUnsubscribe(ptyId: string, clientId: string): void { const subscriber = this.mobileSubscribers.get(ptyId) - mfLog( - `handleMobileUnsubscribe ptyId=${ptyId} hasSub=${!!subscriber} wasResized=${subscriber?.wasResizedToPhone} prev=${subscriber?.previousCols}x${subscriber?.previousRows}` - ) - console.log( - `[mobile-fit] handleMobileUnsubscribe ptyId=${ptyId} hasSubscriber=${!!subscriber} wasResized=${subscriber?.wasResizedToPhone}` - ) if (!subscriber || subscriber.clientId !== clientId) { - mfLog(` → SKIP (no subscriber or clientId mismatch)`) return } const mode = this.mobileDisplayModes.get(ptyId) ?? 'auto' this.mobileSubscribers.delete(ptyId) - mfLog(` mode=${mode} deleted subscriber`) if (mode === 'auto' && subscriber.wasResizedToPhone) { const existing = this.pendingRestoreTimers.get(ptyId) @@ -1239,14 +1191,11 @@ export class OrcaRuntimeService { } const { previousCols, previousRows } = subscriber - mfLog(` scheduling delayed restore to ${previousCols}x${previousRows} in 300ms`) const timer = setTimeout(() => { this.pendingRestoreTimers.delete(ptyId) if (this.mobileSubscribers.has(ptyId)) { - mfLog(` delayed restore CANCELLED — new subscriber exists`) return } - mfLog(` delayed restore FIRING: ptyId=${ptyId} resize to ${previousCols}x${previousRows}`) if (previousCols != null && previousRows != null) { this.ptyController?.resize?.(ptyId, previousCols, previousRows) this.resizeHeadlessTerminal(ptyId, previousCols, previousRows) @@ -1275,19 +1224,10 @@ export class OrcaRuntimeService { applyMobileDisplayMode(ptyId: string): void { const mode = this.mobileDisplayModes.get(ptyId) ?? 'auto' const subscriber = this.mobileSubscribers.get(ptyId) - const rendererSize = this.lastRendererSizes.get(ptyId) - const currentSize = this.getTerminalSize(ptyId) - mfLog( - `applyMobileDisplayMode ptyId=${ptyId} mode=${mode} hasSub=${!!subscriber} wasResized=${subscriber?.wasResizedToPhone} sub.prev=${subscriber?.previousCols}x${subscriber?.previousRows} rendererSize=${rendererSize ? `${rendererSize.cols}x${rendererSize.rows}` : 'null'} currentSize=${currentSize ? `${currentSize.cols}x${currentSize.rows}` : 'null'}` - ) - console.log( - `[mobile-fit] applyMobileDisplayMode ptyId=${ptyId} mode=${mode} hasSubscriber=${!!subscriber} wasResized=${subscriber?.wasResizedToPhone}` - ) if (mode === 'desktop') { if (subscriber?.wasResizedToPhone) { const { previousCols, previousRows } = subscriber - mfLog(` DESKTOP RESTORE: previousCols=${previousCols} previousRows=${previousRows}`) if (previousCols != null && previousRows != null) { this.ptyController?.resize?.(ptyId, previousCols, previousRows) this.resizeHeadlessTerminal(ptyId, previousCols, previousRows) @@ -1311,7 +1251,6 @@ export class OrcaRuntimeService { ) } const size = this.getTerminalSize(ptyId) - mfLog(` NOTIFY desktop resize: ${size?.cols}x${size?.rows}`) this.notifyTerminalResize(ptyId, { cols: size?.cols ?? 0, rows: size?.rows ?? 0, @@ -1345,23 +1284,14 @@ export class OrcaRuntimeService { // the actual pane geometry instead of a stale PTY size for previousCols. onExternalPtyResize(ptyId: string, cols: number, rows: number): void { this.lastRendererSizes.set(ptyId, { cols, rows }) - mfLog(`onExternalPtyResize ptyId=${ptyId} cols=${cols} rows=${rows}`) const subscriber = this.mobileSubscribers.get(ptyId) if (!subscriber) { - mfLog(` no subscriber, stored in lastRendererSizes only`) return } if (!subscriber.wasResizedToPhone) { - mfLog( - ` updated subscriber.previousCols ${subscriber.previousCols}→${cols} previousRows ${subscriber.previousRows}→${rows}` - ) subscriber.previousCols = cols subscriber.previousRows = rows - } else { - mfLog( - ` SKIPPED (wasResizedToPhone=true, keeping prev=${subscriber.previousCols}x${subscriber.previousRows})` - ) } } @@ -1399,9 +1329,6 @@ export class OrcaRuntimeService { event: { cols: number; rows: number; displayMode: string; reason: string } ): void { const listeners = this.resizeListeners.get(ptyId) - mfLog( - `notifyTerminalResize ptyId=${ptyId} cols=${event.cols} rows=${event.rows} mode=${event.displayMode} reason=${event.reason} listenerCount=${listeners?.size ?? 0}` - ) if (!listeners) { return } diff --git a/src/main/runtime/rpc/methods/terminal.ts b/src/main/runtime/rpc/methods/terminal.ts index cd59a170586..f69a3fc9c84 100644 --- a/src/main/runtime/rpc/methods/terminal.ts +++ b/src/main/runtime/rpc/methods/terminal.ts @@ -1,17 +1,8 @@ /* oxlint-disable max-lines -- Why: terminal RPC methods are co-located for discoverability; splitting would scatter related handlers across files. */ import { z } from 'zod' -import { appendFileSync } from 'fs' import { defineMethod, defineStreamingMethod, type RpcAnyMethod } from '../core' import { OptionalFiniteNumber, OptionalString, requiredString } from '../schemas' -function mfLog(msg: string): void { - try { - appendFileSync('/tmp/mobile-fit-debug.log', `[${new Date().toISOString()}] [rpc] ${msg}\n`) - } catch { - /* ignore */ - } -} - const TerminalHandle = z.object({ terminal: requiredString('Missing terminal handle') }) @@ -247,12 +238,6 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ params: TerminalSetDisplayMode, handler: async (params, { runtime }) => { const leaf = runtime.resolveLeafForHandle(params.terminal) - mfLog( - `setDisplayMode handle=${params.terminal} mode=${params.mode} ptyId=${leaf?.ptyId ?? 'none'}` - ) - console.log( - `[mobile-fit] setDisplayMode handle=${params.terminal} mode=${params.mode} ptyId=${leaf?.ptyId ?? 'none'}` - ) if (!leaf?.ptyId) { throw new Error('no_connected_pty') } @@ -280,15 +265,6 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ handler: async (params, { runtime }, emit) => { let leaf = runtime.resolveLeafForHandle(params.terminal) const isMobile = params.client?.type === 'mobile' - if (isMobile) { - mfLog(`\n========== MOBILE SUBSCRIBE ==========`) - } - mfLog( - `terminal.subscribe handle=${params.terminal} ptyId=${leaf?.ptyId ?? 'none'} client=${params.client?.type ?? 'none'} viewport=${params.viewport ? `${params.viewport.cols}x${params.viewport.rows}` : 'none'}` - ) - console.log( - `[mobile-fit] terminal.subscribe handle=${params.terminal} ptyId=${leaf?.ptyId ?? 'none'} client=${params.client?.type ?? 'none'} viewport=${params.viewport ? `${params.viewport.cols}x${params.viewport.rows}` : 'none'}` - ) // Why: the left pane's PTY spawns asynchronously after the tab is created. // Mobile clients that subscribe before the PTY is ready would get a bare @@ -298,22 +274,12 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ try { const ptyId = await runtime.waitForLeafPtyId(params.terminal) leaf = { ptyId } - mfLog( - ` terminal.subscribe handle=${params.terminal} ptyId resolved to ${ptyId} after wait` - ) - console.log( - `[mobile-fit] terminal.subscribe handle=${params.terminal} ptyId resolved to ${ptyId} after wait` - ) } catch { - mfLog(` terminal.subscribe handle=${params.terminal} PTY wait timed out`) - console.log( - `[mobile-fit] terminal.subscribe handle=${params.terminal} PTY wait timed out, falling back` - ) + // PTY wait timed out — fall through to scrollback-only path below } } if (!leaf?.ptyId) { - mfLog(` terminal.subscribe handle=${params.terminal} no ptyId, sending scrollback+end`) const read = await runtime.readTerminal(params.terminal) emit({ type: 'scrollback', @@ -329,9 +295,6 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ const ptyId = leaf.ptyId const clientId = params.client?.id - mfLog( - ` terminal.subscribe resolved ptyId=${ptyId} clientId=${clientId ?? 'none'} isMobile=${isMobile}` - ) // Server-side auto-fit: resize PTY to phone dims before serializing scrollback if (isMobile && clientId) { @@ -361,9 +324,6 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ // mobile clients. They include fresh serialized scrollback so the client // can reinitialize xterm without resubscribing. const unsubscribeResize = runtime.subscribeToTerminalResize(ptyId, async (event) => { - mfLog( - ` terminal.subscribe RESIZE event ptyId=${ptyId} cols=${event.cols} rows=${event.rows} displayMode=${event.displayMode} reason=${event.reason}` - ) const fresh = await runtime.serializeTerminalBuffer(ptyId) emit({ type: 'resized', @@ -389,9 +349,6 @@ export const TERMINAL_METHODS: RpcAnyMethod[] = [ const subscriptionId = params.terminal runtime.registerSubscriptionCleanup(subscriptionId, () => { - mfLog( - ` terminal.subscribe CLEANUP ptyId=${ptyId} isMobile=${isMobile} clientId=${clientId ?? 'none'}` - ) unsubscribeData() unsubscribeResize() unsubscribeFit() diff --git a/src/renderer/src/components/terminal-pane/TerminalPane.tsx b/src/renderer/src/components/terminal-pane/TerminalPane.tsx index 9671d649255..49d27d8adc8 100644 --- a/src/renderer/src/components/terminal-pane/TerminalPane.tsx +++ b/src/renderer/src/components/terminal-pane/TerminalPane.tsx @@ -114,9 +114,6 @@ export default function TerminalPane({ useEffect( () => onOverrideChange((event) => { - console.log( - `[mobile-fit] desktop onOverrideChange ptyId=${event.ptyId} mode=${event.mode} cols=${event.cols} rows=${event.rows}` - ) setOverrideTick((n) => n + 1) if (event.mode === 'desktop-fit') { const paneIds = getPaneIdsForPty(event.ptyId) diff --git a/src/renderer/src/hooks/useIpcEvents.ts b/src/renderer/src/hooks/useIpcEvents.ts index 3470fcc3005..91f38c3e0e7 100644 --- a/src/renderer/src/hooks/useIpcEvents.ts +++ b/src/renderer/src/hooks/useIpcEvents.ts @@ -789,9 +789,6 @@ export function useIpcEvents(): void { unsubs.push( window.api.runtime.onTerminalFitOverrideChanged((event) => { - console.log( - `[mobile-fit] desktop received fitOverrideChanged ptyId=${event.ptyId} mode=${event.mode} cols=${event.cols} rows=${event.rows}` - ) setFitOverride(event.ptyId, event.mode, event.cols, event.rows) }) )