Skip to content

Commit

Permalink
Merge pull request #347 from yamadashy/feat/quiet
Browse files Browse the repository at this point in the history
feat(cli): Add quiet mode option
  • Loading branch information
yamadashy authored Feb 11, 2025
2 parents 3d1d5da + dd999d8 commit 78374fc
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 89 deletions.
12 changes: 6 additions & 6 deletions src/cli/actions/defaultAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { type PackResult, pack } from '../../core/packager.js';
import { rethrowValidationErrorIfZodError } from '../../shared/errorHandle.js';
import { logger } from '../../shared/logger.js';
import { printCompletion, printSecurityCheck, printSummary, printTopFiles } from '../cliPrint.js';
import type { CliOptions } from '../cliRun.js';
import Spinner from '../cliSpinner.js';
import type { CliOptions } from '../types.js';
import { runMigrationAction } from './migrationAction.js';

export interface DefaultActionRunnerResult {
Expand All @@ -23,19 +23,19 @@ export interface DefaultActionRunnerResult {
export const runDefaultAction = async (
directories: string[],
cwd: string,
options: CliOptions,
cliOptions: CliOptions,
): Promise<DefaultActionRunnerResult> => {
logger.trace('Loaded CLI options:', options);
logger.trace('Loaded CLI options:', cliOptions);

// Run migration before loading config
await runMigrationAction(cwd);

// Load the config file
const fileConfig: RepomixConfigFile = await loadFileConfig(cwd, options.config ?? null);
const fileConfig: RepomixConfigFile = await loadFileConfig(cwd, cliOptions.config ?? null);
logger.trace('Loaded file config:', fileConfig);

// Parse the CLI options into a config
const cliConfig: RepomixConfigCli = buildCliConfig(options);
const cliConfig: RepomixConfigCli = buildCliConfig(cliOptions);
logger.trace('CLI config:', cliConfig);

// Merge default, file, and CLI configs
Expand All @@ -45,7 +45,7 @@ export const runDefaultAction = async (

const targetPaths = directories.map((directory) => path.resolve(directory));

const spinner = new Spinner('Packing files...');
const spinner = new Spinner('Packing files...', cliOptions);
spinner.start();

let packResult: PackResult;
Expand Down
10 changes: 5 additions & 5 deletions src/cli/actions/remoteAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import pc from 'picocolors';
import { execGitShallowClone, isGitInstalled } from '../../core/file/gitCommand.js';
import { RepomixError } from '../../shared/errorHandle.js';
import { logger } from '../../shared/logger.js';
import type { CliOptions } from '../cliRun.js';
import Spinner from '../cliSpinner.js';
import type { CliOptions } from '../types.js';
import { type DefaultActionRunnerResult, runDefaultAction } from './defaultAction.js';
interface IGitUrl extends GitUrl {
commit: string | undefined;
}
export const runRemoteAction = async (
repoUrl: string,
options: CliOptions,
cliOptions: CliOptions,
deps = {
isGitInstalled,
execGitShallowClone,
Expand All @@ -26,23 +26,23 @@ export const runRemoteAction = async (
}

const parsedFields = parseRemoteValue(repoUrl);
const spinner = new Spinner('Cloning repository...');
const spinner = new Spinner('Cloning repository...', cliOptions);
const tempDirPath = await createTempDirectory();
let result: DefaultActionRunnerResult;

try {
spinner.start();

// Clone the repository
await cloneRepository(parsedFields.repoUrl, tempDirPath, options.remoteBranch || parsedFields.remoteBranch, {
await cloneRepository(parsedFields.repoUrl, tempDirPath, cliOptions.remoteBranch || parsedFields.remoteBranch, {
execGitShallowClone: deps.execGitShallowClone,
});

spinner.succeed('Repository cloned successfully!');
logger.log('');

// Run the default action on the cloned repository
result = await deps.runDefaultAction([tempDirPath], tempDirPath, options);
result = await deps.runDefaultAction([tempDirPath], tempDirPath, cliOptions);
await copyOutputToCurrentDirectory(tempDirPath, process.cwd(), result.config.output.filePath);
} catch (error) {
spinner.fail('Error during repository cloning. cleanup...');
Expand Down
47 changes: 13 additions & 34 deletions src/cli/cliRun.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,14 @@
import process from 'node:process';
import { type OptionValues, program } from 'commander';
import { Option, program } from 'commander';
import pc from 'picocolors';
import type { RepomixOutputStyle } from '../config/configSchema.js';
import { getVersion } from '../core/file/packageJsonParse.js';
import { handleError } from '../shared/errorHandle.js';
import { logger } from '../shared/logger.js';
import { logger, repomixLogLevels } from '../shared/logger.js';
import { runDefaultAction } from './actions/defaultAction.js';
import { runInitAction } from './actions/initAction.js';
import { runRemoteAction } from './actions/remoteAction.js';
import { runVersionAction } from './actions/versionAction.js';

export interface CliOptions extends OptionValues {
version?: boolean;
output?: string;
include?: string;
ignore?: string;
gitignore?: boolean;
defaultPatterns?: boolean;
config?: string;
copy?: boolean;
verbose?: boolean;
topFilesLen?: number;
outputShowLineNumbers?: boolean;
style?: RepomixOutputStyle;
parsableStyle?: boolean;
init?: boolean;
global?: boolean;
remote?: string;
remoteBranch?: string;
securityCheck?: boolean;
fileSummary?: boolean;
headerText?: string;
directoryStructure?: boolean;
removeComments?: boolean;
removeEmptyLines?: boolean;
tokenCountEncoding?: string;
instructionFilePath?: string;
includeEmptyDirectories?: boolean;
}
import type { CliOptions } from './types.js';

export const run = async () => {
try {
Expand All @@ -61,7 +32,8 @@ export const run = async () => {
.option('--no-directory-structure', 'disable directory structure section output')
.option('--remove-comments', 'remove comments')
.option('--remove-empty-lines', 'remove empty lines')
.option('--verbose', 'enable verbose logging for detailed output')
.addOption(new Option('--verbose', 'enable verbose logging for detailed output').conflicts('quiet'))
.addOption(new Option('--quiet', 'disable all output to stdout').conflicts('verbose'))
.option('--init', 'initialize a new repomix.config.json file')
.option('--global', 'use global configuration (only applicable with --init)')
.option('--remote <url>', 'process a remote Git repository')
Expand All @@ -82,7 +54,14 @@ export const run = async () => {
};

export const executeAction = async (directories: string[], cwd: string, options: CliOptions) => {
logger.setVerbose(options.verbose || false);
// Set log level based on verbose and quiet flags
if (options.quiet) {
logger.setLogLevel(repomixLogLevels.SILENT);
} else if (options.verbose) {
logger.setLogLevel(repomixLogLevels.DEBUG);
} else {
logger.setLogLevel(repomixLogLevels.INFO);
}

logger.trace('directories:', directories);
logger.trace('cwd:', cwd);
Expand Down
25 changes: 19 additions & 6 deletions src/cli/cliSpinner.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import cliSpinners from 'cli-spinners';
import logUpdate from 'log-update';
import pc from 'picocolors';
import { logger } from '../shared/logger.js';
import type { CliOptions } from './types.js';

class Spinner {
private spinner = cliSpinners.dots;
private message: string;
private currentFrame = 0;
private interval: ReturnType<typeof setInterval> | null = null;
private isEnabled: boolean;
private readonly isQuiet: boolean;

constructor(message: string) {
constructor(message: string, cliOptions: CliOptions) {
this.message = message;
this.isEnabled = !logger.isVerboseEnabled();
// If the user has specified the verbose flag, don't show the spinner
this.isQuiet = cliOptions.quiet || cliOptions.verbose || false;
}

start(): void {
if (!this.isEnabled) {
if (this.isQuiet) {
return;
}

Expand All @@ -30,14 +31,18 @@ class Spinner {
}

update(message: string): void {
if (!this.isEnabled) {
if (this.isQuiet) {
return;
}

this.message = message;
}

stop(finalMessage: string): void {
if (this.isQuiet) {
return;
}

if (this.interval) {
clearInterval(this.interval);
this.interval = null;
Expand All @@ -47,10 +52,18 @@ class Spinner {
}

succeed(message: string): void {
if (this.isQuiet) {
return;
}

this.stop(`${pc.green('✔')} ${message}`);
}

fail(message: string): void {
if (this.isQuiet) {
return;
}

this.stop(`${pc.red('✖')} ${message}`);
}
}
Expand Down
32 changes: 32 additions & 0 deletions src/cli/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { OptionValues } from 'commander';
import type { RepomixOutputStyle } from '../config/configSchema.js';

export interface CliOptions extends OptionValues {
version?: boolean;
output?: string;
include?: string;
ignore?: string;
gitignore?: boolean;
defaultPatterns?: boolean;
config?: string;
copy?: boolean;
verbose?: boolean;
quiet?: boolean;
topFilesLen?: number;
outputShowLineNumbers?: boolean;
style?: RepomixOutputStyle;
parsableStyle?: boolean;
init?: boolean;
global?: boolean;
remote?: string;
remoteBranch?: string;
securityCheck?: boolean;
fileSummary?: boolean;
headerText?: string;
directoryStructure?: boolean;
removeComments?: boolean;
removeEmptyLines?: boolean;
tokenCountEncoding?: string;
instructionFilePath?: string;
includeEmptyDirectories?: boolean;
}
7 changes: 5 additions & 2 deletions src/config/configLoad.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'node:fs/promises';
import path from 'node:path';
import pc from 'picocolors';
import stripJsonComments from 'strip-json-comments';
import { RepomixError, rethrowValidationErrorIfZodError } from '../shared/errorHandle.js';
import { logger } from '../shared/logger.js';
Expand Down Expand Up @@ -56,8 +57,10 @@ export const loadFileConfig = async (rootDir: string, argConfigPath: string | nu
return await loadAndValidateConfig(globalConfigPath);
}

logger.note(
`No custom config found at ${configPath} or global config at ${globalConfigPath}.\nYou can add a config file for additional settings. Please check https://github.com/yamadashy/repomix for more information.`,
logger.log(
pc.dim(
`No custom config found at ${configPath} or global config at ${globalConfigPath}.\nYou can add a config file for additional settings. Please check https://github.com/yamadashy/repomix for more information.`,
),
);
return {};
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/file/workers/fileCollectWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'node:path';
import iconv from 'iconv-lite';
import { isBinary } from 'istextorbinary';
import jschardet from 'jschardet';
import pc from 'picocolors';
import { logger } from '../../../shared/logger.js';

// Maximum file size to process (50MB)
Expand Down Expand Up @@ -38,7 +39,7 @@ const readRawFile = async (filePath: string): Promise<string | null> => {
logger.log('⚠️ Large File Warning:');
logger.log('──────────────────────');
logger.log(`File exceeds size limit: ${sizeMB}MB > ${MAX_FILE_SIZE / 1024 / 1024}MB (${filePath})`);
logger.note('Add this file to .repomixignore if you want to exclude it permanently');
logger.log(pc.dim('Add this file to .repomixignore if you want to exclude it permanently'));
logger.log('');
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// CLI
export { run as cli } from './cli/cliRun.js';
export type { CliOptions } from './cli/cliRun.js';
export type { CliOptions } from './cli/types.js';

// Config
export type { RepomixConfigFile as RepomixConfig } from './config/configSchema.js';
Expand Down
Loading

0 comments on commit 78374fc

Please sign in to comment.