From 27f73e32e6f5bf74b87b5dcc8295ccb3588b7946 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 4 Mar 2025 10:34:54 -0500 Subject: [PATCH 1/2] Add GitHub mode to MyCoder for working with issues and PRs --- .changeset/github-mode.md | 6 + README.md | 120 ++----------- docs/github-mode.md | 75 ++++++++ packages/agent/src/core/toolAgent/config.ts | 21 ++- packages/cli/README.md | 147 ++++++--------- packages/cli/src/commands/.ts | 187 ++++++++++++++++++++ 6 files changed, 361 insertions(+), 195 deletions(-) create mode 100644 .changeset/github-mode.md create mode 100644 docs/github-mode.md create mode 100644 packages/cli/src/commands/.ts diff --git a/.changeset/github-mode.md b/.changeset/github-mode.md new file mode 100644 index 0000000..31b529b --- /dev/null +++ b/.changeset/github-mode.md @@ -0,0 +1,6 @@ +--- +"mycoder-agent": minor +"mycoder": minor +--- + +Add GitHub mode to MyCoder for working with issues and PRs diff --git a/README.md b/README.md index 46cb003..78958d0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# MyCoder Mono-repository +# MyCoder An open-source mono-repository containing the MyCoder agent and cli. @@ -12,128 +12,36 @@ An open-source mono-repository containing the MyCoder agent and cli. - 📝 **Self-Modification**: Can modify code, it was built and tested by writing itself - 🔍 **Smart Logging**: Hierarchical, color-coded logging system for clear output - 👤 **Human Compatible**: Uses README.md, project files and shell commands to build its own context +- 🌐 **GitHub Integration**: GitHub mode for working with issues and PRs as part of workflow Please join the MyCoder.ai discord for support: https://discord.gg/5K6TYrHGHt -## 🚀 Quick Start +## Packages -### Prerequisites +- [mycoder](packages/cli) - Command-line interface for MyCoder +- [mycoder-agent](packages/agent) - Agent module for MyCoder -- Node.js >= 20.0.0 -- pnpm >= 10.2.1 -- ANTHROPIC_API_KEY (for AI features) - -### Installation +## Development ```bash +# Clone the repository +git clone https://github.com/drivecore/mycoder.git +cd mycoder + # Install dependencies pnpm install # Build all packages pnpm build -# Run locally built cli in interactive mode -pnpm cli -i -``` - -## 📦 Packages - -### [`cli`](packages/cli) - -Command-line interface for AI-powered coding tasks: - -- Interactive mode -- File-based prompt support -- Code migration and refactoring capabilities - -### [`agent`](packages/agent) - -Core AI agent system powering MyCoder's intelligent features: - -- Extensible Tool System -- Parallel Execution with sub-agents -- AI-Powered using Anthropic's Claude API - -## 🛠 Development - -### Common Commands - -```bash -# Development mode -pnpm dev - -# Build all packages -pnpm build - # Run tests pnpm test - -# Type checking -pnpm typecheck - -# Linting -pnpm lint - -# Formatting -pnpm format - -# Clean build artifacts -pnpm clean - -# Clean everything including node_modules -pnpm clean:all ``` -## 📚 Documentation - -Each package contains detailed documentation in its respective README.md file. See individual package directories for: - -- Detailed setup instructions -- API documentation -- Development guidelines -- Package-specific commands - -## 📦 Publishing - -This monorepo uses [Changesets](https://github.com/changesets/changesets) to manage versions and publish packages. The following packages are published to npm: - -- `mycoder` - CLI package -- `mycoder-agent` - Core agent functionality - -To publish changes: - -1. Make your code changes -2. Create a changeset (documents your changes): - - ```bash - pnpm changeset - ``` - -3. Select the packages that have changes -4. Write a clear description of the changes -5. Commit the generated changeset file - -When ready to publish: - -1. Update versions based on changesets: - - ```bash - pnpm changeset version - ``` - -2. Review the changes -3. Publish packages: - - ```bash - pnpm publish -r - ``` +## Contributing -Note: Both packages are versioned together to ensure compatibility. +Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project. -## 🤝 Contributing +## License -1. Fork the repository -2. Create your feature branch -3. Commit your changes -4. Push to the branch -5. Create a Pull Request +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/docs/github-mode.md b/docs/github-mode.md new file mode 100644 index 0000000..b4d02e7 --- /dev/null +++ b/docs/github-mode.md @@ -0,0 +1,75 @@ +# GitHub Mode for MyCoder + +GitHub mode enables MyCoder to work with GitHub issues and PRs as part of its workflow. This feature provides better continuity between sessions and makes it easier to track progress on larger projects. + +## Overview + +When GitHub mode is enabled, MyCoder will: + +- Start from existing GitHub issues or create new ones for tasks +- Create branches for issues it's working on +- Make commits with descriptive messages +- Create PRs when work is complete +- Create additional GitHub issues for follow-up tasks or ideas + +## Prerequisites + +Before using GitHub mode, ensure you have: + +1. Installed the GitHub CLI (`gh`) +2. Authenticated with GitHub (`gh auth login`) +3. Appropriate permissions for your target repository + +## Enabling GitHub Mode + +You can enable GitHub mode using the `config` command: + +```bash +mycoder config set githubMode true +``` + +To disable GitHub mode: + +```bash +mycoder config set githubMode false +``` + +To check if GitHub mode is enabled: + +```bash +mycoder config get githubMode +``` + +## Using GitHub Mode + +When GitHub mode is enabled, MyCoder will automatically include GitHub-specific instructions in its system prompt. You can ask MyCoder to: + +1. **Work on existing issues**: + ```bash + mycoder "Implement GitHub issue #42" + ``` + +2. **Create new issues**: + ```bash + mycoder "Create a GitHub issue for adding dark mode to the UI" + ``` + +3. **Create PRs for completed work**: + ```bash + mycoder "Create a PR for the changes I just made to fix issue #42" + ``` + +## GitHub Commands + +MyCoder uses the GitHub CLI directly. Here are some common commands it may use: + +- **View issues**: `gh issue list --state open` +- **View a specific issue**: `gh issue view ` +- **Create an issue**: `gh issue create --title "Title" --body "Description"` +- **Create a PR**: `gh pr create --title "Title" --body "Description"` +- **Create a branch**: `git checkout -b branch-name` +- **Make commits**: `git commit -m "Descriptive message"` + +## Configuration Storage + +GitHub mode settings are stored in the `.mycoder/config.json` file in your home directory, along with other MyCoder settings. diff --git a/packages/agent/src/core/toolAgent/config.ts b/packages/agent/src/core/toolAgent/config.ts index 8eea29e..596d878 100644 --- a/packages/agent/src/core/toolAgent/config.ts +++ b/packages/agent/src/core/toolAgent/config.ts @@ -16,7 +16,9 @@ export const DEFAULT_CONFIG = { /** * Gets the default system prompt with contextual information about the environment */ -export function getDefaultSystemPrompt(): string { +export function getDefaultSystemPrompt(options?: { + githubMode?: boolean; +}): string { // Gather context with error handling const getCommandOutput = (command: string, label: string): string => { try { @@ -31,8 +33,24 @@ export function getDefaultSystemPrompt(): string { files: getCommandOutput('ls -la', 'file listing'), system: getCommandOutput('uname -a', 'system information'), datetime: new Date().toString(), + githubMode: options?.githubMode || false, }; + const githubModeInstructions = context.githubMode + ? [ + '', + '## GitHub Mode', + 'GitHub mode is enabled. You should work with GitHub issues and PRs as part of your workflow:', + '- Start from existing GitHub issues or create new ones for tasks', + "- Create branches for issues you're working on", + '- Make commits with descriptive messages', + '- Create PRs when work is complete', + '- Create additional GitHub issues for follow-up tasks or ideas', + '', + 'You can use the GitHub CLI (`gh`) for all GitHub interactions.', + ].join('\n') + : ''; + return [ 'You are an AI agent that can use tools to accomplish tasks.', '', @@ -42,6 +60,7 @@ export function getDefaultSystemPrompt(): string { context.files, `System: ${context.system}`, `DateTime: ${context.datetime}`, + githubModeInstructions, '', 'You prefer to call tools in parallel when possible because it leads to faster execution and less resource usage.', 'When done, call the sequenceComplete tool with your results to indicate that the sequence has completed.', diff --git a/packages/cli/README.md b/packages/cli/README.md index 1c7e5f6..a4eb3e5 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1,130 +1,101 @@ # MyCoder CLI -[![NPM Package][npm]][npm-url] -[![NPM Downloads][npm-downloads]][npmtrends-url] -[![CI Status][ci]][ci-url] -[![Discord][discord]][discord-url] +Command-line interface for AI-powered coding tasks. -## Overview +## Features -MyCoder is a simple to install, powerful command-line AI agent that can perform arbitrary tasks with a particular focus on coding tasks. It uses the [mycoder-agent](https://www.npmjs.com/package/mycoder-agent) package to provide AI-powered automation capabilities. - -- 🤖 **AI-Powered**: Leverages Anthropic's Claude API for intelligent decision making +- 🤖 **AI-Powered**: Leverages Anthropic's Claude API for intelligent coding assistance - 🛠️ **Extensible Tool System**: Modular architecture with various tool categories - 🔄 **Parallel Execution**: Ability to spawn sub-agents for concurrent task processing - 📝 **Self-Modification**: Can modify code, it was built and tested by writing itself - 🔍 **Smart Logging**: Hierarchical, color-coded logging system for clear output - 👤 **Human Compatible**: Uses README.md, project files and shell commands to build its own context +- 🌐 **GitHub Integration**: GitHub mode for working with issues and PRs as part of workflow -Please join the MyCoder.ai discord for support: https://discord.gg/5K6TYrHGHt - -## WARNING and LIABILITY WAIVER - -This tool can do anything on your command line that you ask it to. It can delete files, install software, and even send data to remote servers. It is a powerful tool that should be used with caution. By using this tool, you agree that the authors and contributors are not responsible for any damage that may occur as a result of using this tool. - -## API Key Required - -Before using MyCoder, you must have an ANTHROPIC_API_KEY specified either: - -- As an environment variable, "export ANTHROPIC_API_KEY=[your-api-key]" or -- In a .env file in the folder you run `mycoder` from - -Get an API key from https://www.anthropic.com/api - -## Quick Start +## Installation ```bash -# Install globally (pnpm, bun, yarn also work) npm install -g mycoder +``` -# Start MyCoder with a prompt -mycoder "fix all build errors and ensure the tests pass" +## Usage -# Start in interactive mode +```bash +# Interactive mode mycoder -i -# Read prompt from a file -mycoder --promptFile=your-prompt.txt -``` +# Run with a prompt +mycoder "Implement a React component that displays a list of items" + +# Run with a prompt from a file +mycoder -f prompt.txt -## CLI Options +# Enable GitHub mode +mycoder config set githubMode true +``` -- `[prompt]`: Main prompt text (positional argument) -- `-i, --interactive`: Run in interactive mode, asking for prompts -- `-f, --file`: Read prompt from a specified file -- `--log`: Set log level (info, verbose, warn, error) -- `--tokenUsage`: Output token usage at info log level -- `--headless`: Use browser in headless mode with no UI showing (default: true) -- `--userSession`: Use user's existing browser session instead of sandboxed session (default: false) -- `-h, --help`: Show help -- `-V, --version`: Show version +## GitHub Mode -## Example Use Cases & Prompts +MyCoder includes a GitHub mode that enables the agent to work with GitHub issues and PRs as part of its workflow. When enabled, the agent will: -MyCoder excels at various software development tasks. Here are some example prompts: +- Start from existing GitHub issues or create new ones for tasks +- Create branches for issues it's working on +- Make commits with descriptive messages +- Create PRs when work is complete +- Create additional GitHub issues for follow-up tasks or ideas -### Code Migration & Updates +To enable GitHub mode: ```bash -# Converting test framework -mycoder "Convert all Jest tests in the src/ directory to Vitest, updating any necessary configuration files and dependencies" - -# Dependency updates -mycoder "Update all dependencies to their latest versions, handle any breaking changes, and ensure all tests pass" +mycoder config set githubMode true ``` -### Code Refactoring +To disable GitHub mode: ```bash -# Class refactoring -mycoder "Refactor the UserService class in src/services/UserService.ts to use the repository pattern, update all files that use this class, and ensure tests pass" - -# API modernization -mycoder "Convert all callback-based functions in the project to use async/await, update tests accordingly" +mycoder config set githubMode false ``` -### Feature Implementation +Requirements for GitHub mode: +- GitHub CLI (`gh`) needs to be installed and authenticated +- User needs to have appropriate GitHub permissions for the target repository -```bash -# CLI enhancement -mycoder "Add a new global --debug command line option that enables verbose logging throughout the application" - -# New functionality -mycoder "Create a new caching system for API responses using Redis, including configuration options and unit tests" -``` +## Configuration -### Maintenance & Fixes +MyCoder stores configuration in `~/.mycoder/config.json`. You can manage configuration using the `config` command: ```bash -# Build fixes -mycoder "Fix all TypeScript build errors and ensure all tests pass" +# List all configuration +mycoder config list -# Test coverage -mycoder "Add unit tests for all untested functions in the src/utils directory, aiming for 80% coverage" +# Get a specific configuration value +mycoder config get githubMode + +# Set a configuration value +mycoder config set githubMode true ``` -### Documentation +## Environment Variables + +- `ANTHROPIC_API_KEY`: Your Anthropic API key (required) + +## Development ```bash -# Documentation generation -mycoder "Generate comprehensive JSDoc documentation for all exported functions and update the API documentation in the docs/ directory" +# Clone the repository +git clone https://github.com/drivecore/mycoder.git +cd mycoder -# Architecture documentation -mycoder "Analyze the current codebase and create detailed architecture documentation including component diagrams and data flow" +# Install dependencies +pnpm install + +# Build the CLI +pnpm build + +# Run the locally built CLI +pnpm cli -i ``` -## Technical Requirements - -- Node.js >= 20.0.0 -- pnpm >= 10.2.1 - -[npm]: https://img.shields.io/npm/v/mycoder -[npm-downloads]: https://img.shields.io/npm/dw/mycoder -[npm]: https://img.shields.io/npm/v/mycoder -[npm-url]: https://www.npmjs.com/package/mycoder -[npm-downloads]: https://img.shields.io/npm/dw/mycoder -[npmtrends-url]: https://www.npmtrends.com/mycoder -[ci]: https://img.shields.io/github/checks-status/bhouston/mycoder/main -[ci-url]: https://github.com/bhouston/mycoder/actions -[discord]: https://img.shields.io/discord/1339025847331328000 -[discord-url]: https://discord.gg/5K6TYrHGHt +## License + +MIT diff --git a/packages/cli/src/commands/.ts b/packages/cli/src/commands/.ts new file mode 100644 index 0000000..165667d --- /dev/null +++ b/packages/cli/src/commands/.ts @@ -0,0 +1,187 @@ +import * as fs from 'fs/promises'; +import { createInterface } from 'readline/promises'; + +import chalk from 'chalk'; +import { + toolAgent, + Logger, + getTools, + getAnthropicApiKeyError, + userPrompt, + LogLevel, + subAgentTool, + errorToString, +} from 'mycoder-agent'; +import { TokenTracker } from 'mycoder-agent/dist/core/tokens.js'; + +import { SharedOptions } from '../options.js'; +import { initSentry, captureException } from '../sentry/index.js'; +import { getConfig } from '../settings/config.js'; +import { hasUserConsented, saveUserConsent } from '../settings/settings.js'; +import { nameToLogIndex } from '../utils/nameToLogIndex.js'; +import { checkForUpdates, getPackageInfo } from '../utils/versionCheck.js'; + +import type { CommandModule, Argv } from 'yargs'; + +interface DefaultArgs extends SharedOptions { + prompt?: string; +} + +export const command: CommandModule = { + command: '* [prompt]', + describe: 'Execute a prompt or start interactive mode', + builder: (yargs: Argv): Argv => { + return yargs.positional('prompt', { + type: 'string', + description: 'The prompt to execute', + }) as Argv; + }, + handler: async (argv) => { + // Initialize Sentry with custom DSN if provided + if (argv.sentryDsn) { + initSentry(argv.sentryDsn); + } + + const logger = new Logger({ + name: 'Default', + logLevel: nameToLogIndex(argv.logLevel), + customPrefix: subAgentTool.logPrefix, + }); + + const packageInfo = getPackageInfo(); + + logger.info( + `MyCoder v${packageInfo.version} - AI-powered coding assistant`, + ); + + await checkForUpdates(logger); + + if (!hasUserConsented()) { + const readline = createInterface({ + input: process.stdin, + output: process.stdout, + }); + + logger.warn( + 'This tool can do anything on your command line that you ask it to.', + 'It can delete files, install software, and even send data to remote servers.', + 'It is a powerful tool that should be used with caution.', + 'Do you consent to using this tool at your own risk? (y/N)', + ); + + const answer = (await readline.question('> ')).trim().toLowerCase(); + readline.close(); + + if (answer === 'y' || answer === 'yes') { + saveUserConsent(); + } else { + logger.info('User did not consent. Exiting.'); + throw new Error('User did not consent'); + } + } + + const tokenTracker = new TokenTracker( + 'Root', + undefined, + argv.tokenUsage ? LogLevel.info : LogLevel.debug, + ); + + try { + // Early API key check + if (!process.env.ANTHROPIC_API_KEY) { + logger.error(getAnthropicApiKeyError()); + throw new Error('Anthropic API key not found'); + } + + let prompt: string | undefined; + + // If promptFile is specified, read from file + if (argv.file) { + prompt = await fs.readFile(argv.file, 'utf-8'); + } + + // If interactive mode + if (argv.interactive) { + prompt = await userPrompt( + "Type your request below or 'help' for usage information. Use Ctrl+C to exit.", + ); + } else if (!prompt) { + // Use command line prompt if provided + prompt = argv.prompt; + } + + if (!prompt) { + logger.error( + 'No prompt provided. Either specify a prompt, use --promptFile, or run in --interactive mode.', + ); + throw new Error('No prompt provided'); + } + + // Add the standard suffix to all prompts + prompt += [ + 'Please ask for clarifications if required or if the tasks is confusing.', + "If you need more context, don't be scared to create a sub-agent to investigate and generate report back, this can save a lot of time and prevent obvious mistakes.", + 'Once the task is complete ask the user, via the userPrompt tool if the results are acceptable or if changes are needed or if there are additional follow on tasks.', + ].join('\n'); + + const tools = getTools(); + + // Error handling + process.on('SIGINT', () => { + logger.log( + tokenTracker.logLevel, + chalk.blueBright(`[Token Usage Total] ${tokenTracker.toString()}`), + ); + process.exit(0); + }); + + // Get configuration + const config = getConfig(); + + // Create a custom config with GitHub mode + const customConfig = { + ...undefined, // Use default config + getSystemPrompt: () => { + // Import the function dynamically to avoid circular dependencies + const { + getDefaultSystemPrompt, + } = require('mycoder-agent/dist/core/toolAgent/config.js'); + return getDefaultSystemPrompt({ githubMode: config.githubMode }); + }, + }; + + // If GitHub mode is enabled, log it + if (config.githubMode) { + logger.info('GitHub mode is enabled'); + } + + const result = await toolAgent(prompt, tools, customConfig, { + logger, + headless: argv.headless ?? true, + userSession: argv.userSession ?? false, + pageFilter: argv.pageFilter ?? 'none', + workingDirectory: '.', + tokenTracker, + }); + + const output = + typeof result.result === 'string' + ? result.result + : JSON.stringify(result.result, null, 2); + logger.info('\n=== Result ===\n', output); + } catch (error) { + logger.error( + 'An error occurred:', + errorToString(error), + error instanceof Error ? error.stack : '', + ); + // Capture the error with Sentry + captureException(error); + } + + logger.log( + tokenTracker.logLevel, + chalk.blueBright(`[Token Usage Total] ${tokenTracker.toString()}`), + ); + }, +}; From d686cbbf87af5c9dc554d85888fe2471c07f45c7 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 4 Mar 2025 10:39:06 -0500 Subject: [PATCH 2/2] forgotten changes. --- .changeset/github-mode.md | 4 ++-- .changeset/text-editor.md | 2 +- docs/github-mode.md | 2 ++ packages/cli/README.md | 1 + packages/cli/src/commands/config.ts | 5 +--- packages/cli/tests/commands/config.test.ts | 2 -- packages/cli/tests/settings/config.test.ts | 28 +++++++++++----------- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/.changeset/github-mode.md b/.changeset/github-mode.md index 31b529b..7b22dd7 100644 --- a/.changeset/github-mode.md +++ b/.changeset/github-mode.md @@ -1,6 +1,6 @@ --- -"mycoder-agent": minor -"mycoder": minor +'mycoder-agent': minor +'mycoder': minor --- Add GitHub mode to MyCoder for working with issues and PRs diff --git a/.changeset/text-editor.md b/.changeset/text-editor.md index b99b5be..d4e5f2a 100644 --- a/.changeset/text-editor.md +++ b/.changeset/text-editor.md @@ -1,5 +1,5 @@ --- -"mycoder-agent": minor +'mycoder-agent': minor --- Add textEditor tool that combines readFile and updateFile functionality diff --git a/docs/github-mode.md b/docs/github-mode.md index b4d02e7..9b4d430 100644 --- a/docs/github-mode.md +++ b/docs/github-mode.md @@ -45,11 +45,13 @@ mycoder config get githubMode When GitHub mode is enabled, MyCoder will automatically include GitHub-specific instructions in its system prompt. You can ask MyCoder to: 1. **Work on existing issues**: + ```bash mycoder "Implement GitHub issue #42" ``` 2. **Create new issues**: + ```bash mycoder "Create a GitHub issue for adding dark mode to the UI" ``` diff --git a/packages/cli/README.md b/packages/cli/README.md index a4eb3e5..251bd41 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -57,6 +57,7 @@ mycoder config set githubMode false ``` Requirements for GitHub mode: + - GitHub CLI (`gh`) needs to be installed and authenticated - User needs to have appropriate GitHub permissions for the target repository diff --git a/packages/cli/src/commands/config.ts b/packages/cli/src/commands/config.ts index 35312bb..53ee5ad 100644 --- a/packages/cli/src/commands/config.ts +++ b/packages/cli/src/commands/config.ts @@ -37,10 +37,7 @@ export const command: CommandModule = { '$0 config get githubMode', 'Get the value of githubMode setting', ) - .example( - '$0 config set githubMode true', - 'Enable GitHub mode', - ) as any; // eslint-disable-line @typescript-eslint/no-explicit-any + .example('$0 config set githubMode true', 'Enable GitHub mode') as any; // eslint-disable-line @typescript-eslint/no-explicit-any }, handler: async (argv: ArgumentsCamelCase) => { const logger = new Logger({ diff --git a/packages/cli/tests/commands/config.test.ts b/packages/cli/tests/commands/config.test.ts index e55b58b..3071a14 100644 --- a/packages/cli/tests/commands/config.test.ts +++ b/packages/cli/tests/commands/config.test.ts @@ -2,8 +2,6 @@ import { Logger } from 'mycoder-agent'; import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; import { command } from '../../src/commands/config.js'; -import type { ConfigOptions } from '../../src/commands/config.js'; -import type { ArgumentsCamelCase } from 'yargs'; import { getConfig, updateConfig } from '../../src/settings/config.js'; // Mock dependencies diff --git a/packages/cli/tests/settings/config.test.ts b/packages/cli/tests/settings/config.test.ts index 3d62d15..f056918 100644 --- a/packages/cli/tests/settings/config.test.ts +++ b/packages/cli/tests/settings/config.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; import * as fs from 'fs'; -import * as os from 'os'; import * as path from 'path'; +import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; + import { getConfig, updateConfig } from '../../src/settings/config.js'; import { getSettingsDir } from '../../src/settings/settings.js'; @@ -21,7 +21,7 @@ vi.mock('fs', () => ({ describe('Config', () => { const mockSettingsDir = '/mock/settings/dir'; const mockConfigFile = path.join(mockSettingsDir, 'config.json'); - + beforeEach(() => { vi.mocked(getSettingsDir).mockReturnValue(mockSettingsDir); }); @@ -33,9 +33,9 @@ describe('Config', () => { describe('getConfig', () => { it('should return default config if config file does not exist', () => { vi.mocked(fs.existsSync).mockReturnValue(false); - + const config = getConfig(); - + expect(config).toEqual({ githubMode: false }); expect(fs.existsSync).toHaveBeenCalledWith(mockConfigFile); }); @@ -44,9 +44,9 @@ describe('Config', () => { const mockConfig = { githubMode: true, customSetting: 'value' }; vi.mocked(fs.existsSync).mockReturnValue(true); vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockConfig)); - + const config = getConfig(); - + expect(config).toEqual(mockConfig); expect(fs.existsSync).toHaveBeenCalledWith(mockConfigFile); expect(fs.readFileSync).toHaveBeenCalledWith(mockConfigFile, 'utf-8'); @@ -57,9 +57,9 @@ describe('Config', () => { vi.mocked(fs.readFileSync).mockImplementation(() => { throw new Error('Read error'); }); - + const config = getConfig(); - + expect(config).toEqual({ githubMode: false }); }); }); @@ -70,13 +70,13 @@ describe('Config', () => { const newConfig = { githubMode: true }; vi.mocked(fs.existsSync).mockReturnValue(true); vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(currentConfig)); - + const result = updateConfig(newConfig); - + expect(result).toEqual({ githubMode: true }); expect(fs.writeFileSync).toHaveBeenCalledWith( mockConfigFile, - JSON.stringify({ githubMode: true }, null, 2) + JSON.stringify({ githubMode: true }, null, 2), ); }); @@ -85,9 +85,9 @@ describe('Config', () => { const partialConfig = { githubMode: true }; vi.mocked(fs.existsSync).mockReturnValue(true); vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(currentConfig)); - + const result = updateConfig(partialConfig); - + expect(result).toEqual({ githubMode: true, existingSetting: 'value' }); }); });