Skip to main content
Glama
MIT License
27,120
19,746
  • Linux
  • Apple
cliRun.test.ts12.3 kB
import { program } from 'commander'; import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import * as defaultAction from '../../src/cli/actions/defaultAction.js'; import * as initAction from '../../src/cli/actions/initAction.js'; import * as remoteAction from '../../src/cli/actions/remoteAction.js'; import * as versionAction from '../../src/cli/actions/versionAction.js'; import { run, runCli } from '../../src/cli/cliRun.js'; import type { CliOptions } from '../../src/cli/types.js'; import type { PackResult } from '../../src/core/packager.js'; import { logger, type RepomixLogLevel, repomixLogLevels } from '../../src/shared/logger.js'; import { createMockConfig } from '../testing/testUtils.js'; let logLevel: RepomixLogLevel; vi.mock('../../src/shared/logger', () => ({ repomixLogLevels: { SILENT: -1, ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3, }, logger: { log: vi.fn(), trace: vi.fn(), debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn(), success: vi.fn(), note: vi.fn(), setLogLevel: vi.fn((level: RepomixLogLevel) => { logLevel = level; }), getLogLevel: vi.fn(() => logLevel), }, setLogLevelByWorkerData: vi.fn(), })); vi.mock('../../src/cli/actions/defaultAction'); vi.mock('../../src/cli/actions/initAction'); vi.mock('../../src/cli/actions/remoteAction'); vi.mock('../../src/cli/actions/versionAction'); describe('cliRun', () => { beforeEach(() => { vi.resetAllMocks(); vi.mocked(defaultAction.runDefaultAction).mockResolvedValue({ config: createMockConfig({ cwd: process.cwd(), input: { maxFileSize: 50 * 1024 * 1024, }, output: { filePath: 'repomix-output.txt', style: 'plain', stdout: false, parsableStyle: false, fileSummary: true, directoryStructure: true, topFilesLength: 5, showLineNumbers: false, removeComments: false, removeEmptyLines: false, compress: false, copyToClipboard: false, files: true, git: { sortByChanges: true, sortByChangesMaxCommits: 100, includeDiffs: false, }, }, include: [], ignore: { useGitignore: true, useDefaultPatterns: true, customPatterns: [], }, security: { enableSecurityCheck: true, }, tokenCount: { encoding: 'o200k_base', }, }), packResult: { totalFiles: 0, totalCharacters: 0, totalTokens: 0, fileCharCounts: {}, fileTokenCounts: {}, suspiciousFilesResults: [], gitDiffTokenCount: 0, gitLogTokenCount: 0, suspiciousGitDiffResults: [], suspiciousGitLogResults: [], processedFiles: [], safeFilePaths: [], skippedFiles: [], } satisfies PackResult, }); vi.mocked(initAction.runInitAction).mockResolvedValue(); vi.mocked(remoteAction.runRemoteAction).mockResolvedValue({ config: createMockConfig({ cwd: process.cwd(), input: { maxFileSize: 50 * 1024 * 1024, }, output: { filePath: 'repomix-output.txt', stdout: false, style: 'plain', parsableStyle: false, fileSummary: true, directoryStructure: true, topFilesLength: 5, showLineNumbers: false, removeComments: false, removeEmptyLines: false, compress: false, copyToClipboard: false, files: true, git: { sortByChanges: true, sortByChangesMaxCommits: 100, includeDiffs: false, }, }, include: [], ignore: { useGitignore: true, useDefaultPatterns: true, customPatterns: [], }, security: { enableSecurityCheck: true, }, tokenCount: { encoding: 'o200k_base', }, }), packResult: { totalFiles: 0, totalCharacters: 0, totalTokens: 0, fileCharCounts: {}, fileTokenCounts: {}, suspiciousFilesResults: [], gitDiffTokenCount: 0, gitLogTokenCount: 0, suspiciousGitDiffResults: [], suspiciousGitLogResults: [], processedFiles: [], safeFilePaths: [], skippedFiles: [], } satisfies PackResult, }); vi.mocked(versionAction.runVersionAction).mockResolvedValue(); }); test('should call process.exit(1) on error', async () => { const exitSpy = vi.spyOn(process, 'exit').mockImplementationOnce(() => undefined as never); const parseSpy = vi.spyOn(program, 'description').mockImplementationOnce(() => { throw Error(); }); const handleErrorSpy = vi.spyOn(logger, 'error'); await expect(run()).resolves.not.toThrow(); expect(exitSpy).toHaveBeenCalledWith(1); expect(handleErrorSpy).toHaveBeenCalled(); exitSpy.mockReset(); parseSpy.mockReset(); handleErrorSpy.mockReset(); }); describe('executeAction', () => { test('should execute default action when no special options provided', async () => { await runCli(['.'], process.cwd(), {}); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith(['.'], process.cwd(), expect.any(Object)); }); test('should enable verbose logging when verbose option is true', async () => { await runCli(['.'], process.cwd(), { verbose: true }); expect(logger.setLogLevel).toHaveBeenCalledWith(repomixLogLevels.DEBUG); }); test('should execute version action when version option is true', async () => { await runCli(['.'], process.cwd(), { version: true }); expect(versionAction.runVersionAction).toHaveBeenCalled(); expect(defaultAction.runDefaultAction).not.toHaveBeenCalled(); }); test('should execute init action when init option is true', async () => { await runCli(['.'], process.cwd(), { init: true }); expect(initAction.runInitAction).toHaveBeenCalledWith(process.cwd(), false); expect(defaultAction.runDefaultAction).not.toHaveBeenCalled(); }); test('should execute remote action when remote option is provided', async () => { await runCli(['.'], process.cwd(), { remote: 'yamadashy/repomix', }); expect(remoteAction.runRemoteAction).toHaveBeenCalledWith('yamadashy/repomix', expect.any(Object)); expect(defaultAction.runDefaultAction).not.toHaveBeenCalled(); }); }); describe('parsable style flag', () => { test('should disable parsable style by default', async () => { await runCli(['.'], process.cwd(), {}); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.not.objectContaining({ parsableStyle: false, }), ); }); test('should handle --parsable-style flag', async () => { await runCli(['.'], process.cwd(), { parsableStyle: true }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ parsableStyle: true, }), ); }); }); describe('security check flag', () => { test('should enable security check by default', async () => { await runCli(['.'], process.cwd(), {}); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.not.objectContaining({ securityCheck: false, }), ); }); test('should handle --no-security-check flag', async () => { await runCli(['.'], process.cwd(), { securityCheck: false }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ securityCheck: false, }), ); }); test('should handle explicit --security-check flag', async () => { await runCli(['.'], process.cwd(), { securityCheck: true }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ securityCheck: true, }), ); }); test('should handle explicit --no-gitignore flag', async () => { await runCli(['.'], process.cwd(), { gitignore: false }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ gitignore: false, }), ); }); test('should handle explicit --no-default-patterns flag', async () => { await runCli(['.'], process.cwd(), { defaultPatterns: false }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ defaultPatterns: false, }), ); }); test('should handle explicit --header-text flag', async () => { await runCli(['.'], process.cwd(), { headerText: 'I am a good header text', }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ headerText: 'I am a good header text', }), ); }); test('should handle --instruction-file-path flag', async () => { await runCli(['.'], process.cwd(), { instructionFilePath: 'path/to/instruction.txt', }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ instructionFilePath: 'path/to/instruction.txt', }), ); }); test('should handle --include-empty-directories flag', async () => { await runCli(['.'], process.cwd(), { includeEmptyDirectories: true, }); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ includeEmptyDirectories: true, }), ); }); }); describe('quiet mode', () => { test('should set log level to SILENT when quiet option is true', async () => { const options: CliOptions = { quiet: true, }; await runCli(['.'], process.cwd(), options); expect(logger.getLogLevel()).toBe(repomixLogLevels.SILENT); }); test('should set log level to DEBUG when verbose option is true', async () => { const options: CliOptions = { verbose: true, }; await runCli(['.'], process.cwd(), options); expect(logger.getLogLevel()).toBe(repomixLogLevels.DEBUG); }); test('should set log level to INFO by default', async () => { const options: CliOptions = {}; await runCli(['.'], process.cwd(), options); expect(logger.getLogLevel()).toBe(repomixLogLevels.INFO); }); }); describe('stdout mode', () => { const originalIsTTY = process.stdout.isTTY; afterEach(() => { process.stdout.isTTY = originalIsTTY; }); test('should handle --stdout flag', async () => { const options: CliOptions = { stdout: true, }; await runCli(['.'], process.cwd(), options); expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ stdout: true, }), ); }); test('should not enable stdout mode when explicitly setting output', async () => { // Mock pipe detection process.stdout.isTTY = false; const options: CliOptions = { output: 'custom-output.txt', }; await runCli(['.'], process.cwd(), options); // stdout should not be set expect(defaultAction.runDefaultAction).toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ output: 'custom-output.txt', }), ); expect(defaultAction.runDefaultAction).not.toHaveBeenCalledWith( ['.'], process.cwd(), expect.objectContaining({ stdout: true, }), ); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yamadashy/repomix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server