Skip to content

Commit 095697a

Browse files
committed
refactor(tui): improve debug logging and error handling
- Add detailed debug logging throughout TUI launch process - Implement proper error handling in startTUI function - Add file existence check before reading theme storage - Wrap render call in try-catch block - Improve debug messages for better troubleshooting
1 parent d15ce9b commit 095697a

4 files changed

Lines changed: 85 additions & 37 deletions

File tree

src/cli/tui/app.tsx

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,22 +58,25 @@ export async function startTUI(
5858
knownMode?: "dark" | "light",
5959
initialToast?: InitialToast
6060
): Promise<void> {
61-
appDebug('[TUI] startTUI called, skipBackgroundDetection=%s', skipBackgroundDetection)
61+
appDebug('[TUI] startTUI function entered')
62+
appDebug('[TUI] skipBackgroundDetection=%s, knownMode=%s', skipBackgroundDetection, knownMode)
6263

6364
// Priority: 1. Saved theme from KV, 2. Known mode, 3. Auto-detect
6465
appDebug('[TUI] Getting saved theme')
6566
const savedTheme = await getSavedTheme()
6667
appDebug('[TUI] savedTheme=%s', savedTheme)
6768

69+
appDebug('[TUI] Resolving mode')
6870
const mode = savedTheme
6971
?? (skipBackgroundDetection && knownMode ? knownMode : null)
7072
?? await getTerminalBackgroundColor()
7173
appDebug('[TUI] Resolved mode=%s', mode)
7274

7375
// Wait for stdin to settle after background detection
7476
if (!skipBackgroundDetection) {
75-
appDebug('[TUI] Waiting for stdin to settle')
77+
appDebug('[TUI] Waiting for stdin to settle (100ms)')
7678
await new Promise((r) => setTimeout(r, 100))
79+
appDebug('[TUI] stdin settled')
7780
}
7881

7982
// Clear terminal before OpenTUI takes over
@@ -82,39 +85,50 @@ export async function startTUI(
8285
process.stdout.write('\x1b[2J\x1b[H\x1b[?25h')
8386
}
8487

85-
appDebug('[TUI] Starting OpenTUI render')
88+
appDebug('[TUI] About to create render Promise')
8689
return new Promise<void>((resolve) => {
90+
appDebug('[TUI] Inside Promise, creating VignetteEffect')
8791
const vignetteEffect = new VignetteEffect(0.35)
92+
appDebug('[TUI] VignetteEffect created, calling render()')
8893

89-
render(
90-
() => <Root mode={mode} initialToast={initialToast} onExit={() => {
91-
appDebug('[TUI] onExit called, closing TUI')
92-
closeTUILogger()
93-
if (process.stdout.isTTY) {
94-
process.stdout.write('\x1b[2J\x1b[H\x1b[?25h')
94+
try {
95+
render(
96+
() => {
97+
appDebug('[TUI] Root component render function called')
98+
return <Root mode={mode} initialToast={initialToast} onExit={() => {
99+
appDebug('[TUI] onExit called, closing TUI')
100+
closeTUILogger()
101+
if (process.stdout.isTTY) {
102+
process.stdout.write('\x1b[2J\x1b[H\x1b[?25h')
103+
}
104+
resolve()
105+
}} />
106+
},
107+
{
108+
targetFps: 60,
109+
gatherStats: false,
110+
exitOnCtrlC: false,
111+
useKittyKeyboard: { events: true },
112+
useMouse: true,
113+
postProcessFns: [
114+
(buffer) => {
115+
if (currentView === "workflow") return buffer
116+
return vignetteEffect.apply(buffer)
117+
},
118+
(buffer) => {
119+
if (currentView === "workflow") return buffer
120+
return applyScanlines(buffer, 0.92, 2)
121+
},
122+
],
95123
}
96-
resolve()
97-
}} />,
98-
{
99-
targetFps: 60,
100-
gatherStats: false,
101-
exitOnCtrlC: false,
102-
useKittyKeyboard: { events: true },
103-
useMouse: true,
104-
postProcessFns: [
105-
(buffer) => {
106-
if (currentView === "workflow") return buffer
107-
return vignetteEffect.apply(buffer)
108-
},
109-
(buffer) => {
110-
if (currentView === "workflow") return buffer
111-
return applyScanlines(buffer, 0.92, 2)
112-
},
113-
],
114-
}
115-
)
124+
)
125+
appDebug('[TUI] render() call completed')
126+
} catch (renderErr) {
127+
appDebug('[TUI] render() error: %s', renderErr)
128+
throw renderErr
129+
}
116130

117-
appDebug('[TUI] Render started, initializing TUI logger in 200ms')
131+
appDebug('[TUI] Setting up TUI logger timeout (200ms)')
118132
setTimeout(() => {
119133
appDebug('[TUI] Initializing TUI logger')
120134
initTUILogger()

src/cli/tui/launcher.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,22 @@ appDebug('[Launcher] isDev=%s', isDev);
2525
if (isDev) {
2626
appDebug('[Launcher] Loading OpenTUI preload');
2727
await import("@opentui/solid/preload")
28+
appDebug('[Launcher] OpenTUI preload loaded');
2829
}
2930

3031
// Dynamic import ensures app.js is loaded AFTER preload is registered (in dev)
3132
export async function startTUI() {
33+
appDebug('[Launcher] startTUI() called');
3234
appDebug('[Launcher] Importing TUI app module');
33-
const app = await import("./app.js");
34-
appDebug('[Launcher] Starting TUI app');
35-
return app.startTUI();
35+
try {
36+
const app = await import("./app.js");
37+
appDebug('[Launcher] app.js imported successfully');
38+
appDebug('[Launcher] Calling app.startTUI()');
39+
const result = await app.startTUI();
40+
appDebug('[Launcher] app.startTUI() returned');
41+
return result;
42+
} catch (err) {
43+
appDebug('[Launcher] Error: %s', err);
44+
throw err;
45+
}
3646
}

src/cli/tui/utils/theme-storage.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,35 @@
66

77
import { homedir } from "os"
88
import path from "path"
9+
import { appDebug } from "../../../shared/logging/logger.js"
910

1011
/**
1112
* Read saved theme from KV file (if exists)
1213
*/
1314
export async function getSavedTheme(): Promise<"dark" | "light" | null> {
15+
appDebug('[ThemeStorage] getSavedTheme called')
1416
try {
1517
const kvPath = path.join(homedir(), ".codemachine", "state", "kv.json")
18+
appDebug('[ThemeStorage] kvPath=%s', kvPath)
1619
const file = Bun.file(kvPath)
20+
21+
// Check if file exists before calling .json() - Bun crashes hard otherwise
22+
const exists = await file.exists()
23+
appDebug('[ThemeStorage] file exists=%s', exists)
24+
if (!exists) {
25+
appDebug('[ThemeStorage] File does not exist, returning null')
26+
return null
27+
}
28+
1729
const data = await file.json() as { theme?: string }
30+
appDebug('[ThemeStorage] data=%o', data)
1831
if (data.theme === "dark" || data.theme === "light") {
32+
appDebug('[ThemeStorage] Returning saved theme=%s', data.theme)
1933
return data.theme
2034
}
21-
} catch {
35+
appDebug('[ThemeStorage] No valid theme in data, returning null')
36+
} catch (err) {
37+
appDebug('[ThemeStorage] Error reading theme: %s', err)
2238
// File doesn't exist or invalid
2339
}
2440
return null

src/runtime/cli-setup.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,11 @@ export async function runCodemachineCli(argv: string[] = process.argv): Promise<
120120
.option('-d, --dir <path>', 'Target workspace directory', process.cwd())
121121
.option('--spec <path>', 'Path to the planning specification file', DEFAULT_SPEC_PATH)
122122
.action(async (options) => {
123+
appDebug('[CLI] Action handler entered');
123124
// Set CWD immediately (lightweight, no I/O)
124125
const cwd = options.dir || process.cwd();
125126
process.env.CODEMACHINE_CWD = cwd;
127+
appDebug('[CLI] CWD set to %s', cwd);
126128

127129
// Start background initialization (non-blocking, fire-and-forget)
128130
// This runs while TUI is visible and user is reading/thinking
@@ -134,10 +136,16 @@ export async function runCodemachineCli(argv: string[] = process.argv): Promise<
134136

135137
// Launch TUI immediately - don't wait for background init
136138
// Import via launcher to scope SolidJS transform to TUI only
137-
appDebug('[CLI] Launching TUI');
139+
appDebug('[CLI] Importing TUI launcher');
138140
const { startTUI } = await import('../cli/tui/launcher.js');
139-
await startTUI();
140-
appDebug('[CLI] TUI exited');
141+
appDebug('[CLI] TUI launcher imported, calling startTUI()');
142+
try {
143+
await startTUI();
144+
appDebug('[CLI] TUI exited normally');
145+
} catch (tuiError) {
146+
appDebug('[CLI] TUI error: %s', tuiError);
147+
throw tuiError;
148+
}
141149
});
142150

143151
// Lazy load CLI commands only if user uses subcommands

0 commit comments

Comments
 (0)