mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-21 18:46:47 +00:00
feat(core): migrate console calls to debugLogger (M3 Phase 6)
Migrate remaining console.* calls in packages/core utilities and services to use the structured DebugLogger pattern. This continues the Phase 6 migration work for utilities and helpers. Files migrated: - config/config.ts, core/client.ts, core/prompts.ts - core/anthropicContentGenerator, core/openaiContentGenerator - core/coreToolScheduler.ts, fallback/handler.ts - models/modelRegistry.ts, prompts/prompt-registry.ts - services/chatRecordingService.ts, sessionService.ts, loopDetectionService.ts - skills/skill-load.ts, skill-manager.ts - subagents/subagent.ts, subagent-manager.ts - utils: editor, environmentContext, fileUtils, getFolderStructure, installationManager, jsonl-utils, llm-edit-fixer, nextSpeakerChecker, openaiLogger, request-tokenizer/*, retry, ripgrepUtils, safeJsonParse, summarizer, systemEncoding, workspaceContext Remaining: utils/errorReporting.ts (13 calls)
This commit is contained in:
parent
78f6bd4d88
commit
45df0e8b82
34 changed files with 186 additions and 92 deletions
|
|
@ -1584,10 +1584,9 @@ export class Config {
|
|||
|
||||
if (!toolName) {
|
||||
// Log warning and skip this tool instead of crashing
|
||||
console.warn(
|
||||
`[Config] Skipping tool registration: ${className} is missing static Name property. ` +
|
||||
`Tools must define a static Name property to be registered. ` +
|
||||
`Location: config.ts:registerCoreTool`,
|
||||
this.debugLogger.warn(
|
||||
`Skipping tool registration: ${className} is missing static Name property. ` +
|
||||
`Tools must define a static Name property to be registered.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1596,8 +1595,8 @@ export class Config {
|
|||
try {
|
||||
registry.registerTool(new ToolClass(...args));
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[Config] Failed to register tool ${className} (${toolName}):`,
|
||||
this.debugLogger.error(
|
||||
`Failed to register tool ${className} (${toolName}):`,
|
||||
error,
|
||||
);
|
||||
throw error; // Re-throw after logging context
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ import { RequestTokenEstimator } from '../../utils/request-tokenizer/index.js';
|
|||
import { safeJsonParse } from '../../utils/safeJsonParse.js';
|
||||
import { AnthropicContentConverter } from './converter.js';
|
||||
import { buildRuntimeFetchOptions } from '../../utils/runtimeFetchOptions.js';
|
||||
import { createDebugLogger } from '../../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('ANTHROPIC');
|
||||
|
||||
type StreamingBlockState = {
|
||||
type: string;
|
||||
|
|
@ -117,7 +120,7 @@ export class AnthropicContentGenerator implements ContentGenerator {
|
|||
totalTokens: result.totalTokens,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
'Failed to calculate tokens with tokenizer, ' +
|
||||
'falling back to simple method:',
|
||||
error,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import type {
|
|||
|
||||
// Config
|
||||
import { ApprovalMode, type Config } from '../config/config.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('CLIENT');
|
||||
|
||||
// Core modules
|
||||
import type { ContentGenerator } from './contentGenerator.js';
|
||||
|
|
@ -262,9 +265,7 @@ export class GeminiClient {
|
|||
contextLines.join('\n'),
|
||||
];
|
||||
|
||||
if (this.config.getDebugMode()) {
|
||||
console.log(contextParts.join('\n'));
|
||||
}
|
||||
debugLogger.debug(contextParts.join('\n'));
|
||||
return {
|
||||
contextParts,
|
||||
newIdeContext: currentIdeContext,
|
||||
|
|
@ -394,9 +395,7 @@ export class GeminiClient {
|
|||
changeLines.join('\n'),
|
||||
];
|
||||
|
||||
if (this.config.getDebugMode()) {
|
||||
console.log(contextParts.join('\n'));
|
||||
}
|
||||
debugLogger.debug(contextParts.join('\n'));
|
||||
return {
|
||||
contextParts,
|
||||
newIdeContext: currentIdeContext,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ import type {
|
|||
AnyToolInvocation,
|
||||
ChatRecordingService,
|
||||
} from '../index.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('TOOL_SCHEDULER');
|
||||
import {
|
||||
ToolConfirmationOutcome,
|
||||
ApprovalMode,
|
||||
|
|
@ -1301,7 +1304,7 @@ export class CoreToolScheduler {
|
|||
this.setStatusInternal(pendingTool.request.callId, 'scheduled');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
debugLogger.error(
|
||||
`Error checking confirmation for tool ${pendingTool.request.callId}:`,
|
||||
error,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
import type { GenerateContentParameters } from '@google/genai';
|
||||
import { createDebugLogger } from '../../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('OPENAI_ERROR');
|
||||
|
||||
export interface RequestContext {
|
||||
userPromptId: string;
|
||||
|
|
@ -48,7 +51,7 @@ export class EnhancedErrorHandler implements ErrorHandler {
|
|||
const logPrefix = context.isStreaming
|
||||
? 'OpenAI API Streaming Error:'
|
||||
: 'OpenAI API Error:';
|
||||
console.error(logPrefix, errorMessage);
|
||||
debugLogger.error(logPrefix, errorMessage);
|
||||
}
|
||||
|
||||
// Provide helpful timeout-specific error message
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ import { EnhancedErrorHandler } from './errorHandler.js';
|
|||
import { RequestTokenEstimator } from '../../utils/request-tokenizer/index.js';
|
||||
import type { ContentGeneratorConfig } from '../contentGenerator.js';
|
||||
import { isAbortError } from '../../utils/errors.js';
|
||||
import { createDebugLogger } from '../../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('OPENAI');
|
||||
|
||||
export class OpenAIContentGenerator implements ContentGenerator {
|
||||
protected pipeline: ContentGenerationPipeline;
|
||||
|
|
@ -88,7 +91,7 @@ export class OpenAIContentGenerator implements ContentGenerator {
|
|||
totalTokens: result.totalTokens,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
'Failed to calculate tokens with new tokenizer, falling back to simple method:',
|
||||
error,
|
||||
);
|
||||
|
|
@ -152,7 +155,7 @@ export class OpenAIContentGenerator implements ContentGenerator {
|
|||
],
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('OpenAI API Embedding Error:', error);
|
||||
debugLogger.error('OpenAI API Embedding Error:', error);
|
||||
throw new Error(
|
||||
`OpenAI API error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import process from 'node:process';
|
|||
import { isGitRepository } from '../utils/gitUtils.js';
|
||||
import { QWEN_CONFIG_DIR } from '../tools/memoryTool.js';
|
||||
import type { GenerateContentConfig } from '@google/genai';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('PROMPTS');
|
||||
|
||||
export function resolvePathFromEnv(envVar?: string): {
|
||||
isSwitch: boolean;
|
||||
|
|
@ -46,7 +49,7 @@ export function resolvePathFromEnv(envVar?: string): {
|
|||
}
|
||||
} catch (error) {
|
||||
// If os.homedir() fails, we catch the error instead of crashing.
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Could not resolve home directory for path: ${trimmedEnvVar}`,
|
||||
error,
|
||||
);
|
||||
|
|
@ -774,7 +777,7 @@ function getToolCallExamples(model?: string): string {
|
|||
case 'general':
|
||||
return generalToolCallExamples;
|
||||
default:
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Unknown QWEN_CODE_TOOL_CALL_STYLE value: ${toolCallStyle}. Using model-based detection.`,
|
||||
);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
import type { Config } from '../config/config.js';
|
||||
import { AuthType } from '../core/contentGenerator.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('FALLBACK');
|
||||
|
||||
export async function handleFallback(
|
||||
config: Config,
|
||||
|
|
@ -56,17 +59,17 @@ async function handleQwenOAuthError(error?: unknown): Promise<string | null> {
|
|||
errorMessage.includes('too many requests');
|
||||
|
||||
if (isAuthError) {
|
||||
console.warn('Qwen OAuth authentication error detected:', errorMessage);
|
||||
debugLogger.warn('Qwen OAuth authentication error detected:', errorMessage);
|
||||
// The QwenContentGenerator should automatically handle token refresh
|
||||
// If it still fails, it likely means the refresh token is also expired
|
||||
console.log(
|
||||
debugLogger.info(
|
||||
'Note: If this persists, you may need to re-authenticate with Qwen OAuth',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isRateLimitError) {
|
||||
console.warn('Qwen API rate limit encountered:', errorMessage);
|
||||
debugLogger.warn('Qwen API rate limit encountered:', errorMessage);
|
||||
// For rate limiting, we don't need to do anything special
|
||||
// The retry mechanism will handle the backoff
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import {
|
|||
} from './types.js';
|
||||
import { DEFAULT_QWEN_MODEL } from '../config/models.js';
|
||||
import { QWEN_OAUTH_MODELS } from './constants.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('MODEL_REGISTRY');
|
||||
|
||||
export { QWEN_OAUTH_MODELS } from './constants.js';
|
||||
|
||||
|
|
@ -62,8 +65,8 @@ export class ModelRegistry {
|
|||
const authType = validateAuthTypeKey(rawKey);
|
||||
|
||||
if (!authType) {
|
||||
console.warn(
|
||||
`[ModelRegistry] Invalid authType key "${rawKey}" in modelProviders config. Expected one of: ${Object.values(AuthType).join(', ')}. Skipping.`,
|
||||
debugLogger.warn(
|
||||
`Invalid authType key "${rawKey}" in modelProviders config. Expected one of: ${Object.values(AuthType).join(', ')}. Skipping.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
import type { DiscoveredMCPPrompt } from '../tools/mcp-client.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('PROMPT_REGISTRY');
|
||||
|
||||
export class PromptRegistry {
|
||||
private prompts: Map<string, DiscoveredMCPPrompt> = new Map();
|
||||
|
|
@ -16,7 +19,7 @@ export class PromptRegistry {
|
|||
registerPrompt(prompt: DiscoveredMCPPrompt): void {
|
||||
if (this.prompts.has(prompt.name)) {
|
||||
const newName = `${prompt.serverName}_${prompt.name}`;
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Prompt with name "${prompt.name}" is already registered. Renaming to "${newName}".`,
|
||||
);
|
||||
this.prompts.set(newName, { ...prompt, name: newName });
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import {
|
|||
} from '@google/genai';
|
||||
import * as jsonl from '../utils/jsonl-utils.js';
|
||||
import { getGitBranch } from '../utils/gitUtils.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('CHAT_RECORDING');
|
||||
import type {
|
||||
ChatCompressionInfo,
|
||||
ToolCallResponseInfo,
|
||||
|
|
@ -247,7 +250,7 @@ export class ChatRecordingService {
|
|||
jsonl.writeLineSync(conversationFile, record);
|
||||
this.lastRecordUuid = record.uuid;
|
||||
} catch (error) {
|
||||
console.error('Error appending record:', error);
|
||||
debugLogger.error('Error appending record:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -266,7 +269,7 @@ export class ChatRecordingService {
|
|||
};
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving user message:', error);
|
||||
debugLogger.error('Error saving user message:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +303,7 @@ export class ChatRecordingService {
|
|||
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving assistant turn:', error);
|
||||
debugLogger.error('Error saving assistant turn:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,7 +347,7 @@ export class ChatRecordingService {
|
|||
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving tool result:', error);
|
||||
debugLogger.error('Error saving tool result:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +367,7 @@ export class ChatRecordingService {
|
|||
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving slash command record:', error);
|
||||
debugLogger.error('Error saving slash command record:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -384,7 +387,7 @@ export class ChatRecordingService {
|
|||
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving chat compression record:', error);
|
||||
debugLogger.error('Error saving chat compression record:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -402,7 +405,7 @@ export class ChatRecordingService {
|
|||
|
||||
this.appendRecord(record);
|
||||
} catch (error) {
|
||||
console.error('Error saving ui telemetry record:', error);
|
||||
debugLogger.error('Error saving ui telemetry record:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ import {
|
|||
isFunctionResponse,
|
||||
} from '../utils/messageInspectors.js';
|
||||
import { DEFAULT_QWEN_MODEL } from '../config/models.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('LOOP_DETECTION');
|
||||
|
||||
const TOOL_CALL_LOOP_THRESHOLD = 5;
|
||||
const CONTENT_LOOP_THRESHOLD = 10;
|
||||
|
|
@ -438,7 +441,7 @@ export class LoopDetectionService {
|
|||
if (typeof result['confidence'] === 'number') {
|
||||
if (result['confidence'] > 0.9) {
|
||||
if (typeof result['reasoning'] === 'string' && result['reasoning']) {
|
||||
console.warn(result['reasoning']);
|
||||
debugLogger.warn(result['reasoning']);
|
||||
}
|
||||
logLoopDetected(
|
||||
this.config,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import type {
|
|||
UiTelemetryRecordPayload,
|
||||
} from './chatRecordingService.js';
|
||||
import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SESSION');
|
||||
|
||||
/**
|
||||
* Session item for list display.
|
||||
|
|
@ -324,7 +327,7 @@ export class SessionService {
|
|||
return await jsonl.read<ChatRecord>(filePath);
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
console.error('Error reading session file:', error);
|
||||
debugLogger.error('Error reading session file:', error);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ import type { SkillConfig, SkillValidationResult } from './types.js';
|
|||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { parse as parseYaml } from '../utils/yaml-parser.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SKILL_LOAD');
|
||||
|
||||
const SKILL_MANIFEST_FILE = 'SKILL.md';
|
||||
|
||||
|
|
@ -26,7 +29,7 @@ export async function loadSkillsFromDir(
|
|||
const config = parseSkillContent(content, skillManifest);
|
||||
skills.push(config);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to parse skill at ${skillDir}: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import type {
|
|||
import { SkillError, SkillErrorCode } from './types.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { validateConfig } from './skill-load.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SKILL_MANAGER');
|
||||
|
||||
const QWEN_CONFIG_DIR = '.qwen';
|
||||
const SKILLS_CONFIG_DIR = 'skills';
|
||||
|
|
@ -57,7 +60,7 @@ export class SkillManager {
|
|||
try {
|
||||
listener();
|
||||
} catch (error) {
|
||||
console.warn('Skill change listener threw an error:', error);
|
||||
debugLogger.warn('Skill change listener threw an error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,7 +217,7 @@ export class SkillManager {
|
|||
stopWatching(): void {
|
||||
for (const watcher of this.watchers.values()) {
|
||||
void watcher.close().catch((error) => {
|
||||
console.warn('Failed to close skills watcher:', error);
|
||||
debugLogger.warn('Failed to close skills watcher:', error);
|
||||
});
|
||||
}
|
||||
this.watchers.clear();
|
||||
|
|
@ -426,7 +429,7 @@ export class SkillManager {
|
|||
// Skip directories without valid SKILL.md
|
||||
if (error instanceof SkillError) {
|
||||
// Parse error was already recorded
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to parse skill at ${skillDir}: ${error.message}`,
|
||||
);
|
||||
}
|
||||
|
|
@ -486,7 +489,7 @@ export class SkillManager {
|
|||
.get(existingPath)
|
||||
?.close()
|
||||
.catch((error) => {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to close skills watcher for ${existingPath}:`,
|
||||
error,
|
||||
);
|
||||
|
|
@ -508,11 +511,11 @@ export class SkillManager {
|
|||
this.scheduleRefresh();
|
||||
})
|
||||
.on('error', (error) => {
|
||||
console.warn(`Skills watcher error for ${watchPath}:`, error);
|
||||
debugLogger.warn(`Skills watcher error for ${watchPath}:`, error);
|
||||
});
|
||||
this.watchers.set(watchPath, watcher);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to watch skills directory at ${watchPath}:`,
|
||||
error,
|
||||
);
|
||||
|
|
@ -536,7 +539,7 @@ export class SkillManager {
|
|||
try {
|
||||
await fs.mkdir(baseDir, { recursive: true });
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to create user skills directory at ${baseDir}:`,
|
||||
error,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ import { SubagentError, SubagentErrorCode } from './types.js';
|
|||
import { SubagentValidator } from './validation.js';
|
||||
import { SubAgentScope } from './subagent.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SUBAGENT_MANAGER');
|
||||
import { BuiltinAgentRegistry } from './builtin-agents.js';
|
||||
import { ToolDisplayNamesMigration } from '../tools/tool-names.js';
|
||||
|
||||
|
|
@ -59,7 +62,7 @@ export class SubagentManager {
|
|||
try {
|
||||
listener();
|
||||
} catch (error) {
|
||||
console.warn('Subagent change listener threw an error:', error);
|
||||
debugLogger.warn('Subagent change listener threw an error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -699,7 +702,7 @@ export class SubagentManager {
|
|||
// If no match found, preserve the original identifier as-is
|
||||
// This allows for tools that might not be registered yet or custom tools
|
||||
result.push(toolIdentifier);
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Tool "${toolIdentifier}" not found in tool registry, preserving as-is`,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
import { reportError } from '../utils/errorReporting.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SUBAGENT');
|
||||
import { type ToolCallRequestInfo } from '../core/turn.js';
|
||||
import {
|
||||
CoreToolScheduler,
|
||||
|
|
@ -515,7 +518,7 @@ export class SubAgentScope {
|
|||
} as SubAgentRoundEvent);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during subagent execution:', error);
|
||||
debugLogger.error('Error during subagent execution:', error);
|
||||
this.terminateMode = SubagentTerminateMode.ERROR;
|
||||
this.eventEmitter?.emit(SubAgentEventType.ERROR, {
|
||||
subagentId: this.subagentId,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
import { execSync, spawn, spawnSync } from 'node:child_process';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('EDITOR');
|
||||
|
||||
export type EditorType =
|
||||
| 'vscode'
|
||||
|
|
@ -174,7 +177,7 @@ export async function openDiff(
|
|||
): Promise<void> {
|
||||
const diffCommand = getDiffCommand(oldPath, newPath, editor);
|
||||
if (!diffCommand) {
|
||||
console.error('No diff tool available. Install a supported editor.');
|
||||
debugLogger.error('No diff tool available. Install a supported editor.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +220,7 @@ export async function openDiff(
|
|||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
debugLogger.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
import type { Content, Part } from '@google/genai';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { getFolderStructure } from './getFolderStructure.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('ENV_CONTEXT');
|
||||
|
||||
/**
|
||||
* Generates a string describing the current workspace directories and their structures.
|
||||
|
|
@ -87,18 +90,18 @@ ${directoryContext}
|
|||
text: `\n--- Full File Context ---\n${result.llmContent}`,
|
||||
});
|
||||
} else {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
'Full context requested, but read_many_files returned no content.',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
'Full context requested, but read_many_files tool not found.',
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// Not using reportError here as it's a startup/config phase, not a chat/generation phase error.
|
||||
console.error('Error reading full file context:', error);
|
||||
debugLogger.error('Error reading full file context:', error);
|
||||
initialParts.push({
|
||||
text: '\n--- Error reading full file context ---',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import mime from 'mime/lite';
|
|||
import { ToolErrorType } from '../tools/tool-error.js';
|
||||
import { BINARY_EXTENSIONS } from './ignorePatterns.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('FILE_UTILS');
|
||||
|
||||
// Default values for encoding and separator format
|
||||
export const DEFAULT_ENCODING: BufferEncoding = 'utf-8';
|
||||
|
|
@ -218,7 +221,7 @@ export async function isBinaryFile(filePath: string): Promise<boolean> {
|
|||
// If >30% non-printable characters, consider it binary
|
||||
return nonPrintableCount / bytesRead > 0.3;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to check if file is binary: ${filePath}`,
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
|
|
@ -228,7 +231,7 @@ export async function isBinaryFile(filePath: string): Promise<boolean> {
|
|||
try {
|
||||
await fh.close();
|
||||
} catch (closeError) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to close file handle for: ${filePath}`,
|
||||
closeError instanceof Error ? closeError.message : String(closeError),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import { getErrorMessage, isNodeError } from './errors.js';
|
|||
import type { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
||||
import type { FileFilteringOptions } from '../config/constants.js';
|
||||
import { DEFAULT_FILE_FILTERING_OPTIONS } from '../config/constants.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('FOLDER_STRUCTURE');
|
||||
|
||||
const MAX_ITEMS = 20;
|
||||
const TRUNCATION_INDICATOR = '...';
|
||||
|
|
@ -104,7 +107,7 @@ async function readFullStructure(
|
|||
isNodeError(error) &&
|
||||
(error.code === 'EACCES' || error.code === 'ENOENT')
|
||||
) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Warning: Could not read directory ${currentPath}: ${error.message}`,
|
||||
);
|
||||
if (currentPath === rootPath && error.code === 'ENOENT') {
|
||||
|
|
@ -342,7 +345,10 @@ export async function getFolderStructure(
|
|||
|
||||
return `${summary}\n\n${resolvedPath}${path.sep}\n${structureLines.join('\n')}`;
|
||||
} catch (error: unknown) {
|
||||
console.error(`Error getting folder structure for ${resolvedPath}:`, error);
|
||||
debugLogger.error(
|
||||
`Error getting folder structure for ${resolvedPath}:`,
|
||||
error,
|
||||
);
|
||||
return `Error processing directory "${resolvedPath}": ${getErrorMessage(error)}`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import * as fs from 'node:fs';
|
|||
import { randomUUID } from 'node:crypto';
|
||||
import * as path from 'node:path';
|
||||
import { Storage } from '../config/storage.js';
|
||||
import { createDebugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('INSTALLATION');
|
||||
|
||||
export class InstallationManager {
|
||||
private getInstallationIdPath(): string {
|
||||
|
|
@ -48,7 +51,7 @@ export class InstallationManager {
|
|||
|
||||
return installationId;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
debugLogger.error(
|
||||
'Error accessing installation ID file, generating ephemeral ID:',
|
||||
error,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ import fs from 'node:fs';
|
|||
import path from 'node:path';
|
||||
import readline from 'node:readline';
|
||||
import { Mutex } from 'async-mutex';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('JSONL');
|
||||
|
||||
/**
|
||||
* A map of file paths to mutexes for preventing concurrent writes.
|
||||
|
|
@ -68,7 +71,7 @@ export async function readLines<T = unknown>(
|
|||
return results;
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
console.error(
|
||||
debugLogger.error(
|
||||
`Error reading first ${count} lines from ${filePath}:`,
|
||||
error,
|
||||
);
|
||||
|
|
@ -100,7 +103,7 @@ export async function read<T = unknown>(filePath: string): Promise<T[]> {
|
|||
return results;
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
console.error(`Error reading ${filePath}:`, error);
|
||||
debugLogger.error(`Error reading ${filePath}:`, error);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
|
@ -174,7 +177,7 @@ export async function countLines(filePath: string): Promise<number> {
|
|||
return count;
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
console.error(`Error counting lines in ${filePath}:`, error);
|
||||
debugLogger.error(`Error counting lines in ${filePath}:`, error);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ import { type BaseLlmClient } from '../core/baseLlmClient.js';
|
|||
import { LruCache } from './LruCache.js';
|
||||
import { DEFAULT_QWEN_FLASH_MODEL } from '../config/models.js';
|
||||
import { promptIdContext } from './promptIdContext.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('LLM_EDIT_FIXER');
|
||||
|
||||
const MAX_CACHE_SIZE = 50;
|
||||
|
||||
|
|
@ -112,7 +115,7 @@ export async function FixLLMEditWithInstruction(
|
|||
let promptId = promptIdContext.getStore();
|
||||
if (!promptId) {
|
||||
promptId = `llm-fixer-fallback-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Could not find promptId in context. This is unexpected. Using a fallback ID: ${promptId}`,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import { DEFAULT_QWEN_MODEL } from '../config/models.js';
|
|||
import type { GeminiChat } from '../core/geminiChat.js';
|
||||
import { isFunctionResponse } from './messageInspectors.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('NEXT_SPEAKER');
|
||||
|
||||
const CHECK_PROMPT = `Analyze *only* the content and structure of your immediately preceding response (your last turn in the conversation history). Based *strictly* on that response, determine who should logically speak next: the 'user' or the 'model' (you).
|
||||
**Decision Rules (apply in order):**
|
||||
|
|
@ -126,7 +129,7 @@ export async function checkNextSpeaker(
|
|||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
'Failed to talk to Gemini endpoint when seeing if conversation should continue.',
|
||||
error,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import * as path from 'node:path';
|
|||
import { promises as fs } from 'node:fs';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import * as os from 'os';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('OPENAI_LOGGER');
|
||||
|
||||
/**
|
||||
* Logger specifically for OpenAI API requests and responses
|
||||
|
|
@ -47,7 +50,7 @@ export class OpenAILogger {
|
|||
await fs.mkdir(this.logDir, { recursive: true });
|
||||
this.initialized = true;
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize OpenAI logger:', error);
|
||||
debugLogger.error('Failed to initialize OpenAI logger:', error);
|
||||
throw new Error(`Failed to initialize OpenAI logger: ${error}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +98,7 @@ export class OpenAILogger {
|
|||
await fs.writeFile(filePath, JSON.stringify(logData, null, 2), 'utf-8');
|
||||
return filePath;
|
||||
} catch (writeError) {
|
||||
console.error('Failed to write OpenAI log file:', writeError);
|
||||
debugLogger.error('Failed to write OpenAI log file:', writeError);
|
||||
throw new Error(`Failed to write OpenAI log file: ${writeError}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +126,7 @@ export class OpenAILogger {
|
|||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
return [];
|
||||
}
|
||||
console.error('Failed to read OpenAI log directory:', error);
|
||||
debugLogger.error('Failed to read OpenAI log directory:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +141,7 @@ export class OpenAILogger {
|
|||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
return JSON.parse(content);
|
||||
} catch (error) {
|
||||
console.error(`Failed to read log file ${filePath}:`, error);
|
||||
debugLogger.error(`Failed to read log file ${filePath}:`, error);
|
||||
throw new Error(`Failed to read log file: ${error}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
import type { ImageMetadata } from './types.js';
|
||||
import { isSupportedImageMimeType } from './supportedImageFormats.js';
|
||||
import { createDebugLogger } from '../debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('IMAGE_TOKENIZER');
|
||||
|
||||
/**
|
||||
* Image tokenizer for calculating image tokens based on dimensions
|
||||
|
|
@ -44,7 +47,7 @@ export class ImageTokenizer {
|
|||
try {
|
||||
// Check if the MIME type is supported
|
||||
if (!isSupportedImageMimeType(mimeType)) {
|
||||
console.warn(`Unsupported image format: ${mimeType}`);
|
||||
debugLogger.warn(`Unsupported image format: ${mimeType}`);
|
||||
// Return default metadata for unsupported formats
|
||||
return {
|
||||
width: 512,
|
||||
|
|
@ -65,7 +68,7 @@ export class ImageTokenizer {
|
|||
dataSize: buffer.length,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn('Failed to extract image metadata:', error);
|
||||
debugLogger.warn('Failed to extract image metadata:', error);
|
||||
// Return default metadata for fallback
|
||||
return {
|
||||
width: 512,
|
||||
|
|
@ -320,7 +323,7 @@ export class ImageTokenizer {
|
|||
const metadata = await this.extractImageMetadata(data, mimeType);
|
||||
results.push(this.calculateTokens(metadata));
|
||||
} catch (error) {
|
||||
console.warn('Error calculating tokens for image:', error);
|
||||
debugLogger.warn('Error calculating tokens for image:', error);
|
||||
// Return minimum tokens as fallback
|
||||
results.push(
|
||||
ImageTokenizer.MIN_TOKENS_PER_IMAGE +
|
||||
|
|
@ -499,7 +502,7 @@ export class ImageTokenizer {
|
|||
}
|
||||
|
||||
// Fallback: return default dimensions if we can't parse the structure
|
||||
console.warn('Could not extract HEIC dimensions, using default');
|
||||
debugLogger.warn('Could not extract HEIC dimensions, using default');
|
||||
return { width: 512, height: 512 };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import type {
|
|||
import type { TokenCalculationResult } from './types.js';
|
||||
import { TextTokenizer } from './textTokenizer.js';
|
||||
import { ImageTokenizer } from './imageTokenizer.js';
|
||||
import { createDebugLogger } from '../debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('TOKENIZER');
|
||||
|
||||
/**
|
||||
* Simple request token estimator that handles text and image content serially
|
||||
|
|
@ -77,7 +80,7 @@ export class RequestTokenizer {
|
|||
processingTime,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calculating tokens:', error);
|
||||
debugLogger.error('Error calculating tokens:', error);
|
||||
|
||||
// Fallback calculation
|
||||
const fallbackTokens = this.calculateFallbackTokens(request);
|
||||
|
|
@ -105,7 +108,7 @@ export class RequestTokenizer {
|
|||
// Avoid per-part rounding inflation by estimating once on the combined text.
|
||||
return await this.textTokenizer.calculateTokens(textContents.join(''));
|
||||
} catch (error) {
|
||||
console.warn('Error calculating text tokens:', error);
|
||||
debugLogger.warn('Error calculating text tokens:', error);
|
||||
// Fallback: character-based estimation
|
||||
const totalChars = textContents.join('').length;
|
||||
return Math.ceil(totalChars / 4);
|
||||
|
|
@ -125,7 +128,7 @@ export class RequestTokenizer {
|
|||
await this.imageTokenizer.calculateTokensBatch(imageContents);
|
||||
return tokenCounts.reduce((sum, count) => sum + count, 0);
|
||||
} catch (error) {
|
||||
console.warn('Error calculating image tokens:', error);
|
||||
debugLogger.warn('Error calculating image tokens:', error);
|
||||
// Fallback: minimum tokens per image
|
||||
return imageContents.length * 6; // 4 image tokens + 2 special tokens as minimum
|
||||
}
|
||||
|
|
@ -151,7 +154,7 @@ export class RequestTokenizer {
|
|||
// Rough estimate: 1 token per 100 bytes of audio data
|
||||
totalTokens += Math.max(Math.ceil(dataSize / 100), 10); // Minimum 10 tokens per audio
|
||||
} catch (error) {
|
||||
console.warn('Error calculating audio tokens:', error);
|
||||
debugLogger.warn('Error calculating audio tokens:', error);
|
||||
totalTokens += 10; // Fallback minimum
|
||||
}
|
||||
}
|
||||
|
|
@ -169,7 +172,7 @@ export class RequestTokenizer {
|
|||
// Treat other content as text, and avoid per-item rounding inflation.
|
||||
return await this.textTokenizer.calculateTokens(otherContents.join(''));
|
||||
} catch (error) {
|
||||
console.warn('Error calculating other content tokens:', error);
|
||||
debugLogger.warn('Error calculating other content tokens:', error);
|
||||
// Fallback: character-based estimation
|
||||
const totalChars = otherContents.join('').length;
|
||||
return Math.ceil(totalChars / 4);
|
||||
|
|
@ -184,7 +187,7 @@ export class RequestTokenizer {
|
|||
const content = JSON.stringify(request.contents);
|
||||
return Math.ceil(content.length / 4); // Rough estimate: 1 token ≈ 4 characters
|
||||
} catch (error) {
|
||||
console.warn('Error in fallback token calculation:', error);
|
||||
debugLogger.warn('Error in fallback token calculation:', error);
|
||||
return 100; // Conservative fallback
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +324,7 @@ export class RequestTokenizer {
|
|||
otherContents.push(serialized);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to serialize unknown part type:', error);
|
||||
debugLogger.warn('Failed to serialize unknown part type:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ export async function retryWithBackoff<T>(
|
|||
|
||||
if (delayDurationMs > 0) {
|
||||
// Respect Retry-After header if present and parsed
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Attempt ${attempt} failed with status ${delayErrorStatus ?? 'unknown'}. Retrying after explicit delay of ${delayDurationMs}ms...`,
|
||||
error,
|
||||
);
|
||||
|
|
@ -279,25 +279,25 @@ function logRetryAttempt(
|
|||
}
|
||||
|
||||
if (errorStatus === 429) {
|
||||
console.warn(message, error);
|
||||
debugLogger.warn(message, error);
|
||||
} else if (errorStatus && errorStatus >= 500 && errorStatus < 600) {
|
||||
console.error(message, error);
|
||||
debugLogger.error(message, error);
|
||||
} else if (error instanceof Error) {
|
||||
// Fallback for errors that might not have a status but have a message
|
||||
if (error.message.includes('429')) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Attempt ${attempt} failed with 429 error (no Retry-After header). Retrying with backoff...`,
|
||||
error,
|
||||
);
|
||||
} else if (error.message.match(/5\d{2}/)) {
|
||||
console.error(
|
||||
debugLogger.error(
|
||||
`Attempt ${attempt} failed with 5xx error. Retrying with backoff...`,
|
||||
error,
|
||||
);
|
||||
} else {
|
||||
console.warn(message, error); // Default to warn for other errors
|
||||
debugLogger.warn(message, error); // Default to warn for other errors
|
||||
}
|
||||
} else {
|
||||
console.warn(message, error); // Default to warn if error type is unknown
|
||||
debugLogger.warn(message, error); // Default to warn if error type is unknown
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import { fileURLToPath } from 'node:url';
|
|||
import { execFile } from 'node:child_process';
|
||||
import { fileExists } from './fileUtils.js';
|
||||
import { execCommand, isCommandAvailable } from './shell-utils.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('RIPGREP');
|
||||
|
||||
const RIPGREP_COMMAND = 'rg';
|
||||
const RIPGREP_BUFFER_LIMIT = 20_000_000; // Keep buffers aligned with the original bundle.
|
||||
|
|
@ -313,7 +316,7 @@ export async function runRipgrep(
|
|||
|
||||
// Log warnings for abnormal exits (except syntax errors)
|
||||
if (!syntaxError && truncated) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`ripgrep exited abnormally (signal=${error.signal} code=${error.code}) with stderr:\n${stderr.trim() || '(empty)'}`,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
import { jsonrepair } from 'jsonrepair';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('JSON_PARSE');
|
||||
|
||||
/**
|
||||
* Safely parse JSON string with jsonrepair fallback for malformed JSON.
|
||||
|
|
@ -34,7 +37,7 @@ export function safeJsonParse<T = Record<string, unknown>>(
|
|||
// jsonrepair always returns a string, so we need to parse it
|
||||
return JSON.parse(repairedJson) as T;
|
||||
} catch (repairError) {
|
||||
console.error('Failed to parse JSON even with jsonrepair:', {
|
||||
debugLogger.error('Failed to parse JSON even with jsonrepair:', {
|
||||
originalError: error,
|
||||
repairError,
|
||||
jsonString,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import type {
|
|||
import type { GeminiClient } from '../core/client.js';
|
||||
import { DEFAULT_QWEN_FLASH_MODEL } from '../config/models.js';
|
||||
import { getResponseText, partToString } from './partUtils.js';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('SUMMARIZER');
|
||||
|
||||
/**
|
||||
* A function that summarizes the result of a tool execution.
|
||||
|
|
@ -90,7 +93,7 @@ export async function summarizeToolOutput(
|
|||
)) as unknown as GenerateContentResponse;
|
||||
return getResponseText(parsedResponse) || textToSummarize;
|
||||
} catch (error) {
|
||||
console.error('Failed to summarize tool output.', error);
|
||||
debugLogger.error('Failed to summarize tool output.', error);
|
||||
return textToSummarize;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
import { execSync } from 'node:child_process';
|
||||
import os from 'node:os';
|
||||
import { detect as chardetDetect } from 'chardet';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('ENCODING');
|
||||
|
||||
// Cache for system encoding to avoid repeated detection
|
||||
// Use undefined to indicate "not yet checked" vs null meaning "checked but failed"
|
||||
|
|
@ -75,7 +78,7 @@ export function getSystemEncoding(): string | null {
|
|||
`Unable to parse Windows code page from 'chcp' output "${output.trim()}". `,
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
debugLogger.warn(
|
||||
`Failed to get Windows code page using 'chcp' command: ${error instanceof Error ? error.message : String(error)}. ` +
|
||||
`Will attempt to detect encoding from command output instead.`,
|
||||
);
|
||||
|
|
@ -97,7 +100,7 @@ export function getSystemEncoding(): string | null {
|
|||
.toString()
|
||||
.trim();
|
||||
} catch (_e) {
|
||||
console.warn('Failed to get locale charmap.');
|
||||
debugLogger.warn('Failed to get locale charmap.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +153,7 @@ export function windowsCodePageToEncoding(cp: number): string | null {
|
|||
return map[cp];
|
||||
}
|
||||
|
||||
console.warn(`Unable to determine encoding for windows code page ${cp}.`);
|
||||
debugLogger.warn(`Unable to determine encoding for windows code page ${cp}.`);
|
||||
return null; // Return null if no mapping found
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +171,7 @@ export function detectEncodingFromBuffer(buffer: Buffer): string | null {
|
|||
return detected.toLowerCase();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to detect encoding with chardet:', error);
|
||||
debugLogger.warn('Failed to detect encoding with chardet:', error);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import { isNodeError } from '../utils/errors.js';
|
|||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as process from 'node:process';
|
||||
import { createDebugLogger } from './debugLogger.js';
|
||||
|
||||
const debugLogger = createDebugLogger('WORKSPACE');
|
||||
|
||||
export type Unsubscribe = () => void;
|
||||
|
||||
|
|
@ -53,7 +56,7 @@ export class WorkspaceContext {
|
|||
listener();
|
||||
} catch (e) {
|
||||
// Don't let one listener break others.
|
||||
console.error('Error in WorkspaceContext listener:', e);
|
||||
debugLogger.error('Error in WorkspaceContext listener:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,8 +75,8 @@ export class WorkspaceContext {
|
|||
this.directories.add(resolved);
|
||||
this.notifyDirectoriesChanged();
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`[WARN] Skipping unreadable directory: ${directory} (${err instanceof Error ? err.message : String(err)})`,
|
||||
debugLogger.warn(
|
||||
`Skipping unreadable directory: ${directory} (${err instanceof Error ? err.message : String(err)})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue