diff --git a/CHANGELOG.md b/CHANGELOG.md index d787c21..78e01a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,31 @@ and this project aims to adhere to [Semantic Versioning](https://semver.org/spec _(Future changes will go here)_ +### Added + +- A new `agent_task` command for advanced, agent-based workflows, including clickable log entries and dynamic prompt updates. ([a69b80c](https://github.com/lacerbi/athanor/commit/a69b80c), [94aa97f](https://github.com/lacerbi/athanor/commit/94aa97f), [67ba73e](https://github.com/lacerbi/athanor/commit/67ba73e)) +- Enhanced `CREATE` file operation to allow overwriting existing files with a clear user warning. ([4e2027a](https://github.com/lacerbi/athanor/commit/4e2027a)) +- Listeners for `Ctrl+C`/`Ctrl+V` to improve clipboard interaction. ([7743aa8](https://github.com/lacerbi/athanor/commit/7743aa8)) + +### Changed + +- Updated the agentic architect prompt for better performance. ([4e2027a](https://github.com/lacerbi/athanor/commit/4e2027a)) + +### Fixed + +- Corrected paste behavior within the application. ([bfb3a3e](https://github.com/lacerbi/athanor/commit/bfb3a3e)) +- Added `ELECTRON_USE_DESKTOP_GL` environment flag to mitigate potential rendering issues. ([87ba6e3](https://github.com/lacerbi/athanor/commit/87ba6e3)) +- Minor text clarifications in the Review panel for better usability. ([ef6d6d5](https://github.com/lacerbi/athanor/commit/ef6d6d5)) + +### Documentation + +- Added `GEMINI.md` and updated `CLAUDE.md` to provide guidance for different AI models. ([b2f15cb](https://github.com/lacerbi/athanor/commit/b2f15cb), [fdc032d](https://github.com/lacerbi/athanor/commit/fdc032d)) +- Clarified that Prettier is used for code formatting. ([c02b34a](https://github.com/lacerbi/athanor/commit/c02b34a)) + +### Tests + +- Fixed and updated unit tests to align with the new `agent_task` command. ([8050594](https://github.com/lacerbi/athanor/commit/8050594)) + ## [0.7.7] - 2025-07-01 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index eb24d33..ca5202c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - `npm test` - Run Jest unit tests (includes both main and renderer process tests) - `npm run test:watch` - Run tests in watch mode -- `npm run lint` - Run ESLint on TypeScript/React code +- `npm run lint` - **Note: Currently non-functional** due to ESLint configuration incompatibility (`.eslintrc.js` uses old format incompatible with ESLint 9+). Prettier is used for code formatting. **Platform-specific builds:** @@ -39,6 +39,11 @@ Athanor is an Electron desktop application for AI-assisted development workflows - `RelevanceEngineService.ts` - Intelligent context discovery using multiple heuristics - `ProjectGraphService.ts` - Background project analysis and dependency mapping - `GitService.ts` - Git repository analysis for relevance scoring +- `UserActivityService.ts` - Real-time file activity tracking for relevance signals +- `SettingsService.ts` - Project and application settings management +- `ShellService.ts` - Terminal/CLI session management with persistent PTY sessions +- `TaskAnalysisUtils.ts` - Task description analysis and keyword extraction +- `DependencyResolver.ts` / `DependencyScanner.ts` - Language-aware dependency analysis ### Critical File System Patterns @@ -63,6 +68,10 @@ Athanor is an Electron desktop application for AI-assisted development workflows - `promptStore.ts` - Prompt templates and variants - `taskStore.ts` - Task templates and variants - `applyChangesStore.ts` - AI-generated file change management +- `settingsStore.ts` - Project and application settings state +- `logStore.ts` - Application log management with interactive entries +- `commandStore.ts` - Clipboard and command validation state +- `cliStore.ts` - Terminal session state management ### Project Structure Insights @@ -71,18 +80,47 @@ Athanor is an Electron desktop application for AI-assisted development workflows - Relevance Engine uses Git history, dependencies, file mentions, and user activity - Project analysis runs in background worker thread (`projectAnalysisWorker.ts`) - Results cached in `.ath_materials/project_graph.json` +- Two-phase scoring engine with multiple heuristics for relevance +- Automatic re-analysis when file changes are detected after inactivity **AI Integration:** - Optional direct API integration via secure storage (`electron/modules/secure-api-storage/`) - Primary workflow: copy prompts to external AI, paste responses back - XML command parsing for applying AI-generated changes +- Modular LLM provider system (`electron/modules/llm/`) supporting: + - Anthropic Claude API + - OpenAI GPT models + - Google Gemini models + - Mistral models (API key storage only) +- Type-safe IPC channels for LLM operations +- Extensive model configuration and client adapters **File Management:** - Supports `.athignore` and `.gitignore` patterns - Chokidar file watchers for real-time updates - Path normalization via `PathUtils.ts` +- Agent task creation in `.ath_materials` directory + +**CLI/Terminal Support:** + +- Integrated terminal via `node-pty` and `xterm.js` +- Multi-session support with persistent terminals +- Platform-specific shell detection (PowerShell on Windows, zsh/bash on Unix) +- Managed by `ShellService.ts` and `cliStore.ts` + +**Additional Features:** + +- **Tooltips**: Contextual help throughout the UI via hover tooltips +- **Drag and Drop**: File paths can be dragged from explorer to task/context areas +- **Context Suggestions**: Automatic context suggestions based on task content +- **Preset Tasks**: Pre-defined task templates loaded from `task_*.xml` files +- **Token Budgeting**: Intelligent file inclusion based on token limits +- **Smart Preview**: Configurable preview of file contents in prompts +- **Documentation Format**: Multiple format options for file inclusion +- **Ignore Rules**: Advanced pattern matching with `.athignore` and `.gitignore` +- **Project Settings**: Stored in `.ath_materials/project_settings.json` ## Testing Considerations @@ -108,6 +146,22 @@ Athanor is an Electron desktop application for AI-assisted development workflows 4. Update `src/types/global.d.ts` type definitions 5. Implement UI-level operations in `fileSystemService.ts` +**When adding new IPC handlers:** + +1. Create handler functions in appropriate file in `electron/handlers/` +2. Export from `ipcHandlers.ts` for registration +3. Add corresponding methods to `preload.ts` +4. Update type definitions in `src/types/global.d.ts` + +**Important UI Patterns:** + +- **Left Panel**: File explorer with context menus and ignore functionality +- **Right Panel**: Task tabs, file viewer, and Apply Changes panel +- **Bottom Panel**: Log viewer with clickable entries for debugging +- **Action Panel**: Controls for prompt generation, preset tasks, and settings toggles +- **Task Templates**: XML-based templates in `resources/prompts/` +- **Prompt Variants**: Context menu for switching between prompt modes (Query, Coder, Architect) + **Security considerations:** - Never bypass IPC bridge for file operations @@ -117,7 +171,7 @@ Athanor is an Electron desktop application for AI-assisted development workflows **Code style:** - TypeScript 5+ with strict typing -- ESLint + Prettier configuration +- Prettier for code formatting (ESLint config exists but is incompatible with ESLint 9+) - TailwindCSS 3 + Material-UI components - Conventional Commits for commit messages @@ -131,3 +185,8 @@ Athanor is an Electron desktop application for AI-assisted development workflows - **ignore** - .gitignore/.athignore parsing - **js-tiktoken** - Token counting for prompts - **Jest + ts-jest** - Testing framework +- **@anthropic-ai/sdk** - Anthropic Claude API integration +- **openai** - OpenAI API integration +- **@google/genai** - Google Gemini API integration +- **node-pty** - Terminal emulation support +- **xterm & xterm-addon-fit** - Terminal rendering in UI diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..a111b00 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,192 @@ +# GEMINI.md + +This file provides guidance to Gemini CLI when working with code in this repository. + +## Essential Commands + +**Development:** + +- `npm run package` - **(Standard)** Build a local production application (in `out/`). This is the recommended way to test changes. +- `npm start` or `npm run dev` - **(Deprecated for testing)** Start development mode with hot reload. Do not use. +- `npm run make` - Unsupported. Do not use. + +**Testing & Quality:** + +- `npm test` - Run Jest unit tests (includes both main and renderer process tests) +- `npm run test:watch` - Run tests in watch mode +- `npm run lint` - **Note: Currently non-functional** due to ESLint configuration incompatibility (`.eslintrc.js` uses old format incompatible with ESLint 9+). Prettier is used for code formatting. + +**Platform-specific builds:** + +- `npm run build:win` - Build for Windows +- `npm run build:linux` - Build for Linux + +## Architecture Overview + +Athanor is an Electron desktop application for AI-assisted development workflows. It helps developers create context-rich prompts and apply AI-generated changes to codebases. + +### Core Architecture Principles + +**Main/Renderer Separation:** + +- **Main Process** (`electron/`): File system operations, Git integration, project analysis +- **Renderer Process** (`src/`): React UI, state management with Zustand +- **IPC Communication**: Secure bridge via `preload.ts` and typed in `src/types/global.d.ts` + +**Key Services:** + +- `FileService.ts` - Central file system operations manager (main process) +- `RelevanceEngineService.ts` - Intelligent context discovery using multiple heuristics +- `ProjectGraphService.ts` - Background project analysis and dependency mapping +- `GitService.ts` - Git repository analysis for relevance scoring +- `UserActivityService.ts` - Real-time file activity tracking for relevance signals +- `SettingsService.ts` - Project and application settings management +- `ShellService.ts` - Terminal/CLI session management with persistent PTY sessions +- `TaskAnalysisUtils.ts` - Task description analysis and keyword extraction +- `DependencyResolver.ts` / `DependencyScanner.ts` - Language-aware dependency analysis + +### Critical File System Patterns + +**Always use proper abstraction layers:** + +- Main process: Use `FileService.ts` singleton for all file operations +- Renderer process: Use `fileSystemService.ts` for UI-related file operations +- Never bypass IPC for file operations from renderer + +**Global type definitions:** + +- `src/types/global.d.ts` - Extends window interface and defines core types +- Must be updated when modifying IPC method signatures + +### State Management + +**Zustand stores in `src/stores/`:** + +- `fileSystemStore.ts` - Selected files, file tree, preview state +- `workbenchStore.ts` - Multi-tab task management +- `contextStore.ts` - Intelligent context builder state +- `promptStore.ts` - Prompt templates and variants +- `taskStore.ts` - Task templates and variants +- `applyChangesStore.ts` - AI-generated file change management +- `settingsStore.ts` - Project and application settings state +- `logStore.ts` - Application log management with interactive entries +- `commandStore.ts` - Clipboard and command validation state +- `cliStore.ts` - Terminal session state management + +### Project Structure Insights + +**Core Intelligence:** + +- Relevance Engine uses Git history, dependencies, file mentions, and user activity +- Project analysis runs in background worker thread (`projectAnalysisWorker.ts`) +- Results cached in `.ath_materials/project_graph.json` +- Two-phase scoring engine with multiple heuristics for relevance +- Automatic re-analysis when file changes are detected after inactivity + +**AI Integration:** + +- Optional direct API integration via secure storage (`electron/modules/secure-api-storage/`) +- Primary workflow: copy prompts to external AI, paste responses back +- XML command parsing for applying AI-generated changes +- Modular LLM provider system (`electron/modules/llm/`) supporting: + - Anthropic Claude API + - OpenAI GPT models + - Google Gemini models + - Mistral models (API key storage only) +- Type-safe IPC channels for LLM operations +- Extensive model configuration and client adapters + +**File Management:** + +- Supports `.athignore` and `.gitignore` patterns +- Chokidar file watchers for real-time updates +- Path normalization via `PathUtils.ts` +- Agent task creation in `.ath_materials` directory + +**CLI/Terminal Support:** + +- Integrated terminal via `node-pty` and `xterm.js` +- Multi-session support with persistent terminals +- Platform-specific shell detection (PowerShell on Windows, zsh/bash on Unix) +- Managed by `ShellService.ts` and `cliStore.ts` + +**Additional Features:** + +- **Tooltips**: Contextual help throughout the UI via hover tooltips +- **Drag and Drop**: File paths can be dragged from explorer to task/context areas +- **Context Suggestions**: Automatic context suggestions based on task content +- **Preset Tasks**: Pre-defined task templates loaded from `task_*.xml` files +- **Token Budgeting**: Intelligent file inclusion based on token limits +- **Smart Preview**: Configurable preview of file contents in prompts +- **Documentation Format**: Multiple format options for file inclusion +- **Ignore Rules**: Advanced pattern matching with `.athignore` and `.gitignore` +- **Project Settings**: Stored in `.ath_materials/project_settings.json` + +## Testing Considerations + +**Mocking Strategy:** + +- Electron modules mocked via `tests/__mocks__/electron.ts` +- File system operations mocked for isolation +- Tests co-located with source files (e.g., `FileService.test.ts`) + +**Test Environment:** + +- Jest with Node.js environment for main process +- ts-jest for TypeScript compilation +- Tests cover both main and renderer processes + +## Development Guidelines + +**When adding file system features:** + +1. Add core functionality to `FileService.ts` or `PathUtils.ts` +2. Create IPC handlers in `handlers/` directory +3. Update `preload.ts` interface methods +4. Update `src/types/global.d.ts` type definitions +5. Implement UI-level operations in `fileSystemService.ts` + +**When adding new IPC handlers:** + +1. Create handler functions in appropriate file in `electron/handlers/` +2. Export from `ipcHandlers.ts` for registration +3. Add corresponding methods to `preload.ts` +4. Update type definitions in `src/types/global.d.ts` + +**Important UI Patterns:** + +- **Left Panel**: File explorer with context menus and ignore functionality +- **Right Panel**: Task tabs, file viewer, and Apply Changes panel +- **Bottom Panel**: Log viewer with clickable entries for debugging +- **Action Panel**: Controls for prompt generation, preset tasks, and settings toggles +- **Task Templates**: XML-based templates in `resources/prompts/` +- **Prompt Variants**: Context menu for switching between prompt modes (Query, Coder, Architect) + +**Security considerations:** + +- Never bypass IPC bridge for file operations +- Validate all paths in main process handlers +- Use secure API key storage for LLM integration + +**Code style:** + +- TypeScript 5+ with strict typing +- Prettier for code formatting (ESLint config exists but is incompatible with ESLint 9+) +- TailwindCSS 3 + Material-UI components +- Conventional Commits for commit messages + +## Key Dependencies + +- **Electron 33+** - Desktop app framework +- **React 19+** - UI framework +- **TypeScript 5+** - Type safety +- **Zustand** - State management +- **Chokidar** - File watching +- **ignore** - .gitignore/.athignore parsing +- **js-tiktoken** - Token counting for prompts +- **Jest + ts-jest** - Testing framework +- **@anthropic-ai/sdk** - Anthropic Claude API integration +- **openai** - OpenAI API integration +- **@google/genai** - Google Gemini API integration +- **node-pty** - Terminal emulation support +- **xterm & xterm-addon-fit** - Terminal rendering in UI diff --git a/PROJECT.md b/PROJECT.md index 8d7d639..31d65e3 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -158,7 +158,8 @@ Athanor follows Electron's recommended **“secure by default”** pattern, sepa - **Webpack & electron-forge**: Build, package, and run the Electron application. - **TailwindCSS 3 + Lucide Icons**: Provides a flexible styling system and icon library for a clean UI. - **Material-UI (MUI) 5**: Partially integrated for certain UI elements (used in some components). -- **ESLint / Prettier**: Linting & formatting for consistent code style. +- **Prettier**: Code formatting for consistent style (configured via `.prettierrc`). +- **ESLint**: Currently non-functional due to incompatible configuration format (`.eslintrc.js` uses old format incompatible with ESLint 9+). The `npm run lint` command will not work properly. - **Jest & ts-jest**: Provide the unit testing framework. Tests are typically colocated with the source code they validate (e.g., `FileService.test.ts` alongside `FileService.ts`). - **Testing Mocks**: Key dependencies, including Electron itself (via `tests/__mocks__/electron.ts`) and Node.js modules like `fs/promises`, are mocked to ensure isolated and reliable unit tests. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 46e9bce..0b48736 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -70,10 +70,32 @@ If you're running Athanor in WSL, installing `libsecret` alone is not sufficient ---- - -**IMPORTANT FINAL STEP (ALL DISTRIBUTIONS):** +#### **IMPORTANT FINAL STEP (ALL DISTRIBUTIONS):** After the installation is complete, **you must log out and log back in**, or simply restart your computer. This ensures the newly installed keyring service is active and available to all applications, including Athanor. After restarting, when you first try to save a key, your system might prompt you to create a new default keyring and set a password for it. This is a one-time setup. Once completed, Athanor will be able to store API keys securely. + +--- + +## Linux/WSL Graphics Issue (Blank Screen) + +### Problem: The application window is blank or black on startup + +When launching Athanor on certain Linux desktop environments or within the Windows Subsystem for Linux (WSL), the application may start, but the window remains completely blank. You may see a black or white screen instead of the user interface. + +### Cause + +This issue typically occurs when Electron, the framework used by Athanor, fails to automatically select the correct graphics rendering backend for your system. The default choice may be incompatible with your graphics driver setup, especially within the virtualized environment of WSL. + +### Solution + +You can resolve this by instructing Athanor to use a specific, more compatible graphics backend called "Desktop OpenGL." This is done by setting an environment variable before launching the application. + +1. Open your shell's configuration file. This is usually `~/.bashrc`, `~/.zshrc`, or `~/.profile`, depending on your shell. +2. Add the following line to the end of the file: + ```bash + export ELECTRON_USE_DESKTOP_GL=1 + ``` +3. Save the file and restart your terminal, or run `source ~/.bashrc` (or the equivalent for your shell) to apply the changes. +4. Launch Athanor from the terminal. It should now start correctly with the UI visible. diff --git a/electron/main.ts b/electron/main.ts index 3f6495f..ba1507b 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -23,6 +23,19 @@ import { import { PROJECT_ANALYSIS } from '../src/utils/constants'; import type { ApplicationSettings } from '../src/types/global'; +// --- WSL Graphics Fix Start --- +// This addresses a specific rendering issue on WSL where Electron may default +// to an incompatible graphics backend, causing a blank screen. +// By checking for a custom environment variable, we allow affected users to opt-in +// to forcing the 'desktop' OpenGL backend without affecting other users. +if (process.env.ELECTRON_USE_DESKTOP_GL === '1') { + console.log( + '[Main] ELECTRON_USE_DESKTOP_GL=1 detected. Applying --use-gl=desktop switch.' + ); + app.commandLine.appendSwitch('use-gl', 'desktop'); +} +// --- WSL Graphics Fix End --- + // Debug flag for menu diagnostics const DEBUG_MENU = false; const DEBUG_PATH = false; diff --git a/package-lock.json b/package-lock.json index 1ac651d..e843c12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "athanor", - "version": "0.7.5", + "version": "0.7.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "athanor", - "version": "0.7.5", + "version": "0.7.7", "license": "Apache-2.0", "dependencies": { "@anthropic-ai/sdk": "^0.52.0", diff --git a/package.json b/package.json index 56ef356..cec0d58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "athanor", - "version": "0.7.7", + "version": "0.7.8", "bugs": { "url": "https://github.com/lacerbi/athanor/issues" }, diff --git a/resources/prompts/prompt_architect.xml b/resources/prompts/prompt_architect.xml index 6433d15..c551903 100644 --- a/resources/prompts/prompt_architect.xml +++ b/resources/prompts/prompt_architect.xml @@ -479,36 +479,50 @@ The purpose is to: - All verification steps must be executable from the command line - Consider that the agent needs precise, unambiguous instructions -The XML block should include: +The XML block should be formatted as follows: -1. An XML tag - * The task_description slightly edited and rewritten for clarity (do not omit parts) - * An extended, thorough answer and analysis - * A high-level overview of the implementation strategy - * Break down the implementation into logical commits if the task is complex - - Each commit should focus on one self-contained piece of functionality - - Each commit should result in working (though potentially incomplete) code - - Each commit should modify a reasonable number of files (typically 1-3) - - Each commit should have a clear, specific purpose - * For each commit, provide: - - A clear description of what the commit achieves - - Files that will be modified - - Detailed step-by-step implementation instructions - - Any dependencies on previous commits - - **CLI-based verification commands** appropriate for the programming language and task - * For a simple task, one commit might be enough +```xml + +{{task_tab_name}}.md + +[Full Plan here] + + +``` -2. A XML tag with a list of all relevant files - * List all the files that the developer will need to read in full, change or delete from the file_tree provided above - * Consider broadly which files might be useful to see for the feature, even if not immediately related - * These might include preloaders, utility or global constant files, etc. - * If in doubt whether you need to include a file, include it - * This list may match the list of highlighted (*) files above (if any), but might include additional files, or remove some which are clearly not needed - * Use the relative path of each file +Use the provided task file name `{{task_tab_name}}.md` + +The full plan will contain: +* The task_description slightly edited and rewritten for clarity (do not omit parts) +* An extended, thorough answer and analysis +* A high-level overview of the implementation strategy +* Break down the implementation into logical commits if the task is complex + - Each commit should focus on one self-contained piece of functionality + - Each commit should result in working (though potentially incomplete) code + - Each commit should modify a reasonable number of files (typically 1-3) + - Each commit should have a clear, specific purpose +* For each commit, provide: + - A clear description of what the commit achieves + - Files that will be modified + - Detailed step-by-step implementation instructions + - Any dependencies on previous commits + - **CLI-based verification commands** appropriate for the programming language and task +* For a simple task, one commit might be enough + +At the end of the full plan, list "Relevant Files": + +* List all the files that the developer will need to read in full, change or delete from the file_tree provided above +* Consider broadly which files might be useful to see for the feature, even if not immediately related +* These might include preloaders, utility or global constant files, etc. +* If in doubt whether you need to include a file, include it +* This list may match the list of highlighted (*) files above (if any), but might include additional files, or remove some which are clearly not needed +* Use the relative path of each file ```xml - + +{{task_tab_name}}.md + # Task [Task description, rewritten for clarity] @@ -548,10 +562,12 @@ The XML block should include: - API endpoints respond (if applicable) [Additional commits as needed...] - - -file1 file2 [...] +# Relevant Files +file1 +file2 +... + ``` diff --git a/src/actions/ApplyAiOutputAction.ts b/src/actions/ApplyAiOutputAction.ts index 4f481d9..4a57fad 100644 --- a/src/actions/ApplyAiOutputAction.ts +++ b/src/actions/ApplyAiOutputAction.ts @@ -81,6 +81,13 @@ export async function processAiResponseContent( }); break; + case commands.COMMAND_TYPES.AGENT_TASK: + success = await commands.executeAgentTaskCommand({ + content: command.content, + addLog, + }); + break; + default: addLog(`Unknown command type: ${command.type}`); continue; diff --git a/src/actions/buildTaskAction.test.ts b/src/actions/buildTaskAction.test.ts index 0a63f4b..e4b5443 100644 --- a/src/actions/buildTaskAction.test.ts +++ b/src/actions/buildTaskAction.test.ts @@ -241,6 +241,7 @@ describe('buildTaskAction', () => { '/fake/project/dir', 'existing task description', 'existing context', + 'Task 1', // activeTabName undefined, // passedFormatTypeOverride undefined, // smartPreviewConfigInput 200 // currentThresholdLineLength @@ -284,6 +285,7 @@ describe('buildTaskAction', () => { expect.anything(), expect.anything(), expect.anything(), + 'Task 1', undefined, undefined, 150 // should use the passed value @@ -398,6 +400,7 @@ describe('buildTaskAction', () => { expect.anything(), 'existing task description', // from mocked store state 'existing context', // from mocked store state + 'Task 1', undefined, undefined, expect.anything() @@ -442,6 +445,7 @@ describe('buildTaskAction', () => { expect.anything(), expect.anything(), expect.anything(), + 'Task 1', undefined, undefined, expect.anything() @@ -492,6 +496,7 @@ describe('buildTaskAction', () => { expect.anything(), expect.anything(), expect.anything(), + 'Task 1', undefined, undefined, expect.anything() @@ -515,6 +520,7 @@ describe('buildTaskAction', () => { expect.anything(), expect.anything(), expect.anything(), + 'Task 1', undefined, undefined, expect.anything() diff --git a/src/actions/buildTaskAction.ts b/src/actions/buildTaskAction.ts index 777b9da..1965994 100644 --- a/src/actions/buildTaskAction.ts +++ b/src/actions/buildTaskAction.ts @@ -71,6 +71,7 @@ export async function buildTaskAction(params: BuildTaskActionParams): Promise Promise } + ) => void; +} + +export async function executeAgentTaskCommand({ + content, + addLog, +}: AgentTaskCommandParams): Promise { + try { + const fileName = extractTagContent(content, 'file_name'); + const taskContent = extractTagContent(content, 'task_content'); + + if (!fileName) { + addLog('Error: "agent task" command is missing .'); + return false; + } + + if (!taskContent) { + addLog('Error: "agent task" command is missing .'); + return false; + } + + const materialsDir = await window.fileService.getMaterialsDir(); + const filePath = await window.pathUtils.join(materialsDir, fileName); + const displayPath = await window.pathUtils.relative(filePath); + + await window.fileService.write(filePath, taskContent); + + const instruction = `Review and execute the instructions in ${displayPath}`; + addLog({ + message: `Agent task created: ${displayPath}. Click to copy instruction.`, + onClick: async () => { + await copyToClipboard({ + content: instruction, + addLog: (msg: string) => addLog(msg), + }); + }, + }); + + return true; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + addLog(`Error executing "agent task" command: ${errorMessage}`); + console.error('Agent Task execution failed:', error); + return false; + } +} diff --git a/src/commands/index.ts b/src/commands/index.ts index 40ed837..f4e210c 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -5,9 +5,11 @@ export { executeSelectCommand } from './selectCommand'; export { executeTaskCommand } from './taskCommand'; export { executeApplyChangesCommand } from './applyChangesCommand'; +export { executeAgentTaskCommand } from './agentTaskCommand'; export type { SelectCommandParams } from './selectCommand'; export type { TaskCommandParams } from './taskCommand'; export type { ApplyChangesParams } from './applyChangesCommand'; +export type { AgentTaskCommandParams } from './agentTaskCommand'; // Command types and constants export { COMMAND_TYPES } from './types'; diff --git a/src/commands/parser/applyChangesParser.ts b/src/commands/parser/applyChangesParser.ts index c8e69a3..00629f7 100644 --- a/src/commands/parser/applyChangesParser.ts +++ b/src/commands/parser/applyChangesParser.ts @@ -265,8 +265,18 @@ export async function parseXmlContent( try { let oldCode = ''; let processedNewCode = ''; - const operation = block.operation; + let operation = block.operation; const path = block.path; + let warning: string | undefined; + + if (operation === 'CREATE') { + const fileExists = await window.fileService.exists(path); + if (fileExists) { + operation = 'UPDATE_FULL'; + warning = `File already exists. Operation changed from CREATE to a full update.`; + addLog(`Warning for ${path}: ${warning}`); + } + } // Track failed UPDATE_DIFF operations if (operation === 'UPDATE_DIFF') { @@ -276,9 +286,9 @@ export async function parseXmlContent( // Get existing file content if needed if (operation !== 'CREATE') { try { - const isDir = await window.fileSystem.isDirectory(path); + const isDir = await window.fileService.isDirectory(path); if (!isDir) { - oldCode = (await window.fileSystem.readFile(path, { + oldCode = (await window.fileService.read(path, { encoding: 'utf8', })) as string; } else { @@ -329,6 +339,7 @@ export async function parseXmlContent( accepted: false, rejected: false, diff_blocks: operation === 'UPDATE_DIFF' ? [] : undefined, + warning: warning, }); } catch (error) { console.error(`Error processing file ${block.path}:`, error); @@ -338,7 +349,7 @@ export async function parseXmlContent( // If there were any failed UPDATE_DIFF operations, create a clickable log entry if (failedDiffPaths.length > 0) { - const currentDir = await window.fileSystem.getCurrentDirectory(); + const currentDir = await window.fileService.getCurrentDirectory(); // Create a clickable log entry by passing an object addLog({ message: `${failedDiffPaths.length} UPDATE_DIFF operation(s) failed - Click to copy files`, diff --git a/src/commands/types.ts b/src/commands/types.ts index 122440a..bde4296 100644 --- a/src/commands/types.ts +++ b/src/commands/types.ts @@ -6,9 +6,10 @@ export const COMMAND_TYPES = { SELECT: 'select', TASK: 'task', APPLY_CHANGES: 'apply changes', + AGENT_TASK: 'agent task', } as const; -export type CommandType = typeof COMMAND_TYPES[keyof typeof COMMAND_TYPES]; +export type CommandType = (typeof COMMAND_TYPES)[keyof typeof COMMAND_TYPES]; // Re-export common types used across commands export type { FileOperation } from '../types/global'; diff --git a/src/components/ActionPanel.tsx b/src/components/ActionPanel.tsx index 0359fd9..7b13cd6 100644 --- a/src/components/ActionPanel.tsx +++ b/src/components/ActionPanel.tsx @@ -229,6 +229,7 @@ const ActionPanel: React.FC = ({ await window.fileSystem.getCurrentDirectory(), tabs[activeTabIndex].content, // Current tab's content tabs[activeTabIndex].context, // Current tab's context + activeTab.name, // Pass the active tab's name formatType, // Pass the current format type smartPreviewConfig, // Pass the smart preview configuration from settings currentThresholdLineLength // Pass the current threshold line length diff --git a/src/components/CliPanel.tsx b/src/components/CliPanel.tsx index e06eb89..d8795ca 100644 --- a/src/components/CliPanel.tsx +++ b/src/components/CliPanel.tsx @@ -16,6 +16,8 @@ const CliPanel: React.FC = ({ currentDirectory, isVisible }) => { null ); const listenersAttached = useRef(false); + const lastPasteTime = useRef(0); + const isPasting = useRef(false); // Effect to initialize the terminal once per project (due to key={currentDirectory}) useEffect(() => { @@ -28,6 +30,56 @@ const CliPanel: React.FC = ({ currentDirectory, isVisible }) => { termInstanceRef.current = { term, fitAddon }; term.open(terminalRef.current); + // Add custom key event handler for copy/paste + term.attachCustomKeyEventHandler((event) => { + // Handle Ctrl+C (copy) + if (event.ctrlKey && event.key === 'c' && term.hasSelection()) { + navigator.clipboard.writeText(term.getSelection()); + return false; // Prevent default terminal behavior + } + // Handle Ctrl+V (paste) - only on keydown to prevent double execution + if (event.ctrlKey && event.key === 'v') { + if (event.type !== 'keydown') { + return false; // Ignore keyup events + } + + event.preventDefault(); + event.stopPropagation(); + + if (isPasting.current) { + console.log('[CliPanel] Already processing paste, ignoring'); + return false; + } + + isPasting.current = true; + console.log('[CliPanel] Processing paste event'); + + navigator.clipboard + .readText() + .then((text) => { + if (text) { + // Send the pasted text to the terminal + const sessionId = useCliStore + .getState() + .getSessionId(currentDirectory); + if (sessionId) { + window.electronBridge.shell.write(sessionId, text); + } + } + // Reset the flag after a delay + setTimeout(() => { + isPasting.current = false; + }, 100); + }) + .catch((err) => { + console.error('[CliPanel] Failed to read clipboard:', err); + isPasting.current = false; + }); + return false; // Prevent default terminal behavior + } + return true; // Let other keys pass through + }); + (async () => { let sessionId = useCliStore.getState().getSessionId(currentDirectory); if (!sessionId) { @@ -43,6 +95,11 @@ const CliPanel: React.FC = ({ currentDirectory, isVisible }) => { if (!listenersAttached.current) { term.onData((data) => { + // Skip if we're handling a paste operation + if (isPasting.current) { + console.log('[CliPanel] Skipping onData during paste operation'); + return; + } window.electronBridge.shell.write(sessionId, data); }); term.onResize(({ cols, rows }) => { diff --git a/src/components/ReviewPanel.tsx b/src/components/ReviewPanel.tsx index ef5b8c9..6aa16c0 100644 --- a/src/components/ReviewPanel.tsx +++ b/src/components/ReviewPanel.tsx @@ -14,7 +14,7 @@ import { ChevronsDown, ChevronsUp, ChevronUp, - DraftingCompass, + Pen, GitCompare, Wrench, X, @@ -341,6 +341,13 @@ const FileOperationItem = React.forwardRef< + {op.warning && ( +
+ +

{op.warning}

+
+ )} +
onReject(index)} + onClick={() => onReject(index)} + title={ + mode === 'git' + ? 'Revert change to the last commit' + : 'Reject change' + } > - {mode === 'git' ? 'Revert Change' : 'Reject'} + {mode === 'git' ? 'Revert Change' : 'Reject'}
@@ -421,7 +433,7 @@ const ReviewPanel: React.FC = () => { // Handle clear operations with confirmation for AI mode const handleClear = () => { const { addLog } = useLogStore.getState(); - + if (mode === 'git') { // Git mode: clear immediately, no confirmation needed clearOperations(); @@ -434,11 +446,11 @@ const ReviewPanel: React.FC = () => { const pendingCount = activeOperations.filter( (op) => !op.accepted && !op.rejected ).length; - + const confirmed = window.confirm( `There are ${pendingCount} pending change${pendingCount === 1 ? '' : 's'} that haven't been accepted or rejected.\n\nAre you sure you want to clear all changes? This action cannot be undone.` ); - + if (!confirmed) { return; } @@ -1013,24 +1025,24 @@ const ReviewPanel: React.FC = () => { - - AI changes appear here after you use the "Apply AI - Output" action. This processes responses from prompts like Coder{' '} - or Architect{' '} - . - + /> + + AI changes appear here after you use the "Apply + AI Output" action. This processes responses from prompts like + Coder or + Writer . +

- - - For Git changes, click the{' '} - button - above the file explorer. - + + + For Git changes, click the{' '} + button + above the file explorer. +

@@ -1106,30 +1118,32 @@ const ReviewPanel: React.FC = () => { {mode === 'ai' && ( - + )}