src — doctor
src — doctor
The src/doctor module is the diagnostic and self-healing component of the application. Its primary purpose is to inspect the current environment, system dependencies, and application configuration to identify potential issues that might hinder functionality. It provides a structured way to report these issues and, for many of them, offers automated fixes.
This module is crucial for ensuring a smooth user experience by proactively identifying and resolving common setup problems, making the application more robust and user-friendly.
Core Concepts
The module operates around two key interfaces:
DoctorCheck
Represents the result of a single diagnostic check.
export interface DoctorCheck {
name: string; class="hl-cmt">// A human-readable name for the check (e.g., "Node.js version")
status: 39;ok39; | 39;warn39; | 39;error39;; class="hl-cmt">// The severity of the check result
message: string; class="hl-cmt">// A detailed message explaining the status
fixable?: boolean; class="hl-cmt">// True if an automated fix is available
fix?: () => Promise<FixResult>; class="hl-cmt">// An optional async function to apply the fix
}
FixResult
Represents the outcome of an attempted fix operation.
export interface FixResult {
success: boolean; class="hl-cmt">// True if the fix was applied successfully
message: string; class="hl-cmt">// A message describing the outcome of the fix
action: string; class="hl-cmt">// A short identifier for the action performed (e.g., "create-codebuddy-dir")
}
How it Works: The Doctor Process
The diagnostic process involves two main stages, exposed through the module's public API:
- Running Checks: The
runDoctorChecksfunction orchestrates all individual diagnostic checks. It gathers their results into an array ofDoctorCheckobjects. - Applying Fixes: The
runFixesfunction takes an array ofDoctorCheckresults (typically fromrunDoctorChecks) and iterates through them. For any check marked asfixablewith an associatedfixfunction, it attempts to execute that fix.
graph TD
A[CLI Command] --> B{runDoctorChecks(cwd)}
B --> C(checkNodeVersion)
B --> D(checkDependencies)
B --> E(checkApiKeys)
B --> F(checkConfigFiles)
B --> G(checkStaleLockFiles)
B --> H(checkTtsProviders)
B --> I(checkDiskSpace)
B --> J(checkGit)
B -- Returns DoctorCheck[] --> K{Display Checks to User}
K -- User chooses to fix --> L{runFixes(DoctorCheck[])}
L --> M{For each fixable check}
M --> N(Call check.fix())
N -- Returns FixResult --> O{Display Fix Results}
Key Checks Explained
The module performs a comprehensive set of checks, categorized below:
System Environment Checks
These functions verify the presence and version of external tools and system resources.
checkNodeVersion(): Ensures the Node.js runtime meets the minimum version requirement (>= 18).checkDependencies(): Checks for essential command-line tools likeripgrep (rg),sox,RTK,ICM, and common audio players (ffplay,aplay,mpv). These are often optional but highly recommended for full functionality.checkTtsProviders(): Verifies the availability of Text-to-Speech (TTS) providers likeedge-ttsorespeak.checkDiskSpace(cwd: string): Reports on the available disk space in the current working directory, warning if it falls below 1 GB.checkGit(cwd: string): Confirmsgitis installed and whether the current working directory is part of a Git repository.
Helper:
commandExists(cmd: string): A utility function used by many checks to determine if a given command-line tool is available in the system's PATH.
Configuration Checks
These functions validate the application's internal configuration and directory structure.
checkApiKeys(): Inspects environment variables for required API keys (GROK_API_KEY,OPENAI_API_KEY, etc.), which are crucial for interacting with AI models.checkConfigFiles(cwd: string):- Verifies the existence of the
.codebuddydirectory. - Checks for the
config.jsonfile within.codebuddy. - Examines
settings.jsonfor JSON corruption and schema migration needs (e.g., missingmodel,maxToolRounds,themefields).
Helpers:
isJsonCorrupted(filePath: string): Determines if a given file contains valid JSON.checkSettingsMigration(filePath: string): Checks ifsettings.jsonis missing required fields, indicating a need for schema migration.
Runtime State Checks
These functions look for artifacts from previous runs that might indicate an issue.
checkStaleLockFiles(cwd: string): Scans common directories (.codebuddy,.codebuddy/daemon,.codebuddy/sessions) for.lockor.pidfiles older than one hour, which might indicate a crashed process or improper shutdown.
Helper:
findStaleLockFiles(cwd: string): Locates.lockand.pidfiles older than one hour within specified directories.
Fixing Issues
For many identified problems, the doctor module provides automated fix functions. These functions are designed to be idempotent where possible and log their actions using the logger.
fixMissingCodebuddyDir(cwd: string): Creates the.codebuddydirectory if it's missing.fixCorruptedSettings(cwd: string): Recreatessettings.jsonwith default values if it's found to be corrupted (invalid JSON).fixSettingsMigration(filePath: string): Merges missing default settings (likemodel,maxToolRounds,theme) into an existingsettings.jsonfile.fixStaleLockFiles(lockFiles: string[]): Deletes the specified list of stale lock files.
Module Architecture and Dependencies
The src/doctor/index.ts module is a self-contained unit for diagnostics and fixes.
- Internal Structure: It consists of a collection of
checkfunctions,fixfunctions, and several helper utilities. TherunDoctorChecksandrunFixesfunctions serve as the public API. - External Dependencies:
child_process: Used for executing system commands (execSync) to check for command existence or Git status.fs: Heavily used for file system operations (existsSync,mkdirSync,readFileSync,readdirSync,statSync,statfsSync,unlinkSync,writeFileSync) to inspect directories, read/write configuration, and manage lock files.path: Used for path manipulation (join) to construct file and directory paths correctly.../utils/logger.js: For logging informational messages and errors during fix operations.- Integration Points:
- Incoming Calls: The primary consumer of this module is the CLI, specifically the
registerUtilityCommandsincommands/cli/utility-commands.ts, which exposesdoctoranddoctor --fixcommands. It's also used extensively in unit and integration tests (doctor-fix.test.ts,doctor.test.ts). - Outgoing Calls: Beyond standard Node.js modules, it calls
logger.infofor reporting.
Usage
Developers can integrate the doctor module into various parts of the application, typically for pre-flight checks or maintenance tasks.
import { runDoctorChecks, runFixes, DoctorCheck, FixResult } from 39;./src/doctor/index.js39;;
async function performDiagnosticsAndFixes() {
console.log(39;Running diagnostic checks...39;);
const checks: DoctorCheck[] = await runDoctorChecks();
console.log(39;\n--- Doctor Report ---39;);
checks.forEach(check => {
console.log(`[${check.status.toUpperCase()}] ${check.name}: ${check.message}`);
});
const fixableChecks = checks.filter(check => check.fixable && check.status !== 39;ok39;);
if (fixableChecks.length > 0) {
console.log(`\nFound ${fixableChecks.length} fixable issues. Attempting to fix...`);
const fixResults: FixResult[] = await runFixes(fixableChecks);
console.log(39;\n--- Fix Results ---39;);
fixResults.forEach(result => {
console.log(`[${result.success ? 39;SUCCESS39; : 39;FAILURE39;}] ${result.action}: ${result.message}`);
});
} else {
console.log(39;\nNo fixable issues found.39;);
}
}
performDiagnosticsAndFixes();
Contributing
To add a new diagnostic check or fix:
- Implement a
check*function:
- Create a new function (e.g.,
checkNewFeatureDependency) that returns aDoctorCheckorDoctorCheck[]. - Determine its
status(ok,warn,error) andmessage. - If it's fixable, set
fixable: trueand provide anasync fixfunction.
- Implement a
fix*function (if applicable):
- Create an
asyncfunction (e.g.,fixNewFeatureDependency) that performs the necessary corrective action. - It should return a
FixResultindicating success or failure and a descriptive message. - Use
logger.infofor successful actions and handle errors gracefully.
- Integrate into
runDoctorChecks:
- Add your new
check*function to the array returned byrunDoctorChecks. Ensure it's placed logically with related checks.
- Test: Write unit tests to cover both the diagnostic check and the fix logic, ensuring it correctly identifies issues and applies fixes as expected.