Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
ThinkingVerbsConfig,
TweakccConfig,
} from './types';
import { debug, expandTilde, deepMergeWithDefaults } from './utils';
import { debug, warn, expandTilde, deepMergeWithDefaults } from './utils';
import { hasUnappliedSystemPromptChanges } from './systemPromptHashIndex';
import {
migrateUserMessageDisplayToV320,
Expand Down Expand Up @@ -108,18 +108,16 @@ export const warnAboutMultipleConfigs = (): void => {
});

if (existingLocations.length > 0) {
console.warn(chalk.yellow('\nMultiple configuration locations detected:'));
console.warn(chalk.gray(` Active: ${configDir}`));
console.warn(chalk.gray(' Other existing locations:'));
warn(chalk.yellow('\nMultiple configuration locations detected:'));
warn(chalk.gray(` Active: ${configDir}`));
warn(chalk.gray(' Other existing locations:'));
existingLocations.forEach(loc => {
console.warn(chalk.gray(` - ${loc}`));
warn(chalk.gray(` - ${loc}`));
});
console.warn(
warn(
chalk.gray(' Only the active location is used. To switch locations,')
);
console.warn(
chalk.gray(' move your config.json to the desired directory.\n')
);
warn(chalk.gray(' move your config.json to the desired directory.\n'));
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/nativeInstallation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import fs from 'node:fs';
import { execSync } from 'node:child_process';
import LIEF from 'node-lief';
import { isDebug, debug } from './utils';
import { isDebug, debug, warn } from './utils';

/**
* Constants for Bun trailer and serialized layout sizes.
Expand Down Expand Up @@ -950,7 +950,7 @@ function repackMachO(
});
debug('repackMachO: Code signing completed successfully');
} catch (codesignError) {
console.warn(
warn(
'Warning: Failed to re-sign binary. The binary may not run correctly on macOS:',
codesignError
);
Expand Down
3 changes: 2 additions & 1 deletion src/patches/conversationTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { showDiff, getReactVar, getRequireFuncName } from './index';
import { writeSlashCommandDefinition as writeSlashCmd } from './slashCommands';
import { debug } from '../utils';

// ============================================================================
// SUB PATCH 1: Add /title slash command
Expand Down Expand Up @@ -541,7 +542,7 @@ export const writeConversationTitle = (oldFile: string): string | null => {
if (tmp) {
result = tmp;
} else {
console.log(
debug(
'patch: conversationTitle: step 5 failed (enableRenameConversationCommand)'
);
// It's okay if it fails--we'll not abort the whole operation.
Expand Down
7 changes: 4 additions & 3 deletions src/patches/fixLspSupport.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Please see the note about writing patches in ./index

import { escapeIdent, globalReplace, LocationResult, showDiff } from './index';
import { warn } from '../utils';

const getOpenDocumentLocation = (oldFile: string): LocationResult | null => {
// Step 1: Find `ensureServerStarted:[$\w]+`
Expand Down Expand Up @@ -109,21 +110,21 @@ export const writeFixLspSupport = (oldFile: string): string | null => {
const beforeReplace1 = content;
content = globalReplace(content, validationPattern1, '');
if (content === beforeReplace1) {
console.warn('patch: fixLspSupport: restartOnCrash validation not found');
warn('patch: fixLspSupport: restartOnCrash validation not found');
}

// Replace second validation
const beforeReplace2 = content;
content = globalReplace(content, validationPattern2, '');
if (content === beforeReplace2) {
console.warn('patch: fixLspSupport: startupTimeout validation not found');
warn('patch: fixLspSupport: startupTimeout validation not found');
}

// Replace third validation
const beforeReplace3 = content;
content = globalReplace(content, validationPattern3, '');
if (content === beforeReplace3) {
console.warn('patch: fixLspSupport: shutdownTimeout validation not found');
warn('patch: fixLspSupport: shutdownTimeout validation not found');
}

// Patch 2: Add the openDocument patch
Expand Down
23 changes: 11 additions & 12 deletions src/patches/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { escapeIdent } from '.';
import { debug } from '../utils';

export const findChalkVar = (fileContents: string): string | undefined => {
// Find chalk variable using the counting method
Expand Down Expand Up @@ -48,7 +49,7 @@ export const getModuleLoaderFunction = (
return match[1];
}

console.log(
debug(
'patch: getModuleLoaderFunction: failed to find module loader function'
);
return undefined;
Expand All @@ -65,9 +66,7 @@ export const getReactModuleNameNonBun = (
/var ([$\w]+)=[$\w]+\(\([$\w]+\)=>\{var [$\w]+=Symbol\.for\("react\.(transitional\.)?element"\)/;
const match = fileContents.match(pattern);
if (!match) {
console.log(
'patch: getReactModuleNameNonBun: failed to find React module name'
);
debug('patch: getReactModuleNameNonBun: failed to find React module name');
return undefined;
}
return match[1];
Expand All @@ -94,7 +93,7 @@ export const getReactModuleFunctionBun = (
): string | undefined => {
const reactModuleNameNonBun = getReactModuleNameNonBun(fileContents);
if (!reactModuleNameNonBun) {
console.log(
debug(
'^ patch: getReactModuleFunctionBun: failed to find React module name (Bun)'
);
return undefined;
Expand All @@ -106,7 +105,7 @@ export const getReactModuleFunctionBun = (
);
const match = fileContents.match(pattern);
if (!match) {
console.log(
debug(
`patch: getReactModuleFunctionBun: failed to find React module function (Bun) (reactModuleNameNonBun=${reactModuleNameNonBun})`
);
return undefined;
Expand All @@ -131,15 +130,15 @@ export const getReactVar = (fileContents: string): string | undefined => {

const moduleLoader = getModuleLoaderFunction(fileContents);
if (!moduleLoader) {
console.log('^ patch: getReactVar: failed to find moduleLoader');
debug('^ patch: getReactVar: failed to find moduleLoader');
reactVarCache = undefined;
return undefined;
}

// Try non-bun first (reactModuleNameNonBun)
const reactModuleVarNonBun = getReactModuleNameNonBun(fileContents);
if (!reactModuleVarNonBun) {
console.log('^ patch: getReactVar: failed to find reactModuleVarNonBun');
debug('^ patch: getReactVar: failed to find reactModuleVarNonBun');
reactVarCache = undefined;
return undefined;
}
Expand All @@ -159,7 +158,7 @@ export const getReactVar = (fileContents: string): string | undefined => {
// If reactModuleNameNonBun fails, try reactModuleFunctionBun
const reactModuleFunctionBun = getReactModuleFunctionBun(fileContents);
if (!reactModuleFunctionBun) {
console.log('^ patch: getReactVar: failed to find reactModuleFunctionBun');
debug('^ patch: getReactVar: failed to find reactModuleFunctionBun');
reactVarCache = undefined;
return undefined;
}
Expand All @@ -170,7 +169,7 @@ export const getReactVar = (fileContents: string): string | undefined => {
);
const bunMatch = fileContents.match(bunPattern);
if (!bunMatch) {
console.log(
debug(
`patch: getReactVar: failed to find bunPattern (moduleLoader=${moduleLoader}, reactModuleVarNonBun=${reactModuleVarNonBun}, reactModuleFunctionBun=${reactModuleFunctionBun})`
);
reactVarCache = undefined;
Expand Down Expand Up @@ -222,7 +221,7 @@ export const findRequireFunc = (fileContents: string): string | undefined => {
);
const requireFuncMatch = fileContents.match(requireFuncPattern);
if (!requireFuncMatch) {
console.log(
debug(
`patch: findRequireFunc: failed to find require function variable (createRequireVar=${createRequireVar})`
);
return undefined;
Expand Down Expand Up @@ -291,7 +290,7 @@ export const findTextComponent = (fileContents: string): string | undefined => {
/\bfunction ([$\w]+).{0,20}color:[$\w]+,backgroundColor:[$\w]+,dimColor:[$\w]+(?:=![01])?,bold:[$\w]+(?:=![01])?/;
const match = fileContents.match(textComponentPattern);
if (!match) {
console.log('patch: findTextComponent: failed to find text component');
debug('patch: findTextComponent: failed to find text component');
return undefined;
}
return match[1];
Expand Down
5 changes: 2 additions & 3 deletions src/patches/suppressNativeInstallerWarning.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { showDiff } from './index';
import { warn } from '../utils';

export const writeSuppressNativeInstallerWarning = (
file: string
Expand All @@ -9,9 +10,7 @@ export const writeSuppressNativeInstallerWarning = (
const match = file.match(pattern);

if (!match || match.index === undefined) {
console.warn(
'patch: suppressNativeInstallerWarning: failed to find pattern'
);
warn('patch: suppressNativeInstallerWarning: failed to find pattern');
return null;
}

Expand Down
15 changes: 11 additions & 4 deletions src/patches/systemPrompts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import chalk from 'chalk';
import { debug, stringifyRegex, verbose } from '../utils';
import { debug, warn, stringifyRegex, verbose } from '../utils';
import { showDiff, PatchResult, PatchGroup } from './index';
import {
loadSystemPromptsWithRegex,
Expand Down Expand Up @@ -127,12 +127,19 @@ export const applySystemPrompts = async (
// number by accounting for any frontmatter/comment lines.
const absoluteLineNum = lineNum + (prompt.contentLineOffset || 0);
const lineText = contentLines[lineNum - 1] || '';
console.log(
warn(
formatBacktickError(filePath, absoluteLineNum, lineText, columns)
);
console.log();
warn('');
}

results.push({
id: promptId,
name: prompt.name,
group: PatchGroup.SYSTEM_PROMPTS,
applied: false,
details: 'unescaped backticks',
});
continue; // Skip this prompt
}
}
Expand Down Expand Up @@ -201,7 +208,7 @@ export const applySystemPrompts = async (
details,
});
} else {
console.log(
debug(
chalk.yellow(
`Could not find system prompt "${prompt.name}" in cli.js (using regex ${stringifyRegex(pattern)})`
)
Expand Down
5 changes: 2 additions & 3 deletions src/systemPromptDownload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as fs from 'node:fs/promises';
import * as path from 'path';
import type { StringsFile } from './systemPromptSync';
import { PROMPT_CACHE_DIR } from './config';
import { warn } from './utils';

/**
* Downloads the strings file for a given CC version from GitHub
Expand Down Expand Up @@ -59,9 +60,7 @@ export async function downloadStringsFile(
'utf-8'
);
} catch (cacheError) {
console.warn(
`Failed to write to cache to ${cacheFilePath}: ${cacheError}`
);
warn(`Failed to write to cache to ${cacheFilePath}: ${cacheError}`);
}

return jsonData;
Expand Down
66 changes: 66 additions & 0 deletions src/tests/logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { isDebug, debug, warn } from '../utils';

describe('isDebug', () => {
const originalEnv = process.env.DEBUG;

beforeEach(() => {
delete process.env.DEBUG;
});

afterEach(() => {
if (originalEnv !== undefined) {
process.env.DEBUG = originalEnv;
} else {
delete process.env.DEBUG;
}
});

it('returns true when DEBUG=tweakcc', () => {
process.env.DEBUG = 'tweakcc';
expect(isDebug()).toBe(true);
});

it('returns true when DEBUG=*', () => {
process.env.DEBUG = '*';
expect(isDebug()).toBe(true);
});

it('returns false when DEBUG is unset', () => {
delete process.env.DEBUG;
expect(isDebug()).toBe(false);
});

it('returns false when DEBUG is set to another value', () => {
process.env.DEBUG = 'other-app';
expect(isDebug()).toBe(false);
});
});

describe('debug', () => {
it('only outputs when debug is enabled', () => {
const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
delete process.env.DEBUG;

debug('should not appear');
expect(spy).not.toHaveBeenCalled();

process.env.DEBUG = 'tweakcc';
debug('should appear');
expect(spy).toHaveBeenCalledWith('should appear');

spy.mockRestore();
delete process.env.DEBUG;
});
});

describe('warn', () => {
it('always outputs via console.warn', () => {
const spy = vi.spyOn(console, 'warn').mockImplementation(() => {});

warn('warning message');
expect(spy).toHaveBeenCalledWith('warning message');

spy.mockRestore();
});
});
17 changes: 16 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ let isDebugModeOn = false;
let isVerboseModeOn = false;
let isShowUnchangedOn = false;

/**
* Returns true when debug mode is active via --debug flag or DEBUG env var.
*/
export const isDebug = (): boolean => {
return isDebugModeOn;
if (isDebugModeOn) return true;
const debugEnv = process.env.DEBUG;
return debugEnv === 'tweakcc' || debugEnv === '*';
};
export const isVerbose = (): boolean => {
return isVerboseModeOn;
Expand All @@ -30,6 +35,9 @@ export const enableVerbose = (): void => {
export const enableShowUnchanged = (): void => {
isShowUnchangedOn = true;
};
/**
* Logs a message to stdout only when debug mode is enabled.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const debug = (message: any, ...optionalParams: any[]) => {
if (isDebug()) {
Expand All @@ -42,6 +50,13 @@ export const verbose = (message: any, ...optionalParams: any[]) => {
console.log(message, ...optionalParams);
}
};
/**
* Logs a warning message unconditionally via console.warn.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const warn = (message: any, ...optionalParams: any[]) => {
console.warn(message, ...optionalParams);
};

export function getCurrentClaudeCodeTheme(): string {
try {
Expand Down